Compare commits

..

513 Commits

Author SHA1 Message Date
Ishaan Bhardwaj
9fbfbd5cda Refined and cleaned up buffer drop input functionality 2021-07-11 17:10:51 -04:00
Ishaan Bhardwaj
c5c4c4d95c Fixed delay curve calculation in Marathon 2020 2021-07-11 15:38:38 -04:00
Ishaan Bhardwaj
53c51c2062 Removed debug code for Marathon 2020 2021-07-11 14:57:14 -04:00
Ishaan Bhardwaj
e4eb9972e6 Fixed section COOL conditions for Marathon 2020 2021-07-11 14:55:45 -04:00
Ishaan Bhardwaj
7dbfe23059 Bump version to beta6 (also closes #19) 2021-07-11 14:04:22 -04:00
Ishaan Bhardwaj
61d5410f22 Prevent mapping the same key to two controls (fixes #20) 2021-07-11 13:53:27 -04:00
Ishaan Bhardwaj
2cb0416548 Shorten Death credit roll 2021-07-07 18:23:37 -04:00
83f3e297ce Changed "Notable Games" to "Other Notable Games" 2021-07-07 03:33:13 -04:00
Ishaan Bhardwaj
8fb01dc9a8 Another credits update 2021-07-05 22:09:06 -04:00
Ishaan Bhardwaj
61de3c6dbf Miscellaneous fixes to piece behavior in addition to fixing prev. commit 2021-06-26 16:27:33 -04:00
Ishaan Bhardwaj
3c718c38e4 Revert "Fixed a bug where pieces would check gravity before a block out"
This reverts commit d18c3e298d.
2021-06-26 14:55:18 -04:00
Ishaan Bhardwaj
d18c3e298d Fixed a bug where pieces would check gravity before a block out 2021-06-26 00:20:47 -04:00
Ishaan Bhardwaj
33934bfb53 Fixed some redundancies in the piece class and Survival A1 2021-06-20 15:20:09 -04:00
Ishaan Bhardwaj
3e2d107687 Small grade fix for Marathon A3 2021-06-19 13:31:45 -04:00
Ishaan Bhardwaj
312b95728d Fixed an issue with Survival A3 that prevented extension of the mode 2021-06-17 22:59:30 -04:00
Ishaan Bhardwaj
5013443302 Phantom Mania mechanic bugfixes 2021-06-17 19:10:21 -04:00
Ishaan Bhardwaj
a8ac8f5966 Whoops forgot a contributor, fixed 2021-06-15 21:47:38 -04:00
Ishaan Bhardwaj
a5032386e6 Small update to a contributor's name 2021-06-14 23:55:36 -04:00
Ishaan Bhardwaj
264255290d Credit bump! 2021-06-14 23:53:14 -04:00
Ishaan Bhardwaj
a5839bede2 Added another notable game 2021-06-14 23:28:27 -04:00
Ishaan Bhardwaj
4ebf24316a Added notable games that I think you should play 2021-06-14 23:25:32 -04:00
Ishaan Bhardwaj
f2acab4496 A few minor changes, read below
Clean up big pieces for a temporary hotfix, an overhaul soon to come
Refactored BGM and SE playing
Moved draw code completely into gamemode - mod makers can now control everything on screen
2021-06-09 20:15:37 -04:00
929069c1b6 Merge pull request #21 from Trixciel/master
Fixed ARE Cancelling when using a Sonic Drop RS
2021-06-07 23:12:58 -04:00
Trixciel
3f2b38f7b3 Fixed ARE Cancelling with Sonic Drop RS
Changed the code in a way that allows ARE Cancelling to work with rotation systems that use sonic drop and a locking soft drop.
2021-06-06 17:38:47 +02:00
Ishaan Bhardwaj
56fb5aebea Small cleanup to file info checking 2021-06-03 16:00:33 -04:00
Ishaan Bhardwaj
6c201596b0 Fixed O failing to rotate in CRS 2021-06-02 12:10:02 -04:00
Ishaan Bhardwaj
50466c5902 Fixed unary negation and to-string bigint metamethods 2021-05-29 19:48:34 -04:00
ae1231c47a Merge pull request #17 from nightmareci/master
Improved latency and performance
2021-05-27 09:34:46 -04:00
Ishaan Bhardwaj
366ac1d552 Update credits.lua 2021-05-23 17:37:38 -04:00
302353f716 Update README.md 2021-05-23 17:20:26 -04:00
nightmareci
7f550b629f Made start-of-line spacing all hard tabs 2021-05-23 11:57:04 -07:00
nightmareci
6b2252e6d9 Implemented custom love.run to get lower latency 2021-05-23 11:07:07 -07:00
Ishaan Bhardwaj
e1741440f2 Fixed an edge case with the last save commit 2021-05-22 21:42:14 -04:00
Ishaan Bhardwaj
c56f290921 Fixed a bug where the game would sometimes not save on macOS
Version bump to beta5.2
2021-05-22 21:19:33 -04:00
Ishaan Bhardwaj
86e975f929 Fixed up an edge case in immobile spin 2021-05-22 14:41:51 -04:00
Ishaan Bhardwaj
9f8e9a9778 Changed additive gravity behavior for main TGM modes 2021-05-21 15:34:50 -04:00
Ishaan Bhardwaj
62f9475fa9 Small cosmetic change to input config menus 2021-05-21 15:32:28 -04:00
Ishaan Bhardwaj
99d3732d00 Bump to v0.3-beta5.1, release tomorrow 2021-05-20 23:25:24 -04:00
Ishaan Bhardwaj
f5121b62e5 Added bigint comparison metamethods 2021-05-15 22:39:15 -04:00
Ishaan Bhardwaj
cbdbfa6633 Fixed a small cosmetic issue in Survival A1 2021-04-26 21:51:42 -04:00
Ishaan Bhardwaj
1b1abc9792 Fixed an issue with buffer lock inputs 2021-04-20 16:11:49 -04:00
Ishaan Bhardwaj
894e99e677 Cambridge has a logo now! 2021-04-16 22:14:59 -04:00
Ishaan Bhardwaj
d4b619da89 Fixed an edge case with last commit 2021-04-08 13:17:34 -04:00
Ishaan Bhardwaj
3766149cb7 Fixed a 0 ARR gravity bug 2021-04-08 11:55:36 -04:00
Ishaan Bhardwaj
449ca16bc4 Updated to be on rebrand 2021-04-01 14:11:38 -04:00
Ishaan Bhardwaj
71d76e8a6b Fixed Death torikan (why was this changed?) 2021-03-30 22:08:48 -04:00
Ishaan Bhardwaj
3bdc6e1b2d HOTFIX TO BETA5: Fixed another floorkick issue with ARS 2021-03-30 21:29:09 -04:00
Ishaan Bhardwaj
d9b6c85704 Fix up credits a bit, add new people 2021-03-28 10:03:27 -04:00
Ishaan Bhardwaj
5ce0686e1a Update version to beta5 2021-03-26 23:11:59 -04:00
Ishaan Bhardwaj
3cf496ba98 Fixed a Ti-ARS floorkick issue 2021-03-16 14:13:44 -04:00
Ishaan Bhardwaj
5ddc6ec561 Fixed a priority order bug with Ti-ARS and ACE-ARS 2021-03-11 20:16:23 -05:00
Ishaan Bhardwaj
b91ffc913b CRS no longer locks in midair 2021-03-11 15:29:24 -05:00
Ishaan Bhardwaj
ab445ff699 Cleaned up love.load 2021-03-11 09:24:19 -05:00
Ishaan Bhardwaj
7b7a255bf8 Fullscreen swap now persists between reboots 2021-03-11 08:33:05 -05:00
Ishaan Bhardwaj
57721ed35d Shrunk the bone coloring code 2021-03-10 16:30:45 -05:00
Ishaan Bhardwaj
8383d3f445 Debug print statement removal 2021-03-10 14:06:57 -05:00
Ishaan Bhardwaj
116284f31c Fixed colour scheme issues for non-standard piece sets 2021-03-10 13:58:08 -05:00
Ishaan Bhardwaj
2189e3a7b8 Made a previous fix to soft drop points obsolete w/ new fix 2021-03-10 13:30:29 -05:00
Ishaan Bhardwaj
b1d325b714 Fixed negative soft drop and hard drop points again
For finer control of piece drops, use GameMode:onPieceDrop
2021-03-09 16:35:57 -05:00
Ishaan Bhardwaj
4ab5e3747a Fixed an issue with the generic bag randomizer 2021-03-09 13:00:43 -05:00
Ishaan Bhardwaj
9761ead48f Fixed an odd bug where the score wouldn't reset in Big A2 2021-03-08 21:12:05 -05:00
Ishaan Bhardwaj
8dedc8a70e Cut down Big A2's size 2021-03-08 20:59:51 -05:00
Ishaan Bhardwaj
21769f21c8 Sakura removed from the main game, will be re-added after mass bugfix 2021-03-08 18:53:01 -05:00
Ishaan Bhardwaj
5cf26b4500 Merge branch 'master' of https://github.com/sashlilac/cambridge 2021-03-08 12:41:54 -05:00
Ishaan Bhardwaj
4b4a968632 Fixed a bone block drawing issue 2021-03-08 12:41:46 -05:00
Ishaan Bhardwaj
e0d98de50d The Discord server has been reopened! 2021-03-08 11:11:26 -05:00
Ishaan Bhardwaj
4992ea733c Made the bone block world sprite a bit brighter 2021-03-08 10:20:25 -05:00
Ishaan Bhardwaj
30ca434027 Fixed ACE-ARS to floorkick infinitely 2021-03-07 22:24:11 -05:00
Ishaan Bhardwaj
502a50d004 Merge pull request #16 from SashLilac/hat_handling
Fixed the handling of joystick hats.
2021-03-07 21:17:59 -05:00
Joe Z
36f5287a39 Fixed the hat input mapping. 2021-03-07 20:43:55 -05:00
Ishaan Bhardwaj
a9bbe4a08d Init hat handling 2021-03-07 16:42:33 -05:00
Ishaan Bhardwaj
ee431f5fd8 Revert "(Hopefully) Fixed an obscure bug with SOCD and joystick hats"
This did not fix it.
This reverts commit 36f2672e06.
2021-03-07 16:29:01 -05:00
Ishaan Bhardwaj
36f2672e06 (Hopefully) Fixed an obscure bug with SOCD and joystick hats 2021-03-07 16:20:43 -05:00
Ishaan Bhardwaj
6ecea7edb1 Fixed an issue where axes would not detect left or up 2021-03-07 16:03:02 -05:00
Ishaan Bhardwaj
dc764b9177 Fixed the timer in Sakura to be the correct value 2021-03-07 15:52:55 -05:00
Ishaan Bhardwaj
5a1494cb5a Fixed a timer display issue in Sakura 2021-03-07 15:52:24 -05:00
Ishaan Bhardwaj
684c4f5b78 Sakura stage time limit fix 2021-03-07 15:18:13 -05:00
Ishaan Bhardwaj
b568c0fe69 Removed the credit roll from AX 2021-03-07 09:49:07 -05:00
Ishaan Bhardwaj
2ea75cdfaf Fixed a corner case in the last commit 2021-03-06 22:13:38 -05:00
Ishaan Bhardwaj
1f0b43f1b7 ACTUALLY fixed negative drop points 2021-03-06 22:00:30 -05:00
Ishaan Bhardwaj
40bdc5ed99 Revert "Fixed negative drop points"
This commit didn't actually fix the issue.
This reverts commit 33f2a96ae8.
2021-03-06 21:54:36 -05:00
Ishaan Bhardwaj
33f2a96ae8 Fixed negative drop points 2021-03-06 21:39:13 -05:00
Ishaan Bhardwaj
846013ce7a Indentation fix in funcs.lua 2021-03-04 19:05:43 -05:00
Ishaan Bhardwaj
37c85adc75 Fixed clamping once more 2021-03-04 19:05:20 -05:00
Ishaan Bhardwaj
e7bb44deb4 Fixed clamping 2021-03-04 18:44:30 -05:00
Ishaan Bhardwaj
57518dc299 Removed some future features that I committed by accident 2021-03-04 15:18:32 -05:00
Ishaan Bhardwaj
0453a3db97 Fixed an issue where first piece IHS was possible when it shouldn't have been 2021-03-04 15:16:23 -05:00
Ishaan Bhardwaj
b85de17e51 Last LCD added to fix up line clear animations 2021-03-03 11:54:43 -05:00
Ishaan Bhardwaj
163b8f6cc5 Added a version display 2021-03-03 10:33:10 -05:00
Ishaan Bhardwaj
7250bee619 Ti randomizer no longer draws Z as first piece 2021-03-02 20:31:56 -05:00
Ishaan Bhardwaj
83de216408 Touched up screenshotting a bit 2021-03-01 20:37:44 -05:00
Ishaan Bhardwaj
ba235c8a41 Credits update <3 2021-02-28 18:40:53 -05:00
Ishaan Bhardwaj
ca18d090c9 Split keyboard and joystick input config screens 2021-02-25 14:41:13 -05:00
Ishaan Bhardwaj
a3a27d2566 Refactored joystick input handling 2021-02-24 16:58:42 -05:00
Ishaan Bhardwaj
b15cd9802f Updated DAS last key setting to not use hacky workaround
DAS last key is off by default
2021-02-22 21:43:01 -05:00
Ishaan Bhardwaj
4c4a818c5c Race 40 added to main game, PAIRS moved to modpack 2021-02-21 23:19:53 -05:00
Ishaan Bhardwaj
716de2814b More bigint type checks added
Strict checking is still off, however a check can be coerced
2021-02-21 20:38:16 -05:00
Ishaan Bhardwaj
bf19f49323 Add piece last rotated events 2021-02-21 10:48:15 -05:00
Ishaan Bhardwaj
1234e78354 Refactored immobile detection 2021-02-21 10:41:05 -05:00
Ishaan Bhardwaj
9129503d54 Fixed a sound effect handle with negative gravity 2021-02-21 10:08:58 -05:00
Ishaan Bhardwaj
eae58f11e9 Fixed a clipping issue with negative gravity
Gamemodes are able to define their own piece class behavior to override negative gravity handling
2021-02-21 10:05:09 -05:00
Ishaan Bhardwaj
3cf5daeb2e Piece class now handles negative gravity correctly 2021-02-21 09:52:50 -05:00
Ishaan Bhardwaj
1dfe68ccff onExit call for exiting prematurely 2021-02-19 15:58:00 -05:00
Ishaan Bhardwaj
8a459b68ba Allowed gamemode and ruleset objects to control each other
Also added GameMode:onExit(), which triggers on game exit or retry
2021-02-19 11:01:18 -05:00
Ishaan Bhardwaj
cb2b693bcb Fixed T-floorkick behavior in Ti/ACE ARS 2021-02-18 21:04:03 -05:00
Ishaan Bhardwaj
ef6d156d38 Turned draw offsets and above field offsets into function calls 2021-02-18 15:09:27 -05:00
Ishaan Bhardwaj
83e498534c Merge branch 'master' of https://github.com/sashlilac/cambridge 2021-02-18 12:01:05 -05:00
Ishaan Bhardwaj
8f19c73e2a Simultaneous keyboard and joystick inputs implemented!
Implements #9!!!
2021-02-18 12:00:57 -05:00
Ishaan Bhardwaj
e36b855ff7 The Discord server is no longer sponsored by the project. 2021-02-18 10:42:19 -05:00
Ishaan Bhardwaj
23b58951cb World rule Survival A2 has a lenient torikan time 2021-02-17 22:46:33 -05:00
Ishaan Bhardwaj
1d73916b7c Arika-SRS rulesets no longer lock immediately 2021-02-17 18:29:14 -05:00
Ishaan Bhardwaj
3947e9f02f Fix the drop block lock rotation with SRS 2021-02-17 17:31:16 -05:00
Ishaan Bhardwaj
99b15803ee Adjusted 0 ARR to trigger onPieceMove multiple times 2021-02-17 17:21:51 -05:00
Ishaan Bhardwaj
d350b25726 Forgot to set guideline SRS to always rotate 2021-02-17 14:52:05 -05:00
Ishaan Bhardwaj
44e4d00172 Merge branch 'master' of https://github.com/sashlilac/cambridge 2021-02-17 14:48:42 -05:00
Ishaan Bhardwaj
31e2529265 Upward kicks for SRS count toward rotation limit 2021-02-17 14:48:35 -05:00
Ishaan Bhardwaj
ea7c75f0b3 Cambridge Discord Server temp. decommissioned
Please contact Milla#7746 on Discord for help.
2021-02-17 10:45:07 -05:00
Ishaan Bhardwaj
714c6b5e99 Floorkicks reworked (read comments)
If not classic lock, upward kicks reset to the top of the tile
2021-02-16 23:28:54 -05:00
Ishaan Bhardwaj
6a5d5a9c88 Fixed some modes' getNextPiece routines 2021-02-16 17:02:13 -05:00
Ishaan Bhardwaj
03491ba151 Strategy mode endgame nerfed 2021-02-16 16:57:31 -05:00
Ishaan Bhardwaj
6e22e3d15b Ti-ARS autolock fix 2021-02-16 16:19:51 -05:00
Ishaan Bhardwaj
66ab5992ad Added onPieceMove/Rotate/Drop for gamemodes 2021-02-16 15:27:57 -05:00
Ishaan Bhardwaj
2c07c2a58c BigInt changes, read extended description
Disabled strict type checking, can be re-enabled in bleeding edge. (This is done so bigint ops run faster)
Added a negation method and updated the corresponding metamethod to use it.
2021-02-16 13:03:53 -05:00
Ishaan Bhardwaj
a4d3f3bffc Update README.md 2021-02-16 13:00:07 -05:00
Ishaan Bhardwaj
9ac60cbb5e afterLineClear func added and splits time draw fix 2021-02-15 12:26:52 -05:00
Ishaan Bhardwaj
cdd846c3e6 Made the volume sliders scroll more consistently 2021-02-13 22:00:45 -05:00
Ishaan Bhardwaj
33d260b753 Removed the print statement from A2 2021-02-12 23:31:13 -05:00
Ishaan Bhardwaj
1644fcdf8e Bigint exponentiation by 1 now returns a clone 2021-02-12 10:05:04 -05:00
Ishaan Bhardwaj
f3c1cf6e1f Fixed an issue where DS-World wouldn't harddrop 2021-02-11 22:11:35 -05:00
Ishaan Bhardwaj
06a8a2ebf7 Mandate safelock on 0 ARE rulesets/modes 2021-02-11 22:08:52 -05:00
Ishaan Bhardwaj
15354ce004 dropToBottom no longer resets lock delay
it's already handled by the rulesets anyhow
2021-02-11 21:20:23 -05:00
Ishaan Bhardwaj
af02cd3467 Classic lock (GB/NES-like) added as a gamemode var 2021-02-11 15:46:56 -05:00
Ishaan Bhardwaj
acb05918c1 Custom line clear animations 2021-02-10 23:10:10 -05:00
Ishaan Bhardwaj
b644c8e457 Revert "Default line clear animation set to fadeout"
Please, reminder to self, TEST YOUR COMMITS.
This reverts commit 288961e12a.
2021-02-10 22:46:58 -05:00
Ishaan Bhardwaj
288961e12a Default line clear animation set to fadeout 2021-02-10 22:41:07 -05:00
Ishaan Bhardwaj
a047e51681 Framework for custom line clear animations added
Colored fadeout is the default
2021-02-10 18:35:51 -05:00
Ishaan Bhardwaj
77f24f5ee5 Human readable bigint output changes 2021-02-10 12:45:55 -05:00
Ishaan Bhardwaj
32c2274bef Optimized bigint exponentiation (again) 2021-02-10 11:38:10 -05:00
Ishaan Bhardwaj
4920e5de1c Added another type check to the bigint 2021-02-10 11:15:56 -05:00
Ishaan Bhardwaj
8418fc8ab7 Update README.md 2021-02-10 10:32:18 -05:00
Ishaan Bhardwaj
711a5120f1 Update README.md 2021-02-10 10:31:52 -05:00
Ishaan Bhardwaj
e7c3c9446a Cambridge banner looks better on dark theme now
Courtesy of @sinefuse
2021-02-10 09:05:10 -05:00
Ishaan Bhardwaj
3ac39acd7a Removed bigint comparison metamethods (read below)
Use bigint.compare from now on
2021-02-09 12:27:57 -05:00
Ishaan Bhardwaj
d0505251b3 Spawn positions now ruleset dependent
Is configurable in options
2021-02-08 23:23:50 -05:00
Ishaan Bhardwaj
bb0fe2ac20 BigInt now has a digits method (read comments)
Kind of unnecessary but included for completeness
2021-02-08 16:56:06 -05:00
Ishaan Bhardwaj
986ebac47f BigInt division fixed 2021-02-08 16:07:48 -05:00
Ishaan Bhardwaj
9799147f96 Revert "BigInt fixes and optimization (read comments)"
Apparently division *still* isn't being handled correctly.
This reverts commit 1dda12e4be.
2021-02-08 14:53:19 -05:00
Ishaan Bhardwaj
1dda12e4be BigInt fixes and optimization (read comments)
Fixed a nasty division bug where intermediate operations could result in negative zero. Optimized exponentiation to use exponentiation by squaring.
2021-02-08 14:10:34 -05:00
Ishaan Bhardwaj
38947e00c0 Added a tostring function for bigints 2021-02-08 10:34:47 -05:00
Ishaan Bhardwaj
035f6dd7b4 Fixed big division when (big1 < big2) 2021-02-08 10:23:10 -05:00
Ishaan Bhardwaj
aa3eadc93d Update README.md 2021-02-08 09:00:51 -05:00
Ishaan Bhardwaj
cb6962825f Update package.bat script 2021-02-07 20:50:27 -05:00
Ishaan Bhardwaj
b5e7ce5be6 Grid outline draw refactorization 2021-02-05 22:13:10 -05:00
Ishaan Bhardwaj
1ccd6a09d3 Gamemodes have a default (empty) name 2021-02-05 21:44:29 -05:00
Ishaan Bhardwaj
5a074f77cf Adjusted how DAS cut subtracts from the counter 2021-02-03 16:50:03 -05:00
Ishaan Bhardwaj
81677221f1 Fixed 0 next queue modes 2021-02-03 11:42:21 -05:00
Ishaan Bhardwaj
a998be6f7b Global vars suck. Nothing more 2021-02-02 22:30:28 -05:00
Ishaan Bhardwaj
9c1c8eea21 Added default high score retrieval method 2021-02-02 14:51:49 -05:00
Ishaan Bhardwaj
f022c6c4b7 Sakura no longer draws game over effect on completion 2021-02-01 15:58:30 -05:00
Ishaan Bhardwaj
38f3d23b95 More default methods for gamemodes provided 2021-02-01 15:41:43 -05:00
Ishaan Bhardwaj
816d27db39 Set default gravity for gamemode 2021-02-01 14:50:31 -05:00
Ishaan Bhardwaj
ce08ffd3da SRS-X fixed to use symmetric wallkicks 2021-01-30 22:28:34 -05:00
Ishaan Bhardwaj
f0e84a8874 SRS-X rotate lock reset behavior fixed 2021-01-30 16:54:09 -05:00
Ishaan Bhardwaj
5e02471fb4 SRS now has upgraded 180s 2021-01-30 16:49:52 -05:00
Oshisaure
fa2fe77081 Apparently macs don't have a printscreen key, screenshot bound to f12 now instead 2021-01-29 22:29:27 +00:00
Joe Z
682c4a485a Updated fonts. 2021-01-29 12:24:54 -05:00
Oshisaure
68760105cc Bound printscreen to saving screenshots 2021-01-29 04:13:17 +00:00
Ishaan Bhardwaj
e19da98ea1 Standard SRS now has correct amount of move resets 2021-01-28 21:19:47 -05:00
Ishaan Bhardwaj
e8904b92ed check_new_low doesn't exist! 2021-01-28 21:15:04 -05:00
Ishaan Bhardwaj
4f574e7716 Guideline SRS now specifies dependency 2021-01-28 21:13:31 -05:00
Ishaan Bhardwaj
f1528e8d71 Fixed the SRS variants from latest commit. 2021-01-28 21:05:36 -05:00
Joe Zeng
79a25c3954 Renamed Marathon AX4 to Survival AX, among other things. 2021-01-28 01:15:21 -05:00
Ishaan Bhardwaj
0f3883e18d Sakura ghost piece fix 2021-01-27 18:28:12 -05:00
Ishaan Bhardwaj
1acd0ec65a Holding a piece that would block you out now works 2021-01-27 13:29:53 -05:00
Ishaan Bhardwaj
b22f671409 2020, A2, A3 section time draw fixes 2021-01-25 22:26:55 -05:00
Ishaan Bhardwaj
0b6f62d50e Applied a fix for locking big pieces out of the grid 2021-01-25 16:34:22 -05:00
Ishaan Bhardwaj
086f327371 Large commit, read below
DAS Cut Delay added and configurable (like ARR and DAS)
BigInt lib added
IRS / IHS do not take effect when ARE = 0
Game now saves highscore correctly on game over
2021-01-24 14:55:35 -05:00
Ishaan Bhardwaj
3c83ae0bf4 Fixed stray ends 2021-01-23 13:50:40 -05:00
Ishaan Bhardwaj
450833b246 Instant ARR fix on grids not 10-wide 2021-01-23 11:35:07 -05:00
Ishaan Bhardwaj
8e7a5418dc Fixed how grade points decay in A2 and A3 2021-01-23 11:34:46 -05:00
Ishaan Bhardwaj
6609b642dc formatBigNum prettifier 2021-01-20 10:53:39 -05:00
Ishaan Bhardwaj
452879ebab Fixed Marathon A3 section times, read comments
Some modes may not launch currently, will fix
2021-01-20 10:53:22 -05:00
Ishaan Bhardwaj
70a827b477 fixed A2 point decay 2021-01-16 13:27:07 -05:00
Ishaan Bhardwaj
d281a732db fixed A2 M-roll reqs again 2021-01-16 12:57:20 -05:00
Ishaan Bhardwaj
01e91fbd93 Fixes issues with retrying modes with BGM 2021-01-16 09:34:41 -05:00
Ishaan Bhardwaj
ece853c9d3 Swapped opacity and brightness for hold color 2021-01-15 16:00:15 -05:00
Ishaan Bhardwaj
ea8d008370 Set piece opacity fixes 2021-01-15 15:46:28 -05:00
Ishaan Bhardwaj
e20eb048c8 Game over animation (customizable per mode) 2021-01-14 21:51:47 -05:00
Ishaan Bhardwaj
a33ca1af24 Fixed a bug where you could not get M-roll in A2 2021-01-14 19:34:02 -05:00
Ishaan Bhardwaj
664bca2282 Fixed a notorious ARR bug 2021-01-14 19:27:20 -05:00
Ishaan Bhardwaj
fc8fb8b66f Added immobile spin bonus toggle (read comments)
Use piece.spin in your onPieceLock method to check for a spin
2021-01-14 19:22:53 -05:00
Ishaan Bhardwaj
fc58e6e908 Square mode added as toggle
Other things may get toggles too
Immobile spins, cascade, credit roll?
2021-01-14 17:52:23 -05:00
Ishaan Bhardwaj
061f6f5164 Square mode update 2021-01-14 16:28:18 -05:00
Ishaan Bhardwaj
4e9cea7dda Another bottom SFX bug fix 2021-01-12 15:57:45 -05:00
Ishaan Bhardwaj
fa97216167 Minor piece bottom SFX fix 2021-01-12 15:20:22 -05:00
Ishaan Bhardwaj
3f8d68cc9d Small game / settings fix 2021-01-12 14:32:10 -05:00
Ishaan Bhardwaj
6639d73c1c Spawn positions are now configurable 2021-01-12 13:47:03 -05:00
Ishaan Bhardwaj
668f061077 Fixed drawing frame on non-standard grids 2021-01-11 22:40:48 -05:00
Ishaan Bhardwaj
cb70967b82 Default field graphic fix 2021-01-11 15:52:11 -05:00
Ishaan Bhardwaj
0c2ba5f0cc Custom field heights implemented 2021-01-11 15:46:43 -05:00
Ishaan Bhardwaj
6d07a3b820 Removed outdated functions 2021-01-11 15:27:18 -05:00
Ishaan Bhardwaj
2de13a97f0 10-wide graphic restored 2021-01-11 15:17:32 -05:00
Ishaan Bhardwaj
512c2149f0 Adjusted spawn x positions 2021-01-11 14:48:03 -05:00
Ishaan Bhardwaj
6fb19220b7 Marathon A1 is back to 10 wide 2021-01-10 23:00:03 -05:00
Ishaan Bhardwaj
08da67c434 Merge pull request #13 from SashLilac/arbitrary-widths
Init arbitrary widths functionality.
2021-01-10 22:59:05 -05:00
Joe Zeng
2d63ca8ee1 Changed row initialization to also use parametrized width. 2021-01-10 22:52:56 -05:00
Ishaan Bhardwaj
0f09d47e60 Init arbitrary widths 2021-01-10 22:40:13 -05:00
Ishaan Bhardwaj
9d44d1e771 Fixed big mode gravity being twice as big 2021-01-10 22:01:25 -05:00
Ishaan Bhardwaj
5d022f9037 Rulesets can offset next queue draws (read below)
A ruleset can now have offsets for where pieces should be drawn in queue
No rulesets use this *yet*
2021-01-10 16:42:48 -05:00
Ishaan Bhardwaj
818743fe77 No "RANDOM PIECES ACTIVE!" on Sakura for pentos 2021-01-10 16:31:48 -05:00
Ishaan Bhardwaj
f22424d671 Update README.md - loading custom assets 2021-01-10 13:39:28 -05:00
Ishaan Bhardwaj
dd6baf1fe6 Draw outline now has line clear anim 2021-01-10 11:41:34 -05:00
Ishaan Bhardwaj
11cf5a9d55 Spawn SE bugfix 2021-01-10 11:15:36 -05:00
Ishaan Bhardwaj
5642ed1326 Added a ruleset toggle for ARE. 2021-01-09 23:17:24 -05:00
Ishaan Bhardwaj
c0888c484f Fixed the first easter egg 2021-01-08 20:33:44 -05:00
Ishaan Bhardwaj
3ef3b193fd 3-tall pentoes spawn highest on 21 now 2021-01-08 17:16:15 -05:00
Ishaan Bhardwaj
0c2e3efd1a PAIRS anti-stall added 2021-01-08 16:46:19 -05:00
Ishaan Bhardwaj
5076adf022 Secret inputs fix 2021-01-08 13:59:42 -05:00
Ishaan Bhardwaj
1a75d983dc Corrected PAIRS big spawns 2021-01-07 20:53:36 -05:00
Ishaan Bhardwaj
5b8e9586bd Sakura bugfixes 2021-01-07 19:59:11 -05:00
Ishaan Bhardwaj
7d7dd8c3c2 Roll roll bugfixes 2021-01-07 19:52:36 -05:00
Ishaan Bhardwaj
29afdcecfc PAIRS I5 and U spawns fixed 2021-01-07 19:06:37 -05:00
Ishaan Bhardwaj
8b09833ae6 PAIRS added, with bugfixes 2021-01-07 18:42:49 -05:00
Ishaan Bhardwaj
64047eaf9c Slight randomizer logic change, PAIRS incoming 2021-01-07 16:53:46 -05:00
Ishaan Bhardwaj
125488b4d9 Can no longer buffer a hard drop when not allowed 2021-01-06 23:06:51 -05:00
Ishaan Bhardwaj
1fdd091456 Ruleset and randomizer refactoring (Read comments)
You can now specify an arbitrary number of pieces for a ruleset.
The randomizers will adjust accordingly.
Expect a pento ruleset in the modpack soon!
Also, gamemode skin selection has been refactored.
2021-01-06 22:53:44 -05:00
Ishaan Bhardwaj
ced40297cc Line clear anim part 3 2021-01-06 21:37:51 -05:00
Ishaan Bhardwaj
32f2a0b3e7 Line clear anim part 2 2021-01-06 18:01:56 -05:00
Ishaan Bhardwaj
dd5347ad8d (Beta) line clear animation 2021-01-06 16:56:44 -05:00
Ishaan Bhardwaj
b732ebb213 Credits scene no longer plays while not focused 2021-01-06 16:10:01 -05:00
Ishaan Bhardwaj
84634d6933 Added an option to control buffer locking.
You can now choose if you want a drop input
during ARE to lock the piece on the first frame it is active.
2021-01-06 16:06:17 -05:00
Ishaan Bhardwaj
0d13a9f236 Can send inputs from mode select to game
Warning: this may break some things
2021-01-05 21:59:50 -05:00
Ishaan Bhardwaj
45120bc9f7 Update README MacOS instructions 2021-01-05 08:59:22 -05:00
Ishaan Bhardwaj
57c7d9c4c3 v0.3-beta1: Sakura done 2021-01-04 18:01:29 -05:00
Ishaan Bhardwaj
9f52d8bf10 relocated non bgm to modpack 2021-01-04 14:43:39 -05:00
Ishaan Bhardwaj
57bd6a8286 Almost done with Sakura 2021-01-03 23:18:57 -05:00
Oshisaure
1a68cd8fce More work on sakura, Xray and colour block effects implemented. Added Grid:drawCustom() to handle custom opacity/tint effects. 2021-01-03 00:05:54 +00:00
Ishaan Bhardwaj
56baf46839 Sakura *should* be complete now, please bug-report 2021-01-02 14:31:53 -05:00
Ishaan Bhardwaj
305d07e10a Sakura beta v2.k 2021-01-02 14:10:01 -05:00
Ishaan Bhardwaj
8d954cabc2 Sakura Beta v2.j 2021-01-02 12:56:52 -05:00
Ishaan Bhardwaj
0281220ea0 Sakura Beta v2.i 2021-01-02 12:51:00 -05:00
Ishaan Bhardwaj
aef5d88d3f Sakura Beta v2.h 2021-01-02 12:36:26 -05:00
Ishaan Bhardwaj
3676f7697c Sakura Beta v2 2021-01-02 12:21:10 -05:00
Ishaan Bhardwaj
acb0eb1a71 Sakura mode beta 2020-12-30 15:19:53 -05:00
Ishaan Bhardwaj
a89bf05cab Fixed an issue with controllers on the menu 2020-12-29 22:55:51 -05:00
Ishaan Bhardwaj
8008315994 Condensed ARE canceling code a bit 2020-12-29 14:00:11 -05:00
Ishaan Bhardwaj
90f62cb7dd Refactored ARE cancel 2020-12-28 23:32:41 -05:00
Oshisaure
eaee5fc7f0 Tweaked rotation/manipulation behaviour on SRS rules.
Also changed order of operations to call onPieceRotate in Rulesets after actually rotating the piece.
2020-12-28 03:41:26 +00:00
Ishaan Bhardwaj
e3b038b5a7 A festive easter egg has arrived! (v0.2.6.1)
Good luck hunting for the egg!
2020-12-24 22:58:06 -05:00
Ishaan Bhardwaj
083693496e Grid piece placement conditions 2020-12-22 22:04:06 -05:00
Ishaan Bhardwaj
ba576dfc77 Allow sliders to be controlled with keyboard
Credits to Phoenix Flare
2020-12-22 14:43:59 -05:00
Ishaan Bhardwaj
e195ccd721 Marathon A3 fixes 2020-12-21 23:32:39 -05:00
Ishaan Bhardwaj
70f703eb2f Fixed piece fade out when paused 2020-12-21 16:20:25 -05:00
Ishaan Bhardwaj
dc4d4a8259 Credits now stops music when you exit the screen 2020-12-21 16:00:03 -05:00
Ishaan Bhardwaj
565510c7b2 Credits and credit roll music updated 2020-12-21 15:48:34 -05:00
Ishaan Bhardwaj
c26a3f37de Update README.md 2020-12-20 20:35:36 -05:00
Ishaan Bhardwaj
0c1ce2f717 Fix package script not packing slider lib 2020-12-20 20:06:16 -05:00
Ishaan Bhardwaj
f14ab2a328 BGM focus fix 2020-12-20 16:55:34 -05:00
Ishaan Bhardwaj
042dbd220b text was slightly off-center 2020-12-20 15:31:42 -05:00
Ishaan Bhardwaj
548612123a SFX and BGM are now separate sliders 2020-12-20 15:26:32 -05:00
Ishaan Bhardwaj
f4675da0b0 Unlock and fix BGM, add pause button 2020-12-20 15:08:53 -05:00
Ishaan Bhardwaj
511e9592bc Fixed next piece sounds not playing 2020-12-20 10:47:24 -05:00
Ishaan Bhardwaj
5f3990ff58 Small credits update 2020-12-20 10:35:05 -05:00
Ishaan Bhardwaj
50ff4adf27 Credits scene <3 2020-12-20 10:28:34 -05:00
Ishaan Bhardwaj
87b88f4b42 Refactored settings menus 2020-12-20 09:45:49 -05:00
Ishaan Bhardwaj
130c2ea403 Easier easter egg #2 2020-12-19 20:44:24 -05:00
Ishaan Bhardwaj
1ea304916e Made it easier to see the egg 2020-12-19 20:43:57 -05:00
Ishaan Bhardwaj
e26b094830 A little easter egg... 2020-12-19 20:31:14 -05:00
Ishaan Bhardwaj
bcb44725bf Cambridge RS fix lock in midair 2020-12-19 14:04:08 -05:00
Ishaan Bhardwaj
2990844c52 Adjusted tuning scene 2020-12-18 23:17:53 -05:00
Ishaan Bhardwaj
c343014d6f Tuning scene 2020-12-18 21:28:30 -05:00
Ishaan Bhardwaj
605add7e94 Added customizable DAS and ARR! (read comments)
This only applies to modes that allow it.
This feature does not apply to main modes (yet)
2020-12-18 21:25:09 -05:00
Ishaan Bhardwaj
d3b647ca71 Fixed certain rulesets locking in midair 2020-12-18 21:24:10 -05:00
Ishaan Bhardwaj
1101aa467d Smooth piece drop 2020-12-17 18:00:07 -05:00
Ishaan Bhardwaj
ce27a7ed18 Update Tetra Online README 2020-12-17 10:51:08 -05:00
Ishaan Bhardwaj
f31beffab8 Update release script 2020-12-16 22:47:56 -05:00
Ishaan Bhardwaj
2ff8fb5edc Modpack README update 2020-12-16 22:33:48 -05:00
Boshi
1bf8f91ef2 Displays current gamemode in game (toggle) 2020-12-16 22:21:26 -05:00
Ishaan Bhardwaj
ba5f78d5f1 Merge branch 'master' of https://github.com/sashlilac/cambridge 2020-12-14 22:44:16 -05:00
Ishaan Bhardwaj
f7c4908062 Added an option to disable diagonal input 2020-12-14 22:43:50 -05:00
Ishaan Bhardwaj
3aa5bae7be Tetra Online notice and stuff 2020-12-10 21:22:16 -05:00
Ishaan Bhardwaj
40a2e78280 Marathon 2020 section colour function fixed 2020-12-06 11:38:45 -05:00
Ishaan Bhardwaj
696da3fa3f Marathon 2020 colour function removed 2020-12-06 11:27:44 -05:00
Ishaan Bhardwaj
4afe9f2bd4 Major sound effect update (closes #7?)
Sound effects can still be changed, and #7 can still be reopened.
2020-12-05 20:30:59 -05:00
Ishaan Bhardwaj
1f686fb5d4 Ti-ARS: T can no longer floorkick the air 2020-12-05 18:32:06 -05:00
Ishaan Bhardwaj
f4779c9847 Added the ability to toggle next piece SFX 2020-12-05 17:32:15 -05:00
Ishaan Bhardwaj
06cbec4bc8 Guideline SRS kicks fixed 2020-12-05 17:15:28 -05:00
Ishaan Bhardwaj
668564ffb0 Revert "big a3! (but its buggy??)"
This reverts commit 513cd6ba90.
Hailey, please do not add modes.
2020-12-05 16:56:12 -05:00
Hailey
e6edeea3d1 Merge branch 'master' of https://github.com/SashLilac/cambridge 2020-12-05 12:50:45 +10:00
Hailey
513cd6ba90 big a3! (but its buggy??) 2020-12-05 12:49:57 +10:00
Ishaan Bhardwaj
1beef8f157 Guideline SRS has 180s now 2020-12-04 21:36:25 -05:00
Ishaan Bhardwaj
d3b2b4c2d9 Ruleset refactoring! 2020-12-04 20:36:11 -05:00
Ishaan Bhardwaj
2b8b9d5084 Reduced the sound volume a little bit. 2020-12-04 20:12:36 -05:00
Ishaan Bhardwaj
2728780c45 Raised the piece sound volume by a factor of 10. 2020-12-04 19:42:33 -05:00
Ishaan Bhardwaj
ca592a3bcf Changed piece sounds, added sound sources 2020-12-04 19:27:02 -05:00
Ishaan Bhardwaj
b6f4158d70 Fixed SRS infinity bug! 2020-12-04 16:51:53 -05:00
Ishaan Bhardwaj
e43f5c470a Renaming backgrounds 2020-12-04 16:32:29 -05:00
Ishaan Bhardwaj
7bcdc517c0 Revert "Merge pull request #11 from Rexxt/master"
Reverting this pull request for a few reasons:
The piece sounds were too quiet.
The piece landing sound was distasteful.
2020-12-04 16:22:22 -05:00
Ishaan Bhardwaj
1d30987f9a Merge pull request #11 from Rexxt/master
Uncopyrightening and making the game slightly friendlier to mod
2020-12-04 16:13:38 -05:00
Ishaan Bhardwaj
1dd46a11ef Fixed torikans giving you a green line 2020-12-04 15:41:44 -05:00
Ishaan Bhardwaj
935c7aa14c Default secret grade names 2020-12-04 15:16:13 -05:00
Ishaan Bhardwaj
aea115d953 ACE-SRS has correct number of resets 2020-12-04 11:22:32 -05:00
Ishaan Bhardwaj
3d5b33f41a Added ability to enable/disable synchroes
On by default in anything but world rulesets.
Gamemodes / rulesets can override this setting.
2020-12-04 10:57:43 -05:00
Mizu
29f07bb6ab Update piece sounds 2020-12-04 15:38:34 +01:00
Ishaan Bhardwaj
891f96e814 I broke the DAS switch functionality 2020-12-03 14:10:46 -05:00
Ishaan Bhardwaj
36837a3af5 Update main.lua 2020-12-03 13:45:23 -05:00
Ishaan Bhardwaj
01b0f9f618 DAS switch behavior implemented 2020-12-02 21:09:52 -05:00
Ishaan Bhardwaj
7c8c5bb11d Hide hold queue when hold is disabled 2020-12-02 13:41:47 -05:00
Ishaan Bhardwaj
acaa6bdbbf whoops forgot to not require socket 2020-12-01 11:58:29 -05:00
Ishaan Bhardwaj
c37757f592 Implement an axis timer (fixes #12) 2020-12-01 11:57:09 -05:00
Ishaan Bhardwaj
905e4bcc77 drawSectionTimesWithSecondary update 2020-12-01 11:56:44 -05:00
Ishaan Bhardwaj
d956647678 Core mode rebalancing 2020-12-01 11:56:28 -05:00
Ishaan Bhardwaj
10f032b49b Added more functionality to advanceOneFrame 2020-11-30 12:34:21 -05:00
Ishaan Bhardwaj
5590e6c89b Small DAS changes 2020-11-29 11:11:47 -05:00
Joe Z
0393396d74 Made instant DAS respect instant gravity. 2020-11-29 09:19:17 -05:00
Joe Zeng
8c1eaec1aa DAS priority reversal (#25)
* Reversed the priority of key presses when charging DAS.
* Made it an actual config option.
* Config should be false by default.
2020-11-28 23:29:46 -05:00
Ishaan Bhardwaj
957802a78e Fixed a minor bug in the scope of SA2's line 2020-11-27 23:21:59 -05:00
Ishaan Bhardwaj
169a4e4d2f AX4 no longer shows timer in the roll 2020-11-22 10:39:42 -05:00
Ishaan Bhardwaj
48aee18340 Fix I wallkicks in ARS rules 2020-11-21 23:29:06 -05:00
Ishaan Bhardwaj
7b496d9412 Ti and ACE floorkick fix 2020-11-21 21:48:45 -05:00
Ishaan Bhardwaj
7abb861446 Hard drop can ARE cancel now 2020-11-21 16:29:24 -05:00
Ishaan Bhardwaj
21f8769228 Made ARE canceling also cancel LCD 2020-11-20 11:29:46 -05:00
Ishaan Bhardwaj
44423fd2e8 Made ARE canceling less slippery (again) 2020-11-19 22:22:43 -05:00
Ishaan Bhardwaj
351fb4cfe9 Added the functionality to draw only an outline of the stack 2020-11-18 12:17:04 -05:00
Ishaan Bhardwaj
103f04ceaa added a misc function 2020-11-17 21:52:20 -05:00
Ishaan Bhardwaj
88d2f0d8d1 Made ARE canceling more consistent. 2020-11-17 13:50:38 -05:00
Ishaan Bhardwaj
e100289c82 Made ARE canceling less slippery 2020-11-16 22:23:05 -05:00
Ishaan Bhardwaj
e38da49180 ARE canceling 2020-11-16 21:16:59 -05:00
Ishaan Bhardwaj
b03473d2fe IRS fix 2020-11-16 12:51:21 -05:00
Ishaan Bhardwaj
cf6e0be4e7 New IRS and IHS settings 2020-11-16 12:48:28 -05:00
Ishaan Bhardwaj
2bc9dc179c Updated README with another contributor 2020-11-14 20:00:24 -05:00
Ishaan Bhardwaj
d626926d5a Fixed 180 rotation directions 2020-11-14 19:20:25 -05:00
Ishaan Bhardwaj
721acefea0 Cleaned up TAP M-roll 2020-11-14 09:35:16 -05:00
Ishaan Bhardwaj
b9b71e90bb Finished Marathon 2020 grading! 2020-11-12 17:01:28 -05:00
Ishaan Bhardwaj
9f61b139fd TAP M-roll created 2020-11-12 16:52:40 -05:00
Ishaan Bhardwaj
3b0fdba27d Updated README.md to have the updated mod pack 2020-11-12 09:45:48 -05:00
Ishaan Bhardwaj
d8fad3dc37 Added some more developer functions, to aid in building modes. 2020-11-11 22:30:30 -05:00
Mizu
6d326a142c Update some sounds (not the pieces 2020-11-11 18:38:45 +01:00
Mizu
b6f1072587 Merge branch 'master' of https://github.com/Rexxt/cambridge 2020-11-11 17:43:53 +01:00
Mizu
eef04ebf05 Update graphic names and SOURCES.md 2020-11-11 17:42:48 +01:00
Mizu
e24737a3b8 Merge pull request #1 from SashLilac/master
Update fork
2020-11-11 17:17:22 +01:00
Ishaan Bhardwaj
f9368fa806 Forgot to add a contributor, whoops... 2020-11-11 11:11:55 -05:00
Ishaan Bhardwaj
189feb1802 Fixed the last of the hard drop safelocks... 2020-11-10 23:13:25 -05:00
Ishaan Bhardwaj
dc09dabacb Fixed Phantom Mania safelock behaviors 2020-11-10 23:10:39 -05:00
Ishaan Bhardwaj
e13278c6a8 Fixed safelock behavior for hard drop modes 2020-11-10 22:34:48 -05:00
Ishaan Bhardwaj
f7f11b0e22 Updated README.md with new Windows instructions 2020-11-10 21:41:34 -05:00
Ishaan Bhardwaj
869a0f7ec5 Added more input failsafes 2020-11-10 21:26:19 -05:00
Ishaan Bhardwaj
10a9d97848 Removed modes from core game to create modpack. Check README 2020-11-10 21:16:17 -05:00
Ishaan Bhardwaj
a470b40def Refactored input handling, so that arrow keys will always work on menus. 2020-11-10 20:08:34 -05:00
nightmareci
fd739dcfdf Changed reserved keys (arrows are no longer reserved) and now F2 always gets to the input config except when in-game. 2020-11-10 14:37:59 -08:00
Ishaan Bhardwaj
e1dc01d0d0 Changed the rotation game setting to be less ambiguous 2020-11-10 16:10:10 -05:00
Ishaan Bhardwaj
7228707241 Changed the way color override works on bone blocks 2020-11-10 16:03:30 -05:00
Ishaan Bhardwaj
af86ce3a98 Updated README.md 2020-11-10 13:41:23 -05:00
Ishaan Bhardwaj
78ae0ae671 Fixed the piece lock SFX where applicable, in modes that had their own lock functions. 2020-11-09 23:22:28 -05:00
Ishaan Bhardwaj
c614e9c4cd Fixed safelock behavior on modes that needed it. 2020-11-09 23:16:28 -05:00
Ishaan Bhardwaj
b27ef0e9f4 Made it so that in TGM3, you can only get GM by clearing the roll, and fixed hold sound in Phantom Mania 2 2020-11-09 23:04:50 -05:00
Joe Zeng
843b1e108a Added safe-lock back to Survival CK. 2020-11-09 21:13:07 -05:00
Brandon McGriff
a8d697064c Merge branch 'master' of https://github.com/SashLilac/cambridge 2020-11-09 16:09:39 -08:00
Brandon McGriff
cf32474898 Fixed libs/discordRPC.lua so Discord RPC loads on Linux.
I changed how the library was loaded before, but turns out that way only
worked on Windows. Changed it back to how it was, so it works on Linux
for me, and presumably macOS.
2020-11-09 16:06:09 -08:00
Brandon McGriff
6a295cad59 Added Windows batch files for automated packaging of fused Windows packages.
They require the tar utility, but that's included in the latest versions of Windows 10. The utility is available for installation on other versions of Windows.

I also found out how to get the Discord RPC library to load with all ways of running the game, but that required changing libs/discordRPC.lua. Binary libraries can only be loaded from the filesystem, outside of a .love archive or fused executable.
2020-11-09 15:51:00 -08:00
Ishaan Bhardwaj
2d80e20c82 Updated README.md with more new contributors 2020-11-09 11:47:21 -05:00
Ishaan Bhardwaj
2279c24d11 Closed an if in the previous fix 2020-11-08 23:23:26 -05:00
Ishaan Bhardwaj
8510ad9bea Fixed Phantom Mania 2 roll grade points. 2020-11-08 23:19:21 -05:00
Joe Zeng
6b77ad8547 Merge pull request #8 from nightmareci/master
Implemented joystick input.
2020-11-08 17:17:30 -05:00
nightmareci
6834e92674 Changed indentation to hard tabs. 2020-11-08 13:19:01 -08:00
nightmareci
3479374686 Forgot that the code used "enter" instead of "return" in the input config scene before, so changed it back. 2020-11-08 13:06:29 -08:00
nightmareci
863c614a4c Implemented joystick input.
I had to redo how input is done entirely, so more than one source of input can be used for game inputs.

I added new inputs, menu_decide and menu_back. Return and escape still have their reserved status, sending menu_decide and menu_back, respectively. Other keys are reserved too, like arrows, to ensure users can always reconfigure input.
2020-11-08 12:55:06 -08:00
Joe Zeng
49e52c6a39 Merge pull request #4 from Rexxt/master
Small updates to visuals and sound
2020-11-07 14:31:17 -05:00
Joe Zeng
a105086ca6 Fixed the garbage pausing problem in Phantom Mania 2. 2020-11-07 01:31:09 -05:00
Joe Zeng
1b381c4bf3 Might as well add the dark square while I'm at it. 2020-11-07 01:29:44 -05:00
Joe Zeng
91a87fea73 Fixed the garbage pausing problem in Phantom Mania 2. 2020-11-07 01:12:13 -05:00
Ishaan Bhardwaj
28b455fcc0 Updated README.md with new contributors 2020-11-06 20:57:01 -05:00
Joe Zeng
2e3eff025f Replaced spaces with tabs.
Check CONTRIBUTING.md, guys!
2020-11-06 20:54:14 -05:00
Joe Zeng
4670cb7c15 Added the ability to _always_ reverse rotation. 2020-11-06 20:46:36 -05:00
Joe Zeng
9b04e14388 Added "Always reverse" option for rotation reversal. 2020-11-06 19:17:32 -05:00
Ishaan Bhardwaj
f52da36bf7 TGM3 cool system change 2020-11-06 14:01:28 -05:00
Ishaan Bhardwaj
76142c1dff More Green Orange line 2020-11-05 16:21:58 -05:00
Ishaan Bhardwaj
a3458e2413 Fix Arika SRS 2020-11-04 22:46:45 -05:00
Ishaan Bhardwaj
7eba9c012f Merge branch 'master' of https://github.com/sashlilac/cambridge 2020-11-04 16:58:11 -05:00
Ishaan Bhardwaj
4d2868b7b6 Small changes. 2020-11-04 16:57:44 -05:00
Ishaan Bhardwaj
2e6fcd232b Update README.md 2020-11-04 08:42:42 -05:00
Ishaan Bhardwaj
10833f2ec1 Score drain changes 2020-11-03 23:20:41 -05:00
Ishaan Bhardwaj
abb2b9491e Preparing for v0.2.1 2020-11-03 23:04:47 -05:00
Ishaan Bhardwaj
062ab2005e v0.2 release commit - hold piece darken 2020-11-03 16:56:08 -05:00
Ishaan Bhardwaj
468025fc80 last commit to core modes before release 2020-11-03 12:17:36 -05:00
Ishaan Bhardwaj
c8544975d6 Fix interval training 2020-11-03 11:55:30 -05:00
Ishaan Bhardwaj
6776229bfb Small push to Cambridge modes 2020-11-03 11:52:52 -05:00
Ishaan Bhardwaj
84b4dc5073 World Bone Blocks 2020-11-03 10:58:21 -05:00
Ishaan Bhardwaj
35dafb6615 keep leaving debug code in new commits 2020-11-02 22:51:16 -05:00
Ishaan Bhardwaj
3641d85fcb Major changes, including modpack support 2020-11-02 22:47:58 -05:00
Ishaan Bhardwaj
9b89c4d1de G/O line fix 2020-11-02 21:17:13 -05:00
Ishaan Bhardwaj
2dba120919 Green line and orange line for TAP Master 2020-11-02 20:43:10 -05:00
Ishaan Bhardwaj
9224f271b1 Hotfix for last 2020-11-02 16:20:22 -05:00
Ishaan Bhardwaj
febb5d546c Score overhauls 2020-11-02 16:12:05 -05:00
Ishaan Bhardwaj
c6482c423e 4w optimization and green/orange line adding for applicable modes 2020-11-02 13:46:16 -05:00
Ishaan Bhardwaj
6beb313c6b Debug fixes 2020-11-02 12:44:15 -05:00
Ishaan Bhardwaj
eb70f55b6e TGM2 fixes and cool fixes 2020-11-02 12:21:12 -05:00
Ishaan Bhardwaj
0badcde9ad Basset: the only person to leave debug code in a repo 2020-11-01 13:44:35 -05:00
Ishaan Bhardwaj
6f39b591d3 Hotfix for TGM+ 2020-11-01 13:28:13 -05:00
Ishaan Bhardwaj
129237f0b0 TGM+ 2020-11-01 13:24:52 -05:00
Ishaan Bhardwaj
741c246244 second lol 2020-11-01 12:04:07 -05:00
Ishaan Bhardwaj
b5937af8b2 lol 2020-11-01 12:01:26 -05:00
Ishaan Bhardwaj
33b8533d8e Fixes to TAP M-roll requirements 2020-11-01 11:06:43 -05:00
Ishaan Bhardwaj
69959ff687 TA Death level advance formula is very bugged 2020-10-30 21:36:05 -04:00
Ishaan Bhardwaj
f91cd99dfd Minor fixes to TGM modes 2020-10-30 21:28:39 -04:00
Ishaan Bhardwaj
be59727ca5 Some demon mode fixes 2020-10-30 13:09:49 -04:00
Ishaan Bhardwaj
cca295066c Fix. 2020-10-29 23:05:49 -04:00
Ishaan Bhardwaj
f2862b4d93 Some score fixes for core TGM modes 2020-10-29 23:03:54 -04:00
Ishaan Bhardwaj
2aafd30253 Fixed secret grade detection 2020-10-29 22:14:34 -04:00
Ishaan Bhardwaj
b27ba335ba Improved secret grade 2020-10-29 21:40:50 -04:00
Ishaan Bhardwaj
33244736b8 Secret grade for sprint? Also ARR and DAS change so remember to change it in the lua file 2020-10-29 20:56:18 -04:00
Mizu
a324e0015a Replace SFX and add hold 2020-10-27 12:17:00 +01:00
Ishaan Bhardwaj
285108ca08 ACTUALLY fixed TI Master torikan 2020-10-26 14:07:09 -04:00
Ishaan Bhardwaj
4b1fed727c Update marathon_a3.lua 2020-10-26 14:03:09 -04:00
Mizu
d38168ca00 Updated title screen background 2020-10-26 16:57:20 +01:00
Mizu
b0ce0f17f5 Add new sound effects to the game 2020-10-26 14:21:49 +01:00
Ishaan Bhardwaj
9fca272e8d Update ck.lua 2020-10-24 09:12:12 -04:00
Ishaan Bhardwaj
5a21c8244b Update README.md 2020-10-23 21:28:32 -04:00
Ishaan Bhardwaj
4923b2e2d4 Removed debug code 2020-10-23 21:23:45 -04:00
Ishaan Bhardwaj
8810f24e7a v0.1.8, SHIRASE-CK ADDEDgit add scene/mode_select.lua tetris/modes/ck.lua ! 2020-10-23 21:02:27 -04:00
Ishaan Bhardwaj
57a9f6ef55 Fixing Demon Mode backgrounds 2020-10-23 14:52:59 -04:00
Oshisaure
342036bc28 Fixed guideline SRS anti-stalling to work closer to guideline games
Currenly behaves similarly to Tetris Friends, lock as soon as it can after exceeding the manipulation limit.
That still allows to have a piece in the air forever in low G though, might be worth looking into it?
2020-10-21 05:30:28 +01:00
Oshisaure
78dcfe43c4 Made Survival A2/A3 torikans stop your game instead of giving an end roll 2020-10-21 05:24:11 +01:00
Ishaan Bhardwaj
cdf6b5cf33 TI Master torikan 2020-10-20 23:14:25 -04:00
Oshisaure
e6a60b0021 Merge branch 'master' of https://github.com/SashLilac/cambridge into master 2020-10-19 16:54:27 +01:00
Oshisaure
5f29c987f2 Tweaked Cambridge RS to fix how S and Z show in the next queue 2020-10-19 16:50:49 +01:00
Ishaan Bhardwaj
608d75b1ac Update README.md 2020-10-19 08:45:22 -04:00
Oshisaure
1427c0d19e Updated Ti-World and ACE-SRS to use the Arika kick table
This possibly needs further testing, although the example
given [on the wiki](tetris.wiki/SRS#Arika_SRS) works
2020-10-19 05:07:31 +01:00
Ishaan Bhardwaj
e221a91d73 Swapped some settings around 2020-10-18 23:32:57 -04:00
Oshisaure
bdcd25b82c Fixed T floorkick in ARS Ti/ACE/ACE2 2020-10-19 04:19:36 +01:00
Ishaan Bhardwaj
a5158e0994 Fixed Demon Mode torikan madness 2020-10-18 21:54:24 -04:00
Oshisaure
d946b17e13 Minor change on PR #3 to use the error handling that was already implemented 2020-10-18 00:40:14 +01:00
Oshisaure
69a5c0a21a Merge pull request #3 from MyPasswordIsWeak/master
Fixed discord rpc not working on linux
2020-10-18 00:12:50 +01:00
MyPasswordIsWeak
b6423c3335 Change tabs to spaces for consistency 2020-10-17 21:17:49 +02:00
MyPasswordIsWeak
5b960d7291 Change single quotes to double quotes 2020-10-17 21:15:06 +02:00
MyPasswordIsWeak
54f4b0b890 Fixed rpc not working on linux 2020-10-17 21:11:38 +02:00
Oshisaure
8c62f321a0 Added secret grade for the Phantom Mania/-2/-N modes 2020-10-17 04:22:41 +01:00
Oshisaure
fdffd2cd9a Actually made ACE-ARS2 selectable 2020-10-17 04:17:25 +01:00
Oshisaure
8ddf468121 Removed print statements leftover from when i was making sure the torikans were working as intended 2020-10-17 03:42:31 +01:00
Oshisaure
8e77407ff2 Merge branch 'master' of https://github.com/SashLilac/cambridge 2020-10-17 03:38:07 +01:00
Oshisaure
92c852d178 Renamed ACE-ARS to ACE-ARS2 and added ACE-ARS that guideline piece lock and colours 2020-10-17 03:37:44 +01:00
Ishaan Bhardwaj
f658ed63f2 apparently I made ti-srs too strict 2020-10-16 22:20:18 -04:00
Oshisaure
c2d1c1183c Survival A3 torikan now switches to 03:03:00 when playing with World-type rulesets 2020-10-17 02:51:29 +01:00
Ishaan Bhardwaj
36c568feaf demon mode grade display fixed 2020-10-16 21:35:30 -04:00
Ishaan Bhardwaj
bf30fcefbd Add Sega randomizer 2020-10-14 15:00:17 -04:00
Oshisaure
d9f5bd16d7 Disabled BGM for now since the only music is the pacer test (not selectable in game) and the credit roll 2020-10-14 19:30:37 +01:00
Ishaan Bhardwaj
d978ff8d87 fixed a thing 2020-10-14 13:45:56 -04:00
Ishaan Bhardwaj
b47d0f36b9 oshi forced me to add bags 2020-10-14 13:43:28 -04:00
Ishaan Bhardwaj
abc210c69c made our debug randomizer not bad 2020-10-13 22:10:27 -04:00
Ishaan Bhardwaj
436e4ac861 Update README.md 2020-10-13 15:56:11 -04:00
Oshisaure
a48d7c67b5 Merge branch 'HEAD' of https://github.com/SashLilac/cambridge.git 2020-10-13 20:26:33 +01:00
Oshisaure
f6ca79ff91 Fixed big mode spawn positions 2020-10-13 20:26:07 +01:00
Ishaan Bhardwaj
4eb3901610 Some big mode fixes 2020-10-13 14:16:23 -04:00
Ishaan Bhardwaj
3f7fc4b622 Rename Mac RPC lib 2020-10-13 11:20:46 -04:00
Ishaan Bhardwaj
ac7ae91c39 Small RPC change 2020-10-12 22:44:47 -04:00
Oshisaure
0c8e910245 Linux RPC maybe? 2020-10-13 01:23:24 +01:00
Oshisaure
6233ffb12d Fixed RPC icon and included RPC lib for mac 2020-10-13 00:39:13 +01:00
Oshisaure
1f78bb9e99 Merge branch 'HEAD' of https://github.com/SashLilac/cambridge.git 2020-10-12 21:22:15 +01:00
Oshisaure
a125c09106 Fixed crash on loading the game with no save 2020-10-12 21:21:10 +01:00
Ishaan Bhardwaj
090ffa5126 Update README.md 2020-10-12 14:48:00 -04:00
Ishaan Bhardwaj
12a6f42198 Revert "Fixing step reset" - didn't realize infinite floorkicks
This reverts commit 0c317d9ce1.
2020-10-11 15:46:34 -04:00
Ishaan Bhardwaj
0c317d9ce1 Fixing step reset 2020-10-11 15:41:56 -04:00
Ishaan Bhardwaj
eddfee566d Grade display changed for TA Death modes 2020-10-11 15:34:10 -04:00
Ishaan Bhardwaj
7fe366a8de Bravo score update 2020-10-11 14:17:18 -04:00
Ishaan Bhardwaj
55be30c99f experimental bravo formula for tgm1 2020-10-11 13:21:03 -04:00
Ishaan Bhardwaj
36ceef8488 experimental bravo formula for tgm1 2020-10-11 12:57:57 -04:00
Oshisaure
b59edb5e8e Accidentally swapped blue and orange in the colour scheme update, changing it back with this commit 2020-10-11 03:12:22 +01:00
Oshisaure
5d32b6a3e7 Discord RPC cleanup
- Loading Discord RPC is now handled by `load/rpc.lua`
- Removed `presence` global, call `DiscordRPC:update()` directly with what needs updating
- Game doesn't crash anymore if the Discord RPC fails to load
- Added RPC variables in the gamemode superclass to let each gamemode handle its special case
2020-10-11 02:17:48 +01:00
Oshisaure
05230ac046 Game settings screen, and minor fix on discordRPC
- Uses BG previously from the input config screen, which has gotten a new BG
- Minor tweak on the input config screen to display all inputs names regardless of if they are bound or not
- Added Mod1 function to `funcs.lua`, may be useful again sometime
- Added game settings
  * Manual locking (per gamemode, per ruleset, on harddrop or on softdrop)
  * Piece colours (per ruleset, TTC or Arika)
  * World Reverse toggle
- Moved the discordRPC `libs/` directory, as it's a third party library
- Edited the `discordRPC.lua` file to look for the dll at the right place regardless of how you run the game (until we fuse it that is)

This should have probably been done in several commits, sorry about that
2020-10-11 00:42:56 +01:00
Oshisaure
f28dc08ae2 Updated Race 40 randomiser to use 7-bag no SZO start 2020-10-10 23:07:12 +01:00
Ishaan Bhardwaj
ecd958bdc5 Update README.md 2020-10-10 10:30:31 -04:00
Ishaan Bhardwaj
43f59cfde8 Merge pull request #1 from haileylgbt/master
Added fitting menu sfx + RPC
2020-10-09 21:37:45 -04:00
Ishaan Bhardwaj
00c46961f9 Bug. 2020-10-09 21:31:49 -04:00
Ishaan Bhardwaj
0a0053276b SG!!!! 2020-10-09 21:14:20 -04:00
Hailey
d0f1d869a8 RP Icon 2020-10-10 09:47:33 +10:00
Hailey
29ee000998 Minor Rich Presence adjustments 2020-10-10 09:05:59 +10:00
Hailey
995fd7fee9 rich presence!! 2020-10-10 08:43:22 +10:00
Hailey
67abf35a28 Merge pull request #1 from SashLilac/master
Removed the BG limit, because someone is a madman
2020-10-10 08:02:00 +10:00
Ishaan Bhardwaj
9982613e26 Removed the BG limit, because someone is a madman 2020-10-09 17:55:22 -04:00
Hailey
629beb7240 Added fitting menu sfx 2020-10-10 07:50:05 +10:00
Oshisaure
4cb20101b0 Added background for options screen 2020-10-09 18:44:48 +01:00
Ishaan Bhardwaj
63c0721978 Slight cosmetic change concerning the bonus timer 2020-10-09 13:37:39 -04:00
Oshisaure
1366451a3d Fixed randomisers in A1-A4 modes:
- History 4-rolls, history 6-rolls and history 6-rolls 35-bag no longer deal S, Z or O as their first piece
- Added a 7-bag randomiser with the same behaviour (bag7noSZOstart)
- Tweaked the "35-bag" part of the history 6-rolls 35-bag randomiser to work closer to what it's supposed to be
- Switched Marathon AX4's randomiser from history 6-rolls to 7-bag no SZO start
2020-10-09 04:34:11 +01:00
Ishaan Bhardwaj
6b624b9853 Ti-World placeholder 2020-10-08 22:20:37 -04:00
Ishaan Bhardwaj
b0bda25466 Cool Regret System TM 2020-10-08 22:13:35 -04:00
Oshisaure
2bde9d1378 Added secret grade detection for Marathon A1-A3 and Survival A1-A3 2020-10-09 02:00:42 +01:00
Ishaan Bhardwaj
6178b2cee9 Proper bravo detection! 2020-10-08 20:44:06 -04:00
Ishaan Bhardwaj
4e8a237de3 TA GM requirements updated 2020-10-08 20:35:40 -04:00
Oshisaure
5606251ea7 Added extra buttons:
- Implemented retry button*
- Escape on mode select sends you to title screen
- Escape on title screen closes the game
- Added "Exit Game" entry on title screen, closes the game when selected

*Pardon my angry comment in `scene/game.lua`.
2020-10-08 04:56:46 +01:00
Oshisaure
a4984fd687 Fixed jank regarding the area above the field
- The game now discards blocks locked over y = 1 instead of panicking and crashing
2020-10-07 20:40:43 +01:00
Ishaan Bhardwaj
b7ef7d1976 Fix I's ghost piece in ACE modes 2020-10-07 15:17:56 -04:00
Oshisaure
293b7398a2 Typo lol 2020-10-07 20:11:15 +01:00
Oshisaure
8a2237a77c Fixed Arika rulesets
- Fixed centre column rule on Classic ARS, Ti-ARS and ACE-ARS
- Added T floorkick for Ti-ARS and ACE-ARS
2020-10-07 19:54:18 +01:00
Ishaan Bhardwaj
bdad32ac79 For Oshisaure :) 2020-10-07 13:24:28 -04:00
Oshisaure
3cc918841f Added display for time limit extensions 2020-10-07 01:57:07 +01:00
Oshisaure
5f7ea0648e Fixed Konoha randomiser and added ghost before lv100 2020-10-06 23:53:02 +01:00
Oshisaure
5d34218b97 Merge branch 'master' of https://github.com/SashLilac/cambridge 2020-10-06 21:50:36 +01:00
Oshisaure
fcd8b0f360 Set a fixed height for piece previews 2020-10-06 21:45:57 +01:00
Ishaan Bhardwaj
b983e1c108 Merge branch 'master' of https://github.com/SashLilac/cambridge 2020-10-06 16:29:24 -04:00
Ishaan Bhardwaj
36ab451b70 Fix big mode spawns 2020-10-06 16:27:28 -04:00
Oshisaure
8fef7faa6a Fixed randomiser and next queue whhhackiness 2020-10-06 21:10:15 +01:00
Ishaan Bhardwaj
f13e2096b2 More randomizer fixes? 2020-10-06 15:49:06 -04:00
Oshisaure
6b7f18d58a Refactored funcs.lua
- Renamed st and sp to strTrueValues and frameTime respectively
- Modified files calling these to use the new names
- Tidying like formatTime now using a single string.format
2020-10-06 18:14:00 +01:00
Ishaan Bhardwaj
d5ce2ee9ba Update README.md 2020-10-06 10:22:23 -04:00
Ishaan Bhardwaj
f04b57e7eb Update README.md 2020-10-06 10:20:01 -04:00
Ishaan Bhardwaj
be644bf57b Made level counter not look awkward 2020-10-05 23:24:59 -04:00
Ishaan Bhardwaj
9d15feef33 Another fix? 2020-10-05 22:47:34 -04:00
Ishaan Bhardwaj
634a5bc03b Potential fix for bag not working 2020-10-05 22:33:57 -04:00
Ishaan Bhardwaj
f1ad1f0ea4 Added the lost Konoha mode from TGM4 2020-10-05 22:17:15 -04:00
Ishaan Bhardwaj
a534331b11 Ace-ARS! 2020-10-05 11:52:37 -04:00
Ishaan Bhardwaj
d602fdfc7e TAP big mode added 2020-10-05 11:11:46 -04:00
Ishaan Bhardwaj
971151e210 Added 5 bag randomizer 2020-10-04 22:49:17 -04:00
Ishaan Bhardwaj
593cad0e71 Update README to fork 2020-09-24 22:23:05 -04:00
157 changed files with 8788 additions and 3592 deletions

2
.gitignore vendored
View File

@@ -2,3 +2,5 @@
*.love
dist/*.zip
dist/**/cambridge.exe
dist/**/libs
dist/**/*.md

View File

@@ -1,48 +1,72 @@
![Cambridge Banner](https://t-sp.in/public/img/cambridge.png)
Cambridge
=========
Welcome to Cambridge, the next open-source falling-block game engine!
The project is written and maintained exclusively by [Milla](https://github.com/MillaBasset), [joezeng](https://github.com/joezeng) and [Oshisaure](https://github.com/oshisaure)!
Installation instructions
-------------------------
The Discord server has been reopened! https://discord.gg/AADZUmgsph
Pre-built releases are available on the releases page.
The game also has a website now with more detail than seen on this README: https://t-sp.in/cambridge
Playing the game
----------------
### Windows
Unzip the exe file and run it directly. All assets are currently bundled inside the executable.
You do not need LÖVE on Windows, as it comes bundled with the program.
### macOS
#### Stable release
For the time being, the file `cambridge.love` only works on the command line. Install `love` with [https://brew.sh/](Homebrew), and run:
To get the stable release, simply download either `cambridge-win32.zip` (32-bit) or `cambridge-windows.zip` (64-bit) in the [latest release](https://github.com/MillaBasset/cambridge/releases/latest).
$ love cambridge.love
All assets needed are bundled with the executable.
### Linux
#### Bleeding edge
Same as macOS, except install `love` with your favourite package manager.
If you want the bleeding edge version, download [this](https://github.com/MillaBasset/cambridge/archive/master.zip).
Extract the ZIP, open a Command Prompt at the folder you extracted Cambridge to, then run this command:
Running from source
-------------------
dist\windows\love.exe .
If you want the bleeding-edge release, you can also clone the code straight from this repository.
Alternatively, if you're on a 32-bit system, run this instead:
dist\win32\love.exe .
32-bit systems do not support rich presence integration.
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!**
#### Downloading a release
You can download the .love file in the latest release, and run it with:
love cambridge.love
#### Installing from source
Clone the repository in git:
git clone https://github.com/joezeng/cambridge
git clone https://github.com/MillaBasset/cambridge
Alternatively, download the source code ZIP in the latest release.
Then, navigate to the root directory that you just cloned, and type:
love .
love .
It should run automatically!
## Installing modpacks
For instructions on how to install modpacks, go to [this](https://github.com/MillaBasset/cambridge-modpack) mod pack to get a taste of the mod potential.
License
-------
@@ -54,3 +78,32 @@ community, as well as borrowed from other places, either with licensing
or as placeholders until suitable material can be found that is properly
licensed. Their original sources, and copyright notices if applicable, are
listed in the file SOURCES.
Credits
-------
- [Lilla Oshisaure](https://www.youtube.com/user/LeSpyroshisaure) for being my co-dev!
- [joezeng](https://github.com/joezeng) for the original project, and for offering to help with the expansion!
- [The Tetra Legends Discord](http://discord.com/invite/7hMx5r2) for supporting me and playtesting!
- [The Absolute Plus](https://discord.gg/6Gf2awJ) for being another source of motivation!
More special thanks can be found in-game, under the "Credits" menu.
Other Notable Games
-------------------
- [TGMsim](https://github.com/2Tie/TGMsim) by 2Tie
- [Multimino](https://gamejolt.com/games/multimino/556683) by Axel Fox
- [Tetra Legends](https://tetralegends.app) by Dr Ocelot
- [ZTrix](https://discord.gg/MGhqCBDGNH) by Electra
- [Shiromino](https://github.com/shiromino/shiromino) by Felicity/nightmareci/kdex
- [Cursed Blocks](https://github.com/Manabender/Cursed-Blocks) by Manabender
- Picoris 1/2 by MarkGamed
- [Tetra Online](https://github.com/Juan-Cartes/Tetra-Offline) by Mine
- [Techmino](https://discord.gg/6Yuww44tq8) by MrZ
- [TETR.IO](https://tetr.io) by osk
- [Master of Blocks](https://discord.gg/72FZ49mjWh) by Phoenix Flare
- [Spirit Drop](https://rayblastgames.com/spiritdrop.php) by RayRay26
- [stackfuse](https://github.com/sinefuse/stackfuse) by sinefuse
![Cambridge Logo](https://cdn.discordapp.com/attachments/625496179433668635/763363717730664458/Icon_2.png)

View File

@@ -8,7 +8,7 @@ Some of the assets are used without proper licenses. We aim to have fully licens
Backgrounds
-----------
1. Title: "Motus Glacies." Contributed by Daniel "Explo" McCarthy.
1. Title: Original picrute found on the Wikipedia article for Cambridge
1. *Gameplay level 0: "Quantum foam." Alex Sukontsev. https://www.flickr.com/photos/control9/14957509814/
2. *Gameplay level 1: No name. http://www.onekind.tv/univision-mqb/q5mqh5brlvuuj2nhdx7ch7eum183uu
@@ -34,10 +34,18 @@ Backgrounds
Backgrounds marked with a * are placeholders that will be replaced in later versions due to incompatible licenses. We are generally aiming for public domain background images, but will also accept backgrounds given proper licenses to be included within Cambridge.
Sounds
------
All piece sounds are (c) 2020 Damian Yerrick.
Other sounds from:
- NullpoMino
- DTET, (c) 2003 Mihys.
Music
-----
1. TGM3 credit roll music.
1. Second Reality opening scene music (1993).
2. The FitnessGram™ Pacer Test.
All background music is (currently) only unofficially included. In later releases they may be replaced with specifically licensed music as applicable.
@@ -106,3 +114,59 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
simple-slider (https://love2d.org/forums/viewtopic.php?t=80711)
--------------------
Copyright (c) 2016 George Prosser
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
bigint.lua (https://github.com/empyreuma/bigint.lua)
--------------------
3-Clause BSD License
Copyright (c) Emily "empyreuma" 2016
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

11
clean.bat Normal file
View File

@@ -0,0 +1,11 @@
@del cambridge.love
@del dist\windows\cambridge.exe
@del dist\windows\SOURCES.md
@del dist\windows\LICENSE.md
@rmdir /Q /S dist\windows\libs
@del dist\win32\cambridge.exe
@del dist\win32\SOURCES.md
@del dist\win32\LICENSE.md
@rmdir /Q /S dist\win32\libs
@del dist\cambridge-windows.zip
@del dist\cambridge-win32.zip

View File

@@ -6,5 +6,6 @@ function love.conf(t)
t.window.title = "Cambridge"
t.window.width = 640
t.window.height = 480
t.window.icon = "res/img/cambridge_icon.png"
t.window.vsync = false
end

View File

@@ -3,21 +3,11 @@ Game modes
There are several classes of game modes. The modes that originate from other games are organized by suffix:
* The "C" series stand for "Classic" games, games that were produced before around 1992-1993 and generally have no wallkicks or lock delay.
* C84 - The original version from the Electronika 60.
* C88 - Sega Tetris.
* C89 - Nintendo / NES Tetris.
* The "A" series stand for "Arika" games, or games in the Tetris the Grand Master series.
* A1 - Tetris The Grand Master (the original from 1998).
* A2 - Tetris The Absolute The Grand Master 2 PLUS.
* A3 - Tetris The Grand Master 3 Terror-Instinct.
* AX - Tetris The Grand Master ACE (X for Xbox).
* The "G" series stand for "Guideline" games, or games that follow the Tetris Guideline.
* GF - Tetris Friends (2007-2019)
* GJ - Tetris Online Japan (2005-2011)
* The "N" series stands for Nullpomino, only used for Phantom Mania N.
* The "W" series stands for "Web" games, which are fanmade games released on the web.
* WCB - RainComplex.net's Cat Boi Quatro.
* A1 - Tetris The Grand Master (the original from 1998).
* A2 - Tetris The Absolute The Grand Master 2 PLUS.
* A3 - Tetris The Grand Master 3 Terror-Instinct.
* AX - Tetris The Grand Master ACE (X for Xbox).
MARATHON
--------
@@ -25,16 +15,11 @@ MARATHON
Modes in which the goal is to play as well as possible over a limited game interval.
* **MARATHON 2020**: 2020 levels of pure pain. Can you make it all the way?
* **MARATHON WCB**: CatBoiQuatro! Can you control the pieces?
From other games:
* **MARATHON A1**: Tetris the Grand Master 1.
* **MARATHON A2**: Tetris the Grand Master 2 (TAP Master).
* **MARATHON A3**: Tetris the Grand Master 3 (no exams).
* **MARATHON AX**: Normal mode from TGM Ace.
* **MARATHON AX2**: Hi-Speed1 mode from TGM Ace.
* **MARATHON AX3**: Hi-Speed2 mode from TGM Ace.
* **MARATHON C89**: Nintendo NES Tetris. Can you transition and make it to the killscreen?
SURVIVAL
@@ -49,23 +34,6 @@ From other games:
* **SURVIVAL A2**: T.A. Death.
* **SURVIVAL A3**: Ti Shirase.
* **SURVIVAL AX**: Another mode from TGM Ace.
* **SURVIVAL AX2**: Another2 mode from TGM Ace.
RACE
----
Modes with no levels, just a single timed goal.
* **Race 40**: How fast can you clear 40 lines? No limits, no holds barred.
CREDITS
-------
Modes that are just the credit rolls of specific games.
* **CREDITS A3**: Tetris the Grand Master 3's famous M-roll.
PHANTOM MANIA
@@ -78,13 +46,10 @@ Modes where pieces turn invisible as soon as you lock them. One of Cambridge's s
* **Phantom Mania 2**: Phantom Mania but way faster! Can you face a mode where even the garbage and the next preview turn invisible?
OTHER MODES
-----------
* **Strategy**: How well can you plan ahead your movements? Can you handle only having a short time to place each piece?
* **TetrisGram™ Pacer Test**: is a multi-stage piece-placing ability test that progressively gets more difficult as it continues.
* **Interval Training**: 30 seconds per section. 20G. 15 frames of lock delay. How long can you last?
* **Demon Mode**: An original mode from Oshisaure! Can you push through the ever faster levels and not get denied?
* **Big A2**: Marathon A2 but all the pieces are BIG!

View File

@@ -10,13 +10,16 @@ A ruleset consists of the following things:
If you're used to Nullpomino, you may notice a few things missing from that definition. For example, piece previews, hold queues, and randomizers have been moved to being game-specific rules, rather than rules that are changeable with the ruleset you use. Soft and hard drop behaviour is also game-specific now, so that times can be more plausibly compared across rulesets.
There are six rulesets currently supported:
* Cambridge - a ruleset original to Cambridge, used for all custom modes. Supports 180-degree rotations!
Rotation system
---------------
A rotation system defines the following things:
* The block offsets of each piece orientation.
* The wall or floor kicks that will be attempted for each type of rotation.
* SRS - the rotation system used in the Tetris Guideline games. Supports 180-degree rotations!
* Ti-SRS - SRS but with no 180-degree rotations.
There are four rotation systems currently supported:
* ARS - the rotation system from the original Tetris the Grand Master.
* Ti-ARS - ARS with floorkicks! From TGM3: Terror Instinct.
* Ace-ARS - ARS with floorkicks and move reset! From TGM ACE.
* Cambridge
* Classic ARS
* Ti-ARS
* SRS

View File

@@ -1,13 +1,15 @@
function copy(t)
-- returns deep copy of t (as opposed to the shallow copy you get from var = t)
if type(t) ~= "table" then return t end
local meta = getmetatable(t)
local target = {}
for k, v in pairs(t) do target[k] = v end
setmetatable(target, meta)
return target
local meta = getmetatable(t)
local target = {}
for k, v in pairs(t) do target[k] = v end
setmetatable(target, meta)
return target
end
function st(tbl)
function strTrueValues(tbl)
-- returns a concatenation of all the keys in tbl with value true, separated with spaces
str = ""
for k, v in pairs(tbl) do
if v == true then
@@ -17,14 +19,16 @@ function st(tbl)
return str
end
function sp(m, s, f)
if m == nil then m = 0 end
if s == nil then s = 0 end
if f == nil then f = 0 end
return m*3600 + s*60 + math.ceil(f * 0.6)
function frameTime(min, sec, hth)
-- returns a time in frames from a time in minutes-seconds-hundredths format
if min == nil then min = 0 end
if sec == nil then sec = 0 end
if hth == nil then hth = 0 end
return min*3600 + sec*60 + math.ceil(hth * 0.6)
end
function vAdd(v1, v2)
-- returns the sum of vectors v1 and v2
return {
x = v1.x + v2.x,
y = v1.y + v2.y
@@ -32,6 +36,7 @@ function vAdd(v1, v2)
end
function vNeg(v)
-- returns the opposite of vector v
return {
x = -v.x,
y = -v.y
@@ -39,17 +44,52 @@ function vNeg(v)
end
function formatTime(frames)
-- returns a mm:ss:hh (h=hundredths) representation of the time in frames given
if frames < 0 then return formatTime(0) end
str = string.format("%02d", math.floor(frames / 3600)) .. ":"
.. string.format("%02d", math.floor(frames / 60) % 60) .. "."
.. string.format("%02d", math.floor(frames / 0.6) % 100)
local min, sec, hund
min = math.floor(frames/3600)
sec = math.floor(frames/60) % 60
hund = math.floor(frames/.6) % 100
str = string.format("%02d:%02d.%02d", min, sec, hund)
return str
end
function formatBigNum(number)
local s = string.format("%d", number)
local pos = string.len(s) % 3
if pos == 0 then pos = 3 end
-- returns a string representing a number with commas as thousands separator (e.g. 12,345,678)
local s
if type(number) == "number" then
s = string.format("%d", number)
elseif type(number) == "string" then
if not tonumber(number) then
return
else
s = number
end
else
return
end
local pos = Mod1(string.len(s), 3)
return string.sub(s, 1, pos)
.. string.gsub(string.sub(s, pos+1), "(...)", ",%1")
end
end
function Mod1(n, m)
-- returns a number congruent to n modulo m in the range [1;m] (as opposed to [0;m-1])
return ((n-1) % m) + 1
end
function table.contains(table, element)
for _, value in pairs(table) do
if value == element then
return true
end
end
return false
end
function clamp(x, min, max)
if max < min then
min, max = max, min
end
return x < min and min or (x > max and max or x)
end

566
libs/bigint/bigint.lua Normal file
View File

@@ -0,0 +1,566 @@
#!/usr/bin/env lua
-- If this variable is true, then strict type checking is performed for all
-- operations. This may result in slower code, but it will allow you to catch
-- errors and bugs earlier.
local strict = false
--------------------------------------------------------------------------------
local bigint = {}
local mt = {
__add = function(lhs, rhs)
return bigint.add(lhs, rhs)
end,
__unm = function(arg)
return bigint.negate(arg)
end,
__sub = function(lhs, rhs)
return bigint.subtract(lhs, rhs)
end,
__mul = function(lhs, rhs)
return bigint.multiply(lhs, rhs)
end,
__div = function(lhs, rhs)
return bigint.divide(lhs, rhs)
end,
__mod = function(lhs, rhs)
return bigint.modulus(lhs, rhs)
end,
__pow = function(lhs, rhs)
return bigint.exponentiate(lhs, rhs)
end,
__tostring = function(arg)
return bigint.unserialize(arg, "s")
end,
__eq = function(lhs, rhs)
return bigint.compare(lhs, rhs, "==")
end,
__lt = function(lhs, rhs)
return bigint.compare(lhs, rhs, "<")
end,
__le = function(lhs, rhs)
return bigint.compare(lhs, rhs, "<=")
end
}
local named_powers = require("libs.bigint.named-powers-of-ten")
-- Create a new bigint or convert a number or string into a big
-- Returns an empty, positive bigint if no number or string is given
function bigint.new(num)
local self = {
sign = "+",
digits = {}
}
-- Return a new bigint with the same sign and digits
function self:clone()
local newint = bigint.new()
newint.sign = self.sign
for _, digit in pairs(self.digits) do
newint.digits[#newint.digits + 1] = digit
end
return newint
end
setmetatable(self, mt)
if (num) then
local num_string = tostring(num)
for digit in string.gmatch(num_string, "[0-9]") do
table.insert(self.digits, tonumber(digit))
end
if string.sub(num_string, 1, 1) == "-" then
self.sign = "-"
end
end
return self
end
-- Check the type of a big
-- Normally only runs when global variable "strict" == true, but checking can be
-- forced by supplying "true" as the second argument.
function bigint.check(big, force)
if (strict or force) then
assert(getmetatable(big) == mt, "at least one arg is not a bigint")
assert(#big.digits > 0, "bigint is empty")
assert(big.sign == "+" or big.sign == "-", "bigint is unsigned")
for _, digit in pairs(big.digits) do
assert(type(digit) == "number", "at least one digit is invalid")
assert(digit <= 9 and digit >= 0, digit .. " is not between 0 and 9")
assert(math.floor(digit) == digit, digit .. " is not an integer")
end
end
return true
end
-- Return a new big with the same digits but with a positive sign (absolute
-- value)
function bigint.abs(big)
bigint.check(big)
local result = big:clone()
result.sign = "+"
return result
end
-- Return a new big with the same digits but the opposite sign (negation)
function bigint.negate(big)
bigint.check(big)
local result = big:clone()
if (result.sign == "+") then
result.sign = "-"
else
result.sign = "+"
end
return result
end
-- Return the number of digits in the big
function bigint.digits(big)
bigint.check(big)
return #big.digits
end
-- Convert a big to a number or string
function bigint.unserialize(big, output_type, precision)
bigint.check(big)
local num = ""
if big.sign == "-" then
num = "-"
end
if ((output_type == nil)
or (output_type == "number")
or (output_type == "n")
or (output_type == "string")
or (output_type == "s")) then
-- Unserialization to a string or number requires reconstructing the
-- entire number
for _, digit in pairs(big.digits) do
num = num .. math.floor(digit) -- lazy way of getting rid of .0$
end
if ((output_type == nil)
or (output_type == "number")
or (output_type == "n")) then
return tonumber(num)
else
return num
end
else
-- Unserialization to human-readable form or scientific notation only
-- requires reading the first few digits
if (precision == nil) then
precision = math.min(#big.digits, 3)
else
assert(precision > 0, "Precision cannot be less than 1")
assert(math.floor(precision) == precision,
"Precision must be a positive integer")
end
-- num is the first (precision + 1) digits, the first being separated by
-- a decimal point from the others
num = num .. math.floor(big.digits[1])
if (precision > 1) then
num = num .. "."
for i = 1, (precision - 1) do
num = num .. math.floor(big.digits[i + 1])
end
end
if ((output_type == "human-readable")
or (output_type == "human")
or (output_type == "h"))
and (#big.digits >= 3 and #big.digits <= 10002) then
-- Human-readable output contributed by 123eee555
local name
local walkback = 0 -- Used to enumerate "ten", "hundred", etc
-- Walk backwards in the index of named_powers starting at the
-- number of digits of the input until the first value is found
for i = (#big.digits - 1), (#big.digits - 4), -1 do
name = named_powers[i]
if (name) then
if (walkback == 1) then
name = "ten " .. name
elseif (walkback == 2) then
name = "hundred " .. name
end
break
else
walkback = walkback + 1
end
end
return num .. " " .. name
else
return num .. "*10^" .. (#big.digits - 1)
end
end
end
-- Basic comparisons
-- Accepts symbols (<, >=, ~=) and Unix shell-like options (lt, ge, ne)
function bigint.compare(big1, big2, comparison)
bigint.check(big1)
bigint.check(big2)
local greater = false -- If big1.digits > big2.digits
local equal = false
if (big1.sign == "-") and (big2.sign == "+") then
greater = false
elseif (#big1.digits > #big2.digits)
or ((big1.sign == "+") and (big2.sign == "-")) then
greater = true
elseif (#big1.digits == #big2.digits) then
-- Walk left to right, comparing digits
for digit = 1, #big1.digits do
if (big1.digits[digit] > big2.digits[digit]) then
greater = true
break
elseif (big2.digits[digit] > big1.digits[digit]) then
break
elseif (digit == #big1.digits)
and (big1.digits[digit] == big2.digits[digit]) then
equal = true
end
end
end
-- If both numbers are negative, then the requirements for greater are
-- reversed
if (not equal) and (big1.sign == "-") and (big2.sign == "-") then
greater = not greater
end
return (((comparison == "<") or (comparison == "lt"))
and ((not greater) and (not equal)) and true)
or (((comparison == ">") or (comparison == "gt"))
and ((greater) and (not equal)) and true)
or (((comparison == "==") or (comparison == "eq"))
and (equal) and true)
or (((comparison == ">=") or (comparison == "ge"))
and (equal or greater) and true)
or (((comparison == "<=") or (comparison == "le"))
and (equal or not greater) and true)
or (((comparison == "~=") or (comparison == "!=") or (comparison == "ne"))
and (not equal) and true)
or false
end
-- BACKEND: Add big1 and big2, ignoring signs
function bigint.add_raw(big1, big2)
bigint.check(big1)
bigint.check(big2)
local result = bigint.new()
local max_digits = 0
local carry = 0
if (#big1.digits >= #big2.digits) then
max_digits = #big1.digits
else
max_digits = #big2.digits
end
-- Walk backwards right to left, like in long addition
for digit = 0, max_digits - 1 do
local sum = (big1.digits[#big1.digits - digit] or 0)
+ (big2.digits[#big2.digits - digit] or 0)
+ carry
if (sum >= 10) then
carry = 1
sum = sum - 10
else
carry = 0
end
result.digits[max_digits - digit] = sum
end
-- Leftover carry in cases when #big1.digits == #big2.digits and sum > 10, ex. 7 + 9
if (carry == 1) then
table.insert(result.digits, 1, 1)
end
return result
end
-- BACKEND: Subtract big2 from big1, ignoring signs
function bigint.subtract_raw(big1, big2)
-- Type checking is done by bigint.compare
assert(bigint.compare(bigint.abs(big1), bigint.abs(big2), ">="),
"Size of " .. bigint.unserialize(big1, "string") .. " is less than "
.. bigint.unserialize(big2, "string"))
local result = big1:clone()
local max_digits = #big1.digits
local borrow = 0
-- Logic mostly copied from bigint.add_raw ---------------------------------
-- Walk backwards right to left, like in long subtraction
for digit = 0, max_digits - 1 do
local diff = (big1.digits[#big1.digits - digit] or 0)
- (big2.digits[#big2.digits - digit] or 0)
- borrow
if (diff < 0) then
borrow = 1
diff = diff + 10
else
borrow = 0
end
result.digits[max_digits - digit] = diff
end
----------------------------------------------------------------------------
-- Strip leading zeroes if any, but not if 0 is the only digit
while (#result.digits > 1) and (result.digits[1] == 0) do
table.remove(result.digits, 1)
end
return result
end
-- FRONTEND: Addition and subtraction operations, accounting for signs
function bigint.add(big1, big2)
-- Type checking is done by bigint.compare
local result
-- If adding numbers of different sign, subtract the smaller sized one from
-- the bigger sized one and take the sign of the bigger sized one
if (big1.sign ~= big2.sign) then
if (bigint.compare(bigint.abs(big1), bigint.abs(big2), ">")) then
result = bigint.subtract_raw(big1, big2)
result.sign = big1.sign
else
result = bigint.subtract_raw(big2, big1)
result.sign = big2.sign
end
elseif (big1.sign == "+") and (big2.sign == "+") then
result = bigint.add_raw(big1, big2)
elseif (big1.sign == "-") and (big2.sign == "-") then
result = bigint.add_raw(big1, big2)
result.sign = "-"
end
return result
end
function bigint.subtract(big1, big2)
-- Type checking is done by bigint.compare in bigint.add
-- Subtracting is like adding a negative
local big2_local = big2:clone()
if (big2.sign == "+") then
big2_local.sign = "-"
else
big2_local.sign = "+"
end
return bigint.add(big1, big2_local)
end
-- BACKEND: Multiply a big by a single digit big, ignoring signs
function bigint.multiply_single(big1, big2)
bigint.check(big1)
bigint.check(big2)
assert(#big2.digits == 1, bigint.unserialize(big2, "string")
.. " has more than one digit")
local result = bigint.new()
local carry = 0
-- Logic mostly copied from bigint.add_raw ---------------------------------
-- Walk backwards right to left, like in long multiplication
for digit = 0, #big1.digits - 1 do
local this_digit = big1.digits[#big1.digits - digit]
* big2.digits[1]
+ carry
if (this_digit >= 10) then
carry = math.floor(this_digit / 10)
this_digit = this_digit - (carry * 10)
else
carry = 0
end
result.digits[#big1.digits - digit] = this_digit
end
-- Leftover carry in cases when big1.digits[1] * big2.digits[1] > 0
if (carry > 0) then
table.insert(result.digits, 1, carry)
end
----------------------------------------------------------------------------
return result
end
-- FRONTEND: Multiply two bigs, accounting for signs
function bigint.multiply(big1, big2)
-- Type checking done by bigint.multiply_single
local result = bigint.new(0)
local larger, smaller -- Larger and smaller in terms of digits, not size
if (bigint.unserialize(big1) == 0) or (bigint.unserialize(big2) == 0) then
return result
end
if (#big1.digits >= #big2.digits) then
larger = big1
smaller = big2
else
larger = big2
smaller = big1
end
-- Walk backwards right to left, like in long multiplication
for digit = 0, #smaller.digits - 1 do
-- Sorry for going over column 80! There's lots of big names here
local this_digit_product = bigint.multiply_single(larger,
bigint.new(smaller.digits[#smaller.digits - digit]))
-- "Placeholding zeroes"
if (digit > 0) then
for placeholder = 1, digit do
table.insert(this_digit_product.digits, 0)
end
end
result = bigint.add(result, this_digit_product)
end
if (larger.sign == smaller.sign) then
result.sign = "+"
else
result.sign = "-"
end
return result
end
-- Raise a big to a positive integer or big power (TODO: negative integer power)
function bigint.exponentiate(big, power)
-- Type checking for big done by bigint.multiply
assert(bigint.compare(power, bigint.new(0), ">="),
" negative powers are not supported")
local exp = power:clone()
if (bigint.compare(exp, bigint.new(0), "==")) then
return bigint.new(1)
elseif (bigint.compare(exp, bigint.new(1), "==")) then
return big:clone()
else
local result = bigint.new(1)
local base = big:clone()
while (true) do
if (bigint.compare(
bigint.modulus(exp, bigint.new(2)), bigint.new(1), "=="
)) then
result = bigint.multiply(result, base)
end
if (bigint.compare(exp, bigint.new(1), "==")) then
break
else
exp = bigint.divide(exp, bigint.new(2))
base = bigint.multiply(base, base)
end
end
return result
end
end
-- BACKEND: Divide two bigs (decimals not supported), returning big result and
-- big remainder
-- WARNING: Only supports positive integers
function bigint.divide_raw(big1, big2)
-- Type checking done by bigint.compare
if (bigint.compare(big1, big2, "==")) then
return bigint.new(1), bigint.new(0)
elseif (bigint.compare(big1, big2, "<")) then
return bigint.new(0), big1:clone()
else
assert(bigint.compare(big2, bigint.new(0), "!="), "error: divide by zero")
assert(big1.sign == "+", "error: big1 is not positive")
assert(big2.sign == "+", "error: big2 is not positive")
local result = bigint.new()
local dividend = bigint.new() -- Dividend of a single operation
local neg_zero = bigint.new(0)
neg_zero.sign = "-"
for i = 1, #big1.digits do
-- Fixes a negative zero bug
if (#dividend.digits ~= 0) and (bigint.compare(dividend, neg_zero, "==")) then
dividend = bigint.new()
end
table.insert(dividend.digits, big1.digits[i])
local factor = bigint.new(0)
while bigint.compare(dividend, big2, ">=") do
dividend = bigint.subtract(dividend, big2)
factor = bigint.add(factor, bigint.new(1))
end
for i = 0, #factor.digits - 1 do
result.digits[#result.digits + 1 - i] = factor.digits[i + 1]
end
end
-- Remove leading zeros from result
while (result.digits[1] == 0) do
table.remove(result.digits, 1)
end
return result, dividend
end
end
-- FRONTEND: Divide two bigs (decimals not supported), returning big result and
-- big remainder, accounting for signs
function bigint.divide(big1, big2)
local result, remainder = bigint.divide_raw(bigint.abs(big1),
bigint.abs(big2))
if (big1.sign == big2.sign) then
result.sign = "+"
else
result.sign = "-"
end
return result, remainder
end
-- FRONTEND: Return only the remainder from bigint.divide
function bigint.modulus(big1, big2)
local result, remainder = bigint.divide(big1, big2)
-- Remainder will always have the same sign as the dividend per C standard
-- https://en.wikipedia.org/wiki/Modulo_operation#Remainder_calculation_for_the_modulo_operation
remainder.sign = big1.sign
return remainder
end
return bigint

File diff suppressed because it is too large Load Diff

BIN
libs/discord-rpc.dll Normal file

Binary file not shown.

BIN
libs/discord-rpc.dylib Normal file

Binary file not shown.

BIN
libs/discord-rpc.so Normal file

Binary file not shown.

282
libs/discordRPC.lua Normal file
View File

@@ -0,0 +1,282 @@
local ffi = require "ffi"
-- Get the host os to load correct lib
local osname = love.system.getOS()
local discordRPClib = nil
-- FFI requires the libraries really be files just sitting in the filesystem. It
-- can't load libraries from a .love archive, nor a fused executable on Windows.
-- Merely using love.filesystem.getSource() only works when running LOVE with
-- the game unarchived from command line, like "love .".
--
-- The code here setting "source" will set the directory where the game was run
-- from, so FFI can load discordRPC. We assume that the discordRPC library's
-- libs directory is in the same directory as the .love archive; if it's
-- missing, it just won't load.
local source = love.filesystem.getSource()
if string.sub(source, -5) == ".love" or love.filesystem.isFused() then
source = love.filesystem.getSourceBaseDirectory()
end
if osname == "Linux" then
discordRPClib = ffi.load(source.."/libs/discord-rpc.so")
elseif osname == "OS X" then
discordRPClib = ffi.load(source.."/libs/discord-rpc.dylib")
elseif osname == "Windows" then
discordRPClib = ffi.load(source.."/libs/discord-rpc.dll")
else
-- Else it crashes later on
error(string.format("Discord rpc not supported on platform (%s)", osname))
end
ffi.cdef[[
typedef struct DiscordRichPresence {
const char* state; /* max 128 bytes */
const char* details; /* max 128 bytes */
int64_t startTimestamp;
int64_t endTimestamp;
const char* largeImageKey; /* max 32 bytes */
const char* largeImageText; /* max 128 bytes */
const char* smallImageKey; /* max 32 bytes */
const char* smallImageText; /* max 128 bytes */
const char* partyId; /* max 128 bytes */
int partySize;
int partyMax;
const char* matchSecret; /* max 128 bytes */
const char* joinSecret; /* max 128 bytes */
const char* spectateSecret; /* max 128 bytes */
int8_t instance;
} DiscordRichPresence;
typedef struct DiscordUser {
const char* userId;
const char* username;
const char* discriminator;
const char* avatar;
} DiscordUser;
typedef void (*readyPtr)(const DiscordUser* request);
typedef void (*disconnectedPtr)(int errorCode, const char* message);
typedef void (*erroredPtr)(int errorCode, const char* message);
typedef void (*joinGamePtr)(const char* joinSecret);
typedef void (*spectateGamePtr)(const char* spectateSecret);
typedef void (*joinRequestPtr)(const DiscordUser* request);
typedef struct DiscordEventHandlers {
readyPtr ready;
disconnectedPtr disconnected;
erroredPtr errored;
joinGamePtr joinGame;
spectateGamePtr spectateGame;
joinRequestPtr joinRequest;
} DiscordEventHandlers;
void Discord_Initialize(const char* applicationId,
DiscordEventHandlers* handlers,
int autoRegister,
const char* optionalSteamId);
void Discord_Shutdown(void);
void Discord_RunCallbacks(void);
void Discord_UpdatePresence(const DiscordRichPresence* presence);
void Discord_ClearPresence(void);
void Discord_Respond(const char* userid, int reply);
void Discord_UpdateHandlers(DiscordEventHandlers* handlers);
]]
local discordRPC = {} -- module table
-- proxy to detect garbage collection of the module
discordRPC.gcDummy = newproxy(true)
local function unpackDiscordUser(request)
return ffi.string(request.userId), ffi.string(request.username),
ffi.string(request.discriminator), ffi.string(request.avatar)
end
-- callback proxies
-- note: callbacks are not JIT compiled (= SLOW), try to avoid doing performance critical tasks in them
-- luajit.org/ext_ffi_semantics.html
local ready_proxy = ffi.cast("readyPtr", function(request)
if discordRPC.ready then
discordRPC.ready(unpackDiscordUser(request))
end
end)
local disconnected_proxy = ffi.cast("disconnectedPtr", function(errorCode, message)
if discordRPC.disconnected then
discordRPC.disconnected(errorCode, ffi.string(message))
end
end)
local errored_proxy = ffi.cast("erroredPtr", function(errorCode, message)
if discordRPC.errored then
discordRPC.errored(errorCode, ffi.string(message))
end
end)
local joinGame_proxy = ffi.cast("joinGamePtr", function(joinSecret)
if discordRPC.joinGame then
discordRPC.joinGame(ffi.string(joinSecret))
end
end)
local spectateGame_proxy = ffi.cast("spectateGamePtr", function(spectateSecret)
if discordRPC.spectateGame then
discordRPC.spectateGame(ffi.string(spectateSecret))
end
end)
local joinRequest_proxy = ffi.cast("joinRequestPtr", function(request)
if discordRPC.joinRequest then
discordRPC.joinRequest(unpackDiscordUser(request))
end
end)
-- helpers
local function checkArg(arg, argType, argName, func, maybeNil)
assert(type(arg) == argType or (maybeNil and arg == nil),
string.format("Argument \"%s\" to function \"%s\" has to be of type \"%s\"",
argName, func, argType))
end
local function checkStrArg(arg, maxLen, argName, func, maybeNil)
if maxLen then
assert(type(arg) == "string" and arg:len() <= maxLen or (maybeNil and arg == nil),
string.format("Argument \"%s\" of function \"%s\" has to be of type string with maximum length %d",
argName, func, maxLen))
else
checkArg(arg, "string", argName, func, true)
end
end
local function checkIntArg(arg, maxBits, argName, func, maybeNil)
maxBits = math.min(maxBits or 32, 52) -- lua number (double) can only store integers < 2^53
local maxVal = 2^(maxBits-1) -- assuming signed integers, which, for now, are the only ones in use
assert(type(arg) == "number" and math.floor(arg) == arg
and arg < maxVal and arg >= -maxVal
or (maybeNil and arg == nil),
string.format("Argument \"%s\" of function \"%s\" has to be a whole number <= %d",
argName, func, maxVal))
end
-- function wrappers
function discordRPC.initialize(applicationId, autoRegister, optionalSteamId)
local func = "discordRPC.Initialize"
checkStrArg(applicationId, nil, "applicationId", func)
checkArg(autoRegister, "boolean", "autoRegister", func)
if optionalSteamId ~= nil then
checkStrArg(optionalSteamId, nil, "optionalSteamId", func)
end
local eventHandlers = ffi.new("struct DiscordEventHandlers")
eventHandlers.ready = ready_proxy
eventHandlers.disconnected = disconnected_proxy
eventHandlers.errored = errored_proxy
eventHandlers.joinGame = joinGame_proxy
eventHandlers.spectateGame = spectateGame_proxy
eventHandlers.joinRequest = joinRequest_proxy
discordRPClib.Discord_Initialize(applicationId, eventHandlers,
autoRegister and 1 or 0, optionalSteamId)
end
function discordRPC.shutdown()
discordRPClib.Discord_Shutdown()
end
function discordRPC.runCallbacks()
discordRPClib.Discord_RunCallbacks()
end
-- http://luajit.org/ext_ffi_semantics.html#callback :
-- It is not allowed, to let an FFI call into a C function (runCallbacks)
-- get JIT-compiled, which in turn calls a callback, calling into Lua again (e.g. discordRPC.ready).
-- Usually this attempt is caught by the interpreter first and the C function
-- is blacklisted for compilation.
-- solution:
-- "Then you'll need to manually turn off JIT-compilation with jit.off() for
-- the surrounding Lua function that invokes such a message polling function."
jit.off(discordRPC.runCallbacks)
function discordRPC.updatePresence(presence)
local func = "discordRPC.updatePresence"
checkArg(presence, "table", "presence", func)
-- -1 for string length because of 0-termination
checkStrArg(presence.state, 127, "presence.state", func, true)
checkStrArg(presence.details, 127, "presence.details", func, true)
checkIntArg(presence.startTimestamp, 64, "presence.startTimestamp", func, true)
checkIntArg(presence.endTimestamp, 64, "presence.endTimestamp", func, true)
checkStrArg(presence.largeImageKey, 31, "presence.largeImageKey", func, true)
checkStrArg(presence.largeImageText, 127, "presence.largeImageText", func, true)
checkStrArg(presence.smallImageKey, 31, "presence.smallImageKey", func, true)
checkStrArg(presence.smallImageText, 127, "presence.smallImageText", func, true)
checkStrArg(presence.partyId, 127, "presence.partyId", func, true)
checkIntArg(presence.partySize, 32, "presence.partySize", func, true)
checkIntArg(presence.partyMax, 32, "presence.partyMax", func, true)
checkStrArg(presence.matchSecret, 127, "presence.matchSecret", func, true)
checkStrArg(presence.joinSecret, 127, "presence.joinSecret", func, true)
checkStrArg(presence.spectateSecret, 127, "presence.spectateSecret", func, true)
checkIntArg(presence.instance, 8, "presence.instance", func, true)
local cpresence = ffi.new("struct DiscordRichPresence")
cpresence.state = presence.state
cpresence.details = presence.details
cpresence.startTimestamp = presence.startTimestamp or 0
cpresence.endTimestamp = presence.endTimestamp or 0
cpresence.largeImageKey = presence.largeImageKey
cpresence.largeImageText = presence.largeImageText
cpresence.smallImageKey = presence.smallImageKey
cpresence.smallImageText = presence.smallImageText
cpresence.partyId = presence.partyId
cpresence.partySize = presence.partySize or 0
cpresence.partyMax = presence.partyMax or 0
cpresence.matchSecret = presence.matchSecret
cpresence.joinSecret = presence.joinSecret
cpresence.spectateSecret = presence.spectateSecret
cpresence.instance = presence.instance or 0
discordRPClib.Discord_UpdatePresence(cpresence)
end
function discordRPC.clearPresence()
discordRPClib.Discord_ClearPresence()
end
local replyMap = {
no = 0,
yes = 1,
ignore = 2
}
-- maybe let reply take ints too (0, 1, 2) and add constants to the module
function discordRPC.respond(userId, reply)
checkStrArg(userId, nil, "userId", "discordRPC.respond")
assert(replyMap[reply], "Argument 'reply' to discordRPC.respond has to be one of \"yes\", \"no\" or \"ignore\"")
discordRPClib.Discord_Respond(userId, replyMap[reply])
end
-- garbage collection callback
getmetatable(discordRPC.gcDummy).__gc = function()
discordRPC.shutdown()
ready_proxy:free()
disconnected_proxy:free()
errored_proxy:free()
joinGame_proxy:free()
spectateGame_proxy:free()
joinRequest_proxy:free()
end
return discordRPC

138
libs/simple-slider.lua Normal file
View File

@@ -0,0 +1,138 @@
--[[
Copyright (c) 2016 George Prosser
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
]]
local slider = {}
slider.__index = slider
function newSlider(x, y, length, value, min, max, setter, style)
local s = {}
s.value = (value - min) / (max - min)
s.min = min
s.max = max
s.setter = setter
s.x = x
s.y = y
s.length = length
local p = style or {}
s.width = p.width or length * 0.1
s.orientation = p.orientation or 'horizontal'
s.track = p.track or 'rectangle'
s.knob = p.knob or 'rectangle'
s.grabbed = false
s.wasDown = true
s.ox = 0
s.oy = 0
return setmetatable(s, slider)
end
function slider:update(mouseX, mouseY, mouseDown)
local x = mouseX or love.mouse.getX()
local y = mouseY or love.mouse.getY()
local down = love.mouse.isDown(1)
if mouseDown ~= nil then
down = mouseDown
end
local knobX = self.x
local knobY = self.y
if self.orientation == 'horizontal' then
knobX = self.x - self.length/2 + self.length * self.value
elseif self.orientation == 'vertical' then
knobY = self.y + self.length/2 - self.length * self.value
end
local ox = x - knobX
local oy = y - knobY
local dx = ox - self.ox
local dy = oy - self.oy
if down then
if self.grabbed then
if self.orientation == 'horizontal' then
self.value = self.value + dx / self.length
elseif self.orientation == 'vertical' then
self.value = self.value - dy / self.length
end
elseif (x > knobX - self.width/2 and x < knobX + self.width/2 and y > knobY - self.width/2 and y < knobY + self.width/2) and not self.wasDown then
self.ox = ox
self.oy = oy
self.grabbed = true
end
else
self.grabbed = false
end
self.value = math.max(0, math.min(1, self.value))
if self.setter ~= nil then
self.setter(self.min + self.value * (self.max - self.min))
end
self.wasDown = down
end
function slider:draw()
if self.track == 'rectangle' then
if self.orientation == 'horizontal' then
love.graphics.rectangle('line', self.x - self.length/2 - self.width/2, self.y - self.width/2, self.length + self.width, self.width)
elseif self.orientation == 'vertical' then
love.graphics.rectangle('line', self.x - self.width/2, self.y - self.length/2 - self.width/2, self.width, self.length + self.width)
end
elseif self.track == 'line' then
if self.orientation == 'horizontal' then
love.graphics.line(self.x - self.length/2, self.y, self.x + self.length/2, self.y)
elseif self.orientation == 'vertical' then
love.graphics.line(self.x, self.y - self.length/2, self.x, self.y + self.length/2)
end
elseif self.track == 'roundrect' then
if self.orientation == 'horizontal' then
love.graphics.rectangle('line', self.x - self.length/2 - self.width/2, self.y - self.width/2, self.length + self.width, self.width, self.width/2, self.width)
elseif self.orientation == 'vertical' then
love.graphics.rectangle('line', self.x - self.width/2, self.y - self.length/2 - self.width/2, self.width, self.length + self.width, self.width, self.width/2)
end
end
local knobX = self.x
local knobY = self.y
if self.orientation == 'horizontal' then
knobX = self.x - self.length/2 + self.length * self.value
elseif self.orientation == 'vertical' then
knobY = self.y + self.length/2 - self.length * self.value
end
if self.knob == 'rectangle' then
love.graphics.rectangle('fill', knobX - self.width/2, knobY - self.width/2, self.width, self.width)
elseif self.knob == 'circle' then
love.graphics.circle('fill', knobX, knobY, self.width/2)
end
end
function slider:getValue()
return self.min + self.value * (self.max - self.min)
end

View File

@@ -9,31 +9,38 @@ local current_bgm = nil
local bgm_locked = false
function switchBGM(sound, subsound)
if bgm_locked then return end
if current_bgm ~= nil then
current_bgm:stop()
end
if subsound ~= nil then
current_bgm = bgm[sound][subsound]
resetBGMFadeout()
if bgm_locked or config.bgm_volume <= 0 then
current_bgm = nil
elseif sound ~= nil then
current_bgm = bgm[sound]
resetBGMFadeout()
if subsound ~= nil then
current_bgm = bgm[sound][subsound]
else
current_bgm = bgm[sound]
end
else
current_bgm = nil
end
if current_bgm ~= nil then
resetBGMFadeout()
end
end
function switchBGMLoop(sound, subsound)
if bgm_locked then return end
switchBGM(sound, subsound)
current_bgm:setLooping(true)
if current_bgm then current_bgm:setLooping(true) end
end
function lockBGM()
bgm_locked = true
end
function unlockBGM()
bgm_locked = false
end
local fading_bgm = false
local fadeout_time = 0
local total_fadeout_time = 0
@@ -47,19 +54,19 @@ function fadeoutBGM(time)
end
function resetBGMFadeout(time)
current_bgm:setVolume(1)
current_bgm:setVolume(config.bgm_volume)
fading_bgm = false
current_bgm:play()
end
function processBGMFadeout(dt)
if fading_bgm then
if current_bgm and fading_bgm then
fadeout_time = fadeout_time - dt
if fadeout_time < 0 then
fadeout_time = 0
fading_bgm = false
end
current_bgm:setVolume(fadeout_time / total_fadeout_time)
current_bgm:setVolume(fadeout_time * config.bgm_volume / total_fadeout_time)
end
end

2
load/bigint.lua Normal file
View File

@@ -0,0 +1,2 @@
bigint = require "libs.bigint.bigint"
number_names = require "libs.bigint.named-powers-of-ten"

View File

@@ -1,54 +1,95 @@
backgrounds = {
[0] = love.graphics.newImage("res/backgrounds/0-quantum-foam.png"),
love.graphics.newImage("res/backgrounds/100-big-bang.png"),
love.graphics.newImage("res/backgrounds/200-spiral-galaxy.png"),
love.graphics.newImage("res/backgrounds/300-sun-and-dust.png"),
love.graphics.newImage("res/backgrounds/400-earth-and-moon.png"),
love.graphics.newImage("res/backgrounds/500-cambrian-explosion.png"),
love.graphics.newImage("res/backgrounds/600-dinosaurs.png"),
love.graphics.newImage("res/backgrounds/700-asteroid.png"),
love.graphics.newImage("res/backgrounds/800-human-fire.png"),
love.graphics.newImage("res/backgrounds/900-early-civilization.png"),
love.graphics.newImage("res/backgrounds/1000-vikings.png"),
love.graphics.newImage("res/backgrounds/1100-crusades.png"),
love.graphics.newImage("res/backgrounds/1200-genghis-khan.png"),
love.graphics.newImage("res/backgrounds/1300-black-death.png"),
love.graphics.newImage("res/backgrounds/1400-columbus-discovery.png"),
love.graphics.newImage("res/backgrounds/1500-aztecas.png"),
love.graphics.newImage("res/backgrounds/1600-telescope.png"),
love.graphics.newImage("res/backgrounds/1700-american-revolution.png"),
love.graphics.newImage("res/backgrounds/1800-railways.png"),
love.graphics.newImage("res/backgrounds/1900-world-wide-web.png"),
title = love.graphics.newImage("res/backgrounds/title_v0.1.png"),
[0] = love.graphics.newImage("res/backgrounds/0.png"),
love.graphics.newImage("res/backgrounds/100.png"),
love.graphics.newImage("res/backgrounds/200.png"),
love.graphics.newImage("res/backgrounds/300.png"),
love.graphics.newImage("res/backgrounds/400.png"),
love.graphics.newImage("res/backgrounds/500.png"),
love.graphics.newImage("res/backgrounds/600.png"),
love.graphics.newImage("res/backgrounds/700.png"),
love.graphics.newImage("res/backgrounds/800.png"),
love.graphics.newImage("res/backgrounds/900.png"),
love.graphics.newImage("res/backgrounds/1000.png"),
love.graphics.newImage("res/backgrounds/1100.png"),
love.graphics.newImage("res/backgrounds/1200.png"),
love.graphics.newImage("res/backgrounds/1300.png"),
love.graphics.newImage("res/backgrounds/1400.png"),
love.graphics.newImage("res/backgrounds/1500.png"),
love.graphics.newImage("res/backgrounds/1600.png"),
love.graphics.newImage("res/backgrounds/1700.png"),
love.graphics.newImage("res/backgrounds/1800.png"),
love.graphics.newImage("res/backgrounds/1900.png"),
title = love.graphics.newImage("res/backgrounds/title.png"),
snow = love.graphics.newImage("res/backgrounds/snow.png"),
input_config = love.graphics.newImage("res/backgrounds/options-input.png"),
game_config = love.graphics.newImage("res/backgrounds/options-game.png"),
}
blocks = {
["2tie"] = {
I = love.graphics.newImage("res/img/s1.png"),
J = love.graphics.newImage("res/img/s4.png"),
L = love.graphics.newImage("res/img/s3.png"),
O = love.graphics.newImage("res/img/s7.png"),
S = love.graphics.newImage("res/img/s5.png"),
T = love.graphics.newImage("res/img/s2.png"),
Z = love.graphics.newImage("res/img/s6.png"),
R = love.graphics.newImage("res/img/s1.png"),
O = love.graphics.newImage("res/img/s3.png"),
Y = love.graphics.newImage("res/img/s7.png"),
G = love.graphics.newImage("res/img/s6.png"),
C = love.graphics.newImage("res/img/s2.png"),
B = love.graphics.newImage("res/img/s4.png"),
M = love.graphics.newImage("res/img/s5.png"),
F = love.graphics.newImage("res/img/s9.png"),
G = love.graphics.newImage("res/img/s9.png"),
A = love.graphics.newImage("res/img/s8.png"),
X = love.graphics.newImage("res/img/s9.png"),
},
["bone"] = {
I = love.graphics.newImage("res/img/bone.png"),
J = love.graphics.newImage("res/img/bone.png"),
L = love.graphics.newImage("res/img/bone.png"),
R = love.graphics.newImage("res/img/bone.png"),
O = love.graphics.newImage("res/img/bone.png"),
S = love.graphics.newImage("res/img/bone.png"),
T = love.graphics.newImage("res/img/bone.png"),
Z = love.graphics.newImage("res/img/bone.png"),
F = love.graphics.newImage("res/img/bone.png"),
Y = love.graphics.newImage("res/img/bone.png"),
G = love.graphics.newImage("res/img/bone.png"),
C = love.graphics.newImage("res/img/bone.png"),
B = love.graphics.newImage("res/img/bone.png"),
M = love.graphics.newImage("res/img/bone.png"),
F = love.graphics.newImage("res/img/bone.png"),
A = love.graphics.newImage("res/img/bone.png"),
X = love.graphics.newImage("res/img/bone.png"),
},
["gem"] = {
R = love.graphics.newImage("res/img/gem1.png"),
O = love.graphics.newImage("res/img/gem3.png"),
Y = love.graphics.newImage("res/img/gem7.png"),
G = love.graphics.newImage("res/img/gem6.png"),
C = love.graphics.newImage("res/img/gem2.png"),
B = love.graphics.newImage("res/img/gem4.png"),
M = love.graphics.newImage("res/img/gem5.png"),
F = love.graphics.newImage("res/img/gem9.png"),
A = love.graphics.newImage("res/img/gem9.png"),
X = love.graphics.newImage("res/img/gem9.png"),
},
["square"] = {
F = love.graphics.newImage("res/img/squares.png"),
Y = love.graphics.newImage("res/img/squareg.png"),
X = love.graphics.newImage("res/img/squares.png"),
}
}
ColourSchemes = {
Arika = {
I = "R",
L = "O",
J = "B",
S = "M",
Z = "G",
O = "Y",
T = "C",
},
TTC = {
I = "C",
L = "O",
J = "B",
S = "G",
Z = "R",
O = "Y",
T = "M",
},
}
for name, blockset in pairs(blocks) do
for shape, image in pairs(blockset) do
image:setFilter("nearest")
@@ -61,4 +102,5 @@ misc_graphics = {
go = love.graphics.newImage("res/img/go.png"),
select_mode = love.graphics.newImage("res/img/select_mode.png"),
strike = love.graphics.newImage("res/img/strike.png"),
}
santa = love.graphics.newImage("res/img/santa.png")
}

58
load/rpc.lua Normal file
View File

@@ -0,0 +1,58 @@
print("Loading discord RPC...")
DiscordRPC = {
loaded = false
}
local success, RPC = pcall(require, "libs.discordRPC")
if success then
DiscordRPC.loaded = true
DiscordRPC.appId = "599778517789573120"
function RPC.ready(userId, username, discriminator, avatar)
print(string.format("Discord: ready (%s, %s, %s, %s)", userId, username, discriminator, avatar))
end
function RPC.disconnected(errorCode, message)
print(string.format("Discord: disconnected (%d: %s)", errorCode, message))
end
function RPC.errored(errorCode, message)
print(string.format("Discord: error (%d: %s)", errorCode, message))
end
function RPC.joinGame(joinSecret)
print(string.format("Discord: join (%s)", joinSecret))
end
function RPC.spectateGame(spectateSecret)
print(string.format("Discord: spectate (%s)", spectateSecret))
end
function RPC.joinRequest(userId, username, discriminator, avatar)
print(string.format("Discord: join request (%s, %s, %s, %s)", userId, username, discriminator, avatar))
RPC.respond(userId, "yes")
end
RPC.initialize(DiscordRPC.appId, true)
local now = os.time(os.date("*t"))
DiscordRPC.RPC = RPC
print("DiscordRPC successfully loaded.")
else
print("DiscordRPC failed to load!")
print(RPC)
end
DiscordRPC.presence = {
startTimestamp = now,
details = "Loading game...",
state = "",
largeImageKey = "icon2",
largeImageText = "Arcade Stacker",
smallImageKey = "",
smallImageText = ""
}
function DiscordRPC:update(newstuff)
for k, v in pairs(newstuff) do self.presence[k] = v end
if self.loaded then self.RPC.updatePresence(self.presence) end
end

View File

@@ -1,8 +1,19 @@
local binser = require 'libs.binser'
function loadSave()
config = loadFromFile('config.sav')
highscores = loadFromFile('highscores.sav')
local info = love.filesystem.getInfo(
love.filesystem.getSaveDirectory(), "directory"
)
if not info then
love.filesystem.remove(love.filesystem.getSaveDirectory())
love.filesystem.createDirectory(love.filesystem.getSaveDirectory())
end
config = loadFromFile(
love.filesystem.getSaveDirectory() .. '/config.sav'
)
highscores = loadFromFile(
love.filesystem.getSaveDirectory() .. '/highscores.sav'
)
end
function loadFromFile(filename)
@@ -13,12 +24,40 @@ function loadFromFile(filename)
return save_data[1]
end
function initConfig()
if not config.das then config.das = 10 end
if not config.arr then config.arr = 2 end
if not config.dcd then config.dcd = 0 end
if not config.sfx_volume then config.sfx_volume = 0.5 end
if not config.bgm_volume then config.bgm_volume = 0.5 end
if config.fullscreen == nil then config.fullscreen = false end
if config.secret == nil then config.secret = false end
if not config.gamesettings then config.gamesettings = {} end
for _, option in ipairs(GameConfigScene.options) do
if not config.gamesettings[option[1]] then
config.gamesettings[option[1]] = 1
end
end
if not config.input then
scene = InputConfigScene()
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()
end
end
function saveConfig()
binser.writeFile('config.sav', config)
binser.writeFile(
love.filesystem.getSaveDirectory() .. '/config.sav', config
)
end
function saveHighscores()
binser.writeFile('highscores.sav', highscores)
binser.writeFile(
love.filesystem.getSaveDirectory() .. '/highscores.sav', highscores
)
end

View File

@@ -10,20 +10,54 @@ sounds = {
},
move = love.audio.newSource("res/se/move.wav", "static"),
bottom = love.audio.newSource("res/se/bottom.wav", "static"),
cursor = love.audio.newSource("res/se/cursor.wav", "static"),
cursor_lr = love.audio.newSource("res/se/cursor_lr.wav", "static"),
main_decide = love.audio.newSource("res/se/main_decide.wav", "static"),
mode_decide = love.audio.newSource("res/se/mode_decide.wav", "static"),
lock = love.audio.newSource("res/se/lock.wav", "static"),
hold = love.audio.newSource("res/se/hold.wav", "static"),
erase = love.audio.newSource("res/se/erase.wav", "static"),
fall = love.audio.newSource("res/se/fall.wav", "static"),
ready = love.audio.newSource("res/se/ready.wav", "static"),
go = love.audio.newSource("res/se/go.wav", "static"),
irs = love.audio.newSource("res/se/irs.wav", "static"),
ihs = love.audio.newSource("res/se/ihs.wav", "static"),
-- a secret sound!
welcome = love.audio.newSource("res/se/welcomeToCambridge.wav", "static"),
}
function playSE(sound, subsound)
if subsound == nil then
sounds[sound]:setVolume(0.1)
if sounds[sound]:isPlaying() then
sounds[sound]:stop()
if sound ~= nil then
if subsound ~= nil then
sounds[sound][subsound]:setVolume(config.sfx_volume)
if sounds[sound][subsound]:isPlaying() then
sounds[sound][subsound]:stop()
end
sounds[sound][subsound]:play()
else
sounds[sound]:setVolume(config.sfx_volume)
if sounds[sound]:isPlaying() then
sounds[sound]:stop()
end
sounds[sound]:play()
end
sounds[sound]:play()
else
sounds[sound][subsound]:setVolume(0.1)
if sounds[sound][subsound]:isPlaying() then
sounds[sound][subsound]:stop()
end
sounds[sound][subsound]:play()
end
end
function playSEOnce(sound, subsound)
if sound ~= nil then
if subsound ~= nil then
sounds[sound][subsound]:setVolume(config.sfx_volume)
if sounds[sound][subsound]:isPlaying() then
return
end
sounds[sound][subsound]:play()
else
sounds[sound]:setVolume(config.sfx_volume)
if sounds[sound]:isPlaying() then
return
end
sounds[sound]:play()
end
end
end

1
load/version.lua Normal file
View File

@@ -0,0 +1 @@
version = "v0.3-beta6"

327
main.lua
View File

@@ -1,71 +1,66 @@
function love.load()
math.randomseed(os.time())
highscores = {}
require "load.rpc"
require "load.graphics"
require "load.fonts"
require "load.sounds"
require "load.bgm"
require "load.save"
require "load.bigint"
require "load.version"
loadSave()
require "scene"
config["side_next"] = false
config["reverse_rotate"] = true
config["fullscreen"] = false
config["das_last_key"] = false
--config["side_next"] = false
--config["reverse_rotate"] = true
--config["das_last_key"] = false
--config["fullscreen"] = false
love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true});
-- used for screenshots
GLOBAL_CANVAS = love.graphics.newCanvas()
if not config.input then
config.input = {}
scene = InputConfigScene()
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()
end
-- init config
initConfig()
love.window.setFullscreen(config["fullscreen"])
if config.secret then playSE("welcome") end
-- import custom modules
initModules()
end
local TARGET_FPS = 60
local SAMPLE_SIZE = 60
local rolling_samples = {}
local rolling_total = 0
local average_n = 0
local frame = 0
function getSmoothedDt(dt)
rolling_total = rolling_total + dt
frame = frame + 1
if frame > SAMPLE_SIZE then frame = frame - SAMPLE_SIZE end
if average_n == SAMPLE_SIZE then
rolling_total = rolling_total - rolling_samples[frame]
else
average_n = average_n + 1
function initModules()
game_modes = {}
mode_list = love.filesystem.getDirectoryItems("tetris/modes")
for i=1,#mode_list do
if(mode_list[i] ~= "gamemode.lua" and mode_list[i] ~= "unrefactored_modes") then
game_modes[#game_modes+1] = require ("tetris.modes."..string.sub(mode_list[i],1,-5))
end
end
rolling_samples[frame] = dt
return rolling_total / average_n
end
local update_time = 0.52
function love.update(dt)
processBGMFadeout(dt)
local old_update_time = update_time
update_time = update_time + getSmoothedDt(dt) * TARGET_FPS
updates = 0
while (update_time >= 1.02) do
scene:update()
updates = updates + 1
update_time = update_time - 1
end
if math.abs(update_time - old_update_time) < 0.02 then
update_time = old_update_time
rulesets = {}
rule_list = love.filesystem.getDirectoryItems("tetris/rulesets")
for i=1,#rule_list do
if(rule_list[i] ~= "ruleset.lua" and rule_list[i] ~= "unrefactored_rulesets") then
rulesets[#rulesets+1] = require ("tetris.rulesets."..string.sub(rule_list[i],1,-5))
end
end
--sort mode/rule lists
local function padnum(d) return ("%03d%s"):format(#d, d) end
table.sort(game_modes, function(a,b)
return tostring(a.name):gsub("%d+",padnum) < tostring(b.name):gsub("%d+",padnum) end)
table.sort(rulesets, function(a,b)
return tostring(a.name):gsub("%d+",padnum) < tostring(b.name):gsub("%d+",padnum) end)
end
function love.draw()
love.graphics.setCanvas(GLOBAL_CANVAS)
love.graphics.clear()
love.graphics.push()
-- get offset matrix
love.graphics.setDefaultFilter("linear", "nearest")
local width = love.graphics.getWidth()
@@ -76,25 +71,255 @@ function love.draw()
(height - scale_factor * 480) / 2
)
love.graphics.scale(scale_factor)
scene:render()
love.graphics.pop()
love.graphics.setCanvas()
love.graphics.setColor(1,1,1,1)
love.graphics.draw(GLOBAL_CANVAS)
end
function love.keypressed(key, scancode, isrepeat)
function love.keypressed(key, scancode)
-- global hotkeys
if scancode == "f4" then
config["fullscreen"] = not config["fullscreen"]
saveConfig()
love.window.setFullscreen(config["fullscreen"])
elseif scancode == "f2" and scene.title ~= "Input Config" and scene.title ~= "Game" then
scene = InputConfigScene()
switchBGM(nil)
-- secret sound playing :eyes:
elseif scancode == "f8" and scene.title == "Title" then
config.secret = not config.secret
saveConfig()
scene.restart_message = true
if config.secret then playSE("mode_decide")
else playSE("erase") end
-- f12 is reserved for saving screenshots
elseif scancode == "f12" then
local ss_name = os.date("ss/%Y-%m-%d_%H-%M-%S.png")
local info = love.filesystem.getInfo("ss", "directory")
if not info then
love.filesystem.remove("ss")
love.filesystem.createDirectory("ss")
end
print("Saving screenshot as "..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
return
-- escape is reserved for menu_back
elseif scancode == "escape" then
scene:onInputPress({input="menu_back", type="key", key=key, scancode=scancode})
-- pass any other key to the scene, with its configured mapping
else
scene:onKeyPress({key=key, scancode=scancode, isRepeat=isrepeat})
local input_pressed = nil
if config.input and config.input.keys then
input_pressed = config.input.keys[scancode]
end
scene:onInputPress({input=input_pressed, type="key", key=key, scancode=scancode})
end
end
function love.keyreleased(key, scancode)
-- escape is reserved for menu_back
if scancode == "escape" then
scene:onInputRelease({input="menu_back", type="key", key=key, scancode=scancode})
-- function keys are reserved
elseif string.match(scancode, "^f[1-9]$") or string.match(scancode, "^f[1-9][0-9]+$") then
return
-- handle all other keys; tab is reserved, but the input config scene keeps it from getting configured as a game input, so pass tab to the scene here
else
local input_released = nil
if config.input and config.input.keys then
input_released = config.input.keys[scancode]
end
scene:onInputRelease({input=input_released, type="key", key=key, scancode=scancode})
end
end
function love.joystickpressed(joystick, button)
local input_pressed = nil
if
config.input and
config.input.joysticks and
config.input.joysticks[joystick:getName()] and
config.input.joysticks[joystick:getName()].buttons
then
input_pressed = config.input.joysticks[joystick:getName()].buttons[button]
end
scene:onInputPress({input=input_pressed, type="joybutton", name=joystick:getName(), button=button})
end
function love.joystickreleased(joystick, button)
local input_released = nil
if
config.input and
config.input.joysticks and
config.input.joysticks[joystick:getName()] and
config.input.joysticks[joystick:getName()].buttons
then
input_released = config.input.joysticks[joystick:getName()].buttons[button]
end
scene:onInputRelease({input=input_released, type="joybutton", name=joystick:getName(), button=button})
end
function love.joystickaxis(joystick, axis, value)
local input_pressed = nil
local positive_released = nil
local negative_released = nil
if
config.input and
config.input.joysticks and
config.input.joysticks[joystick:getName()] and
config.input.joysticks[joystick:getName()].axes and
config.input.joysticks[joystick:getName()].axes[axis]
then
if math.abs(value) >= 1 then
input_pressed = config.input.joysticks[joystick:getName()].axes[axis][value >= 1 and "positive" or "negative"]
end
positive_released = config.input.joysticks[joystick:getName()].axes[axis].positive
negative_released = config.input.joysticks[joystick:getName()].axes[axis].negative
end
if math.abs(value) >= 1 then
scene:onInputPress({input=input_pressed, type="joyaxis", name=joystick:getName(), axis=axis, value=value})
else
scene:onInputRelease({input=positive_released, type="joyaxis", name=joystick:getName(), axis=axis, value=value})
scene:onInputRelease({input=negative_released, type="joyaxis", name=joystick:getName(), axis=axis, value=value})
end
end
local last_hat_direction = ""
local directions = {
["u"] = "up",
["d"] = "down",
["l"] = "left",
["r"] = "right",
}
function love.joystickhat(joystick, hat, direction)
local input_pressed = nil
local has_hat = false
if
config.input and
config.input.joysticks and
config.input.joysticks[joystick:getName()] and
config.input.joysticks[joystick:getName()].hats and
config.input.joysticks[joystick:getName()].hats[hat]
then
if direction ~= "c" then
input_pressed = config.input.joysticks[joystick:getName()].hats[hat][direction]
end
has_hat = true
end
if input_pressed then
for i = 1, #direction do
local char = direction:sub(i, i)
local _, count = last_hat_direction:gsub(char, char)
if count == 0 then
scene:onInputPress({input=config.input.joysticks[joystick:getName()].hats[hat][char], type="joyhat", name=joystick:getName(), hat=hat, direction=char})
end
end
for i = 1, #last_hat_direction do
local char = last_hat_direction:sub(i, i)
local _, count = direction:gsub(char, char)
if count == 0 then
scene:onInputRelease({input=config.input.joysticks[joystick:getName()].hats[hat][char], type="joyhat", name=joystick:getName(), hat=hat, direction=char})
end
end
last_hat_direction = direction
elseif has_hat then
for i, direction in ipairs{"d", "l", "ld", "lu", "r", "rd", "ru", "u"} do
scene:onInputRelease({input=config.input.joysticks[joystick:getName()].hats[hat][direction], type="joyhat", name=joystick:getName(), hat=hat, direction=direction})
end
last_hat_direction = ""
elseif direction ~= "c" then
for i = 1, #direction do
local char = direction:sub(i, i)
local _, count = last_hat_direction:gsub(char, char)
if count == 0 then
scene:onInputPress({input=directions[char], type="joyhat", name=joystick:getName(), hat=hat, direction=char})
end
end
for i = 1, #last_hat_direction do
local char = last_hat_direction:sub(i, i)
local _, count = direction:gsub(char, char)
if count == 0 then
scene:onInputRelease({input=directions[char], type="joyhat", name=joystick:getName(), hat=hat, direction=char})
end
end
last_hat_direction = direction
else
for i, direction in ipairs{"d", "l", "ld", "lu", "r", "rd", "ru", "u"} do
scene:onInputRelease({input=nil, type="joyhat", name=joystick:getName(), hat=hat, direction=direction})
end
last_hat_direction = ""
end
end
function love.focus(f)
if f then
if f and (scene.title ~= "Game" or not scene.paused) then
resumeBGM()
else
pauseBGM()
end
end
function love.resize(w, h)
GLOBAL_CANVAS:release()
GLOBAL_CANVAS = love.graphics.newCanvas(w, h)
end
local TARGET_FPS = 60
function love.run()
if love.load then love.load(love.arg.parseGameArguments(arg), arg) end
if love.timer then love.timer.step() end
local dt = 0
local last_time = love.timer.getTime()
local time_accumulator = 0
return function()
if love.event then
love.event.pump()
for name, a,b,c,d,e,f in love.event.poll() do
if name == "quit" then
if not love.quit or not love.quit() then
return a or 0
end
end
love.handlers[name](a,b,c,d,e,f)
end
end
if love.timer then
processBGMFadeout(love.timer.step())
end
if scene and scene.update and love.timer then
scene:update()
local frame_duration = 1.0 / TARGET_FPS
if time_accumulator < frame_duration then
if love.graphics and love.graphics.isActive() and love.draw then
love.graphics.origin()
love.graphics.clear(love.graphics.getBackgroundColor())
love.draw()
love.graphics.present()
end
local end_time = last_time + frame_duration
local time = love.timer.getTime()
while time < end_time do
love.timer.sleep(0.001)
time = love.timer.getTime()
end
time_accumulator = time_accumulator + time - last_time
end
time_accumulator = time_accumulator - frame_duration
end
last_time = love.timer.getTime()
end
end

2
package.bat Normal file
View File

@@ -0,0 +1,2 @@
tar -a -c -f cambridge.zip libs load res scene tetris conf.lua main.lua scene.lua funcs.lua
rename cambridge.zip cambridge.love

View File

@@ -4,6 +4,6 @@ mkdir dist/windows
mkdir dist/win32
cp cambridge.love dist/
cat dist/windows/love.exe cambridge.love > dist/windows/cambridge.exe
zip dist/cambridge-windows.zip dist/windows/* SOURCES.md LICENSE
zip dist/cambridge-windows.zip dist/windows/* SOURCES.md LICENSE.md
cat dist/win32/love.exe cambridge.love > dist/win32/cambridge.exe
zip dist/cambridge-win32.zip dist/win32/* SOURCES.md LICENSE
zip dist/cambridge-win32.zip dist/win32/* SOURCES.md LICENSE.md

26
release.bat Normal file
View File

@@ -0,0 +1,26 @@
call package.bat
mkdir dist
mkdir dist\windows
mkdir dist\windows\libs
mkdir dist\win32
mkdir dist\win32\libs
copy /b dist\windows\love.exe+cambridge.love dist\windows\cambridge.exe
copy /b dist\win32\love.exe+cambridge.love dist\win32\cambridge.exe
copy libs\discord-rpc.dll dist\windows\libs
copy libs\discord-rpc.dll dist\win32\libs
copy SOURCES.md dist\windows
copy LICENSE.md dist\windows
copy SOURCES.md dist\win32
copy LICENSE.md dist\win32
cd dist\windows
tar -a -c -f ..\cambridge-windows.zip cambridge.exe *.dll libs *.md
cd ..\..
cd dist\win32
tar -a -c -f ..\cambridge-win32.zip cambridge.exe *.dll libs *.md
cd ..\..

View File

Before

Width:  |  Height:  |  Size: 2.4 MiB

After

Width:  |  Height:  |  Size: 2.4 MiB

View File

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.9 MiB

After

Width:  |  Height:  |  Size: 2.9 MiB

View File

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

Before

Width:  |  Height:  |  Size: 2.6 MiB

After

Width:  |  Height:  |  Size: 2.6 MiB

View File

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

Before

Width:  |  Height:  |  Size: 2.4 MiB

After

Width:  |  Height:  |  Size: 2.4 MiB

View File

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 1.9 MiB

View File

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

View File

Before

Width:  |  Height:  |  Size: 1.7 MiB

After

Width:  |  Height:  |  Size: 1.7 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

Before

Width:  |  Height:  |  Size: 3.1 MiB

After

Width:  |  Height:  |  Size: 3.1 MiB

View File

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

Before

Width:  |  Height:  |  Size: 2.7 MiB

After

Width:  |  Height:  |  Size: 2.7 MiB

View File

Before

Width:  |  Height:  |  Size: 3.6 MiB

After

Width:  |  Height:  |  Size: 3.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

BIN
res/backgrounds/snow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

BIN
res/backgrounds/title.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
res/img/bonew.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 B

BIN
res/img/cambridge_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
res/img/gem1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

BIN
res/img/gem2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 B

BIN
res/img/gem3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 B

BIN
res/img/gem4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 B

BIN
res/img/gem5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 B

BIN
res/img/gem6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 B

BIN
res/img/gem7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 B

BIN
res/img/gem9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 B

BIN
res/img/s8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

BIN
res/img/santa.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

BIN
res/img/squareg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 B

BIN
res/img/squares.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

Binary file not shown.

BIN
res/se/cursor.wav Normal file

Binary file not shown.

BIN
res/se/cursor_lr.wav Normal file

Binary file not shown.

BIN
res/se/erase.wav Normal file

Binary file not shown.

BIN
res/se/fall.wav Normal file

Binary file not shown.

BIN
res/se/go.wav Normal file

Binary file not shown.

BIN
res/se/hold.wav Normal file

Binary file not shown.

BIN
res/se/ihs.wav Normal file

Binary file not shown.

BIN
res/se/irs.wav Normal file

Binary file not shown.

BIN
res/se/lock.wav Normal file

Binary file not shown.

BIN
res/se/main_decide.wav Normal file

Binary file not shown.

BIN
res/se/mode_decide.wav Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
res/se/ready.wav Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -5,10 +5,17 @@ Scene = Object:extend()
function Scene:new() end
function Scene:update() end
function Scene:render() end
function Scene:onKeyPress() end
function Scene:onInputPress() end
function Scene:onInputRelease() end
ExitScene = require "scene.exit"
GameScene = require "scene.game"
ModeSelectScene = require "scene.mode_select"
KeyConfigScene = require "scene.key_config"
StickConfigScene = require "scene.stick_config"
InputConfigScene = require "scene.input_config"
ConfigScene = require "scene.config"
GameConfigScene = require "scene.game_config"
TuningScene = require "scene.tuning"
SettingsScene = require "scene.settings"
CreditsScene = require "scene.credits"
TitleScene = require "scene.title"

View File

@@ -17,7 +17,7 @@ function ConfigScene:changeOption(rel)
self.main_menu_state = (self.main_menu_state + len + rel - 1) % len + 1
end
function ConfigScene:onKeyPress(e)
function ConfigScene:onInputPress(e)
end
return ConfigScene

84
scene/credits.lua Normal file
View File

@@ -0,0 +1,84 @@
local CreditsScene = Scene:extend()
CreditsScene.title = "Credits"
function CreditsScene:new()
self.frames = 0
-- higher = slower
self.scroll_speed = 1.9
switchBGM("credit_roll", "gm3")
end
function CreditsScene:update()
if love.window.hasFocus() then
self.frames = self.frames + 1
end
if self.frames >= 2100 * self.scroll_speed then
playSE("mode_decide")
scene = TitleScene()
switchBGM(nil)
elseif self.frames == math.floor(1950 * self.scroll_speed) then
fadeoutBGM(2)
end
end
function CreditsScene:render()
local offset = self.frames / self.scroll_speed
love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw(
backgrounds[19],
0, 0, 0,
0.5, 0.5
)
love.graphics.setFont(font_3x5_4)
love.graphics.print("Cambridge Credits", 320, 500 - offset)
love.graphics.print("THANK YOU\nFOR PLAYING!", 320, math.max(2010 - 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, 730 - offset)
love.graphics.print("Special Thanks", 320, 980 - offset)
love.graphics.print("- Milla", 320, math.max(2090 - offset, 320))
love.graphics.setFont(font_3x5_2)
love.graphics.print("Oshisaure\nJoe Zeng", 320, 590 - offset)
love.graphics.print("Mizu\nMarkGamed", 320, 680 - offset)
love.graphics.print(
"2Tie - TGMsim\nAxel Fox - Multimino\nDr Ocelot - Tetra Legends\n" ..
"Electra - ZTrix\nFelicity/nightmareci/kdex - Shiromino\n" ..
"Mine - Tetra Online\nMrZ - Techmino\nosk - TETR.IO\n" ..
"Phoenix Flare - Master of Blocks\nRayRay26 - Spirit Drop\n" ..
"sinefuse - stackfuse",
320, 770 - offset
)
love.graphics.print(
"321MrHaatz\nAdventium\nAgentBasey\nArchina\nAurora\n" ..
"Caithness\nCheez\ncolour_thief\nCommando\nCublex\n" ..
"CylinderKnot\neightsixfivezero\nEricICX\nGesomaru\n" ..
"gizmo4487\nJBroms\nKirby703\nKitaru\n" ..
"M1ssing0\nMattMayuga\nMyPasswordIsWeak\n" ..
"Nikki Karissa\noffwo\nOliver\nPineapple\npokemonfan1937\n" ..
"Pyra Neoxi\nRDST64\nRocketLanterns\nRustyFoxxo\n" ..
"saphie\nShelleloch\nSimon\nstratus\nSuper302\n" ..
"switchpalacecorner\nterpyderp\nTetrian22\nTetro48\nThatCookie\n" ..
"TimmSkiller\nTrixciel\nuser74003\nZaptorZap\nZircean\n" ..
"All other contributors and friends!\nThe Absolute PLUS Discord\n" ..
"Tetra Legends Discord\nTetra Online Discord\nMultimino Discord\n" ..
"Hard Drop Discord\nRusty's Systemspace\nCambridge Discord\n" ..
"And to you, the player!",
320, 1020 - offset
)
end
function CreditsScene:onInputPress(e)
if e.input == "menu_decide" or e.scancode == "return" or
e.input == "menu_back" or e.scancode == "delete" or e.scancode == "backspace" then
scene = TitleScene()
switchBGM(nil)
end
end
return CreditsScene

23
scene/exit.lua Normal file
View File

@@ -0,0 +1,23 @@
local ExitScene = Scene:extend()
require 'load.save'
ExitScene.title = "Exit Game"
function ExitScene:new()
end
function ExitScene:update()
love.event.quit()
end
function ExitScene:render()
end
function ExitScene:changeOption(rel)
end
function ExitScene:onInputPress(e)
end
return ExitScene

View File

@@ -1,67 +1,82 @@
local GameScene = Scene:extend()
GameScene.title = "Game"
require 'load.save'
function GameScene:new(game_mode, ruleset)
self.game = game_mode()
self.ruleset = ruleset()
function GameScene: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 = self.game.rpc_details,
state = self.game.name,
})
end
function GameScene:update()
if love.window.hasFocus() then
self.game:update({
left = love.keyboard.isScancodeDown(config.input.left),
right = love.keyboard.isScancodeDown(config.input.right),
up = love.keyboard.isScancodeDown(config.input.up),
down = love.keyboard.isScancodeDown(config.input.down),
rotate_left = love.keyboard.isScancodeDown(config.input.rotate_left),
rotate_left2 = love.keyboard.isScancodeDown(config.input.rotate_left2),
rotate_right = love.keyboard.isScancodeDown(config.input.rotate_right),
rotate_right2 = love.keyboard.isScancodeDown(config.input.rotate_right2),
rotate_180 = love.keyboard.isScancodeDown(config.input.rotate_180),
hold = love.keyboard.isScancodeDown(config.input.hold),
}, self.ruleset)
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()
end
self.game.grid:update()
end
function GameScene:render()
love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw(
backgrounds[self.game:getBackground()],
0, 0, 0,
0.5, 0.5
)
-- game frame
love.graphics.draw(misc_graphics["frame"], 48, 64)
love.graphics.setColor(0, 0, 0, 200)
love.graphics.rectangle("fill", 64, 80, 160, 320)
self.game:drawGrid()
self.game:drawPiece()
self.game:drawNextQueue(self.ruleset)
self.game:drawScoringInfo()
-- ready/go graphics
if self.game.ready_frames <= 100 and self.game.ready_frames > 52 then
love.graphics.draw(misc_graphics["ready"], 144 - 50, 240 - 14)
elseif self.game.ready_frames <= 50 and self.game.ready_frames > 2 then
love.graphics.draw(misc_graphics["go"], 144 - 27, 240 - 14)
end
self.game:drawCustom()
self.game:draw(self.paused)
end
function GameScene:onKeyPress(e)
if (self.game.completed) and
e.scancode == "return" and e.isRepeat == false then
function GameScene: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 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)
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()
elseif e.input and string.sub(e.input, 1, 5) ~= "menu_" then
self.inputs[e.input] = true
end
end
function GameScene:onInputRelease(e)
if e.input and string.sub(e.input, 1, 5) ~= "menu_" then
self.inputs[e.input] = false
end
end

123
scene/game_config.lua Normal file
View File

@@ -0,0 +1,123 @@
local ConfigScene = Scene:extend()
ConfigScene.title = "Game Settings"
require 'load.save'
require 'libs.simple-slider'
ConfigScene.options = {
-- this serves as reference to what the options' values mean i guess?
-- Format: {name in config, displayed name, uses slider?, options OR slider name}
{"manlock", "Manual Locking", false, {"Per ruleset", "Per gamemode", "Harddrop", "Softdrop"}},
{"piece_colour", "Piece Colours", false, {"Per ruleset", "Arika", "TTC"}},
{"world_reverse", "A Button Rotation", false, {"Left", "Auto", "Right"}},
{"spawn_positions", "Spawn Positions", false, {"Per ruleset", "In field", "Out of field"}},
{"display_gamemode", "Display Gamemode", false, {"On", "Off"}},
{"das_last_key", "DAS Last Key", false, {"Off", "On"}},
{"smooth_movement", "Smooth Piece Drop", false, {"On", "Off"}},
{"synchroes_allowed", "Synchroes", false, {"Per ruleset", "On", "Off"}},
{"diagonal_input", "Diagonal Input", false, {"On", "Off"}},
{"buffer_lock", "Buffer Drop Type", false, {"Off", "Hold", "Tap"}},
{"sfx_volume", "SFX", true, "sfxSlider"},
{"bgm_volume", "BGM", true, "bgmSlider"},
}
local optioncount = #ConfigScene.options
function ConfigScene:new()
-- load current config
self.config = config.input
self.highlight = 1
DiscordRPC:update({
details = "In menus",
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"})
end
function ConfigScene:update()
self.sfxSlider:update()
self.bgmSlider:update()
end
function ConfigScene:render()
love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw(
backgrounds["game_config"],
0, 0, 0,
0.5, 0.5
)
love.graphics.setFont(font_3x5_4)
love.graphics.print("GAME SETTINGS", 80, 40)
--Lazy check to see if we're on the SFX or BGM slider. Probably will need to be rewritten if more options get added.
love.graphics.setColor(1, 1, 1, 0.5)
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)
end
love.graphics.setFont(font_3x5_2)
for i, option in ipairs(ConfigScene.options) do
if not option[3] then
love.graphics.setColor(1, 1, 1, 1)
love.graphics.printf(option[2], 40, 100 + i * 20, 150, "left")
for j, setting in ipairs(option[4]) do
love.graphics.setColor(1, 1, 1, config.gamesettings[option[1]] == j and 1 or 0.5)
love.graphics.printf(setting, 100 + 110 * j, 100 + i * 20, 100, "center")
end
end
end
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.setColor(1, 1, 1, 0.75)
self.sfxSlider:draw()
self.bgmSlider:draw()
end
function ConfigScene:onInputPress(e)
if e.input == "menu_decide" or e.scancode == "return" then
playSE("mode_decide")
saveConfig()
scene = SettingsScene()
elseif e.input == "up" or e.scancode == "up" then
playSE("cursor")
self.highlight = Mod1(self.highlight-1, optioncount)
elseif e.input == "down" or e.scancode == "down" then
playSE("cursor")
self.highlight = Mod1(self.highlight+1, optioncount)
elseif e.input == "left" or e.scancode == "left" then
if not self.options[self.highlight][3] then
playSE("cursor_lr")
local option = ConfigScene.options[self.highlight]
config.gamesettings[option[1]] = Mod1(config.gamesettings[option[1]]-1, #option[4])
else
playSE("cursor")
sld = self[self.options[self.highlight][4]]
sld.value = math.max(sld.min, math.min(sld.max, (sld:getValue() - 5) / (sld.max - sld.min)))
end
elseif e.input == "right" or e.scancode == "right" then
if not self.options[self.highlight][3] then
playSE("cursor_lr")
local option = ConfigScene.options[self.highlight]
config.gamesettings[option[1]] = Mod1(config.gamesettings[option[1]]+1, #option[4])
else
playSE("cursor")
sld = self[self.options[self.highlight][4]]
sld.value = math.max(sld.min, math.min(sld.max, (sld:getValue() + 5) / (sld.max - sld.min)))--math.max(0, (math.floor(sld:getValue())+2)/(sld.max-sld.min))
end
elseif e.input == "menu_back" or e.scancode == "delete" or e.scancode == "backspace" then
loadSave()
scene = SettingsScene()
end
end
return ConfigScene

View File

@@ -2,61 +2,65 @@ local ConfigScene = Scene:extend()
ConfigScene.title = "Input Config"
require 'load.save'
local configurable_inputs = {
"left",
"right",
"up",
"down",
"rotate_left",
"rotate_left2",
"rotate_right",
"rotate_right2",
"rotate_180",
"hold",
local menu_screens = {
KeyConfigScene,
StickConfigScene
}
function ConfigScene:new()
-- load current config
self.config = config.input
self.input_state = 1
self.menu_state = 1
DiscordRPC:update({
details = "In menus",
state = "Changing input config",
})
end
function ConfigScene:update()
end
function ConfigScene:update() end
function ConfigScene:render()
love.graphics.setFont(font_3x5_2)
for i, input in pairs(configurable_inputs) do
if config.input[input] then
love.graphics.printf(input, 40, 50 + i * 20, 200, "left")
love.graphics.printf(
love.keyboard.getKeyFromScancode(config.input[input]) .. " (" .. config.input[input] .. ")",
240, 50 + i * 20, 200, "left"
)
end
end
if self.input_state > table.getn(configurable_inputs) then
love.graphics.print("press enter to confirm, delete to retry")
else
love.graphics.print("press key for " .. configurable_inputs[self.input_state])
love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw(
backgrounds["input_config"],
0, 0, 0,
0.5, 0.5
)
love.graphics.setFont(font_3x5_4)
love.graphics.print("INPUT CONFIG", 80, 40)
love.graphics.setFont(font_3x5_2)
love.graphics.print("Which controls do you want to configure?", 80, 90)
love.graphics.setColor(1, 1, 1, 0.5)
love.graphics.rectangle("fill", 75, 118 + 50 * self.menu_state, 200, 33)
love.graphics.setFont(font_3x5_3)
love.graphics.setColor(1, 1, 1, 1)
for i, screen in pairs(menu_screens) do
love.graphics.printf(screen.title, 80, 120 + 50 * i, 200, "left")
end
end
function ConfigScene:changeOption(rel)
local len = table.getn(menu_screens)
self.menu_state = (self.menu_state + len + rel - 1) % len + 1
end
function ConfigScene:onInputPress(e)
if e.input == "menu_decide" or e.scancode == "return" then
playSE("main_decide")
scene = menu_screens[self.menu_state]()
elseif e.input == "up" or e.scancode == "up" then
self:changeOption(-1)
playSE("cursor")
elseif e.input == "down" or e.scancode == "down" then
self:changeOption(1)
playSE("cursor")
elseif config.input and (
e.input == "menu_back" or e.scancode == "backspace" or e.scancode == "delete"
) then
scene = SettingsScene()
end
end
function ConfigScene:onKeyPress(e)
if self.input_state > table.getn(configurable_inputs) then
if e.scancode == "return" then
-- save, then load next scene
saveConfig()
scene = TitleScene()
elseif e.scancode == "delete" or e.scancode == "backspace" then
self.input_state = 1
end
else
config.input[configurable_inputs[self.input_state]] = e.scancode
self.input_state = self.input_state + 1
end
end
return ConfigScene
return ConfigScene

Some files were not shown because too many files have changed in this diff Show More