Renamed elements in PerkInfo/TraitInfo structs

Implemented StatFormula struct from 4.x for Stats.cpp.
Implemented DudeState struct from 4.x for PartyControl.cpp.
This commit is contained in:
NovaRain
2020-10-15 13:12:15 +08:00
parent cca0fe0cb6
commit 8e6a961fba
8 changed files with 229 additions and 208 deletions
+14 -2
View File
@@ -175,7 +175,7 @@ char* ptr_pc_name = reinterpret_cast<char*>(_pc_name);
DWORD* ptr_pc_proto = reinterpret_cast<DWORD*>(_pc_proto);
BYTE* ptr_PeanutButter = reinterpret_cast<BYTE*>(_PeanutButter);
DWORD* ptr_perk_data = reinterpret_cast<DWORD*>(_perk_data);
int** ptr_perkLevelDataList = reinterpret_cast<int**>(_perkLevelDataList);
long** ptr_perkLevelDataList = reinterpret_cast<long**>(_perkLevelDataList); // dynamic array, limited to PERK_Count
const DWORD* ptr_pip_win = reinterpret_cast<DWORD*>(_pip_win);
DWORD* ptr_pipboy_message_file = reinterpret_cast<DWORD*>(_pipboy_message_file);
DWORD* ptr_pipmesg = reinterpret_cast<DWORD*>(_pipmesg);
@@ -185,7 +185,7 @@ MSGList* ptr_proto_main_msg_file = reinterpret_cast<MSGList*>(_proto_main
MSGList* ptr_proto_msg_files = reinterpret_cast<MSGList*>(_proto_msg_files); // array of 6 elements
DWORD* ptr_ptable = reinterpret_cast<DWORD*>(_ptable);
DWORD* ptr_pud = reinterpret_cast<DWORD*>(_pud);
DWORD* ptr_queue = reinterpret_cast<DWORD*>(_queue);
Queue** ptr_queue = reinterpret_cast<Queue**>(_queue);
DWORD* ptr_quick_done = reinterpret_cast<DWORD*>(_quick_done);
DWORD* ptr_read_callback = reinterpret_cast<DWORD*>(_read_callback);
RectList** ptr_rectList = reinterpret_cast<RectList**>(_rectList);
@@ -1299,6 +1299,18 @@ const char* MsgSearch(const MSGList* fileAddr, long messageId) {
return nullptr;
}
Queue* QueueFindUtil(TGameObj* object, long type) {
if (*ptr_queue) {
Queue* queue = *ptr_queue;
while (queue->object != object && queue->type != type) {
queue = queue->next;
if (!queue) break;
}
return queue;
}
return nullptr;
}
char* GetProtoPtr(long pid) {
char* proto;
long result;
+4 -2
View File
@@ -478,7 +478,7 @@ extern char* ptr_pc_name;
extern DWORD* ptr_pc_proto;
extern BYTE* ptr_PeanutButter;
extern DWORD* ptr_perk_data;
extern int** ptr_perkLevelDataList; // limited to PERK_Count
extern long** ptr_perkLevelDataList; // dynamic array, limited to PERK_Count
extern const DWORD* ptr_pip_win;
extern DWORD* ptr_pipboy_message_file;
extern DWORD* ptr_pipmesg;
@@ -488,7 +488,7 @@ extern MSGList* ptr_proto_main_msg_file;
extern MSGList* ptr_proto_msg_files; // array of 6 elements
extern DWORD* ptr_ptable;
extern DWORD* ptr_pud;
extern DWORD* ptr_queue;
extern Queue** ptr_queue;
extern DWORD* ptr_quick_done;
extern DWORD* ptr_read_callback;
extern RectList** ptr_rectList;
@@ -1283,6 +1283,8 @@ const char* GetMessageStr(const MSGList* fileAddr, long messageId);
// similar to GetMessageStr, but returns nullptr when no message is found
const char* MsgSearch(const MSGList* fileAddr, long messageId);
Queue* QueueFindUtil(TGameObj* object, long type);
// returns pointer to prototype by PID, or nullptr on failure
char* GetProtoPtr(long pid);
+7 -4
View File
@@ -38,7 +38,8 @@ WRAP_WATCOM_FFUNC4(long, MouseClickIn, mouse_click_in_, long, x, long, y, long,
WRAP_WATCOM_FFUNC4(long, MouseIn, mouse_in_, long, x, long, y, long, x_offs, long, y_offs)
WRAP_WATCOM_FFUNC3(TGameObj*, ObjBlockingAt, obj_blocking_at_, TGameObj*, object, long, tile, long, elevation)
WRAP_WATCOM_FFUNC3(long, ObjNewSidInst, obj_new_sid_inst_, TGameObj*, object, long, sType, long, scriptIndex)
WRAP_WATCOM_FFUNC3(long, ObjectUnderMouse, object_under_mouse_, long, crSwitch, long, inclDude, long, elevation)
WRAP_WATCOM_FFUNC3(TGameObj*, ObjectUnderMouse, object_under_mouse_, long, crSwitch, long, inclDude, long, elevation)
WRAP_WATCOM_FFUNC4(long, QueueAdd, queue_add_, long, time, TGameObj*, object, void*, data, long, qType)
WRAP_WATCOM_FFUNC4(void, RegisterObjectCall, register_object_call_, long*, target, long*, source, void*, func, long, delay)
WRAP_WATCOM_FFUNC3(long, ScrGetLocalVar, scr_get_local_var_, long, sid, long, varId, long*, value)
WRAP_WATCOM_FFUNC3(long, ScrSetLocalVar, scr_set_local_var_, long, sid, long, varId, long, value)
@@ -96,6 +97,7 @@ WRAP_WATCOM_FUNC0(void, DisplayStats, display_stats_)
WRAP_WATCOM_FUNC1(long, CritterIsDead, critter_is_dead_, TGameObj*, critter)
// Execute script proc by internal proc number (from script's proc table, basically a sequential number of a procedure as defined in code, starting from 1)
WRAP_WATCOM_FUNC2(void, ExecuteProcedure, executeProcedure_, TProgram*, sptr, long, procNum)
WRAP_WATCOM_FUNC1(long, FolderPrintLine, folder_print_line_, const char*, text)
WRAP_WATCOM_FUNC1(const char*, FindCurrentProc, findCurrentProc_, TProgram*, program) // Returns the name of current procedure by program pointer
WRAP_WATCOM_FUNC1(long, FMtextWidth, FMtext_width_, const char*, text)
WRAP_WATCOM_FUNC0(long, GetInputBtn, get_input_)
@@ -124,8 +126,8 @@ WRAP_WATCOM_FUNC1(TGameObj*, InvenRightHand, inven_right_hand_, TGameObj*, critt
WRAP_WATCOM_FUNC2(TGameObj*, InvenPidIsCarriedPtr, inven_pid_is_carried_ptr_, TGameObj*, invenObj, long, pid)
WRAP_WATCOM_FUNC2(long, InvenUnwield, inven_unwield_, TGameObj*, critter, long, slot)
WRAP_WATCOM_FUNC1(TGameObj*, InvenWorn, inven_worn_, TGameObj*, critter) // Critter worn item (armor)
WRAP_WATCOM_FUNC1(long, IsPartyMember, isPartyMember_, TGameObj*, obj)
WRAP_WATCOM_FUNC2(long, IsWithinPerception, is_within_perception_, TGameObj*, source, TGameObj*, target)
WRAP_WATCOM_FUNC1(long, IsPartyMember, isPartyMember_, TGameObj*, obj)
WRAP_WATCOM_FUNC1(long, ItemCCurrSize, item_c_curr_size_, TGameObj*, critter)
WRAP_WATCOM_FUNC1(long, ItemCapsTotal, item_caps_total_, TGameObj*, object)
WRAP_WATCOM_FUNC1(long, ItemGetType, item_get_type_, TGameObj*, item)
@@ -174,8 +176,9 @@ WRAP_WATCOM_FUNC2(long, PerkLevel, perk_level_, TGameObj*, critter, long, perkId
WRAP_WATCOM_FUNC6(long, PickDeath, pick_death_, TGameObj*, attacker, TGameObj*, target, TGameObj*, weapon, long, amount, long, anim, long, hitFromBack)
WRAP_WATCOM_FUNC0(void, ProcessBk, process_bk_)
WRAP_WATCOM_FUNC0(void, ProtoDudeUpdateGender, proto_dude_update_gender_)
WRAP_WATCOM_FUNC2(long*, QueueFindFirst, queue_find_first_, TGameObj*, object, long, qType)
WRAP_WATCOM_FUNC2(long*, QueueFindNext, queue_find_next_, TGameObj*, object, long, qType)
WRAP_WATCOM_FUNC2(void*, QueueFindFirst, queue_find_first_, TGameObj*, object, long, qType)
WRAP_WATCOM_FUNC2(void*, QueueFindNext, queue_find_next_, TGameObj*, object, long, qType)
WRAP_WATCOM_FUNC2(void, QueueRemoveThis, queue_remove_this_, TGameObj*, object, long, qType)
WRAP_WATCOM_FUNC3(long, RegisterObjectAnimateAndHide, register_object_animate_and_hide_, TGameObj*, object, long, anim, long, delay)
WRAP_WATCOM_FUNC3(long, RegisterObjectChangeFid, register_object_change_fid_, TGameObj*, object, long, artFid, long, delay)
WRAP_WATCOM_FUNC3(long, RegisterObjectLight, register_object_light_, TGameObj*, object, long, lightRadius, long, delay)
+24 -24
View File
@@ -216,30 +216,30 @@ struct ItemButtonItem {
long fid;
};
// When gained, the perk increases Stat by StatMag, which may be negative. All other perk effects come from being
// When gained, the perk increases Stat by StatMod, which may be negative. All other perk effects come from being
// specifically checked for by scripts or the engine. If a primary stat requirement is negative, that stat must be
// below the value specified (e.g., -7 indicates a stat must be less than 7). Type is only non-zero when there
// below the value specified (e.g., -7 indicates a stat must be less than 7). Operator is only non-zero when there
// are two skill requirements. If set to 1, only one of those requirements must be met; if set to 2, both must be met.
struct PerkInfo {
const char* Name;
const char* Desc;
long Image;
long Ranks;
long Level;
long Stat;
long StatMag;
long Skill1;
long Skill1Mag;
long Type;
long Skill2;
long Skill2Mag;
long Str;
long Per;
long End;
long Chr;
long Int;
long Agl;
long Lck;
const char* name;
const char* description;
long image;
long ranks;
long levelMin;
long stat;
long statMod;
long skill1;
long skill1Min;
long skillOperator;
long skill2;
long skill2Min;
long strengthMin;
long perceptionMin;
long enduranceMin;
long charismaMin;
long intelligenceMin;
long agilityMin;
long luckMin;
};
struct DbFile {
@@ -443,9 +443,9 @@ struct SkillInfo {
};
struct TraitInfo {
const char* Name;
const char* Desc;
long Image;
const char* name;
const char* description;
long image;
};
//fallout2 path node structure
+67 -60
View File
@@ -36,24 +36,28 @@ static bool skipCounterAnim = false;
static std::vector<WORD> Chars;
static int delayedExperience;
static TGameObj* real_dude = nullptr;
static long real_traits[2];
static char real_pc_name[32];
static DWORD real_last_level;
static DWORD real_Level;
static DWORD real_Experience;
static char real_free_perk;
static DWORD real_unspent_skill_points;
//static DWORD real_map_elevation;
static DWORD real_sneak_working;
//static DWORD real_sneak_queue_time;
static DWORD real_hand;
static ItemButtonItem real_itemButtonItems[2];
static DWORD real_perkLevelDataList[PERK_count];
//static DWORD real_drug_gvar[6];
//static DWORD real_jet_gvar;
static long real_tag_skill[4];
//static DWORD real_bbox_sneak;
static struct DudeState {
TGameObj* obj_dude;
DWORD art_vault_guy_num;
long traits[2];
char pc_name[32];
DWORD last_level;
DWORD Level;
DWORD Experience;
char free_perk;
DWORD unspent_skill_points;
//DWORD map_elevation;
DWORD sneak_working;
//DWORD sneak_queue_time;
DWORD itemCurrentItem;
ItemButtonItem itemButtonItems[2];
long perkLevelDataList[PERK_count];
//long addictGvar[8];
long tag_skill[4];
//DWORD bbox_sneak;
DudeState() : obj_dude(nullptr) {}
} realDude;
static const DWORD* list_com = ptr_list_com;
@@ -86,19 +90,20 @@ static void __stdcall StatPcAddExperience(int amount) {
// saves the state of PC before moving control to NPC
static void SaveRealDudeState() {
real_dude = *ptr_obj_dude;
real_hand = *ptr_itemCurrentItem;
memcpy(real_itemButtonItems, ptr_itemButtonItems, sizeof(ItemButtonItem) * 2);
memcpy(real_traits, ptr_pc_traits, sizeof(long) * 2);
memcpy(real_perkLevelDataList, *ptr_perkLevelDataList, sizeof(DWORD) * PERK_count);
strcpy_s(real_pc_name, 32, ptr_pc_name);
real_Level = *ptr_Level_;
real_last_level = *ptr_last_level;
real_Experience = *ptr_Experience_;
real_free_perk = *ptr_free_perk;
real_unspent_skill_points = ptr_curr_pc_stat[0];
real_sneak_working = *ptr_sneak_working;
SkillGetTags(real_tag_skill, 4);
realDude.obj_dude = *ptr_obj_dude;
realDude.art_vault_guy_num = *ptr_art_vault_guy_num;
realDude.itemCurrentItem = *ptr_itemCurrentItem;
memcpy(realDude.itemButtonItems, ptr_itemButtonItems, sizeof(ItemButtonItem) * 2);
memcpy(realDude.traits, ptr_pc_traits, sizeof(long) * 2);
memcpy(realDude.perkLevelDataList, *ptr_perkLevelDataList, sizeof(DWORD) * PERK_count);
strcpy_s(realDude.pc_name, 32, ptr_pc_name);
realDude.Level = *ptr_Level_;
realDude.last_level = *ptr_last_level;
realDude.Experience = *ptr_Experience_;
realDude.free_perk = *ptr_free_perk;
realDude.unspent_skill_points = ptr_curr_pc_stat[0];
realDude.sneak_working = *ptr_sneak_working;
SkillGetTags(realDude.tag_skill, 4);
if (skipCounterAnim) {
const DWORD counterAnimAddr[] = {0x422BDE, 0x4229EC};
@@ -144,17 +149,17 @@ static void TakeControlOfNPC(TGameObj* npc) {
// deduce active hand by weapon anim code
char critterAnim = (npc->artFid & 0xF000) >> 12; // current weapon as seen in hands
if (AnimCodeByWeapon(InvenLeftHand(npc)) == critterAnim) { // definitely left hand..
if (AnimCodeByWeapon(InvenLeftHand(npc)) == critterAnim) { // definitely left hand
*ptr_itemCurrentItem = 0;
} else {
*ptr_itemCurrentItem = 1;
}
*ptr_inven_pid = npc->protoId;
// switch main dude_obj pointers - this should be done last!
*ptr_obj_dude = npc;
*ptr_inven_dude = npc;
*ptr_inven_pid = npc->protoId;
*ptr_art_vault_guy_num = npc->artFid & 0xFFF;
isControllingNPC = true;
delayedExperience = 0;
@@ -165,26 +170,27 @@ static void TakeControlOfNPC(TGameObj* npc) {
// restores the real dude state
static void RestoreRealDudeState(bool redraw = true) {
assert(real_dude != nullptr);
assert(realDude.obj_dude != nullptr);
*ptr_map_elevation = real_dude->elevation;
*ptr_map_elevation = realDude.obj_dude->elevation;
*ptr_obj_dude = real_dude;
*ptr_inven_dude = real_dude;
*ptr_inven_pid = real_dude->protoId;
*ptr_obj_dude = realDude.obj_dude;
*ptr_inven_dude = realDude.obj_dude;
*ptr_inven_pid = realDude.obj_dude->protoId;
*ptr_art_vault_guy_num = realDude.art_vault_guy_num;
*ptr_itemCurrentItem = real_hand;
memcpy(ptr_itemButtonItems, real_itemButtonItems, sizeof(ItemButtonItem) * 2);
memcpy(ptr_pc_traits, real_traits, sizeof(long) * 2);
memcpy(*ptr_perkLevelDataList, real_perkLevelDataList, sizeof(DWORD) * PERK_count);
strcpy_s(ptr_pc_name, 32, real_pc_name);
*ptr_Level_ = real_Level;
*ptr_last_level = real_last_level;
*ptr_Experience_ = real_Experience;
*ptr_free_perk = real_free_perk;
ptr_curr_pc_stat[0] = real_unspent_skill_points;
*ptr_sneak_working = real_sneak_working;
SkillSetTags(real_tag_skill, 4);
*ptr_itemCurrentItem = realDude.itemCurrentItem;
memcpy(ptr_itemButtonItems, realDude.itemButtonItems, sizeof(ItemButtonItem) * 2);
memcpy(ptr_pc_traits, realDude.traits, sizeof(long) * 2);
memcpy(*ptr_perkLevelDataList, realDude.perkLevelDataList, sizeof(DWORD) * PERK_count);
strcpy_s(ptr_pc_name, 32, realDude.pc_name);
*ptr_Level_ = realDude.Level;
*ptr_last_level = realDude.last_level;
*ptr_Experience_ = realDude.Experience;
*ptr_free_perk = realDude.free_perk;
ptr_curr_pc_stat[0] = realDude.unspent_skill_points;
*ptr_sneak_working = realDude.sneak_working;
SkillSetTags(realDude.tag_skill, 4);
if (delayedExperience > 0) {
StatPcAddExperience(delayedExperience);
@@ -199,7 +205,6 @@ static void RestoreRealDudeState(bool redraw = true) {
SetInventoryCheck(false);
isControllingNPC = false;
real_dude = nullptr;
if (isDebug) DebugPrintf("\n[SFALL] Restore control to dude.\n");
}
@@ -269,15 +274,15 @@ int __fastcall PartyControl_SwitchHandHook(TGameObj* item) {
}
static long __fastcall GetRealDudePerk(TGameObj* source, long perk) {
if (isControllingNPC && source == real_dude) {
return real_perkLevelDataList[perk];
if (isControllingNPC && source == realDude.obj_dude) {
return realDude.perkLevelDataList[perk];
}
return PerkLevel(source, perk);
}
static long __fastcall GetRealDudeTrait(TGameObj* source, long trait) {
if (isControllingNPC && source == real_dude) {
return (trait == real_traits[0] || trait == real_traits[1]) ? 1 : 0;
if (isControllingNPC && source == realDude.obj_dude) {
return (trait == realDude.traits[0] || trait == realDude.traits[1]) ? 1 : 0;
}
return TraitLevel(trait);
}
@@ -379,15 +384,16 @@ static void __declspec(naked) proto_name_hook() {
jne pcName;
jmp critter_name_;
pcName:
lea eax, real_pc_name;
lea eax, realDude.pc_name;
retn;
}
}
static void PartyControlReset() {
if (real_dude != nullptr && isControllingNPC) {
if (realDude.obj_dude != nullptr && isControllingNPC) {
RestoreRealDudeState(false);
}
realDude.obj_dude = nullptr;
}
bool IsNpcControlled() {
@@ -395,12 +401,13 @@ bool IsNpcControlled() {
}
TGameObj* RealDudeObject() {
return real_dude != nullptr
? real_dude
return realDude.obj_dude != nullptr
? realDude.obj_dude
: *ptr_obj_dude;
}
static char levelMsg[12], armorClassMsg[12], addictMsg[16];
static void __fastcall PartyMemberPrintStat(BYTE* surface, DWORD toWidth) {
const char* fmt = "%s %d";
char lvlMsg[16], acMsg[16];
+38 -45
View File
@@ -44,9 +44,8 @@ static DWORD addPerkMode = 2;
static bool perksReInit = false;
static int perksEnable = 0;
//static const PerkInfo BlankPerk={ &Name[PERK_count*64], &Desc[PERK_count*1024], 0x48, 1, 1, -1, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0 };
static PerkInfo Perks[PERK_count];
static TraitInfo Traits[TRAIT_count];
static PerkInfo perks[PERK_count];
static TraitInfo traits[TRAIT_count];
#pragma pack(push, 1)
struct FakePerk {
@@ -330,13 +329,7 @@ static void __declspec(naked) GetFakeSPerkLevel() {
static DWORD __stdcall HandleFakeTraits(int isSelect) {
for (DWORD i = 0; i < fakeTraits.size(); i++) {
DWORD a = (DWORD)fakeTraits[i].Name;
__asm {
mov eax, a;
call folder_print_line_;
mov a, eax;
}
if (a && !isSelect) {
if (FolderPrintLine(fakeTraits[i].Name) && !isSelect) {
isSelect = 1;
*ptr_folder_card_fid = fakeTraits[i].Image;
*ptr_folder_card_title = (DWORD)fakeTraits[i].Name;
@@ -626,7 +619,7 @@ lower:
static bool perkHeaveHoModFix = false;
void __stdcall ApplyHeaveHoFix() { // not really a fix
MakeJump(0x478AC4, HeaveHoHook);
Perks[PERK_heave_ho].Str = 0;
perks[PERK_heave_ho].strengthMin = 0;
perkHeaveHoModFix = true;
}
@@ -682,59 +675,59 @@ static void PerkSetup() {
if (!perksReInit) {
// _perk_data
const DWORD perkDataAddr[] = {0x496669, 0x496837, 0x496BAD, 0x496C41, 0x496D25};
SafeWriteBatch<DWORD>((DWORD)Perks, perkDataAddr);
SafeWriteBatch<DWORD>((DWORD)perks, perkDataAddr);
const DWORD perkDataDescAddr[] = {0x496696, 0x496BD1};
SafeWriteBatch<DWORD>((DWORD)&Perks[0].Desc, perkDataDescAddr);
SafeWrite32(0x496BF5, (DWORD)&Perks[0].Image);
SafeWrite32(0x496AD4, (DWORD)&Perks[0].Ranks);
SafeWriteBatch<DWORD>((DWORD)&perks[0].description, perkDataDescAddr);
SafeWrite32(0x496BF5, (DWORD)&perks[0].image);
SafeWrite32(0x496AD4, (DWORD)&perks[0].ranks);
}
memcpy(Perks, (void*)_perk_data, sizeof(PerkInfo) * PERK_count); // copy vanilla data
memcpy(perks, (void*)_perk_data, sizeof(PerkInfo) * PERK_count); // copy vanilla data
if (perksEnable) {
char num[4];
for (int i = 0; i < PERK_count; i++) {
_itoa(i, num, 10);
if (iniGetString(num, "Name", "", &Name[i * maxNameLen], maxNameLen - 1, perksFile)) {
Perks[i].Name = &Name[i * maxNameLen];
perks[i].name = &Name[i * maxNameLen];
}
if (iniGetString(num, "Desc", "", &Desc[i * descLen], descLen - 1, perksFile)) {
Perks[i].Desc = &Desc[i * descLen];
perks[i].description = &Desc[i * descLen];
}
int value;
value = iniGetInt(num, "Image", -99999, perksFile);
if (value != -99999) Perks[i].Image = value;
if (value != -99999) perks[i].image = value;
value = iniGetInt(num, "Ranks", -99999, perksFile);
if (value != -99999) Perks[i].Ranks = value;
if (value != -99999) perks[i].ranks = value;
value = iniGetInt(num, "Level", -99999, perksFile);
if (value != -99999) Perks[i].Level = value;
if (value != -99999) perks[i].levelMin = value;
value = iniGetInt(num, "Stat", -99999, perksFile);
if (value != -99999) Perks[i].Stat = value;
if (value != -99999) perks[i].stat = value;
value = iniGetInt(num, "StatMag", -99999, perksFile);
if (value != -99999) Perks[i].StatMag = value;
if (value != -99999) perks[i].statMod = value;
value = iniGetInt(num, "Skill1", -99999, perksFile);
if (value != -99999) Perks[i].Skill1 = value;
if (value != -99999) perks[i].skill1 = value;
value = iniGetInt(num, "Skill1Mag", -99999, perksFile);
if (value != -99999) Perks[i].Skill1Mag = value;
if (value != -99999) perks[i].skill1Min = value;
value = iniGetInt(num, "Type", -99999, perksFile);
if (value != -99999) Perks[i].Type = value;
if (value != -99999) perks[i].skillOperator = value;
value = iniGetInt(num, "Skill2", -99999, perksFile);
if (value != -99999) Perks[i].Skill2 = value;
if (value != -99999) perks[i].skill2 = value;
value = iniGetInt(num, "Skill2Mag", -99999, perksFile);
if (value != -99999) Perks[i].Skill2Mag = value;
if (value != -99999) perks[i].skill2Min = value;
value = iniGetInt(num, "STR", -99999, perksFile);
if (value != -99999) Perks[i].Str = value;
if (value != -99999) perks[i].strengthMin = value;
value = iniGetInt(num, "PER", -99999, perksFile);
if (value != -99999) Perks[i].Per = value;
if (value != -99999) perks[i].perceptionMin = value;
value = iniGetInt(num, "END", -99999, perksFile);
if (value != -99999) Perks[i].End = value;
if (value != -99999) perks[i].enduranceMin = value;
value = iniGetInt(num, "CHR", -99999, perksFile);
if (value != -99999) Perks[i].Chr = value;
if (value != -99999) perks[i].charismaMin = value;
value = iniGetInt(num, "INT", -99999, perksFile);
if (value != -99999) Perks[i].Int = value;
if (value != -99999) perks[i].intelligenceMin = value;
value = iniGetInt(num, "AGL", -99999, perksFile);
if (value != -99999) Perks[i].Agl = value;
if (value != -99999) perks[i].agilityMin = value;
value = iniGetInt(num, "LCK", -99999, perksFile);
if (value != -99999) Perks[i].Lck = value;
if (value != -99999) perks[i].luckMin = value;
}
}
perksReInit = false;
@@ -883,28 +876,28 @@ static void TraitSetup() {
MakeJump(0x4B3C7C, TraitAdjustStatHack); // trait_adjust_stat_
MakeJump(0x4B40FC, TraitAdjustSkillHack); // trait_adjust_skill_
memcpy(Traits, (void*)_trait_data, sizeof(TraitInfo) * TRAIT_count);
memcpy(traits, (void*)_trait_data, sizeof(TraitInfo) * TRAIT_count);
// _trait_data
const DWORD traitDataAddr[] = {0x4B3A81, 0x4B3B80};
SafeWriteBatch<DWORD>((DWORD)Traits, traitDataAddr);
SafeWriteBatch<DWORD>((DWORD)traits, traitDataAddr);
const DWORD traitDataDescAddr[] = {0x4B3AAE, 0x4B3BA0};
SafeWriteBatch<DWORD>((DWORD)&Traits[0].Desc, traitDataDescAddr);
SafeWrite32(0x4B3BC0, (DWORD)&Traits[0].Image);
SafeWriteBatch<DWORD>((DWORD)&traits[0].description, traitDataDescAddr);
SafeWrite32(0x4B3BC0, (DWORD)&traits[0].image);
char buf[512], num[5] = {'t'};
char* num2 = &num[1];
for (int i = 0; i < TRAIT_count; i++) {
_itoa_s(i, num2, 4, 10);
if (iniGetString(num, "Name", "", &tName[i * maxNameLen], maxNameLen - 1, perksFile)) {
Traits[i].Name = &tName[i * maxNameLen];
traits[i].name = &tName[i * maxNameLen];
}
if (iniGetString(num, "Desc", "", &tDesc[i * descLen], descLen - 1, perksFile)) {
Traits[i].Desc = &tDesc[i * descLen];
traits[i].description = &tDesc[i * descLen];
}
int value;
value = iniGetInt(num, "Image", -99999, perksFile);
if (value != -99999) Traits[i].Image = value;
if (value != -99999) traits[i].image = value;
if (iniGetString(num, "StatMod", "", buf, 512, perksFile) > 0) {
char *stat, *mod;
@@ -1068,21 +1061,21 @@ static void FastShotTraitFix() {
void __fastcall SetPerkValue(int id, int param, int value) {
if (id < 0 || id >= PERK_count) return;
*(DWORD*)((DWORD)(&Perks[id]) + param) = value;
*(DWORD*)((DWORD)(&perks[id]) + param) = value;
perksReInit = true;
}
void __stdcall SetPerkName(int id, const char* value) {
if (id < 0 || id >= PERK_count) return;
strncpy_s(&Name[id * maxNameLen], maxNameLen, value, _TRUNCATE);
Perks[id].Name = &Name[maxNameLen * id];
perks[id].name = &Name[maxNameLen * id];
perksReInit = true;
}
void __stdcall SetPerkDesc(int id, const char* value) {
if (id < 0 || id >= PERK_count) return;
strncpy_s(&Desc[id * descLen], descLen, value, _TRUNCATE);
Perks[id].Desc = &Desc[descLen * id];
perks[id].description = &Desc[descLen * id];
perksReInit = true;
}
+54 -50
View File
@@ -32,10 +32,10 @@ void __fastcall sf_critter_adjust_poison(TGameObj* critter, long amount) {
if (critter->critter.poison < 0) critter->critter.poison = 0; // level can't be negative
}
static DWORD StatMaximumsPC[STAT_max_stat];
static DWORD StatMinimumsPC[STAT_max_stat];
static DWORD StatMaximumsNPC[STAT_max_stat];
static DWORD StatMinimumsNPC[STAT_max_stat];
static DWORD statMaximumsPC[STAT_max_stat];
static DWORD statMinimumsPC[STAT_max_stat];
static DWORD statMaximumsNPC[STAT_max_stat];
static DWORD statMinimumsNPC[STAT_max_stat];
static DWORD xpTable[99];
@@ -43,9 +43,12 @@ float ExperienceMod = 1.0f; // set_xp_mod func
DWORD StandardApAcBonus = 4;
DWORD ExtraApAcBonus = 4;
static int StatFormulas[33 * 2] = {0};
static int StatShifts[33 * 7] = {0};
static double StatMulti[33 * 7] = {0};
static struct StatFormula {
long base;
long min;
long shift[STAT_lu + 1];
double multi[STAT_lu + 1];
} statFormulas[STAT_max_derived + 1] = {0};
static TGameObj* cCritter;
@@ -62,14 +65,14 @@ static void __declspec(naked) stat_level_hack() {
static int __fastcall check_stat_level(int value, DWORD stat) {
int valLimit;
if (cCritter == *ptr_obj_dude) {
valLimit = StatMinimumsPC[stat];
valLimit = statMinimumsPC[stat];
if (value < valLimit) return valLimit;
valLimit = StatMaximumsPC[stat];
valLimit = statMaximumsPC[stat];
if (value > valLimit) return valLimit;
} else {
valLimit = StatMinimumsNPC[stat];
valLimit = statMinimumsNPC[stat];
if (value < valLimit) return valLimit;
valLimit = StatMaximumsNPC[stat];
valLimit = statMaximumsNPC[stat];
if (value > valLimit) return valLimit;
}
return value;
@@ -90,15 +93,15 @@ static void __declspec(naked) stat_set_base_hack_check() {
__asm {
cmp esi, dword ptr ds:[_obj_dude];
jz pc;
cmp ebx, StatMinimumsNPC[eax];
cmp ebx, statMinimumsNPC[eax];
jl failMin;
cmp ebx, StatMaximumsNPC[eax];
cmp ebx, statMaximumsNPC[eax];
jg failMax;
jmp StatSetBaseHack_Ret;
pc:
cmp ebx, StatMinimumsPC[eax];
cmp ebx, statMinimumsPC[eax];
jl failMin;
cmp ebx, StatMaximumsPC[eax];
cmp ebx, statMaximumsPC[eax];
jg failMax;
jmp StatSetBaseHack_Ret;
failMin:
@@ -157,7 +160,7 @@ static void __declspec(naked) __stdcall ProtoPtr(DWORD pid, int** proto) {
static void __stdcall StatRecalcDerived(TGameObj* critter) {
int baseStats[7];
for (int i = STAT_st; i <= STAT_lu; i++) baseStats[i] = StatLevel(critter, i);
for (int stat = STAT_st; stat <= STAT_lu; stat++) baseStats[stat] = StatLevel(critter, stat);
int* proto;
ProtoPtr(critter->protoId, &proto);
@@ -166,11 +169,12 @@ static void __stdcall StatRecalcDerived(TGameObj* critter) {
if (i >= STAT_dmg_thresh && i <= STAT_dmg_resist_explosion) continue;
double sum = 0;
for (int j = STAT_st; j <= STAT_lu; j++) {
sum += (baseStats[j] + StatShifts[i * 7 + j]) * StatMulti[i * 7 + j];
for (int stat = STAT_st; stat <= STAT_lu; stat++) {
sum += (baseStats[stat] + statFormulas[i].shift[stat]) * statFormulas[i].multi[stat];
}
proto[i + 9] = StatFormulas[i * 2] + (int)floor(sum);
if (proto[i + 9] < StatFormulas[i * 2 + 1]) proto[i + 9] = StatFormulas[i * 2 + 1];
long calcStat = statFormulas[i].base + (int)floor(sum);
if (calcStat < statFormulas[i].min) calcStat = statFormulas[i].min;
proto[9 + i] = calcStat; // offset from base_stat_srength
}
}
@@ -227,8 +231,8 @@ static void __declspec(naked) critter_adjust_poison_hack() {
static void StatsReset() {
for (size_t i = 0; i < STAT_max_stat; i++) {
StatMaximumsPC[i] = StatMaximumsNPC[i] = *(DWORD*)(_stat_data + 16 + i * 24);
StatMinimumsPC[i] = StatMinimumsNPC[i] = *(DWORD*)(_stat_data + 12 + i * 24);
statMaximumsPC[i] = statMaximumsNPC[i] = *(DWORD*)(_stat_data + 16 + i * 24);
statMinimumsPC[i] = statMinimumsNPC[i] = *(DWORD*)(_stat_data + 12 + i * 24);
}
}
@@ -283,32 +287,32 @@ void StatsInit() {
MakeJump(0x4AF6FC, stat_recalc_derived_hack); // overrides function
// STAT_st + STAT_en * 2 + 15
StatFormulas[7 * 2] = 15; // max hp
StatMulti[7 * 7 + STAT_st] = 1;
StatMulti[7 * 7 + STAT_en] = 2;
statFormulas[STAT_max_hit_points].base = 15; // max hp
statFormulas[STAT_max_hit_points].multi[STAT_st] = 1;
statFormulas[STAT_max_hit_points].multi[STAT_en] = 2;
// STAT_ag / 2 + 5
StatFormulas[8 * 2] = 5; // max ap
StatMulti[8 * 7 + STAT_ag] = 0.5;
statFormulas[STAT_max_move_points].base = 5; // max ap
statFormulas[STAT_max_move_points].multi[STAT_ag] = 0.5;
StatMulti[9 * 7 + STAT_ag] = 1; // ac
statFormulas[STAT_ac].multi[STAT_ag] = 1; // ac
// STAT_st - 5
StatFormulas[11 * 2 + 1] = 1; // melee damage
StatShifts[11 * 7 + STAT_st] = -5;
StatMulti[11 * 7 + STAT_st] = 1;
statFormulas[STAT_melee_dmg].min = 1; // melee damage
statFormulas[STAT_melee_dmg].shift[STAT_st] = -5;
statFormulas[STAT_melee_dmg].multi[STAT_st] = 1;
// STAT_st * 25 + 25
StatFormulas[12 * 2] = 25; // carry weight
StatMulti[12 * 7 + STAT_st] = 25;
statFormulas[STAT_carry_amt].base = 25; // carry weight
statFormulas[STAT_carry_amt].multi[STAT_st] = 25;
// STAT_pe * 2
StatMulti[13 * 7 + STAT_pe] = 2; // sequence
statFormulas[STAT_sequence].multi[STAT_pe] = 2; // sequence
// STAT_en / 3
StatFormulas[14 * 2 + 1] = 1; // heal rate
StatMulti[14 * 7 + STAT_en] = 1.0 / 3.0;
statFormulas[STAT_heal_rate].min = 1; // heal rate
statFormulas[STAT_heal_rate].multi[STAT_en] = 1.0 / 3.0;
StatMulti[15 * 7 + STAT_lu] = 1; // critical chance
statFormulas[STAT_crit_chance].multi[STAT_lu] = 1; // critical chance
// STAT_en * 2
StatMulti[31 * 7 + STAT_en] = 2; // rad resist
statFormulas[STAT_rad_resist].multi[STAT_en] = 2; // rad resist
// STAT_en * 5
StatMulti[32 * 7 + STAT_en] = 5; // poison resist
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();
@@ -318,15 +322,15 @@ void StatsInit() {
if (i >= STAT_dmg_thresh && i <= STAT_dmg_resist_explosion) continue;
_itoa(i, key, 10);
StatFormulas[i * 2] = iniGetInt(key, "base", StatFormulas[i * 2], statFile);
StatFormulas[i * 2 + 1] = iniGetInt(key, "min", StatFormulas[i * 2 + 1], statFile);
statFormulas[i].base = iniGetInt(key, "base", statFormulas[i].base, statFile);
statFormulas[i].min = iniGetInt(key, "min", statFormulas[i].min, statFile);
for (int j = 0; j < STAT_max_hit_points; j++) {
sprintf(buf2, "shift%d", j);
StatShifts[i * 7 + j] = iniGetInt(key, buf2, StatShifts[i * 7 + j], statFile);
statFormulas[i].shift[j] = iniGetInt(key, buf2, statFormulas[i].shift[j], statFile);
sprintf(buf2, "multi%d", j);
_gcvt(StatMulti[i * 7 + j], 16, buf3);
_gcvt(statFormulas[i].multi[j], 16, buf3);
iniGetString(key, buf2, buf3, buf2, 256, statFile);
StatMulti[i * 7 + j] = atof(buf2);
statFormulas[i].multi[j] = atof(buf2);
}
}
}
@@ -334,38 +338,38 @@ void StatsInit() {
long __stdcall GetStatMax(int stat, int isNPC) {
if (stat >= 0 && stat < STAT_max_stat) {
return (isNPC) ? StatMaximumsNPC[stat] : StatMaximumsPC[stat];
return (isNPC) ? statMaximumsNPC[stat] : statMaximumsPC[stat];
}
return 0;
}
long __stdcall GetStatMin(int stat, int isNPC) {
if (stat >= 0 && stat < STAT_max_stat) {
return (isNPC) ? StatMinimumsNPC[stat] : StatMinimumsPC[stat];
return (isNPC) ? statMinimumsNPC[stat] : statMinimumsPC[stat];
}
return 0;
}
void __stdcall SetPCStatMax(int stat, int value) {
if (stat >= 0 && stat < STAT_max_stat) {
StatMaximumsPC[stat] = value;
statMaximumsPC[stat] = value;
}
}
void __stdcall SetPCStatMin(int stat, int value) {
if (stat >= 0 && stat < STAT_max_stat) {
StatMinimumsPC[stat] = value;
statMinimumsPC[stat] = value;
}
}
void __stdcall SetNPCStatMax(int stat, int value) {
if (stat >= 0 && stat < STAT_max_stat) {
StatMaximumsNPC[stat] = value;
statMaximumsNPC[stat] = value;
}
}
void __stdcall SetNPCStatMin(int stat, int value) {
if (stat >= 0 && stat < STAT_max_stat) {
StatMinimumsNPC[stat] = value;
statMinimumsNPC[stat] = value;
}
}
+1 -1
View File
@@ -63,7 +63,7 @@ static void TimerReset() {
addedYears += 13;
// fix queue time
Queue* queue = (Queue*)(*ptr_queue);
Queue* queue = *ptr_queue;
while (queue) {
if (queue->time > time) {
queue->time -= time;