forked from EasyRPG/Player
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgame_interpreter.h
396 lines (340 loc) · 14.6 KB
/
game_interpreter.h
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
/*
* This file is part of EasyRPG Player.
*
* EasyRPG Player is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EasyRPG Player is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EP_GAME_INTERPRETER_H
#define EP_GAME_INTERPRETER_H
#include <cstdint>
#include <map>
#include <string>
#include <vector>
#include "async_handler.h"
#include "game_character.h"
#include "game_actor.h"
#include <lcf/dbarray.h>
#include <lcf/rpg/fwd.h>
#include <lcf/rpg/eventcommand.h>
#include "system.h"
#include <lcf/rpg/saveeventexecstate.h>
#include <lcf/flag_set.h>
#include "async_op.h"
class Game_Event;
class Game_CommonEvent;
class PendingMessage;
/**
* Game_Interpreter class
*/
class Game_Interpreter
{
public:
using Cmd = lcf::rpg::EventCommand::Code;
static Game_Interpreter& GetForegroundInterpreter();
Game_Interpreter(bool _main_flag = false);
#ifndef EMSCRIPTEN
// No idea why but emscripten will complain about a missing destructor when
// using virtual here
virtual
#endif
~Game_Interpreter();
void Clear();
bool IsRunning() const;
int GetLoopCount() const;
bool ReachedLoopLimit() const;
void Update(bool reset_loop_count=true);
void Push(
std::vector<lcf::rpg::EventCommand> _list,
int _event_id,
bool started_by_decision_key = false,
int event_page_id = 0
);
void Push(Game_Event* ev);
void Push(Game_Event* ev, const lcf::rpg::EventPage* page, bool triggered_by_decision_key);
void Push(Game_CommonEvent* ev);
void InputButton();
void SetupChoices(const std::vector<std::string>& choices, int indent, PendingMessage& pm);
bool ExecuteCommand();
virtual bool ExecuteCommand(lcf::rpg::EventCommand const& com);
/**
* Returns the interpreters current state information.
* For saving state into a save file, use GetSaveState instead.
*/
const lcf::rpg::SaveEventExecState& GetState() const;
/**
* Returns a SaveEventExecState needed for the savefile.
*
* @return interpreter commands stored in SaveEventCommands
*/
lcf::rpg::SaveEventExecState GetSaveState();
/** @return Game_Character of the passed event_id */
Game_Character* GetCharacter(int event_id) const;
/** @return the event_id of the current frame */
int GetCurrentEventId() const;
/** @return the event_id used by "ThisEvent" in commands */
int GetThisEventId() const;
/** @return the event_id of the event at the base of the call stack */
int GetOriginalEventId() const;
/** Return true if the interpreter is waiting for an async operation and needs to be resumed */
bool IsAsyncPending();
/** Return true if the interpreter is waiting for an async operation and needs to be resumed */
AsyncOp GetAsyncOp() const;
/** @return true if wait command (time or key) is active. Used by 2k3 battle system */
bool IsWaitingForWaitCommand() const;
protected:
static constexpr int loop_limit = 10000;
static constexpr int call_stack_limit = 1000;
static constexpr int subcommand_sentinel = 255;
const lcf::rpg::SaveEventExecFrame& GetFrame() const;
lcf::rpg::SaveEventExecFrame& GetFrame();
const lcf::rpg::SaveEventExecFrame* GetFramePtr() const;
lcf::rpg::SaveEventExecFrame* GetFramePtr();
bool main_flag;
int loop_count = 0;
/**
* Gets strings for choice selection.
* This is just a helper (private) method
* to avoid repeating code.
*
* @param max_num_choices The maximum number of choices to allow. Any choice with id >= this value (cancel handler) is ignored.
*/
std::vector<std::string> GetChoices(int max_num_choices);
/**
* Calculates operated value.
*
* @param operation operation (increase: 0, decrease: 1).
* @param operand_type operand type (0: set, 1: variable).
* @param operand operand (number or var ID).
*/
int OperateValue(int operation, int operand_type, int operand);
/**
* Skips to the next option in a chain of conditional commands.
* Works by skipping until we hit the end or the next command
* with com.indent <= indent.
* The <= protects against broken game code which terminates without
* a proper conditional.
*
* @param codes which codes to check.
* @param indent the indentation level to check
*/
void SkipToNextConditional(std::initializer_list<Cmd> codes, int indent);
/**
* Sets up a wait (and closes the message box)
*/
void SetupWait(int duration);
/**
* Sets up a wait using frames (and closes the message box)
*/
void SetupWaitFrames(int duration);
/**
* Calculates list of actors.
*
* @param mode 0: party, 1: specific actor, 2: actor referenced by variable.
* @param id actor ID (mode = 1) or variable ID (mode = 2).
*/
static std::vector<Game_Actor*> GetActors(int mode, int id);
static int ValueOrVariable(int mode, int val);
static int ValueOrVariableBitfield(int mode, int shift, int val);
// Range checked, conditional version (slower) of ValueOrVariableBitfield
static int ValueOrVariableBitfield(lcf::rpg::EventCommand const& com, int mode_idx, int shift, int val_idx);
static StringView CommandStringOrVariable(lcf::rpg::EventCommand const& com, int mode_idx, int val_idx);
static StringView CommandStringOrVariableBitfield(lcf::rpg::EventCommand const& com, int mode_idx, int shift, int val_idx);
/**
* When current frame finishes executing we pop the stack
*/
bool OnFinishStackFrame();
/**
* Triggers a game over when all party members are dead.
*
* @return true if game over was started.
*/
bool CheckGameOver();
bool CommandOptionGeneric(lcf::rpg::EventCommand const& com, int option_sub_idx, std::initializer_list<Cmd> next);
bool CommandShowMessage(lcf::rpg::EventCommand const& com);
bool CommandMessageOptions(lcf::rpg::EventCommand const& com);
bool CommandChangeFaceGraphic(lcf::rpg::EventCommand const& com);
bool CommandShowChoices(lcf::rpg::EventCommand const& com);
bool CommandShowChoiceOption(lcf::rpg::EventCommand const& com);
bool CommandShowChoiceEnd(lcf::rpg::EventCommand const& com);
bool CommandInputNumber(lcf::rpg::EventCommand const& com);
bool CommandControlSwitches(lcf::rpg::EventCommand const& com);
bool CommandControlVariables(lcf::rpg::EventCommand const& com);
bool CommandTimerOperation(lcf::rpg::EventCommand const& com);
bool CommandChangeGold(lcf::rpg::EventCommand const& com);
bool CommandChangeItems(lcf::rpg::EventCommand const& com);
bool CommandChangePartyMember(lcf::rpg::EventCommand const& com);
bool CommandChangeExp(lcf::rpg::EventCommand const& com);
bool CommandChangeLevel(lcf::rpg::EventCommand const& com);
bool CommandChangeParameters(lcf::rpg::EventCommand const& com);
bool CommandChangeSkills(lcf::rpg::EventCommand const& com);
bool CommandChangeEquipment(lcf::rpg::EventCommand const& com);
bool CommandChangeHP(lcf::rpg::EventCommand const& com);
bool CommandChangeSP(lcf::rpg::EventCommand const& com);
bool CommandChangeCondition(lcf::rpg::EventCommand const& com);
bool CommandFullHeal(lcf::rpg::EventCommand const& com);
bool CommandSimulatedAttack(lcf::rpg::EventCommand const& com);
bool CommandWait(lcf::rpg::EventCommand const& com);
bool CommandPlayBGM(lcf::rpg::EventCommand const& com);
bool CommandFadeOutBGM(lcf::rpg::EventCommand const& com);
bool CommandPlaySound(lcf::rpg::EventCommand const& com);
bool CommandEndEventProcessing(lcf::rpg::EventCommand const& com);
bool CommandComment(lcf::rpg::EventCommand const& com);
bool CommandGameOver(lcf::rpg::EventCommand const& com);
bool CommandChangeHeroName(lcf::rpg::EventCommand const& com);
bool CommandChangeHeroTitle(lcf::rpg::EventCommand const& com);
bool CommandChangeSpriteAssociation(lcf::rpg::EventCommand const& com);
bool CommandChangeActorFace(lcf::rpg::EventCommand const& com);
bool CommandChangeVehicleGraphic(lcf::rpg::EventCommand const& com);
bool CommandChangeSystemBGM(lcf::rpg::EventCommand const& com);
bool CommandChangeSystemSFX(lcf::rpg::EventCommand const& com);
bool CommandChangeSystemGraphics(lcf::rpg::EventCommand const& com);
bool CommandChangeScreenTransitions(lcf::rpg::EventCommand const& com);
bool CommandMemorizeLocation(lcf::rpg::EventCommand const& com);
bool CommandSetVehicleLocation(lcf::rpg::EventCommand const& com);
bool CommandChangeEventLocation(lcf::rpg::EventCommand const& com);
bool CommandTradeEventLocations(lcf::rpg::EventCommand const& com);
bool CommandStoreTerrainID(lcf::rpg::EventCommand const& com);
bool CommandStoreEventID(lcf::rpg::EventCommand const& com);
bool CommandEraseScreen(lcf::rpg::EventCommand const& com);
bool CommandShowScreen(lcf::rpg::EventCommand const& com);
bool CommandTintScreen(lcf::rpg::EventCommand const& com);
bool CommandFlashScreen(lcf::rpg::EventCommand const& com);
bool CommandShakeScreen(lcf::rpg::EventCommand const& com);
bool CommandWeatherEffects(lcf::rpg::EventCommand const& com);
bool CommandShowPicture(lcf::rpg::EventCommand const& com);
bool CommandMovePicture(lcf::rpg::EventCommand const& com);
bool CommandErasePicture(lcf::rpg::EventCommand const& com);
bool CommandPlayerVisibility(lcf::rpg::EventCommand const& com);
bool CommandMoveEvent(lcf::rpg::EventCommand const& com);
bool CommandMemorizeBGM(lcf::rpg::EventCommand const& com);
bool CommandPlayMemorizedBGM(lcf::rpg::EventCommand const& com);
bool CommandKeyInputProc(lcf::rpg::EventCommand const& com);
bool CommandChangeMapTileset(lcf::rpg::EventCommand const& com);
bool CommandChangePBG(lcf::rpg::EventCommand const& com);
bool CommandChangeEncounterSteps(lcf::rpg::EventCommand const& com);
bool CommandTileSubstitution(lcf::rpg::EventCommand const& com);
bool CommandTeleportTargets(lcf::rpg::EventCommand const& com);
bool CommandChangeTeleportAccess(lcf::rpg::EventCommand const& com);
bool CommandEscapeTarget(lcf::rpg::EventCommand const& com);
bool CommandChangeEscapeAccess(lcf::rpg::EventCommand const& com);
bool CommandChangeSaveAccess(lcf::rpg::EventCommand const& com);
bool CommandChangeMainMenuAccess(lcf::rpg::EventCommand const& com);
bool CommandConditionalBranch(lcf::rpg::EventCommand const& com);
bool CommandElseBranch(lcf::rpg::EventCommand const& com);
bool CommandEndBranch(lcf::rpg::EventCommand const& com);
bool CommandJumpToLabel(lcf::rpg::EventCommand const& com);
bool CommandLoop(lcf::rpg::EventCommand const& com);
bool CommandBreakLoop(lcf::rpg::EventCommand const& com);
bool CommandEndLoop(lcf::rpg::EventCommand const& com);
bool CommandEraseEvent(lcf::rpg::EventCommand const& com);
bool CommandCallEvent(lcf::rpg::EventCommand const& com);
bool CommandReturnToTitleScreen(lcf::rpg::EventCommand const& com);
bool CommandChangeClass(lcf::rpg::EventCommand const& com);
bool CommandChangeBattleCommands(lcf::rpg::EventCommand const& com);
bool CommandExitGame(lcf::rpg::EventCommand const& com);
bool CommandToggleFullscreen(lcf::rpg::EventCommand const& com);
bool CommandOpenVideoOptions(lcf::rpg::EventCommand const& com);
bool CommandManiacGetSaveInfo(lcf::rpg::EventCommand const& com);
bool CommandManiacSave(lcf::rpg::EventCommand const& com);
bool CommandManiacLoad(lcf::rpg::EventCommand const& com);
bool CommandManiacEndLoadProcess(lcf::rpg::EventCommand const& com);
bool CommandManiacGetMousePosition(lcf::rpg::EventCommand const& com);
bool CommandManiacSetMousePosition(lcf::rpg::EventCommand const& com);
bool CommandManiacShowStringPicture(lcf::rpg::EventCommand const& com);
bool CommandManiacGetPictureInfo(lcf::rpg::EventCommand const& com);
bool CommandManiacControlVarArray(lcf::rpg::EventCommand const& com);
bool CommandManiacKeyInputProcEx(lcf::rpg::EventCommand const& com);
bool CommandManiacRewriteMap(lcf::rpg::EventCommand const& com);
bool CommandManiacControlGlobalSave(lcf::rpg::EventCommand const& com);
bool CommandManiacChangePictureId(lcf::rpg::EventCommand const& com);
bool CommandManiacSetGameOption(lcf::rpg::EventCommand const& com);
bool CommandManiacControlStrings(lcf::rpg::EventCommand const& com);
bool CommandManiacCallCommand(lcf::rpg::EventCommand const& com);
bool CommandEasyRpgSetInterpreterFlag(lcf::rpg::EventCommand const& com);
int DecodeInt(lcf::DBArray<int32_t>::const_iterator& it);
const std::string DecodeString(lcf::DBArray<int32_t>::const_iterator& it);
lcf::rpg::MoveCommand DecodeMove(lcf::DBArray<int32_t>::const_iterator& it);
void SetSubcommandIndex(int indent, int idx);
uint8_t& ReserveSubcommandIndex(int indent);
int GetSubcommandIndex(int indent) const;
void ForegroundTextPush(PendingMessage pm);
void EndEventProcessing();
FileRequestBinding request_id;
enum class Keys {
eDown,
eLeft,
eRight,
eUp,
eDecision,
eCancel,
eShift,
eNumbers,
eOperators,
// ManiacPatch
eMouseLeft,
eMouseRight,
eMouseMiddle,
eMouseScrollDown,
eMouseScrollUp
};
struct KeyInputState {
lcf::FlagSet<Keys> keys = {};
int variable = 0;
int time_variable = 0;
int wait_frames = 0;
bool wait = false;
bool timed = false;
int CheckInput() const;
void fromSave(const lcf::rpg::SaveEventExecState& save);
void toSave(lcf::rpg::SaveEventExecState& save) const;
};
bool CheckOperator(int val, int val2, int op) const;
bool ManiacCheckContinueLoop(int val, int val2, int type, int op) const;
int ManiacBitmask(int value, int mask) const;
lcf::rpg::SaveEventExecState _state;
KeyInputState _keyinput;
AsyncOp _async_op = {};
friend class Scene_Debug;
};
inline const lcf::rpg::SaveEventExecFrame* Game_Interpreter::GetFramePtr() const {
return !_state.stack.empty() ? &_state.stack.back() : nullptr;
}
inline lcf::rpg::SaveEventExecFrame* Game_Interpreter::GetFramePtr() {
return !_state.stack.empty() ? &_state.stack.back() : nullptr;
}
inline const lcf::rpg::SaveEventExecFrame& Game_Interpreter::GetFrame() const {
auto* frame = GetFramePtr();
assert(frame);
return *frame;
}
inline lcf::rpg::SaveEventExecFrame& Game_Interpreter::GetFrame() {
auto* frame = GetFramePtr();
assert(frame);
return *frame;
}
inline int Game_Interpreter::GetCurrentEventId() const {
return !_state.stack.empty() ? _state.stack.back().event_id : 0;
}
inline int Game_Interpreter::GetOriginalEventId() const {
return !_state.stack.empty() ? _state.stack.front().event_id : 0;
}
inline int Game_Interpreter::GetLoopCount() const {
return loop_count;
}
inline bool Game_Interpreter::IsAsyncPending() {
return GetAsyncOp().IsActive();
}
inline AsyncOp Game_Interpreter::GetAsyncOp() const {
return _async_op;
}
#endif