2849 lines
72 KiB
C++
2849 lines
72 KiB
C++
#include "scripts.h"
|
|
|
|
#include "actions.h"
|
|
#include "automap.h"
|
|
#include "combat.h"
|
|
#include "core.h"
|
|
#include "critter.h"
|
|
#include "debug.h"
|
|
#include "dialog.h"
|
|
#include "elevator.h"
|
|
#include "endgame.h"
|
|
#include "export.h"
|
|
#include "game.h"
|
|
#include "game_dialog.h"
|
|
#include "game_mouse.h"
|
|
#include "game_movie.h"
|
|
#include "memory.h"
|
|
#include "object.h"
|
|
#include "proto.h"
|
|
#include "proto_instance.h"
|
|
#include "queue.h"
|
|
#include "tile.h"
|
|
#include "window_manager.h"
|
|
#include "window_manager_private.h"
|
|
#include "world_map.h"
|
|
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
|
|
// 0x50D6B8
|
|
char _Error_2[] = "Error";
|
|
|
|
// 0x50D6C0
|
|
char byte_50D6C0[] = "";
|
|
|
|
// Number of lines in scripts.lst
|
|
//
|
|
// 0x51C6AC
|
|
int _num_script_indexes = 0;
|
|
|
|
// 0x51C6B0
|
|
int gScriptsEnumerationScriptIndex = 0;
|
|
|
|
// 0x51C6B4
|
|
ScriptListExtent* gScriptsEnumerationScriptListExtent = NULL;
|
|
|
|
// 0x51C6B8
|
|
int gScriptsEnumerationElevation = 0;
|
|
|
|
// 0x51C6BC
|
|
bool _scr_SpatialsEnabled = true;
|
|
|
|
// 0x51C6C0
|
|
ScriptList gScriptLists[SCRIPT_TYPE_COUNT];
|
|
|
|
// 0x51C710
|
|
const char* gScriptsBasePath = "scripts\\";
|
|
|
|
// 0x51C714
|
|
bool gScriptsEnabled = false;
|
|
|
|
// 0x51C718
|
|
int _script_engine_run_critters = 0;
|
|
|
|
// 0x51C71C
|
|
int _script_engine_game_mode = 0;
|
|
|
|
// Game time in ticks (1/10 second).
|
|
//
|
|
// 0x51C720
|
|
int gGameTime = 302400;
|
|
|
|
// 0x51C724
|
|
const int gGameTimeDaysPerMonth[12] = {
|
|
31, // Jan
|
|
28, // Feb
|
|
31, // Mar
|
|
30, // Apr
|
|
31, // May
|
|
30, // Jun
|
|
31, // Jul
|
|
31, // Aug
|
|
30, // Sep
|
|
31, // Oct
|
|
30, // Nov
|
|
31, // Dec
|
|
};
|
|
|
|
// 0x51C758
|
|
const char* gScriptProcNames[28] = {
|
|
"no_p_proc",
|
|
"start",
|
|
"spatial_p_proc",
|
|
"description_p_proc",
|
|
"pickup_p_proc",
|
|
"drop_p_proc",
|
|
"use_p_proc",
|
|
"use_obj_on_p_proc",
|
|
"use_skill_on_p_proc",
|
|
"none_x_bad",
|
|
"none_x_bad",
|
|
"talk_p_proc",
|
|
"critter_p_proc",
|
|
"combat_p_proc",
|
|
"damage_p_proc",
|
|
"map_enter_p_proc",
|
|
"map_exit_p_proc",
|
|
"create_p_proc",
|
|
"destroy_p_proc",
|
|
"none_x_bad",
|
|
"none_x_bad",
|
|
"look_at_p_proc",
|
|
"timed_event_p_proc",
|
|
"map_update_p_proc",
|
|
"push_p_proc",
|
|
"is_dropping_p_proc",
|
|
"combat_is_starting_p_proc",
|
|
"combat_is_over_p_proc",
|
|
};
|
|
|
|
// scripts.lst
|
|
//
|
|
// 0x51C7C8
|
|
ScriptsListEntry* gScriptsListEntries = NULL;
|
|
|
|
// 0x51C7CC
|
|
int gScriptsListEntriesLength = 0;
|
|
|
|
// 0x51C7D4
|
|
int _cur_id = 4;
|
|
|
|
// 0x51C7DC
|
|
int _count_ = 0;
|
|
|
|
// 0x51C7E0
|
|
int _last_time__ = 0;
|
|
|
|
// 0x51C7E4
|
|
int _last_light_time = 0;
|
|
|
|
// 0x51C7E8
|
|
Object* _scrQueueTestObj = NULL;
|
|
|
|
// 0x51C7EC
|
|
int _scrQueueTestValue = 0;
|
|
|
|
// 0x51C7F0
|
|
char* _err_str = _Error_2;
|
|
|
|
// 0x51C7F4
|
|
char* _blank_str = byte_50D6C0;
|
|
|
|
// 0x664954
|
|
unsigned int gScriptsRequests;
|
|
|
|
// 0x664958
|
|
STRUCT_664980 stru_664958;
|
|
|
|
// 0x664980
|
|
STRUCT_664980 stru_664980;
|
|
|
|
// 0x6649A8
|
|
int gScriptsRequestedElevatorType;
|
|
|
|
// 0x6649AC
|
|
int gScriptsRequestedElevatorLevel;
|
|
|
|
// 0x6649B0
|
|
int gScriptsRequestedExplosionTile;
|
|
|
|
// 0x6649B4
|
|
int gScriptsRequestedExplosionElevation;
|
|
|
|
// 0x6649B8
|
|
int gScriptsRequestedExplosionMinDamage;
|
|
|
|
// 0x6649BC
|
|
int gScriptsRequestedExplosionMaxDamage;
|
|
|
|
// 0x6649C0
|
|
Object* gScriptsRequestedDialogWith;
|
|
|
|
// 0x6649C4
|
|
Object* gScriptsRequestedLootingBy;
|
|
|
|
// 0x6649C8
|
|
Object* gScriptsRequestedLootingFrom;
|
|
|
|
// 0x6649CC
|
|
Object* gScriptsRequestedStealingBy;
|
|
|
|
// 0x6649D0
|
|
Object* gScriptsRequestedStealingFrom;
|
|
|
|
// 0x6649D4
|
|
MessageList _script_dialog_msgs[1450];
|
|
|
|
// scr.msg
|
|
//
|
|
// 0x667724
|
|
MessageList gScrMessageList;
|
|
|
|
// time string (h:ss)
|
|
//
|
|
// 0x66772C
|
|
char _hour_str[7];
|
|
|
|
// 0x667748
|
|
int _lasttime;
|
|
|
|
// 0x66774C
|
|
bool _set;
|
|
|
|
// 0x667750
|
|
char _tempStr1[20];
|
|
|
|
// TODO: Make unsigned.
|
|
//
|
|
// Returns game time in ticks (1/10 second).
|
|
//
|
|
// 0x4A3330
|
|
int gameTimeGetTime()
|
|
{
|
|
return gGameTime;
|
|
}
|
|
|
|
// 0x4A3338
|
|
void gameTimeGetDate(int* monthPtr, int* dayPtr, int* yearPtr)
|
|
{
|
|
int year = (gGameTime / GAME_TIME_TICKS_PER_DAY + 24) / 365 + 2241;
|
|
int month = 6;
|
|
int day = (gGameTime / GAME_TIME_TICKS_PER_DAY + 24) % 365;
|
|
|
|
while (1) {
|
|
int daysInMonth = gGameTimeDaysPerMonth[month];
|
|
if (day < daysInMonth) {
|
|
break;
|
|
}
|
|
|
|
month++;
|
|
day -= daysInMonth;
|
|
|
|
if (month == 12) {
|
|
year++;
|
|
month = 0;
|
|
}
|
|
}
|
|
|
|
if (dayPtr != NULL) {
|
|
*dayPtr = day + 1;
|
|
}
|
|
|
|
if (monthPtr != NULL) {
|
|
*monthPtr = month + 1;
|
|
}
|
|
|
|
if (yearPtr != NULL) {
|
|
*yearPtr = year;
|
|
}
|
|
}
|
|
|
|
// Returns game hour/minute in military format (hhmm).
|
|
//
|
|
// Examples:
|
|
// - 8:00 A.M. -> 800
|
|
// - 3:00 P.M. -> 1500
|
|
// - 11:59 P.M. -> 2359
|
|
//
|
|
// game_time_hour
|
|
// 0x4A33C8
|
|
int gameTimeGetHour()
|
|
{
|
|
return 100 * ((gGameTime / 600) / 60 % 24) + (gGameTime / 600) % 60;
|
|
}
|
|
|
|
// Returns time string (h:mm)
|
|
//
|
|
// 0x4A3420
|
|
char* gameTimeGetTimeString()
|
|
{
|
|
sprintf(_hour_str, "%d:%02d", (gGameTime / 600) / 60 % 24, (gGameTime / 600) % 60);
|
|
return _hour_str;
|
|
}
|
|
|
|
// TODO: Make unsigned.
|
|
//
|
|
// 0x4A347C
|
|
void gameTimeSetTime(int time)
|
|
{
|
|
if (time == 0) {
|
|
time = 1;
|
|
}
|
|
|
|
gGameTime = time;
|
|
}
|
|
|
|
// 0x4A34CC
|
|
void gameTimeAddTicks(int ticks)
|
|
{
|
|
gGameTime += ticks;
|
|
|
|
int v1 = 0;
|
|
|
|
unsigned int year = gGameTime / GAME_TIME_TICKS_PER_YEAR;
|
|
if (year >= 13) {
|
|
endgameSetupDeathEnding(ENDGAME_DEATH_ENDING_REASON_TIMEOUT);
|
|
_game_user_wants_to_quit = 2;
|
|
}
|
|
|
|
// FIXME: This condition will never be true.
|
|
if (v1) {
|
|
gameTimeEventProcess(NULL, NULL);
|
|
}
|
|
}
|
|
|
|
// 0x4A3518
|
|
void gameTimeAddSeconds(int seconds)
|
|
{
|
|
// NOTE: Uninline.
|
|
gameTimeAddTicks(seconds * 10);
|
|
}
|
|
|
|
// 0x4A3570
|
|
int gameTimeScheduleUpdateEvent()
|
|
{
|
|
int v1 = 10 * (60 * (60 - (gGameTime / 600) % 60 - 1) + 3600 * (24 - (gGameTime / 600) / 60 % 24 - 1) + 60);
|
|
if (queueAddEvent(v1, NULL, NULL, EVENT_TYPE_GAME_TIME) == -1) {
|
|
return -1;
|
|
}
|
|
|
|
if (gMapHeader.name[0] != '\0') {
|
|
if (queueAddEvent(600, NULL, NULL, EVENT_TYPE_MAP_UPDATE_EVENT) == -1) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A3620
|
|
int gameTimeEventProcess(Object* obj, void* data)
|
|
{
|
|
int movie_index;
|
|
int v4;
|
|
|
|
movie_index = -1;
|
|
|
|
debugPrint("\nQUEUE PROCESS: Midnight!");
|
|
|
|
if (gameMovieIsPlaying()) {
|
|
return 0;
|
|
}
|
|
|
|
objectUnjamAll();
|
|
|
|
if (!_gdialogActive()) {
|
|
_scriptsCheckGameEvents(&movie_index, -1);
|
|
}
|
|
|
|
v4 = _critter_check_rads(gDude);
|
|
|
|
_queue_clear_type(4, 0);
|
|
|
|
gameTimeScheduleUpdateEvent();
|
|
|
|
if (movie_index != -1) {
|
|
v4 = 1;
|
|
}
|
|
|
|
return v4;
|
|
}
|
|
|
|
// 0x4A3690
|
|
int _scriptsCheckGameEvents(int* moviePtr, int window)
|
|
{
|
|
int movie = -1;
|
|
int movieFlags = GAME_MOVIE_FADE_IN | GAME_MOVIE_FADE_OUT | GAME_MOVIE_PAUSE_MUSIC;
|
|
bool endgame = false;
|
|
bool adjustRep = false;
|
|
|
|
int day = gGameTime / GAME_TIME_TICKS_PER_DAY;
|
|
|
|
if (gameGetGlobalVar(GVAR_ENEMY_ARROYO)) {
|
|
movie = MOVIE_AFAILED;
|
|
movieFlags = GAME_MOVIE_FADE_IN | GAME_MOVIE_STOP_MUSIC;
|
|
endgame = true;
|
|
} else {
|
|
if (day >= 360 || gameGetGlobalVar(GVAR_FALLOUT_2) >= 3) {
|
|
movie = MOVIE_ARTIMER4;
|
|
if (!gameMovieIsSeen(MOVIE_ARTIMER4)) {
|
|
adjustRep = true;
|
|
_wmAreaSetVisibleState(CITY_ARROYO, 0, 1);
|
|
_wmAreaSetVisibleState(CITY_DESTROYED_ARROYO, 1, 1);
|
|
_wmAreaMarkVisitedState(CITY_DESTROYED_ARROYO, 2);
|
|
}
|
|
} else if (day >= 270 && gameGetGlobalVar(GVAR_FALLOUT_2) != 3) {
|
|
adjustRep = true;
|
|
movie = MOVIE_ARTIMER3;
|
|
} else if (day >= 180 && gameGetGlobalVar(GVAR_FALLOUT_2) != 3) {
|
|
adjustRep = true;
|
|
movie = MOVIE_ARTIMER2;
|
|
} else if (day >= 90 && gameGetGlobalVar(GVAR_FALLOUT_2) != 3) {
|
|
adjustRep = true;
|
|
movie = MOVIE_ARTIMER1;
|
|
}
|
|
}
|
|
|
|
if (movie != -1) {
|
|
if (gameMovieIsSeen(movie)) {
|
|
movie = -1;
|
|
} else {
|
|
if (window != -1) {
|
|
windowHide(window);
|
|
}
|
|
|
|
gameMoviePlay(movie, movieFlags);
|
|
|
|
if (window != -1) {
|
|
windowUnhide(window);
|
|
}
|
|
|
|
if (adjustRep) {
|
|
int rep = gameGetGlobalVar(GVAR_TOWN_REP_ARROYO);
|
|
gameSetGlobalVar(GVAR_TOWN_REP_ARROYO, rep - 15);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (endgame) {
|
|
_game_user_wants_to_quit = 2;
|
|
} else {
|
|
tileWindowRefresh();
|
|
}
|
|
|
|
if (moviePtr != NULL) {
|
|
*moviePtr = movie;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A382C
|
|
int mapUpdateEventProcess(Object* obj, void* data)
|
|
{
|
|
scriptsExecMapUpdateScripts(SCRIPT_PROC_MAP_UPDATE);
|
|
|
|
_queue_clear_type(EVENT_TYPE_MAP_UPDATE_EVENT, NULL);
|
|
|
|
if (gMapHeader.name[0] == '\0') {
|
|
return 0;
|
|
}
|
|
|
|
if (queueAddEvent(600, NULL, NULL, EVENT_TYPE_MAP_UPDATE_EVENT) != -1) {
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// new_obj_id
|
|
// 0x4A386C
|
|
int scriptsNewObjectId()
|
|
{
|
|
Object* ptr;
|
|
|
|
do {
|
|
_cur_id++;
|
|
ptr = objectFindFirst();
|
|
|
|
while (ptr) {
|
|
if (_cur_id == ptr->id) {
|
|
break;
|
|
}
|
|
|
|
ptr = objectFindNext();
|
|
}
|
|
} while (ptr);
|
|
|
|
if (_cur_id >= 18000) {
|
|
debugPrint("\n ERROR: new_obj_id() !!!! Picked PLAYER ID!!!!");
|
|
}
|
|
|
|
_cur_id++;
|
|
|
|
return _cur_id;
|
|
}
|
|
|
|
// 0x4A390C
|
|
int scriptGetSid(Program* program)
|
|
{
|
|
for (int type = 0; type < SCRIPT_TYPE_COUNT; type++) {
|
|
ScriptListExtent* extent = gScriptLists[type].head;
|
|
while (extent != NULL) {
|
|
for (int index = 0; index < extent->length; index++) {
|
|
Script* script = &(extent->scripts[index]);
|
|
if (script->program == program) {
|
|
return script->sid;
|
|
}
|
|
}
|
|
extent = extent->next;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// 0x4A39AC
|
|
Object* scriptGetSelf(Program* program)
|
|
{
|
|
int sid = scriptGetSid(program);
|
|
|
|
Script* script;
|
|
if (scriptGetScript(sid, &script) == -1) {
|
|
return NULL;
|
|
}
|
|
|
|
if (script->owner != NULL) {
|
|
return script->owner;
|
|
}
|
|
|
|
if ((sid >> 24) != SCRIPT_TYPE_SPATIAL) {
|
|
return NULL;
|
|
}
|
|
|
|
Object* object;
|
|
int fid = buildFid(6, 3, 0, 0, 0);
|
|
objectCreateWithFidPid(&object, fid, -1);
|
|
objectHide(object, NULL);
|
|
_obj_toggle_flat(object, NULL);
|
|
object->sid = sid;
|
|
|
|
// NOTE: Redundant, we've already obtained script earlier. Probably
|
|
// inlining.
|
|
Script* v1;
|
|
if (scriptGetScript(sid, &v1) == -1) {
|
|
// FIXME: this is clearly an error, but I guess it's never reached since
|
|
// we've already obtained script for given sid earlier.
|
|
return (Object*)-1;
|
|
}
|
|
|
|
object->id = scriptsNewObjectId();
|
|
v1->field_1C = object->id;
|
|
v1->owner = object;
|
|
|
|
for (int elevation = 0; elevation < ELEVATION_COUNT; elevation++) {
|
|
Script* spatialScript = scriptGetFirstSpatialScript(elevation);
|
|
while (spatialScript != NULL) {
|
|
if (spatialScript == script) {
|
|
objectSetLocation(object, script->sp.built_tile & 0x3FFFFFF, elevation, NULL);
|
|
return object;
|
|
}
|
|
spatialScript = scriptGetNextSpatialScript();
|
|
}
|
|
}
|
|
|
|
return object;
|
|
}
|
|
|
|
// 0x4A3B0C
|
|
int scriptSetObjects(int sid, Object* source, Object* target)
|
|
{
|
|
Script* script;
|
|
if (scriptGetScript(sid, &script) == -1) {
|
|
return -1;
|
|
}
|
|
|
|
script->source = source;
|
|
script->target = target;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A3B34
|
|
void scriptSetFixedParam(int sid, int value)
|
|
{
|
|
Script* script;
|
|
if (scriptGetScript(sid, &script) != -1) {
|
|
script->fixedParam = value;
|
|
}
|
|
}
|
|
|
|
// 0x4A3B54
|
|
int scriptSetActionBeingUsed(int sid, int value)
|
|
{
|
|
Script* scr;
|
|
|
|
if (scriptGetScript(sid, &scr) == -1) {
|
|
return -1;
|
|
}
|
|
|
|
scr->actionBeingUsed = value;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A3B74
|
|
Program* scriptsCreateProgramByName(const char* name)
|
|
{
|
|
char path[MAX_PATH];
|
|
|
|
strcpy(path, _cd_path_base);
|
|
strcat(path, gScriptsBasePath);
|
|
strcat(path, name);
|
|
strcat(path, ".int");
|
|
|
|
return programCreateByPath(path);
|
|
}
|
|
|
|
// 0x4A3C2C
|
|
void _doBkProcesses()
|
|
{
|
|
if (!_set) {
|
|
_lasttime = _get_bk_time();
|
|
_set = 1;
|
|
}
|
|
|
|
int v0 = _get_bk_time();
|
|
if (gScriptsEnabled) {
|
|
_lasttime = v0;
|
|
|
|
// NOTE: There is a loop at 0x4A3C64, consisting of one iteration, going
|
|
// downwards from 1.
|
|
for (int index = 0; index < 1; index++) {
|
|
_updatePrograms();
|
|
}
|
|
}
|
|
|
|
_updateWindows();
|
|
|
|
if (gScriptsEnabled && _script_engine_run_critters) {
|
|
// SFALL: Fix to prevent the execution of critter_p_proc and game events
|
|
// when playing movies.
|
|
if (!_gdialogActive() && !gameMovieIsPlaying()) {
|
|
_script_chk_critters();
|
|
_script_chk_timed_events();
|
|
}
|
|
}
|
|
}
|
|
|
|
// 0x4A3CA0
|
|
void _script_chk_critters()
|
|
{
|
|
if (!_gdialogActive() && !isInCombat()) {
|
|
ScriptList* scriptList;
|
|
ScriptListExtent* scriptListExtent;
|
|
|
|
int scriptsCount = 0;
|
|
|
|
scriptList = &(gScriptLists[SCRIPT_TYPE_CRITTER]);
|
|
scriptListExtent = scriptList->head;
|
|
while (scriptListExtent != NULL) {
|
|
scriptsCount += scriptListExtent->length;
|
|
scriptListExtent = scriptListExtent->next;
|
|
}
|
|
|
|
_count_ += 1;
|
|
if (_count_ >= scriptsCount) {
|
|
_count_ = 0;
|
|
}
|
|
|
|
if (_count_ < scriptsCount) {
|
|
int proc = isInCombat() ? SCRIPT_PROC_COMBAT : SCRIPT_PROC_CRITTER;
|
|
int extentIndex = _count_ / SCRIPT_LIST_EXTENT_SIZE;
|
|
int scriptIndex = _count_ % SCRIPT_LIST_EXTENT_SIZE;
|
|
|
|
scriptList = &(gScriptLists[SCRIPT_TYPE_CRITTER]);
|
|
scriptListExtent = scriptList->head;
|
|
while (scriptListExtent != NULL && extentIndex != 0) {
|
|
extentIndex -= 1;
|
|
scriptListExtent = scriptListExtent->next;
|
|
}
|
|
|
|
if (scriptListExtent != NULL) {
|
|
Script* script = &(scriptListExtent->scripts[scriptIndex]);
|
|
scriptExecProc(script->sid, proc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: Check.
|
|
//
|
|
// 0x4A3D84
|
|
void _script_chk_timed_events()
|
|
{
|
|
int v0 = _get_bk_time();
|
|
|
|
int v1 = false;
|
|
if (!isInCombat()) {
|
|
v1 = true;
|
|
}
|
|
|
|
if (_game_state() != 4) {
|
|
if (getTicksBetween(v0, _last_light_time) >= 30000) {
|
|
_last_light_time = v0;
|
|
scriptsExecMapUpdateScripts(SCRIPT_PROC_MAP_UPDATE);
|
|
}
|
|
} else {
|
|
v1 = false;
|
|
}
|
|
|
|
if (getTicksBetween(v0, _last_time__) >= 100) {
|
|
_last_time__ = v0;
|
|
if (!isInCombat()) {
|
|
gGameTime += 1;
|
|
}
|
|
v1 = true;
|
|
}
|
|
|
|
if (v1) {
|
|
while (!queueIsEmpty()) {
|
|
int time = gameTimeGetTime();
|
|
int v2 = queueGetNextEventTime();
|
|
if (time < v2) {
|
|
break;
|
|
}
|
|
|
|
queueProcessEvents();
|
|
}
|
|
}
|
|
}
|
|
|
|
// 0x4A3E30
|
|
void _scrSetQueueTestVals(Object* a1, int a2)
|
|
{
|
|
_scrQueueTestObj = a1;
|
|
_scrQueueTestValue = a2;
|
|
}
|
|
|
|
// 0x4A3E3C
|
|
int _scrQueueRemoveFixed(Object* obj, void* data)
|
|
{
|
|
ScriptEvent* scriptEvent = (ScriptEvent*)data;
|
|
return obj == _scrQueueTestObj && scriptEvent->field_4 == _scrQueueTestValue;
|
|
}
|
|
|
|
// 0x4A3E60
|
|
int scriptAddTimerEvent(int sid, int delay, int param)
|
|
{
|
|
ScriptEvent* scriptEvent = (ScriptEvent*)internal_malloc(sizeof(*scriptEvent));
|
|
if (scriptEvent == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
scriptEvent->sid = sid;
|
|
scriptEvent->field_4 = param;
|
|
|
|
Script* script;
|
|
if (scriptGetScript(sid, &script) == -1) {
|
|
internal_free(scriptEvent);
|
|
return -1;
|
|
}
|
|
|
|
if (queueAddEvent(delay, script->owner, scriptEvent, EVENT_TYPE_SCRIPT) == -1) {
|
|
internal_free(scriptEvent);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A3EDC
|
|
int scriptEventWrite(File* stream, void* data)
|
|
{
|
|
ScriptEvent* scriptEvent = (ScriptEvent*)data;
|
|
|
|
if (fileWriteInt32(stream, scriptEvent->sid) == -1) return -1;
|
|
if (fileWriteInt32(stream, scriptEvent->field_4) == -1) return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A3F04
|
|
int scriptEventRead(File* stream, void** dataPtr)
|
|
{
|
|
ScriptEvent* scriptEvent = (ScriptEvent*)internal_malloc(sizeof(*scriptEvent));
|
|
if (scriptEvent == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (fileReadInt32(stream, &(scriptEvent->sid)) == -1) goto err;
|
|
if (fileReadInt32(stream, &(scriptEvent->field_4)) == -1) goto err;
|
|
|
|
*dataPtr = scriptEvent;
|
|
|
|
return 0;
|
|
|
|
err:
|
|
|
|
// there is a memory leak in original code, free is not called
|
|
internal_free(scriptEvent);
|
|
|
|
return -1;
|
|
}
|
|
|
|
// 0x4A3F4C
|
|
int scriptEventProcess(Object* obj, void* data)
|
|
{
|
|
ScriptEvent* scriptEvent = (ScriptEvent*)data;
|
|
|
|
Script* script;
|
|
if (scriptGetScript(scriptEvent->sid, &script) == -1) {
|
|
return 0;
|
|
}
|
|
|
|
script->fixedParam = scriptEvent->field_4;
|
|
|
|
scriptExecProc(scriptEvent->sid, SCRIPT_PROC_TIMED);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A3F80
|
|
int scriptsClearPendingRequests()
|
|
{
|
|
gScriptsRequests = 0;
|
|
return 0;
|
|
}
|
|
|
|
// NOTE: Inlined.
|
|
//
|
|
// 0x4A3F90
|
|
int _scripts_clear_combat_requests(Script* script)
|
|
{
|
|
if ((gScriptsRequests & SCRIPT_REQUEST_COMBAT) != 0 && stru_664958.attacker == script->owner) {
|
|
gScriptsRequests &= ~(SCRIPT_REQUEST_0x0400 | SCRIPT_REQUEST_COMBAT);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A3FB4
|
|
int scriptsHandleRequests()
|
|
{
|
|
if (gScriptsRequests == 0) {
|
|
return 0;
|
|
}
|
|
|
|
if ((gScriptsRequests & SCRIPT_REQUEST_COMBAT) != 0) {
|
|
if (!_action_explode_running()) {
|
|
// entering combat
|
|
gScriptsRequests &= ~(SCRIPT_REQUEST_0x0400 | SCRIPT_REQUEST_COMBAT);
|
|
memcpy(&stru_664980, &stru_664958, sizeof(stru_664980));
|
|
|
|
if ((gScriptsRequests & SCRIPT_REQUEST_0x40) != 0) {
|
|
gScriptsRequests &= ~SCRIPT_REQUEST_0x40;
|
|
_combat(NULL);
|
|
} else {
|
|
_combat(&stru_664980);
|
|
memset(&stru_664980, 0, sizeof(stru_664980));
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((gScriptsRequests & SCRIPT_REQUEST_0x02) != 0) {
|
|
gScriptsRequests &= ~SCRIPT_REQUEST_0x02;
|
|
_wmTownMap();
|
|
}
|
|
|
|
if ((gScriptsRequests & SCRIPT_REQUEST_WORLD_MAP) != 0) {
|
|
gScriptsRequests &= ~SCRIPT_REQUEST_WORLD_MAP;
|
|
_wmWorldMap();
|
|
}
|
|
|
|
if ((gScriptsRequests & SCRIPT_REQUEST_ELEVATOR) != 0) {
|
|
int map = gMapHeader.field_34;
|
|
int elevation = gScriptsRequestedElevatorLevel;
|
|
int tile = -1;
|
|
|
|
gScriptsRequests &= ~SCRIPT_REQUEST_ELEVATOR;
|
|
|
|
if (elevatorSelectLevel(gScriptsRequestedElevatorType, &map, &elevation, &tile) != -1) {
|
|
automapSaveCurrent();
|
|
|
|
if (map == gMapHeader.field_34) {
|
|
if (elevation == gElevation) {
|
|
reg_anim_clear(gDude);
|
|
objectSetRotation(gDude, ROTATION_SE, 0);
|
|
_obj_attempt_placement(gDude, tile, elevation, 0);
|
|
} else {
|
|
Object* elevatorDoors = objectFindFirstAtElevation(gDude->elevation);
|
|
while (elevatorDoors != NULL) {
|
|
int pid = elevatorDoors->pid;
|
|
if ((pid >> 24) == OBJ_TYPE_SCENERY
|
|
&& (pid == PROTO_ID_0x2000099 || pid == PROTO_ID_0x20001A5 || pid == PROTO_ID_0x20001D6)
|
|
&& tileDistanceBetween(elevatorDoors->tile, gDude->tile) <= 4) {
|
|
break;
|
|
}
|
|
elevatorDoors = objectFindNextAtElevation();
|
|
}
|
|
|
|
reg_anim_clear(gDude);
|
|
objectSetRotation(gDude, ROTATION_SE, 0);
|
|
_obj_attempt_placement(gDude, tile, elevation, 0);
|
|
|
|
if (elevatorDoors != NULL) {
|
|
objectSetFrame(elevatorDoors, 0, NULL);
|
|
objectSetLocation(elevatorDoors, elevatorDoors->tile, elevatorDoors->elevation, NULL);
|
|
elevatorDoors->flags &= ~OBJECT_OPEN_DOOR;
|
|
elevatorDoors->data.scenery.door.openFlags &= ~0x01;
|
|
_obj_rebuild_all_light();
|
|
} else {
|
|
debugPrint("\nWarning: Elevator: Couldn't find old elevator doors!");
|
|
}
|
|
}
|
|
} else {
|
|
Object* elevatorDoors = objectFindFirstAtElevation(gDude->elevation);
|
|
while (elevatorDoors != NULL) {
|
|
int pid = elevatorDoors->pid;
|
|
if ((pid >> 24) == OBJ_TYPE_SCENERY
|
|
&& (pid == PROTO_ID_0x2000099 || pid == PROTO_ID_0x20001A5 || pid == PROTO_ID_0x20001D6)
|
|
&& tileDistanceBetween(elevatorDoors->tile, gDude->tile) <= 4) {
|
|
break;
|
|
}
|
|
elevatorDoors = objectFindNextAtElevation();
|
|
}
|
|
|
|
if (elevatorDoors != NULL) {
|
|
objectSetFrame(elevatorDoors, 0, NULL);
|
|
objectSetLocation(elevatorDoors, elevatorDoors->tile, elevatorDoors->elevation, NULL);
|
|
elevatorDoors->flags &= ~OBJECT_OPEN_DOOR;
|
|
elevatorDoors->data.scenery.door.openFlags &= ~0x01;
|
|
_obj_rebuild_all_light();
|
|
} else {
|
|
debugPrint("\nWarning: Elevator: Couldn't find old elevator doors!");
|
|
}
|
|
|
|
MapTransition transition;
|
|
memset(&transition, 0, sizeof(transition));
|
|
|
|
transition.map = map;
|
|
transition.elevation = elevation;
|
|
transition.tile = tile;
|
|
transition.rotation = ROTATION_SE;
|
|
|
|
mapSetTransition(&transition);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((gScriptsRequests & SCRIPT_REQUEST_EXPLOSION) != 0) {
|
|
gScriptsRequests &= ~SCRIPT_REQUEST_EXPLOSION;
|
|
actionExplode(gScriptsRequestedExplosionTile, gScriptsRequestedExplosionElevation, gScriptsRequestedExplosionMinDamage, gScriptsRequestedExplosionMaxDamage, NULL, 1);
|
|
}
|
|
|
|
if ((gScriptsRequests & SCRIPT_REQUEST_DIALOG) != 0) {
|
|
gScriptsRequests &= ~SCRIPT_REQUEST_DIALOG;
|
|
gameDialogEnter(gScriptsRequestedDialogWith, 0);
|
|
}
|
|
|
|
if ((gScriptsRequests & SCRIPT_REQUEST_ENDGAME) != 0) {
|
|
gScriptsRequests &= ~SCRIPT_REQUEST_ENDGAME;
|
|
endgamePlaySlideshow();
|
|
endgamePlayMovie();
|
|
}
|
|
|
|
if ((gScriptsRequests & SCRIPT_REQUEST_LOOTING) != 0) {
|
|
gScriptsRequests &= ~SCRIPT_REQUEST_LOOTING;
|
|
inventoryOpenLooting(gScriptsRequestedLootingBy, gScriptsRequestedLootingFrom);
|
|
}
|
|
|
|
if ((gScriptsRequests & SCRIPT_REQUEST_STEALING) != 0) {
|
|
gScriptsRequests &= ~SCRIPT_REQUEST_STEALING;
|
|
inventoryOpenStealing(gScriptsRequestedStealingBy, gScriptsRequestedStealingFrom);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A43A0
|
|
int _scripts_check_state_in_combat()
|
|
{
|
|
if ((gScriptsRequests & SCRIPT_REQUEST_ELEVATOR) != 0) {
|
|
int map = gMapHeader.field_34;
|
|
int elevation = gScriptsRequestedElevatorLevel;
|
|
int tile = -1;
|
|
|
|
if (elevatorSelectLevel(gScriptsRequestedElevatorType, &map, &elevation, &tile) != -1) {
|
|
automapSaveCurrent();
|
|
|
|
if (map == gMapHeader.field_34) {
|
|
if (elevation == gElevation) {
|
|
reg_anim_clear(gDude);
|
|
objectSetRotation(gDude, ROTATION_SE, 0);
|
|
_obj_attempt_placement(gDude, tile, elevation, 0);
|
|
} else {
|
|
Object* elevatorDoors = objectFindFirstAtElevation(gDude->elevation);
|
|
while (elevatorDoors != NULL) {
|
|
int pid = elevatorDoors->pid;
|
|
if ((pid >> 24) == OBJ_TYPE_SCENERY
|
|
&& (pid == PROTO_ID_0x2000099 || pid == PROTO_ID_0x20001A5 || pid == PROTO_ID_0x20001D6)
|
|
&& tileDistanceBetween(elevatorDoors->tile, gDude->tile) <= 4) {
|
|
break;
|
|
}
|
|
elevatorDoors = objectFindNextAtElevation();
|
|
}
|
|
|
|
reg_anim_clear(gDude);
|
|
objectSetRotation(gDude, ROTATION_SE, 0);
|
|
_obj_attempt_placement(gDude, tile, elevation, 0);
|
|
|
|
if (elevatorDoors != NULL) {
|
|
objectSetFrame(elevatorDoors, 0, NULL);
|
|
objectSetLocation(elevatorDoors, elevatorDoors->tile, elevatorDoors->elevation, NULL);
|
|
elevatorDoors->flags &= ~OBJECT_OPEN_DOOR;
|
|
elevatorDoors->data.scenery.door.openFlags &= ~0x01;
|
|
_obj_rebuild_all_light();
|
|
} else {
|
|
debugPrint("\nWarning: Elevator: Couldn't find old elevator doors!");
|
|
}
|
|
}
|
|
} else {
|
|
MapTransition transition;
|
|
memset(&transition, 0, sizeof(transition));
|
|
|
|
transition.map = map;
|
|
transition.elevation = elevation;
|
|
transition.tile = tile;
|
|
transition.rotation = ROTATION_SE;
|
|
|
|
mapSetTransition(&transition);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((gScriptsRequests & SCRIPT_REQUEST_LOOTING) != 0) {
|
|
inventoryOpenLooting(gScriptsRequestedLootingBy, gScriptsRequestedLootingFrom);
|
|
}
|
|
|
|
// NOTE: Uninline.
|
|
scriptsClearPendingRequests();
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A457C
|
|
int scriptsRequestCombat(STRUCT_664980* a1)
|
|
{
|
|
if ((gScriptsRequests & SCRIPT_REQUEST_0x0400) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (a1) {
|
|
memcpy(&stru_664958, a1, sizeof(stru_664958));
|
|
} else {
|
|
gScriptsRequests |= SCRIPT_REQUEST_0x40;
|
|
}
|
|
|
|
gScriptsRequests |= SCRIPT_REQUEST_COMBAT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Likely related to random encounter, ala scriptsRequestRandomEncounter RELEASE
|
|
//
|
|
// 0x4A45D4
|
|
void _scripts_request_combat_locked(STRUCT_664980* a1)
|
|
{
|
|
if (a1 != NULL) {
|
|
memcpy(&stru_664958, a1, sizeof(stru_664958));
|
|
} else {
|
|
gScriptsRequests |= SCRIPT_REQUEST_0x40;
|
|
}
|
|
|
|
gScriptsRequests |= (SCRIPT_REQUEST_0x0400 | SCRIPT_REQUEST_COMBAT);
|
|
}
|
|
|
|
// request_world_map()
|
|
// 0x4A4644
|
|
void scriptsRequestWorldMap()
|
|
{
|
|
if (isInCombat()) {
|
|
_game_user_wants_to_quit = 1;
|
|
}
|
|
|
|
gScriptsRequests |= SCRIPT_REQUEST_WORLD_MAP;
|
|
}
|
|
|
|
// scripts_request_elevator
|
|
// 0x4A466C
|
|
int scriptsRequestElevator(Object* a1, int a2)
|
|
{
|
|
int elevatorType = a2;
|
|
int elevatorLevel = gElevation;
|
|
|
|
int tile = a1->tile;
|
|
if (tile == -1) {
|
|
debugPrint("\nError: scripts_request_elevator! Bad tile num");
|
|
return -1;
|
|
}
|
|
|
|
// TODO: What the hell is this?
|
|
tile -= 1005;
|
|
|
|
Object* obj;
|
|
for (int y = -5; y < 5; y++) {
|
|
for (int x = -5; x < 5; x++) {
|
|
obj = objectFindFirstAtElevation(a1->elevation);
|
|
while (obj != NULL) {
|
|
if (tile == obj->tile && obj->pid == PROTO_ID_0x200050D) {
|
|
break;
|
|
}
|
|
|
|
obj = objectFindNextAtElevation();
|
|
}
|
|
|
|
if (obj != NULL) {
|
|
break;
|
|
}
|
|
|
|
tile += 1;
|
|
}
|
|
|
|
if (obj != NULL) {
|
|
break;
|
|
}
|
|
|
|
tile += 190;
|
|
}
|
|
|
|
if (obj != NULL) {
|
|
elevatorType = obj->data.scenery.elevator.field_0;
|
|
elevatorLevel = obj->data.scenery.elevator.field_4;
|
|
}
|
|
|
|
if (elevatorType == -1) {
|
|
return -1;
|
|
}
|
|
|
|
gScriptsRequests |= SCRIPT_REQUEST_ELEVATOR;
|
|
gScriptsRequestedElevatorType = elevatorType;
|
|
gScriptsRequestedElevatorLevel = elevatorLevel;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A4730
|
|
int scriptsRequestExplosion(int tile, int elevation, int minDamage, int maxDamage)
|
|
{
|
|
gScriptsRequests |= SCRIPT_REQUEST_EXPLOSION;
|
|
gScriptsRequestedExplosionTile = tile;
|
|
gScriptsRequestedExplosionElevation = elevation;
|
|
gScriptsRequestedExplosionMinDamage = minDamage;
|
|
gScriptsRequestedExplosionMaxDamage = maxDamage;
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A4754
|
|
void scriptsRequestDialog(Object* obj)
|
|
{
|
|
gScriptsRequestedDialogWith = obj;
|
|
gScriptsRequests |= SCRIPT_REQUEST_DIALOG;
|
|
}
|
|
|
|
// 0x4A4770
|
|
void scriptsRequestEndgame()
|
|
{
|
|
gScriptsRequests |= SCRIPT_REQUEST_ENDGAME;
|
|
}
|
|
|
|
// 0x4A477C
|
|
int scriptsRequestLooting(Object* a1, Object* a2)
|
|
{
|
|
gScriptsRequestedLootingBy = a1;
|
|
gScriptsRequestedLootingFrom = a2;
|
|
gScriptsRequests |= SCRIPT_REQUEST_LOOTING;
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A479C
|
|
int scriptsRequestStealing(Object* a1, Object* a2)
|
|
{
|
|
gScriptsRequestedStealingBy = a1;
|
|
gScriptsRequestedStealingFrom = a2;
|
|
gScriptsRequests |= SCRIPT_REQUEST_STEALING;
|
|
return 0;
|
|
}
|
|
|
|
// exec_script_proc
|
|
// 0x4A4810
|
|
int scriptExecProc(int sid, int proc)
|
|
{
|
|
if (!gScriptsEnabled) {
|
|
return -1;
|
|
}
|
|
|
|
Script* script;
|
|
if (scriptGetScript(sid, &script) == -1) {
|
|
return -1;
|
|
}
|
|
|
|
script->scriptOverrides = 0;
|
|
|
|
bool programLoaded = false;
|
|
if ((script->flags & SCRIPT_FLAG_0x01) == 0) {
|
|
clock();
|
|
|
|
char name[16];
|
|
if (scriptsGetFileName(script->field_14 & 0xFFFFFF, name) == -1) {
|
|
return -1;
|
|
}
|
|
|
|
char* pch = strchr(name, '.');
|
|
if (pch != NULL) {
|
|
*pch = '\0';
|
|
}
|
|
|
|
script->program = scriptsCreateProgramByName(name);
|
|
if (script->program == NULL) {
|
|
debugPrint("\nError: exec_script_proc: script load failed!");
|
|
return -1;
|
|
}
|
|
|
|
programLoaded = true;
|
|
script->flags |= SCRIPT_FLAG_0x01;
|
|
}
|
|
|
|
Program* program = script->program;
|
|
if (program == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if ((program->flags & 0x0124) != 0) {
|
|
return 0;
|
|
}
|
|
|
|
int v9 = script->procs[proc];
|
|
if (v9 == 0) {
|
|
v9 = 1;
|
|
}
|
|
|
|
if (v9 == -1) {
|
|
return -1;
|
|
}
|
|
|
|
if (script->target == NULL) {
|
|
script->target = script->owner;
|
|
}
|
|
|
|
script->flags |= SCRIPT_FLAG_0x04;
|
|
|
|
if (programLoaded) {
|
|
scriptLocateProcs(script);
|
|
|
|
v9 = script->procs[proc];
|
|
if (v9 == 0) {
|
|
v9 = 1;
|
|
}
|
|
|
|
script->action = 0;
|
|
programListNodeCreate(program);
|
|
_interpret(program, -1);
|
|
}
|
|
|
|
script->action = proc;
|
|
|
|
_executeProcedure(program, v9);
|
|
|
|
script->source = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Locate built-in procs for given script.
|
|
//
|
|
// 0x4A49D0
|
|
int scriptLocateProcs(Script* script)
|
|
{
|
|
for (int proc = 0; proc < SCRIPT_PROC_COUNT; proc++) {
|
|
int index = programFindProcedure(script->program, gScriptProcNames[proc]);
|
|
if (index == -1) {
|
|
index = SCRIPT_PROC_NO_PROC;
|
|
}
|
|
script->procs[proc] = index;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A4A08
|
|
bool scriptHasProc(int sid, int proc)
|
|
{
|
|
Script* scr;
|
|
|
|
if (scriptGetScript(sid, &scr) == -1) {
|
|
return 0;
|
|
}
|
|
|
|
return scr->procs[proc] != SCRIPT_PROC_NO_PROC;
|
|
}
|
|
|
|
// 0x4A4D50
|
|
int scriptsLoadScriptsList()
|
|
{
|
|
char path[MAX_PATH];
|
|
sprintf(path, "%s%s", "scripts\\", "scripts.lst");
|
|
|
|
File* stream = fileOpen(path, "rt");
|
|
if (stream == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
char string[260];
|
|
while (fileReadString(string, 260, stream)) {
|
|
gScriptsListEntriesLength++;
|
|
|
|
ScriptsListEntry* entries = (ScriptsListEntry*)internal_realloc(gScriptsListEntries, sizeof(*entries) * gScriptsListEntriesLength);
|
|
if (entries == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
gScriptsListEntries = entries;
|
|
|
|
ScriptsListEntry* entry = &(entries[gScriptsListEntriesLength - 1]);
|
|
entry->local_vars_num = 0;
|
|
|
|
char* substr = strstr(string, ".int");
|
|
if (substr != NULL) {
|
|
int length = substr - string;
|
|
if (length > 13) {
|
|
return -1;
|
|
}
|
|
|
|
strncpy(entry->name, string, 13);
|
|
entry->name[length] = '\0';
|
|
}
|
|
|
|
if (strstr(string, "#") != NULL) {
|
|
substr = strstr(string, "local_vars=");
|
|
if (substr != NULL) {
|
|
entry->local_vars_num = atoi(substr + 11);
|
|
}
|
|
}
|
|
}
|
|
|
|
fileClose(stream);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// NOTE: Inlined.
|
|
//
|
|
// 0x4A4EFC
|
|
int scriptsFreeScriptsList()
|
|
{
|
|
if (gScriptsListEntries != NULL) {
|
|
internal_free(gScriptsListEntries);
|
|
gScriptsListEntries = NULL;
|
|
}
|
|
|
|
gScriptsListEntriesLength = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A4F28
|
|
int _scr_find_str_run_info(int scriptIndex, int* a2, int sid)
|
|
{
|
|
Script* script;
|
|
if (scriptGetScript(sid, &script) == -1) {
|
|
return -1;
|
|
}
|
|
|
|
script->localVarsCount = gScriptsListEntries[scriptIndex].local_vars_num;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A4F68
|
|
int scriptsGetFileName(int scriptIndex, char* name)
|
|
{
|
|
sprintf(name, "%s.int", gScriptsListEntries[scriptIndex].name);
|
|
return 0;
|
|
}
|
|
|
|
// scr_set_dude_script
|
|
// 0x4A4F90
|
|
int scriptsSetDudeScript()
|
|
{
|
|
if (scriptsClearDudeScript() == -1) {
|
|
return -1;
|
|
}
|
|
|
|
if (gDude == NULL) {
|
|
debugPrint("Error in scr_set_dude_script: obj_dude uninitialized!");
|
|
return -1;
|
|
}
|
|
|
|
Proto* proto;
|
|
if (protoGetProto(0x1000000, &proto) == -1) {
|
|
debugPrint("Error in scr_set_dude_script: can't find obj_dude proto!");
|
|
return -1;
|
|
}
|
|
|
|
proto->critter.sid = 0x4000000;
|
|
|
|
_obj_new_sid(gDude, &(gDude->sid));
|
|
|
|
Script* script;
|
|
if (scriptGetScript(gDude->sid, &script) == -1) {
|
|
debugPrint("Error in scr_set_dude_script: can't find obj_dude script!");
|
|
return -1;
|
|
}
|
|
|
|
script->flags |= (SCRIPT_FLAG_0x08 | SCRIPT_FLAG_0x10);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// scr_clear_dude_script
|
|
// 0x4A5044
|
|
int scriptsClearDudeScript()
|
|
{
|
|
if (gDude == NULL) {
|
|
debugPrint("\nError in scr_clear_dude_script: obj_dude uninitialized!");
|
|
return -1;
|
|
}
|
|
|
|
if (gDude->sid != -1) {
|
|
Script* script;
|
|
if (scriptGetScript(gDude->sid, &script) != -1) {
|
|
script->flags &= ~(SCRIPT_FLAG_0x08 | SCRIPT_FLAG_0x10);
|
|
}
|
|
|
|
scriptRemove(gDude->sid);
|
|
|
|
gDude->sid = -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// scr_init
|
|
// 0x4A50A8
|
|
int scriptsInit()
|
|
{
|
|
if (!messageListInit(&gScrMessageList)) {
|
|
return -1;
|
|
}
|
|
|
|
for (int index = 0; index < 1450; index++) {
|
|
if (!messageListInit(&(_script_dialog_msgs[index]))) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
_scr_remove_all();
|
|
_interpretOutputFunc(_win_debug);
|
|
interpreterRegisterOpcodeHandlers();
|
|
_scr_header_load();
|
|
|
|
// NOTE: Uninline.
|
|
scriptsClearPendingRequests();
|
|
|
|
_partyMemberClear();
|
|
|
|
if (scriptsLoadScriptsList() == -1) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A5120
|
|
int _scr_reset()
|
|
{
|
|
_scr_remove_all();
|
|
|
|
// NOTE: Uninline.
|
|
scriptsClearPendingRequests();
|
|
|
|
_partyMemberClear();
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A5138
|
|
int _scr_game_init()
|
|
{
|
|
int i;
|
|
char path[MAX_PATH];
|
|
|
|
if (!messageListInit(&gScrMessageList)) {
|
|
debugPrint("\nError initing script message file!");
|
|
return -1;
|
|
}
|
|
|
|
for (i = 0; i < 1450; i++) {
|
|
if (!messageListInit(&(_script_dialog_msgs[i]))) {
|
|
debugPrint("\nERROR IN SCRIPT_DIALOG_MSGS!");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
sprintf(path, "%s%s", asc_5186C8, "script.msg");
|
|
if (!messageListLoad(&gScrMessageList, path)) {
|
|
debugPrint("\nError loading script message file!");
|
|
return -1;
|
|
}
|
|
|
|
gScriptsEnabled = true;
|
|
_script_engine_game_mode = 1;
|
|
gGameTime = 1;
|
|
gameTimeSetTime(302400);
|
|
tickersAdd(_doBkProcesses);
|
|
|
|
if (scriptsSetDudeScript() == -1) {
|
|
return -1;
|
|
}
|
|
|
|
_scr_SpatialsEnabled = true;
|
|
|
|
// NOTE: Uninline.
|
|
scriptsClearPendingRequests();
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A5240
|
|
int scriptsReset()
|
|
{
|
|
debugPrint("\nScripts: [Game Reset]");
|
|
_scr_game_exit();
|
|
_scr_game_init();
|
|
_partyMemberClear();
|
|
_scr_remove_all_force();
|
|
return scriptsSetDudeScript();
|
|
}
|
|
|
|
// 0x4A5274
|
|
int scriptsExit()
|
|
{
|
|
gScriptsEnabled = false;
|
|
_script_engine_run_critters = 0;
|
|
if (!messageListFree(&gScrMessageList)) {
|
|
debugPrint("\nError exiting script message file!");
|
|
return -1;
|
|
}
|
|
|
|
_scr_remove_all();
|
|
_scr_remove_all_force();
|
|
_interpretClose();
|
|
programListFree();
|
|
|
|
// NOTE: Uninline.
|
|
scriptsClearPendingRequests();
|
|
|
|
// NOTE: Uninline.
|
|
scriptsFreeScriptsList();
|
|
|
|
return 0;
|
|
}
|
|
|
|
// scr_message_free
|
|
// 0x4A52F4
|
|
int _scr_message_free()
|
|
{
|
|
for (int index = 0; index < 1450; index++) {
|
|
MessageList* messageList = &(_script_dialog_msgs[index]);
|
|
if (messageList->entries_num != 0) {
|
|
if (!messageListFree(messageList)) {
|
|
debugPrint("\nERROR in scr_message_free!");
|
|
return -1;
|
|
}
|
|
|
|
if (!messageListInit(messageList)) {
|
|
debugPrint("\nERROR in scr_message_free!");
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A535C
|
|
int _scr_game_exit()
|
|
{
|
|
_script_engine_game_mode = 0;
|
|
gScriptsEnabled = false;
|
|
_script_engine_run_critters = 0;
|
|
_scr_message_free();
|
|
_scr_remove_all();
|
|
programListFree();
|
|
tickersRemove(_doBkProcesses);
|
|
messageListFree(&gScrMessageList);
|
|
if (scriptsClearDudeScript() == -1) {
|
|
return -1;
|
|
}
|
|
|
|
// NOTE: Uninline.
|
|
scriptsClearPendingRequests();
|
|
|
|
return 0;
|
|
}
|
|
|
|
// scr_enable
|
|
// 0x4A53A8
|
|
int scriptsEnable()
|
|
{
|
|
if (!_script_engine_game_mode) {
|
|
return -1;
|
|
}
|
|
|
|
_script_engine_run_critters = 1;
|
|
gScriptsEnabled = true;
|
|
return 0;
|
|
}
|
|
|
|
// scr_disable
|
|
// 0x4A53D0
|
|
int scriptsDisable()
|
|
{
|
|
gScriptsEnabled = false;
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A53E0
|
|
void _scr_enable_critters()
|
|
{
|
|
_script_engine_run_critters = 1;
|
|
}
|
|
|
|
// 0x4A53F0
|
|
void _scr_disable_critters()
|
|
{
|
|
_script_engine_run_critters = 0;
|
|
}
|
|
|
|
// 0x4A5400
|
|
int scriptsSaveGameGlobalVars(File* stream)
|
|
{
|
|
return fileWriteInt32List(stream, gGameGlobalVars, gGameGlobalVarsLength);
|
|
}
|
|
|
|
// 0x4A5424
|
|
int scriptsLoadGameGlobalVars(File* stream)
|
|
{
|
|
return fileReadInt32List(stream, gGameGlobalVars, gGameGlobalVarsLength);
|
|
}
|
|
|
|
// NOTE: For unknown reason save game files contains two identical sets of game
|
|
// global variables (saved with [scriptsSaveGameGlobalVars]). The first set is
|
|
// read with [scriptsLoadGameGlobalVars], the second set is simply thrown away
|
|
// using this function.
|
|
//
|
|
// 0x4A5448
|
|
int scriptsSkipGameGlobalVars(File* stream)
|
|
{
|
|
int* vars = (int*)internal_malloc(sizeof(*vars) * gGameGlobalVarsLength);
|
|
if (vars == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (fileReadInt32List(stream, vars, gGameGlobalVarsLength) == -1) {
|
|
// FIXME: Leaks vars.
|
|
return -1;
|
|
}
|
|
|
|
internal_free(vars);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A5490
|
|
int _scr_header_load()
|
|
{
|
|
_num_script_indexes = 0;
|
|
|
|
char path[MAX_PATH];
|
|
strcpy(path, _cd_path_base);
|
|
strcat(path, gScriptsBasePath);
|
|
strcat(path, "scripts.lst");
|
|
|
|
File* stream = fileOpen(path, "rt");
|
|
if (stream == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
while (1) {
|
|
char ch = fileReadChar(stream);
|
|
if (ch == -1) {
|
|
break;
|
|
}
|
|
|
|
if (ch == '\n') {
|
|
_num_script_indexes++;
|
|
}
|
|
}
|
|
|
|
_num_script_indexes++;
|
|
|
|
fileClose(stream);
|
|
|
|
for (int scriptType = 0; scriptType < SCRIPT_TYPE_COUNT; scriptType++) {
|
|
ScriptList* scriptList = &(gScriptLists[scriptType]);
|
|
scriptList->head = NULL;
|
|
scriptList->tail = NULL;
|
|
scriptList->length = 0;
|
|
scriptList->nextScriptId = 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A5590
|
|
int scriptWrite(Script* scr, File* stream)
|
|
{
|
|
if (fileWriteInt32(stream, scr->sid) == -1) return -1;
|
|
if (fileWriteInt32(stream, scr->field_4) == -1) return -1;
|
|
|
|
switch (scr->sid >> 24) {
|
|
case SCRIPT_TYPE_SPATIAL:
|
|
if (fileWriteInt32(stream, scr->sp.built_tile) == -1) return -1;
|
|
if (fileWriteInt32(stream, scr->sp.radius) == -1) return -1;
|
|
break;
|
|
case SCRIPT_TYPE_TIMED:
|
|
if (fileWriteInt32(stream, scr->tm.time) == -1) return -1;
|
|
break;
|
|
}
|
|
|
|
if (fileWriteInt32(stream, scr->flags) == -1) return -1;
|
|
if (fileWriteInt32(stream, scr->field_14) == -1) return -1;
|
|
if (fileWriteInt32(stream, (int)scr->program) == -1) return -1; // FIXME: writing pointer to file
|
|
if (fileWriteInt32(stream, scr->field_1C) == -1) return -1;
|
|
if (fileWriteInt32(stream, scr->localVarsOffset) == -1) return -1;
|
|
if (fileWriteInt32(stream, scr->localVarsCount) == -1) return -1;
|
|
if (fileWriteInt32(stream, scr->field_28) == -1) return -1;
|
|
if (fileWriteInt32(stream, scr->action) == -1) return -1;
|
|
if (fileWriteInt32(stream, scr->fixedParam) == -1) return -1;
|
|
if (fileWriteInt32(stream, scr->actionBeingUsed) == -1) return -1;
|
|
if (fileWriteInt32(stream, scr->scriptOverrides) == -1) return -1;
|
|
if (fileWriteInt32(stream, scr->field_48) == -1) return -1;
|
|
if (fileWriteInt32(stream, scr->howMuch) == -1) return -1;
|
|
if (fileWriteInt32(stream, scr->field_50) == -1) return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A5704
|
|
int scriptListExtentWrite(ScriptListExtent* a1, File* stream)
|
|
{
|
|
for (int index = 0; index < SCRIPT_LIST_EXTENT_SIZE; index++) {
|
|
Script* script = &(a1->scripts[index]);
|
|
if (scriptWrite(script, stream) != 0) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (fileWriteInt32(stream, a1->length) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (fileWriteInt32(stream, (int)a1->next) != 0) {
|
|
// FIXME: writing pointer to file
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A5768
|
|
int scriptSaveAll(File* stream)
|
|
{
|
|
for (int scriptType = 0; scriptType < SCRIPT_TYPE_COUNT; scriptType++) {
|
|
ScriptList* scriptList = &(gScriptLists[scriptType]);
|
|
|
|
int scriptCount = scriptList->length * SCRIPT_LIST_EXTENT_SIZE;
|
|
if (scriptList->tail != NULL) {
|
|
scriptCount += scriptList->tail->length - SCRIPT_LIST_EXTENT_SIZE;
|
|
}
|
|
|
|
ScriptListExtent* scriptExtent = scriptList->head;
|
|
ScriptListExtent* lastScriptExtent = NULL;
|
|
while (scriptExtent != NULL) {
|
|
for (int index = 0; index < scriptExtent->length; index++) {
|
|
Script* script = &(scriptExtent->scripts[index]);
|
|
|
|
if ((script->flags & SCRIPT_FLAG_0x08) != 0) {
|
|
scriptCount--;
|
|
|
|
lastScriptExtent = scriptList->tail;
|
|
int backwardsIndex = lastScriptExtent->length - 1;
|
|
while (lastScriptExtent != scriptExtent || backwardsIndex > index) {
|
|
if (lastScriptExtent == scriptExtent) {
|
|
if (backwardsIndex >= index) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
Script* backwardsScript = &(lastScriptExtent->scripts[backwardsIndex]);
|
|
if ((backwardsScript->flags & SCRIPT_FLAG_0x08) == 0) {
|
|
break;
|
|
}
|
|
|
|
backwardsIndex--;
|
|
|
|
if (backwardsIndex < 0) {
|
|
ScriptListExtent* previousScriptExtent = scriptList->head;
|
|
while (previousScriptExtent->next != lastScriptExtent) {
|
|
previousScriptExtent = previousScriptExtent->next;
|
|
}
|
|
|
|
lastScriptExtent = previousScriptExtent;
|
|
backwardsIndex = lastScriptExtent->length - 1;
|
|
}
|
|
}
|
|
|
|
if (lastScriptExtent != scriptExtent || backwardsIndex > index) {
|
|
Script temp;
|
|
memcpy(&temp, script, sizeof(Script));
|
|
memcpy(script, &(lastScriptExtent->scripts[backwardsIndex]), sizeof(Script));
|
|
memcpy(&(lastScriptExtent->scripts[backwardsIndex]), &temp, sizeof(Script));
|
|
|
|
scriptCount++;
|
|
}
|
|
}
|
|
}
|
|
scriptExtent = scriptExtent->next;
|
|
}
|
|
|
|
if (fileWriteInt32(stream, scriptCount) == -1) {
|
|
return -1;
|
|
}
|
|
|
|
if (scriptCount > 0) {
|
|
ScriptListExtent* scriptExtent = scriptList->head;
|
|
while (scriptExtent != lastScriptExtent) {
|
|
if (scriptListExtentWrite(scriptExtent, stream) == -1) {
|
|
return -1;
|
|
}
|
|
scriptExtent = scriptExtent->next;
|
|
}
|
|
|
|
if (lastScriptExtent != NULL) {
|
|
int index;
|
|
for (index = 0; index < lastScriptExtent->length; index++) {
|
|
Script* script = &(lastScriptExtent->scripts[index]);
|
|
if ((script->flags & SCRIPT_FLAG_0x08) != 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (index > 0) {
|
|
int length = lastScriptExtent->length;
|
|
lastScriptExtent->length = index;
|
|
if (scriptListExtentWrite(lastScriptExtent, stream) == -1) {
|
|
return -1;
|
|
}
|
|
lastScriptExtent->length = length;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A5A1C
|
|
int scriptRead(Script* scr, File* stream)
|
|
{
|
|
int prg;
|
|
|
|
if (fileReadInt32(stream, &(scr->sid)) == -1) return -1;
|
|
if (fileReadInt32(stream, &(scr->field_4)) == -1) return -1;
|
|
|
|
switch (scr->sid >> 24) {
|
|
case SCRIPT_TYPE_SPATIAL:
|
|
if (fileReadInt32(stream, &(scr->sp.built_tile)) == -1) return -1;
|
|
if (fileReadInt32(stream, &(scr->sp.radius)) == -1) return -1;
|
|
break;
|
|
case SCRIPT_TYPE_TIMED:
|
|
if (fileReadInt32(stream, &(scr->tm.time)) == -1) return -1;
|
|
break;
|
|
}
|
|
|
|
if (fileReadInt32(stream, &(scr->flags)) == -1) return -1;
|
|
if (fileReadInt32(stream, &(scr->field_14)) == -1) return -1;
|
|
if (fileReadInt32(stream, &(prg)) == -1) return -1;
|
|
if (fileReadInt32(stream, &(scr->field_1C)) == -1) return -1;
|
|
if (fileReadInt32(stream, &(scr->localVarsOffset)) == -1) return -1;
|
|
if (fileReadInt32(stream, &(scr->localVarsCount)) == -1) return -1;
|
|
if (fileReadInt32(stream, &(scr->field_28)) == -1) return -1;
|
|
if (fileReadInt32(stream, &(scr->action)) == -1) return -1;
|
|
if (fileReadInt32(stream, &(scr->fixedParam)) == -1) return -1;
|
|
if (fileReadInt32(stream, &(scr->actionBeingUsed)) == -1) return -1;
|
|
if (fileReadInt32(stream, &(scr->scriptOverrides)) == -1) return -1;
|
|
if (fileReadInt32(stream, &(scr->field_48)) == -1) return -1;
|
|
if (fileReadInt32(stream, &(scr->howMuch)) == -1) return -1;
|
|
if (fileReadInt32(stream, &(scr->field_50)) == -1) return -1;
|
|
|
|
scr->program = NULL;
|
|
scr->owner = NULL;
|
|
scr->source = NULL;
|
|
scr->target = NULL;
|
|
|
|
for (int index = 0; index < SCRIPT_PROC_COUNT; index++) {
|
|
scr->procs[index] = 0;
|
|
}
|
|
|
|
if (!(gMapHeader.flags & 1)) {
|
|
scr->localVarsCount = 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A5BE8
|
|
int scriptListExtentRead(ScriptListExtent* scriptExtent, File* stream)
|
|
{
|
|
for (int index = 0; index < SCRIPT_LIST_EXTENT_SIZE; index++) {
|
|
Script* scr = &(scriptExtent->scripts[index]);
|
|
if (scriptRead(scr, stream) != 0) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (fileReadInt32(stream, &(scriptExtent->length)) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
int next;
|
|
if (fileReadInt32(stream, &(next)) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A5C50
|
|
int scriptLoadAll(File* stream)
|
|
{
|
|
for (int index = 0; index < SCRIPT_TYPE_COUNT; index++) {
|
|
ScriptList* scriptList = &(gScriptLists[index]);
|
|
|
|
int scriptsCount = 0;
|
|
if (fileReadInt32(stream, &scriptsCount) == -1) {
|
|
return -1;
|
|
}
|
|
|
|
if (scriptsCount != 0) {
|
|
scriptList->length = scriptsCount / 16;
|
|
|
|
if (scriptsCount % 16 != 0) {
|
|
scriptList->length++;
|
|
}
|
|
|
|
ScriptListExtent* extent = (ScriptListExtent*)internal_malloc(sizeof(*extent));
|
|
scriptList->head = extent;
|
|
scriptList->tail = extent;
|
|
if (extent == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (scriptListExtentRead(extent, stream) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
for (int scriptIndex = 0; scriptIndex < extent->length; scriptIndex++) {
|
|
Script* script = &(extent->scripts[scriptIndex]);
|
|
script->owner = NULL;
|
|
script->source = NULL;
|
|
script->target = NULL;
|
|
script->program = NULL;
|
|
script->flags &= ~SCRIPT_FLAG_0x01;
|
|
}
|
|
|
|
extent->next = NULL;
|
|
|
|
ScriptListExtent* prevExtent = extent;
|
|
for (int extentIndex = 1; extentIndex < scriptList->length; extentIndex++) {
|
|
ScriptListExtent* extent = (ScriptListExtent*)internal_malloc(sizeof(*extent));
|
|
if (extent == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (scriptListExtentRead(extent, stream) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
for (int scriptIndex = 0; scriptIndex < extent->length; scriptIndex++) {
|
|
Script* script = &(extent->scripts[scriptIndex]);
|
|
script->owner = NULL;
|
|
script->source = NULL;
|
|
script->target = NULL;
|
|
script->program = NULL;
|
|
script->flags &= ~SCRIPT_FLAG_0x01;
|
|
}
|
|
|
|
prevExtent->next = extent;
|
|
|
|
extent->next = NULL;
|
|
prevExtent = extent;
|
|
}
|
|
|
|
scriptList->tail = prevExtent;
|
|
} else {
|
|
scriptList->head = NULL;
|
|
scriptList->tail = NULL;
|
|
scriptList->length = 0;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// scr_ptr
|
|
// 0x4A5E34
|
|
int scriptGetScript(int sid, Script** scriptPtr)
|
|
{
|
|
*scriptPtr = NULL;
|
|
|
|
if (sid == -1) {
|
|
return -1;
|
|
}
|
|
|
|
if (sid == 0xCCCCCCCC) {
|
|
debugPrint("\nERROR: scr_ptr called with UN-SET id #!!!!");
|
|
return -1;
|
|
}
|
|
|
|
ScriptList* scriptList = &(gScriptLists[sid >> 24]);
|
|
ScriptListExtent* scriptListExtent = scriptList->head;
|
|
|
|
while (scriptListExtent != NULL) {
|
|
for (int index = 0; index < scriptListExtent->length; index++) {
|
|
Script* script = &(scriptListExtent->scripts[index]);
|
|
if (script->sid == sid) {
|
|
*scriptPtr = script;
|
|
return 0;
|
|
}
|
|
}
|
|
scriptListExtent = scriptListExtent->next;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// 0x4A5ED8
|
|
int scriptGetNewId(int scriptType)
|
|
{
|
|
int scriptId = gScriptLists[scriptType].nextScriptId++;
|
|
int v1 = scriptType << 24;
|
|
|
|
while (scriptId < 32000) {
|
|
Script* script;
|
|
if (scriptGetScript(v1 | scriptId, &script) == -1) {
|
|
break;
|
|
}
|
|
scriptId++;
|
|
}
|
|
|
|
return scriptId;
|
|
}
|
|
|
|
// 0x4A5F28
|
|
int scriptAdd(int* sidPtr, int scriptType)
|
|
{
|
|
ScriptList* scriptList = &(gScriptLists[scriptType]);
|
|
ScriptListExtent* scriptListExtent = scriptList->tail;
|
|
if (scriptList->head != NULL) {
|
|
// There is at least one extent available, which means tail is also set.
|
|
if (scriptListExtent->length == SCRIPT_LIST_EXTENT_SIZE) {
|
|
ScriptListExtent* newExtent = scriptListExtent->next = (ScriptListExtent*)internal_malloc(sizeof(*newExtent));
|
|
if (newExtent == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
newExtent->length = 0;
|
|
newExtent->next = NULL;
|
|
|
|
scriptList->tail = newExtent;
|
|
scriptList->length++;
|
|
|
|
scriptListExtent = newExtent;
|
|
}
|
|
} else {
|
|
// Script head
|
|
scriptListExtent = (ScriptListExtent*)internal_malloc(sizeof(ScriptListExtent));
|
|
if (scriptListExtent == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
scriptListExtent->length = 0;
|
|
scriptListExtent->next = NULL;
|
|
|
|
scriptList->head = scriptListExtent;
|
|
scriptList->tail = scriptListExtent;
|
|
scriptList->length = 1;
|
|
}
|
|
|
|
int sid = scriptGetNewId(scriptType) | (scriptType << 24);
|
|
|
|
*sidPtr = sid;
|
|
|
|
Script* scr = &(scriptListExtent->scripts[scriptListExtent->length]);
|
|
scr->sid = sid;
|
|
scr->sp.built_tile = -1;
|
|
scr->sp.radius = -1;
|
|
scr->flags = 0;
|
|
scr->field_14 = -1;
|
|
scr->program = 0;
|
|
scr->localVarsOffset = -1;
|
|
scr->localVarsCount = 0;
|
|
scr->field_28 = 0;
|
|
scr->action = 0;
|
|
scr->fixedParam = 0;
|
|
scr->owner = 0;
|
|
scr->source = 0;
|
|
scr->target = 0;
|
|
scr->actionBeingUsed = -1;
|
|
scr->scriptOverrides = 0;
|
|
scr->field_48 = 0;
|
|
scr->howMuch = 0;
|
|
scr->field_50 = 0;
|
|
|
|
for (int index = 0; index < SCRIPT_PROC_COUNT; index++) {
|
|
scr->procs[index] = SCRIPT_PROC_NO_PROC;
|
|
}
|
|
|
|
scriptListExtent->length++;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// scr_remove_local_vars
|
|
// 0x4A60D4
|
|
int scriptsRemoveLocalVars(Script* script)
|
|
{
|
|
if (script == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (script->localVarsCount != 0) {
|
|
int oldMapLocalVarsCount = gMapLocalVarsLength;
|
|
if (oldMapLocalVarsCount > 0 && script->localVarsOffset >= 0) {
|
|
gMapLocalVarsLength -= script->localVarsCount;
|
|
|
|
if (oldMapLocalVarsCount - script->localVarsCount != script->localVarsOffset && script->localVarsOffset != -1) {
|
|
memmove(gMapLocalVars + script->localVarsOffset,
|
|
gMapLocalVars + (script->localVarsOffset + script->localVarsCount),
|
|
sizeof(*gMapLocalVars) * (oldMapLocalVarsCount - script->localVarsCount - script->localVarsOffset));
|
|
|
|
gMapLocalVars = (int*)internal_realloc(gMapLocalVars, sizeof(*gMapLocalVars) * gMapLocalVarsLength);
|
|
if (gMapLocalVars == NULL) {
|
|
debugPrint("\nError in mem_realloc in scr_remove_local_vars!\n");
|
|
}
|
|
|
|
for (int index = 0; index < SCRIPT_TYPE_COUNT; index++) {
|
|
ScriptList* scriptList = &(gScriptLists[index]);
|
|
ScriptListExtent* extent = scriptList->head;
|
|
while (extent != NULL) {
|
|
for (int index = 0; index < extent->length; index++) {
|
|
Script* other = &(extent->scripts[index]);
|
|
if (other->localVarsOffset > script->localVarsOffset) {
|
|
other->localVarsOffset -= script->localVarsCount;
|
|
}
|
|
}
|
|
extent = extent->next;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// scr_remove
|
|
// 0x4A61D4
|
|
int scriptRemove(int sid)
|
|
{
|
|
if (sid == -1) {
|
|
return -1;
|
|
}
|
|
|
|
ScriptList* scriptList = &(gScriptLists[sid >> 24]);
|
|
|
|
ScriptListExtent* scriptListExtent = scriptList->head;
|
|
int index;
|
|
while (scriptListExtent != NULL) {
|
|
for (index = 0; index < scriptListExtent->length; index++) {
|
|
Script* script = &(scriptListExtent->scripts[index]);
|
|
if (script->sid == sid) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (index < scriptListExtent->length) {
|
|
break;
|
|
}
|
|
|
|
scriptListExtent = scriptListExtent->next;
|
|
}
|
|
|
|
if (scriptListExtent == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
Script* script = &(scriptListExtent->scripts[index]);
|
|
if ((script->flags & SCRIPT_FLAG_0x02) != 0) {
|
|
if (script->program != NULL) {
|
|
script->program = NULL;
|
|
}
|
|
}
|
|
|
|
if ((script->flags & SCRIPT_FLAG_0x10) == 0) {
|
|
// NOTE: Uninline.
|
|
_scripts_clear_combat_requests(script);
|
|
|
|
if (scriptsRemoveLocalVars(script) == -1) {
|
|
debugPrint("\nERROR Removing local vars on scr_remove!!\n");
|
|
}
|
|
|
|
if (queueRemoveEventsByType(script->owner, EVENT_TYPE_SCRIPT) == -1) {
|
|
debugPrint("\nERROR Removing Timed Events on scr_remove!!\n");
|
|
}
|
|
|
|
if (scriptListExtent == scriptList->tail && index + 1 == scriptListExtent->length) {
|
|
// Removing last script in tail extent
|
|
scriptListExtent->length -= 1;
|
|
|
|
if (scriptListExtent->length == 0) {
|
|
scriptList->length--;
|
|
internal_free(scriptListExtent);
|
|
|
|
if (scriptList->length != 0) {
|
|
ScriptListExtent* v13 = scriptList->head;
|
|
while (scriptList->tail != v13->next) {
|
|
v13 = v13->next;
|
|
}
|
|
v13->next = NULL;
|
|
scriptList->tail = v13;
|
|
} else {
|
|
scriptList->head = NULL;
|
|
scriptList->tail = NULL;
|
|
}
|
|
}
|
|
} else {
|
|
// Relocate last script from tail extent into this script's slot.
|
|
memcpy(&(scriptListExtent->scripts[index]), &(scriptList->tail->scripts[scriptList->tail->length - 1]), sizeof(Script));
|
|
|
|
// Decrement number of scripts in tail extent.
|
|
scriptList->tail->length -= 1;
|
|
|
|
// Check to see if this extent became empty.
|
|
if (scriptList->tail->length == 0) {
|
|
scriptList->length -= 1;
|
|
|
|
// Find previous extent that is about to become a new tail for
|
|
// this script list.
|
|
ScriptListExtent* prev = scriptList->head;
|
|
while (prev->next != scriptList->tail) {
|
|
prev = prev->next;
|
|
}
|
|
prev->next = NULL;
|
|
|
|
internal_free(scriptList->tail);
|
|
scriptList->tail = prev;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A63E0
|
|
int _scr_remove_all()
|
|
{
|
|
_queue_clear_type(EVENT_TYPE_SCRIPT, NULL);
|
|
_scr_message_free();
|
|
|
|
for (int scrType = 0; scrType < SCRIPT_TYPE_COUNT; scrType++) {
|
|
ScriptList* scriptList = &(gScriptLists[scrType]);
|
|
|
|
// TODO: Super odd way to remove scripts. The problem is that [scrRemove]
|
|
// does relocate scripts between extents, so current extent may become
|
|
// empty. In addition there is a 0x10 flag on the script that is not
|
|
// removed. Find a way to refactor this.
|
|
ScriptListExtent* scriptListExtent = scriptList->head;
|
|
while (scriptListExtent != NULL) {
|
|
ScriptListExtent* next = NULL;
|
|
for (int scriptIndex = 0; scriptIndex < scriptListExtent->length;) {
|
|
Script* script = &(scriptListExtent->scripts[scriptIndex]);
|
|
|
|
if ((script->flags & SCRIPT_FLAG_0x10) != 0) {
|
|
scriptIndex++;
|
|
} else {
|
|
if (scriptIndex != 0 || scriptListExtent->length != 1) {
|
|
scriptRemove(script->sid);
|
|
} else {
|
|
next = scriptListExtent->next;
|
|
scriptRemove(script->sid);
|
|
}
|
|
}
|
|
}
|
|
|
|
scriptListExtent = next;
|
|
}
|
|
}
|
|
|
|
gScriptsEnumerationScriptIndex = 0;
|
|
gScriptsEnumerationScriptListExtent = NULL;
|
|
gScriptsEnumerationElevation = 0;
|
|
gMapSid = -1;
|
|
|
|
programListFree();
|
|
_exportClearAllVariables();
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A64A8
|
|
int _scr_remove_all_force()
|
|
{
|
|
_queue_clear_type(EVENT_TYPE_SCRIPT, NULL);
|
|
_scr_message_free();
|
|
|
|
for (int type = 0; type < SCRIPT_TYPE_COUNT; type++) {
|
|
ScriptList* scriptList = &(gScriptLists[type]);
|
|
ScriptListExtent* extent = scriptList->head;
|
|
while (extent != NULL) {
|
|
ScriptListExtent* next = extent->next;
|
|
internal_free(extent);
|
|
extent = next;
|
|
}
|
|
|
|
scriptList->head = NULL;
|
|
scriptList->tail = NULL;
|
|
scriptList->length = 0;
|
|
}
|
|
|
|
gScriptsEnumerationScriptIndex = 0;
|
|
gScriptsEnumerationScriptListExtent = 0;
|
|
gScriptsEnumerationElevation = 0;
|
|
gMapSid = -1;
|
|
programListFree();
|
|
_exportClearAllVariables();
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A6524
|
|
Script* scriptGetFirstSpatialScript(int elevation)
|
|
{
|
|
gScriptsEnumerationElevation = elevation;
|
|
gScriptsEnumerationScriptIndex = 0;
|
|
gScriptsEnumerationScriptListExtent = gScriptLists[SCRIPT_TYPE_SPATIAL].head;
|
|
|
|
if (gScriptsEnumerationScriptListExtent == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
Script* script = &(gScriptsEnumerationScriptListExtent->scripts[0]);
|
|
if ((script->flags & SCRIPT_FLAG_0x02) != 0 || ((script->sp.built_tile & 0xE0000000) >> 29) != elevation) {
|
|
script = scriptGetNextSpatialScript();
|
|
}
|
|
|
|
return script;
|
|
}
|
|
|
|
// 0x4A6564
|
|
Script* scriptGetNextSpatialScript()
|
|
{
|
|
ScriptListExtent* scriptListExtent = gScriptsEnumerationScriptListExtent;
|
|
int scriptIndex = gScriptsEnumerationScriptIndex;
|
|
|
|
if (scriptListExtent == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
for (;;) {
|
|
scriptIndex++;
|
|
|
|
if (scriptIndex == SCRIPT_LIST_EXTENT_SIZE) {
|
|
scriptListExtent = scriptListExtent->next;
|
|
scriptIndex = 0;
|
|
} else if (scriptIndex >= scriptListExtent->length) {
|
|
scriptListExtent = NULL;
|
|
}
|
|
|
|
if (scriptListExtent == NULL) {
|
|
break;
|
|
}
|
|
|
|
Script* script = &(scriptListExtent->scripts[scriptIndex]);
|
|
if ((script->flags & SCRIPT_FLAG_0x02) == 0 && ((script->sp.built_tile & 0xE0000000) >> 29) == gScriptsEnumerationElevation) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
Script* script;
|
|
if (scriptListExtent != NULL) {
|
|
script = &(scriptListExtent->scripts[scriptIndex]);
|
|
} else {
|
|
script = NULL;
|
|
}
|
|
|
|
gScriptsEnumerationScriptIndex = scriptIndex;
|
|
gScriptsEnumerationScriptListExtent = scriptListExtent;
|
|
|
|
return script;
|
|
}
|
|
|
|
// 0x4A65F0
|
|
void _scr_spatials_enable()
|
|
{
|
|
_scr_SpatialsEnabled = true;
|
|
}
|
|
|
|
// 0x4A6600
|
|
void _scr_spatials_disable()
|
|
{
|
|
_scr_SpatialsEnabled = false;
|
|
}
|
|
|
|
// 0x4A6610
|
|
bool scriptsExecSpatialProc(Object* object, int tile, int elevation)
|
|
{
|
|
if (object == gGameMouseBouncingCursor) {
|
|
return false;
|
|
}
|
|
|
|
if (object == gGameMouseHexCursor) {
|
|
return false;
|
|
}
|
|
|
|
if ((object->flags & OBJECT_HIDDEN) != 0 || (object->flags & OBJECT_FLAG_0x08) != 0) {
|
|
return false;
|
|
}
|
|
|
|
if (tile < 10) {
|
|
return false;
|
|
}
|
|
|
|
if (!_scr_SpatialsEnabled) {
|
|
return false;
|
|
}
|
|
|
|
_scr_SpatialsEnabled = false;
|
|
|
|
int builtTile = ((elevation << 29) & 0xE0000000) | tile;
|
|
|
|
for (Script* script = scriptGetFirstSpatialScript(elevation); script != NULL; script = scriptGetNextSpatialScript()) {
|
|
if (builtTile == script->sp.built_tile) {
|
|
// NOTE: Uninline.
|
|
scriptSetObjects(script->sid, object, NULL);
|
|
} else {
|
|
if (script->sp.radius == 0) {
|
|
continue;
|
|
}
|
|
|
|
int distance = tileDistanceBetween(script->sp.built_tile & 0x3FFFFFF, tile);
|
|
if (distance > script->sp.radius) {
|
|
continue;
|
|
}
|
|
|
|
// NOTE: Uninline.
|
|
scriptSetObjects(script->sid, object, NULL);
|
|
}
|
|
|
|
scriptExecProc(script->sid, SCRIPT_PROC_SPATIAL);
|
|
}
|
|
|
|
_scr_SpatialsEnabled = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
// scr_load_all_scripts
|
|
// 0x4A677C
|
|
int scriptsExecStartProc()
|
|
{
|
|
for (int scriptListIndex = 0; scriptListIndex < SCRIPT_TYPE_COUNT; scriptListIndex++) {
|
|
ScriptList* scriptList = &(gScriptLists[scriptListIndex]);
|
|
ScriptListExtent* extent = scriptList->head;
|
|
while (extent != NULL) {
|
|
for (int scriptIndex = 0; scriptIndex < extent->length; scriptIndex++) {
|
|
Script* script = &(extent->scripts[scriptIndex]);
|
|
scriptExecProc(script->sid, SCRIPT_PROC_START);
|
|
}
|
|
extent = extent->next;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A67DC
|
|
void scriptsExecMapEnterProc()
|
|
{
|
|
scriptsExecMapUpdateScripts(SCRIPT_PROC_MAP_ENTER);
|
|
}
|
|
|
|
// 0x4A67E4
|
|
void scriptsExecMapUpdateProc()
|
|
{
|
|
scriptsExecMapUpdateScripts(SCRIPT_PROC_MAP_UPDATE);
|
|
}
|
|
|
|
// scr_exec_map_update_scripts
|
|
// 0x4A67EC
|
|
void scriptsExecMapUpdateScripts(int proc)
|
|
{
|
|
_scr_SpatialsEnabled = false;
|
|
|
|
int fixedParam = 0;
|
|
if (proc == SCRIPT_PROC_MAP_ENTER) {
|
|
fixedParam = (gMapHeader.flags & 1) == 0;
|
|
} else {
|
|
scriptExecProc(gMapSid, proc);
|
|
}
|
|
|
|
int sidListCapacity = 0;
|
|
for (int scriptType = 0; scriptType < SCRIPT_TYPE_COUNT; scriptType++) {
|
|
ScriptList* scriptList = &(gScriptLists[scriptType]);
|
|
ScriptListExtent* scriptListExtent = scriptList->head;
|
|
while (scriptListExtent != NULL) {
|
|
sidListCapacity += scriptListExtent->length;
|
|
scriptListExtent = scriptListExtent->next;
|
|
}
|
|
}
|
|
|
|
if (sidListCapacity == 0) {
|
|
return;
|
|
}
|
|
|
|
int* sidList = (int*)internal_malloc(sizeof(*sidList) * sidListCapacity);
|
|
if (sidList == NULL) {
|
|
debugPrint("\nError: scr_exec_map_update_scripts: Out of memory for sidList!");
|
|
return;
|
|
}
|
|
|
|
int sidListLength = 0;
|
|
for (int scriptType = 0; scriptType < SCRIPT_TYPE_COUNT; scriptType++) {
|
|
ScriptList* scriptList = &(gScriptLists[scriptType]);
|
|
ScriptListExtent* scriptListExtent = scriptList->head;
|
|
while (scriptListExtent != NULL) {
|
|
for (int scriptIndex = 0; scriptIndex < scriptListExtent->length; scriptIndex++) {
|
|
Script* script = &(scriptListExtent->scripts[scriptIndex]);
|
|
if (script->sid != gMapSid && script->procs[proc] > 0) {
|
|
sidList[sidListLength++] = script->sid;
|
|
}
|
|
}
|
|
scriptListExtent = scriptListExtent->next;
|
|
}
|
|
}
|
|
|
|
if (proc == SCRIPT_PROC_MAP_ENTER) {
|
|
for (int index = 0; index < sidListLength; index++) {
|
|
Script* script;
|
|
if (scriptGetScript(sidList[index], &script) != -1) {
|
|
script->fixedParam = fixedParam;
|
|
}
|
|
|
|
scriptExecProc(sidList[index], proc);
|
|
}
|
|
} else {
|
|
for (int index = 0; index < sidListLength; index++) {
|
|
scriptExecProc(sidList[index], proc);
|
|
}
|
|
}
|
|
|
|
internal_free(sidList);
|
|
|
|
_scr_SpatialsEnabled = true;
|
|
}
|
|
|
|
// 0x4A69A0
|
|
void scriptsExecMapExitProc()
|
|
{
|
|
scriptsExecMapUpdateScripts(SCRIPT_PROC_MAP_EXIT);
|
|
}
|
|
|
|
// 0x4A6B64
|
|
int scriptsGetMessageList(int a1, MessageList** messageListPtr)
|
|
{
|
|
if (a1 == -1) {
|
|
return -1;
|
|
}
|
|
|
|
int messageListIndex = a1 - 1;
|
|
MessageList* messageList = &(_script_dialog_msgs[messageListIndex]);
|
|
if (messageList->entries_num == 0) {
|
|
char scriptName[20];
|
|
scriptName[0] = '\0';
|
|
scriptsGetFileName(messageListIndex & 0xFFFFFF, scriptName);
|
|
|
|
char* pch = strrchr(scriptName, '.');
|
|
if (pch != NULL) {
|
|
*pch = '\0';
|
|
}
|
|
|
|
char path[MAX_PATH];
|
|
sprintf(path, "dialog\\%s.msg", scriptName);
|
|
|
|
if (!messageListLoad(messageList, path)) {
|
|
debugPrint("\nError loading script dialog message file!");
|
|
return -1;
|
|
}
|
|
|
|
if (!messageListFilterBadwords(messageList)) {
|
|
debugPrint("\nError filtering script dialog message file!");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
*messageListPtr = messageList;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A6C50
|
|
char* _scr_get_msg_str(int messageListId, int messageId)
|
|
{
|
|
return _scr_get_msg_str_speech(messageListId, messageId, 0);
|
|
}
|
|
|
|
// message_str
|
|
// 0x4A6C5C
|
|
char* _scr_get_msg_str_speech(int messageListId, int messageId, int a3)
|
|
{
|
|
if (messageListId == 0 && messageId == 0) {
|
|
return _blank_str;
|
|
}
|
|
|
|
if (messageListId == -1 && messageId == -1) {
|
|
return _blank_str;
|
|
}
|
|
|
|
if (messageListId == -2 && messageId == -2) {
|
|
MessageListItem messageListItem;
|
|
return getmsg(&gProtoMessageList, &messageListItem, 650);
|
|
}
|
|
|
|
MessageList* messageList;
|
|
if (scriptsGetMessageList(messageListId, &messageList) == -1) {
|
|
debugPrint("\nERROR: message_str: can't find message file: List: %d!", messageListId);
|
|
return NULL;
|
|
}
|
|
|
|
if (((gGameDialogHeadFid & 0xF000000) >> 24) != 8) {
|
|
a3 = 0;
|
|
}
|
|
|
|
MessageListItem messageListItem;
|
|
messageListItem.num = messageId;
|
|
if (!messageListGetItem(messageList, &messageListItem)) {
|
|
debugPrint("\nError: can't find message: List: %d, Num: %d!", messageListId, messageId);
|
|
return _err_str;
|
|
}
|
|
|
|
if (a3) {
|
|
if (_gdialogActive()) {
|
|
if (messageListItem.audio != NULL && messageListItem.audio[0] != '\0') {
|
|
if (messageListItem.flags & 0x01) {
|
|
gameDialogStartLips(NULL);
|
|
} else {
|
|
gameDialogStartLips(messageListItem.audio);
|
|
}
|
|
} else {
|
|
debugPrint("Missing speech name: %d\n", messageListItem.num);
|
|
}
|
|
}
|
|
}
|
|
|
|
return messageListItem.text;
|
|
}
|
|
|
|
// 0x4A6D64
|
|
int scriptGetLocalVar(int sid, int variable, int* value)
|
|
{
|
|
if (sid >> 24 == SCRIPT_TYPE_SYSTEM) {
|
|
debugPrint("\nError! System scripts/Map scripts not allowed local_vars! ");
|
|
|
|
_tempStr1[0] = '\0';
|
|
scriptsGetFileName(sid & 0xFFFFFF, _tempStr1);
|
|
|
|
debugPrint(":%s\n", _tempStr1);
|
|
|
|
*value = -1;
|
|
return -1;
|
|
}
|
|
|
|
Script* script;
|
|
if (scriptGetScript(sid, &script) == 1) {
|
|
*value = -1;
|
|
return -1;
|
|
}
|
|
|
|
if (script->localVarsCount == 0) {
|
|
// NOTE: Uninline.
|
|
_scr_find_str_run_info(script->field_14, &(script->field_50), sid);
|
|
}
|
|
|
|
if (script->localVarsCount > 0) {
|
|
if (script->localVarsOffset == -1) {
|
|
script->localVarsOffset = _map_malloc_local_var(script->localVarsCount);
|
|
}
|
|
|
|
*value = mapGetLocalVar(script->localVarsOffset + variable);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4A6E58
|
|
int scriptSetLocalVar(int sid, int variable, int value)
|
|
{
|
|
Script* script;
|
|
if (scriptGetScript(sid, &script) == -1) {
|
|
return -1;
|
|
}
|
|
|
|
if (script->localVarsCount == 0) {
|
|
// NOTE: Uninline.
|
|
_scr_find_str_run_info(script->field_14, &(script->field_50), sid);
|
|
}
|
|
|
|
if (script->localVarsCount <= 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (script->localVarsOffset == -1) {
|
|
script->localVarsOffset = _map_malloc_local_var(script->localVarsCount);
|
|
}
|
|
|
|
mapSetLocalVar(script->localVarsOffset + variable, value);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Performs combat script and returns true if default action has been overriden
|
|
// by script.
|
|
//
|
|
// 0x4A6EFC
|
|
bool _scr_end_combat()
|
|
{
|
|
if (gMapSid == 0 || gMapSid == -1) {
|
|
return false;
|
|
}
|
|
|
|
int team = _combat_player_knocked_out_by();
|
|
if (team == -1) {
|
|
return false;
|
|
}
|
|
|
|
Script* before;
|
|
if (scriptGetScript(gMapSid, &before) != -1) {
|
|
before->fixedParam = team;
|
|
}
|
|
|
|
scriptExecProc(gMapSid, SCRIPT_PROC_COMBAT);
|
|
|
|
bool success = false;
|
|
|
|
Script* after;
|
|
if (scriptGetScript(gMapSid, &after) != -1) {
|
|
if (after->scriptOverrides != 0) {
|
|
success = true;
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
// 0x4A6F70
|
|
int _scr_explode_scenery(Object* a1, int tile, int radius, int elevation)
|
|
{
|
|
int scriptExtentsCount = gScriptLists[SCRIPT_TYPE_SPATIAL].length + gScriptLists[SCRIPT_TYPE_ITEM].length;
|
|
if (scriptExtentsCount == 0) {
|
|
return 0;
|
|
}
|
|
|
|
int* scriptIds = (int*)internal_malloc(sizeof(*scriptIds) * scriptExtentsCount * SCRIPT_LIST_EXTENT_SIZE);
|
|
if (scriptIds == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
ScriptListExtent* extent;
|
|
int scriptsCount = 0;
|
|
|
|
_scr_SpatialsEnabled = false;
|
|
|
|
extent = gScriptLists[SCRIPT_TYPE_ITEM].head;
|
|
while (extent != NULL) {
|
|
for (int index = 0; index < extent->length; index++) {
|
|
Script* script = &(extent->scripts[index]);
|
|
if (script->procs[SCRIPT_PROC_DAMAGE] <= 0 && script->program == NULL) {
|
|
scriptExecProc(script->sid, SCRIPT_PROC_START);
|
|
}
|
|
|
|
if (script->procs[SCRIPT_PROC_DAMAGE] > 0) {
|
|
Object* self = script->owner;
|
|
if (self != NULL) {
|
|
if (self->elevation == elevation && tileDistanceBetween(self->tile, tile) <= radius) {
|
|
scriptIds[scriptsCount] = script->sid;
|
|
scriptsCount += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
extent = extent->next;
|
|
}
|
|
|
|
extent = gScriptLists[SCRIPT_TYPE_SPATIAL].head;
|
|
while (extent != NULL) {
|
|
for (int index = 0; index < extent->length; index++) {
|
|
Script* script = &(extent->scripts[index]);
|
|
if (script->procs[SCRIPT_PROC_DAMAGE] <= 0 && script->program == NULL) {
|
|
scriptExecProc(script->sid, SCRIPT_PROC_START);
|
|
}
|
|
|
|
if (script->procs[SCRIPT_PROC_DAMAGE] > 0
|
|
&& (script->sp.built_tile & 0xE0000000) >> 29 == elevation
|
|
&& tileDistanceBetween(script->sp.built_tile & 0x3FFFFFF, tile) <= radius) {
|
|
scriptIds[scriptsCount] = script->sid;
|
|
scriptsCount += 1;
|
|
}
|
|
}
|
|
extent = extent->next;
|
|
}
|
|
|
|
for (int index = 0; index < scriptsCount; index++) {
|
|
Script* script;
|
|
int sid = scriptIds[index];
|
|
|
|
if (scriptGetScript(sid, &script) != -1) {
|
|
script->fixedParam = 20;
|
|
}
|
|
|
|
// TODO: Obtaining script twice, probably some inlining.
|
|
if (scriptGetScript(sid, &script) != -1) {
|
|
script->source = NULL;
|
|
script->target = a1;
|
|
}
|
|
|
|
scriptExecProc(sid, SCRIPT_PROC_DAMAGE);
|
|
}
|
|
|
|
// TODO: Redundant, we already know `scriptIds` is not NULL.
|
|
if (scriptIds != NULL) {
|
|
internal_free(scriptIds);
|
|
}
|
|
|
|
_scr_SpatialsEnabled = true;
|
|
|
|
return 0;
|
|
}
|