mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Added "get_terrain_name" script function
Updated documents for the function. Minor edits to other code.
This commit is contained in:
@@ -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: |
|
||||
|
||||
@@ -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)`\
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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}},
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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&);
|
||||
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user