- add options sub-menu to title screen: bgm, sfx, fullscreen, and exit

- hide UI when gamepad is in use, enable when mouse is in use
- indicate selected UI button using hue rotation animation
- support for gamepad hat
- support for disconnecting and reconnecting gamepads
- sanitize collected data in WASM build and write files per session
- add function for finding the closest UI button in a given direction
- bug fix: prevent character from moving when level loads or play is resumed from the pause menu
- bug fix: cancel character walking sfx when paused
This commit is contained in:
ohsqueezy 2024-05-01 20:35:15 -04:00 committed by Cocktail Frank
parent ba53c72b01
commit 290e23b5da
13 changed files with 560 additions and 248 deletions

2
.gitignore vendored
View File

@ -15,7 +15,7 @@ ext/
local/
src/__pycache__/
storage/
Play_History.json
*Play_History.json
press.html
feed
test.html

View File

@ -116,8 +116,8 @@ $(addsuffix /Input.o, $(BUILD_DIRS)): $(addprefix $(SB_SRC_DIR)/, Input.cpp Inpu
Delegate.hpp) | $(BUILD_DIRS)
$(CXX) $(CXXFLAGS) $< -c -o $@
$(addsuffix /Configuration.o, $(BUILD_DIRS)): $(addprefix $(SB_SRC_DIR)/, Configuration.cpp Configuration.hpp Node.hpp Animation.hpp \
Log.hpp extension.hpp) | $(BUILD_DIRS)
$(addsuffix /Configuration.o, $(BUILD_DIRS)): $(addprefix $(SB_SRC_DIR)/, Configuration.cpp Configuration.hpp Animation.hpp Log.hpp \
extension.hpp) | $(BUILD_DIRS)
$(CXX) $(CXXFLAGS) $< -c -o $@
$(addsuffix /Delegate.o, $(BUILD_DIRS)): $(addprefix $(SB_SRC_DIR)/, Delegate.cpp Delegate.hpp Node.hpp Game.hpp Input.hpp) \
@ -265,7 +265,7 @@ cakefoot.js : CXXFLAGS = $(CFLAGS) --std=c++17
cakefoot.js : $(addprefix $(WASM_BUILD_DIR)/, SDL2_rotozoom.o SDL2_gfxPrimitives.o $(SB_O_FILES) $(SRC_O_FILES)) \
$(EMSCRIPTEN_GAME_CONFIGS)
$(CXX) $(filter-out $(EMSCRIPTEN_GAME_CONFIGS), $^) $(CXXFLAGS) $(EMSCRIPTEN_LFLAGS) $(EMSCRIPTEN_PRELOADS) \
--pre-js "src/pre_js_foam.js" -o $(WASM_BUILD_DIR)/$@
--pre-js "src/pre_js_collect.js" -o $(WASM_BUILD_DIR)/$@
cakefoot_debug.html : CC = $(EMSCRIPTENHOME)/emcc
cakefoot_debug.html : CXX = $(EMSCRIPTENHOME)/em++
@ -505,7 +505,7 @@ press :
###################
all : Cakefoot-linux.x64 Cakefoot-linux_debug.x64 cakefoot.js cakefoot_debug.html cakefoot_coolmath.js Cakefoot-win32.exe \
Cakefoot-win64.exe Cakefoot-win32-ARCADE_ONLY.exe Cakefoot-win32-DEMO.exe press
Cakefoot-win64.exe Cakefoot-win32-ARCADE_ONLY.exe Cakefoot-win32-DEMO.exe press Cakefoot.app Ubuntu-18
#########################
# Clean up object files #

View File

@ -54,6 +54,21 @@ The code is open source under the zlib license. The images and sound effects are
See [LICENSE.txt](LICENSE.txt) for details.
History
=======
1.0.4
- add options sub-menu to title screen: bgm, sfx, fullscreen, and exit
- hide UI when gamepad is in use, enable when mouse is in use
- indicate selected UI button using hue rotation animation
- support for gamepad hat
- support for disconnecting and reconnecting gamepads
- sanitize collected data in WASM build and write files per session
- add function for finding the closest UI button in a given direction
- bug fix: prevent character from moving when level loads or play is resumed from the pause menu
- bug fix: cancel character walking sfx when paused
Contact
=======

View File

@ -28,7 +28,7 @@
"hitbox": false,
"use play button": false,
"arcade only": false,
"use arcade prompt": true,
"use arcade prompt": false,
"game over text": "GAME OVER",
"game over display time": 2.5,
"game over foreground": [255.0, 255.0, 255.0, 255.0],
@ -54,7 +54,7 @@
"scoreboard translation": [-0.4, 0.835],
"scoreboard scale": [1.35, 0.14],
"scoreboard wrap": 3000,
"qr display": true,
"qr display": false,
"qr background display": true,
"qr background texture": "resource/qr_background.png",
"qr texture": "resource/qr.png",
@ -95,7 +95,9 @@
"arcade warning color": [0.5, 0.0, 0.0, 1.0],
"auto save translation": [-1.45, -0.65],
"auto save scale": [0.325, 0.15],
"social media click": false
"social media click": false,
"highlight saturation": 1.0,
"highlight value": 0.5
},
"shader":
@ -116,7 +118,7 @@
{
"screenshot directory": "local/screenshots",
"video directory": "local/video",
"enabled": true,
"enabled": false,
"write mp4": true,
"video frame length": 0.016666666,
"max video memory": 2000,
@ -129,7 +131,8 @@
"any key ignore commands": ["left", "right", "up", "down", "pause"],
"gamepad pause button index": 9,
"gamepad axis cooldown": 0.2,
"gamepad reset button index": 8
"gamepad reset button index": 8,
"gamepad home button index": 10
},
"keys":
@ -267,16 +270,16 @@
"text dimensions": [275.0, 50.0],
"text scale": 0.71,
"text foreground": [200.0, 200.0, 200.0, 255.0],
"text background": [60.0, 60.0, 60.0, 190.0],
"text background": [60.0, 60.0, 60.0, 255.0],
"start text": "✶✶ PLAY ✶✶",
"start translation": [0.0, -0.4],
"start alt texture": "resource/press_button_to_start.png",
"start alt translation": [0.0, -0.5],
"start alt scale": [0.5787, 0.91],
"resume text": "RESUME",
"resume translation": [0.0, 0.25],
"resume translation": [0.0, 0.35],
"reset text": "SAVE & EXIT",
"reset translation": [0.0, -0.25],
"reset translation": [0.0, -0.025],
"level decrement translation": [-0.67, -0.71],
"level decrement text": "◀",
"level decrement dimensions": [40.0, 40.0],
@ -336,7 +339,22 @@
"fullscreen texture": "resource/fullscreen.png",
"fullscreen translation": [-1.45, -0.85],
"fullscreen scale": 0.07,
"fullscreen scale ratio": 0.75
"fullscreen scale ratio": 0.75,
"fullscreen text text": "FULLSCREEN",
"fullscreen text translation home": [0.0, -0.69],
"fullscreen text translation pause": [0.0, -0.29],
"fullscreen text dimensions": [850.0, 40.0],
"fullscreen text scale": 0.71,
"bgm text on": "BGM ON",
"bgm text off": "BGM OFF",
"bgm translation home": [0.0, -0.77],
"bgm translation pause": [0.0, -0.38],
"sfx text on": "SFX ON",
"sfx text off": "SFX OFF",
"sfx translation home": [0.0, -0.85],
"sfx translation pause": [0.0, -0.47],
"exit text": "EXIT GAME",
"exit translation": [0.0, -0.93]
},
"world": [
@ -387,6 +405,9 @@
"level addition advanced": 30.0,
"bank bonus": 5.0,
"advanced": 14
},
{
"name": "OPTIONS"
}
],
@ -456,7 +477,7 @@
"demo":
{
"active": true,
"active": false,
"idle timeout": 30.0,
"countdown display timeout": 10.0,
"countdown message": "IDLE RESET IN ",

View File

@ -252,7 +252,7 @@
var ticker_content = [
"Use ☝&#xFE0F;, &#x1F5B1;&#xFE0F;, &#x2328;&#xFE0F; or 🎮 to play",
"🗓&#xFE0F; Releasing on <a href='https://store.steampowered.com/app/2869020/Cakefoot/' target='_blank'>Steam</a>, " +
"<a href='https://ohsqueezy.itch.io/cakefoot' target='new'>itch.io</a>, Android & " +
"<a href='https://ohsqueezy.itch.io/cakefoot' target='new'>itch.io</a> & " +
"<a href='https://coolmathgames.com' target='_blank'>Coolmath</a> May 10th",
"<a href='https://youtu.be/xn-iNcUlIpo' target='_blank'>Watch the trailer</a>&#xFE0F; and " +
"<a href='https://store.steampowered.com/app/2869020/Cakefoot/'>wishlist on Steam</a>",

2
lib/sb

@ -1 +1 @@
Subproject commit 8498dfa00472431a6dd8a2ec588f0792a9e435dc
Subproject commit a9665c7e3799636940c21c97d2e5ade7fcce6e5e

File diff suppressed because it is too large Load Diff

View File

@ -236,7 +236,11 @@ private:
{"name 3 decrement", sb::Pad<>()},
{"fullscreen", sb::Pad<>()},
{"diskmem", sb::Pad<>()},
{"azuria sky", sb::Pad<>()}
{"azuria sky", sb::Pad<>()},
{"fullscreen text", sb::Pad<>()},
{"bgm", sb::Pad<>()},
{"sfx", sb::Pad<>()},
{"exit", sb::Pad<>()}
};
std::map<std::string, std::shared_ptr<TTF_Font>> fonts {
{"medium", font(configuration()("font", "medium", "path").get<std::string>(), configuration()("font", "medium", "size"))},
@ -277,7 +281,7 @@ private:
std::string name_entry;
sb::Text scoreboard {fonts.at("large")}, thanks {fonts.at("medium")};
std::vector<Flame> ending_coins;
sb::Color rotating_hue {128, 0, 0, 0};
sb::Color rotating_hue;
std::vector<sb::Text> ending_messages;
std::optional<std::string> selected;
std::shared_ptr<SDL_GameController> controller = nullptr;
@ -369,7 +373,8 @@ private:
int distance() const;
/*!
* @return The time limit of the current run. Combines the challenge mode's initial limit with added time for completed levels and checkpoints.
* @return The time limit of the current run. Combines the challenge mode's initial limit with added time for completed levels and
* checkpoints.
*/
float limit() const;
@ -411,14 +416,14 @@ private:
inline bool skip_resume_quest()
{
return configuration()("challenge", challenge_index, "name") == "RESUME QUEST" && configuration()("progress", "quest level") == 1 &&
configuration()("progress", "quest checkpoint") == 0.0f;
return configuration()("challenge", challenge_index, "name") == "RESUME QUEST" &&
configuration()("progress", "quest level") == 1 && configuration()("progress", "quest checkpoint") == 0.0f;
}
inline bool skip_resume_arcade()
{
return configuration()("challenge", challenge_index, "name") == "RESUME ARCADE" && configuration()("progress", "arcade level") == 1 &&
configuration()("progress", "arcade checkpoint") == 0.0f;
return configuration()("challenge", challenge_index, "name") == "RESUME ARCADE" &&
configuration()("progress", "arcade level") == 1 && configuration()("progress", "arcade checkpoint") == 0.0f;
}
inline bool skip_level_select()
@ -515,6 +520,30 @@ private:
*/
void refresh_scoreboard();
/*!
* Return the name of the button closest to a given button in Cakefoot::buttons in the specified direction ("up", "right", "down",
* or "left").
*
* @param subject The button to base the search on
* @param direction One of either "up", "right", "down", or "left"
* @param pool Buttons to search through. If omitted, all buttons will be searched.
* @return The nearest button in the specified direction or the subject if none is found
*/
std::string nearest_button(const std::string& subject, const std::string& direction,
const std::map<std::string, sb::Pad<>>& pool) const;
/*!
* @overload nearest_button(const std::string&, const std::string&, const std::map<std::string, sb::Pad<>>&)
*/
std::string nearest_button(const std::string& subject, const std::string& direction,
const std::vector<std::string>& names) const;
/*!
* @overload nearest_button(const std::string&, const std::string&, const std::map<std::string, sb::Pad<>>&)
*
* Searches every Cakefoot::button
*/
std::string nearest_button(const std::string& subject, const std::string& direction) const;
public:
/*!

View File

@ -14,7 +14,8 @@ void Character::profile(const std::string& name)
/* Reload the texture */
_sprite.clear_textures();
nlohmann::json frames = configuration("progress", "jackpot") == 777 ? configuration("character", "jackpot frames") : profile().at("animation frames");
nlohmann::json frames = configuration("progress", "jackpot") == 777 ? configuration("character", "jackpot frames") :
profile().at("animation frames");
for (const std::string path : frames)
{
_sprite.texture(path, GL_LINEAR);
@ -95,6 +96,12 @@ bool Character::resting() const
return _resting;
}
bool Character::resting(bool state)
{
_resting = state;
return _resting;
}
float Character::relative(const Curve& curve) const
{
return float(next_point_index) / curve.length();
@ -118,12 +125,14 @@ void Character::update(const Curve& curve, const sb::Timer& timer, bool muted, s
_resting = false;
/* Apply delta time to the speed increase. */
speed += timer.delta(profile()["speed increment"].get<float>()) + glm::abs(speed) * profile()["increment mod"].get<float>();
speed += timer.delta(profile()["speed increment"].get<float>()) +
glm::abs(speed) * profile()["increment mod"].get<float>();
}
else
{
/* Apply delta time to the speed decrease. */
speed -= timer.delta(profile()["speed decrement"].get<float>()) + glm::abs(speed) * profile()["decrement mod"].get<float>();
speed -= timer.delta(profile()["speed decrement"].get<float>()) +
glm::abs(speed) * profile()["decrement mod"].get<float>();
}
}

View File

@ -140,6 +140,12 @@ public:
*/
bool resting() const;
/*!
* @param state resting state
* @return resting state
*/
bool resting(bool state);
/*!
* @return character's relative position on the given curve
*/

11
src/config_local.json Normal file
View File

@ -0,0 +1,11 @@
{
"recording":
{
"enabled": true
},
"log":
{
"enabled": true
}
}

View File

@ -1,12 +1,13 @@
/* _ _
* c/a`k-e'f`o^o~t-, | a single-button action game | by @ooofoam
* / _< | wow a living cake the sweet | play online: https://foam.ooo/cakefoot
* > `~_/ | taste of victory | open source: https://open.shampoo.ooo/shampoo/cakefoot
/* _ _
* / `-' `-^~~-, | cakefoot presented by dank.game
* \__ _ _< |
* `v ) `~_/ | source code and license at https://open.shampoo.ooo/shampoo/cakefoot
*
* Custom modifications to Emscripten's Module object and other JavaScript to be included in the WASM build specific to the FOAM site.
* @file pre_js_collect.js
*
* Addition to Emscripten's Module object to be included in WASM builds that will collect user play data.
*/
/* Collect user play data when running on the FOAM site */
function collectData()
{
/* Open the database Emscripten's IDBFS library created. */

View File

@ -4,8 +4,9 @@
session_start();
/* The log of play history is stored in JSON format in a file in the same directory as this script. If this file doesn't exist yet, it
* will be created at write time. */
$history_path = "Play_History.json";
* will be created at write time. Each session ID is written to its own file to avoid race conditions between multiple sessions
* sharing a single file. */
$history_path = session_id() . "-Play_History.json";
/* Read JSON data from the history path. If the file doesn't exist, is not in JSON format, or any other exception occurs, just set the
* history to an empty array. */
@ -18,11 +19,15 @@ catch (Exception $e)
$history = array();
}
/* JSON data containing the user's play history is passed as a POST request from JavaScript */
$submitted_user_log = array(session_id() => json_decode(file_get_contents("php://input"), true)["progress"]);
/* JSON data containing the user's play history is passed as a POST request from JavaScript in pre_js_dank.js. Remove HTML and PHP
* special characters and limit length of input to 2048 characters to protect against injections. */
$submitted_user_log = array(session_id() => json_decode(file_get_contents("php://input", false, null, 0, 2048), true)["progress"]);
/* Merge the passed play history into the history array, overwriting any existing data at the current session ID, or adding a new section
* to the array if the session ID doesn't exist as a key in the array yet. Write the array to the history path. */
/* Add a timestamp to the log */
$submitted_user_log["timestamp"] = date("Y-m-d H:i:s");
/* Merge the passed play history into the history array, overwriting any existing data at the current session ID, or adding a new
* section to the array if the session ID doesn't exist as a key in the array yet. Write the array to the history path. */
file_put_contents(
$history_path,
json_encode(