2015-06-30 00:07:12 +07:00
|
|
|
/*
|
|
|
|
|
* sfall
|
2016-11-14 02:07:08 +07:00
|
|
|
* Copyright (C) 2008-2016 The sfall team
|
2015-06-30 00:07:12 +07:00
|
|
|
*
|
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
2020-03-19 12:32:42 +08:00
|
|
|
#include "..\..\..\FalloutEngine\AsmMacros.h"
|
2016-11-14 02:07:08 +07:00
|
|
|
#include "..\..\..\FalloutEngine\Fallout2.h"
|
2020-03-19 12:32:42 +08:00
|
|
|
|
2016-11-14 02:07:08 +07:00
|
|
|
#include "..\..\..\SafeWrite.h"
|
|
|
|
|
#include "..\..\LoadGameHook.h"
|
|
|
|
|
#include "..\..\ScriptExtender.h"
|
2017-04-15 02:04:21 +07:00
|
|
|
#include "..\..\Worldmap.h"
|
2018-04-27 19:40:23 +08:00
|
|
|
#include "..\Arrays.h"
|
2017-04-15 02:04:21 +07:00
|
|
|
#include "..\OpcodeContext.h"
|
2015-06-30 00:07:12 +07:00
|
|
|
|
2016-11-14 02:07:08 +07:00
|
|
|
#include "Worldmap.h"
|
2015-06-30 00:07:12 +07:00
|
|
|
|
2017-03-05 21:49:21 +07:00
|
|
|
namespace sfall
|
|
|
|
|
{
|
|
|
|
|
namespace script
|
|
|
|
|
{
|
|
|
|
|
|
2019-08-22 11:32:33 +08:00
|
|
|
static DWORD ForceEncounterMapID = -1;
|
|
|
|
|
static DWORD ForceEncounterFlags;
|
2019-04-24 09:55:52 +08:00
|
|
|
|
2019-08-12 12:06:45 +08:00
|
|
|
DWORD ForceEncounterRestore() {
|
2020-01-21 10:10:30 +08:00
|
|
|
if (ForceEncounterMapID == -1) return 0;
|
2020-03-07 14:21:12 +08:00
|
|
|
__int64 data = 0x672E043D83; // cmp ds:_Meet_Frank_Horrigan, 0
|
2019-08-12 12:06:45 +08:00
|
|
|
SafeWriteBytes(0x4C06D1, (BYTE*)&data, 5);
|
2019-08-22 11:32:33 +08:00
|
|
|
ForceEncounterFlags = 0;
|
|
|
|
|
DWORD mapID = ForceEncounterMapID;
|
|
|
|
|
ForceEncounterMapID = -1;
|
2019-08-12 12:06:45 +08:00
|
|
|
return mapID;
|
2015-06-30 00:07:12 +07:00
|
|
|
}
|
2016-11-11 01:27:38 +07:00
|
|
|
|
2020-01-21 10:10:30 +08:00
|
|
|
static void ForceEncounterEffects() {
|
|
|
|
|
if (ForceEncounterFlags & 0x10) { // _FadeOut flag
|
|
|
|
|
__asm mov eax, FO_VAR_black_palette;
|
|
|
|
|
__asm call fo::funcoffs::palette_fade_to_;
|
|
|
|
|
return;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// implements a flashing encounter icon
|
|
|
|
|
if (ForceEncounterFlags & 4) return; // _NoIcon flag
|
|
|
|
|
long iconType = (ForceEncounterFlags & 8) ? 3 : 1; // icon type flag (special: 0-3, normal: 0-1)
|
|
|
|
|
|
2021-08-27 20:45:53 +08:00
|
|
|
fo::var::setInt(FO_VAR_wmEncounterIconShow) = 1;
|
|
|
|
|
fo::var::setInt(FO_VAR_wmRndCursorFid) = 0;
|
2020-01-21 10:10:30 +08:00
|
|
|
|
|
|
|
|
for (size_t n = 8; n > 0; --n) {
|
2021-08-27 20:45:53 +08:00
|
|
|
long iconFidIndex = iconType - fo::var::getInt(FO_VAR_wmRndCursorFid);
|
|
|
|
|
fo::var::setInt(FO_VAR_wmRndCursorFid) = iconFidIndex;
|
2020-01-20 11:39:41 +08:00
|
|
|
__asm call fo::funcoffs::wmInterfaceRefresh_;
|
|
|
|
|
fo::func::block_for_tocks(200);
|
|
|
|
|
}
|
2021-08-27 20:45:53 +08:00
|
|
|
fo::var::setInt(FO_VAR_wmEncounterIconShow) = 0;
|
2020-01-20 11:39:41 +08:00
|
|
|
}
|
|
|
|
|
|
2019-08-12 12:06:45 +08:00
|
|
|
static void __declspec(naked) wmRndEncounterOccurred_hack() {
|
2015-06-30 00:07:12 +07:00
|
|
|
__asm {
|
2019-08-22 11:32:33 +08:00
|
|
|
test ForceEncounterFlags, 0x1; // _NoCar flag
|
2019-08-12 12:06:45 +08:00
|
|
|
jnz noCar;
|
2022-11-30 14:27:46 +08:00
|
|
|
cmp dword ptr ds:[FO_VAR_Move_on_Car], 0;
|
2019-08-12 12:06:45 +08:00
|
|
|
jz noCar;
|
|
|
|
|
mov edx, FO_VAR_carCurrentArea;
|
2019-08-22 11:32:33 +08:00
|
|
|
mov eax, ForceEncounterMapID;
|
2019-08-12 12:06:45 +08:00
|
|
|
call fo::funcoffs::wmMatchAreaContainingMapIdx_;
|
|
|
|
|
noCar:
|
2020-01-21 10:10:30 +08:00
|
|
|
call ForceEncounterEffects;
|
2019-08-12 12:06:45 +08:00
|
|
|
call ForceEncounterRestore;
|
|
|
|
|
push 0x4C0721; // return addr
|
|
|
|
|
jmp fo::funcoffs::map_load_idx_; // eax - mapID
|
2015-06-30 00:07:12 +07:00
|
|
|
}
|
|
|
|
|
}
|
2016-11-11 01:27:38 +07:00
|
|
|
|
2020-05-20 11:30:25 +08:00
|
|
|
void op_force_encounter(OpcodeContext& cxt) {
|
2019-08-22 11:32:33 +08:00
|
|
|
if (ForceEncounterFlags & (1 << 31)) return; // wait prev. encounter
|
2019-08-12 12:06:45 +08:00
|
|
|
|
|
|
|
|
DWORD mapID = cxt.arg(0).rawValue();
|
|
|
|
|
if (mapID < 0) {
|
|
|
|
|
cxt.printOpcodeError("%s() - invalid map number.", cxt.getOpcodeName());
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-08-22 11:32:33 +08:00
|
|
|
if (ForceEncounterMapID == -1) MakeJump(0x4C06D1, wmRndEncounterOccurred_hack);
|
2019-08-12 12:06:45 +08:00
|
|
|
|
2019-08-22 11:32:33 +08:00
|
|
|
ForceEncounterMapID = mapID;
|
2019-08-12 12:06:45 +08:00
|
|
|
DWORD flags = 0;
|
|
|
|
|
if (cxt.numArgs() > 1) {
|
|
|
|
|
flags = cxt.arg(1).rawValue();
|
|
|
|
|
if (flags & 2) { // _Lock flag
|
|
|
|
|
flags |= (1 << 31); // set bit 31
|
|
|
|
|
} else {
|
2019-08-22 11:32:33 +08:00
|
|
|
flags &= ~(1 << 31);
|
2019-08-12 12:06:45 +08:00
|
|
|
}
|
2015-06-30 00:07:12 +07:00
|
|
|
}
|
2019-08-22 11:32:33 +08:00
|
|
|
ForceEncounterFlags = flags;
|
2015-06-30 00:07:12 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// world_map_functions
|
2016-11-14 02:07:08 +07:00
|
|
|
void __declspec(naked) op_in_world_map() {
|
2015-06-30 00:07:12 +07:00
|
|
|
__asm {
|
2019-12-04 10:39:35 +08:00
|
|
|
mov esi, ecx;
|
2015-06-30 00:07:12 +07:00
|
|
|
call InWorldMap;
|
2019-04-23 10:33:43 +08:00
|
|
|
mov edx, eax;
|
2019-11-28 14:05:36 +08:00
|
|
|
mov eax, ebx;
|
|
|
|
|
_RET_VAL_INT;
|
2019-12-04 10:39:35 +08:00
|
|
|
mov ecx, esi;
|
2015-06-30 00:07:12 +07:00
|
|
|
retn;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-11-11 01:27:38 +07:00
|
|
|
|
2016-11-14 02:07:08 +07:00
|
|
|
void __declspec(naked) op_get_game_mode() {
|
2015-06-30 00:07:12 +07:00
|
|
|
__asm {
|
2019-12-04 10:39:35 +08:00
|
|
|
mov esi, ecx;
|
2017-03-26 19:41:04 +07:00
|
|
|
call GetLoopFlags;
|
2019-04-23 10:33:43 +08:00
|
|
|
mov edx, eax;
|
2019-11-28 14:05:36 +08:00
|
|
|
mov eax, ebx;
|
|
|
|
|
_RET_VAL_INT;
|
2019-12-04 10:39:35 +08:00
|
|
|
mov ecx, esi;
|
2015-06-30 00:07:12 +07:00
|
|
|
retn;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-11-11 01:27:38 +07:00
|
|
|
|
2016-11-14 02:07:08 +07:00
|
|
|
void __declspec(naked) op_get_world_map_x_pos() {
|
2015-06-30 00:07:12 +07:00
|
|
|
__asm {
|
2019-04-23 10:33:43 +08:00
|
|
|
mov edx, ds:[FO_VAR_world_xpos];
|
2019-12-04 10:39:35 +08:00
|
|
|
_J_RET_VAL_TYPE(VAR_TYPE_INT);
|
|
|
|
|
// retn;
|
2015-06-30 00:07:12 +07:00
|
|
|
}
|
|
|
|
|
}
|
2016-11-11 01:27:38 +07:00
|
|
|
|
2016-11-14 02:07:08 +07:00
|
|
|
void __declspec(naked) op_get_world_map_y_pos() {
|
2015-06-30 00:07:12 +07:00
|
|
|
__asm {
|
2019-04-23 10:33:43 +08:00
|
|
|
mov edx, ds:[FO_VAR_world_ypos];
|
2019-12-04 10:39:35 +08:00
|
|
|
_J_RET_VAL_TYPE(VAR_TYPE_INT);
|
|
|
|
|
// retn;
|
2015-06-30 00:07:12 +07:00
|
|
|
}
|
|
|
|
|
}
|
2016-11-11 01:27:38 +07:00
|
|
|
|
2016-11-14 02:07:08 +07:00
|
|
|
void __declspec(naked) op_set_world_map_pos() {
|
2015-06-30 00:07:12 +07:00
|
|
|
__asm {
|
|
|
|
|
push ecx;
|
2020-03-19 12:32:42 +08:00
|
|
|
_GET_ARG(ecx, esi); // get y value
|
|
|
|
|
mov eax, ebx;
|
|
|
|
|
_GET_ARG_INT(end); // get x value
|
|
|
|
|
cmp si, VAR_TYPE_INT;
|
|
|
|
|
jne end;
|
|
|
|
|
mov ds:[FO_VAR_world_xpos], eax;
|
|
|
|
|
mov ds:[FO_VAR_world_ypos], ecx;
|
2015-06-30 00:07:12 +07:00
|
|
|
end:
|
2020-03-19 12:32:42 +08:00
|
|
|
pop ecx;
|
2015-06-30 00:07:12 +07:00
|
|
|
retn;
|
|
|
|
|
}
|
2015-11-16 10:40:26 +08:00
|
|
|
}
|
2016-11-14 02:07:08 +07:00
|
|
|
|
2020-05-20 11:30:25 +08:00
|
|
|
void op_set_map_time_multi(OpcodeContext& ctx) {
|
2020-03-19 12:32:42 +08:00
|
|
|
Worldmap::SetMapMulti(ctx.arg(0).asFloat());
|
2019-02-27 11:50:46 +08:00
|
|
|
}
|
|
|
|
|
|
2020-05-20 11:30:25 +08:00
|
|
|
void mf_set_car_intface_art(OpcodeContext& ctx) {
|
2019-11-28 14:05:36 +08:00
|
|
|
Worldmap::SetCarInterfaceArt(ctx.arg(0).rawValue());
|
2017-04-15 02:04:21 +07:00
|
|
|
}
|
|
|
|
|
|
2020-05-20 11:30:25 +08:00
|
|
|
void mf_set_map_enter_position(OpcodeContext& ctx) {
|
2019-11-28 14:05:36 +08:00
|
|
|
int tile = ctx.arg(0).rawValue();
|
|
|
|
|
int elev = ctx.arg(1).rawValue();
|
|
|
|
|
int rot = ctx.arg(2).rawValue();
|
2018-04-27 14:35:29 +03:00
|
|
|
|
2018-04-27 19:40:23 +08:00
|
|
|
if (tile > -1 && tile < 40000) {
|
2018-04-27 14:35:29 +03:00
|
|
|
fo::var::tile = tile;
|
|
|
|
|
}
|
|
|
|
|
if (elev > -1 && elev < 3) {
|
|
|
|
|
fo::var::elevation = elev;
|
|
|
|
|
}
|
|
|
|
|
if (rot > -1 && rot < 6) {
|
|
|
|
|
fo::var::rotation = rot;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-20 11:30:25 +08:00
|
|
|
void mf_get_map_enter_position(OpcodeContext& ctx) {
|
2020-10-12 11:01:25 +08:00
|
|
|
DWORD id = CreateTempArray(3, 0);
|
2018-04-27 14:35:29 +03:00
|
|
|
arrays[id].val[0].set((long)fo::var::tile);
|
|
|
|
|
arrays[id].val[1].set((long)fo::var::elevation);
|
|
|
|
|
arrays[id].val[2].set((long)fo::var::rotation);
|
2019-11-28 14:05:36 +08:00
|
|
|
ctx.setReturn(id);
|
2018-04-27 14:35:29 +03:00
|
|
|
}
|
|
|
|
|
|
2020-05-20 11:30:25 +08:00
|
|
|
void mf_set_rest_heal_time(OpcodeContext& ctx) {
|
2019-11-28 14:05:36 +08:00
|
|
|
Worldmap::SetRestHealTime(ctx.arg(0).rawValue());
|
2018-05-08 07:18:44 +03:00
|
|
|
}
|
|
|
|
|
|
2020-05-20 11:30:25 +08:00
|
|
|
void mf_set_rest_mode(OpcodeContext& ctx) {
|
2019-11-28 14:05:36 +08:00
|
|
|
Worldmap::SetRestMode(ctx.arg(0).rawValue());
|
2018-05-08 07:18:44 +03:00
|
|
|
}
|
|
|
|
|
|
2020-05-20 11:30:25 +08:00
|
|
|
void mf_set_rest_on_map(OpcodeContext& ctx) {
|
2019-11-28 14:05:36 +08:00
|
|
|
long mapId = ctx.arg(0).rawValue();
|
2018-09-28 13:59:09 +08:00
|
|
|
if (mapId < 0) {
|
2019-04-30 10:09:34 +08:00
|
|
|
ctx.printOpcodeError("%s() - invalid map number argument.", ctx.getMetaruleName());
|
2019-11-28 14:05:36 +08:00
|
|
|
ctx.setReturn(-1);
|
2018-09-28 13:59:09 +08:00
|
|
|
return;
|
|
|
|
|
}
|
2019-11-28 14:05:36 +08:00
|
|
|
long elev = ctx.arg(1).rawValue();
|
2019-07-17 09:15:00 +08:00
|
|
|
if (elev < -1 || elev > 2) {
|
2019-04-30 10:09:34 +08:00
|
|
|
ctx.printOpcodeError("%s() - invalid map elevation argument.", ctx.getMetaruleName());
|
2019-11-28 14:05:36 +08:00
|
|
|
ctx.setReturn(-1);
|
2018-09-28 13:59:09 +08:00
|
|
|
} else {
|
|
|
|
|
Worldmap::SetRestMapLevel(mapId, elev, ctx.arg(2).asBool());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-20 11:30:25 +08:00
|
|
|
void mf_get_rest_on_map(OpcodeContext& ctx) {
|
2019-11-28 14:05:36 +08:00
|
|
|
long result = -1;
|
|
|
|
|
long elev = ctx.arg(1).rawValue();
|
2019-07-17 09:15:00 +08:00
|
|
|
if (elev < 0 || elev > 2) {
|
2019-04-30 10:09:34 +08:00
|
|
|
ctx.printOpcodeError("%s() - invalid map elevation argument.", ctx.getMetaruleName());
|
2018-09-28 13:59:09 +08:00
|
|
|
} else {
|
2019-11-28 14:05:36 +08:00
|
|
|
result = Worldmap::GetRestMapLevel(elev, ctx.arg(0).rawValue());
|
2018-09-28 13:59:09 +08:00
|
|
|
}
|
2019-11-28 14:05:36 +08:00
|
|
|
ctx.setReturn(result);
|
2018-09-28 13:59:09 +08:00
|
|
|
}
|
|
|
|
|
|
2020-05-20 11:30:25 +08:00
|
|
|
void mf_tile_by_position(OpcodeContext& ctx) {
|
2019-12-11 15:52:03 +08:00
|
|
|
ctx.setReturn(fo::func::tile_num(ctx.arg(0).rawValue(), ctx.arg(1).rawValue()));
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-14 21:04:51 +08:00
|
|
|
static const char* invalidSubTilePos = "%s() - invalid x/y coordinates for the sub-tile.";
|
|
|
|
|
|
2020-05-20 11:30:25 +08:00
|
|
|
void mf_set_terrain_name(OpcodeContext& ctx) {
|
2022-06-14 21:04:51 +08:00
|
|
|
long x = ctx.arg(0).rawValue();
|
|
|
|
|
long y = ctx.arg(1).rawValue();
|
|
|
|
|
|
|
|
|
|
if (x < 0 || x >= (long)(7 * fo::var::wmNumHorizontalTiles) ||
|
|
|
|
|
y < 0 || y >= (long)(6 * (fo::var::wmMaxTileNum / fo::var::wmNumHorizontalTiles)))
|
|
|
|
|
{
|
|
|
|
|
ctx.printOpcodeError(invalidSubTilePos, ctx.getMetaruleName());
|
|
|
|
|
} else {
|
|
|
|
|
Worldmap::SetTerrainTypeName(x, y, ctx.arg(2).strValue());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mf_get_terrain_name(OpcodeContext& ctx) {
|
|
|
|
|
if (ctx.numArgs() < 2) {
|
|
|
|
|
ctx.setReturn(Worldmap::GetCurrentTerrainName());
|
|
|
|
|
} else {
|
|
|
|
|
long x = ctx.arg(0).rawValue();
|
|
|
|
|
long y = ctx.arg(1).rawValue();
|
|
|
|
|
|
|
|
|
|
if (x < 0 || x >= (long)(7 * fo::var::wmNumHorizontalTiles) ||
|
|
|
|
|
y < 0 || y >= (long)(6 * (fo::var::wmMaxTileNum / fo::var::wmNumHorizontalTiles)))
|
|
|
|
|
{
|
|
|
|
|
ctx.printOpcodeError(invalidSubTilePos, ctx.getMetaruleName());
|
|
|
|
|
ctx.setReturn("Error");
|
|
|
|
|
} else {
|
|
|
|
|
ctx.setReturn(Worldmap::GetTerrainTypeName(x, y));
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-01-18 17:28:05 +08:00
|
|
|
}
|
|
|
|
|
|
2020-05-20 11:30:25 +08:00
|
|
|
void mf_set_town_title(OpcodeContext& ctx) {
|
2020-01-25 15:47:57 +08:00
|
|
|
Worldmap::SetCustomAreaTitle(ctx.arg(0).rawValue(), ctx.arg(1).strValue());
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-05 21:49:21 +07:00
|
|
|
}
|
|
|
|
|
}
|