mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Added an option about max HP calculation to the stats ini file
Added an update to the HP stats when the map is loaded first time. Minor code edits.
This commit is contained in:
@@ -6,6 +6,10 @@
|
||||
;multi[x] - where x is from 0 to 6, the multiplier of st/pe/en/etc.
|
||||
;shift[x] - shifts the base stat before the multiplication
|
||||
|
||||
[Main]
|
||||
;Set to 1 to take the bonus values of SPECIAL stats into account when calculating maximum hit points
|
||||
;Set to 0 for the original behavior (bonus stats do not affect maximum hit points)
|
||||
HPDependOnBonusStats=0
|
||||
|
||||
;max hp
|
||||
[7]
|
||||
|
||||
@@ -254,6 +254,7 @@ WRAP_WATCOM_FUNC2(long, skill_dec_point_force, GameObject*, critter, long, skill
|
||||
WRAP_WATCOM_FUNC2(long, skill_inc_point_force, GameObject*, critter, long, skill)
|
||||
WRAP_WATCOM_FUNC1(long, skill_is_tagged, long, skill)
|
||||
WRAP_WATCOM_FUNC2(long, skill_level, GameObject*, critter, long, statID)
|
||||
WRAP_WATCOM_FUNC2(long, stat_get_base, GameObject*, critter, long, statID)
|
||||
WRAP_WATCOM_FUNC2(long, stat_get_base_direct, GameObject*, critter, long, statID)
|
||||
WRAP_WATCOM_FUNC2(long, stat_get_bonus, GameObject*, critter, long, statID)
|
||||
WRAP_WATCOM_FUNC3(long, stat_set_bonus, GameObject*, critter, long, statID, long, amount)
|
||||
|
||||
@@ -36,7 +36,7 @@ static std::unordered_map<fo::GameObject*, fo::GameObject*> sources;
|
||||
|
||||
// Returns the friendly critter or any blocking object in the line of fire
|
||||
fo::GameObject* AI::CheckShootAndFriendlyInLineOfFire(fo::GameObject* object, long targetTile, long team) {
|
||||
if (object && object->Type() == ObjType::OBJ_TYPE_CRITTER && object->critter.teamNum != team) { // is not friendly fire
|
||||
if (object && object->IsCritter() && object->critter.teamNum != team) { // is not friendly fire
|
||||
long objTile = object->tile;
|
||||
if (objTile == targetTile) return nullptr;
|
||||
|
||||
|
||||
@@ -2075,7 +2075,7 @@ static void __stdcall combat_attack_gcsd() {
|
||||
if (fo::var::main_ctd.targetDamage > fo::var::gcsd->maxDamage) {
|
||||
fo::var::main_ctd.targetDamage = fo::var::gcsd->maxDamage;
|
||||
}
|
||||
if (damage > fo::var::main_ctd.targetDamage && fo::var::main_ctd.target->Type() == fo::ObjType::OBJ_TYPE_CRITTER) {
|
||||
if (damage > fo::var::main_ctd.targetDamage && fo::var::main_ctd.target->IsCritter()) {
|
||||
long cHP = fo::var::main_ctd.target->critter.health;
|
||||
if (cHP > fo::var::gcsd->maxDamage && cHP <= damage) {
|
||||
fo::var::main_ctd.targetFlags &= ~fo::DamageFlag::DAM_DEAD; // unset
|
||||
|
||||
@@ -107,7 +107,7 @@ static void RunEditorInternal(SOCKET &s) {
|
||||
for (int tile = 0; tile < 40000; tile++) {
|
||||
fo::GameObject* obj = fo::func::obj_find_first_at_tile(elv, tile);
|
||||
while (obj) {
|
||||
if ((obj->Type()) == fo::OBJ_TYPE_CRITTER) {
|
||||
if (obj->IsCritter()) {
|
||||
vec.push_back(reinterpret_cast<DWORD*>(obj));
|
||||
}
|
||||
obj = fo::func::obj_find_next_at_tile();
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "..\main.h"
|
||||
#include "..\FalloutEngine\Fallout2.h"
|
||||
#include "LoadGameHook.h"
|
||||
#include "Stats.h"
|
||||
|
||||
#include "Objects.h"
|
||||
|
||||
@@ -93,14 +94,17 @@ pickNewID: // skip PM range (18000 - 83535)
|
||||
}
|
||||
}
|
||||
|
||||
// Reassigns object IDs to all critters upon first loading a map
|
||||
// Reassigns object IDs to all critters upon first loading a map and updates HP stats
|
||||
static void map_fix_critter_id() {
|
||||
long npcStartID = 4096;
|
||||
fo::GameObject* obj = fo::func::obj_find_first();
|
||||
while (obj) {
|
||||
if (obj->Type() == fo::OBJ_TYPE_CRITTER && obj->id < fo::PLAYER_ID) {
|
||||
obj->id = npcStartID++;
|
||||
SetScriptObjectID(obj);
|
||||
if (obj->IsCritter()) {
|
||||
if (obj->id < fo::PLAYER_ID) {
|
||||
obj->id = npcStartID++;
|
||||
SetScriptObjectID(obj);
|
||||
}
|
||||
Stats::UpdateHPStat(obj);
|
||||
}
|
||||
obj = fo::func::obj_find_next();
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ void op_set_script(OpcodeContext& ctx) {
|
||||
fo::func::scr_remove(object->scriptId);
|
||||
object->scriptId = 0xFFFFFFFF;
|
||||
}
|
||||
if (object->Type() == fo::ObjType::OBJ_TYPE_CRITTER) {
|
||||
if (object->IsCritter()) {
|
||||
scriptType = fo::Scripts::ScriptTypes::SCRIPT_CRITTER;
|
||||
} else {
|
||||
scriptType = fo::Scripts::ScriptTypes::SCRIPT_ITEM;
|
||||
@@ -182,7 +182,7 @@ void op_make_path(OpcodeContext& ctx) {
|
||||
auto func = getBlockingFunc(type);
|
||||
|
||||
// if the object is not a critter, then there is no need to check tile (tileTo) for blocking
|
||||
long checkFlag = (objFrom->Type() == fo::OBJ_TYPE_CRITTER);
|
||||
long checkFlag = (objFrom->IsCritter());
|
||||
|
||||
char pathData[800];
|
||||
long pathLength = fo::func::make_path_func(objFrom, objFrom->tile, tileTo, pathData, checkFlag, (void*)func);
|
||||
@@ -225,7 +225,7 @@ void op_get_party_members(OpcodeContext& ctx) {
|
||||
auto partyMemberList = fo::var::partyMemberList;
|
||||
for (int i = 0; i < actualCount; i++) {
|
||||
auto obj = reinterpret_cast<fo::GameObject*>(partyMemberList[i * 4]);
|
||||
if (includeHidden || (obj->Type() == fo::OBJ_TYPE_CRITTER && !fo::func::critter_is_dead(obj) && !(obj->flags & fo::ObjectFlag::Mouse_3d))) {
|
||||
if (includeHidden || (obj->IsCritter() && !fo::func::critter_is_dead(obj) && !(obj->flags & fo::ObjectFlag::Mouse_3d))) {
|
||||
arrays[arrayId].push_back((long)obj);
|
||||
}
|
||||
}
|
||||
@@ -307,7 +307,7 @@ void mf_item_weight(OpcodeContext& ctx) {
|
||||
|
||||
void mf_set_dude_obj(OpcodeContext& ctx) {
|
||||
auto obj = ctx.arg(0).object();
|
||||
if (obj == nullptr || obj->Type() == fo::ObjType::OBJ_TYPE_CRITTER) {
|
||||
if (obj == nullptr || obj->IsCritter()) {
|
||||
//if (!InCombat && obj && obj != PartyControl::RealDudeObject()) {
|
||||
// ctx.printOpcodeError("%s() - controlling of the critter is only allowed in combat mode.", ctx.getMetaruleName());
|
||||
//} else {
|
||||
|
||||
@@ -116,7 +116,7 @@ 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();
|
||||
if (obj->Type() == fo::ObjType::OBJ_TYPE_CRITTER && fo::func::isPartyMember(obj)) {
|
||||
if (obj->IsCritter() && fo::func::isPartyMember(obj)) {
|
||||
Perks::SetSelectablePerk(ctx.arg(1).strValue(), ctx.arg(2).rawValue(), ctx.arg(3).rawValue(), ctx.arg(4).strValue(), (obj->id != fo::PLAYER_ID) ? obj->id : 0);
|
||||
} else {
|
||||
ctx.printOpcodeError(notPartyMemberErr, ctx.getMetaruleName());
|
||||
@@ -126,7 +126,7 @@ void mf_set_selectable_perk_npc(OpcodeContext& ctx) {
|
||||
|
||||
void mf_set_fake_perk_npc(OpcodeContext& ctx) {
|
||||
auto obj = ctx.arg(0).object();
|
||||
if (obj->Type() == fo::ObjType::OBJ_TYPE_CRITTER && fo::func::isPartyMember(obj)) {
|
||||
if (obj->IsCritter() && fo::func::isPartyMember(obj)) {
|
||||
Perks::SetFakePerk(ctx.arg(1).strValue(), ctx.arg(2).rawValue(), ctx.arg(3).rawValue(), ctx.arg(4).strValue(), (obj->id != fo::PLAYER_ID) ? obj->id : 0);
|
||||
} else {
|
||||
ctx.printOpcodeError(notPartyMemberErr, ctx.getMetaruleName());
|
||||
@@ -136,7 +136,7 @@ void mf_set_fake_perk_npc(OpcodeContext& ctx) {
|
||||
|
||||
void mf_set_fake_trait_npc(OpcodeContext& ctx) {
|
||||
auto obj = ctx.arg(0).object();
|
||||
if (obj->Type() == fo::ObjType::OBJ_TYPE_CRITTER && fo::func::isPartyMember(obj)) {
|
||||
if (obj->IsCritter() && fo::func::isPartyMember(obj)) {
|
||||
Perks::SetFakeTrait(ctx.arg(1).strValue(), ctx.arg(2).rawValue(), ctx.arg(3).rawValue(), ctx.arg(4).strValue(), (obj->id != fo::PLAYER_ID) ? obj->id : 0);
|
||||
} else {
|
||||
ctx.printOpcodeError(notPartyMemberErr, ctx.getMetaruleName());
|
||||
@@ -204,7 +204,7 @@ void op_has_fake_trait(OpcodeContext& ctx) {
|
||||
void mf_has_fake_perk_npc(OpcodeContext& ctx) {
|
||||
long result = 0;
|
||||
auto obj = ctx.arg(0).object();
|
||||
if (obj->Type() == fo::ObjType::OBJ_TYPE_CRITTER && fo::func::isPartyMember(obj)) {
|
||||
if (obj->IsCritter() && fo::func::isPartyMember(obj)) {
|
||||
result = Perks::HasFakePerkOwner(ctx.arg(1).strValue(), (obj->id != fo::PLAYER_ID) ? obj->id : 0);
|
||||
} else {
|
||||
ctx.printOpcodeError(notPartyMemberErr, ctx.getMetaruleName());
|
||||
@@ -215,7 +215,7 @@ void mf_has_fake_perk_npc(OpcodeContext& ctx) {
|
||||
void mf_has_fake_trait_npc(OpcodeContext& ctx) {
|
||||
long result = 0;
|
||||
auto obj = ctx.arg(0).object();
|
||||
if (obj->Type() == fo::ObjType::OBJ_TYPE_CRITTER && fo::func::isPartyMember(obj)) {
|
||||
if (obj->IsCritter() && fo::func::isPartyMember(obj)) {
|
||||
result = Perks::HasFakeTraitOwner(ctx.arg(1).strValue(), (obj->id != fo::PLAYER_ID) ? obj->id : 0);
|
||||
} else {
|
||||
ctx.printOpcodeError(notPartyMemberErr, ctx.getMetaruleName());
|
||||
|
||||
@@ -79,7 +79,7 @@ void op_get_pc_extra_stat(OpcodeContext& ctx) {
|
||||
|
||||
void op_set_critter_base_stat(OpcodeContext& ctx) {
|
||||
fo::GameObject* obj = ctx.arg(0).object();
|
||||
if (obj && obj->Type() == fo::OBJ_TYPE_CRITTER) {
|
||||
if (obj && obj->IsCritter()) {
|
||||
int stat = ctx.arg(1).rawValue();
|
||||
if (stat >= 0 && stat < fo::STAT_max_stat) {
|
||||
CritterStats::SetStat(obj, stat, ctx.arg(2).rawValue(), 9);
|
||||
@@ -93,7 +93,7 @@ void op_set_critter_base_stat(OpcodeContext& ctx) {
|
||||
|
||||
void op_set_critter_extra_stat(OpcodeContext& ctx) {
|
||||
fo::GameObject* obj = ctx.arg(0).object();
|
||||
if (obj && obj->Type() == fo::OBJ_TYPE_CRITTER) {
|
||||
if (obj && obj->IsCritter()) {
|
||||
int stat = ctx.arg(1).rawValue();
|
||||
if (stat >= 0 && stat < fo::STAT_max_stat) {
|
||||
CritterStats::SetStat(obj, stat, ctx.arg(2).rawValue(), 44);
|
||||
@@ -108,7 +108,7 @@ void op_set_critter_extra_stat(OpcodeContext& ctx) {
|
||||
void op_get_critter_base_stat(OpcodeContext& ctx) {
|
||||
int result = 0;
|
||||
fo::GameObject* obj = ctx.arg(0).object();
|
||||
if (obj && obj->Type() == fo::OBJ_TYPE_CRITTER) {
|
||||
if (obj && obj->IsCritter()) {
|
||||
int stat = ctx.arg(1).rawValue();
|
||||
if (stat >= 0 && stat < fo::STAT_max_stat) {
|
||||
result = CritterStats::GetStat(obj, stat, 9);
|
||||
@@ -124,7 +124,7 @@ void op_get_critter_base_stat(OpcodeContext& ctx) {
|
||||
void op_get_critter_extra_stat(OpcodeContext& ctx) {
|
||||
int result = 0;
|
||||
fo::GameObject* obj = ctx.arg(0).object();
|
||||
if (obj && obj->Type() == fo::OBJ_TYPE_CRITTER) {
|
||||
if (obj && obj->IsCritter()) {
|
||||
int stat = ctx.arg(1).rawValue();
|
||||
if (stat >= 0 && stat < fo::STAT_max_stat) {
|
||||
result = CritterStats::GetStat(obj, stat, 44);
|
||||
@@ -145,7 +145,7 @@ void op_set_critter_skill_points(OpcodeContext& ctx) {
|
||||
}
|
||||
|
||||
fo::GameObject* obj = ctx.arg(0).object();
|
||||
if (obj->Type() == fo::OBJ_TYPE_CRITTER) {
|
||||
if (obj->IsCritter()) {
|
||||
fo::Proto* proto = fo::GetProto(obj->protoId);
|
||||
if (proto) proto->critter.skills[skill] = ctx.arg(2).rawValue();
|
||||
} else {
|
||||
@@ -161,7 +161,7 @@ void op_get_critter_skill_points(OpcodeContext& ctx) {
|
||||
}
|
||||
|
||||
fo::GameObject* obj = ctx.arg(0).object();
|
||||
if (obj->Type() == fo::OBJ_TYPE_CRITTER) {
|
||||
if (obj->IsCritter()) {
|
||||
fo::Proto* proto = fo::GetProto(obj->protoId);
|
||||
if (proto) ctx.setReturn(proto->critter.skills[skill]);
|
||||
} else {
|
||||
@@ -232,7 +232,7 @@ fail:
|
||||
|
||||
void op_set_critter_current_ap(OpcodeContext& ctx) {
|
||||
fo::GameObject* obj = ctx.arg(0).object();
|
||||
if (obj->Type() == fo::OBJ_TYPE_CRITTER) {
|
||||
if (obj->IsCritter()) {
|
||||
long ap = ctx.arg(1).rawValue();
|
||||
if (ap < 0) ap = 0;
|
||||
obj->critter.movePoints = ap;
|
||||
@@ -285,7 +285,7 @@ end:
|
||||
|
||||
void op_set_critter_hit_chance_mod(OpcodeContext& ctx) {
|
||||
fo::GameObject* obj = ctx.arg(0).object();
|
||||
if (obj->Type() == fo::OBJ_TYPE_CRITTER) {
|
||||
if (obj->IsCritter()) {
|
||||
SetHitChanceMax(obj, ctx.arg(1).rawValue(), ctx.arg(2).rawValue());
|
||||
} else {
|
||||
ctx.printOpcodeError(objNotCritter, ctx.getOpcodeName());
|
||||
@@ -312,7 +312,7 @@ end:
|
||||
|
||||
void op_set_critter_pickpocket_mod(OpcodeContext& ctx) {
|
||||
fo::GameObject* obj = ctx.arg(0).object();
|
||||
if (obj->Type() == fo::OBJ_TYPE_CRITTER) {
|
||||
if (obj->IsCritter()) {
|
||||
SetPickpocketMax(obj, ctx.arg(1).rawValue(), ctx.arg(2).rawValue());
|
||||
} else {
|
||||
ctx.printOpcodeError(objNotCritter, ctx.getOpcodeName());
|
||||
@@ -339,7 +339,7 @@ end:
|
||||
|
||||
void op_set_critter_skill_mod(OpcodeContext& ctx) {
|
||||
fo::GameObject* obj = ctx.arg(0).object();
|
||||
if (obj->Type() == fo::OBJ_TYPE_CRITTER) {
|
||||
if (obj->IsCritter()) {
|
||||
SetSkillMax(obj, ctx.arg(1).rawValue());
|
||||
} else {
|
||||
ctx.printOpcodeError(objNotCritter, ctx.getOpcodeName());
|
||||
|
||||
+53
-15
@@ -26,6 +26,9 @@
|
||||
namespace sfall
|
||||
{
|
||||
|
||||
bool engineDerivedStats = true;
|
||||
bool derivedHPwBonus = false; // recalculate the hit points with bonus stat values
|
||||
|
||||
static DWORD statMaximumsPC[fo::STAT_max_stat];
|
||||
static DWORD statMinimumsPC[fo::STAT_max_stat];
|
||||
static DWORD statMaximumsNPC[fo::STAT_max_stat];
|
||||
@@ -144,23 +147,31 @@ end:
|
||||
}
|
||||
}
|
||||
|
||||
static long RecalcStat(int stat, int statsValue[]) {
|
||||
double sum = 0;
|
||||
for (int i = fo::Stat::STAT_st; i <= fo::Stat::STAT_lu; i++) {
|
||||
sum += (statsValue[i] + statFormulas[stat].shift[i]) * statFormulas[stat].multi[i];
|
||||
}
|
||||
long calcStatValue = statFormulas[stat].base + (int)floor(sum);
|
||||
return (calcStatValue < statFormulas[stat].min) ? statFormulas[stat].min : calcStatValue;
|
||||
}
|
||||
|
||||
static void __stdcall StatRecalcDerived(fo::GameObject* critter) {
|
||||
int baseStats[7];
|
||||
for (int stat = fo::Stat::STAT_st; stat <= fo::Stat::STAT_lu; stat++) baseStats[stat] = fo::func::stat_level(critter, stat);
|
||||
|
||||
long* proto = CritterStats::GetProto(critter);
|
||||
if (!proto) fo::func::proto_ptr(critter->protoId, (fo::Proto**)&proto);
|
||||
if (!proto && fo::func::proto_ptr(critter->protoId, (fo::Proto**)&proto) == -1) return;
|
||||
|
||||
for (int i = fo::Stat::STAT_max_hit_points; i <= fo::Stat::STAT_poison_resist; i++) {
|
||||
if (i >= fo::Stat::STAT_dmg_thresh && i <= fo::Stat::STAT_dmg_resist_explosion) continue;
|
||||
int baseStats[7], levelStats[7];
|
||||
for (int stat = fo::Stat::STAT_st; stat <= fo::Stat::STAT_lu; stat++) {
|
||||
levelStats[stat] = fo::func::stat_level(critter, stat);
|
||||
if (!derivedHPwBonus) baseStats[stat] = fo::func::stat_get_base(critter, stat);
|
||||
}
|
||||
|
||||
double sum = 0;
|
||||
for (int stat = fo::Stat::STAT_st; stat <= fo::Stat::STAT_lu; stat++) {
|
||||
sum += (baseStats[stat] + statFormulas[i].shift[stat]) * statFormulas[i].multi[stat];
|
||||
}
|
||||
long calcStat = statFormulas[i].base + (int)floor(sum);
|
||||
if (calcStat < statFormulas[i].min) calcStat = statFormulas[i].min;
|
||||
proto[OffsetStat::base + i] = calcStat; // offset from base_stat_srength
|
||||
((fo::Proto*)proto)->critter.base.health = RecalcStat(fo::Stat::STAT_max_hit_points, (derivedHPwBonus) ? levelStats : baseStats);
|
||||
|
||||
for (int stat = fo::Stat::STAT_max_move_points; stat <= fo::Stat::STAT_poison_resist; stat++) {
|
||||
if (stat >= fo::Stat::STAT_dmg_thresh && stat <= fo::Stat::STAT_dmg_resist_explosion) continue;
|
||||
// offset from base_stat_srength
|
||||
proto[OffsetStat::base + stat] = RecalcStat(stat, levelStats);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,6 +187,29 @@ static void __declspec(naked) stat_recalc_derived_hack() {
|
||||
}
|
||||
}
|
||||
|
||||
void Stats::UpdateHPStat(fo::GameObject* critter) {
|
||||
if (engineDerivedStats) return;
|
||||
|
||||
fo::Proto* proto;
|
||||
if (fo::func::proto_ptr(critter->protoId, &proto) == -1) return;
|
||||
|
||||
auto getStatFunc = (derivedHPwBonus) ? fo::func::stat_level : fo::func::stat_get_base;
|
||||
|
||||
double sum = 0;
|
||||
for (int stat = fo::Stat::STAT_st; stat <= fo::Stat::STAT_lu; stat++) {
|
||||
sum += (getStatFunc(critter, stat) + statFormulas[fo::Stat::STAT_max_hit_points].shift[stat]) * statFormulas[fo::Stat::STAT_max_hit_points].multi[stat];
|
||||
}
|
||||
long calcStatValue = statFormulas[fo::Stat::STAT_max_hit_points].base + (int)floor(sum);
|
||||
if (calcStatValue < statFormulas[fo::Stat::STAT_max_hit_points].min) calcStatValue = statFormulas[fo::Stat::STAT_max_hit_points].min;
|
||||
|
||||
if (proto->critter.base.health != calcStatValue) {
|
||||
fo::func::debug_printf("\nWarning: critter PID: %d, ID: %d, has an incorrect base value %d (must be %d) of the max HP stat.",
|
||||
critter->protoId, critter->id, proto->critter.base.health, calcStatValue);
|
||||
}
|
||||
proto->critter.base.health = calcStatValue;
|
||||
critter->critter.health = calcStatValue + proto->critter.bonus.health;
|
||||
}
|
||||
|
||||
static void __declspec(naked) stat_set_base_hack_allow() {
|
||||
static const DWORD StatSetBaseRet = 0x4AF559;
|
||||
using namespace fo;
|
||||
@@ -240,7 +274,7 @@ void Stats::init() {
|
||||
|
||||
MakeCall(0x4AF09C, CalcApToAcBonus, 3); // stat_level_
|
||||
|
||||
// Allow set_critter_stat function to change STAT_unused and STAT_dmg_* stats for the player
|
||||
// Allow set_critter_stat function to change the base stats of STAT_unused and STAT_dmg_* for the player
|
||||
MakeCall(0x4AF54E, stat_set_base_hack_allow);
|
||||
MakeCall(0x455D65, op_set_critter_stat_hack); // STAT_unused for other critters
|
||||
|
||||
@@ -263,6 +297,7 @@ void Stats::init() {
|
||||
|
||||
auto statsFile = GetConfigString("Misc", "DerivedStats", "", MAX_PATH);
|
||||
if (!statsFile.empty()) {
|
||||
engineDerivedStats = false;
|
||||
MakeJump(0x4AF6FC, stat_recalc_derived_hack); // overrides function
|
||||
|
||||
// STAT_st + STAT_en * 2 + 15
|
||||
@@ -293,10 +328,13 @@ void Stats::init() {
|
||||
// STAT_en * 5
|
||||
statFormulas[STAT_poison_resist].multi[STAT_en] = 5; // poison resist
|
||||
|
||||
char key[6], buf2[256], buf3[256];
|
||||
const char* statFile = statsFile.insert(0, ".\\").c_str();
|
||||
if (GetFileAttributes(statFile) == INVALID_FILE_ATTRIBUTES) return;
|
||||
|
||||
derivedHPwBonus = (iniGetInt("Main", "HPDependOnBonusStats", 0, statFile) != 0);
|
||||
|
||||
char key[6], buf2[256], buf3[256];
|
||||
|
||||
for (int i = fo::Stat::STAT_max_hit_points; i <= fo::Stat::STAT_poison_resist; i++) {
|
||||
if (i >= fo::Stat::STAT_dmg_thresh && i <= fo::Stat::STAT_dmg_resist_explosion) continue;
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ public:
|
||||
|
||||
static long GetStatMax(int stat, int isNPC);
|
||||
static long GetStatMin(int stat, int isNPC);
|
||||
|
||||
static void UpdateHPStat(fo::GameObject* critter);
|
||||
};
|
||||
|
||||
void __stdcall SetPCStatMax(int stat, int value);
|
||||
|
||||
Reference in New Issue
Block a user