Compare commits

...

11 Commits

Author SHA1 Message Date
Hailey
e42e0225cf cleanup before pr 2021-11-14 17:49:27 +10:00
Hailey
d937ce8507 added information on haileyjunk in case people wonder what it is 2021-11-14 17:41:40 +10:00
Hailey
f994d768ef Added freeplay mode details and challenge details!! 2021-11-14 15:07:07 +10:00
Hailey
9f5f9bc336 Implemented challenges!!!!! 2021-11-14 14:18:55 +10:00
Hailey
23b42a534e Merge branch 'master' into haileyjunk 2021-11-09 14:58:14 +10:00
hailey
6a465f8441 changed version for screenshots 2021-10-22 20:37:49 +10:00
hailey
8c5564f196 debug keys and splash text i guess 2021-10-22 15:39:39 +10:00
hailey
035a3aa2f2 Merge branch 'master' into haileyjunk 2021-10-22 15:09:03 +10:00
hailey
9f88faa0a7 wip bs 2021-10-22 15:08:14 +10:00
hailey
63e9531b28 h 2021-09-30 12:46:38 +10:00
hailey
174c45e7eb new branch where i practice getting back into the coding groove while testing and experimenting with new and interesing ideas and concepts 2021-09-30 11:38:20 +10:00
16 changed files with 466 additions and 23 deletions

View File

@@ -40,6 +40,14 @@ Alternatively, if you're on a 32-bit system, run this instead:
Then, check the mod pack section at the bottom of this page. Then, check the mod pack section at the bottom of this page.
#### Other branches/haileyjunk
The Cambridge repository has multiple public and private branches for working on and testing out major new features over the course of many commits.
If you're looking to test even newer features that aren't even in the master branch, the closest you're going to get is probably the haileyjunk branch, which you can download [here](https://github.com/MillaBasset/cambridge/archive/master.zip).
> WARNING: This branch can be very buggy and broken at times. Use with care.
### macOS, Linux ### macOS, Linux
If you haven't already, install `love` with your favourite package manager (Homebrew on macOS, your system's default on Linux). **Make sure you're using LÖVE 11, because it won't work with earlier versions!** If you haven't already, install `love` with your favourite package manager (Homebrew on macOS, your system's default on Linux). **Make sure you're using LÖVE 11, because it won't work with earlier versions!**

View File

@@ -5,6 +5,8 @@ bgm = {
pacer_test = love.audio.newSource("res/bgm/pacer_test.mp3", "stream"), pacer_test = love.audio.newSource("res/bgm/pacer_test.mp3", "stream"),
} }
local frames = 0
local current_bgm = nil local current_bgm = nil
local bgm_locked = false local bgm_locked = false
local unfocused = false local unfocused = false

View File

@@ -118,6 +118,7 @@ misc_graphics = {
ready = love.graphics.newImage("res/img/ready.png"), ready = love.graphics.newImage("res/img/ready.png"),
go = love.graphics.newImage("res/img/go.png"), go = love.graphics.newImage("res/img/go.png"),
select_mode = love.graphics.newImage("res/img/select_mode.png"), select_mode = love.graphics.newImage("res/img/select_mode.png"),
select_challenge = love.graphics.newImage("res/img/select_challenge_placeholder.png"),
strike = love.graphics.newImage("res/img/strike.png"), strike = love.graphics.newImage("res/img/strike.png"),
santa = love.graphics.newImage("res/img/santa.png"), santa = love.graphics.newImage("res/img/santa.png"),
icon = love.graphics.newImage("res/img/cambridge_transparent.png") icon = love.graphics.newImage("res/img/cambridge_transparent.png")

View File

@@ -1 +1 @@
version = "v0.3" version = "v0.3.1"

View File

@@ -42,6 +42,13 @@ function initModules()
game_modes[#game_modes+1] = require ("tetris.modes."..string.sub(mode_list[i],1,-5)) game_modes[#game_modes+1] = require ("tetris.modes."..string.sub(mode_list[i],1,-5))
end end
end end
challenges = {}
challenge_list = love.filesystem.getDirectoryItems("tetris/challenges")
for i=1,#challenge_list do
if(challenge_list[i] ~= "challenge.lua" and string.sub(challenge_list[i], -4) == ".lua") then
challenges[#challenges+1] = require ("tetris.challenges."..string.sub(challenge_list[i],1,-5))
end
end
rulesets = {} rulesets = {}
rule_list = love.filesystem.getDirectoryItems("tetris/rulesets") rule_list = love.filesystem.getDirectoryItems("tetris/rulesets")
for i=1,#rule_list do for i=1,#rule_list do

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@@ -10,7 +10,9 @@ function Scene:onInputRelease() end
ExitScene = require "scene.exit" ExitScene = require "scene.exit"
GameScene = require "scene.game" GameScene = require "scene.game"
ChallengeScene = require "scene.challenge"
ModeSelectScene = require "scene.mode_select" ModeSelectScene = require "scene.mode_select"
ChallengeSelectScene = require "scene.challenge_select"
KeyConfigScene = require "scene.key_config" KeyConfigScene = require "scene.key_config"
StickConfigScene = require "scene.stick_config" StickConfigScene = require "scene.stick_config"
InputConfigScene = require "scene.input_config" InputConfigScene = require "scene.input_config"

93
scene/challenge.lua Normal file
View File

@@ -0,0 +1,93 @@
local ChallengeScene = Scene:extend()
ChallengeScene.title = "Challenge"
require 'load.save'
function ChallengeScene:new(game_mode, ruleset, inputs)
self.retry_mode = game_mode
self.retry_ruleset = ruleset
self.secret_inputs = inputs
self.game = game_mode(self.secret_inputs)
self.ruleset = ruleset(self.game)
self.game:initialize(self.ruleset)
self.inputs = {
left=false,
right=false,
up=false,
down=false,
rotate_left=false,
rotate_left2=false,
rotate_right=false,
rotate_right2=false,
rotate_180=false,
hold=false,
}
self.paused = false
DiscordRPC:update({
details = "In challenge",
state = self.game.name,
largeImageKey = "ingame-"..self.game:getBackground().."00"
})
end
function ChallengeScene:update()
if love.window.hasFocus() and not self.paused then
local inputs = {}
for input, value in pairs(self.inputs) do
inputs[input] = value
end
self.game:update(inputs, self.ruleset)
self.game.grid:update()
DiscordRPC:update({
largeImageKey = "ingame-"..self.game:getBackground().."00"
})
end
end
function ChallengeScene:render()
self.game:draw(self.paused)
end
function ChallengeScene:onInputPress(e)
if (
self.game.game_over or self.game.completed
) and (
e.input == "menu_decide" or
e.input == "menu_back" or
e.input == "retry"
) then
highscore_entry = self.game:getHighscoreData()
highscore_hash = self.game.hash .. "-" .. self.ruleset.hash
submitHighscore(highscore_hash, highscore_entry)
self.game:onExit()
scene = e.input == "retry" and ChallengeScene(self.retry_mode, self.retry_ruleset, self.secret_inputs) or ModeSelectScene()
elseif e.input == "retry" then
switchBGM(nil)
self.game:onExit()
scene = ChallengeScene(self.retry_mode, self.retry_ruleset, self.secret_inputs)
elseif e.input == "pause" and not (self.game.game_over or self.game.completed) then
self.paused = not self.paused
if self.paused then pauseBGM()
else resumeBGM() end
elseif e.input == "menu_back" then
self.game:onExit()
scene = ChallengeSelectScene()
elseif e.input and string.sub(e.input, 1, 5) ~= "menu_" then
self.inputs[e.input] = true
end
end
function ChallengeScene:onInputRelease(e)
if e.input and string.sub(e.input, 1, 5) ~= "menu_" then
self.inputs[e.input] = false
end
end
function submitHighscore(hash, data)
if not highscores[hash] then highscores[hash] = {} end
table.insert(highscores[hash], data)
saveHighscores()
end
return ChallengeScene

186
scene/challenge_select.lua Normal file
View File

@@ -0,0 +1,186 @@
local ChallengeSelectScene = Scene:extend()
ChallengeSelectScene.title = "Challenges"
current_challenge = 1
function indexOf(array, value)
for i, v in ipairs(array) do
if v == value then
return i
end
end
return nil
end
function ChallengeSelectScene:new()
-- reload custom modules
initModules()
if table.getn(challenges) == 0 then
self.display_warning = true
current_challenge = 1
else
self.display_warning = false
if current_challenge > table.getn(challenges) then
current_challenge = 1
end
end
self.menu_state = {
challenge = current_challenge,
select = "challenge",
}
self.secret_inputs = {}
self.das = 0
DiscordRPC:update({
details = "In menus",
state = "Choosing a challenge",
largeImageKey = "ingame-000"
})
end
function ChallengeSelectScene:update()
switchBGM(nil) -- experimental
if self.das_up or self.das_down then
self.das = self.das + 1
else
self.das = 0
end
if self.das >= 15 then
self:changeOption(self.das_up and -1 or 1)
self.das = self.das - 4
end
DiscordRPC:update({
details = "In menus",
state = "Choosing a challenge",
largeImageKey = "ingame-000"
})
end
function ChallengeSelectScene:render()
love.graphics.draw(
backgrounds[0],
0, 0, 0,
0.5, 0.5
)
love.graphics.draw(misc_graphics["select_challenge"], 20, 40)
if self.display_warning then
love.graphics.setFont(font_3x5_3)
love.graphics.printf(
"You have no challenges",
80, 200, 480, "center"
)
love.graphics.setFont(font_3x5_2)
love.graphics.printf(
"Come back to this menu after getting more challenges. " ..
"Press any button to return to the main menu.",
80, 250, 480, "center"
)
return
end
if self.menu_state.select == "challenge" then
love.graphics.setColor(1, 1, 1, 0.5)
end
love.graphics.rectangle("fill", 20, 258, 240, 22)
if self.menu_state.select == "challenge" then
love.graphics.setColor(1, 1, 1, 0.25)
end
love.graphics.setColor(1, 1, 1, 1)
love.graphics.setFont(font_3x5_2)
for idx, challenge in pairs(challenges) do
if(idx >= self.menu_state.challenge-9 and idx <= self.menu_state.challenge+9) then
love.graphics.printf(challenge.name, 40, (260 - 20*(self.menu_state.challenge)) + 20 * idx, 200, "left")
end
end
-- challenge details
love.graphics.printf(challenges[self.menu_state.challenge].tagline, 340, 150, 200, "left")
love.graphics.printf(challenges[self.menu_state.challenge].description, 340, 250, 200, "left")
love.graphics.printf("Mode: "..challenges[self.menu_state.challenge].mode, 340, 350, 200, "left")
love.graphics.printf("Ruleset: "..challenges[self.menu_state.challenge].ruleset, 340, 380, 200, "left")
end
function ChallengeSelectScene:onInputPress(e)
if self.display_warning and e.input then
scene = TitleScene()
elseif e.type == "wheel" then
if e.x % 2 == 1 then
self:switchSelect()
end
if e.y ~= 0 then
self:changeOption(-e.y)
end
elseif e.input == "menu_decide" or e.scancode == "return" then
for idx, mode in pairs(game_modes) do
if mode.hash == challenges[self.menu_state.challenge].mode then
cur_mode = idx
break
end
end
for idx, ruleset in pairs(rulesets) do
if ruleset.hash == challenges[self.menu_state.challenge].ruleset then
cur_ruleset = idx
break
end
end
playSE("mode_decide")
saveConfig()
scene = ChallengeScene(
challenges[current_challenge],
rulesets[cur_ruleset]
)
elseif e.input == "up" or e.scancode == "up" then
self:changeOption(-1)
self.das_up = true
self.das_down = nil
elseif e.input == "down" or e.scancode == "down" then
self:changeOption(1)
self.das_down = true
self.das_up = nil
elseif e.input == "menu_back" or e.scancode == "delete" or e.scancode == "backspace" then
scene = TitleScene()
elseif e.input then
self.secret_inputs[e.input] = true
end
end
function ChallengeSelectScene:onInputRelease(e)
if e.input == "up" or e.scancode == "up" then
self.das_up = nil
elseif e.input == "down" or e.scancode == "down" then
self.das_down = nil
elseif e.input then
self.secret_inputs[e.input] = false
end
end
function ChallengeSelectScene:changeOption(rel)
self:changechallenge(rel)
playSE("cursor")
end
function ChallengeSelectScene:changechallenge(rel)
local len = table.getn(challenges)
self.menu_state.challenge = Mod1(self.menu_state.challenge + rel, len)
end
return ChallengeSelectScene

View File

@@ -1,6 +1,6 @@
local ModeSelectScene = Scene:extend() local ModeSelectScene = Scene:extend()
ModeSelectScene.title = "Game Start" ModeSelectScene.title = "Freeplay"
current_mode = 1 current_mode = 1
current_ruleset = 1 current_ruleset = 1
@@ -108,6 +108,7 @@ function ModeSelectScene:render()
love.graphics.printf(ruleset.name, 360, (260 - 20*(self.menu_state.ruleset)) + 20 * idx, 160, "left") love.graphics.printf(ruleset.name, 360, (260 - 20*(self.menu_state.ruleset)) + 20 * idx, 160, "left")
end end
end end
love.graphics.printf(game_modes[self.menu_state.mode].tagline, 5, 5, 600, "left")
end end
function ModeSelectScene:onInputPress(e) function ModeSelectScene:onInputPress(e)

View File

@@ -5,6 +5,7 @@ TitleScene.restart_message = false
local main_menu_screens = { local main_menu_screens = {
ModeSelectScene, ModeSelectScene,
ChallengeSelectScene,
SettingsScene, SettingsScene,
CreditsScene, CreditsScene,
ExitScene, ExitScene,
@@ -34,6 +35,21 @@ local mainmenuidle = {
"This is probably the longest RPC string out of every possible RPC string that can be displayed." "This is probably the longest RPC string out of every possible RPC string that can be displayed."
} }
local menusplash = {
"Welcome to Cambridge!",
"Get ready to put the block!",
"Also try Master of Blocks!",
"Also try Shiromino!",
"1 year in the making!",
"haileyjunk!",
"WOOOOAAAAAHHH!!!!!"
}
local currentSplash = menusplash[math.random(#menusplash)]
local now = os.date("t")
showDebugKeys = false
function TitleScene:new() function TitleScene:new()
self.main_menu_state = 1 self.main_menu_state = 1
self.frames = 0 self.frames = 0
@@ -47,6 +63,12 @@ function TitleScene:new()
largeImageKey = "1year", largeImageKey = "1year",
largeImageText = version.." | Thanks for 1 year!" largeImageText = version.." | Thanks for 1 year!"
}) })
if now.month == 12 then
DiscordRPC:update({
largeImageKey = "snow"
})
end
end end
function TitleScene:update() function TitleScene:update()
@@ -79,7 +101,7 @@ function TitleScene:render()
460, 170, 0, 460, 170, 0,
2, 2 2, 2
) )
love.graphics.printf("Thanks for 1 year!", 430, 280, 160, "center") love.graphics.printf(currentSplash, 390, 280, 320, "center", 0, 0.75, 0.75)
love.graphics.setFont(font_3x5_2) love.graphics.setFont(font_3x5_2)
love.graphics.setColor(1, 1, 1, self.snow_bg_opacity) love.graphics.setColor(1, 1, 1, self.snow_bg_opacity)
@@ -106,6 +128,11 @@ function TitleScene:render()
for i, screen in pairs(main_menu_screens) do for i, screen in pairs(main_menu_screens) do
love.graphics.printf(screen.title, 40, 280 + 20 * i, 120, "left") love.graphics.printf(screen.title, 40, 280 + 20 * i, 120, "left")
end end
if showDebugKeys then
love.graphics.print("DEBUG KEYS\n\nF3+S: Get new splash message\nF3+R: Restart\nF3+I: Toggle this")
end
end end
function TitleScene:changeOption(rel) function TitleScene:changeOption(rel)
@@ -113,7 +140,10 @@ function TitleScene:changeOption(rel)
self.main_menu_state = (self.main_menu_state + len + rel - 1) % len + 1 self.main_menu_state = (self.main_menu_state + len + rel - 1) % len + 1
end end
function TitleScene:onInputPress(e) function TitleScene:onInputPress(e)
local debugkey = love.keyboard.isDown("f3")
if e.input == "menu_decide" or e.scancode == "return" then if e.input == "menu_decide" or e.scancode == "return" then
playSE("main_decide") playSE("main_decide")
scene = main_menu_screens[self.main_menu_state]() scene = main_menu_screens[self.main_menu_state]()
@@ -125,6 +155,25 @@ function TitleScene:onInputPress(e)
playSE("cursor") playSE("cursor")
elseif e.input == "menu_back" or e.scancode == "backspace" or e.scancode == "delete" then elseif e.input == "menu_back" or e.scancode == "backspace" or e.scancode == "delete" then
love.event.quit() love.event.quit()
-- small debug feature, press f3+s to get a new splash message
elseif e.scancode == "s" then
if debugkey then
currentSplash = menusplash[math.random(#menusplash)]
playSE("main_decide")
end
elseif e.scancode == "r" then
if debugkey then
love.event.quit("restart")
end
elseif e.scancode == "i" then
if debugkey then
if showDebugKeys then
showDebugKeys = false
else
showDebugKeys = true
end
end
-- no winter easter egg for now -- no winter easter egg for now
--[[ --[[
else else

View File

@@ -0,0 +1,26 @@
require 'funcs'
local GameMode = require 'tetris.modes.gamemode'
local Piece = require 'tetris.components.piece'
local Grid = require 'tetris.components.grid'
local Randomizer = require 'tetris.randomizers.randomizer'
local Bag7Randomizer = require 'tetris.randomizers.bag7noI'
local MarathonGF = require 'tetris.modes.marathon_gf'
local TetrsChallenge = MarathonGF:extend()
TetrsChallenge.name = "Tetrs"
TetrsChallenge.hash = "Tetrs"
TetrsChallenge.mode = "MarathonGF"
TetrsChallenge.ruleset = "Standard"
TetrsChallenge.tagline = "Where's the long bar? Seriously, I can't find it."
TetrsChallenge.description = "Complete a 150-line Marathon...without the I piece!"
function TetrsChallenge:new()
TetrsChallenge.super:new()
self.randomizer = Bag7Randomizer()
self.next_queue_length = 6
end
return TetrsChallenge

View File

@@ -0,0 +1,23 @@
-- currently you need to require and extend the gamemode you're making a challenge out of
require 'funcs'
local GameMode = require 'tetris.modes.gamemode'
local Piece = require 'tetris.components.piece'
local Grid = require 'tetris.components.grid'
local Randomizer = require 'tetris.randomizers.randomizer'
local BagRandomizer = require 'tetris.randomizers.bag'
local MarathonGF = require 'tetris.modes.marathon_gf'
local Challenge = GameMode:extend()
Challenge.name = "A really cool challenge name"
Challenge.hash = ""
Challenge.mode = ""
Challenge.ruleset = ""
Challenge.tagline = "Are you up for this challenge?"
Challenge.description = "Complete a mode with a specific ruleset and idk they did some other stupid things too lol"
return Challenge

View File

@@ -0,0 +1,26 @@
require 'funcs'
local GameMode = require 'tetris.modes.gamemode'
local Piece = require 'tetris.components.piece'
local Grid = require 'tetris.components.grid'
local Randomizer = require 'tetris.randomizers.randomizer'
local Bag7Randomizer = require 'tetris.randomizers.bag7noI'
local MarathonGF = require 'tetris.modes.marathon_gf'
local TetrsChallenge = MarathonGF:extend()
TetrsChallenge.name = "Another mode"
TetrsChallenge.hash = "Tetrs2"
TetrsChallenge.mode = "MarathonGF"
TetrsChallenge.ruleset = "Standard"
TetrsChallenge.tagline = "Hey look! The feature works!"
TetrsChallenge.description = "This is just a clone of Tetrs to test out the challenge details feature."
function TetrsChallenge:new()
TetrsChallenge.super:new()
self.randomizer = Bag7Randomizer()
self.next_queue_length = 6
end
return TetrsChallenge

View File

@@ -0,0 +1,19 @@
-- for the pre-packaged/example challenge tetrs
local Randomizer = require 'tetris.randomizers.randomizer'
local Bag7NoIRandomizer = Randomizer:extend()
function Bag7NoIRandomizer:initialize()
self.bag = {"J", "L", "O", "S", "T", "Z"}
end
function Bag7NoIRandomizer:generatePiece()
if next(self.bag) == nil then
self.bag = {"J", "L", "O", "S", "T", "Z"}
end
local x = math.random(table.getn(self.bag))
return table.remove(self.bag, x)
end
return Bag7NoIRandomizer