-
Notifications
You must be signed in to change notification settings - Fork 44
/
minigame.c
171 lines (136 loc) · 5.19 KB
/
minigame.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/***************************************************************
minigame.c
The file contains the minigame manager
***************************************************************/
#include <libdragon.h>
#include <string.h>
#include "core.h"
#include "minigame.h"
/*********************************
Globals
*********************************/
// Minigame info
static bool global_minigame_ending = false;
static Minigame* global_minigame_current = NULL;
Minigame* global_minigame_list;
size_t global_minigame_count;
// Helper consts
static const char* global_minigamepath = "rom:/minigames/";
static const size_t global_minigamepath_len = 15;
/*==============================
minigame_loadall
Loads all the minigames from the filesystem
==============================*/
void minigame_loadall()
{
size_t gamecount = 0;
dir_t minigamesdir;
// First, go through the minigames path and count the number of minigames
dir_findfirst(global_minigamepath, &minigamesdir);
do
{
if (!strstr(minigamesdir.d_name, ".sym"))
gamecount++;
}
while (dir_findnext(global_minigamepath, &minigamesdir) == 0);
global_minigame_count = gamecount;
// Allocate the list of minigames
global_minigame_list = (Minigame*)malloc(sizeof(Minigame) * gamecount);
// Look through the minigames path and register all the known minigames
gamecount = 0;
dir_findfirst(global_minigamepath, &minigamesdir);
do
{
void* handle;
MinigameDef* loadeddef;
Minigame* newdef = &global_minigame_list[gamecount];
char* filename = minigamesdir.d_name;
// Ignore the symbol file
if (strstr(filename, ".sym"))
continue;
// Get the filepath and open the dso
char fullpath[global_minigamepath_len + strlen(filename) + 1];
sprintf(fullpath, "%s%s", global_minigamepath, filename);
handle = dlopen(fullpath, RTLD_LOCAL);
// Get the symbols of the minigame definition.
// Since these symbols will only be temporarily stored in memory, we must make a deep copy
loadeddef = dlsym(handle, "minigame_def");
assertf(loadeddef, "Unable to find symbol minigame_def in %s\n", filename);
newdef->definition.gamename = strdup(loadeddef->gamename);
newdef->definition.developername = strdup(loadeddef->developername);
newdef->definition.description = strdup(loadeddef->description);
newdef->definition.instructions = strdup(loadeddef->instructions);
// Set the internal name as the filename without the extension
strrchr(filename, '.')[0] = '\0';
newdef->internalname = strdup(filename);
// Cleanup
dlclose(handle);
gamecount++;
}
while (dir_findnext("rom:/minigames/", &minigamesdir) == 0);
}
/*==============================
minigame_play
Executes a minigame
@param The internal filename of the minigame to play
==============================*/
void minigame_play(char* name)
{
debugf("Loading minigame: %s\n", name);
// Find the minigame with that name
global_minigame_current = NULL;
for (size_t i=0; i<global_minigame_count; i++)
{
if (!strcmp(global_minigame_list[i].internalname, name))
{
debugf("Success!\n");
global_minigame_current = &global_minigame_list[i];
break;
}
}
assertf(global_minigame_current != NULL, "Unable to find minigame with internal name '%s'", name);
// Load the dso and assign the internal functions
char fullpath[global_minigamepath_len + strlen(name) + 4 + 1];
sprintf(fullpath, "%s%s.dso", global_minigamepath, name);
global_minigame_current->handle = dlopen(fullpath, RTLD_LOCAL);
global_minigame_current->funcPointer_init = dlsym(global_minigame_current->handle, "minigame_init");
global_minigame_current->funcPointer_loop = dlsym(global_minigame_current->handle, "minigame_loop");
global_minigame_current->funcPointer_fixedloop = dlsym(global_minigame_current->handle, "minigame_fixedloop");
global_minigame_current->funcPointer_cleanup = dlsym(global_minigame_current->handle, "minigame_cleanup");
}
/*==============================
minigame_end
Ends the current minigame
==============================*/
void minigame_end()
{
global_minigame_ending = true;
}
/*==============================
minigame_get_game
Gets the currently executing minigame
@return The currently executing minigame
==============================*/
Minigame* minigame_get_game()
{
return global_minigame_current;
}
/*==============================
minigame_get_ended
Checks whether the current minigame is ending
@return Whether the current minigame is ending
==============================*/
bool minigame_get_ended()
{
return global_minigame_ending;
}
/*==============================
minigame_cleanup
Cleans up minigame settings and memory used by the manager
==============================*/
void minigame_cleanup()
{
global_minigame_ending = false;
dlclose(global_minigame_current->handle);
global_minigame_current->handle = NULL;
}