This commit is contained in:
Hailey 2021-12-01 14:57:40 -05:00 committed by GitHub
commit b57153f7d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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