mirror of
https://github.com/fallout2-ce/fallout2-ce.git
synced 2026-07-27 16:47:11 -07:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5f7a54e5de | ||
|
|
1db054e47a |
@@ -42,6 +42,11 @@ The following settings were moved into [`<DAT>/config/game.cfg`](files/ce.dat/co
|
||||
|
||||
| ddraw.ini section | ddraw.ini key | game.cfg section | game.cfg key |
|
||||
| --- | --- | --- | --- |
|
||||
| `Misc` | `StartingMap` | `start` | `map` |
|
||||
| `Misc` | `StartXPos` | `start` | `worldmap_x` |
|
||||
| `Misc` | `StartYPos` | `start` | `worldmap_y` |
|
||||
| `Misc` | `ViewXPos` | `start` | `worldmap_view_x` |
|
||||
| `Misc` | `ViewYPos` | `start` | `worldmap_view_y` |
|
||||
| `Misc` | `StartGDialogFix` | `dialog` | `start_gdialog_fix` |
|
||||
|
||||
## Opcodes / Metarules
|
||||
@@ -52,7 +57,7 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
|
||||
| --- | --- | --- | --- |
|
||||
| Direct memory access| read_byte,short,int,string<br>write_byte,short,int,string<br>call_offset_vX | đźš« | Not possible. Open an issue if you need functionality not covered by other opcodes. |
|
||||
| Stats | get/set_pc_base_stat<br>get/set_pc_extra_stat<br>get/set_critter_base_stat<br>get/set_critter_extra_stat | âś… | CE uses engine stat helpers here instead of sfall's direct proto-field behavior, so derived-stat update behavior can differ. |
|
||||
| Stats / Alter min/max | get/set_stat_min/max<br>set_pc_stat_min/max<br>set_npc_stat_min/max | not implemented | - |
|
||||
| Stats / Alter min/max | get/set_stat_min/max<br>set_pc_stat_min/max<br>set_npc_stat_min/max | âś… | - |
|
||||
| Skills | get/set_critter_skill_points<br>get/set_available_skill_points<br>set_skill_max<br>set_critter_skill_mod<br>set_base_skill_mod<br>mod_skill_points_per_level | not implemented | - |
|
||||
| Graphics | graphics_funcs_available<br>force_graphics_refresh<br>get_screen_width<br>get_screen_height<br>set_palette | implemented: only get_screen_width, get_screen_height | - |
|
||||
| Shaders | load_shader<br>free_shader<br>activate_shader<br>deactivate_shader<br>set/get_shader_* | đźš« | likely will not implement direct compatibility
|
||||
|
||||
@@ -11,6 +11,12 @@ month=6
|
||||
day=24
|
||||
; To start a new game somewhere other than artemple.map, set this to the map file name.
|
||||
map=
|
||||
; Starting worldmap marker position. -1 uses the starting map's world area.
|
||||
worldmap_x=-1
|
||||
worldmap_y=-1
|
||||
; Starting worldmap viewport position. -1 uses the default upper-left view.
|
||||
worldmap_view_x=-1
|
||||
worldmap_view_y=-1
|
||||
; Starting (tribal) and default (jumpsuit) player models. Can also be changed in-game via script.
|
||||
model_male=hmwarr
|
||||
model_male_default=hmjmps
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
#include "define_lite.h"
|
||||
#include "sfall.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
procedure start begin
|
||||
variable original_extra;
|
||||
variable original_value;
|
||||
variable original_pc_max;
|
||||
variable original_pc_min;
|
||||
variable original_npc_max;
|
||||
variable original_npc_min;
|
||||
variable original_npc_luck_max;
|
||||
variable test_npc;
|
||||
variable test_npc_extra;
|
||||
variable test_npc_luck;
|
||||
|
||||
if (not game_loaded) then return;
|
||||
|
||||
display_msg("Testing stat min/max...");
|
||||
test_suite_errors := 0;
|
||||
|
||||
original_extra := get_pc_extra_stat(STAT_rad_resist);
|
||||
original_value := get_critter_stat(dude_obj, STAT_rad_resist);
|
||||
original_pc_max := get_pc_stat_max(STAT_rad_resist);
|
||||
original_pc_min := get_pc_stat_min(STAT_rad_resist);
|
||||
original_npc_max := get_npc_stat_max(STAT_rad_resist);
|
||||
original_npc_min := get_npc_stat_min(STAT_rad_resist);
|
||||
|
||||
set_stat_max(STAT_rad_resist, 101);
|
||||
call assertEquals("set_stat_max changes PC bound", get_pc_stat_max(STAT_rad_resist), 101);
|
||||
call assertEquals("set_stat_max changes NPC bound", get_npc_stat_max(STAT_rad_resist), 101);
|
||||
|
||||
set_stat_min(STAT_rad_resist, -10);
|
||||
call assertEquals("set_stat_min changes PC bound", get_pc_stat_min(STAT_rad_resist), -10);
|
||||
call assertEquals("set_stat_min changes NPC bound", get_npc_stat_min(STAT_rad_resist), -10);
|
||||
|
||||
set_pc_extra_stat(STAT_rad_resist, 200);
|
||||
set_pc_stat_max(STAT_rad_resist, 100);
|
||||
call assertEquals("PC maximum changed independently", get_pc_stat_max(STAT_rad_resist), 100);
|
||||
call assertEquals("NPC maximum unchanged by PC setter", get_npc_stat_max(STAT_rad_resist), 101);
|
||||
call assertEquals("radiation resistance capped at 100", get_critter_stat(dude_obj, STAT_rad_resist), 100);
|
||||
|
||||
set_pc_extra_stat(STAT_rad_resist, -200);
|
||||
set_pc_stat_min(STAT_rad_resist, -5);
|
||||
call assertEquals("PC minimum changed independently", get_pc_stat_min(STAT_rad_resist), -5);
|
||||
call assertEquals("NPC minimum unchanged by PC setter", get_npc_stat_min(STAT_rad_resist), -10);
|
||||
call assertEquals("radiation resistance clamped to PC minimum", get_critter_stat(dude_obj, STAT_rad_resist), -5);
|
||||
|
||||
set_npc_stat_max(STAT_rad_resist, 99);
|
||||
call assertEquals("NPC maximum changed independently", get_npc_stat_max(STAT_rad_resist), 99);
|
||||
call assertEquals("PC maximum unchanged by NPC setter", get_pc_stat_max(STAT_rad_resist), 100);
|
||||
|
||||
set_npc_stat_min(STAT_rad_resist, -4);
|
||||
call assertEquals("NPC minimum changed independently", get_npc_stat_min(STAT_rad_resist), -4);
|
||||
call assertEquals("PC minimum unchanged by NPC setter", get_pc_stat_min(STAT_rad_resist), -5);
|
||||
|
||||
test_npc := create_object_sid(0x01000001, 0, 0, -1);
|
||||
test_npc_extra := get_critter_extra_stat(test_npc, STAT_rad_resist);
|
||||
set_critter_extra_stat(test_npc, STAT_rad_resist, 200);
|
||||
call assertEquals("NPC radiation resistance uses NPC maximum", get_critter_stat(test_npc, STAT_rad_resist), 99);
|
||||
set_critter_extra_stat(test_npc, STAT_rad_resist, test_npc_extra);
|
||||
|
||||
test_npc_luck := get_critter_base_stat(test_npc, STAT_lu);
|
||||
original_npc_luck_max := get_npc_stat_max(STAT_lu);
|
||||
set_npc_stat_max(STAT_lu, test_npc_luck - 1);
|
||||
set_critter_base_stat(test_npc, STAT_lu, test_npc_luck + 1);
|
||||
call assertEquals("NPC base stat rejects value above configured maximum", get_critter_base_stat(test_npc, STAT_lu), test_npc_luck);
|
||||
set_npc_stat_max(STAT_lu, original_npc_luck_max);
|
||||
destroy_object(test_npc);
|
||||
|
||||
set_pc_stat_max(STAT_rad_resist, original_pc_max);
|
||||
set_pc_stat_min(STAT_rad_resist, original_pc_min);
|
||||
set_npc_stat_max(STAT_rad_resist, original_npc_max);
|
||||
set_npc_stat_min(STAT_rad_resist, original_npc_min);
|
||||
set_pc_extra_stat(STAT_rad_resist, original_extra);
|
||||
call assertEquals("original radiation resistance restored", get_critter_stat(dude_obj, STAT_rad_resist), original_value);
|
||||
|
||||
call report_test_results("stat min/max");
|
||||
signal_close_game;
|
||||
end
|
||||
@@ -175,6 +175,10 @@ namespace {
|
||||
constexpr SfallMigrationEntry kSfallMigrationEntries[] = {
|
||||
// [start]
|
||||
{ kSfallMisc, "StartingMap", CONTENT_CONFIG_START_SECTION, "map", "" },
|
||||
{ kSfallMisc, "StartXPos", CONTENT_CONFIG_START_SECTION, "worldmap_x", "-1" },
|
||||
{ kSfallMisc, "StartYPos", CONTENT_CONFIG_START_SECTION, "worldmap_y", "-1" },
|
||||
{ kSfallMisc, "ViewXPos", CONTENT_CONFIG_START_SECTION, "worldmap_view_x", "-1" },
|
||||
{ kSfallMisc, "ViewYPos", CONTENT_CONFIG_START_SECTION, "worldmap_view_y", "-1" },
|
||||
{ kSfallMisc, "MaleStartModel", CONTENT_CONFIG_START_SECTION, "model_male", "hmwarr" },
|
||||
{ kSfallMisc, "MaleDefaultModel", CONTENT_CONFIG_START_SECTION, "model_male_default", "hmjmps" },
|
||||
{ kSfallMisc, "FemaleStartModel", CONTENT_CONFIG_START_SECTION, "model_female", "hfprim" },
|
||||
|
||||
+13
@@ -331,6 +331,19 @@ static int _main_load_new(char* mapFileName)
|
||||
gameMouseSetCursor(MOUSE_CURSOR_NONE);
|
||||
mouseShowCursor();
|
||||
mapLoadByName(mapFileName);
|
||||
|
||||
// SFALL: Fix the starting position of the player's marker on the world map
|
||||
// when starting a new game with a custom starting map.
|
||||
int areaIdx;
|
||||
if (wmMatchAreaContainingMapIdx(gMapHeader.index, &areaIdx) == 0) {
|
||||
if (wmStartWorldPosIsConfigured()) {
|
||||
wmSetPartyCurArea(areaIdx);
|
||||
wmClearPartyWalking();
|
||||
} else {
|
||||
wmTeleportToArea(areaIdx);
|
||||
}
|
||||
}
|
||||
|
||||
wmMapMusicStart();
|
||||
paletteFadeTo(gPaletteWhite);
|
||||
windowDestroy(win);
|
||||
|
||||
+17
-2
@@ -38,6 +38,7 @@
|
||||
#include "sfall_opcodes.h"
|
||||
#include "sfall_script_hooks.h"
|
||||
#include "skilldex.h"
|
||||
#include "stat.h"
|
||||
#include "text_font.h"
|
||||
#include "tile.h"
|
||||
#include "window.h"
|
||||
@@ -779,6 +780,8 @@ static void mf_get_object_ai_data(OpcodeContext& ctx);
|
||||
static void mf_get_object_data(OpcodeContext& ctx);
|
||||
static void mf_get_outline(OpcodeContext& ctx);
|
||||
static void mf_get_sfall_arg_at(OpcodeContext& ctx);
|
||||
static void mf_get_stat_max(OpcodeContext& ctx);
|
||||
static void mf_get_stat_min(OpcodeContext& ctx);
|
||||
static void mf_get_terrain_name(OpcodeContext& ctx);
|
||||
static void mf_get_text_width(OpcodeContext& ctx);
|
||||
static void mf_get_window_attribute(OpcodeContext& ctx);
|
||||
@@ -858,8 +861,8 @@ const MetaruleInfo kMetarules[] = {
|
||||
{ "get_object_data", mf_get_object_data, 2, 2, 0, { ARG_OBJECT, ARG_INT } },
|
||||
{ "get_outline", mf_get_outline, 1, 1, 0, { ARG_OBJECT } },
|
||||
{ "get_sfall_arg_at", mf_get_sfall_arg_at, 1, 1, 0, { ARG_INT } },
|
||||
// {"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_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}}, // note: deprecated; do not implement
|
||||
{ "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 } },
|
||||
@@ -1216,6 +1219,18 @@ void mf_get_sfall_arg_at(OpcodeContext& ctx)
|
||||
ctx.setReturn(result);
|
||||
}
|
||||
|
||||
void mf_get_stat_max(OpcodeContext& ctx)
|
||||
{
|
||||
const bool npc = ctx.numArgs() > 1 && ctx.arg(1).asInt() != 0;
|
||||
ctx.setReturn(statGetConfiguredMaximum(ctx.arg(0).asInt(), npc));
|
||||
}
|
||||
|
||||
void mf_get_stat_min(OpcodeContext& ctx)
|
||||
{
|
||||
const bool npc = ctx.numArgs() > 1 && ctx.arg(1).asInt() != 0;
|
||||
ctx.setReturn(statGetConfiguredMinimum(ctx.arg(0).asInt(), npc));
|
||||
}
|
||||
|
||||
void mf_get_object_ai_data(OpcodeContext& ctx)
|
||||
{
|
||||
Object* object = ctx.arg(0).asObject();
|
||||
|
||||
@@ -160,6 +160,50 @@ static void op_set_critter_extra_stat(Program* program)
|
||||
critterSetBonusStat(obj, stat, value);
|
||||
}
|
||||
|
||||
static void op_set_stat_max(Program* program)
|
||||
{
|
||||
int maximum = programStackPopInteger(program);
|
||||
int stat = programStackPopInteger(program);
|
||||
statSetPcMaximum(stat, maximum);
|
||||
statSetNpcMaximum(stat, maximum);
|
||||
}
|
||||
|
||||
static void op_set_stat_min(Program* program)
|
||||
{
|
||||
int minimum = programStackPopInteger(program);
|
||||
int stat = programStackPopInteger(program);
|
||||
statSetPcMinimum(stat, minimum);
|
||||
statSetNpcMinimum(stat, minimum);
|
||||
}
|
||||
|
||||
static void op_set_pc_stat_max(Program* program)
|
||||
{
|
||||
int maximum = programStackPopInteger(program);
|
||||
int stat = programStackPopInteger(program);
|
||||
statSetPcMaximum(stat, maximum);
|
||||
}
|
||||
|
||||
static void op_set_pc_stat_min(Program* program)
|
||||
{
|
||||
int minimum = programStackPopInteger(program);
|
||||
int stat = programStackPopInteger(program);
|
||||
statSetPcMinimum(stat, minimum);
|
||||
}
|
||||
|
||||
static void op_set_npc_stat_max(Program* program)
|
||||
{
|
||||
int maximum = programStackPopInteger(program);
|
||||
int stat = programStackPopInteger(program);
|
||||
statSetNpcMaximum(stat, maximum);
|
||||
}
|
||||
|
||||
static void op_set_npc_stat_min(Program* program)
|
||||
{
|
||||
int minimum = programStackPopInteger(program);
|
||||
int stat = programStackPopInteger(program);
|
||||
statSetNpcMinimum(stat, minimum);
|
||||
}
|
||||
|
||||
// get_pc_base_stat
|
||||
static void op_get_pc_base_stat(Program* program)
|
||||
{
|
||||
@@ -1896,11 +1940,17 @@ void sfallOpcodesInit()
|
||||
// 0x8246 - void mod_skill_points_per_level(int value)
|
||||
|
||||
// 0x81b4 - void set_stat_max(int stat, int value)
|
||||
interpreterRegisterOpcode(0x81B4, op_set_stat_max);
|
||||
// 0x81b5 - void set_stat_min(int stat, int value)
|
||||
interpreterRegisterOpcode(0x81B5, op_set_stat_min);
|
||||
// 0x81b7 - void set_pc_stat_max(int stat, int value)
|
||||
interpreterRegisterOpcode(0x81B7, op_set_pc_stat_max);
|
||||
// 0x81b8 - void set_pc_stat_min(int stat, int value)
|
||||
interpreterRegisterOpcode(0x81B8, op_set_pc_stat_min);
|
||||
// 0x81b9 - void set_npc_stat_max(int stat, int value)
|
||||
interpreterRegisterOpcode(0x81B9, op_set_npc_stat_max);
|
||||
// 0x81ba - void set_npc_stat_min(int stat, int value)
|
||||
interpreterRegisterOpcode(0x81BA, op_set_npc_stat_min);
|
||||
|
||||
// 0x816b - int input_funcs_available() // deprecated; do not implement
|
||||
// 0x816c - int key_pressed(int dxScancode)
|
||||
|
||||
+89
-3
@@ -98,14 +98,25 @@ static char* gStatValueDescriptions[PRIMARY_STAT_RANGE];
|
||||
// 0x6681AC curr_pc_stat
|
||||
static int gPcStatValues[PC_STAT_COUNT];
|
||||
|
||||
static int pcStatMaximums[SAVEABLE_STAT_COUNT];
|
||||
static int pcStatMinimums[SAVEABLE_STAT_COUNT];
|
||||
static int npcStatMaximums[SAVEABLE_STAT_COUNT];
|
||||
static int npcStatMinimums[SAVEABLE_STAT_COUNT];
|
||||
|
||||
static int unspentApBonus = 4;
|
||||
static int unspentApPerkBonus = 4;
|
||||
|
||||
static void statResetBounds();
|
||||
static int statGetMaximum(Object* critter, int stat);
|
||||
static int statGetMinimum(Object* critter, int stat);
|
||||
|
||||
// 0x4AED70
|
||||
int statsInit()
|
||||
{
|
||||
MessageListItem messageListItem;
|
||||
|
||||
statResetBounds();
|
||||
|
||||
// NOTE: Uninline.
|
||||
pcStatsReset();
|
||||
|
||||
@@ -144,6 +155,7 @@ int statsReset()
|
||||
{
|
||||
// NOTE: Uninline.
|
||||
pcStatsReset();
|
||||
statResetBounds();
|
||||
statResetUnspentApBonuses();
|
||||
|
||||
return 0;
|
||||
@@ -208,6 +220,72 @@ int statGetUnspentApPerkBonus()
|
||||
return unspentApPerkBonus;
|
||||
}
|
||||
|
||||
static void statResetBounds()
|
||||
{
|
||||
for (int stat = 0; stat < SAVEABLE_STAT_COUNT; stat++) {
|
||||
pcStatMaximums[stat] = gStatDescriptions[stat].maximumValue;
|
||||
pcStatMinimums[stat] = gStatDescriptions[stat].minimumValue;
|
||||
npcStatMaximums[stat] = gStatDescriptions[stat].maximumValue;
|
||||
npcStatMinimums[stat] = gStatDescriptions[stat].minimumValue;
|
||||
}
|
||||
}
|
||||
|
||||
static int statGetMaximum(Object* critter, int stat)
|
||||
{
|
||||
return critter == gDude ? pcStatMaximums[stat] : npcStatMaximums[stat];
|
||||
}
|
||||
|
||||
static int statGetMinimum(Object* critter, int stat)
|
||||
{
|
||||
return critter == gDude ? pcStatMinimums[stat] : npcStatMinimums[stat];
|
||||
}
|
||||
|
||||
int statGetConfiguredMaximum(int stat, bool npc)
|
||||
{
|
||||
if (stat >= 0 && stat < SAVEABLE_STAT_COUNT) {
|
||||
return npc ? npcStatMaximums[stat] : pcStatMaximums[stat];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int statGetConfiguredMinimum(int stat, bool npc)
|
||||
{
|
||||
if (stat >= 0 && stat < SAVEABLE_STAT_COUNT) {
|
||||
return npc ? npcStatMinimums[stat] : pcStatMinimums[stat];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void statSetPcMaximum(int stat, int maximum)
|
||||
{
|
||||
if (stat >= 0 && stat < SAVEABLE_STAT_COUNT) {
|
||||
pcStatMaximums[stat] = maximum;
|
||||
}
|
||||
}
|
||||
|
||||
void statSetPcMinimum(int stat, int minimum)
|
||||
{
|
||||
if (stat >= 0 && stat < SAVEABLE_STAT_COUNT) {
|
||||
pcStatMinimums[stat] = minimum;
|
||||
}
|
||||
}
|
||||
|
||||
void statSetNpcMaximum(int stat, int maximum)
|
||||
{
|
||||
if (stat >= 0 && stat < SAVEABLE_STAT_COUNT) {
|
||||
npcStatMaximums[stat] = maximum;
|
||||
}
|
||||
}
|
||||
|
||||
void statSetNpcMinimum(int stat, int minimum)
|
||||
{
|
||||
if (stat >= 0 && stat < SAVEABLE_STAT_COUNT) {
|
||||
npcStatMinimums[stat] = minimum;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4AEF48
|
||||
int critterGetStat(Object* critter, int stat)
|
||||
{
|
||||
@@ -397,7 +475,15 @@ int critterGetStat(Object* critter, int stat)
|
||||
}
|
||||
}
|
||||
|
||||
value = std::clamp(value, gStatDescriptions[stat].minimumValue, gStatDescriptions[stat].maximumValue);
|
||||
int minimum = statGetMinimum(critter, stat);
|
||||
if (value < minimum) {
|
||||
value = minimum;
|
||||
} else {
|
||||
int maximum = statGetMaximum(critter, stat);
|
||||
if (value > maximum) {
|
||||
value = maximum;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (stat) {
|
||||
case STAT_CURRENT_HIT_POINTS:
|
||||
@@ -485,11 +571,11 @@ int critterSetBaseStat(Object* critter, int stat, int value)
|
||||
value -= traitGetStatModifier(stat);
|
||||
}
|
||||
|
||||
if (value < gStatDescriptions[stat].minimumValue) {
|
||||
if (value < statGetMinimum(critter, stat)) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (value > gStatDescriptions[stat].maximumValue) {
|
||||
if (value > statGetMaximum(critter, stat)) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,12 @@ void statSetUnspentApBonus(int multiplier);
|
||||
int statGetUnspentApBonus();
|
||||
void statSetUnspentApPerkBonus(int multiplier);
|
||||
int statGetUnspentApPerkBonus();
|
||||
int statGetConfiguredMaximum(int stat, bool npc);
|
||||
int statGetConfiguredMinimum(int stat, bool npc);
|
||||
void statSetPcMaximum(int stat, int maximum);
|
||||
void statSetPcMinimum(int stat, int minimum);
|
||||
void statSetNpcMaximum(int stat, int maximum);
|
||||
void statSetNpcMinimum(int stat, int minimum);
|
||||
int critterGetStat(Object* critter, int stat);
|
||||
int critterGetBaseStatWithTraitModifier(Object* critter, int stat);
|
||||
int critterGetBaseStat(Object* critter, int stat);
|
||||
|
||||
+95
-4
@@ -480,6 +480,10 @@ static std::vector<std::pair<int, std::string>> wmTerrainNameOverrides;
|
||||
static void wmSetFlags(int* flagsPtr, int flag, int value);
|
||||
static int wmGenDataInit();
|
||||
static int wmGenDataReset();
|
||||
static void wmGenDataSetStartWorldPos();
|
||||
static bool wmGetStartWorldMapConfigValue(const char* key, int* valuePtr);
|
||||
static void wmGenDataClampWorldPosToBounds();
|
||||
static void wmSetStartWorldView();
|
||||
static int wmWorldMapSaveTempData();
|
||||
static int wmWorldMapLoadTempData();
|
||||
static int wmConfigInit();
|
||||
@@ -979,8 +983,11 @@ int wmWorldMap_init()
|
||||
return -1;
|
||||
}
|
||||
|
||||
wmGenDataClampWorldPosToBounds();
|
||||
|
||||
wmGenData.viewportMaxX = WM_TILE_WIDTH * wmNumHorizontalTiles - WM_VIEW_WIDTH;
|
||||
wmGenData.viewportMaxY = WM_TILE_HEIGHT * (wmMaxTileNum / wmNumHorizontalTiles) - WM_VIEW_HEIGHT;
|
||||
wmSetStartWorldView();
|
||||
circleBlendTable = _getColorBlendTable(COLOR_GREEN);
|
||||
|
||||
wmMarkSubTileRadiusVisited(wmGenData.worldPosX, wmGenData.worldPosY);
|
||||
@@ -1009,8 +1016,7 @@ static int wmGenDataInit()
|
||||
{
|
||||
gDidMeetFrankHorrigan = false;
|
||||
wmGenData.currentAreaId = -1;
|
||||
wmGenData.worldPosX = 173;
|
||||
wmGenData.worldPosY = 122;
|
||||
wmGenDataSetStartWorldPos();
|
||||
wmGenData.currentSubtile = nullptr;
|
||||
wmGenData.dword_672E18 = 0;
|
||||
wmGenData.isWalking = false;
|
||||
@@ -1076,8 +1082,8 @@ static int wmGenDataReset()
|
||||
wmGenData.encounterIconIsVisible = false;
|
||||
mousePressed = false;
|
||||
wmGenData.currentAreaId = -1;
|
||||
wmGenData.worldPosX = 173;
|
||||
wmGenData.worldPosY = 122;
|
||||
wmGenDataSetStartWorldPos();
|
||||
wmGenDataClampWorldPosToBounds();
|
||||
wmGenData.walkDestinationX = -1;
|
||||
wmGenData.walkDestinationY = -1;
|
||||
wmGenData.encounterMapId = -1;
|
||||
@@ -1113,6 +1119,70 @@ static int wmGenDataReset()
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wmGenDataSetStartWorldPos()
|
||||
{
|
||||
wmGenData.worldPosX = 173;
|
||||
wmGenData.worldPosY = 122;
|
||||
|
||||
int value;
|
||||
if (wmGetStartWorldMapConfigValue("worldmap_x", &value)) {
|
||||
wmGenData.worldPosX = value;
|
||||
}
|
||||
|
||||
if (wmGetStartWorldMapConfigValue("worldmap_y", &value)) {
|
||||
wmGenData.worldPosY = value;
|
||||
}
|
||||
}
|
||||
|
||||
static bool wmGetStartWorldMapConfigValue(const char* key, int* valuePtr)
|
||||
{
|
||||
assert(key != nullptr);
|
||||
assert(valuePtr != nullptr);
|
||||
|
||||
int value;
|
||||
if (!configGetInt(&gContentConfig, CONTENT_CONFIG_START_SECTION, key, &value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*valuePtr = std::max(value, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void wmGenDataClampWorldPosToBounds()
|
||||
{
|
||||
if (wmNumHorizontalTiles <= 0 || wmMaxTileNum <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int worldMaxX = WM_TILE_WIDTH * wmNumHorizontalTiles;
|
||||
int worldMaxY = WM_TILE_HEIGHT * (wmMaxTileNum / wmNumHorizontalTiles);
|
||||
if (worldMaxX <= 0 || worldMaxY <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
wmGenData.worldPosX = std::clamp(wmGenData.worldPosX, 0, worldMaxX - 1);
|
||||
wmGenData.worldPosY = std::clamp(wmGenData.worldPosY, 0, worldMaxY - 1);
|
||||
}
|
||||
|
||||
static void wmSetStartWorldView()
|
||||
{
|
||||
wmWorldOffsetX = 0;
|
||||
wmWorldOffsetY = 0;
|
||||
|
||||
int value;
|
||||
if (wmGetStartWorldMapConfigValue("worldmap_view_x", &value)) {
|
||||
wmWorldOffsetX = std::clamp(value, 0, std::max(wmGenData.viewportMaxX, 0));
|
||||
}
|
||||
|
||||
if (wmGetStartWorldMapConfigValue("worldmap_view_y", &value)) {
|
||||
wmWorldOffsetY = std::clamp(value, 0, std::max(wmGenData.viewportMaxY, 0));
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4BCE00 wmWorldMap_exit
|
||||
void wmWorldMap_exit()
|
||||
{
|
||||
@@ -1177,6 +1247,7 @@ int wmWorldMap_reset()
|
||||
gGameTimeIncRemainder = 0.0;
|
||||
|
||||
wmWorldMapLoadTempData();
|
||||
wmSetStartWorldView();
|
||||
wmMarkAllSubTiles(0);
|
||||
|
||||
return wmGenDataReset();
|
||||
@@ -6170,6 +6241,14 @@ int wmGetPartyCurArea(int* areaIdxPtr)
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool wmStartWorldPosIsConfigured()
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
return wmGetStartWorldMapConfigValue("worldmap_x", &x)
|
||||
|| wmGetStartWorldMapConfigValue("worldmap_y", &y);
|
||||
}
|
||||
|
||||
// 0x4C47D8 wmMarkAllSubTiles
|
||||
static void wmMarkAllSubTiles(int state)
|
||||
{
|
||||
@@ -7087,6 +7166,18 @@ void wmSetPartyWorldPos(int x, int y)
|
||||
wmGenData.worldPosY = y;
|
||||
}
|
||||
|
||||
void wmSetPartyCurArea(int areaIdx)
|
||||
{
|
||||
wmGenData.currentAreaId = cityIsValid(areaIdx) ? areaIdx : -1;
|
||||
}
|
||||
|
||||
void wmClearPartyWalking()
|
||||
{
|
||||
wmGenData.walkDestinationX = 0;
|
||||
wmGenData.walkDestinationY = 0;
|
||||
wmGenData.isWalking = false;
|
||||
}
|
||||
|
||||
void wmCarSetCurrentArea(int area)
|
||||
{
|
||||
wmGenData.currentCarAreaId = area;
|
||||
|
||||
@@ -285,6 +285,9 @@ int wmMatchAreaContainingMapIdx(int mapIdx, int* areaIdxPtr);
|
||||
int wmTeleportToArea(int areaIdx);
|
||||
|
||||
// CE
|
||||
bool wmStartWorldPosIsConfigured();
|
||||
void wmSetPartyCurArea(int areaIdx);
|
||||
void wmClearPartyWalking();
|
||||
void wmSetPartyWorldPos(int x, int y);
|
||||
void wmCarSetCurrentArea(int area);
|
||||
void wmForceEncounter(int map, unsigned int flags);
|
||||
|
||||
Reference in New Issue
Block a user