1 //=============================================================================
2 //
3 // Adventure Game Studio (AGS)
4 //
5 // Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
6 // The full list of copyright holders can be found in the Copyright.txt
7 // file, which is part of this source code distribution.
8 //
9 // The AGS source code is provided under the Artistic License 2.0.
10 // A copy of this license can be found in the file License.txt and at
11 // http://www.opensource.org/licenses/artistic-license-2.0.php
12 //
13 //=============================================================================
14
15 #include "ac/common.h"
16 #include "ac/view.h"
17 #include "ac/audiochannel.h"
18 #include "ac/character.h"
19 #include "ac/charactercache.h"
20 #include "ac/characterextras.h"
21 #include "ac/dialogtopic.h"
22 #include "ac/draw.h"
23 #include "ac/dynamicsprite.h"
24 #include "ac/event.h"
25 #include "ac/game.h"
26 #include "ac/gamesetup.h"
27 #include "ac/gamesetupstruct.h"
28 #include "ac/gamestate.h"
29 #include "ac/global_audio.h"
30 #include "ac/global_character.h"
31 #include "ac/global_display.h"
32 #include "ac/global_game.h"
33 #include "ac/global_gui.h"
34 #include "ac/global_object.h"
35 #include "ac/global_translation.h"
36 #include "ac/gui.h"
37 #include "ac/hotspot.h"
38 #include "ac/lipsync.h"
39 #include "ac/mouse.h"
40 #include "ac/movelist.h"
41 #include "ac/objectcache.h"
42 #include "ac/overlay.h"
43 #include "ac/path_helper.h"
44 #include "ac/record.h"
45 #include "ac/region.h"
46 #include "ac/richgamemedia.h"
47 #include "ac/room.h"
48 #include "ac/roomobject.h"
49 #include "ac/roomstatus.h"
50 #include "ac/roomstruct.h"
51 #include "ac/runtime_defines.h"
52 #include "ac/screenoverlay.h"
53 #include "ac/spritecache.h"
54 #include "ac/string.h"
55 #include "ac/system.h"
56 #include "ac/timer.h"
57 #include "ac/translation.h"
58 #include "ac/dynobj/all_dynamicclasses.h"
59 #include "ac/dynobj/all_scriptclasses.h"
60 #include "ac/dynobj/cc_audiochannel.h"
61 #include "ac/dynobj/cc_audioclip.h"
62 #include "debug/debug_log.h"
63 #include "debug/out.h"
64 #include "device/mousew32.h"
65 #include "font/fonts.h"
66 #include "game/savegame.h"
67 #include "game/savegame_internal.h"
68 #include "gui/animatingguibutton.h"
69 #include "gfx/graphicsdriver.h"
70 #include "gfx/gfxfilter.h"
71 #include "gui/guidialog.h"
72 #include "main/graphics_mode.h"
73 #include "main/main.h"
74 #include "media/audio/audio.h"
75 #include "media/audio/soundclip.h"
76 #include "plugin/agsplugin.h"
77 #include "plugin/plugin_engine.h"
78 #include "script/cc_error.h"
79 #include "script/runtimescriptvalue.h"
80 #include "script/script.h"
81 #include "script/script_runtime.h"
82 #include "util/alignedstream.h"
83 #include "util/directory.h"
84 #include "util/filestream.h"
85 #include "util/path.h"
86 #include "util/string_utils.h"
87
88 using namespace AGS::Common;
89 using namespace AGS::Engine;
90
91 extern ScriptAudioChannel scrAudioChannel[MAX_SOUND_CHANNELS + 1];
92 extern int time_between_timers;
93 extern Bitmap *virtual_screen;
94 extern int cur_mode,cur_cursor;
95 extern SpeechLipSyncLine *splipsync;
96 extern int numLipLines, curLipLine, curLipLinePhoneme;
97
98 extern CharacterExtras *charextra;
99 extern DialogTopic *dialog;
100
101 extern int ifacepopped; // currently displayed pop-up GUI (-1 if none)
102 extern int mouse_on_iface; // mouse cursor is over this interface
103 extern int mouse_on_iface_button;
104 extern int mouse_pushed_iface; // this BUTTON on interface MOUSE_ON_IFACE is pushed
105 extern int mouse_ifacebut_xoffs,mouse_ifacebut_yoffs;
106
107 extern AnimatingGUIButton animbuts[MAX_ANIMATING_BUTTONS];
108 extern int numAnimButs;
109
110 extern ScreenOverlay screenover[MAX_SCREEN_OVERLAYS];
111 extern int numscreenover;
112 extern int is_complete_overlay,is_text_overlay;
113
114 #if defined(IOS_VERSION) || defined(ANDROID_VERSION)
115 extern int psp_gfx_renderer;
116 #endif
117
118 extern int obj_lowest_yp, char_lowest_yp;
119
120 extern int actSpsCount;
121 extern Bitmap **actsps;
122 extern IDriverDependantBitmap* *actspsbmp;
123 // temporary cache of walk-behind for this actsps image
124 extern Bitmap **actspswb;
125 extern IDriverDependantBitmap* *actspswbbmp;
126 extern CachedActSpsData* actspswbcache;
127 extern Bitmap **guibg;
128 extern IDriverDependantBitmap **guibgbmp;
129 extern char transFileName[MAX_PATH];
130 extern color palette[256];
131 extern int offsetx,offsety;
132 extern unsigned int loopcounter;
133 extern Bitmap *raw_saved_screen;
134 extern Bitmap *dynamicallyCreatedSurfaces[MAX_DYNAMIC_SURFACES];
135 extern IGraphicsDriver *gfxDriver;
136
137 //=============================================================================
138 GameState play;
139 GameSetup usetup;
140 GameSetupStruct game;
141 RoomStatus troom; // used for non-saveable rooms, eg. intro
142 RoomObject*objs;
143 RoomStatus*croom=NULL;
144 roomstruct thisroom;
145
146 volatile int switching_away_from_game = 0;
147 volatile bool switched_away = false;
148 volatile char want_exit = 0, abort_engine = 0;
149 GameDataVersion loaded_game_file_version = kGameVersion_Undefined;
150 int frames_per_second=40;
151 int displayed_room=-10,starting_room = -1;
152 int in_new_room=0, new_room_was = 0; // 1 in new room, 2 first time in new room, 3 loading saved game
153 int new_room_pos=0;
154 int new_room_x = SCR_NO_VALUE, new_room_y = SCR_NO_VALUE;
155 int new_room_loop = SCR_NO_VALUE;
156
157 //Bitmap *spriteset[MAX_SPRITES+1];
158 //SpriteCache spriteset (MAX_SPRITES+1);
159 // initially size 1, this will be increased by the initFile function
160 int spritewidth[MAX_SPRITES],spriteheight[MAX_SPRITES];
161 SpriteCache spriteset(1);
162 int proper_exit=0,our_eip=0;
163
164 std::vector<GUIMain> guis;
165
166 CCGUIObject ccDynamicGUIObject;
167 CCCharacter ccDynamicCharacter;
168 CCHotspot ccDynamicHotspot;
169 CCRegion ccDynamicRegion;
170 CCInventory ccDynamicInv;
171 CCGUI ccDynamicGUI;
172 CCObject ccDynamicObject;
173 CCDialog ccDynamicDialog;
174 CCAudioClip ccDynamicAudioClip;
175 CCAudioChannel ccDynamicAudio;
176 ScriptString myScriptStringImpl;
177 // TODO: IMPORTANT!!
178 // we cannot simply replace these arrays with vectors, or other C++ containers,
179 // until we implement safe management of such containers in script exports
180 // system. Noteably we would need an alternate to StaticArray class to track
181 // access to their elements.
182 ScriptObject scrObj[MAX_INIT_SPR];
183 ScriptGUI *scrGui = NULL;
184 ScriptHotspot scrHotspot[MAX_HOTSPOTS];
185 ScriptRegion scrRegion[MAX_REGIONS];
186 ScriptInvItem scrInv[MAX_INV];
187 ScriptDialog *scrDialog;
188
189 ViewStruct*views=NULL;
190
191 CharacterCache *charcache = NULL;
192 ObjectCache objcache[MAX_INIT_SPR];
193
194 MoveList *mls = NULL;
195
196 //=============================================================================
197
198 char saveGameDirectory[260] = "./";
199 // Custom save game parent directory
200 String saveGameParent;
201
202 const char* sgnametemplate = "agssave.%03d";
203 String saveGameSuffix;
204
205 int game_paused=0;
206 char pexbuf[STD_BUFFER_SIZE];
207
208 unsigned int load_new_game = 0;
209 int load_new_game_restore = -1;
210
211 int getloctype_index = 0, getloctype_throughgui = 0;
212
213 //=============================================================================
214 // Audio
215 //=============================================================================
216
Game_StopAudio(int audioType)217 void Game_StopAudio(int audioType)
218 {
219 if (((audioType < 0) || (audioType >= game.audioClipTypeCount)) && (audioType != SCR_NO_VALUE))
220 quitprintf("!Game.StopAudio: invalid audio type %d", audioType);
221 int aa;
222
223 for (aa = 0; aa < MAX_SOUND_CHANNELS; aa++)
224 {
225 if (audioType == SCR_NO_VALUE)
226 {
227 stop_or_fade_out_channel(aa);
228 }
229 else
230 {
231 ScriptAudioClip *clip = AudioChannel_GetPlayingClip(&scrAudioChannel[aa]);
232 if ((clip != NULL) && (clip->type == audioType))
233 stop_or_fade_out_channel(aa);
234 }
235 }
236
237 remove_clips_of_type_from_queue(audioType);
238 }
239
Game_IsAudioPlaying(int audioType)240 int Game_IsAudioPlaying(int audioType)
241 {
242 if (((audioType < 0) || (audioType >= game.audioClipTypeCount)) && (audioType != SCR_NO_VALUE))
243 quitprintf("!Game.IsAudioPlaying: invalid audio type %d", audioType);
244
245 if (play.fast_forward)
246 return 0;
247
248 for (int aa = 0; aa < MAX_SOUND_CHANNELS; aa++)
249 {
250 ScriptAudioClip *clip = AudioChannel_GetPlayingClip(&scrAudioChannel[aa]);
251 if (clip != NULL)
252 {
253 if ((clip->type == audioType) || (audioType == SCR_NO_VALUE))
254 {
255 return 1;
256 }
257 }
258 }
259 return 0;
260 }
261
Game_SetAudioTypeSpeechVolumeDrop(int audioType,int volumeDrop)262 void Game_SetAudioTypeSpeechVolumeDrop(int audioType, int volumeDrop)
263 {
264 if ((audioType < 0) || (audioType >= game.audioClipTypeCount))
265 quitprintf("!Game.SetAudioTypeVolume: invalid audio type: %d", audioType);
266
267 Debug::Printf("Game.SetAudioTypeSpeechVolumeDrop: type: %d, drop: %d", audioType, volumeDrop);
268 game.audioClipTypes[audioType].volume_reduction_while_speech_playing = volumeDrop;
269 update_volume_drop_if_voiceover();
270 }
271
Game_SetAudioTypeVolume(int audioType,int volume,int changeType)272 void Game_SetAudioTypeVolume(int audioType, int volume, int changeType)
273 {
274 if ((volume < 0) || (volume > 100))
275 quitprintf("!Game.SetAudioTypeVolume: volume %d is not between 0..100", volume);
276 if ((audioType < 0) || (audioType >= game.audioClipTypeCount))
277 quitprintf("!Game.SetAudioTypeVolume: invalid audio type: %d", audioType);
278 int aa;
279
280 Debug::Printf("Game.SetAudioTypeVolume: type: %d, volume: %d, change: %d", audioType, volume, changeType);
281 if ((changeType == VOL_CHANGEEXISTING) ||
282 (changeType == VOL_BOTH))
283 {
284 for (aa = 0; aa < MAX_SOUND_CHANNELS; aa++)
285 {
286 ScriptAudioClip *clip = AudioChannel_GetPlayingClip(&scrAudioChannel[aa]);
287 if ((clip != NULL) && (clip->type == audioType))
288 {
289 channels[aa]->set_volume_percent(volume);
290 }
291 }
292 }
293
294 if ((changeType == VOL_SETFUTUREDEFAULT) ||
295 (changeType == VOL_BOTH))
296 {
297 play.default_audio_type_volumes[audioType] = volume;
298
299 // update queued clip volumes
300 update_queued_clips_volume(audioType, volume);
301 }
302
303 }
304
Game_GetMODPattern()305 int Game_GetMODPattern() {
306 if (current_music_type == MUS_MOD && channels[SCHAN_MUSIC]) {
307 return channels[SCHAN_MUSIC]->get_pos();
308 }
309 return -1;
310 }
311
312 //=============================================================================
313 // ---
314 //=============================================================================
315
Game_GetDialogCount()316 int Game_GetDialogCount()
317 {
318 return game.numdialog;
319 }
320
set_debug_mode(bool on)321 void set_debug_mode(bool on)
322 {
323 play.debug_mode = on ? 1 : 0;
324 debug_set_console(on);
325 }
326
set_game_speed(int fps)327 void set_game_speed(int fps) {
328 frames_per_second = fps;
329 time_between_timers = 1000 / fps;
330 install_int_ex(dj_timer_handler,MSEC_TO_TIMER(time_between_timers));
331 }
332
333 extern int cbuttfont;
334 extern int acdialog_font;
335
336 extern char buffer2[60];
337 int oldmouse;
setup_for_dialog()338 void setup_for_dialog() {
339 cbuttfont = play.normal_font;
340 acdialog_font = play.normal_font;
341 SetVirtualScreen(virtual_screen);
342 if (!play.mouse_cursor_hidden)
343 domouse(1);
344 oldmouse=cur_cursor; set_mouse_cursor(CURS_ARROW);
345 }
restore_after_dialog()346 void restore_after_dialog() {
347 set_mouse_cursor(oldmouse);
348 if (!play.mouse_cursor_hidden)
349 domouse(2);
350 construct_virtual_screen(true);
351 }
352
353
354
get_save_game_path(int slotNum)355 String get_save_game_path(int slotNum) {
356 String filename;
357 filename.Format(sgnametemplate, slotNum);
358 String path = saveGameDirectory;
359 path.Append(filename);
360 path.Append(saveGameSuffix);
361 return path;
362 }
363
364 // Convert a path possibly containing path tags into acceptable save path
MakeSaveGameDir(const char * newFolder)365 String MakeSaveGameDir(const char *newFolder)
366 {
367 // don't allow absolute paths
368 if (!is_relative_filename(newFolder))
369 return "";
370
371 String newSaveGameDir = FixSlashAfterToken(newFolder);
372
373 if (newSaveGameDir.CompareLeft(UserSavedgamesRootToken, UserSavedgamesRootToken.GetLength()) == 0)
374 {
375 if (saveGameParent.IsEmpty())
376 {
377 newSaveGameDir.ReplaceMid(0, UserSavedgamesRootToken.GetLength(),
378 PathOrCurDir(platform->GetUserSavedgamesDirectory()));
379 }
380 else
381 {
382 // If there is a custom save parent directory, then replace
383 // not only root token, but also first subdirectory
384 newSaveGameDir.ClipSection('/', 0, 1);
385 if (!newSaveGameDir.IsEmpty())
386 newSaveGameDir.PrependChar('/');
387 newSaveGameDir.Prepend(saveGameParent);
388 }
389 }
390 else
391 {
392 // Convert the path relative to installation folder into path relative to the
393 // safe save path with default name
394 if (saveGameParent.IsEmpty())
395 newSaveGameDir.Format("%s/%s/%s", PathOrCurDir(platform->GetUserSavedgamesDirectory()),
396 game.saveGameFolderName, newFolder);
397 else
398 newSaveGameDir.Format("%s/%s", saveGameParent.GetCStr(), newFolder);
399 // For games made in the safe-path-aware versions of AGS, report a warning
400 if (game.options[OPT_SAFEFILEPATHS])
401 {
402 debug_script_warn("Attempt to explicitly set savegame location relative to the game installation directory ('%s') denied;\nPath will be remapped to the user documents directory: '%s'",
403 newFolder, newSaveGameDir.GetCStr());
404 }
405 }
406 return newSaveGameDir;
407 }
408
SetCustomSaveParent(const String & path)409 bool SetCustomSaveParent(const String &path)
410 {
411 if (SetSaveGameDirectoryPath(path, true))
412 {
413 saveGameParent = path;
414 return true;
415 }
416 return false;
417 }
418
SetSaveGameDirectoryPath(const char * newFolder,bool explicit_path)419 bool SetSaveGameDirectoryPath(const char *newFolder, bool explicit_path)
420 {
421 if (!newFolder || newFolder[0] == 0)
422 newFolder = ".";
423 String newSaveGameDir = explicit_path ? String(newFolder) : MakeSaveGameDir(newFolder);
424 if (newSaveGameDir.IsEmpty())
425 return false;
426
427 if (!Directory::CreateDirectory(newSaveGameDir))
428 return false;
429 newSaveGameDir.AppendChar('/');
430
431 char newFolderTempFile[260];
432 strcpy(newFolderTempFile, newSaveGameDir);
433 strcat(newFolderTempFile, "agstmp.tmp");
434 if (!Common::File::TestCreateFile(newFolderTempFile))
435 return false;
436
437 // copy the Restart Game file, if applicable
438 char restartGamePath[260];
439 sprintf(restartGamePath, "%s""agssave.%d%s", saveGameDirectory, RESTART_POINT_SAVE_GAME_NUMBER, saveGameSuffix.GetCStr());
440 Stream *restartGameFile = Common::File::OpenFileRead(restartGamePath);
441 if (restartGameFile != NULL)
442 {
443 long fileSize = restartGameFile->GetLength();
444 char *mbuffer = (char*)malloc(fileSize);
445 restartGameFile->Read(mbuffer, fileSize);
446 delete restartGameFile;
447
448 sprintf(restartGamePath, "%s""agssave.%d%s", newSaveGameDir.GetCStr(), RESTART_POINT_SAVE_GAME_NUMBER, saveGameSuffix.GetCStr());
449 restartGameFile = Common::File::CreateFile(restartGamePath);
450 restartGameFile->Write(mbuffer, fileSize);
451 delete restartGameFile;
452 free(mbuffer);
453 }
454
455 strcpy(saveGameDirectory, newSaveGameDir);
456 return true;
457 }
458
Game_SetSaveGameDirectory(const char * newFolder)459 int Game_SetSaveGameDirectory(const char *newFolder)
460 {
461 return SetSaveGameDirectoryPath(newFolder, false) ? 1 : 0;
462 }
463
Game_GetSaveSlotDescription(int slnum)464 const char* Game_GetSaveSlotDescription(int slnum) {
465 String description;
466 if (read_savedgame_description(get_save_game_path(slnum), description))
467 {
468 return CreateNewScriptString(description);
469 }
470 return NULL;
471 }
472
473
restore_game_dialog()474 void restore_game_dialog() {
475 can_run_delayed_command();
476 if (thisroom.options[ST_SAVELOAD] == 1) {
477 DisplayMessage (983);
478 return;
479 }
480 if (inside_script) {
481 curscript->queue_action(ePSARestoreGameDialog, 0, "RestoreGameDialog");
482 return;
483 }
484 setup_for_dialog();
485 int toload=loadgamedialog();
486 restore_after_dialog();
487 if (toload>=0) {
488 try_restore_save(toload);
489 }
490 }
491
save_game_dialog()492 void save_game_dialog() {
493 if (thisroom.options[ST_SAVELOAD] == 1) {
494 DisplayMessage (983);
495 return;
496 }
497 if (inside_script) {
498 curscript->queue_action(ePSASaveGameDialog, 0, "SaveGameDialog");
499 return;
500 }
501 setup_for_dialog();
502 int toload=savegamedialog();
503 restore_after_dialog();
504 if (toload>=0)
505 save_game(toload,buffer2);
506 }
507
508
509
510
511
setup_sierra_interface()512 void setup_sierra_interface() {
513 int rr;
514 game.numgui =0;
515 for (rr=0;rr<42;rr++) game.paluses[rr]=PAL_GAMEWIDE;
516 for (rr=42;rr<256;rr++) game.paluses[rr]=PAL_BACKGROUND;
517 }
518
519
free_do_once_tokens()520 void free_do_once_tokens()
521 {
522 for (int i = 0; i < play.num_do_once_tokens; i++)
523 {
524 free(play.do_once_tokens[i]);
525 }
526 if (play.do_once_tokens != NULL)
527 {
528 free(play.do_once_tokens);
529 play.do_once_tokens = NULL;
530 }
531 play.num_do_once_tokens = 0;
532 }
533
534
535 // Free all the memory associated with the game
unload_game_file()536 void unload_game_file() {
537 int bb, ee;
538
539 for (bb = 0; bb < game.numcharacters; bb++) {
540 if (game.charScripts != NULL)
541 delete game.charScripts[bb];
542
543 if (game.intrChar != NULL)
544 {
545 if (game.intrChar[bb] != NULL)
546 delete game.intrChar[bb];
547 game.intrChar[bb] = NULL;
548 }
549 }
550 if (game.intrChar != NULL)
551 {
552 free(game.intrChar);
553 game.intrChar = NULL;
554 }
555 characterScriptObjNames.clear();
556 free(charextra);
557 free(mls);
558 free(actsps);
559 free(actspsbmp);
560 free(actspswb);
561 free(actspswbbmp);
562 free(actspswbcache);
563 game.charProps.clear();
564
565 for (bb = 1; bb < game.numinvitems; bb++) {
566 if (game.invScripts != NULL)
567 delete game.invScripts[bb];
568 if (game.intrInv[bb] != NULL)
569 delete game.intrInv[bb];
570 game.intrInv[bb] = NULL;
571 }
572
573 if (game.charScripts != NULL)
574 {
575 delete game.charScripts;
576 delete game.invScripts;
577 game.charScripts = NULL;
578 game.invScripts = NULL;
579 }
580
581 if (game.dict != NULL) {
582 game.dict->free_memory();
583 free (game.dict);
584 game.dict = NULL;
585 }
586
587 if ((gameinst != NULL) && (gameinst->pc != 0))
588 quit("Error: unload_game called while script still running");
589 //->AbortAndDestroy (gameinst);
590 else {
591 delete gameinstFork;
592 delete gameinst;
593 gameinstFork = NULL;
594 gameinst = NULL;
595 }
596
597 gamescript.reset();
598
599 if ((dialogScriptsInst != NULL) && (dialogScriptsInst->pc != 0))
600 quit("Error: unload_game called while dialog script still running");
601 else if (dialogScriptsInst != NULL)
602 {
603 delete dialogScriptsInst;
604 dialogScriptsInst = NULL;
605 }
606
607 dialogScriptsScript.reset();
608
609 for (ee = 0; ee < numScriptModules; ee++) {
610 delete moduleInstFork[ee];
611 delete moduleInst[ee];
612 scriptModules[ee].reset();
613 }
614 moduleInstFork.resize(0);
615 moduleInst.resize(0);
616 scriptModules.resize(0);
617 repExecAlways.moduleHasFunction.resize(0);
618 lateRepExecAlways.moduleHasFunction.resize(0);
619 getDialogOptionsDimensionsFunc.moduleHasFunction.resize(0);
620 renderDialogOptionsFunc.moduleHasFunction.resize(0);
621 getDialogOptionUnderCursorFunc.moduleHasFunction.resize(0);
622 runDialogOptionMouseClickHandlerFunc.moduleHasFunction.resize(0);
623 runDialogOptionKeyPressHandlerFunc.moduleHasFunction.resize(0);
624 runDialogOptionRepExecFunc.moduleHasFunction.resize(0);
625 numScriptModules = 0;
626
627 if (game.audioClipCount > 0)
628 {
629 free(game.audioClips);
630 game.audioClipCount = 0;
631 free(game.audioClipTypes);
632 game.audioClipTypeCount = 0;
633 }
634
635 game.viewNames.clear();
636 free (views);
637 views = NULL;
638
639 free (game.chars);
640 game.chars = NULL;
641
642 free (charcache);
643 charcache = NULL;
644
645 if (splipsync != NULL)
646 {
647 for (ee = 0; ee < numLipLines; ee++)
648 {
649 free(splipsync[ee].endtimeoffs);
650 free(splipsync[ee].frame);
651 }
652 free(splipsync);
653 splipsync = NULL;
654 numLipLines = 0;
655 curLipLine = -1;
656 }
657
658 for (ee=0;ee < MAXGLOBALMES;ee++) {
659 if (game.messages[ee]==NULL) continue;
660 free (game.messages[ee]);
661 game.messages[ee] = NULL;
662 }
663
664 for (ee = 0; ee < game.roomCount; ee++)
665 {
666 free(game.roomNames[ee]);
667 }
668 if (game.roomCount > 0)
669 {
670 free(game.roomNames);
671 free(game.roomNumbers);
672 game.roomCount = 0;
673 }
674
675 for (ee=0;ee<game.numdialog;ee++) {
676 if (dialog[ee].optionscripts!=NULL)
677 free (dialog[ee].optionscripts);
678 dialog[ee].optionscripts = NULL;
679 }
680 free (dialog);
681 dialog = NULL;
682 delete [] scrDialog;
683 scrDialog = NULL;
684
685 for (ee = 0; ee < game.numgui; ee++) {
686 free (guibg[ee]);
687 guibg[ee] = NULL;
688 }
689
690 guiScriptObjNames.clear();
691 free(guibg);
692 guis.clear();
693 free(scrGui);
694
695 pl_stop_plugins();
696 ccRemoveAllSymbols();
697 ccUnregisterAllObjects();
698
699 for (ee=0;ee<game.numfonts;ee++)
700 wfreefont(ee);
701
702 free_do_once_tokens();
703 free(play.gui_draw_order);
704
705 resetRoomStatuses();
706
707 }
708
709
710
711
712
713
Game_GetGlobalStrings(int index)714 const char* Game_GetGlobalStrings(int index) {
715 if ((index < 0) || (index >= MAXGLOBALSTRINGS))
716 quit("!Game.GlobalStrings: invalid index");
717
718 return CreateNewScriptString(play.globalstrings[index]);
719 }
720
721
722
723 char gamefilenamebuf[200];
724
725
726 // ** GetGameParameter replacement functions
727
Game_GetInventoryItemCount()728 int Game_GetInventoryItemCount() {
729 // because of the dummy item 0, this is always one higher than it should be
730 return game.numinvitems - 1;
731 }
732
Game_GetFontCount()733 int Game_GetFontCount() {
734 return game.numfonts;
735 }
736
Game_GetMouseCursorCount()737 int Game_GetMouseCursorCount() {
738 return game.numcursors;
739 }
740
Game_GetCharacterCount()741 int Game_GetCharacterCount() {
742 return game.numcharacters;
743 }
744
Game_GetGUICount()745 int Game_GetGUICount() {
746 return game.numgui;
747 }
748
Game_GetViewCount()749 int Game_GetViewCount() {
750 return game.numviews;
751 }
752
Game_GetUseNativeCoordinates()753 int Game_GetUseNativeCoordinates()
754 {
755 if (game.options[OPT_NATIVECOORDINATES] != 0)
756 {
757 return 1;
758 }
759 return 0;
760 }
761
Game_GetSpriteWidth(int spriteNum)762 int Game_GetSpriteWidth(int spriteNum) {
763 if ((spriteNum < 0) || (spriteNum >= MAX_SPRITES))
764 return 0;
765
766 if (!spriteset.doesSpriteExist(spriteNum))
767 return 0;
768
769 return divide_down_coordinate(spritewidth[spriteNum]);
770 }
771
Game_GetSpriteHeight(int spriteNum)772 int Game_GetSpriteHeight(int spriteNum) {
773 if ((spriteNum < 0) || (spriteNum >= MAX_SPRITES))
774 return 0;
775
776 if (!spriteset.doesSpriteExist(spriteNum))
777 return 0;
778
779 return divide_down_coordinate(spriteheight[spriteNum]);
780 }
781
Game_GetLoopCountForView(int viewNumber)782 int Game_GetLoopCountForView(int viewNumber) {
783 if ((viewNumber < 1) || (viewNumber > game.numviews))
784 quit("!GetGameParameter: invalid view specified");
785
786 return views[viewNumber - 1].numLoops;
787 }
788
Game_GetRunNextSettingForLoop(int viewNumber,int loopNumber)789 int Game_GetRunNextSettingForLoop(int viewNumber, int loopNumber) {
790 if ((viewNumber < 1) || (viewNumber > game.numviews))
791 quit("!GetGameParameter: invalid view specified");
792 if ((loopNumber < 0) || (loopNumber >= views[viewNumber - 1].numLoops))
793 quit("!GetGameParameter: invalid loop specified");
794
795 return (views[viewNumber - 1].loops[loopNumber].RunNextLoop()) ? 1 : 0;
796 }
797
Game_GetFrameCountForLoop(int viewNumber,int loopNumber)798 int Game_GetFrameCountForLoop(int viewNumber, int loopNumber) {
799 if ((viewNumber < 1) || (viewNumber > game.numviews))
800 quit("!GetGameParameter: invalid view specified");
801 if ((loopNumber < 0) || (loopNumber >= views[viewNumber - 1].numLoops))
802 quit("!GetGameParameter: invalid loop specified");
803
804 return views[viewNumber - 1].loops[loopNumber].numFrames;
805 }
806
Game_GetViewFrame(int viewNumber,int loopNumber,int frame)807 ScriptViewFrame* Game_GetViewFrame(int viewNumber, int loopNumber, int frame) {
808 if ((viewNumber < 1) || (viewNumber > game.numviews))
809 quit("!GetGameParameter: invalid view specified");
810 if ((loopNumber < 0) || (loopNumber >= views[viewNumber - 1].numLoops))
811 quit("!GetGameParameter: invalid loop specified");
812 if ((frame < 0) || (frame >= views[viewNumber - 1].loops[loopNumber].numFrames))
813 quit("!GetGameParameter: invalid frame specified");
814
815 ScriptViewFrame *sdt = new ScriptViewFrame(viewNumber - 1, loopNumber, frame);
816 ccRegisterManagedObject(sdt, sdt);
817 return sdt;
818 }
819
Game_DoOnceOnly(const char * token)820 int Game_DoOnceOnly(const char *token)
821 {
822 if (strlen(token) > 199)
823 quit("!Game.DoOnceOnly: token length cannot be more than 200 chars");
824
825 for (int i = 0; i < play.num_do_once_tokens; i++)
826 {
827 if (strcmp(play.do_once_tokens[i], token) == 0)
828 {
829 return 0;
830 }
831 }
832 play.do_once_tokens = (char**)realloc(play.do_once_tokens, sizeof(char*) * (play.num_do_once_tokens + 1));
833 play.do_once_tokens[play.num_do_once_tokens] = (char*)malloc(strlen(token) + 1);
834 strcpy(play.do_once_tokens[play.num_do_once_tokens], token);
835 play.num_do_once_tokens++;
836 return 1;
837 }
838
Game_GetTextReadingSpeed()839 int Game_GetTextReadingSpeed()
840 {
841 return play.text_speed;
842 }
843
Game_SetTextReadingSpeed(int newTextSpeed)844 void Game_SetTextReadingSpeed(int newTextSpeed)
845 {
846 if (newTextSpeed < 1)
847 quitprintf("!Game.TextReadingSpeed: %d is an invalid speed", newTextSpeed);
848
849 play.text_speed = newTextSpeed;
850 }
851
Game_GetMinimumTextDisplayTimeMs()852 int Game_GetMinimumTextDisplayTimeMs()
853 {
854 return play.text_min_display_time_ms;
855 }
856
Game_SetMinimumTextDisplayTimeMs(int newTextMinTime)857 void Game_SetMinimumTextDisplayTimeMs(int newTextMinTime)
858 {
859 play.text_min_display_time_ms = newTextMinTime;
860 }
861
Game_GetIgnoreUserInputAfterTextTimeoutMs()862 int Game_GetIgnoreUserInputAfterTextTimeoutMs()
863 {
864 return play.ignore_user_input_after_text_timeout_ms;
865 }
866
Game_SetIgnoreUserInputAfterTextTimeoutMs(int newValueMs)867 void Game_SetIgnoreUserInputAfterTextTimeoutMs(int newValueMs)
868 {
869 play.ignore_user_input_after_text_timeout_ms = newValueMs;
870 }
871
Game_GetFileName()872 const char *Game_GetFileName() {
873 return CreateNewScriptString(usetup.main_data_filename);
874 }
875
Game_GetName()876 const char *Game_GetName() {
877 return CreateNewScriptString(play.game_name);
878 }
879
Game_SetName(const char * newName)880 void Game_SetName(const char *newName) {
881 strncpy(play.game_name, newName, 99);
882 play.game_name[99] = 0;
883
884 #if (ALLEGRO_DATE > 19990103)
885 set_window_title(play.game_name);
886 #endif
887 }
888
Game_GetSkippingCutscene()889 int Game_GetSkippingCutscene()
890 {
891 if (play.fast_forward)
892 {
893 return 1;
894 }
895 return 0;
896 }
897
Game_GetInSkippableCutscene()898 int Game_GetInSkippableCutscene()
899 {
900 if (play.in_cutscene)
901 {
902 return 1;
903 }
904 return 0;
905 }
906
Game_GetColorFromRGB(int red,int grn,int blu)907 int Game_GetColorFromRGB(int red, int grn, int blu) {
908 if ((red < 0) || (red > 255) || (grn < 0) || (grn > 255) ||
909 (blu < 0) || (blu > 255))
910 quit("!GetColorFromRGB: colour values must be 0-255");
911
912 if (game.color_depth == 1)
913 {
914 return makecol8(red, grn, blu);
915 }
916
917 int agscolor = ((blu >> 3) & 0x1f);
918 agscolor += ((grn >> 2) & 0x3f) << 5;
919 agscolor += ((red >> 3) & 0x1f) << 11;
920 return agscolor;
921 }
922
Game_InputBox(const char * msg)923 const char* Game_InputBox(const char *msg) {
924 char buffer[STD_BUFFER_SIZE];
925 sc_inputbox(msg, buffer);
926 return CreateNewScriptString(buffer);
927 }
928
Game_GetLocationName(int x,int y)929 const char* Game_GetLocationName(int x, int y) {
930 char buffer[STD_BUFFER_SIZE];
931 GetLocationName(x, y, buffer);
932 return CreateNewScriptString(buffer);
933 }
934
Game_GetGlobalMessages(int index)935 const char* Game_GetGlobalMessages(int index) {
936 if ((index < 500) || (index >= MAXGLOBALMES + 500)) {
937 return NULL;
938 }
939 char buffer[STD_BUFFER_SIZE];
940 buffer[0] = 0;
941 replace_tokens(get_translation(get_global_message(index)), buffer, STD_BUFFER_SIZE);
942 return CreateNewScriptString(buffer);
943 }
944
Game_GetSpeechFont()945 int Game_GetSpeechFont() {
946 return play.speech_font;
947 }
Game_GetNormalFont()948 int Game_GetNormalFont() {
949 return play.normal_font;
950 }
951
Game_GetTranslationFilename()952 const char* Game_GetTranslationFilename() {
953 char buffer[STD_BUFFER_SIZE];
954 GetTranslationName(buffer);
955 return CreateNewScriptString(buffer);
956 }
957
Game_ChangeTranslation(const char * newFilename)958 int Game_ChangeTranslation(const char *newFilename)
959 {
960 if ((newFilename == NULL) || (newFilename[0] == 0))
961 {
962 close_translation();
963 strcpy(transFileName, "");
964 return 1;
965 }
966
967 String oldTransFileName;
968 oldTransFileName = transFileName;
969
970 if (!init_translation(newFilename, oldTransFileName.LeftSection('.'), false))
971 {
972 strcpy(transFileName, oldTransFileName);
973 return 0;
974 }
975
976 return 1;
977 }
978
Game_GetAudioClip(int index)979 ScriptAudioClip *Game_GetAudioClip(int index)
980 {
981 if (index < 0 || index >= game.audioClipCount)
982 return NULL;
983 return &game.audioClips[index];
984 }
985
986 //=============================================================================
987
988 // save game functions
989
990
991
serialize_bitmap(const Common::Bitmap * thispic,Stream * out)992 void serialize_bitmap(const Common::Bitmap *thispic, Stream *out) {
993 if (thispic != NULL) {
994 out->WriteInt32(thispic->GetWidth());
995 out->WriteInt32(thispic->GetHeight());
996 out->WriteInt32(thispic->GetColorDepth());
997 for (int cc=0;cc<thispic->GetHeight();cc++)
998 {
999 switch (thispic->GetColorDepth())
1000 {
1001 case 8:
1002 // CHECKME: originally, AGS does not use real BPP here, but simply divides color depth by 8;
1003 // therefore 15-bit bitmaps are saved only partially? is this a bug? or?
1004 case 15:
1005 out->WriteArray(&thispic->GetScanLine(cc)[0], thispic->GetWidth(), 1);
1006 break;
1007 case 16:
1008 out->WriteArrayOfInt16((const int16_t*)&thispic->GetScanLine(cc)[0], thispic->GetWidth());
1009 break;
1010 case 32:
1011 out->WriteArrayOfInt32((const int32_t*)&thispic->GetScanLine(cc)[0], thispic->GetWidth());
1012 break;
1013 }
1014 }
1015 }
1016 }
1017
1018 // On Windows we could just use IIDFromString but this is platform-independant
convert_guid_from_text_to_binary(const char * guidText,unsigned char * buffer)1019 void convert_guid_from_text_to_binary(const char *guidText, unsigned char *buffer)
1020 {
1021 guidText++; // skip {
1022 for (int bytesDone = 0; bytesDone < 16; bytesDone++)
1023 {
1024 if (*guidText == '-')
1025 guidText++;
1026
1027 char tempString[3];
1028 tempString[0] = guidText[0];
1029 tempString[1] = guidText[1];
1030 tempString[2] = 0;
1031 int thisByte = 0;
1032 sscanf(tempString, "%X", &thisByte);
1033
1034 buffer[bytesDone] = thisByte;
1035 guidText += 2;
1036 }
1037
1038 // Swap bytes to give correct GUID order
1039 unsigned char temp;
1040 temp = buffer[0]; buffer[0] = buffer[3]; buffer[3] = temp;
1041 temp = buffer[1]; buffer[1] = buffer[2]; buffer[2] = temp;
1042 temp = buffer[4]; buffer[4] = buffer[5]; buffer[5] = temp;
1043 temp = buffer[6]; buffer[6] = buffer[7]; buffer[7] = temp;
1044 }
1045
read_serialized_bitmap(Stream * in)1046 Bitmap *read_serialized_bitmap(Stream *in) {
1047 Bitmap *thispic;
1048 int picwid = in->ReadInt32();
1049 int pichit = in->ReadInt32();
1050 int piccoldep = in->ReadInt32();
1051 thispic = BitmapHelper::CreateBitmap(picwid,pichit,piccoldep);
1052 if (thispic == NULL)
1053 return NULL;
1054 for (int vv=0; vv < pichit; vv++)
1055 {
1056 switch (piccoldep)
1057 {
1058 case 8:
1059 // CHECKME: originally, AGS does not use real BPP here, but simply divides color depth by 8
1060 case 15:
1061 in->ReadArray(thispic->GetScanLineForWriting(vv), picwid, 1);
1062 break;
1063 case 16:
1064 in->ReadArrayOfInt16((int16_t*)thispic->GetScanLineForWriting(vv), picwid);
1065 break;
1066 case 32:
1067 in->ReadArrayOfInt32((int32_t*)thispic->GetScanLineForWriting(vv), picwid);
1068 break;
1069 }
1070 }
1071
1072 return thispic;
1073 }
1074
skip_serialized_bitmap(Stream * in)1075 void skip_serialized_bitmap(Stream *in)
1076 {
1077 int picwid = in->ReadInt32();
1078 int pichit = in->ReadInt32();
1079 int piccoldep = in->ReadInt32();
1080 // CHECKME: originally, AGS does not use real BPP here, but simply divides color depth by 8
1081 int bpp = piccoldep / 8;
1082 in->Seek(picwid * pichit * bpp);
1083 }
1084
write_screen_shot_for_vista(Stream * out,Bitmap * screenshot)1085 long write_screen_shot_for_vista(Stream *out, Bitmap *screenshot)
1086 {
1087 long fileSize = 0;
1088 char tempFileName[MAX_PATH];
1089 sprintf(tempFileName, "%s""_tmpscht.bmp", saveGameDirectory);
1090
1091 screenshot->SaveToFile(tempFileName, palette);
1092
1093 update_polled_stuff_if_runtime();
1094
1095 if (exists(tempFileName))
1096 {
1097 fileSize = file_size_ex(tempFileName);
1098 char *buffer = (char*)malloc(fileSize);
1099
1100 Stream *temp_in = Common::File::OpenFileRead(tempFileName);
1101 temp_in->Read(buffer, fileSize);
1102 delete temp_in;
1103 unlink(tempFileName);
1104
1105 out->Write(buffer, fileSize);
1106 free(buffer);
1107 }
1108 return fileSize;
1109 }
1110
save_game_head_dynamic_values(Stream * out)1111 void save_game_head_dynamic_values(Stream *out)
1112 {
1113 out->WriteInt32(frames_per_second);
1114 out->WriteInt32(cur_mode);
1115 out->WriteInt32(cur_cursor);
1116 out->WriteInt32(offsetx); out->WriteInt32(offsety);
1117 out->WriteInt32(loopcounter);
1118 }
1119
save_game_spriteset(Stream * out)1120 void save_game_spriteset(Stream *out)
1121 {
1122 out->WriteInt32(spriteset.elements);
1123 for (int bb = 1; bb < spriteset.elements; bb++) {
1124 if (game.spriteflags[bb] & SPF_DYNAMICALLOC) {
1125 out->WriteInt32(bb);
1126 out->WriteInt8(game.spriteflags[bb]);
1127 serialize_bitmap(spriteset[bb], out);
1128 }
1129 }
1130 // end of dynamic sprite list
1131 out->WriteInt32(0);
1132 }
1133
save_game_scripts(Stream * out)1134 void save_game_scripts(Stream *out)
1135 {
1136 // write the data segment of the global script
1137 int gdatasize=gameinst->globaldatasize;
1138 out->WriteInt32(gdatasize);
1139 // MACPORT FIX: just in case gdatasize is 2 or 4, don't want to swap endian
1140 out->Write(&gameinst->globaldata[0], gdatasize);
1141 // write the script modules data segments
1142 out->WriteInt32(numScriptModules);
1143 for (int bb = 0; bb < numScriptModules; bb++) {
1144 int glsize = moduleInst[bb]->globaldatasize;
1145 out->WriteInt32(glsize);
1146 if (glsize > 0) {
1147 out->Write(&moduleInst[bb]->globaldata[0], glsize);
1148 }
1149 }
1150 }
1151
WriteRoomStatus_Aligned(RoomStatus * roomstat,Stream * out)1152 void WriteRoomStatus_Aligned(RoomStatus *roomstat, Stream *out)
1153 {
1154 AlignedStream align_s(out, Common::kAligned_Write);
1155 roomstat->WriteToFile_v321(&align_s);
1156 }
1157
save_game_room_state(Stream * out)1158 void save_game_room_state(Stream *out)
1159 {
1160 out->WriteInt32(displayed_room);
1161
1162 // write the room state for all the rooms the player has been in
1163 RoomStatus* roomstat;
1164 for (int bb = 0; bb < MAX_ROOMS; bb++) {
1165 if (isRoomStatusValid(bb))
1166 {
1167 roomstat = getRoomStatus(bb);
1168 if (roomstat->beenhere) {
1169 out->WriteInt8 (1);
1170 WriteRoomStatus_Aligned(roomstat, out);
1171 if (roomstat->tsdatasize>0)
1172 out->Write(&roomstat->tsdata[0], roomstat->tsdatasize);
1173 }
1174 else
1175 out->WriteInt8(0);
1176 }
1177 else
1178 out->WriteInt8(0);
1179 }
1180 }
1181
save_game_play_ex_data(Stream * out)1182 void save_game_play_ex_data(Stream *out)
1183 {
1184 for (int bb = 0; bb < play.num_do_once_tokens; bb++)
1185 {
1186 fputstring(play.do_once_tokens[bb], out);
1187 }
1188 out->WriteArrayOfInt32(&play.gui_draw_order[0], game.numgui);
1189 }
1190
WriteMoveList_Aligned(Stream * out)1191 void WriteMoveList_Aligned(Stream *out)
1192 {
1193 AlignedStream align_s(out, Common::kAligned_Write);
1194 for (int i = 0; i < game.numcharacters + MAX_INIT_SPR + 1; ++i)
1195 {
1196 mls[i].WriteToFile(&align_s);
1197 align_s.Reset();
1198 }
1199 }
1200
WriteGameSetupStructBase_Aligned(Stream * out)1201 void WriteGameSetupStructBase_Aligned(Stream *out)
1202 {
1203 AlignedStream align_s(out, Common::kAligned_Write);
1204 game.GameSetupStructBase::WriteToFile(&align_s);
1205 }
1206
WriteCharacterExtras_Aligned(Stream * out)1207 void WriteCharacterExtras_Aligned(Stream *out)
1208 {
1209 AlignedStream align_s(out, Common::kAligned_Write);
1210 for (int i = 0; i < game.numcharacters; ++i)
1211 {
1212 charextra[i].WriteToFile(&align_s);
1213 align_s.Reset();
1214 }
1215 }
1216
save_game_palette(Stream * out)1217 void save_game_palette(Stream *out)
1218 {
1219 out->WriteArray(&palette[0],sizeof(color),256);
1220 }
1221
save_game_dialogs(Stream * out)1222 void save_game_dialogs(Stream *out)
1223 {
1224 for (int bb=0;bb<game.numdialog;bb++)
1225 out->WriteArrayOfInt32(&dialog[bb].optionflags[0],MAXTOPICOPTIONS);
1226 }
1227
1228 // [IKM] yea, okay this is just plain silly name :)
save_game_more_dynamic_values(Stream * out)1229 void save_game_more_dynamic_values(Stream *out)
1230 {
1231 out->WriteInt32(mouse_on_iface);
1232 out->WriteInt32(mouse_on_iface_button);
1233 out->WriteInt32(mouse_pushed_iface);
1234 out->WriteInt32 (ifacepopped);
1235 out->WriteInt32(game_paused);
1236 //out->WriteInt32(mi.trk);
1237 }
1238
WriteAnimatedButtons_Aligned(Stream * out)1239 void WriteAnimatedButtons_Aligned(Stream *out)
1240 {
1241 AlignedStream align_s(out, Common::kAligned_Write);
1242 for (int i = 0; i < numAnimButs; ++i)
1243 {
1244 animbuts[i].WriteToFile(&align_s);
1245 align_s.Reset();
1246 }
1247 }
1248
save_game_gui(Stream * out)1249 void save_game_gui(Stream *out)
1250 {
1251 write_gui(out,guis,&game,true);
1252 out->WriteInt32(numAnimButs);
1253 WriteAnimatedButtons_Aligned(out);
1254 }
1255
save_game_audiocliptypes(Stream * out)1256 void save_game_audiocliptypes(Stream *out)
1257 {
1258 out->WriteInt32(game.audioClipTypeCount);
1259 for (int i = 0; i < game.audioClipTypeCount; ++i)
1260 {
1261 game.audioClipTypes[i].WriteToFile(out);
1262 }
1263 }
1264
save_game_thisroom(Stream * out)1265 void save_game_thisroom(Stream *out)
1266 {
1267 out->WriteArrayOfInt16(&thisroom.regionLightLevel[0],MAX_REGIONS);
1268 out->WriteArrayOfInt32(&thisroom.regionTintLevel[0],MAX_REGIONS);
1269 out->WriteArrayOfInt16(&thisroom.walk_area_zoom[0],MAX_WALK_AREAS + 1);
1270 out->WriteArrayOfInt16(&thisroom.walk_area_zoom2[0],MAX_WALK_AREAS + 1);
1271 }
1272
save_game_ambientsounds(Stream * out)1273 void save_game_ambientsounds(Stream *out)
1274 {
1275 for (int i = 0; i < MAX_SOUND_CHANNELS; ++i)
1276 {
1277 ambient[i].WriteToFile(out);
1278 }
1279 //out->WriteArray (&ambient[0], sizeof(AmbientSound), MAX_SOUND_CHANNELS);
1280 }
1281
WriteOverlays_Aligned(Stream * out)1282 void WriteOverlays_Aligned(Stream *out)
1283 {
1284 AlignedStream align_s(out, Common::kAligned_Write);
1285 for (int i = 0; i < numscreenover; ++i)
1286 {
1287 screenover[i].WriteToFile(&align_s);
1288 align_s.Reset();
1289 }
1290 }
1291
save_game_overlays(Stream * out)1292 void save_game_overlays(Stream *out)
1293 {
1294 out->WriteInt32(numscreenover);
1295 WriteOverlays_Aligned(out);
1296 for (int bb=0;bb<numscreenover;bb++) {
1297 serialize_bitmap (screenover[bb].pic, out);
1298 }
1299 }
1300
save_game_dynamic_surfaces(Stream * out)1301 void save_game_dynamic_surfaces(Stream *out)
1302 {
1303 for (int bb = 0; bb < MAX_DYNAMIC_SURFACES; bb++)
1304 {
1305 if (dynamicallyCreatedSurfaces[bb] == NULL)
1306 {
1307 out->WriteInt8(0);
1308 }
1309 else
1310 {
1311 out->WriteInt8(1);
1312 serialize_bitmap(dynamicallyCreatedSurfaces[bb], out);
1313 }
1314 }
1315 }
1316
save_game_displayed_room_status(Stream * out)1317 void save_game_displayed_room_status(Stream *out)
1318 {
1319 if (displayed_room >= 0) {
1320
1321 for (int bb = 0; bb < MAX_BSCENE; bb++) {
1322 if (play.raw_modified[bb])
1323 serialize_bitmap (thisroom.ebscene[bb], out);
1324 }
1325
1326 out->WriteInt32 ((raw_saved_screen == NULL) ? 0 : 1);
1327 if (raw_saved_screen)
1328 serialize_bitmap (raw_saved_screen, out);
1329
1330 // save the current troom, in case they save in room 600 or whatever
1331 WriteRoomStatus_Aligned(&troom, out);
1332 if (troom.tsdatasize>0)
1333 out->Write(&troom.tsdata[0],troom.tsdatasize);
1334
1335 }
1336 }
1337
save_game_globalvars(Stream * out)1338 void save_game_globalvars(Stream *out)
1339 {
1340 out->WriteInt32 (numGlobalVars);
1341 for (int i = 0; i < numGlobalVars; ++i)
1342 {
1343 globalvars[i].Write(out);
1344 }
1345 }
1346
save_game_views(Stream * out)1347 void save_game_views(Stream *out)
1348 {
1349 out->WriteInt32 (game.numviews);
1350 for (int bb = 0; bb < game.numviews; bb++) {
1351 for (int cc = 0; cc < views[bb].numLoops; cc++) {
1352 for (int dd = 0; dd < views[bb].loops[cc].numFrames; dd++)
1353 {
1354 out->WriteInt32(views[bb].loops[cc].frames[dd].sound);
1355 out->WriteInt32(views[bb].loops[cc].frames[dd].pic);
1356 }
1357 }
1358 }
1359 }
1360
save_game_audioclips_and_crossfade(Stream * out)1361 void save_game_audioclips_and_crossfade(Stream *out)
1362 {
1363 out->WriteInt32(game.audioClipCount);
1364 for (int bb = 0; bb <= MAX_SOUND_CHANNELS; bb++)
1365 {
1366 if ((channels[bb] != NULL) && (channels[bb]->done == 0) && (channels[bb]->sourceClip != NULL))
1367 {
1368 out->WriteInt32(((ScriptAudioClip*)channels[bb]->sourceClip)->id);
1369 out->WriteInt32(channels[bb]->get_pos());
1370 out->WriteInt32(channels[bb]->priority);
1371 out->WriteInt32(channels[bb]->repeat ? 1 : 0);
1372 out->WriteInt32(channels[bb]->vol);
1373 out->WriteInt32(channels[bb]->panning);
1374 out->WriteInt32(channels[bb]->volAsPercentage);
1375 out->WriteInt32(channels[bb]->panningAsPercentage);
1376 if (loaded_game_file_version >= kGameVersion_340_2)
1377 out->WriteInt32(channels[bb]->speed);
1378 }
1379 else
1380 {
1381 out->WriteInt32(-1);
1382 }
1383 }
1384 out->WriteInt32(crossFading);
1385 out->WriteInt32(crossFadeVolumePerStep);
1386 out->WriteInt32(crossFadeStep);
1387 out->WriteInt32(crossFadeVolumeAtStart);
1388 }
1389
WriteGameState_Aligned(Stream * out)1390 void WriteGameState_Aligned(Stream *out)
1391 {
1392 AlignedStream align_s(out, Common::kAligned_Write);
1393 play.WriteToFile_v321(&align_s);
1394 }
1395
1396 #define MAGICNUMBER 0xbeefcafe
1397 // Write the save game position to the file
save_game_data(Stream * out)1398 void save_game_data(Stream *out)
1399 {
1400 save_game_head_dynamic_values(out);
1401 save_game_spriteset(out);
1402 save_game_scripts(out);
1403 save_game_room_state(out);
1404
1405 update_polled_stuff_if_runtime();
1406
1407 //----------------------------------------------------------------
1408 WriteGameState_Aligned(out);
1409
1410 save_game_play_ex_data(out);
1411 //----------------------------------------------------------------
1412
1413 WriteMoveList_Aligned(out);
1414
1415 WriteGameSetupStructBase_Aligned(out);
1416
1417 //----------------------------------------------------------------
1418 game.WriteForSaveGame_v321(out);
1419
1420 // Modified custom properties are written separately to keep existing save format
1421 play.WriteCustomProperties(out);
1422
1423 WriteCharacterExtras_Aligned(out);
1424 save_game_palette(out);
1425 save_game_dialogs(out);
1426 save_game_more_dynamic_values(out);
1427 save_game_gui(out);
1428 save_game_audiocliptypes(out);
1429 save_game_thisroom(out);
1430 save_game_ambientsounds(out);
1431 save_game_overlays(out);
1432
1433 update_polled_stuff_if_runtime();
1434
1435 save_game_dynamic_surfaces(out);
1436
1437 update_polled_stuff_if_runtime();
1438
1439 save_game_displayed_room_status(out);
1440 save_game_globalvars(out);
1441 save_game_views(out);
1442
1443 out->WriteInt32 (MAGICNUMBER+1);
1444
1445 save_game_audioclips_and_crossfade(out);
1446
1447 // [IKM] Plugins expect FILE pointer! // TODO something with this later...
1448 int pluginFileHandle = AGSE_SAVEGAME;
1449 pl_set_file_handle(pluginFileHandle, out);
1450 pl_run_plugin_hooks(AGSE_SAVEGAME, pluginFileHandle);
1451 pl_clear_file_handle();
1452 out->WriteInt32 (MAGICNUMBER); // to verify the plugins
1453
1454 // save the room music volume
1455 out->WriteInt32(thisroom.options[ST_VOLUME]);
1456
1457 ccSerializeAllObjects(out);
1458
1459 out->WriteInt32(current_music_type);
1460
1461 update_polled_stuff_if_runtime();
1462 }
1463
create_savegame_screenshot(Bitmap * & screenShot)1464 void create_savegame_screenshot(Bitmap *&screenShot)
1465 {
1466 if (game.options[OPT_SAVESCREENSHOT]) {
1467 int usewid = multiply_up_coordinate(play.screenshot_width);
1468 int usehit = multiply_up_coordinate(play.screenshot_height);
1469 const Rect &viewport = play.viewport;
1470 if (usewid > viewport.GetWidth())
1471 usewid = viewport.GetWidth();
1472 if (usehit > viewport.GetHeight())
1473 usehit = viewport.GetHeight();
1474
1475 if ((play.screenshot_width < 16) || (play.screenshot_height < 16))
1476 quit("!Invalid game.screenshot_width/height, must be from 16x16 to screen res");
1477
1478 screenShot = CopyScreenIntoBitmap(usewid, usehit);
1479 }
1480 }
1481
save_game(int slotn,const char * descript)1482 void save_game(int slotn, const char*descript) {
1483
1484 // dont allow save in rep_exec_always, because we dont save
1485 // the state of blocked scripts
1486 can_run_delayed_command();
1487
1488 if (inside_script) {
1489 strcpy(curscript->postScriptSaveSlotDescription[curscript->queue_action(ePSASaveGame, slotn, "SaveGameSlot")], descript);
1490 return;
1491 }
1492
1493 if (platform->GetDiskFreeSpaceMB() < 2) {
1494 Display("ERROR: There is not enough disk space free to save the game. Clear some disk space and try again.");
1495 return;
1496 }
1497
1498 VALIDATE_STRING(descript);
1499 String nametouse;
1500 nametouse = get_save_game_path(slotn);
1501
1502 Bitmap *screenShot = NULL;
1503
1504 // Screenshot
1505 create_savegame_screenshot(screenShot);
1506
1507 Stream *out = StartSavegame(nametouse, descript, screenShot);
1508 if (out == NULL)
1509 quit("save_game: unable to open savegame file for writing");
1510
1511 update_polled_stuff_if_runtime();
1512
1513 // Actual dynamic game data is saved here
1514 SaveGameState(out);
1515
1516 if (screenShot != NULL)
1517 {
1518 int screenShotOffset = out->GetPosition() - sizeof(RICH_GAME_MEDIA_HEADER);
1519 int screenShotSize = write_screen_shot_for_vista(out, screenShot);
1520 delete out;
1521
1522 update_polled_stuff_if_runtime();
1523
1524 out = Common::File::OpenFile(nametouse, Common::kFile_Open, Common::kFile_ReadWrite);
1525 out->Seek(12, kSeekBegin);
1526 out->WriteInt32(screenShotOffset);
1527 out->Seek(4);
1528 out->WriteInt32(screenShotSize);
1529 }
1530
1531 if (screenShot != NULL)
1532 delete screenShot;
1533
1534 delete out;
1535 }
1536
1537 char rbuffer[200];
1538
restore_game_head_dynamic_values(Stream * in,RestoredData & r_data)1539 SavegameError restore_game_head_dynamic_values(Stream *in, RestoredData &r_data)
1540 {
1541 r_data.FPS = in->ReadInt32();
1542 r_data.CursorMode = in->ReadInt32();
1543 r_data.CursorID = in->ReadInt32();
1544 offsetx = in->ReadInt32();
1545 offsety = in->ReadInt32();
1546 loopcounter = in->ReadInt32();
1547
1548 return kSvgErr_NoError;
1549 }
1550
restore_game_spriteset(Stream * in)1551 void restore_game_spriteset(Stream *in)
1552 {
1553 // ensure the sprite set is at least as large as it was
1554 // when the game was saved
1555 spriteset.enlargeTo(in->ReadInt32());
1556 // get serialized dynamic sprites
1557 int sprnum = in->ReadInt32();
1558 while (sprnum) {
1559 unsigned char spriteflag = in->ReadByte();
1560 add_dynamic_sprite(sprnum, read_serialized_bitmap(in));
1561 game.spriteflags[sprnum] = spriteflag;
1562 sprnum = in->ReadInt32();
1563 }
1564 }
1565
restore_game_scripts(Stream * in,const PreservedParams & pp,RestoredData & r_data)1566 SavegameError restore_game_scripts(Stream *in, const PreservedParams &pp, RestoredData &r_data)
1567 {
1568 // read the global script data segment
1569 int gdatasize = in->ReadInt32();
1570 if (pp.GlScDataSize != gdatasize)
1571 {
1572 Debug::Printf(kDbgMsg_Error, "Restore game error: mismatching size of global script data");
1573 return kSvgErr_GameContentAssertion;
1574 }
1575 r_data.GlobalScript.Len = gdatasize;
1576 r_data.GlobalScript.Data.reset(new char[gdatasize]);
1577 in->Read(r_data.GlobalScript.Data.get(), gdatasize);
1578
1579 if (in->ReadInt32() != numScriptModules)
1580 {
1581 Debug::Printf(kDbgMsg_Error, "Restore game error: mismatching number of script modules");
1582 return kSvgErr_GameContentAssertion;
1583 }
1584 r_data.ScriptModules.resize(numScriptModules);
1585 for (int i = 0; i < numScriptModules; ++i)
1586 {
1587 size_t module_size = in->ReadInt32();
1588 if (pp.ScMdDataSize[i] != module_size)
1589 {
1590 Debug::Printf(kDbgMsg_Error, "Restore game error: mismatching size of script module data, module %d", i);
1591 return kSvgErr_GameContentAssertion;
1592 }
1593 r_data.ScriptModules[i].Len = module_size;
1594 r_data.ScriptModules[i].Data.reset(new char[module_size]);
1595 in->Read(r_data.ScriptModules[i].Data.get(), module_size);
1596 }
1597 return kSvgErr_NoError;
1598 }
1599
ReadRoomStatus_Aligned(RoomStatus * roomstat,Stream * in)1600 void ReadRoomStatus_Aligned(RoomStatus *roomstat, Stream *in)
1601 {
1602 AlignedStream align_s(in, Common::kAligned_Read);
1603 roomstat->ReadFromFile_v321(&align_s);
1604 }
1605
restore_game_room_state(Stream * in)1606 void restore_game_room_state(Stream *in)
1607 {
1608 int vv;
1609
1610 displayed_room = in->ReadInt32();
1611
1612 // read the room state for all the rooms the player has been in
1613 RoomStatus* roomstat;
1614 int beenhere;
1615 for (vv=0;vv<MAX_ROOMS;vv++)
1616 {
1617 beenhere = in->ReadByte();
1618 if (beenhere)
1619 {
1620 roomstat = getRoomStatus(vv);
1621 roomstat->beenhere = beenhere;
1622
1623 if (roomstat->beenhere)
1624 {
1625 ReadRoomStatus_Aligned(roomstat, in);
1626 if (roomstat->tsdatasize > 0)
1627 {
1628 roomstat->tsdata=(char*)malloc(roomstat->tsdatasize + 8); // JJS: Why allocate 8 additional bytes?
1629 in->Read(&roomstat->tsdata[0], roomstat->tsdatasize);
1630 }
1631 }
1632 }
1633 }
1634 }
1635
ReadGameState_Aligned(Stream * in)1636 void ReadGameState_Aligned(Stream *in)
1637 {
1638 AlignedStream align_s(in, Common::kAligned_Read);
1639 play.ReadFromFile_v321(&align_s);
1640 }
1641
restore_game_play_ex_data(Stream * in)1642 void restore_game_play_ex_data(Stream *in)
1643 {
1644 if (play.num_do_once_tokens > 0)
1645 {
1646 play.do_once_tokens = (char**)malloc(sizeof(char*) * play.num_do_once_tokens);
1647 for (int bb = 0; bb < play.num_do_once_tokens; bb++)
1648 {
1649 fgetstring_limit(rbuffer, in, 200);
1650 play.do_once_tokens[bb] = (char*)malloc(strlen(rbuffer) + 1);
1651 strcpy(play.do_once_tokens[bb], rbuffer);
1652 }
1653 }
1654
1655 in->ReadArrayOfInt32(&play.gui_draw_order[0], game.numgui);
1656 }
1657
restore_game_play(Stream * in)1658 void restore_game_play(Stream *in)
1659 {
1660 // preserve the replay settings
1661 int playback_was = play.playback, recording_was = play.recording;
1662 int gamestep_was = play.gamestep;
1663 int screenfadedout_was = play.screen_is_faded_out;
1664 int roomchanges_was = play.room_changes;
1665 // make sure the pointer is preserved
1666 int *gui_draw_order_was = play.gui_draw_order;
1667
1668 ReadGameState_Aligned(in);
1669
1670 play.screen_is_faded_out = screenfadedout_was;
1671 play.playback = playback_was;
1672 play.recording = recording_was;
1673 play.gamestep = gamestep_was;
1674 play.room_changes = roomchanges_was;
1675 play.gui_draw_order = gui_draw_order_was;
1676
1677 restore_game_play_ex_data(in);
1678 }
1679
ReadMoveList_Aligned(Stream * in)1680 void ReadMoveList_Aligned(Stream *in)
1681 {
1682 AlignedStream align_s(in, Common::kAligned_Read);
1683 for (int i = 0; i < game.numcharacters + MAX_INIT_SPR + 1; ++i)
1684 {
1685 mls[i].ReadFromFile(&align_s);
1686 align_s.Reset();
1687 }
1688 }
1689
ReadGameSetupStructBase_Aligned(Stream * in)1690 void ReadGameSetupStructBase_Aligned(Stream *in)
1691 {
1692 AlignedStream align_s(in, Common::kAligned_Read);
1693 game.GameSetupStructBase::ReadFromFile(&align_s);
1694 }
1695
ReadCharacterExtras_Aligned(Stream * in)1696 void ReadCharacterExtras_Aligned(Stream *in)
1697 {
1698 AlignedStream align_s(in, Common::kAligned_Read);
1699 for (int i = 0; i < game.numcharacters; ++i)
1700 {
1701 charextra[i].ReadFromFile(&align_s);
1702 align_s.Reset();
1703 }
1704 }
1705
restore_game_palette(Stream * in)1706 void restore_game_palette(Stream *in)
1707 {
1708 in->ReadArray(&palette[0],sizeof(color),256);
1709 }
1710
restore_game_dialogs(Stream * in)1711 void restore_game_dialogs(Stream *in)
1712 {
1713 for (int vv=0;vv<game.numdialog;vv++)
1714 in->ReadArrayOfInt32(&dialog[vv].optionflags[0],MAXTOPICOPTIONS);
1715 }
1716
restore_game_more_dynamic_values(Stream * in)1717 void restore_game_more_dynamic_values(Stream *in)
1718 {
1719 mouse_on_iface=in->ReadInt32();
1720 mouse_on_iface_button=in->ReadInt32();
1721 mouse_pushed_iface=in->ReadInt32();
1722 ifacepopped = in->ReadInt32();
1723 game_paused=in->ReadInt32();
1724 }
1725
ReadAnimatedButtons_Aligned(Stream * in)1726 void ReadAnimatedButtons_Aligned(Stream *in)
1727 {
1728 AlignedStream align_s(in, Common::kAligned_Read);
1729 for (int i = 0; i < numAnimButs; ++i)
1730 {
1731 animbuts[i].ReadFromFile(&align_s);
1732 align_s.Reset();
1733 }
1734 }
1735
restore_game_gui(Stream * in,int numGuisWas)1736 SavegameError restore_game_gui(Stream *in, int numGuisWas)
1737 {
1738 read_gui(in,guis,&game);
1739
1740 if (numGuisWas != game.numgui)
1741 {
1742 Debug::Printf(kDbgMsg_Error, "Restore game error: mismatching number of GUI");
1743 return kSvgErr_GameContentAssertion;
1744 }
1745
1746 numAnimButs = in->ReadInt32();
1747 ReadAnimatedButtons_Aligned(in);
1748 return kSvgErr_NoError;
1749 }
1750
restore_game_audiocliptypes(Stream * in)1751 SavegameError restore_game_audiocliptypes(Stream *in)
1752 {
1753 if (in->ReadInt32() != game.audioClipTypeCount)
1754 {
1755 Debug::Printf(kDbgMsg_Error, "Restore game error: mismatching number of Audio Clip Types");
1756 return kSvgErr_GameContentAssertion;
1757 }
1758
1759 for (int i = 0; i < game.audioClipTypeCount; ++i)
1760 {
1761 game.audioClipTypes[i].ReadFromFile(in);
1762 }
1763 return kSvgErr_NoError;
1764 }
1765
restore_game_thisroom(Stream * in,RestoredData & r_data)1766 void restore_game_thisroom(Stream *in, RestoredData &r_data)
1767 {
1768 in->ReadArrayOfInt16(r_data.RoomLightLevels, MAX_REGIONS);
1769 in->ReadArrayOfInt32(r_data.RoomTintLevels, MAX_REGIONS);
1770 in->ReadArrayOfInt16(r_data.RoomZoomLevels1, MAX_WALK_AREAS + 1);
1771 in->ReadArrayOfInt16(r_data.RoomZoomLevels2, MAX_WALK_AREAS + 1);
1772 }
1773
restore_game_ambientsounds(Stream * in,RestoredData & r_data)1774 void restore_game_ambientsounds(Stream *in, RestoredData &r_data)
1775 {
1776 int bb;
1777
1778 for (int i = 0; i < MAX_SOUND_CHANNELS; ++i)
1779 {
1780 ambient[i].ReadFromFile(in);
1781 }
1782
1783 for (bb = 1; bb < MAX_SOUND_CHANNELS; bb++) {
1784 if (ambient[bb].channel == 0)
1785 r_data.DoAmbient[bb] = 0;
1786 else {
1787 r_data.DoAmbient[bb] = ambient[bb].num;
1788 ambient[bb].channel = 0;
1789 }
1790 }
1791 }
1792
ReadOverlays_Aligned(Stream * in)1793 void ReadOverlays_Aligned(Stream *in)
1794 {
1795 AlignedStream align_s(in, Common::kAligned_Read);
1796 for (int i = 0; i < numscreenover; ++i)
1797 {
1798 screenover[i].ReadFromFile(&align_s);
1799 align_s.Reset();
1800 }
1801 }
1802
restore_game_overlays(Stream * in)1803 void restore_game_overlays(Stream *in)
1804 {
1805 numscreenover = in->ReadInt32();
1806 ReadOverlays_Aligned(in);
1807 for (int bb=0;bb<numscreenover;bb++) {
1808 if (screenover[bb].hasSerializedBitmap)
1809 screenover[bb].pic = read_serialized_bitmap(in);
1810 }
1811 }
1812
restore_game_dynamic_surfaces(Stream * in,RestoredData & r_data)1813 void restore_game_dynamic_surfaces(Stream *in, RestoredData &r_data)
1814 {
1815 // load into a temp array since ccUnserialiseObjects will destroy
1816 // it otherwise
1817 r_data.DynamicSurfaces.resize(MAX_DYNAMIC_SURFACES);
1818 for (int i = 0; i < MAX_DYNAMIC_SURFACES; ++i)
1819 {
1820 if (in->ReadInt8() == 0)
1821 {
1822 r_data.DynamicSurfaces[i] = NULL;
1823 }
1824 else
1825 {
1826 r_data.DynamicSurfaces[i] = read_serialized_bitmap(in);
1827 }
1828 }
1829 }
1830
restore_game_displayed_room_status(Stream * in,RestoredData & r_data)1831 void restore_game_displayed_room_status(Stream *in, RestoredData &r_data)
1832 {
1833 int bb;
1834 for (bb = 0; bb < MAX_BSCENE; bb++)
1835 r_data.RoomBkgScene[bb] = NULL;
1836
1837 if (displayed_room >= 0) {
1838
1839 for (bb = 0; bb < MAX_BSCENE; bb++) {
1840 r_data.RoomBkgScene[bb] = NULL;
1841 if (play.raw_modified[bb]) {
1842 r_data.RoomBkgScene[bb] = read_serialized_bitmap (in);
1843 }
1844 }
1845 bb = in->ReadInt32();
1846
1847 if (bb)
1848 raw_saved_screen = read_serialized_bitmap(in);
1849
1850 // get the current troom, in case they save in room 600 or whatever
1851 ReadRoomStatus_Aligned(&troom, in);
1852
1853 if (troom.tsdatasize > 0) {
1854 troom.tsdata=(char*)malloc(troom.tsdatasize+5);
1855 in->Read(&troom.tsdata[0],troom.tsdatasize);
1856 }
1857 else
1858 troom.tsdata = NULL;
1859 }
1860 }
1861
restore_game_globalvars(Stream * in)1862 SavegameError restore_game_globalvars(Stream *in)
1863 {
1864 if (in->ReadInt32() != numGlobalVars)
1865 {
1866 Debug::Printf(kDbgMsg_Error, "Restore game error: mismatching number of Global Variables");
1867 return kSvgErr_GameContentAssertion;
1868 }
1869
1870 for (int i = 0; i < numGlobalVars; ++i)
1871 {
1872 globalvars[i].Read(in);
1873 }
1874 return kSvgErr_NoError;
1875 }
1876
restore_game_views(Stream * in)1877 SavegameError restore_game_views(Stream *in)
1878 {
1879 if (in->ReadInt32() != game.numviews)
1880 {
1881 Debug::Printf(kDbgMsg_Error, "Restore game error: mismatching number of Views");
1882 return kSvgErr_GameContentAssertion;
1883 }
1884
1885 for (int bb = 0; bb < game.numviews; bb++) {
1886 for (int cc = 0; cc < views[bb].numLoops; cc++) {
1887 for (int dd = 0; dd < views[bb].loops[cc].numFrames; dd++)
1888 {
1889 views[bb].loops[cc].frames[dd].sound = in->ReadInt32();
1890 views[bb].loops[cc].frames[dd].pic = in->ReadInt32();
1891 }
1892 }
1893 }
1894 return kSvgErr_NoError;
1895 }
1896
restore_game_audioclips_and_crossfade(Stream * in,RestoredData & r_data)1897 SavegameError restore_game_audioclips_and_crossfade(Stream *in, RestoredData &r_data)
1898 {
1899 if (in->ReadInt32() != game.audioClipCount)
1900 {
1901 Debug::Printf(kDbgMsg_Error, "Restore game error: mismatching number of Audio Clips");
1902 return kSvgErr_GameContentAssertion;
1903 }
1904
1905 for (int i = 0; i <= MAX_SOUND_CHANNELS; ++i)
1906 {
1907 RestoredData::ChannelInfo &chan_info = r_data.AudioChans[i];
1908 chan_info.Pos = 0;
1909 chan_info.ClipID = in->ReadInt32();
1910 if (chan_info.ClipID >= 0)
1911 {
1912 if (chan_info.ClipID >= game.audioClipCount)
1913 {
1914 Debug::Printf(kDbgMsg_Error, "Restore game error: invalid audio clip index");
1915 return kSvgErr_GameObjectInitFailed;
1916 }
1917
1918 chan_info.Pos = in->ReadInt32();
1919 if (chan_info.Pos < 0)
1920 chan_info.Pos = 0;
1921 chan_info.Priority = in->ReadInt32();
1922 chan_info.Repeat = in->ReadInt32();
1923 chan_info.Vol = in->ReadInt32();
1924 chan_info.Pan = in->ReadInt32();
1925 chan_info.VolAsPercent = in->ReadInt32();
1926 chan_info.PanAsPercent = in->ReadInt32();
1927 chan_info.Speed = 1000;
1928 if (loaded_game_file_version >= kGameVersion_340_2)
1929 chan_info.Speed = in->ReadInt32();
1930 }
1931 }
1932 crossFading = in->ReadInt32();
1933 crossFadeVolumePerStep = in->ReadInt32();
1934 crossFadeStep = in->ReadInt32();
1935 crossFadeVolumeAtStart = in->ReadInt32();
1936 return kSvgErr_NoError;
1937 }
1938
restore_game_data(Stream * in,SavegameVersion svg_version,const PreservedParams & pp,RestoredData & r_data)1939 SavegameError restore_game_data(Stream *in, SavegameVersion svg_version, const PreservedParams &pp, RestoredData &r_data)
1940 {
1941 int vv;
1942
1943 SavegameError err = restore_game_head_dynamic_values(in, r_data);
1944 if (err != kSvgErr_NoError)
1945 return err;
1946 restore_game_spriteset(in);
1947
1948 update_polled_stuff_if_runtime();
1949
1950 err = restore_game_scripts(in, pp, r_data);
1951 if (err != kSvgErr_NoError)
1952 return err;
1953 restore_game_room_state(in);
1954 restore_game_play(in);
1955 ReadMoveList_Aligned(in);
1956
1957 // save pointer members before reading
1958 char* gswas=game.globalscript;
1959 ccScript* compsc=game.compiled_script;
1960 CharacterInfo* chwas=game.chars;
1961 WordsDictionary *olddict = game.dict;
1962 char* mesbk[MAXGLOBALMES];
1963 int numchwas = game.numcharacters;
1964 for (vv=0;vv<MAXGLOBALMES;vv++) mesbk[vv]=game.messages[vv];
1965 int numdiwas = game.numdialog;
1966 int numinvwas = game.numinvitems;
1967 int numviewswas = game.numviews;
1968 int numGuisWas = game.numgui;
1969
1970 ReadGameSetupStructBase_Aligned(in);
1971
1972 // Delete unneeded data
1973 // TODO: reorganize this (may be solved by optimizing safe format too)
1974 delete [] game.load_messages;
1975 game.load_messages = NULL;
1976
1977 if (game.numdialog!=numdiwas)
1978 {
1979 Debug::Printf(kDbgMsg_Error, "Restore game error: mismatching number of Dialogs");
1980 return kSvgErr_GameContentAssertion;
1981 }
1982 if (numchwas != game.numcharacters)
1983 {
1984 Debug::Printf(kDbgMsg_Error, "Restore game error: mismatching number of Characters");
1985 return kSvgErr_GameContentAssertion;
1986 }
1987 if (numinvwas != game.numinvitems)
1988 {
1989 Debug::Printf(kDbgMsg_Error, "Restore game error: mismatching number of Inventory Items");
1990 return kSvgErr_GameContentAssertion;
1991 }
1992 if (game.numviews != numviewswas)
1993 {
1994 Debug::Printf(kDbgMsg_Error, "Restore game error: mismatching number of Views");
1995 return kSvgErr_GameContentAssertion;
1996 }
1997
1998 game.ReadFromSaveGame_v321(in, gswas, compsc, chwas, olddict, mesbk);
1999
2000 // Modified custom properties are read separately to keep existing save format
2001 play.ReadCustomProperties(in);
2002
2003 ReadCharacterExtras_Aligned(in);
2004 restore_game_palette(in);
2005 restore_game_dialogs(in);
2006 restore_game_more_dynamic_values(in);
2007 err = restore_game_gui(in, numGuisWas);
2008 if (err != kSvgErr_NoError)
2009 return err;
2010 err = restore_game_audiocliptypes(in);
2011 if (err != kSvgErr_NoError)
2012 return err;
2013 restore_game_thisroom(in, r_data);
2014 restore_game_ambientsounds(in, r_data);
2015 restore_game_overlays(in);
2016
2017 update_polled_stuff_if_runtime();
2018
2019 restore_game_dynamic_surfaces(in, r_data);
2020
2021 update_polled_stuff_if_runtime();
2022
2023 restore_game_displayed_room_status(in, r_data);
2024 err = restore_game_globalvars(in);
2025 if (err != kSvgErr_NoError)
2026 return err;
2027 err = restore_game_views(in);
2028 if (err != kSvgErr_NoError)
2029 return err;
2030
2031 if (in->ReadInt32() != MAGICNUMBER+1)
2032 {
2033 Debug::Printf(kDbgMsg_Error, "Restore game error: MAGICNUMBER not found before Audio Clips");
2034 return kSvgErr_InconsistentFormat;
2035 }
2036
2037 err = restore_game_audioclips_and_crossfade(in, r_data);
2038 if (err != kSvgErr_NoError)
2039 return err;
2040
2041 int pluginFileHandle = AGSE_RESTOREGAME;
2042 pl_set_file_handle(pluginFileHandle, in);
2043 pl_run_plugin_hooks(AGSE_RESTOREGAME, pluginFileHandle);
2044 pl_clear_file_handle();
2045 if (in->ReadInt32() != (unsigned)MAGICNUMBER)
2046 return kSvgErr_InconsistentPlugin;
2047
2048 // save the new room music vol for later use
2049 r_data.RoomVolume = in->ReadInt32();
2050
2051 if (ccUnserializeAllObjects(in, &ccUnserializer))
2052 {
2053 Debug::Printf(kDbgMsg_Error, "Restore game error: managed pool deserialization failed: %s", ccErrorString);
2054 return kSvgErr_GameObjectInitFailed;
2055 }
2056
2057 // preserve legacy music type setting
2058 current_music_type = in->ReadInt32();
2059
2060 return kSvgErr_NoError;
2061 }
2062
2063 int gameHasBeenRestored = 0;
2064 int oldeip;
2065
read_savedgame_description(const String & savedgame,String & description)2066 bool read_savedgame_description(const String &savedgame, String &description)
2067 {
2068 SavegameDescription desc;
2069 SavegameError err = OpenSavegame(savedgame, desc, kSvgDesc_UserText);
2070 if (err == kSvgErr_NoError)
2071 {
2072 description = desc.UserText;
2073 return true;
2074 }
2075 return false;
2076 }
2077
read_savedgame_screenshot(const String & savedgame,int & want_shot)2078 bool read_savedgame_screenshot(const String &savedgame, int &want_shot)
2079 {
2080 want_shot = 0;
2081
2082 SavegameDescription desc;
2083 SavegameError err = OpenSavegame(savedgame, desc, kSvgDesc_UserImage);
2084 if (err != kSvgErr_NoError)
2085 return false;
2086
2087 if (desc.UserImage.get())
2088 {
2089 int slot = spriteset.findFreeSlot();
2090 if (slot > 0)
2091 {
2092 // add it into the sprite set
2093 add_dynamic_sprite(slot, ReplaceBitmapWithSupportedFormat(desc.UserImage.release()));
2094 want_shot = slot;
2095 }
2096 }
2097 return true;
2098 }
2099
load_game(const String & path,int slotNumber,bool & data_overwritten)2100 SavegameError load_game(const String &path, int slotNumber, bool &data_overwritten)
2101 {
2102 data_overwritten = false;
2103 gameHasBeenRestored++;
2104
2105 oldeip = our_eip;
2106 our_eip = 2050;
2107
2108 SavegameError err;
2109 SavegameSource src;
2110 SavegameDescription desc;
2111 err = OpenSavegame(path, src, desc, kSvgDesc_EnvInfo);
2112
2113 our_eip = 2051;
2114
2115 // saved in incompatible enviroment
2116 if (err != kSvgErr_NoError)
2117 return err;
2118 // CHECKME: is this color depth test still essential? if yes, is there possible workaround?
2119 else if (desc.ColorDepth != game.GetColorDepth())
2120 return kSvgErr_DifferentColorDepth;
2121 else if (!src.InputStream.get())
2122 return kSvgErr_NoStream;
2123
2124 // saved with different game file
2125 if (Path::ComparePaths(desc.MainDataFilename, usetup.main_data_filename))
2126 {
2127 // [IKM] 2012-11-26: this is a workaround, indeed.
2128 // Try to find wanted game's executable; if it does not exist,
2129 // continue loading savedgame in current game, and pray for the best
2130 get_install_dir_path(gamefilenamebuf, desc.MainDataFilename);
2131 if (Common::File::TestReadFile(gamefilenamebuf))
2132 {
2133 RunAGSGame (desc.MainDataFilename, 0, 0);
2134 load_new_game_restore = slotNumber;
2135 return kSvgErr_NoError;
2136 }
2137 Common::Debug::Printf(kDbgMsg_Warn, "WARNING: the saved game '%s' references game file '%s', but it cannot be found in the current directory. Trying to restore in the running game instead.",
2138 path.GetCStr(), desc.MainDataFilename.GetCStr());
2139 }
2140
2141 // do the actual restore
2142 err = RestoreGameState(src.InputStream.get(), src.Version);
2143 data_overwritten = true;
2144 if (err != kSvgErr_NoError)
2145 return err;
2146 src.InputStream.reset();
2147 our_eip = oldeip;
2148
2149 // ensure keyboard buffer is clean
2150 // use the raw versions rather than the rec_ versions so we don't
2151 // interfere with the replay sync
2152 while (keypressed()) readkey();
2153 // call "After Restore" event callback
2154 run_on_event(GE_RESTORE_GAME, RuntimeScriptValue().SetInt32(slotNumber));
2155 return kSvgErr_NoError;
2156 }
2157
try_restore_save(int slot)2158 bool try_restore_save(int slot)
2159 {
2160 return try_restore_save(get_save_game_path(slot), slot);
2161 }
2162
try_restore_save(const Common::String & path,int slot)2163 bool try_restore_save(const Common::String &path, int slot)
2164 {
2165 bool data_overwritten;
2166 SavegameError err = load_game(path, slot, data_overwritten);
2167 if (err != kSvgErr_NoError)
2168 {
2169 String error = String::FromFormat("Unable to restore game:\n%s", GetSavegameErrorText(err).GetCStr());
2170 // currently AGS cannot properly revert to stable state if some of the
2171 // game data was released or overwritten by the data from save file,
2172 // this is why we tell engine to shutdown if that happened.
2173 if (data_overwritten)
2174 quitprintf(error);
2175 else
2176 Display(error);
2177 return false;
2178 }
2179 return true;
2180 }
2181
start_skipping_cutscene()2182 void start_skipping_cutscene () {
2183 play.fast_forward = 1;
2184 // if a drop-down icon bar is up, remove it as it will pause the game
2185 if (ifacepopped>=0)
2186 remove_popup_interface(ifacepopped);
2187
2188 // if a text message is currently displayed, remove it
2189 if (is_text_overlay > 0)
2190 remove_screen_overlay(OVER_TEXTMSG);
2191
2192 }
2193
check_skip_cutscene_keypress(int kgn)2194 void check_skip_cutscene_keypress (int kgn) {
2195
2196 if ((play.in_cutscene > 0) && (play.in_cutscene != 3)) {
2197 if ((kgn != 27) && ((play.in_cutscene == 1) || (play.in_cutscene == 5)))
2198 ;
2199 else
2200 start_skipping_cutscene();
2201 }
2202
2203 }
2204
2205 // Helper functions used by StartCutscene/EndCutscene, but also
2206 // by SkipUntilCharacterStops
initialize_skippable_cutscene()2207 void initialize_skippable_cutscene() {
2208 play.end_cutscene_music = -1;
2209 }
2210
stop_fast_forwarding()2211 void stop_fast_forwarding() {
2212 // when the skipping of a cutscene comes to an end, update things
2213 play.fast_forward = 0;
2214 setpal();
2215 if (play.end_cutscene_music >= 0)
2216 newmusic(play.end_cutscene_music);
2217
2218 // Restore actual volume of sounds
2219 for (int aa = 0; aa < MAX_SOUND_CHANNELS; aa++)
2220 {
2221 if ((channels[aa] != NULL) && (!channels[aa]->done))
2222 {
2223 channels[aa]->set_mute(false);
2224 }
2225 }
2226
2227 update_music_volume();
2228 }
2229
2230 // allowHotspot0 defines whether Hotspot 0 returns LOCTYPE_HOTSPOT
2231 // or whether it returns 0
__GetLocationType(int xxx,int yyy,int allowHotspot0)2232 int __GetLocationType(int xxx,int yyy, int allowHotspot0) {
2233 getloctype_index = 0;
2234 // If it's not in ProcessClick, then return 0 when over a GUI
2235 if ((GetGUIAt(xxx, yyy) >= 0) && (getloctype_throughgui == 0))
2236 return 0;
2237
2238 getloctype_throughgui = 0;
2239
2240 xxx += divide_down_coordinate(offsetx);
2241 yyy += divide_down_coordinate(offsety);
2242 if ((xxx>=thisroom.width) | (xxx<0) | (yyy<0) | (yyy>=thisroom.height))
2243 return 0;
2244
2245 // check characters, objects and walkbehinds, work out which is
2246 // foremost visible to the player
2247 int charat = is_pos_on_character(xxx,yyy);
2248 int hsat = get_hotspot_at(xxx,yyy);
2249 int objat = GetObjectAt(xxx - divide_down_coordinate(offsetx), yyy - divide_down_coordinate(offsety));
2250
2251 multiply_up_coordinates(&xxx, &yyy);
2252
2253 int wbat = thisroom.object->GetPixel(xxx, yyy);
2254
2255 if (wbat <= 0) wbat = 0;
2256 else wbat = croom->walkbehind_base[wbat];
2257
2258 int winner = 0;
2259 // if it's an Ignore Walkbehinds object, then ignore the walkbehind
2260 if ((objat >= 0) && ((objs[objat].flags & OBJF_NOWALKBEHINDS) != 0))
2261 wbat = 0;
2262 if ((charat >= 0) && ((game.chars[charat].flags & CHF_NOWALKBEHINDS) != 0))
2263 wbat = 0;
2264
2265 if ((charat >= 0) && (objat >= 0)) {
2266 if ((wbat > obj_lowest_yp) && (wbat > char_lowest_yp))
2267 winner = LOCTYPE_HOTSPOT;
2268 else if (obj_lowest_yp > char_lowest_yp)
2269 winner = LOCTYPE_OBJ;
2270 else
2271 winner = LOCTYPE_CHAR;
2272 }
2273 else if (charat >= 0) {
2274 if (wbat > char_lowest_yp)
2275 winner = LOCTYPE_HOTSPOT;
2276 else
2277 winner = LOCTYPE_CHAR;
2278 }
2279 else if (objat >= 0) {
2280 if (wbat > obj_lowest_yp)
2281 winner = LOCTYPE_HOTSPOT;
2282 else
2283 winner = LOCTYPE_OBJ;
2284 }
2285
2286 if (winner == 0) {
2287 if (hsat >= 0)
2288 winner = LOCTYPE_HOTSPOT;
2289 }
2290
2291 if ((winner == LOCTYPE_HOTSPOT) && (!allowHotspot0) && (hsat == 0))
2292 winner = 0;
2293
2294 if (winner == LOCTYPE_HOTSPOT)
2295 getloctype_index = hsat;
2296 else if (winner == LOCTYPE_CHAR)
2297 getloctype_index = charat;
2298 else if (winner == LOCTYPE_OBJ)
2299 getloctype_index = objat;
2300
2301 return winner;
2302 }
2303
2304 // Called whenever game looses input focus
display_switch_out()2305 void display_switch_out()
2306 {
2307 switched_away = true;
2308 clear_input_buffer();
2309 // Always unlock mouse when switching out from the game
2310 Mouse::UnlockFromWindow();
2311 platform->DisplaySwitchOut();
2312 platform->ExitFullscreenMode();
2313 }
2314
display_switch_out_suspend()2315 void display_switch_out_suspend()
2316 {
2317 // this is only called if in SWITCH_PAUSE mode
2318 //debug_script_warn("display_switch_out");
2319 display_switch_out();
2320
2321 switching_away_from_game++;
2322
2323 platform->PauseApplication();
2324
2325 // allow background running temporarily to halt the sound
2326 if (set_display_switch_mode(SWITCH_BACKGROUND) == -1)
2327 set_display_switch_mode(SWITCH_BACKAMNESIA);
2328
2329 // stop the sound stuttering
2330 for (int i = 0; i <= MAX_SOUND_CHANNELS; i++) {
2331 if ((channels[i] != NULL) && (channels[i]->done == 0)) {
2332 channels[i]->pause();
2333 }
2334 }
2335
2336 rest(1000);
2337
2338 // restore the callbacks
2339 SetMultitasking(0);
2340
2341 switching_away_from_game--;
2342 }
2343
2344 // Called whenever game gets input focus
display_switch_in()2345 void display_switch_in()
2346 {
2347 switched_away = false;
2348 if (gfxDriver)
2349 {
2350 DisplayMode mode = gfxDriver->GetDisplayMode();
2351 if (!mode.Windowed)
2352 platform->EnterFullscreenMode(mode);
2353 }
2354 platform->DisplaySwitchIn();
2355 clear_input_buffer();
2356 // If auto lock option is set, lock mouse to the game window
2357 if (usetup.mouse_auto_lock && scsystem.windowed)
2358 Mouse::TryLockToWindow();
2359 }
2360
display_switch_in_resume()2361 void display_switch_in_resume()
2362 {
2363 display_switch_in();
2364
2365 for (int i = 0; i <= MAX_SOUND_CHANNELS; i++) {
2366 if ((channels[i] != NULL) && (channels[i]->done == 0)) {
2367 channels[i]->resume();
2368 }
2369 }
2370
2371 // clear the screen if necessary
2372 if (gfxDriver && gfxDriver->UsesMemoryBackBuffer())
2373 gfxDriver->ClearRectangle(0, 0, game.size.Width - 1, game.size.Height - 1, NULL);
2374
2375 platform->ResumeApplication();
2376 }
2377
replace_tokens(const char * srcmes,char * destm,int maxlen)2378 void replace_tokens(const char*srcmes,char*destm, int maxlen) {
2379 int indxdest=0,indxsrc=0;
2380 const char*srcp;
2381 char *destp;
2382 while (srcmes[indxsrc]!=0) {
2383 srcp=&srcmes[indxsrc];
2384 destp=&destm[indxdest];
2385 if ((strncmp(srcp,"@IN",3)==0) | (strncmp(srcp,"@GI",3)==0)) {
2386 int tokentype=0;
2387 if (srcp[1]=='I') tokentype=1;
2388 else tokentype=2;
2389 int inx=atoi(&srcp[3]);
2390 srcp++;
2391 indxsrc+=2;
2392 while (srcp[0]!='@') {
2393 if (srcp[0]==0) quit("!Display: special token not terminated");
2394 srcp++;
2395 indxsrc++;
2396 }
2397 char tval[10];
2398 if (tokentype==1) {
2399 if ((inx<1) | (inx>=game.numinvitems))
2400 quit("!Display: invalid inv item specified in @IN@");
2401 sprintf(tval,"%d",playerchar->inv[inx]);
2402 }
2403 else {
2404 if ((inx<0) | (inx>=MAXGSVALUES))
2405 quit("!Display: invalid global int index speicifed in @GI@");
2406 sprintf(tval,"%d",GetGlobalInt(inx));
2407 }
2408 strcpy(destp,tval);
2409 indxdest+=strlen(tval);
2410 }
2411 else {
2412 destp[0]=srcp[0];
2413 indxdest++;
2414 indxsrc++;
2415 }
2416 if (indxdest >= maxlen - 3)
2417 break;
2418 }
2419 destm[indxdest]=0;
2420 }
2421
get_global_message(int msnum)2422 const char *get_global_message (int msnum) {
2423 if (game.messages[msnum-500] == NULL)
2424 return "";
2425 return get_translation(game.messages[msnum-500]);
2426 }
2427
get_message_text(int msnum,char * buffer,char giveErr)2428 void get_message_text (int msnum, char *buffer, char giveErr) {
2429 int maxlen = 9999;
2430 if (!giveErr)
2431 maxlen = MAX_MAXSTRLEN;
2432
2433 if (msnum>=500) { //quit("global message requseted, nto yet supported");
2434
2435 if ((msnum >= MAXGLOBALMES + 500) || (game.messages[msnum-500]==NULL)) {
2436 if (giveErr)
2437 quit("!DisplayGlobalMessage: message does not exist");
2438 buffer[0] = 0;
2439 return;
2440 }
2441 buffer[0] = 0;
2442 replace_tokens(get_translation(game.messages[msnum-500]), buffer, maxlen);
2443 return;
2444 }
2445 else if (msnum >= thisroom.nummes) {
2446 if (giveErr)
2447 quit("!DisplayMessage: Invalid message number to display");
2448 buffer[0] = 0;
2449 return;
2450 }
2451
2452 buffer[0]=0;
2453 replace_tokens(get_translation(thisroom.message[msnum]), buffer, maxlen);
2454 }
2455
unserialize_audio_script_object(int index,const char * objectType,const char * serializedData,int dataSize)2456 bool unserialize_audio_script_object(int index, const char *objectType, const char *serializedData, int dataSize)
2457 {
2458 if (strcmp(objectType, "AudioChannel") == 0)
2459 {
2460 ccDynamicAudio.Unserialize(index, serializedData, dataSize);
2461 }
2462 else if (strcmp(objectType, "AudioClip") == 0)
2463 {
2464 ccDynamicAudioClip.Unserialize(index, serializedData, dataSize);
2465 }
2466 else
2467 {
2468 return false;
2469 }
2470 return true;
2471 }
2472
2473 //=============================================================================
2474 //
2475 // Script API Functions
2476 //
2477 //=============================================================================
2478
2479 #include "debug/out.h"
2480 #include "script/script_api.h"
2481 #include "script/script_runtime.h"
2482
2483 // int (int audioType);
Sc_Game_IsAudioPlaying(const RuntimeScriptValue * params,int32_t param_count)2484 RuntimeScriptValue Sc_Game_IsAudioPlaying(const RuntimeScriptValue *params, int32_t param_count)
2485 {
2486 API_SCALL_INT_PINT(Game_IsAudioPlaying);
2487 }
2488
2489 // void (int audioType, int volumeDrop)
Sc_Game_SetAudioTypeSpeechVolumeDrop(const RuntimeScriptValue * params,int32_t param_count)2490 RuntimeScriptValue Sc_Game_SetAudioTypeSpeechVolumeDrop(const RuntimeScriptValue *params, int32_t param_count)
2491 {
2492 API_SCALL_VOID_PINT2(Game_SetAudioTypeSpeechVolumeDrop);
2493 }
2494
2495 // void (int audioType, int volume, int changeType)
Sc_Game_SetAudioTypeVolume(const RuntimeScriptValue * params,int32_t param_count)2496 RuntimeScriptValue Sc_Game_SetAudioTypeVolume(const RuntimeScriptValue *params, int32_t param_count)
2497 {
2498 API_SCALL_VOID_PINT3(Game_SetAudioTypeVolume);
2499 }
2500
2501 // void (int audioType)
Sc_Game_StopAudio(const RuntimeScriptValue * params,int32_t param_count)2502 RuntimeScriptValue Sc_Game_StopAudio(const RuntimeScriptValue *params, int32_t param_count)
2503 {
2504 API_SCALL_VOID_PINT(Game_StopAudio);
2505 }
2506
2507 // int (const char *newFilename)
Sc_Game_ChangeTranslation(const RuntimeScriptValue * params,int32_t param_count)2508 RuntimeScriptValue Sc_Game_ChangeTranslation(const RuntimeScriptValue *params, int32_t param_count)
2509 {
2510 API_SCALL_INT_POBJ(Game_ChangeTranslation, const char);
2511 }
2512
2513 // int (const char *token)
Sc_Game_DoOnceOnly(const RuntimeScriptValue * params,int32_t param_count)2514 RuntimeScriptValue Sc_Game_DoOnceOnly(const RuntimeScriptValue *params, int32_t param_count)
2515 {
2516 API_SCALL_INT_POBJ(Game_DoOnceOnly, const char);
2517 }
2518
2519 // int (int red, int grn, int blu)
Sc_Game_GetColorFromRGB(const RuntimeScriptValue * params,int32_t param_count)2520 RuntimeScriptValue Sc_Game_GetColorFromRGB(const RuntimeScriptValue *params, int32_t param_count)
2521 {
2522 API_SCALL_INT_PINT3(Game_GetColorFromRGB);
2523 }
2524
2525 // int (int viewNumber, int loopNumber)
Sc_Game_GetFrameCountForLoop(const RuntimeScriptValue * params,int32_t param_count)2526 RuntimeScriptValue Sc_Game_GetFrameCountForLoop(const RuntimeScriptValue *params, int32_t param_count)
2527 {
2528 API_SCALL_INT_PINT2(Game_GetFrameCountForLoop);
2529 }
2530
2531 // const char* (int x, int y)
Sc_Game_GetLocationName(const RuntimeScriptValue * params,int32_t param_count)2532 RuntimeScriptValue Sc_Game_GetLocationName(const RuntimeScriptValue *params, int32_t param_count)
2533 {
2534 API_SCALL_OBJ_PINT2(const char, myScriptStringImpl, Game_GetLocationName);
2535 }
2536
2537 // int (int viewNumber)
Sc_Game_GetLoopCountForView(const RuntimeScriptValue * params,int32_t param_count)2538 RuntimeScriptValue Sc_Game_GetLoopCountForView(const RuntimeScriptValue *params, int32_t param_count)
2539 {
2540 API_SCALL_INT_PINT(Game_GetLoopCountForView);
2541 }
2542
2543 // int ()
Sc_Game_GetMODPattern(const RuntimeScriptValue * params,int32_t param_count)2544 RuntimeScriptValue Sc_Game_GetMODPattern(const RuntimeScriptValue *params, int32_t param_count)
2545 {
2546 API_SCALL_INT(Game_GetMODPattern);
2547 }
2548
2549 // int (int viewNumber, int loopNumber)
Sc_Game_GetRunNextSettingForLoop(const RuntimeScriptValue * params,int32_t param_count)2550 RuntimeScriptValue Sc_Game_GetRunNextSettingForLoop(const RuntimeScriptValue *params, int32_t param_count)
2551 {
2552 API_SCALL_INT_PINT2(Game_GetRunNextSettingForLoop);
2553 }
2554
2555 // const char* (int slnum)
Sc_Game_GetSaveSlotDescription(const RuntimeScriptValue * params,int32_t param_count)2556 RuntimeScriptValue Sc_Game_GetSaveSlotDescription(const RuntimeScriptValue *params, int32_t param_count)
2557 {
2558 API_SCALL_OBJ_PINT(const char, myScriptStringImpl, Game_GetSaveSlotDescription);
2559 }
2560
2561 // ScriptViewFrame* (int viewNumber, int loopNumber, int frame)
Sc_Game_GetViewFrame(const RuntimeScriptValue * params,int32_t param_count)2562 RuntimeScriptValue Sc_Game_GetViewFrame(const RuntimeScriptValue *params, int32_t param_count)
2563 {
2564 API_SCALL_OBJAUTO_PINT3(ScriptViewFrame, Game_GetViewFrame);
2565 }
2566
2567 // const char* (const char *msg)
Sc_Game_InputBox(const RuntimeScriptValue * params,int32_t param_count)2568 RuntimeScriptValue Sc_Game_InputBox(const RuntimeScriptValue *params, int32_t param_count)
2569 {
2570 API_SCALL_OBJ_POBJ(const char, myScriptStringImpl, Game_InputBox, const char);
2571 }
2572
2573 // int (const char *newFolder)
Sc_Game_SetSaveGameDirectory(const RuntimeScriptValue * params,int32_t param_count)2574 RuntimeScriptValue Sc_Game_SetSaveGameDirectory(const RuntimeScriptValue *params, int32_t param_count)
2575 {
2576 API_SCALL_INT_POBJ(Game_SetSaveGameDirectory, const char);
2577 }
2578
2579 // void (int evenAmbient);
Sc_StopAllSounds(const RuntimeScriptValue * params,int32_t param_count)2580 RuntimeScriptValue Sc_StopAllSounds(const RuntimeScriptValue *params, int32_t param_count)
2581 {
2582 API_SCALL_VOID_PINT(StopAllSounds);
2583 }
2584
2585 // int ()
Sc_Game_GetCharacterCount(const RuntimeScriptValue * params,int32_t param_count)2586 RuntimeScriptValue Sc_Game_GetCharacterCount(const RuntimeScriptValue *params, int32_t param_count)
2587 {
2588 API_SCALL_INT(Game_GetCharacterCount);
2589 }
2590
2591 // int ()
Sc_Game_GetDialogCount(const RuntimeScriptValue * params,int32_t param_count)2592 RuntimeScriptValue Sc_Game_GetDialogCount(const RuntimeScriptValue *params, int32_t param_count)
2593 {
2594 API_SCALL_INT(Game_GetDialogCount);
2595 }
2596
2597 // const char *()
Sc_Game_GetFileName(const RuntimeScriptValue * params,int32_t param_count)2598 RuntimeScriptValue Sc_Game_GetFileName(const RuntimeScriptValue *params, int32_t param_count)
2599 {
2600 API_SCALL_OBJ(const char, myScriptStringImpl, Game_GetFileName);
2601 }
2602
2603 // int ()
Sc_Game_GetFontCount(const RuntimeScriptValue * params,int32_t param_count)2604 RuntimeScriptValue Sc_Game_GetFontCount(const RuntimeScriptValue *params, int32_t param_count)
2605 {
2606 API_SCALL_INT(Game_GetFontCount);
2607 }
2608
2609 // const char* (int index)
Sc_Game_GetGlobalMessages(const RuntimeScriptValue * params,int32_t param_count)2610 RuntimeScriptValue Sc_Game_GetGlobalMessages(const RuntimeScriptValue *params, int32_t param_count)
2611 {
2612 API_SCALL_OBJ_PINT(const char, myScriptStringImpl, Game_GetGlobalMessages);
2613 }
2614
2615 // const char* (int index)
Sc_Game_GetGlobalStrings(const RuntimeScriptValue * params,int32_t param_count)2616 RuntimeScriptValue Sc_Game_GetGlobalStrings(const RuntimeScriptValue *params, int32_t param_count)
2617 {
2618 API_SCALL_OBJ_PINT(const char, myScriptStringImpl, Game_GetGlobalStrings);
2619 }
2620
2621 // void (int index, char *newval);
Sc_SetGlobalString(const RuntimeScriptValue * params,int32_t param_count)2622 RuntimeScriptValue Sc_SetGlobalString(const RuntimeScriptValue *params, int32_t param_count)
2623 {
2624 API_SCALL_VOID_PINT_POBJ(SetGlobalString, const char);
2625 }
2626
2627 // int ()
Sc_Game_GetGUICount(const RuntimeScriptValue * params,int32_t param_count)2628 RuntimeScriptValue Sc_Game_GetGUICount(const RuntimeScriptValue *params, int32_t param_count)
2629 {
2630 API_SCALL_INT(Game_GetGUICount);
2631 }
2632
2633 // int ()
Sc_Game_GetIgnoreUserInputAfterTextTimeoutMs(const RuntimeScriptValue * params,int32_t param_count)2634 RuntimeScriptValue Sc_Game_GetIgnoreUserInputAfterTextTimeoutMs(const RuntimeScriptValue *params, int32_t param_count)
2635 {
2636 API_SCALL_INT(Game_GetIgnoreUserInputAfterTextTimeoutMs);
2637 }
2638
2639 // void (int newValueMs)
Sc_Game_SetIgnoreUserInputAfterTextTimeoutMs(const RuntimeScriptValue * params,int32_t param_count)2640 RuntimeScriptValue Sc_Game_SetIgnoreUserInputAfterTextTimeoutMs(const RuntimeScriptValue *params, int32_t param_count)
2641 {
2642 API_SCALL_VOID_PINT(Game_SetIgnoreUserInputAfterTextTimeoutMs);
2643 }
2644
2645 // int ()
Sc_Game_GetInSkippableCutscene(const RuntimeScriptValue * params,int32_t param_count)2646 RuntimeScriptValue Sc_Game_GetInSkippableCutscene(const RuntimeScriptValue *params, int32_t param_count)
2647 {
2648 API_SCALL_INT(Game_GetInSkippableCutscene);
2649 }
2650
2651 // int ()
Sc_Game_GetInventoryItemCount(const RuntimeScriptValue * params,int32_t param_count)2652 RuntimeScriptValue Sc_Game_GetInventoryItemCount(const RuntimeScriptValue *params, int32_t param_count)
2653 {
2654 API_SCALL_INT(Game_GetInventoryItemCount);
2655 }
2656
2657 // int ()
Sc_Game_GetMinimumTextDisplayTimeMs(const RuntimeScriptValue * params,int32_t param_count)2658 RuntimeScriptValue Sc_Game_GetMinimumTextDisplayTimeMs(const RuntimeScriptValue *params, int32_t param_count)
2659 {
2660 API_SCALL_INT(Game_GetMinimumTextDisplayTimeMs);
2661 }
2662
2663 // void (int newTextMinTime)
Sc_Game_SetMinimumTextDisplayTimeMs(const RuntimeScriptValue * params,int32_t param_count)2664 RuntimeScriptValue Sc_Game_SetMinimumTextDisplayTimeMs(const RuntimeScriptValue *params, int32_t param_count)
2665 {
2666 API_SCALL_VOID_PINT(Game_SetMinimumTextDisplayTimeMs);
2667 }
2668
2669 // int ()
Sc_Game_GetMouseCursorCount(const RuntimeScriptValue * params,int32_t param_count)2670 RuntimeScriptValue Sc_Game_GetMouseCursorCount(const RuntimeScriptValue *params, int32_t param_count)
2671 {
2672 API_SCALL_INT(Game_GetMouseCursorCount);
2673 }
2674
2675 // const char *()
Sc_Game_GetName(const RuntimeScriptValue * params,int32_t param_count)2676 RuntimeScriptValue Sc_Game_GetName(const RuntimeScriptValue *params, int32_t param_count)
2677 {
2678 API_SCALL_OBJ(const char, myScriptStringImpl, Game_GetName);
2679 }
2680
2681 // void (const char *newName)
Sc_Game_SetName(const RuntimeScriptValue * params,int32_t param_count)2682 RuntimeScriptValue Sc_Game_SetName(const RuntimeScriptValue *params, int32_t param_count)
2683 {
2684 API_SCALL_VOID_POBJ(Game_SetName, const char);
2685 }
2686
2687 // int ()
Sc_Game_GetNormalFont(const RuntimeScriptValue * params,int32_t param_count)2688 RuntimeScriptValue Sc_Game_GetNormalFont(const RuntimeScriptValue *params, int32_t param_count)
2689 {
2690 API_SCALL_INT(Game_GetNormalFont);
2691 }
2692
2693 // void (int fontnum);
Sc_SetNormalFont(const RuntimeScriptValue * params,int32_t param_count)2694 RuntimeScriptValue Sc_SetNormalFont(const RuntimeScriptValue *params, int32_t param_count)
2695 {
2696 API_SCALL_VOID_PINT(SetNormalFont);
2697 }
2698
2699 // int ()
Sc_Game_GetSkippingCutscene(const RuntimeScriptValue * params,int32_t param_count)2700 RuntimeScriptValue Sc_Game_GetSkippingCutscene(const RuntimeScriptValue *params, int32_t param_count)
2701 {
2702 API_SCALL_INT(Game_GetSkippingCutscene);
2703 }
2704
2705 // int ()
Sc_Game_GetSpeechFont(const RuntimeScriptValue * params,int32_t param_count)2706 RuntimeScriptValue Sc_Game_GetSpeechFont(const RuntimeScriptValue *params, int32_t param_count)
2707 {
2708 API_SCALL_INT(Game_GetSpeechFont);
2709 }
2710
2711 // void (int fontnum);
Sc_SetSpeechFont(const RuntimeScriptValue * params,int32_t param_count)2712 RuntimeScriptValue Sc_SetSpeechFont(const RuntimeScriptValue *params, int32_t param_count)
2713 {
2714 API_SCALL_VOID_PINT(SetSpeechFont);
2715 }
2716
2717 // int (int spriteNum)
Sc_Game_GetSpriteWidth(const RuntimeScriptValue * params,int32_t param_count)2718 RuntimeScriptValue Sc_Game_GetSpriteWidth(const RuntimeScriptValue *params, int32_t param_count)
2719 {
2720 API_SCALL_INT_PINT(Game_GetSpriteWidth);
2721 }
2722
2723 // int (int spriteNum)
Sc_Game_GetSpriteHeight(const RuntimeScriptValue * params,int32_t param_count)2724 RuntimeScriptValue Sc_Game_GetSpriteHeight(const RuntimeScriptValue *params, int32_t param_count)
2725 {
2726 API_SCALL_INT_PINT(Game_GetSpriteHeight);
2727 }
2728
2729 // int ()
Sc_Game_GetTextReadingSpeed(const RuntimeScriptValue * params,int32_t param_count)2730 RuntimeScriptValue Sc_Game_GetTextReadingSpeed(const RuntimeScriptValue *params, int32_t param_count)
2731 {
2732 API_SCALL_INT(Game_GetTextReadingSpeed);
2733 }
2734
2735 // void (int newTextSpeed)
Sc_Game_SetTextReadingSpeed(const RuntimeScriptValue * params,int32_t param_count)2736 RuntimeScriptValue Sc_Game_SetTextReadingSpeed(const RuntimeScriptValue *params, int32_t param_count)
2737 {
2738 API_SCALL_VOID_PINT(Game_SetTextReadingSpeed);
2739 }
2740
2741 // const char* ()
Sc_Game_GetTranslationFilename(const RuntimeScriptValue * params,int32_t param_count)2742 RuntimeScriptValue Sc_Game_GetTranslationFilename(const RuntimeScriptValue *params, int32_t param_count)
2743 {
2744 API_SCALL_OBJ(const char, myScriptStringImpl, Game_GetTranslationFilename);
2745 }
2746
2747 // int ()
Sc_Game_GetUseNativeCoordinates(const RuntimeScriptValue * params,int32_t param_count)2748 RuntimeScriptValue Sc_Game_GetUseNativeCoordinates(const RuntimeScriptValue *params, int32_t param_count)
2749 {
2750 API_SCALL_INT(Game_GetUseNativeCoordinates);
2751 }
2752
2753 // int ()
Sc_Game_GetViewCount(const RuntimeScriptValue * params,int32_t param_count)2754 RuntimeScriptValue Sc_Game_GetViewCount(const RuntimeScriptValue *params, int32_t param_count)
2755 {
2756 API_SCALL_INT(Game_GetViewCount);
2757 }
2758
Sc_Game_GetAudioClipCount(const RuntimeScriptValue * params,int32_t param_count)2759 RuntimeScriptValue Sc_Game_GetAudioClipCount(const RuntimeScriptValue *params, int32_t param_count)
2760 {
2761 API_VARGET_INT(game.audioClipCount);
2762 }
2763
Sc_Game_GetAudioClip(const RuntimeScriptValue * params,int32_t param_count)2764 RuntimeScriptValue Sc_Game_GetAudioClip(const RuntimeScriptValue *params, int32_t param_count)
2765 {
2766 API_SCALL_OBJ_PINT(ScriptAudioClip, ccDynamicAudioClip, Game_GetAudioClip);
2767 }
2768
Sc_Game_IsPluginLoaded(const RuntimeScriptValue * params,int32_t param_count)2769 RuntimeScriptValue Sc_Game_IsPluginLoaded(const RuntimeScriptValue *params, int32_t param_count)
2770 {
2771 API_SCALL_BOOL_OBJ(pl_is_plugin_loaded, const char);
2772 }
2773
2774
RegisterGameAPI()2775 void RegisterGameAPI()
2776 {
2777 ccAddExternalStaticFunction("Game::IsAudioPlaying^1", Sc_Game_IsAudioPlaying);
2778 ccAddExternalStaticFunction("Game::SetAudioTypeSpeechVolumeDrop^2", Sc_Game_SetAudioTypeSpeechVolumeDrop);
2779 ccAddExternalStaticFunction("Game::SetAudioTypeVolume^3", Sc_Game_SetAudioTypeVolume);
2780 ccAddExternalStaticFunction("Game::StopAudio^1", Sc_Game_StopAudio);
2781 ccAddExternalStaticFunction("Game::ChangeTranslation^1", Sc_Game_ChangeTranslation);
2782 ccAddExternalStaticFunction("Game::DoOnceOnly^1", Sc_Game_DoOnceOnly);
2783 ccAddExternalStaticFunction("Game::GetColorFromRGB^3", Sc_Game_GetColorFromRGB);
2784 ccAddExternalStaticFunction("Game::GetFrameCountForLoop^2", Sc_Game_GetFrameCountForLoop);
2785 ccAddExternalStaticFunction("Game::GetLocationName^2", Sc_Game_GetLocationName);
2786 ccAddExternalStaticFunction("Game::GetLoopCountForView^1", Sc_Game_GetLoopCountForView);
2787 ccAddExternalStaticFunction("Game::GetMODPattern^0", Sc_Game_GetMODPattern);
2788 ccAddExternalStaticFunction("Game::GetRunNextSettingForLoop^2", Sc_Game_GetRunNextSettingForLoop);
2789 ccAddExternalStaticFunction("Game::GetSaveSlotDescription^1", Sc_Game_GetSaveSlotDescription);
2790 ccAddExternalStaticFunction("Game::GetViewFrame^3", Sc_Game_GetViewFrame);
2791 ccAddExternalStaticFunction("Game::InputBox^1", Sc_Game_InputBox);
2792 ccAddExternalStaticFunction("Game::SetSaveGameDirectory^1", Sc_Game_SetSaveGameDirectory);
2793 ccAddExternalStaticFunction("Game::StopSound^1", Sc_StopAllSounds);
2794 ccAddExternalStaticFunction("Game::get_CharacterCount", Sc_Game_GetCharacterCount);
2795 ccAddExternalStaticFunction("Game::get_DialogCount", Sc_Game_GetDialogCount);
2796 ccAddExternalStaticFunction("Game::get_FileName", Sc_Game_GetFileName);
2797 ccAddExternalStaticFunction("Game::get_FontCount", Sc_Game_GetFontCount);
2798 ccAddExternalStaticFunction("Game::geti_GlobalMessages", Sc_Game_GetGlobalMessages);
2799 ccAddExternalStaticFunction("Game::geti_GlobalStrings", Sc_Game_GetGlobalStrings);
2800 ccAddExternalStaticFunction("Game::seti_GlobalStrings", Sc_SetGlobalString);
2801 ccAddExternalStaticFunction("Game::get_GUICount", Sc_Game_GetGUICount);
2802 ccAddExternalStaticFunction("Game::get_IgnoreUserInputAfterTextTimeoutMs", Sc_Game_GetIgnoreUserInputAfterTextTimeoutMs);
2803 ccAddExternalStaticFunction("Game::set_IgnoreUserInputAfterTextTimeoutMs", Sc_Game_SetIgnoreUserInputAfterTextTimeoutMs);
2804 ccAddExternalStaticFunction("Game::get_InSkippableCutscene", Sc_Game_GetInSkippableCutscene);
2805 ccAddExternalStaticFunction("Game::get_InventoryItemCount", Sc_Game_GetInventoryItemCount);
2806 ccAddExternalStaticFunction("Game::get_MinimumTextDisplayTimeMs", Sc_Game_GetMinimumTextDisplayTimeMs);
2807 ccAddExternalStaticFunction("Game::set_MinimumTextDisplayTimeMs", Sc_Game_SetMinimumTextDisplayTimeMs);
2808 ccAddExternalStaticFunction("Game::get_MouseCursorCount", Sc_Game_GetMouseCursorCount);
2809 ccAddExternalStaticFunction("Game::get_Name", Sc_Game_GetName);
2810 ccAddExternalStaticFunction("Game::set_Name", Sc_Game_SetName);
2811 ccAddExternalStaticFunction("Game::get_NormalFont", Sc_Game_GetNormalFont);
2812 ccAddExternalStaticFunction("Game::set_NormalFont", Sc_SetNormalFont);
2813 ccAddExternalStaticFunction("Game::get_SkippingCutscene", Sc_Game_GetSkippingCutscene);
2814 ccAddExternalStaticFunction("Game::get_SpeechFont", Sc_Game_GetSpeechFont);
2815 ccAddExternalStaticFunction("Game::set_SpeechFont", Sc_SetSpeechFont);
2816 ccAddExternalStaticFunction("Game::geti_SpriteWidth", Sc_Game_GetSpriteWidth);
2817 ccAddExternalStaticFunction("Game::geti_SpriteHeight", Sc_Game_GetSpriteHeight);
2818 ccAddExternalStaticFunction("Game::get_TextReadingSpeed", Sc_Game_GetTextReadingSpeed);
2819 ccAddExternalStaticFunction("Game::set_TextReadingSpeed", Sc_Game_SetTextReadingSpeed);
2820 ccAddExternalStaticFunction("Game::get_TranslationFilename", Sc_Game_GetTranslationFilename);
2821 ccAddExternalStaticFunction("Game::get_UseNativeCoordinates", Sc_Game_GetUseNativeCoordinates);
2822 ccAddExternalStaticFunction("Game::get_ViewCount", Sc_Game_GetViewCount);
2823 ccAddExternalStaticFunction("Game::get_AudioClipCount", Sc_Game_GetAudioClipCount);
2824 ccAddExternalStaticFunction("Game::geti_AudioClips", Sc_Game_GetAudioClip);
2825 ccAddExternalStaticFunction("Game::IsPluginLoaded", Sc_Game_IsPluginLoaded);
2826
2827 /* ----------------------- Registering unsafe exports for plugins -----------------------*/
2828
2829 ccAddExternalFunctionForPlugin("Game::IsAudioPlaying^1", (void*)Game_IsAudioPlaying);
2830 ccAddExternalFunctionForPlugin("Game::SetAudioTypeSpeechVolumeDrop^2", (void*)Game_SetAudioTypeSpeechVolumeDrop);
2831 ccAddExternalFunctionForPlugin("Game::SetAudioTypeVolume^3", (void*)Game_SetAudioTypeVolume);
2832 ccAddExternalFunctionForPlugin("Game::StopAudio^1", (void*)Game_StopAudio);
2833 ccAddExternalFunctionForPlugin("Game::ChangeTranslation^1", (void*)Game_ChangeTranslation);
2834 ccAddExternalFunctionForPlugin("Game::DoOnceOnly^1", (void*)Game_DoOnceOnly);
2835 ccAddExternalFunctionForPlugin("Game::GetColorFromRGB^3", (void*)Game_GetColorFromRGB);
2836 ccAddExternalFunctionForPlugin("Game::GetFrameCountForLoop^2", (void*)Game_GetFrameCountForLoop);
2837 ccAddExternalFunctionForPlugin("Game::GetLocationName^2", (void*)Game_GetLocationName);
2838 ccAddExternalFunctionForPlugin("Game::GetLoopCountForView^1", (void*)Game_GetLoopCountForView);
2839 ccAddExternalFunctionForPlugin("Game::GetMODPattern^0", (void*)Game_GetMODPattern);
2840 ccAddExternalFunctionForPlugin("Game::GetRunNextSettingForLoop^2", (void*)Game_GetRunNextSettingForLoop);
2841 ccAddExternalFunctionForPlugin("Game::GetSaveSlotDescription^1", (void*)Game_GetSaveSlotDescription);
2842 ccAddExternalFunctionForPlugin("Game::GetViewFrame^3", (void*)Game_GetViewFrame);
2843 ccAddExternalFunctionForPlugin("Game::InputBox^1", (void*)Game_InputBox);
2844 ccAddExternalFunctionForPlugin("Game::SetSaveGameDirectory^1", (void*)Game_SetSaveGameDirectory);
2845 ccAddExternalFunctionForPlugin("Game::StopSound^1", (void*)StopAllSounds);
2846 ccAddExternalFunctionForPlugin("Game::get_CharacterCount", (void*)Game_GetCharacterCount);
2847 ccAddExternalFunctionForPlugin("Game::get_DialogCount", (void*)Game_GetDialogCount);
2848 ccAddExternalFunctionForPlugin("Game::get_FileName", (void*)Game_GetFileName);
2849 ccAddExternalFunctionForPlugin("Game::get_FontCount", (void*)Game_GetFontCount);
2850 ccAddExternalFunctionForPlugin("Game::geti_GlobalMessages", (void*)Game_GetGlobalMessages);
2851 ccAddExternalFunctionForPlugin("Game::geti_GlobalStrings", (void*)Game_GetGlobalStrings);
2852 ccAddExternalFunctionForPlugin("Game::seti_GlobalStrings", (void*)SetGlobalString);
2853 ccAddExternalFunctionForPlugin("Game::get_GUICount", (void*)Game_GetGUICount);
2854 ccAddExternalFunctionForPlugin("Game::get_IgnoreUserInputAfterTextTimeoutMs", (void*)Game_GetIgnoreUserInputAfterTextTimeoutMs);
2855 ccAddExternalFunctionForPlugin("Game::set_IgnoreUserInputAfterTextTimeoutMs", (void*)Game_SetIgnoreUserInputAfterTextTimeoutMs);
2856 ccAddExternalFunctionForPlugin("Game::get_InSkippableCutscene", (void*)Game_GetInSkippableCutscene);
2857 ccAddExternalFunctionForPlugin("Game::get_InventoryItemCount", (void*)Game_GetInventoryItemCount);
2858 ccAddExternalFunctionForPlugin("Game::get_MinimumTextDisplayTimeMs", (void*)Game_GetMinimumTextDisplayTimeMs);
2859 ccAddExternalFunctionForPlugin("Game::set_MinimumTextDisplayTimeMs", (void*)Game_SetMinimumTextDisplayTimeMs);
2860 ccAddExternalFunctionForPlugin("Game::get_MouseCursorCount", (void*)Game_GetMouseCursorCount);
2861 ccAddExternalFunctionForPlugin("Game::get_Name", (void*)Game_GetName);
2862 ccAddExternalFunctionForPlugin("Game::set_Name", (void*)Game_SetName);
2863 ccAddExternalFunctionForPlugin("Game::get_NormalFont", (void*)Game_GetNormalFont);
2864 ccAddExternalFunctionForPlugin("Game::set_NormalFont", (void*)SetNormalFont);
2865 ccAddExternalFunctionForPlugin("Game::get_SkippingCutscene", (void*)Game_GetSkippingCutscene);
2866 ccAddExternalFunctionForPlugin("Game::get_SpeechFont", (void*)Game_GetSpeechFont);
2867 ccAddExternalFunctionForPlugin("Game::set_SpeechFont", (void*)SetSpeechFont);
2868 ccAddExternalFunctionForPlugin("Game::geti_SpriteWidth", (void*)Game_GetSpriteWidth);
2869 ccAddExternalFunctionForPlugin("Game::geti_SpriteHeight", (void*)Game_GetSpriteHeight);
2870 ccAddExternalFunctionForPlugin("Game::get_TextReadingSpeed", (void*)Game_GetTextReadingSpeed);
2871 ccAddExternalFunctionForPlugin("Game::set_TextReadingSpeed", (void*)Game_SetTextReadingSpeed);
2872 ccAddExternalFunctionForPlugin("Game::get_TranslationFilename", (void*)Game_GetTranslationFilename);
2873 ccAddExternalFunctionForPlugin("Game::get_UseNativeCoordinates", (void*)Game_GetUseNativeCoordinates);
2874 ccAddExternalFunctionForPlugin("Game::get_ViewCount", (void*)Game_GetViewCount);
2875 }
2876
RegisterStaticObjects()2877 void RegisterStaticObjects()
2878 {
2879 ccAddExternalStaticObject("game",&play, &GameStaticManager);
2880 ccAddExternalStaticObject("gs_globals",&play.globalvars[0], &GlobalStaticManager);
2881 ccAddExternalStaticObject("mouse",&scmouse, &GlobalStaticManager);
2882 ccAddExternalStaticObject("palette",&palette[0], &GlobalStaticManager);
2883 ccAddExternalStaticObject("system",&scsystem, &GlobalStaticManager);
2884 ccAddExternalStaticObject("savegameindex",&play.filenumbers[0], &GlobalStaticManager);
2885 }
2886