Skip to content

Commit 428360e

Browse files
authored
Adds support for seed play (#158)
* Adds ability to copy the current seed to clipboard * Adds text input support * Seedling steam achievement
1 parent 6f35f24 commit 428360e

File tree

7 files changed

+315
-21
lines changed

7 files changed

+315
-21
lines changed

src/input.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ input_init(Input *input)
3131
input->lastMouseY = 0;
3232
input->modKeyState = 0;
3333
input->lastModKeyState = 0;
34+
input->textInput[0] = '\0';
3435
}
3536

3637
void
@@ -44,6 +45,7 @@ input_reset(Input *input)
4445
input->modKeyState = 0;
4546
input->lastMouseX = input->mouseX;
4647
input->lastMouseY = input->mouseY;
48+
input->textInput[0] = '\0';
4749
}
4850

4951
static Uint64
@@ -101,6 +103,9 @@ get_event_key(SDL_Event *event)
101103
case SDLK_TAB:
102104
key = KEY_TAB;
103105
break;
106+
case SDLK_BACKSPACE:
107+
key = KEY_BACKSPACE;
108+
break;
104109
default:
105110
key = 0;
106111
break;
@@ -195,6 +200,9 @@ get_event_modkey(SDL_Event *event)
195200
case SDLK_F:
196201
key = KEY_CTRL_F;
197202
break;
203+
case SDLK_V:
204+
key = KEY_CTRL_V;
205+
break;
198206
}
199207
} else if (event->key.mod & (SDL_KMOD_LSHIFT | SDL_KMOD_RSHIFT)) {
200208
switch (event->key.key) {
@@ -278,6 +286,10 @@ input_handle_event(Input *input, SDL_Event *event, InputDeviceType *device_type)
278286
} else {
279287
input->keyState &= ~get_axis_motion(event);
280288
}
289+
} else if (event->type == SDL_EVENT_TEXT_INPUT) {
290+
// Copy the string and ensure null-termination
291+
strncpy(input->textInput, event->text.text, TEXT_INPUT_MAX_LEN - 1);
292+
input->textInput[TEXT_INPUT_MAX_LEN - 1] = '\0';
281293
}
282294

283295
if (device_type != NULL) {

src/input.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#define KEY_ENTER 0x8000
4141
#define KEY_SPACE 0x10000
4242
#define KEY_TAB 0x20000
43+
#define KEY_BACKSPACE 0x40000
4344

4445
#define KEY_CTRL_M 0x1
4546
#define KEY_CTRL_S 0x2
@@ -50,11 +51,14 @@
5051
#define KEY_SHIFT_NUM4 0x40
5152
#define KEY_SHIFT_NUM5 0x80
5253
#define KEY_CTRL_F 0x100
54+
#define KEY_CTRL_V 0x200
5355

5456
#define MBUTTON_LEFT 0x1
5557
#define MBUTTON_MIDDLE 0x2
5658
#define MBUTTON_RIGHT 0x4
5759

60+
#define TEXT_INPUT_MAX_LEN 16
61+
5862
typedef enum InputDeviceType { DeviceType_Unknown, DeviceType_Keyboard, DeviceType_Gamepad } InputDeviceType;
5963

6064
typedef struct Input {
@@ -68,6 +72,7 @@ typedef struct Input {
6872
Uint32 lastMouseY;
6973
Uint32 mouseX;
7074
Uint32 mouseY;
75+
char textInput[TEXT_INPUT_MAX_LEN];
7176
} Input;
7277

7378
void input_init(Input *);

src/main.c

Lines changed: 106 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
#include "event.h"
5757
#include "config.h"
5858
#include "save.h"
59+
#include "text_input.h"
5960

6061
#ifdef DEBUG
6162
#include "debug/debug.h"
@@ -104,6 +105,7 @@ static SDL_Rect statsGuiViewport;
104105
static SDL_Rect minimapViewport;
105106
static SDL_Rect menuViewport;
106107
static Input input;
108+
static unsigned int gCustomSeed = 0;
107109

108110
#ifdef DEBUG
109111
static Sprite *fpsSprite = NULL;
@@ -260,10 +262,16 @@ startGame(void)
260262
else
261263
cLevel = 1;
262264

263-
if (weeklyGame)
265+
if (weeklyGame) {
266+
debug("Using weekly game seed");
264267
set_random_seed((unsigned int)time_get_weekly_seed());
265-
else
266-
set_random_seed(0);
268+
} else if (gCustomSeed) {
269+
debug("Using custom game seed");
270+
set_random_seed(gCustomSeed);
271+
} else {
272+
debug("Setting random seed");
273+
set_random_seed(0); // 0 will trigger a random seed later on.
274+
}
267275

268276
gGameState = PLAYING;
269277
if (gPlayer)
@@ -471,6 +479,18 @@ goToGameSelectMenu(void *unused)
471479
gGameState = GAME_SELECT;
472480
}
473481

482+
static void
483+
openSeedEntry(void *unused)
484+
{
485+
(void)unused;
486+
char seed_str[16] = {0};
487+
if (gCustomSeed > 0) {
488+
SDL_snprintf(seed_str, sizeof(seed_str), "%u", gCustomSeed);
489+
}
490+
text_input_init(gWindow, gRenderer, "Enter game seed:", seed_str);
491+
gGameState = SEED_ENTRY;
492+
}
493+
474494
static void
475495
showHowToTooltip(void *unused)
476496
{
@@ -479,33 +499,66 @@ showHowToTooltip(void *unused)
479499
gGui->activeTooltip = tooltip_manager_get_tooltip(TOOLTIP_TYPE_HOWTO);
480500
}
481501

502+
static void
503+
copySeedToClipboard(void *unused)
504+
{
505+
(void)unused;
506+
char seed_str[16];
507+
SDL_snprintf(seed_str, sizeof(seed_str), "%u", get_random_seed());
508+
SDL_SetClipboardText(seed_str);
509+
gui_event_message("Seed copied to clipboard");
510+
toggleInGameMenu(NULL);
511+
}
512+
513+
static void
514+
buildSeedLabel(char *buf, size_t size)
515+
{
516+
SDL_snprintf(buf, size, "SEED:%u", get_random_seed());
517+
}
518+
482519
static void
483520
initInGameMenu(void)
484521
{
485-
static TEXT_MENU_ITEM menu_items[] = {
486-
{"RESUME", "", toggleInGameMenu},
487-
{"HOW TO PLAY", "", showHowToTooltip},
488-
{"MAIN MENU", "", goToMainMenu},
489-
{"QUIT", "Exit game", exitGame},
490-
};
522+
static char seed_label[32];
523+
buildSeedLabel(seed_label, sizeof(seed_label));
524+
525+
TEXT_MENU_ITEM menu_items[5];
526+
int count = 0;
491527

492-
menu_create_text_menu(&inGameMenu, &menu_items[0], 4, gRenderer);
528+
menu_items[count++] = (TEXT_MENU_ITEM){"RESUME", "Resume the current game", toggleInGameMenu};
529+
menu_items[count++] = (TEXT_MENU_ITEM){"HOW TO PLAY", "Show the in-game guide", showHowToTooltip};
530+
if (!weeklyGame) {
531+
menu_items[count++] = (TEXT_MENU_ITEM){seed_label, "Copy seed to clipboard", copySeedToClipboard};
532+
}
533+
menu_items[count++] = (TEXT_MENU_ITEM){"MAIN MENU", "Return to the main menu", goToMainMenu};
534+
menu_items[count++] = (TEXT_MENU_ITEM){"QUIT", "Exit game", exitGame};
535+
536+
menu_create_text_menu(&inGameMenu, &menu_items[0], count, gRenderer);
493537
}
494538

495539
static void
496540
createInGameGameOverMenu(void)
497541
{
498-
static TEXT_MENU_ITEM menu_items[] = {
499-
{"NEW GAME", "Start a new game with the same settings", goToCharacterMenu},
500-
{"MAIN MENU", "", goToMainMenu},
501-
{"QUIT", "Exit game", exitGame},
502-
};
542+
static char seed_label[32];
543+
buildSeedLabel(seed_label, sizeof(seed_label));
503544

504545
if (inGameMenu) {
505546
menu_destroy(inGameMenu);
506547
inGameMenu = NULL;
507548
}
508-
menu_create_text_menu(&inGameMenu, &menu_items[0], 3, gRenderer);
549+
550+
TEXT_MENU_ITEM menu_items[4];
551+
int count = 0;
552+
553+
menu_items[count++] =
554+
(TEXT_MENU_ITEM){"NEW GAME", "Start a new game with the same settings", goToCharacterMenu};
555+
if (!weeklyGame) {
556+
menu_items[count++] = (TEXT_MENU_ITEM){seed_label, "Copy seed to clipboard", copySeedToClipboard};
557+
}
558+
menu_items[count++] = (TEXT_MENU_ITEM){"MAIN MENU", "Return to the main menu", goToMainMenu};
559+
menu_items[count++] = (TEXT_MENU_ITEM){"QUIT", "Exit game", exitGame};
560+
561+
menu_create_text_menu(&inGameMenu, &menu_items[0], count, gRenderer);
509562
}
510563

511564
static void
@@ -547,6 +600,7 @@ initMainMenu(void)
547600
{
548601
static TEXT_MENU_ITEM menu_items[] = {
549602
{"PLAY", "Start game", goToGameSelectMenu},
603+
{"SET SEED", "Set the game seed", openSeedEntry},
550604
{"SCORES", "View your top 10 scores", viewScoreScreen},
551605
{"CREDITS", "View game credits", viewCredits},
552606
{"QUIT", "Exit game", exitGame},
@@ -557,7 +611,7 @@ initMainMenu(void)
557611

558612
gMap = map_lua_generator_single_room__run(cLevel, gRenderer);
559613

560-
menu_create_text_menu(&mainMenu, &menu_items[0], 4, gRenderer);
614+
menu_create_text_menu(&mainMenu, &menu_items[0], SDL_arraysize(menu_items), gRenderer);
561615
mixer_play_music(MENU_MUSIC);
562616
creditsScreen = screen_create_credits(gRenderer);
563617
scoreScreen = screen_create_hiscore(gRenderer);
@@ -752,6 +806,10 @@ handle_main_input(void)
752806
charSelectMenu = NULL;
753807
gGameState = GAME_SELECT;
754808
break;
809+
case SEED_ENTRY:
810+
text_input_close(gWindow);
811+
gGameState = MENU;
812+
break;
755813
case MENU:
756814
gGameState = QUIT;
757815
break;
@@ -769,7 +827,7 @@ handle_main_input(void)
769827
}
770828

771829
handle_settings_input();
772-
if (input_key_is_pressed(&input, KEY_TAB)) {
830+
if ((gGameState == PLAYING || gGameState == GAME_OVER) && input_key_is_pressed(&input, KEY_TAB)) {
773831
gShowMap = !gShowMap;
774832
}
775833
}
@@ -1059,6 +1117,7 @@ run_game_render(void)
10591117
static inline void
10601118
register_scores(void)
10611119
{
1120+
debug("Registering steam scores");
10621121
uint8_t details[4] = {(uint8_t)gPlayer->stats.lvl, (uint8_t)cLevel, (uint8_t)(gPlayer->class + 1), 0};
10631122
steam_register_score((int)gPlayer->gold, (int32_t *)&details, 1);
10641123
steam_register_kills((int)gPlayer->stat_data.kills, (int32_t *)&details, 1);
@@ -1080,6 +1139,10 @@ register_scores(void)
10801139
steam_set_achievement(MAGICAL);
10811140
steam_register_mage_score((int)gPlayer->gold, (int32_t *)&details, 1);
10821141
}
1142+
1143+
if (gCustomSeed != 0 && !weeklyGame) {
1144+
steam_set_achievement(SEEDLING);
1145+
}
10831146
}
10841147
#endif
10851148

@@ -1207,6 +1270,28 @@ run_menu(void)
12071270
SDL_RenderPresent(gRenderer);
12081271
}
12091272

1273+
static void
1274+
run_seed_entry(void)
1275+
{
1276+
SDL_SetRenderViewport(gRenderer, &mainViewport);
1277+
text_input_update(&input);
1278+
text_input_render(gCamera);
1279+
SDL_RenderPresent(gRenderer);
1280+
1281+
// Di this last since it resets the text_input
1282+
if (text_input_is_confirmed()) {
1283+
const char *val = text_input_get_value();
1284+
if (SDL_strlen(val) > 0) {
1285+
gCustomSeed = (unsigned int)SDL_atoi(val);
1286+
debug("Custom seed set: %u", gCustomSeed);
1287+
} else {
1288+
gCustomSeed = 0;
1289+
}
1290+
text_input_close(gWindow);
1291+
gGameState = MENU;
1292+
}
1293+
}
1294+
12101295
static void
12111296
run(void)
12121297
{
@@ -1252,6 +1337,9 @@ run(void)
12521337
case CHARACTER_MENU:
12531338
run_menu();
12541339
break;
1340+
case SEED_ENTRY:
1341+
run_seed_entry();
1342+
break;
12551343
case QUIT:
12561344
quit = true;
12571345
break;

src/steam/steamworks_api_wrapper.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ static Achievement g_Achievements[] = {_ACH_ID(BAD_DOG, "Bad Dog"),
2323
_ACH_ID(BACK_TO_WORK, "Back to work"),
2424
_ACH_ID(DRAGON_SLAYER, "Platinum dragon slayer"),
2525
_ACH_ID(ROGUE_LIKE, "Rogue-like"),
26-
_ACH_ID(MAGICAL, "Magical")};
27-
static Uint8 numAchievements = 7;
26+
_ACH_ID(MAGICAL, "Magical"),
27+
_ACH_ID(SEEDLING, "Seedling")};
28+
static Uint8 numAchievements = SDL_arraysize(g_Achievements);
2829

2930
static bool m_Initiated = false;
3031
static uint32_t m_AppID = 0;
@@ -140,6 +141,7 @@ steam_set_achievement(EAchievement eAch)
140141
Achievement *a = &g_Achievements[i];
141142
if (a->m_eAchievementID == eAch && !a->m_bAchieved) {
142143
c_SteamUserStats_SetAchievement(g_Achievements[i].m_pchAchievementID);
144+
debug("Setting \"%s\" achievement", a->m_rgchName);
143145
gui_log("You just earned the \"%s\" achievement", a->m_rgchName);
144146
}
145147
}

src/steam/steamworks_api_wrapper.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ typedef enum EAchievement {
1313
BUGGCREATOR = 8,
1414
ROGUE_LIKE = 9,
1515
MAGICAL = 10,
16-
ARCADE_HACK = 11
16+
ARCADE_HACK = 11,
17+
SEEDLING = 12,
1718
} EAchievement;
1819

1920
#define _ACH_ID(id, name) {id, #id, name, "", 0, 0}

0 commit comments

Comments
 (0)