Compare commits

...

15 Commits

Author SHA1 Message Date
--global
bfbba75f17 made the experience feel closer to arcade stackers 2022-03-31 23:27:22 -04:00
--global
27e699841e Fixed a graphical issue in Survival A2 when getting torikanned 2022-03-31 23:00:39 -04:00
--global
fac8c6584e Added batch scripts to start the game on Windows 2022-03-10 22:36:21 -05:00
Oshisaure
9e447d51a7 Merge pull request #57 from jjdelvalle/master
Include complete path when printing screenshot info
2022-03-03 19:29:48 +00:00
JDV
4dfa234bc3 Include complete path when printing screenshot info 2022-03-03 20:27:41 +01:00
Ishaan Bhardwaj
92d67968f5 Tiny UI feature added to the title screen.
If you load a custom block skin, the title screen will use your skin to draw the logo.
2022-02-07 20:39:26 -05:00
Ishaan Bhardwaj
d68bd13d2a LOVE 11.3 notice
Reminder that Windows is unaffected by this, because Windows releases come bundled with the correct version, and the bleeding edge source includes the correct version of LOVE for Windows
2022-01-28 22:22:05 -05:00
Ishaan Bhardwaj
a84335646d Fix two bugs with Marathon A3 grading
S4 now correctly has 3 internal grades instead of 4
You can get a green-line GM
2022-01-28 20:51:25 -05:00
Ishaan Bhardwaj
d46973f12d Fixed color scheme setting not applying to active piece 2021-12-18 21:30:19 -05:00
Ishaan Bhardwaj
d4360b3662 Fixed the replay system's interaction with secret inputs 2021-12-09 23:00:20 -05:00
Ishaan Bhardwaj
06225bd35a Fixed an issue where replays played in the menu could save a duplicate copy 2021-12-09 22:21:48 -05:00
Ishaan Bhardwaj
e68238cbce Fixed disabling saving replays 2021-12-09 22:00:13 -05:00
Ishaan Bhardwaj
83e197b5d6 Slight RPC change to the selection menus 2021-12-09 21:51:41 -05:00
Ishaan Bhardwaj
1c0b73987d Rearrange sliders on the game settings menu 2021-12-09 21:48:39 -05:00
Ishaan Bhardwaj
afe6a43dab Rearrange game settings, add toggle for replay saving 2021-12-09 21:44:18 -05:00
21 changed files with 130 additions and 43 deletions

View File

@@ -26,13 +26,13 @@ All assets needed are bundled with the executable.
#### Bleeding edge
If you want the bleeding edge version, download [this](https://github.com/MillaBasset/cambridge/archive/master.zip).
If you want the bleeding edge version, download [this](https://github.com/MillaBasset/cambridge/archive/master.zip). Extract the ZIP to a folder of your choosing.
Extract the ZIP, open a Command Prompt at the folder you extracted Cambridge to, then run this command:
Assuming you're on a 64-bit system, you can double-click `start_win64.bat` to run the game. If that doesn't work, open a Command Prompt where you extracted Cambridge and run:
dist\windows\love.exe .
Alternatively, if you're on a 32-bit system, run this instead:
If you're on a 32-bit system, you'll want to double-click `start_win32.bat`. If that doesn't work, run this instead:
dist\win32\love.exe .
@@ -42,7 +42,7 @@ Then, check the mod pack section at the bottom of this page.
### 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.3, because it won't work with earlier or later versions!**
#### Downloading a release

View File

@@ -20,6 +20,7 @@ backgrounds = {
love.graphics.newImage("res/backgrounds/1800.png"),
love.graphics.newImage("res/backgrounds/1900.png"),
title = love.graphics.newImage("res/backgrounds/title.png"),
title_no_icon = love.graphics.newImage("res/backgrounds/title-no-icon.jpg"),
title_night = love.graphics.newImage("res/backgrounds/title-night.jpg"),
snow = love.graphics.newImage("res/backgrounds/snow.png"),
input_config = love.graphics.newImage("res/backgrounds/options-input.png"),

View File

@@ -39,7 +39,7 @@ function initConfig()
else
if config.current_mode then current_mode = config.current_mode end
if config.current_ruleset then current_ruleset = config.current_ruleset end
scene = TitleScene()
scene = ArcadeScene()
end
end

View File

@@ -103,6 +103,9 @@ function love.keypressed(key, scancode)
scene = InputConfigScene()
switchBGM(nil)
loadSave()
elseif scancode == "f8" and scene.title == "Arcade" then
scene = TitleScene()
playSE("mode_decide")
-- secret sound playing :eyes:
elseif scancode == "f8" and scene.title == "Title" then
config.secret = not config.secret
@@ -118,7 +121,7 @@ function love.keypressed(key, scancode)
love.filesystem.remove("ss")
love.filesystem.createDirectory("ss")
end
print("Saving screenshot as "..ss_name)
print("Saving screenshot as "..love.filesystem.getSaveDirectory().."/"..ss_name)
GLOBAL_CANVAS:newImageData():encode("png", ss_name)
-- function keys are reserved
elseif string.match(scancode, "^f[1-9]$") or string.match(scancode, "^f[1-9][0-9]+$") then

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 KiB

View File

@@ -8,6 +8,7 @@ function Scene:render() end
function Scene:onInputPress() end
function Scene:onInputRelease() end
ArcadeScene = require "scene.arcade"
ExitScene = require "scene.exit"
GameScene = require "scene.game"
ReplayScene = require "scene.replay"

52
scene/arcade.lua Normal file
View File

@@ -0,0 +1,52 @@
local ArcadeScene = Scene:extend()
ArcadeScene.title = "Arcade"
function ArcadeScene:new()
self.frames = 0
DiscordRPC:update({
details = "In menus",
state = "Waiting for a credit",
largeImageKey = "icon2",
largeImageText = version
})
end
local block_offsets = {
{color = "M", x = 0, y = 0},
{color = "G", x = 32, y = 0},
{color = "Y", x = 64, y = 0},
{color = "B", x = 0, y = 32},
{color = "O", x = 0, y = 64},
{color = "C", x = 32, y = 64},
{color = "R", x = 64, y = 64}
}
function ArcadeScene:update()
self.frames = self.frames + 1
end
function ArcadeScene:render()
love.graphics.setFont(font_3x5_3)
love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw(
backgrounds["title_no_icon"],
0, 0, 0,
0.5, 0.5
)
for _, b in ipairs(block_offsets) do
love.graphics.draw(
blocks["2tie"][b.color],
272 + b.x, 144 + b.y, 0,
2, 2
)
end
love.graphics.printf("CAMBRIDGE: THE OPEN SOURCE ARCADE STACKER", 0, 256, 640, "center")
love.graphics.setFont(font_3x5_2)
love.graphics.setColor(1, 1, 1, 1 - (math.floor(self.frames / 60) % 2))
love.graphics.printf("Insert 1 credit(s)", 0, 416, 640, "center")
end
return ArcadeScene

View File

@@ -5,7 +5,7 @@ CreditsScene.title = "Credits"
function CreditsScene:new()
self.frames = 0
-- higher = slower
self.scroll_speed = 1.85
self.scroll_speed = 1.8
switchBGM("credit_roll", "gm3")
DiscordRPC:update({
@@ -40,14 +40,14 @@ function CreditsScene:render()
love.graphics.setFont(font_3x5_4)
love.graphics.print("Cambridge Credits", 320, 500 - offset)
love.graphics.print("THANK YOU\nFOR PLAYING!", 320, math.max(2030 - offset, 240))
love.graphics.print("THANK YOU\nFOR PLAYING!", 320, math.max(2050 - offset, 240))
love.graphics.setFont(font_3x5_3)
love.graphics.print("Game Developers", 320, 550 - offset)
love.graphics.print("Project Heads", 320, 640 - offset)
love.graphics.print("Notable Game Developers", 320, 750 - offset)
love.graphics.print("Special Thanks", 320, 1000 - offset)
love.graphics.print("- Milla", 320, math.max(2110 - offset, 320))
love.graphics.print("- Milla", 320, math.max(2130 - offset, 320))
love.graphics.setFont(font_3x5_2)
love.graphics.print("Oshisaure\nJoe Zeng", 320, 590 - offset)
@@ -66,7 +66,7 @@ function CreditsScene:render()
"CylinderKnot\neightsixfivezero\nEricICX\nGesomaru\n" ..
"gizmo4487\nJBroms\nKirby703\nKitaru\n" ..
"M1ssing0\nMattMayuga\nMyPasswordIsWeak\n" ..
"Nikki Karissa\noffwo\nOliver\nPineapple\npokemonfan1937\n" ..
"Nikki Karissa\nnim\noffwo\nOliver\nPineapple\npokemonfan1937\n" ..
"Pyra Neoxi\nRDST64\nRocketLanterns\nRustyFoxxo\n" ..
"saphie\nShelleloch\nSimon\nstratus\nSuper302\n" ..
"switchpalacecorner\nterpyderp\nTetrian22\nTetro48\nThatCookie\n" ..

View File

@@ -9,6 +9,7 @@ function GameScene:new(game_mode, ruleset, inputs)
self.retry_ruleset = ruleset
self.secret_inputs = inputs
self.game = game_mode(self.secret_inputs)
self.game.secret_inputs = inputs
self.ruleset = ruleset(self.game)
self.game:initialize(self.ruleset)
self.inputs = {
@@ -40,6 +41,8 @@ function GameScene:update()
self.game:update(inputs, self.ruleset)
self.game.grid:update()
DiscordRPC:update({
details = self.game.rpc_details,
state = self.game.name,
largeImageKey = "ingame-"..self.game:getBackground().."00"
})
end
@@ -61,18 +64,19 @@ function GameScene:onInputPress(e)
highscore_hash = self.game.hash .. "-" .. self.ruleset.hash
submitHighscore(highscore_hash, highscore_entry)
self.game:onExit()
scene = e.input == "retry" and GameScene(self.retry_mode, self.retry_ruleset, self.secret_inputs) or ModeSelectScene()
scene = ArcadeScene()
-- e.input == "retry" and GameScene(self.retry_mode, self.retry_ruleset, self.secret_inputs) or ModeSelectScene()
elseif e.input == "retry" then
switchBGM(nil)
self.game:onExit()
scene = GameScene(self.retry_mode, self.retry_ruleset, self.secret_inputs)
scene = ArcadeScene() --GameScene(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 = ModeSelectScene()
scene = ArcadeScene() -- ModeSelectScene()
elseif e.input and string.sub(e.input, 1, 5) ~= "menu_" then
self.inputs[e.input] = true
end

View File

@@ -13,11 +13,12 @@ ConfigScene.options = {
{"world_reverse", "A Button Rotation", false, {"Left", "Auto", "Right"}},
{"spawn_positions", "Spawn Positions", false, {"Per ruleset", "In field", "Out of field"}},
{"display_gamemode", "Debug Info", false, {"On", "Off"}},
{"das_last_key", "DAS Last Key", false, {"Off", "On"}},
{"save_replay", "Save Replays", false, {"On", "Off"}},
{"smooth_movement", "Smooth Piece Drop", false, {"On", "Off"}},
{"synchroes_allowed", "Synchroes", false, {"Per ruleset", "On", "Off"}},
{"diagonal_input", "Diagonal Input", false, {"On", "Off"}},
{"das_last_key", "DAS Last Key", false, {"Off", "On"}},
{"buffer_lock", "Buffer Drop Type", false, {"Off", "Hold", "Tap"}},
{"synchroes_allowed", "Synchroes", false, {"Per ruleset", "On", "Off"}},
{"sfx_volume", "SFX", true, "sfxSlider"},
{"bgm_volume", "BGM", true, "bgmSlider"},
}
@@ -33,8 +34,8 @@ function ConfigScene:new()
state = "Changing game settings",
})
self.sfxSlider = newSlider(165, 400, 225, config.sfx_volume * 100, 0, 100, function(v) config.sfx_volume = v / 100 end, {width=20, knob="circle", track="roundrect"})
self.bgmSlider = newSlider(465, 400, 225, config.bgm_volume * 100, 0, 100, function(v) config.bgm_volume = v / 100 end, {width=20, knob="circle", track="roundrect"})
self.sfxSlider = newSlider(165, 420, 225, config.sfx_volume * 100, 0, 100, function(v) config.sfx_volume = v / 100 end, {width=20, knob="circle", track="roundrect"})
self.bgmSlider = newSlider(465, 420, 225, config.bgm_volume * 100, 0, 100, function(v) config.bgm_volume = v / 100 end, {width=20, knob="circle", track="roundrect"})
end
function ConfigScene:update()
@@ -58,7 +59,7 @@ function ConfigScene:render()
if not ConfigScene.options[self.highlight][3] then
love.graphics.rectangle("fill", 25, 98 + self.highlight * 20, 170, 22)
else
love.graphics.rectangle("fill", 65 + (1+self.highlight-#self.options) * 300, 342, 215, 33)
love.graphics.rectangle("fill", 65 + (1+self.highlight-#self.options) * 300, 362, 215, 33)
end
love.graphics.setFont(font_3x5_2)
@@ -75,8 +76,8 @@ function ConfigScene:render()
love.graphics.setColor(1, 1, 1, 1)
love.graphics.setFont(font_3x5_3)
love.graphics.print("SFX Volume: " .. math.floor(self.sfxSlider:getValue()) .. "%", 75, 345)
love.graphics.print("BGM Volume: " .. math.floor(self.bgmSlider:getValue()) .. "%", 375, 345)
love.graphics.print("SFX Volume: " .. math.floor(self.sfxSlider:getValue()) .. "%", 75, 365)
love.graphics.print("BGM Volume: " .. math.floor(self.bgmSlider:getValue()) .. "%", 375, 365)
love.graphics.setColor(1, 1, 1, 0.75)
self.sfxSlider:draw()

View File

@@ -78,7 +78,7 @@ function KeyConfigScene:onInputPress(e)
if not config.input then config.input = {} end
config.input.keys = self.new_input
saveConfig()
scene = had_config and InputConfigScene() or TitleScene()
scene = had_config and InputConfigScene() or ArcadeScene()
elseif e.scancode == "delete" or e.scancode == "backspace" then
-- retry
self.input_state = 1

View File

@@ -4,17 +4,18 @@ local ReplayScene = Scene:extend()
ReplayScene.title = "Replay"
function ReplayScene:new(replay, game_mode, ruleset, inputs)
function ReplayScene:new(replay, game_mode, ruleset)
config.gamesettings = replay["gamesettings"]
love.math.setRandomSeed(replay["random_low"], replay["random_high"])
love.math.setRandomState(replay["random_state"])
self.retry_replay = replay
self.retry_mode = game_mode
self.retry_ruleset = ruleset
self.secret_inputs = inputs
self.secret_inputs = replay["secret_inputs"]
self.game = game_mode(self.secret_inputs)
self.game.save_replay = false
self.ruleset = ruleset(self.game)
self.game:initialize(self.ruleset, true)
self.game:initialize(self.ruleset)
self.inputs = {
left=false,
right=false,
@@ -51,6 +52,8 @@ function ReplayScene:update()
self.game:update(input_copy, self.ruleset)
self.game.grid:update()
DiscordRPC:update({
details = "Viewing a replay",
state = self.game.name,
largeImageKey = "ingame-"..self.game:getBackground().."00"
})
end

View File

@@ -121,12 +121,15 @@ function ReplaySelectScene:render()
love.graphics.setFont(font_3x5_2)
for idx, replay in ipairs(replays) do
if(idx >= self.menu_state.replay-9 and idx <= self.menu_state.replay+9) then
local display_string = os.date("%c", replay["timestamp"]).." "..replay["mode"].." "..replay["ruleset"]
local display_string = os.date("%c", replay["timestamp"]).." - "..replay["mode"].." - "..replay["ruleset"]
if replay["level"] ~= nil then
display_string = display_string.." Level: "..replay["level"]
display_string = display_string.." - Level: "..replay["level"]
end
if replay["timer"] ~= nil then
display_string = display_string.." Time: "..formatTime(replay["timer"])
display_string = display_string.." - Time: "..formatTime(replay["timer"])
end
if #display_string > 75 then
display_string = display_string:sub(1, 75) .. "..."
end
love.graphics.printf(display_string, 6, (260 - 20*(self.menu_state.replay)) + 20 * idx, 640, "left")
end
@@ -167,8 +170,7 @@ function ReplaySelectScene:onInputPress(e)
scene = ReplayScene(
replays[self.menu_state.replay],
mode,
rules,
replays[self.menu_state.replay]["secret_inputs"]
rules
)
elseif e.input == "up" or e.scancode == "up" then
self:changeOption(-1)

View File

@@ -86,7 +86,7 @@ function StickConfigScene:onInputPress(e)
if not config.input then config.input = {} end
config.input.joysticks = self.new_input
saveConfig()
scene = had_config and InputConfigScene() or TitleScene()
scene = had_config and InputConfigScene() or ArcadeScene()
elseif e.scancode == "delete" or e.scancode == "backspace" then
-- retry
self.input_state = 1

View File

@@ -60,18 +60,38 @@ function TitleScene:update()
else self.y_offset = 310 - self.frames end
end
local block_offsets = {
{color = "M", x = 0, y = 0},
{color = "G", x = 32, y = 0},
{color = "Y", x = 64, y = 0},
{color = "B", x = 0, y = 32},
{color = "O", x = 0, y = 64},
{color = "C", x = 32, y = 64},
{color = "R", x = 64, y = 64}
}
function TitleScene:render()
love.graphics.setFont(font_3x5_4)
love.graphics.setColor(1, 1, 1, 1 - self.snow_bg_opacity)
love.graphics.draw(
backgrounds["title"], -- title_night
backgrounds["title_no_icon"], -- title, title_night
0, 0, 0,
0.5, 0.5
)
-- 490, 192
for _, b in ipairs(block_offsets) do
love.graphics.draw(
blocks["2tie"][b.color],
490 + b.x, 192 + b.y, 0,
2, 2
)
end
--[[
love.graphics.draw(
misc_graphics["icon"],
460, 170, 0,
490, 192, 0,
2, 2
)
]]

1
start_win32.bat Normal file
View File

@@ -0,0 +1 @@
dist\win32\love.exe .

1
start_win64.bat Normal file
View File

@@ -0,0 +1 @@
dist\windows\love.exe .

View File

@@ -16,12 +16,11 @@ GameMode.hash = ""
GameMode.tagline = ""
GameMode.rollOpacityFunction = function(age) return 0 end
function GameMode:new(secret_inputs)
function GameMode:new()
self.replay_inputs = {}
self.random_low, self.random_high = love.math.getRandomSeed()
self.random_state = love.math.getRandomState()
self.secret_inputs = secret_inputs
self.save_replay = true
self.save_replay = config.gamesettings.save_replay == 1
self.grid = Grid(10, 24)
self.randomizer = Randomizer()
@@ -104,7 +103,7 @@ function GameMode:getSkin()
return "2tie"
end
function GameMode:initialize(ruleset, replay)
function GameMode:initialize(ruleset)
-- generate next queue
self.used_randomizer = (
table.equalvalues(
@@ -114,7 +113,6 @@ function GameMode:initialize(ruleset, replay)
self.randomizer or BagRandomizer(table.keys(ruleset.colourscheme))
)
self.ruleset = ruleset
self.save_replay = not replay
for i = 1, math.max(self.next_queue_length, 1) do
table.insert(self.next_queue, self:getNextPiece(ruleset))
end

View File

@@ -309,7 +309,7 @@ local mroll_points = {10, 20, 30, 100}
local grade_conversion = {
[0] = 0,
1, 2, 3, 4, 5, 5, 6, 6, 7, 7,
7, 8, 8, 8, 9, 9, 9, 10, 11, 12, 12,
7, 8, 8, 8, 9, 9, 9, 10, 11, 12,
12, 12, 13, 13, 14, 14, 15, 15, 16, 16,
17
}
@@ -354,8 +354,7 @@ function MarathonA3Game:getAggregateGrade()
return math.min(
self.section_cool_grade +
math.floor(self.roll_points / 100) +
grade_conversion[self.grade],
self.roll_frames > 3238 and 32 or 31
grade_conversion[self.grade]
)
end

View File

@@ -101,6 +101,7 @@ function SurvivalA2Game:onLineClear(cleared_row_count)
self.clear = true
if new_level < 999 then
self.game_over = true
return
end
end
self.level = new_level

View File

@@ -209,7 +209,7 @@ function Ruleset:initializePiece(
local colours
if table.equalvalues(
self.colourscheme, {"I", "J", "L", "O", "S", "T", "Z"}
table.keys(self.colourscheme), {"I", "J", "L", "O", "S", "T", "Z"}
) then
colours = ({self.colourscheme, ColourSchemes.Arika, ColourSchemes.TTC})[config.gamesettings.piece_colour]
else