Added "get_terrain_name" script function

Updated documents for the function.
Minor edits to other code.
This commit is contained in:
NovaRain
2022-06-14 21:04:51 +08:00
parent 7015db2414
commit 85e5da660b
15 changed files with 192 additions and 135 deletions
+5
View File
@@ -497,6 +497,11 @@
- name: set_terrain_name
detail: void sfall_func3("set_terrain_name", int x, int y, string name)
doc: Overrides the terrain type name for the sub-tile on the world map by the specified coordinates.
macro: sfall.h
- name: get_terrain_name
detail: string sfall_func2("get_terrain_name", int x, int y)
doc: Returns the terrain type name for the sub-tile on the world map by the specified coordinates, or by the player's current position if called without arguments.
macro: sfall.h
- name: set_town_title
detail: void sfall_func2("set_town_title", int areaID, string title)
doc: |
+2
View File
@@ -319,6 +319,7 @@
#define floor2(value) sfall_func1("floor2", value)
#define get_can_rest_on_map(map, elev) sfall_func2("get_can_rest_on_map", map, elev)
#define get_current_inven_size(obj) sfall_func1("get_current_inven_size", obj)
#define get_current_terrain_name sfall_func0("get_terrain_name")
#define get_cursor_mode sfall_func0("get_cursor_mode")
#define get_flags(obj) sfall_func1("get_flags", obj)
#define get_ini_section(file, sect) sfall_func2("get_ini_section", file, sect)
@@ -340,6 +341,7 @@
#define get_npc_stat_min(stat) sfall_func2("get_stat_min", stat, 1)
#define get_sfall_arg_at(argNum) sfall_func1("get_sfall_arg_at", argNum)
#define get_string_pointer(text) sfall_func1("get_string_pointer", text)
#define get_terrain_name(x, y) sfall_func2("get_terrain_name", x, y)
#define get_text_width(text) sfall_func1("get_text_width", text)
#define has_fake_perk_npc(npc, perk) sfall_func2("has_fake_perk_npc", npc, perk)
#define has_fake_trait_npc(npc, trait) sfall_func2("has_fake_trait_npc", npc, trait)
@@ -936,6 +936,12 @@ sfall_funcX metarule functions
`void sfall_func3("set_terrain_name", int x, int y, string name)`
- Overrides the terrain type name for the sub-tile on the world map by the specified coordinates
----
#### get_terrain_name
`string sfall_func0("get_terrain_name")`\
`string sfall_func2("get_terrain_name", int x, int y)`
- Returns the terrain type name for the sub-tile on the world map by the specified coordinates, or by the player's current position if called without arguments
----
#### get_window_attribute
`int sfall_func1("get_window_attribute", int winType)`\
+13 -1
View File
@@ -407,7 +407,19 @@ fo::GameObject* __fastcall MultiHexMoveIsBlocking(fo::GameObject* source, long d
return nullptr;
}
// Returns the type of the terrain sub tile at the the player's position on the world map
// Returns the terrain type of the sub-tile at the specified coordinates on the world map
long wmGetTerrainType(long xPos, long yPos) {
long* terrainId;
__asm {
lea ebx, terrainId;
mov edx, yPos;
mov eax, xPos;
call fo::funcoffs::wmFindCurSubTileFromPos_;
}
return *terrainId;
}
// Returns the terrain type of the sub-tile at the the player's position on the world map
long wmGetCurrentTerrainType() {
long* terrainId = *(long**)FO_VAR_world_subtile;
if (terrainId == nullptr) {
+2
View File
@@ -137,6 +137,8 @@ fo::GameObject* CheckAroundBlockingTiles(fo::GameObject* source, long dstTile);
fo::GameObject* __fastcall MultiHexMoveIsBlocking(fo::GameObject* source, long dstTile);
long wmGetTerrainType(long xPos, long yPos);
long wmGetCurrentTerrainType();
void SurfaceCopyToMem(long fromX, long fromY, long width, long height, long fromWidth, BYTE* fromSurface, BYTE* toMem);
+121 -122
View File
@@ -1258,22 +1258,22 @@ inCombat:
static void __declspec(naked) action_explode_hack() {
using namespace fo::Scripts;
__asm {
mov edx, destroy_p_proc
mov eax, [esi + scriptId] // pobj.sid
call fo::funcoffs::exec_script_proc_
xor edx, edx
dec edx
retn
mov edx, destroy_p_proc;
mov eax, [esi + scriptId]; // pobj.sid
call fo::funcoffs::exec_script_proc_;
xor edx, edx;
dec edx;
retn;
}
}
static void __declspec(naked) action_explode_hack1() {
__asm {
push esi
mov esi, [esi+0x40] // ctd.target#
call action_explode_hack
pop esi
retn
push esi;
mov esi, [esi + 0x40]; // ctd.target#
call action_explode_hack;
pop esi;
retn;
}
}
@@ -1342,140 +1342,140 @@ end:
static void __declspec(naked) db_get_file_list_hack() {
__asm {
push edi
push edx
xchg edi, eax // edi = *filename
mov eax, [eax+4] // file_lists.filenames
lea esi, [eax+edx]
cld
push es
push ds
pop es
xor ecx, ecx
dec ecx
mov edx, ecx
mov ebx, ecx
xor eax, eax // searching for end of line
repne scasb
not ecx
dec ecx
xchg ebx, ecx // ebx = filename length
lea edi, [esp+0x200+4*6]
repne scasb
not ecx
xchg edx, ecx // edx = extension length +1 for "end of line"
mov edi, [esi]
repne scasb
not ecx // ecx = buffer line length +1 for "end of line"
pop es
lea eax, [ebx+edx] // eax = new line length
cmp eax, ecx // new line length <= buffer line length?
jbe end // Yes
mov edx, [esi]
xchg edx, eax
call fo::funcoffs::nrealloc_ // eax = mem, edx = size
test eax, eax
jnz skip
push 0x50B2F0 // "Error: Ran out of memory!"
call fo::funcoffs::debug_printf_
add esp, 4
jmp end
push edi;
push edx;
xchg edi, eax; // edi = *filename
mov eax, [eax + 4]; // file_lists.filenames
lea esi, [eax + edx];
cld;
push es;
push ds;
pop es;
xor ecx, ecx;
dec ecx;
mov edx, ecx;
mov ebx, ecx;
xor eax, eax; // searching for end of line
repne scasb;
not ecx;
dec ecx;
xchg ebx, ecx; // ebx = filename length
lea edi, [esp + 0x200 + 6*4];
repne scasb;
not ecx;
xchg edx, ecx; // edx = extension length +1 for "end of line"
mov edi, [esi];
repne scasb;
not ecx; // ecx = buffer line length +1 for "end of line"
pop es;
lea eax, [ebx + edx]; // eax = new line length
cmp eax, ecx; // new line length <= buffer line length?
jbe end; // Yes
mov edx, [esi];
xchg edx, eax;
call fo::funcoffs::nrealloc_; // eax = mem, edx = size
test eax, eax;
jnz skip;
push 0x50B2F0; // "Error: Ran out of memory!"
call fo::funcoffs::debug_printf_;
add esp, 4;
jmp end;
skip:
mov [esi], eax
mov [esi], eax;
end:
xchg esi, eax
pop edx
pop edi
retn
xchg esi, eax;
pop edx;
pop edi;
retn;
}
}
static void __declspec(naked) gdActivateBarter_hook() {
__asm {
call fo::funcoffs::gdialog_barter_pressed_
cmp ds:[FO_VAR_dialogue_state], ecx
jne skip
cmp ds:[FO_VAR_dialogue_switch_mode], esi
je end
call fo::funcoffs::gdialog_barter_pressed_;
cmp ds:[FO_VAR_dialogue_state], ecx;
jne skip;
cmp ds:[FO_VAR_dialogue_switch_mode], esi;
je end;
skip:
push ecx
push esi
push edi
push ebp
sub esp, 0x18
push 0x44A5CC
push ecx;
push esi;
push edi;
push ebp;
sub esp, 0x18;
push 0x44A5CC;
end:
retn
retn;
}
}
static void __declspec(naked) switch_hand_hack() {
__asm {
mov eax, ds:[FO_VAR_inven_dude]
push eax
mov [edi], ebp
inc ecx // if ecx == -1
jz skip
xor ebx, ebx
inc ebx
mov edx, ebp
call fo::funcoffs::item_remove_mult_
mov eax, ds:[FO_VAR_inven_dude];
push eax;
mov [edi], ebp;
inc ecx; // if ecx == -1
jz skip;
xor ebx, ebx;
inc ebx;
mov edx, ebp;
call fo::funcoffs::item_remove_mult_;
skip:
pop edx // _inven_dude
mov eax, ebp
call fo::funcoffs::item_get_type_
cmp eax, item_type_container
jne end
mov [ebp + owner], edx // iobj.owner = _inven_dude
pop edx; // _inven_dude
mov eax, ebp;
call fo::funcoffs::item_get_type_;
cmp eax, item_type_container;
jne end;
mov [ebp + owner], edx; // iobj.owner = _inven_dude
end:
pop ebp
pop edi
pop esi
retn
pop ebp;
pop edi;
pop esi;
retn;
}
}
static void __declspec(naked) inven_item_wearing() {
__asm {
mov esi, ds:[FO_VAR_inven_dude]
xchg ebx, eax // ebx = source
mov eax, [esi + artFid]
and eax, 0xF000000
sar eax, 0x18
test eax, eax // check if object FID type flag is set to item
jnz skip // No
mov eax, esi
call fo::funcoffs::item_get_type_
cmp eax, item_type_container // Bag/Backpack?
jne skip // No
mov eax, esi
call fo::funcoffs::obj_top_environment_
test eax, eax // has an owner?
jz skip // No
mov ecx, [eax + artFid]
and ecx, 0xF000000
sar ecx, 0x18
cmp ecx, OBJ_TYPE_CRITTER // check if object FID type flag is set to critter
jne skip // No
cmp eax, ebx // the owner of the bag == source?
je end // Yes
mov esi, ds:[FO_VAR_inven_dude];
xchg ebx, eax; // ebx = source
mov eax, [esi + artFid];
and eax, 0xF000000;
sar eax, 0x18;
test eax, eax; // check if object FID type flag is set to item
jnz skip; // No
mov eax, esi;
call fo::funcoffs::item_get_type_;
cmp eax, item_type_container; // Bag/Backpack?
jne skip; // No
mov eax, esi;
call fo::funcoffs::obj_top_environment_;
test eax, eax; // has an owner?
jz skip; // No
mov ecx, [eax + artFid];
and ecx, 0xF000000;
sar ecx, 0x18;
cmp ecx, OBJ_TYPE_CRITTER; // check if object FID type flag is set to critter
jne skip; // No
cmp eax, ebx; // the owner of the bag == source?
je end; // Yes
skip:
xchg ebx, eax
cmp eax, esi
xchg ebx, eax;
cmp eax, esi;
end:
retn
retn;
}
}
static void __declspec(naked) inven_action_cursor_hack() {
__asm {
cmp dword ptr [esp+0x44+0x4], item_type_container
jne end
cmp eax, ds:[FO_VAR_stack]
je end
cmp eax, ds:[FO_VAR_target_stack]
cmp dword ptr [esp + 0x44 + 4], item_type_container;
jne end;
cmp eax, ds:[FO_VAR_stack];
je end;
cmp eax, ds:[FO_VAR_target_stack];
end:
retn
retn;
}
}
@@ -1574,7 +1574,7 @@ end:
static void __declspec(naked) apply_damage_hack() {
__asm {
xchg edx, eax;
test [esi+0x15], dl; // ctd.flags2Source & DAM_HIT_?
test [esi + 0x15], dl; // ctd.flags2Source & DAM_HIT_?
jz end; // No
inc ebx;
end:
@@ -1585,9 +1585,9 @@ end:
static void __declspec(naked) compute_attack_hook() {
__asm {
call fo::funcoffs::attack_crit_success_;
test [esi+0x15], 2; // ctd.flags2Source & DAM_CRITICAL_?
test [esi + 0x15], 2; // ctd.flags2Source & DAM_CRITICAL_?
jz end; // No
cmp dword ptr [esp+0x4+0x20], 4; // Has Silent Death perk?
cmp dword ptr [esp + 0x20 + 4], 4; // Has Silent Death perk?
jne end; // No
shl eax, 1; // Multiply by 2 for the perk effect
end:
@@ -1949,8 +1949,8 @@ fix:
}
}
static DWORD op_start_gdialog_ret = 0x456F4B;
static void __declspec(naked) op_start_gdialog_hack() {
static const DWORD op_start_gdialog_ret = 0x456F4B;
__asm {
cmp eax, -1; // check mood arg
jnz useMood;
@@ -3179,8 +3179,7 @@ static void __declspec(naked) action_can_be_pushed_hook() {
}
}
void BugFixes::init()
{
void BugFixes::init() {
#ifndef NDEBUG
LoadGameHook::OnBeforeGameClose() += PrintAddrList;
if (IniReader::GetIntDefaultConfig("Debugging", "BugFixes", 1) == 0) return;
@@ -170,6 +170,5 @@ void mf_unwield_slot(OpcodeContext& ctx) {
if (update) fo::func::intface_update_items(0, -1, -1);
}
}
}
@@ -98,6 +98,7 @@ static const SfallMetarule metarules[] = {
{"get_stat_max", mf_get_stat_max, 1, 2, 0, {ARG_INT, ARG_INT}},
{"get_stat_min", mf_get_stat_min, 1, 2, 0, {ARG_INT, ARG_INT}},
{"get_string_pointer", mf_get_string_pointer, 1, 1, 0, {ARG_STRING}},
{"get_terrain_name", mf_get_terrain_name, 0, 2, -1, {ARG_INT, ARG_INT}},
{"get_text_width", mf_get_text_width, 1, 1, 0, {ARG_STRING}},
{"get_window_attribute", mf_get_window_attribute, 1, 2, -1, {ARG_INT, ARG_INT}},
{"has_fake_perk_npc", mf_has_fake_perk_npc, 2, 2, 0, {ARG_OBJECT, ARG_STRING}},
+1 -1
View File
@@ -42,7 +42,7 @@ namespace sfall
namespace script
{
const char* stringTooLong = "%s() - the string exceeds maximum length of 64 characters.";
static const char* stringTooLong = "%s() - the string exceeds maximum length of 64 characters.";
void __declspec(naked) op_stop_game() {
__asm {
+1 -1
View File
@@ -112,7 +112,7 @@ void op_set_fake_trait(OpcodeContext& ctx) {
Perks::SetFakeTrait(ctx.arg(0).strValue(), ctx.arg(1).rawValue(), ctx.arg(2).rawValue(), ctx.arg(3).strValue());
}
const char* notPartyMemberErr = "%s() - the object is not a party member.";
static const char* notPartyMemberErr = "%s() - the object is not a party member.";
void mf_set_selectable_perk_npc(OpcodeContext& ctx) {
auto obj = ctx.arg(0).object();
+2 -2
View File
@@ -34,8 +34,8 @@ namespace sfall
namespace script
{
const char* invalidStat = "%s() - stat number out of range.";
const char* objNotCritter = "%s() - the object is not a critter.";
static const char* invalidStat = "%s() - stat number out of range.";
static const char* objNotCritter = "%s() - the object is not a critter.";
void __declspec(naked) op_set_hp_per_level_mod() {
__asm {
+30 -1
View File
@@ -237,8 +237,37 @@ void mf_tile_by_position(OpcodeContext& ctx) {
ctx.setReturn(fo::func::tile_num(ctx.arg(0).rawValue(), ctx.arg(1).rawValue()));
}
static const char* invalidSubTilePos = "%s() - invalid x/y coordinates for the sub-tile.";
void mf_set_terrain_name(OpcodeContext& ctx) {
Worldmap::SetTerrainTypeName(ctx.arg(0).rawValue(), ctx.arg(1).rawValue(), ctx.arg(2).strValue());
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));
}
}
}
void mf_set_town_title(OpcodeContext& ctx) {
@@ -60,6 +60,8 @@ void mf_tile_by_position(OpcodeContext&);
void mf_set_terrain_name(OpcodeContext&);
void mf_get_terrain_name(OpcodeContext&);
void mf_set_town_title(OpcodeContext&);
}
+5 -5
View File
@@ -672,13 +672,13 @@ void Worldmap::SetTerrainTypeName(long x, long y, const char* name) {
wmTerrainTypeNames.push_back(std::make_pair(subTileID, name));
}
// TODO: someone might need to know the name of a terrain type?
/*const char* Worldmap::GetTerrainTypeName(long x, long y) {
// Returns the name of the terrain type at the specified coordinates on the world map
const char* Worldmap::GetTerrainTypeName(long x, long y) {
const char* name = GetOverrideTerrainName(x, y);
return (name) ? name : fo::util::GetMessageStr(&fo::var::wmMsgFile, 1000 + fo::wmGetTerrainType(x, y));
}*/
return (name) ? name : fo::util::GetMessageStr(&fo::var::wmMsgFile, 1000 + fo::util::wmGetTerrainType(x * 50, y * 50));
}
// Returns the name of the terrain type in the position of the player's marker on the world map
// Returns the name of the terrain type at the position of the player's marker on the world map
const char* Worldmap::GetCurrentTerrainName() {
const char* name = GetOverrideTerrainName(fo::var::world_xpos / 50, fo::var::world_ypos / 50);
return (name) ? name : fo::util::GetMessageStr(&fo::var::wmMsgFile, 1000 + fo::util::wmGetCurrentTerrainType());
+1 -1
View File
@@ -44,7 +44,7 @@ public:
static void SetAddedYears(DWORD years);
static void SetTerrainTypeName(long x, long y, const char* name);
//static const char* GetTerrainTypeName(long x, long y);
static const char* GetTerrainTypeName(long x, long y);
static const char* GetCurrentTerrainName();
static bool AreaTitlesIsEmpty();