Fix for fake perks related functions.

* now fake perks are no longer added to all controlled critters.

Added alternative functions that allow to add fake perks to party
member NPC.

Rewrote set_fake_perk/trait, set_selectable_perk, has_fake_perk/trait
functions in C++.
This commit is contained in:
NovaRain
2019-05-27 12:01:09 +08:00
parent 22cdc32d26
commit aa221adea3
9 changed files with 225 additions and 323 deletions
+10
View File
@@ -238,6 +238,11 @@
#define party_member_list_critters party_member_list(0) #define party_member_list_critters party_member_list(0)
#define party_member_list_all party_member_list(1) #define party_member_list_all party_member_list(1)
// fake perks/traits add mode flags
#define ADD_PERK_MODE_TRAIT (1) // add to the player's traits
#define ADD_PERK_MODE_PERK (2) // add to the player's perks
#define ADD_PERK_MODE_REMOVE (4) // remove from the list of selectable perks
// sfall_funcX macros // sfall_funcX macros
#define add_iface_tag sfall_func0("add_iface_tag") #define add_iface_tag sfall_func0("add_iface_tag")
#define art_cache_clear sfall_func0("art_cache_clear") #define art_cache_clear sfall_func0("art_cache_clear")
@@ -264,6 +269,8 @@
#define get_object_data(obj, offset) sfall_func2("get_object_data", obj, offset) #define get_object_data(obj, offset) sfall_func2("get_object_data", obj, offset)
#define get_outline(obj) sfall_func1("get_outline", obj) #define get_outline(obj) sfall_func1("get_outline", obj)
#define get_string_pointer(text) sfall_func1("get_string_pointer", text) #define get_string_pointer(text) sfall_func1("get_string_pointer", 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)
#define intface_hide sfall_func0("intface_hide") #define intface_hide sfall_func0("intface_hide")
#define intface_is_hidden sfall_func0("intface_is_hidden") #define intface_is_hidden sfall_func0("intface_is_hidden")
#define intface_redraw sfall_func0("intface_redraw") #define intface_redraw sfall_func0("intface_redraw")
@@ -282,6 +289,8 @@
#define set_cursor_mode(mode) sfall_func1("set_cursor_mode", mode) #define set_cursor_mode(mode) sfall_func1("set_cursor_mode", mode)
#define set_drugs_data(type, pid, value) sfall_func3("set_drugs_data", type, pid, value) #define set_drugs_data(type, pid, value) sfall_func3("set_drugs_data", type, pid, value)
#define set_dude_obj(critter) sfall_func1("set_dude_obj", critter) #define set_dude_obj(critter) sfall_func1("set_dude_obj", critter)
#define set_fake_perk_npc(npc, perk, level, image, desc) sfall_func5("set_fake_perk_npc", npc, perk, level, image, desc)
#define set_fake_trait_npc(npc, trait, active, image, desc) sfall_func5("set_fake_trait_npc", npc, trait, active, image, desc)
#define set_flags(obj, flags) sfall_func2("set_flags", obj, flags) #define set_flags(obj, flags) sfall_func2("set_flags", obj, flags)
#define set_iface_tag_text(tag, text, color) sfall_func3("set_iface_tag_text", tag, text, color) #define set_iface_tag_text(tag, text, color) sfall_func3("set_iface_tag_text", tag, text, color)
#define set_ini_setting(setting, value) sfall_func2("set_ini_setting", setting, value) #define set_ini_setting(setting, value) sfall_func2("set_ini_setting", setting, value)
@@ -290,6 +299,7 @@
#define set_outline(obj, color) sfall_func2("set_outline", obj, color) #define set_outline(obj, color) sfall_func2("set_outline", obj, color)
#define set_rest_heal_time(time) sfall_func1("set_rest_heal_time", time) #define set_rest_heal_time(time) sfall_func1("set_rest_heal_time", time)
#define set_rest_mode(mode) sfall_func1("set_rest_mode", mode) #define set_rest_mode(mode) sfall_func1("set_rest_mode", mode)
#define set_selectable_perk_npc(npc, perk, active, image, desc) sfall_func5("set_selectable_perk_npc", npc, perk, active, image, desc)
#define set_unique_id(obj) sfall_func1("set_unique_id", obj) #define set_unique_id(obj) sfall_func1("set_unique_id", obj)
#define unset_unique_id(obj) sfall_func2("set_unique_id", obj, -1) #define unset_unique_id(obj) sfall_func2("set_unique_id", obj, -1)
#define set_unjam_locks_time(time) sfall_func1("set_unjam_locks_time", time) #define set_unjam_locks_time(time) sfall_func1("set_unjam_locks_time", time)
+11 -4
View File
@@ -32,7 +32,7 @@ set_shader_mode tells sfall when to use a shader. The parameter is a set of 32 f
force_graphics_refresh forces the screen to redraw at times when it normally wouldn't. If you're using animated shader, turning this option on is recommended. force_graphics_refresh forces the screen to redraw at times when it normally wouldn't. If you're using animated shader, turning this option on is recommended.
The mapper manual lists the functions 'world_map_x_pos' and 'world_map_y_pos', which supposedly return the players x and y positions on the world map. get_world_map_x/y_pos are included here anyway, because I was unable to get those original functions to work, or even to find any evidence that they existed in game. The mapper manual lists the functions 'world_map_x_pos' and 'world_map_y_pos', which supposedly return the player's x and y positions on the world map. get_world_map_x/y_pos are included here anyway, because I was unable to get those original functions to work, or even to find any evidence that they existed in game.
set_pipboy_available will only accept 0 or 1 as an argument. Using any other value will cause the function to have no effect. Use 0 to disable the pipboy, and 1 to enable it. set_pipboy_available will only accept 0 or 1 as an argument. Using any other value will cause the function to have no effect. Use 0 to disable the pipboy, and 1 to enable it.
@@ -42,13 +42,13 @@ The 'type' value in the weapon knockback functions can be 0 or 1. If 0, the valu
The get/set_sfall_global functions require an 8 characters long case sensitive string for the variable name. The variables behave the same as normal Fallout globals, except that they don't have to be declared beforehand in vault13.gam. Trying to get a variable which hasn't been set will always return 0. These functions are intended for use when a patch to a mod requires the addition of a new global variable, a case which would otherwise require the player to start a new game. The get/set_sfall_global functions require an 8 characters long case sensitive string for the variable name. The variables behave the same as normal Fallout globals, except that they don't have to be declared beforehand in vault13.gam. Trying to get a variable which hasn't been set will always return 0. These functions are intended for use when a patch to a mod requires the addition of a new global variable, a case which would otherwise require the player to start a new game.
set_pickpocket_max and set_hit_chance_max effect all critters rather than just the player. set_skill_max can't be used to increase the skill cap above 300. set_perk_level_mod sets a modifier between +25 and -25 that is added/subtracted from the players level for the purposes of deciding which perks can be chosen. set_pickpocket_max and set_hit_chance_max effect all critters rather than just the player. set_skill_max can't be used to increase the skill cap above 300. set_perk_level_mod sets a modifier between +25 and -25 that is added/subtracted from the player's level for the purposes of deciding which perks can be chosen.
set_fake_trait and set_fake_perk can be used to add additional traits and perks to the character screen. They will be saved correctly when the player saves and reloads games, but by themselves they will have no further effect on the character. For perks, the allowed range for levels is between 0 and 100; setting the level to 0 removes that perk. For traits, the level must be 0 or 1. The image is a numeric id that corresponds to an entry in skilldex.lst. The name is limited to 63 characters and the description to 255 characters by sfall, but internal Fallout limits may be lower. set_fake_trait and set_fake_perk can be used to add additional traits and perks to the character screen. They will be saved correctly when the player saves and reloads games, but by themselves they will have no further effect on the character. For perks, the allowed range for levels is between 0 and 100; setting the level to 0 removes that perk. For traits, the level must be 0 or 1. The image is a numeric id that corresponds to an entry in skilldex.lst. The name is limited to 63 characters and the description to 255 characters by sfall, but internal Fallout limits may be lower.
has_fake_trait and has_fake_perk return the number of levels the player has of the perks/traits with the given name or ID of extra perk. has_fake_trait and has_fake_perk return the number of levels the player has of the perks/traits with the given name or ID of extra perk.
perk_add_mode, set_selectable_perk, set_perkbox_title, hide_real_perks, show_real_perks and clear_selectable_perks control the behaviour of the select a perk box. set_selectable_perk can be used to add additional items by setting the 'active' parameter to 1, and to remove them again by setting it to 0. set_perkbox_title can be used to change the title of the box, or by using "" it will be set back to the default. hide and show_real_perks can be used to prevent the dialog from displaying any of the original 119 perks. perk_add_mode modifies what happens when a fake perk is selected from the perks dialog. It is treated as a set of flags - if bit 1 is set then it is added to the players traits, if bit 2 is set it is added to the players perks, and if bit 3 is set it is removed from the list of selectable perks. The default is 0x2. clear_selectable_perks restores the dialog to its default state. perk_add_mode, set_selectable_perk, set_perkbox_title, hide_real_perks, show_real_perks and clear_selectable_perks control the behaviour of the select a perk box. set_selectable_perk can be used to add additional items by setting the 'active' parameter to 1, and to remove them again by setting it to 0. set_perkbox_title can be used to change the title of the box, or by using "" it will be set back to the default. hide and show_real_perks can be used to prevent the dialog from displaying any of the original 119 perks. perk_add_mode modifies what happens when a fake perk is selected from the perks dialog. It is treated as a set of flags - if bit 1 is set then it is added to the player's traits, if bit 2 is set it is added to the player's perks, and if bit 3 is set it is removed from the list of selectable perks. The default is 0x2. clear_selectable_perks restores the dialog to its default state.
show_iface_tag, hide_iface_tag and is_iface_tag_active relate to the boxes that appear above the interface such as SNEAK and LEVEL. You can use 3 for LEVEL and 4 for ADDICT, or the range from 5 to (4 + the value of BoxBarCount in ddraw.ini) for custom boxes. Remember to add your messages to intrface.msg and set up the font colours in ddraw.ini if you're going to use custom boxes. Starting from sfall 4.1, is_iface_tag_active can also be used to check 0 for SNEAK, 1 for POISONED, and 2 for RADIATED. show_iface_tag, hide_iface_tag and is_iface_tag_active relate to the boxes that appear above the interface such as SNEAK and LEVEL. You can use 3 for LEVEL and 4 for ADDICT, or the range from 5 to (4 + the value of BoxBarCount in ddraw.ini) for custom boxes. Remember to add your messages to intrface.msg and set up the font colours in ddraw.ini if you're going to use custom boxes. Starting from sfall 4.1, is_iface_tag_active can also be used to check 0 for SNEAK, 1 for POISONED, and 2 for RADIATED.
@@ -591,7 +591,7 @@ Some utility/math functions are available:
> void sfall_func6("draw_image_scaled", string/int pathFile/artId, int frame, int x, int y, int width, int height) > void sfall_func6("draw_image_scaled", string/int pathFile/artId, int frame, int x, int y, int width, int height)
- displays the specified FRM image in the active window created by vanilla CreateWin or sfall's create_win script function - displays the specified FRM image in the active window created by vanilla CreateWin or sfall's create_win script function
- pathFile/artId: path to the FRM file (e.g. "art\\inven\\5mmap.frm"), or its FRM ID number (e.g. 117440550, see specification of the FID format) - pathFile/artId: path to the FRM file (e.g. "art\\inven\\5mmap.frm"), or its FRM ID number (e.g. 117440550, see specification of the FID format)
Optional arguments: optional arguments:
- frame: frame number, the first frame starts from zero - frame: frame number, the first frame starts from zero
- x/y: offset relative to the top-left corner of the window - x/y: offset relative to the top-left corner of the window
- width/height: image size, used to scale the image when displaying it. Pass -1 to either width or height to keep the aspect ratio when scaling - width/height: image size, used to scale the image when displaying it. Pass -1 to either width or height to keep the aspect ratio when scaling
@@ -599,6 +599,13 @@ Optional arguments:
- NOTE: to omit optional arguments starting from the right, call the functions with different sfall_funcX (e.g. sfall_func4("draw_image", pathFile, frame, x, y)) - NOTE: to omit optional arguments starting from the right, call the functions with different sfall_funcX (e.g. sfall_func4("draw_image", pathFile, frame, x, y))
- if draw_image_scaled is called without x/y/width/height arguments, the image will be scaled to fit the window without transparent background - if draw_image_scaled is called without x/y/width/height arguments, the image will be scaled to fit the window without transparent background
> void sfall_func5("set_fake_perk_npc", object npc, string namePerk, int level, int image, string desc)
> void sfall_func5("set_fake_trait_npc", object npc, string nameTrait, int active, int image, string desc)
> void sfall_func5("set_selectable_perk_npc", object npc, string namePerk, int active, int image, string desc)
> int sfall_func2("has_fake_perk_npc", object npc, string namePerk)
> int sfall_func2("has_fake_trait_npc", object npc, string nameTrait)
- functions are similar to has_fake_*/set_fake_*/set_selectable_perk opcodes, but work on the specified party member NPC (including dude_obj)
------------------------ ------------------------
------ MORE INFO ------- ------ MORE INFO -------
------------------------ ------------------------
+3 -1
View File
@@ -641,7 +641,9 @@ enum BodyType : long
Robotic = 2 Robotic = 2
}; };
#define OBJFLAG_CAN_WEAR_ITEMS (0xf000000) #define PLAYER_ID (18000)
#define OBJFLAG_CAN_WEAR_ITEMS (0xF000000)
#define OBJFLAG_HELD_IN_RIGHT (0x10000) #define OBJFLAG_HELD_IN_RIGHT (0x10000)
#define OBJFLAG_HELD_IN_LEFT (0x20000) #define OBJFLAG_HELD_IN_LEFT (0x20000)
+101 -49
View File
@@ -21,6 +21,7 @@
#include "..\main.h" #include "..\main.h"
#include "..\FalloutEngine\Fallout2.h" #include "..\FalloutEngine\Fallout2.h"
#include "LoadGameHook.h" #include "LoadGameHook.h"
#include "PartyControl.h"
#include "Perks.h" #include "Perks.h"
@@ -75,12 +76,13 @@ struct FakePerk {
int Image; int Image;
char Name[maxNameLen]; char Name[maxNameLen];
char Desc[maxDescLen]; char Desc[maxDescLen];
char reserve[510]; // empty block char reserve[506]; // empty block
int ownerId; // 0 = the player, or ID number of party member NPC
short id; // perk id (use last bytes of the description under the ID value for compatibility) short id; // perk id (use last bytes of the description under the ID value for compatibility)
FakePerk() {} FakePerk() {}
FakePerk(char* _name, int _level, int _image, char* _desc, short _id = -1) : id(_id), Name {0}, Desc {0}, reserve {0} { FakePerk(const char* _name, int _level, int _image, const char* _desc, int npcId, short _id = -1) : ownerId(npcId), id(_id), Name {0}, Desc {0}, reserve {0} {
Level = _level; Level = _level;
Image = _image; Image = _image;
strncpy_s(this->Name, _name, _TRUNCATE); strncpy_s(this->Name, _name, _TRUNCATE);
@@ -151,7 +153,7 @@ static long _stdcall LevelUp() {
} }
} }
int level = fo::var::Level_; // Get players level int level = fo::var::Level_; // Get player's level
if (!((level + 1) % eachLevel)) fo::var::free_perk++; // Increment the number of perks owed if (!((level + 1) % eachLevel)) fo::var::free_perk++; // Increment the number of perks owed
return level; return level;
} }
@@ -191,11 +193,21 @@ void _stdcall SetPerkboxTitle(char* name) {
} }
} }
void _stdcall SetSelectablePerk(char* name, int active, int image, char* desc) { static bool IsOwnedFake(int ownerId) {
if (active < 0 || active > 1) return; return ((!ownerId && !PartyControl::IsNpcControlled()) || ownerId == fo::var::obj_dude->id);
}
static bool IsNotOwnedFake(int ownerId1, int ownerId2) {
return (ownerId1 != ownerId2);
}
void Perks::SetSelectablePerk(const char* name, int active, int image, const char* desc, int npcID) {
if (active < 0) return;
if (active > 1) active = 1;
size_t size = fakeSelectablePerks.size(); size_t size = fakeSelectablePerks.size();
if (active == 0) { if (active == 0) {
for (size_t i = 0; i < size; i++) { for (size_t i = 0; i < size; i++) {
if (IsNotOwnedFake(fakeSelectablePerks[i].ownerId, npcID)) continue;
if (!strcmp(name, fakeSelectablePerks[i].Name)) { if (!strcmp(name, fakeSelectablePerks[i].Name)) {
fakeSelectablePerks.erase(fakeSelectablePerks.begin() + i); fakeSelectablePerks.erase(fakeSelectablePerks.begin() + i);
return; return;
@@ -203,6 +215,7 @@ void _stdcall SetSelectablePerk(char* name, int active, int image, char* desc) {
} }
} else { } else {
for (size_t i = 0; i < size; i++) { for (size_t i = 0; i < size; i++) {
if (IsNotOwnedFake(fakeSelectablePerks[i].ownerId, npcID)) continue;
if (!strcmp(name, fakeSelectablePerks[i].Name)) { if (!strcmp(name, fakeSelectablePerks[i].Name)) {
fakeSelectablePerks[i].Level = active; fakeSelectablePerks[i].Level = active;
fakeSelectablePerks[i].Image = image; fakeSelectablePerks[i].Image = image;
@@ -212,19 +225,17 @@ void _stdcall SetSelectablePerk(char* name, int active, int image, char* desc) {
} }
} }
if (size == fakeSelectablePerks.capacity()) fakeSelectablePerks.reserve(size + 10); if (size == fakeSelectablePerks.capacity()) fakeSelectablePerks.reserve(size + 10);
fakeSelectablePerks.emplace_back(name, active, image, desc); fakeSelectablePerks.emplace_back(name, active, image, desc, npcID);
} }
} }
void _stdcall SetFakePerk(char* name, int level, int image, char* desc) { void Perks::SetFakePerk(const char* name, int level, int image, const char* desc, int npcID) {
if (level > 100) { if (level < 0) return;
level = 100; if (level > 100) level = 100;
} else if (level < 0 ) {
return;
}
size_t size = fakePerks.size(); size_t size = fakePerks.size();
if (level == 0) { // remove perk from fakePerks if (level == 0) { // remove perk from fakePerks
for (size_t i = 0; i < size; i++) { for (size_t i = 0; i < size; i++) {
if (IsNotOwnedFake(fakePerks[i].ownerId, npcID)) continue;
if (!strcmp(name, fakePerks[i].Name)) { if (!strcmp(name, fakePerks[i].Name)) {
fakePerks.erase(fakePerks.begin() + i); fakePerks.erase(fakePerks.begin() + i);
return; return;
@@ -232,6 +243,7 @@ void _stdcall SetFakePerk(char* name, int level, int image, char* desc) {
} }
} else { // add or change the existing fake perk in fakePerks } else { // add or change the existing fake perk in fakePerks
for (size_t i = 0; i < size; i++) { for (size_t i = 0; i < size; i++) {
if (IsNotOwnedFake(fakePerks[i].ownerId, npcID)) continue;
if (!strcmp(name, fakePerks[i].Name)) { if (!strcmp(name, fakePerks[i].Name)) {
fakePerks[i].Level = level; fakePerks[i].Level = level;
fakePerks[i].Image = image; fakePerks[i].Image = image;
@@ -241,19 +253,17 @@ void _stdcall SetFakePerk(char* name, int level, int image, char* desc) {
} }
} }
if (size == fakePerks.capacity()) fakePerks.reserve(size + 10); if (size == fakePerks.capacity()) fakePerks.reserve(size + 10);
fakePerks.emplace_back(name, level, image, desc); fakePerks.emplace_back(name, level, image, desc, npcID);
} }
} }
void _stdcall SetFakeTrait(char* name, int active, int image, char* desc) { void Perks::SetFakeTrait(const char* name, int active, int image, const char* desc, int npcID) {
if (active > 1) { if (active < 0) return;
active = 1; if (active > 1) active = 1;
} else if (active < 0) {
return;
}
size_t size = fakeTraits.size(); size_t size = fakeTraits.size();
if (active == 0) { if (active == 0) {
for (size_t i = 0; i < size; i++) { for (size_t i = 0; i < size; i++) {
if (IsNotOwnedFake(fakeTraits[i].ownerId, npcID)) continue;
if (!strcmp(name, fakeTraits[i].Name)) { if (!strcmp(name, fakeTraits[i].Name)) {
fakeTraits.erase(fakeTraits.begin() + i); fakeTraits.erase(fakeTraits.begin() + i);
return; return;
@@ -261,6 +271,7 @@ void _stdcall SetFakeTrait(char* name, int active, int image, char* desc) {
} }
} else { } else {
for (size_t i = 0; i < size; i++) { for (size_t i = 0; i < size; i++) {
if (IsNotOwnedFake(fakeTraits[i].ownerId, npcID)) continue;
if (!strcmp(name, fakeTraits[i].Name)) { if (!strcmp(name, fakeTraits[i].Name)) {
fakeTraits[i].Level = active; fakeTraits[i].Level = active;
fakeTraits[i].Image = image; fakeTraits[i].Image = image;
@@ -270,7 +281,7 @@ void _stdcall SetFakeTrait(char* name, int active, int image, char* desc) {
} }
} }
if (size == fakeTraits.capacity()) fakeTraits.reserve(size + 5); if (size == fakeTraits.capacity()) fakeTraits.reserve(size + 5);
fakeTraits.emplace_back(name, active, image, desc); fakeTraits.emplace_back(name, active, image, desc, npcID);
} }
} }
@@ -279,7 +290,8 @@ static DWORD _stdcall HaveFakePerks() {
} }
static long __fastcall GetFakePerkLevel(int id) { static long __fastcall GetFakePerkLevel(int id) {
return fakePerks[id - PERK_count].Level; int i = id - PERK_count;
return IsOwnedFake(fakePerks[i].ownerId) ? fakePerks[i].Level : 0;
} }
static long __fastcall GetFakePerkImage(int id) { static long __fastcall GetFakePerkImage(int id) {
@@ -290,16 +302,24 @@ static FakePerk* __fastcall GetFakePerk(int id) {
return &fakePerks[id - PERK_count]; return &fakePerks[id - PERK_count];
} }
// Get level of taken perk
static DWORD __fastcall GetFakeSelectPerkLevel(int id) { static DWORD __fastcall GetFakeSelectPerkLevel(int id) {
if (id < startFakeID) { if (id < startFakeID) {
for (DWORD i = 0; i < fakePerks.size(); i++) { if (!PartyControl::IsNpcControlled()) { // extra perks are not available for controlled NPC
if (fakePerks[i].id == id) return fakePerks[i].Level; for (DWORD i = 0; i < fakePerks.size(); i++) {
if (fakePerks[i].id == id) return fakePerks[i].Level;
}
} }
return 0; return 0;
} }
char* name = fakeSelectablePerks[id - startFakeID].Name; long n = id - startFakeID;
const char* name = fakeSelectablePerks[n].Name;
int ownerID = fakeSelectablePerks[n].ownerId;
for (DWORD i = 0; i < fakePerks.size(); i++) { for (DWORD i = 0; i < fakePerks.size(); i++) {
if (!strcmp(name, fakePerks[i].Name)) return fakePerks[i].Level; if (ownerID != fakePerks[i].ownerId) continue;
if (!strcmp(name, fakePerks[i].Name)) {
return fakePerks[i].Level;
}
} }
return 0; return 0;
} }
@@ -321,8 +341,10 @@ static FakePerk* __fastcall GetFakeSelectPerk(int id) {
return &fakeSelectablePerks[id - startFakeID]; return &fakeSelectablePerks[id - startFakeID];
} }
// Print a list of fake traits
static DWORD HandleFakeTraits(int isSelect) { static DWORD HandleFakeTraits(int isSelect) {
for (DWORD i = 0; i < fakeTraits.size(); i++) { for (DWORD i = 0; i < fakeTraits.size(); i++) {
if (!IsOwnedFake(fakeTraits[i].ownerId)) continue;
if (fo::func::folder_print_line(fakeTraits[i].Name) && !isSelect) { if (fo::func::folder_print_line(fakeTraits[i].Name) && !isSelect) {
isSelect = 1; isSelect = 1;
var::folder_card_fid = fakeTraits[i].Image; var::folder_card_fid = fakeTraits[i].Image;
@@ -340,11 +362,13 @@ static long __fastcall PlayerHasPerk(int &isSelectPtr) {
for (int i = 0; i < PERK_count; i++) { for (int i = 0; i < PERK_count; i++) {
if (fo::func::perk_level(fo::var::obj_dude, i)) return 0x43438A; // print perks if (fo::func::perk_level(fo::var::obj_dude, i)) return 0x43438A; // print perks
} }
return (!fakePerks.empty()) ? 0x43438A : 0x434446; // skip print perks return (!fakePerks.empty())
? 0x43438A // print perks
: 0x434446; // skip print perks
} }
static DWORD __fastcall HaveFakeTraits(int &isSelectPtr) { static DWORD __fastcall HaveFakeTraits(int &isSelectPtr) {
return (fakeTraits.empty()) ? PlayerHasPerk(isSelectPtr) : 0x43425B; return (fakeTraits.empty()) ? PlayerHasPerk(isSelectPtr) : 0x43425B; // print traits
} }
static void __declspec(naked) PlayerHasPerkHack() { static void __declspec(naked) PlayerHasPerkHack() {
@@ -362,7 +386,7 @@ static void __declspec(naked) PlayerHasTraitHook() {
push ecx; // isSelect push ecx; // isSelect
mov ecx, esp; // ptr to isSelect mov ecx, esp; // ptr to isSelect
call HaveFakeTraits; call HaveFakeTraits;
pop ecx; // value from HandleFakeTraits pop ecx; // isSelect value from HandleFakeTraits
jmp eax; jmp eax;
} }
} }
@@ -445,16 +469,21 @@ cLoop:
// Build a table of perks ID numbers available for selection, data buffer has limited size for 119 perks // Build a table of perks ID numbers available for selection, data buffer has limited size for 119 perks
static DWORD _stdcall HandleExtraSelectablePerks(DWORD available, DWORD* data) { static DWORD _stdcall HandleExtraSelectablePerks(DWORD available, DWORD* data) {
size_t count = extPerks.size(); size_t count;
for (size_t i = 0; i < count; i++) { if (!PartyControl::IsNpcControlled()) { // extra perks are not available for controlled NPC
if (available >= 119) return available; // exit if the buffer is overfull count = extPerks.size();
if (fo::func::perk_can_add(fo::var::obj_dude, extPerks[i].id)) data[available++] = extPerks[i].id; for (size_t i = 0; i < count; i++) {
if (available >= 119) return available; // exit if the buffer is overfull
if (fo::func::perk_can_add(fo::var::obj_dude, extPerks[i].id)) data[available++] = extPerks[i].id;
}
} }
count = fakeSelectablePerks.size(); count = fakeSelectablePerks.size();
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
if (available >= 119) break; if (IsOwnedFake(fakeSelectablePerks[i].ownerId)) {
// for fake perks, their ID should start from 256 if (available >= 119) break;
data[available++] = startFakeID + i; // for fake perks, their ID should start from 256
data[available++] = startFakeID + i;
}
} }
return available; // total number of perks available for selection return available; // total number of perks available for selection
} }
@@ -579,10 +608,10 @@ static void ApplyPerkEffect(long index, fo::GameObject* critter, long type) {
} }
// Adds the selected perk to the player // Adds the selected perk to the player
static void _stdcall AddFakePerk(DWORD perkID) { static long _stdcall AddFakePerk(DWORD perkID) {
size_t count; size_t count;
bool matched = false; bool matched = false;
if (perkID < startFakeID) { if (perkID < startFakeID) { // extra perk can only be added to the player
count = fakePerks.size(); count = fakePerks.size();
for (size_t d = 0; d < count; d++) { for (size_t d = 0; d < count; d++) {
if (fakePerks[d].id == perkID) { if (fakePerks[d].id == perkID) {
@@ -593,18 +622,20 @@ static void _stdcall AddFakePerk(DWORD perkID) {
} }
} }
if (!matched) { // add to fakePerks if (!matched) { // add to fakePerks
RemovePerkID.push_back(count); // index of the added perk
int index = PerkSearchID(perkID); int index = PerkSearchID(perkID);
fakePerks.emplace_back(extPerks[index].Name, 1, extPerks[index].data.image, extPerks[index].Desc, extPerks[index].id); // id same as perkID if (index < 0) return -1;
RemovePerkID.push_back(count); // index of the added perk
fakePerks.emplace_back(extPerks[index].Name, 1, extPerks[index].data.image, extPerks[index].Desc, 0, extPerks[index].id); // id same as perkID
} }
fo::func::perk_add_effect(fo::var::obj_dude, perkID); fo::func::perk_add_effect(fo::var::obj_dude, perkID);
return; return 0;
} }
// behavior for fake perk/trait // behavior for fake perk/trait
perkID -= startFakeID; perkID -= startFakeID;
if (addPerkMode & 1) { // add perk to trait if (addPerkMode & 1) { // add perk to trait
count = fakeTraits.size(); count = fakeTraits.size();
for (size_t d = 0; d < count; d++) { for (size_t d = 0; d < count; d++) {
if (IsNotOwnedFake(fakeTraits[d].ownerId, fakeSelectablePerks[perkID].ownerId)) continue;
if (!strcmp(fakeTraits[d].Name, fakeSelectablePerks[perkID].Name)) { if (!strcmp(fakeTraits[d].Name, fakeSelectablePerks[perkID].Name)) {
matched = true; matched = true;
break; break;
@@ -619,6 +650,7 @@ static void _stdcall AddFakePerk(DWORD perkID) {
matched = false; matched = false;
count = fakePerks.size(); count = fakePerks.size();
for (size_t d = 0; d < count; d++) { for (size_t d = 0; d < count; d++) {
if (IsNotOwnedFake(fakePerks[d].ownerId, fakeSelectablePerks[perkID].ownerId)) continue;
if (!strcmp(fakePerks[d].Name, fakeSelectablePerks[perkID].Name)) { if (!strcmp(fakePerks[d].Name, fakeSelectablePerks[perkID].Name)) {
RemovePerkID.push_back(d); RemovePerkID.push_back(d);
fakePerks[d].Level++; fakePerks[d].Level++;
@@ -634,6 +666,7 @@ static void _stdcall AddFakePerk(DWORD perkID) {
if (addPerkMode & 4) { // delete from selectable perks if (addPerkMode & 4) { // delete from selectable perks
RemoveSelectableID.push_back(perkID); //fakeSelectablePerks.remove_at(perkID); RemoveSelectableID.push_back(perkID); //fakeSelectablePerks.remove_at(perkID);
} }
return 0;
} }
// Adds perk from selection window to player // Adds perk from selection window to player
@@ -645,7 +678,6 @@ static void __declspec(naked) AddPerkHook() {
push edx; push edx;
call AddFakePerk; call AddFakePerk;
pop ecx; pop ecx;
xor eax, eax;
retn; retn;
normalPerk: normalPerk:
push edx; push edx;
@@ -1287,23 +1319,43 @@ void _stdcall AddPerkMode(DWORD mode) {
addPerkMode = mode; addPerkMode = mode;
} }
DWORD HasFakePerk(const char* name, long perkId) { DWORD Perks::HasFakePerk(const char* name, long perkId) {
if (perkId < PERK_count && name[0] == 0) return 0; if ((perkId < PERK_count && name[0] == 0) || (perkId && PartyControl::IsNpcControlled())) return 0;
for (DWORD i = 0; i < fakePerks.size(); i++) { for (DWORD i = 0; i < fakePerks.size(); i++) {
if (perkId) { if (perkId) {
if (fakePerks[i].id == perkId) { if (fakePerks[i].id == perkId) return fakePerks[i].Level; // current perk level
return fakePerks[i].Level; } else if (IsOwnedFake(fakePerks[i].ownerId) && !strcmp(name, fakePerks[i].Name)) {
} return fakePerks[i].Level;
} else if (!strcmp(name, fakePerks[i].Name)) {
return fakePerks[i].Level; // current perk level
} }
} }
return 0; return 0;
} }
DWORD _stdcall HasFakeTrait(const char* name) { DWORD Perks::HasFakeTrait(const char* name) {
if (name[0] == 0) return 0; if (name[0] == 0) return 0;
for (DWORD i = 0; i < fakeTraits.size(); i++) { for (DWORD i = 0; i < fakeTraits.size(); i++) {
if (IsOwnedFake(fakeTraits[i].ownerId) && !strcmp(name, fakeTraits[i].Name)) {
return 1;
}
}
return 0;
}
DWORD Perks::HasFakePerkOwner(const char* name, long objId) {
if (name[0] == 0) return 0;
for (DWORD i = 0; i < fakePerks.size(); i++) {
if (IsNotOwnedFake(fakePerks[i].ownerId, objId)) continue;
if (!strcmp(name, fakePerks[i].Name)) {
return fakePerks[i].Level;
}
}
return 0;
}
DWORD Perks::HasFakeTraitOwner(const char* name, long objId) {
if (name[0] == 0) return 0;
for (DWORD i = 0; i < fakeTraits.size(); i++) {
if (IsNotOwnedFake(fakeTraits[i].ownerId, objId)) continue;
if (!strcmp(name, fakeTraits[i].Name)) { if (!strcmp(name, fakeTraits[i].Name)) {
return 1; return 1;
} }
+11 -7
View File
@@ -30,6 +30,15 @@ public:
static void save(HANDLE file); static void save(HANDLE file);
static bool load(HANDLE file); static bool load(HANDLE file);
static void SetSelectablePerk(const char* name, int active, int image, const char* desc, int npcID = 0);
static void SetFakePerk(const char* name, int level, int image, const char* desc, int npcID = 0);
static void SetFakeTrait(const char* name, int active, int image, const char* desc, int npcID = 0);
static DWORD HasFakePerk(const char* name, long perkId);
static DWORD HasFakeTrait(const char* name);
static DWORD HasFakePerkOwner(const char* name, long objId);
static DWORD HasFakeTraitOwner(const char* name, long objId);
}; };
void PerksEnterCharScreen(); void PerksEnterCharScreen();
@@ -43,17 +52,12 @@ void _stdcall SetPerkName(int id, char* value);
void _stdcall SetPerkDesc(int id, char* value); void _stdcall SetPerkDesc(int id, char* value);
void _stdcall SetPerkboxTitle(char* title); void _stdcall SetPerkboxTitle(char* title);
void _stdcall SetSelectablePerk(char* name, int level, int image, char* desc);
void _stdcall SetFakePerk(char* name, int level, int image, char* desc);
void _stdcall SetFakeTrait(char* name, int level, int image, char* desc);
void _stdcall IgnoreDefaultPerks(); void _stdcall IgnoreDefaultPerks();
void _stdcall RestoreDefaultPerks(); void _stdcall RestoreDefaultPerks();
void _stdcall AddPerkMode(DWORD mode); void _stdcall AddPerkMode(DWORD mode);
DWORD HasFakePerk(const char* name, long id);
DWORD _stdcall HasFakeTrait(const char* name);
void _stdcall ClearSelectablePerks();
void _stdcall ClearSelectablePerks();
void _stdcall SetPerkFreq(int i); void _stdcall SetPerkFreq(int i);
} }
@@ -24,6 +24,7 @@
#include "Interface.h" #include "Interface.h"
#include "Misc.h" #include "Misc.h"
#include "Objects.h" #include "Objects.h"
#include "Perks.h"
#include "Utils.h" #include "Utils.h"
#include "Worldmap.h" #include "Worldmap.h"
@@ -83,6 +84,8 @@ static const SfallMetarule metarules[] = {
{"get_object_data", sf_get_object_data, 2, 2, {ARG_OBJECT, ARG_INT}}, {"get_object_data", sf_get_object_data, 2, 2, {ARG_OBJECT, ARG_INT}},
{"get_outline", sf_get_outline, 1, 1, {ARG_OBJECT}}, {"get_outline", sf_get_outline, 1, 1, {ARG_OBJECT}},
{"get_string_pointer", sf_get_string_pointer, 1, 1, {ARG_STRING}}, {"get_string_pointer", sf_get_string_pointer, 1, 1, {ARG_STRING}},
{"has_fake_perk_npc", sf_has_fake_perk_npc, 2, 2, {ARG_OBJECT, ARG_STRING}},
{"has_fake_trait_npc", sf_has_fake_trait_npc, 2, 2, {ARG_OBJECT, ARG_STRING}},
{"intface_hide", sf_intface_hide, 0, 0}, {"intface_hide", sf_intface_hide, 0, 0},
{"intface_is_hidden", sf_intface_is_hidden, 0, 0}, {"intface_is_hidden", sf_intface_is_hidden, 0, 0},
{"intface_redraw", sf_intface_redraw, 0, 0}, {"intface_redraw", sf_intface_redraw, 0, 0},
@@ -101,6 +104,8 @@ static const SfallMetarule metarules[] = {
{"set_cursor_mode", sf_set_cursor_mode, 1, 1, {ARG_INT}}, {"set_cursor_mode", sf_set_cursor_mode, 1, 1, {ARG_INT}},
{"set_drugs_data", sf_set_drugs_data, 3, 3, {ARG_INT, ARG_INT, ARG_INT}}, {"set_drugs_data", sf_set_drugs_data, 3, 3, {ARG_INT, ARG_INT, ARG_INT}},
{"set_dude_obj", sf_set_dude_obj, 1, 1, {ARG_OBJECT}}, {"set_dude_obj", sf_set_dude_obj, 1, 1, {ARG_OBJECT}},
{"set_fake_perk_npc", sf_set_fake_perk_npc, 5, 5, {ARG_OBJECT, ARG_STRING, ARG_INT, ARG_INT, ARG_STRING}},
{"set_fake_trait_npc", sf_set_fake_trait_npc, 5, 5, {ARG_OBJECT, ARG_STRING, ARG_INT, ARG_INT, ARG_STRING}},
{"set_flags", sf_set_flags, 2, 2, {ARG_OBJECT, ARG_INT}}, {"set_flags", sf_set_flags, 2, 2, {ARG_OBJECT, ARG_INT}},
{"set_iface_tag_text", sf_set_iface_tag_text, 3, 3, {ARG_INT, ARG_STRING, ARG_INT}}, {"set_iface_tag_text", sf_set_iface_tag_text, 3, 3, {ARG_INT, ARG_STRING, ARG_INT}},
{"set_ini_setting", sf_set_ini_setting, 2, 2, {ARG_STRING, ARG_INTSTR}}, {"set_ini_setting", sf_set_ini_setting, 2, 2, {ARG_STRING, ARG_INTSTR}},
@@ -109,6 +114,7 @@ static const SfallMetarule metarules[] = {
{"set_outline", sf_set_outline, 2, 2, {ARG_OBJECT, ARG_INT}}, {"set_outline", sf_set_outline, 2, 2, {ARG_OBJECT, ARG_INT}},
{"set_rest_heal_time", sf_set_rest_heal_time, 1, 1, {ARG_INT}}, {"set_rest_heal_time", sf_set_rest_heal_time, 1, 1, {ARG_INT}},
{"set_rest_mode", sf_set_rest_mode, 1, 1, {ARG_INT}}, {"set_rest_mode", sf_set_rest_mode, 1, 1, {ARG_INT}},
{"set_selectable_perk_npc", sf_set_selectable_perk_npc, 5, 5, {ARG_OBJECT, ARG_STRING, ARG_INT, ARG_INT, ARG_STRING}},
{"set_unique_id", sf_set_unique_id, 1, 2, {ARG_OBJECT, ARG_INT}}, {"set_unique_id", sf_set_unique_id, 1, 2, {ARG_OBJECT, ARG_INT}},
{"set_unjam_locks_time", sf_set_unjam_locks_time, 1, 1, {ARG_INT}}, {"set_unjam_locks_time", sf_set_unjam_locks_time, 1, 1, {ARG_INT}},
{"spatial_radius", sf_spatial_radius, 1, 1, {ARG_OBJECT}}, {"spatial_radius", sf_spatial_radius, 1, 1, {ARG_OBJECT}},
+65 -254
View File
@@ -27,7 +27,6 @@ namespace sfall
{ {
namespace script namespace script
{ {
using namespace fo;
void __declspec(naked) op_get_perk_owed() { void __declspec(naked) op_get_perk_owed() {
__asm { __asm {
@@ -183,218 +182,44 @@ end:
} }
} }
void __declspec(naked) op_set_selectable_perk() { void sf_set_selectable_perk(OpcodeContext& ctx) {
__asm { Perks::SetSelectablePerk(ctx.arg(0).strValue(), ctx.arg(1).rawValue(), ctx.arg(2).rawValue(), ctx.arg(3).strValue());
pushad; }
mov ecx, eax;
call fo::funcoffs::interpretPopShort_;
push eax;
mov eax, ecx;
call fo::funcoffs::interpretPopLong_;
push eax;
mov eax, ecx;
call fo::funcoffs::interpretPopShort_;
push eax;
mov eax, ecx;
call fo::funcoffs::interpretPopLong_;
push eax;
mov eax, ecx;
call fo::funcoffs::interpretPopShort_;
push eax;
mov eax, ecx;
call fo::funcoffs::interpretPopLong_;
push eax;
mov eax, ecx;
call fo::funcoffs::interpretPopShort_;
push eax;
mov eax, ecx;
call fo::funcoffs::interpretPopLong_;
push eax;
movzx eax, word ptr[esp + 12]; void sf_set_fake_perk(OpcodeContext& ctx) {
cmp eax, VAR_TYPE_INT; Perks::SetFakePerk(ctx.arg(0).strValue(), ctx.arg(1).rawValue(), ctx.arg(2).rawValue(), ctx.arg(3).strValue());
jne fail; }
movzx eax, word ptr[esp + 20];
cmp eax, VAR_TYPE_INT;
jne fail;
movzx eax, word ptr ds:[esp + 4];
cmp eax, VAR_TYPE_STR2;
je next1;
cmp eax, VAR_TYPE_STR;
jne fail;
next1:
movzx eax, word ptr ds:[esp + 28];
cmp eax, VAR_TYPE_STR2;
je next2;
cmp eax, VAR_TYPE_STR;
jne fail;
next2:
mov eax, ecx;
mov edx, [esp + 28];
mov ebx, [esp + 24];
call fo::funcoffs::interpretGetString_;
push eax;
mov eax, [esp + 20];
push eax;
mov eax, [esp + 16];
push eax;
mov eax, ecx;
mov edx, [esp + 16];
mov ebx, [esp + 12];
call fo::funcoffs::interpretGetString_;
push eax;
call SetSelectablePerk; void sf_set_fake_trait(OpcodeContext& ctx) {
fail: Perks::SetFakeTrait(ctx.arg(0).strValue(), ctx.arg(1).rawValue(), ctx.arg(2).rawValue(), ctx.arg(3).strValue());
add esp, 32; }
popad;
retn; const char* notPartyMemberErr = "%s() - the object is not a party member.";
void sf_set_selectable_perk_npc(OpcodeContext& ctx) {
auto obj = ctx.arg(0).asObject();
if (obj->Type() == fo::ObjType::OBJ_TYPE_CRITTER && fo::func::isPartyMember(obj)) {
Perks::SetSelectablePerk(ctx.arg(1).strValue(), ctx.arg(2).rawValue(), ctx.arg(3).rawValue(), ctx.arg(4).strValue(), (obj->id != PLAYER_ID) ? obj->id : 0);
} else {
ctx.printOpcodeError(notPartyMemberErr, ctx.getMetaruleName());
} }
} }
void __declspec(naked) op_set_fake_perk() { void sf_set_fake_perk_npc(OpcodeContext& ctx) {
__asm { auto obj = ctx.arg(0).asObject();
pushad; if (obj->Type() == fo::ObjType::OBJ_TYPE_CRITTER && fo::func::isPartyMember(obj)) {
mov ecx, eax; Perks::SetFakePerk(ctx.arg(1).strValue(), ctx.arg(2).rawValue(), ctx.arg(3).rawValue(), ctx.arg(4).strValue(), (obj->id != PLAYER_ID) ? obj->id : 0);
call fo::funcoffs::interpretPopShort_; } else {
push eax; ctx.printOpcodeError(notPartyMemberErr, ctx.getMetaruleName());
mov eax, ecx;
call fo::funcoffs::interpretPopLong_;
push eax;
mov eax, ecx;
call fo::funcoffs::interpretPopShort_;
push eax;
mov eax, ecx;
call fo::funcoffs::interpretPopLong_;
push eax;
mov eax, ecx;
call fo::funcoffs::interpretPopShort_;
push eax;
mov eax, ecx;
call fo::funcoffs::interpretPopLong_;
push eax;
mov eax, ecx;
call fo::funcoffs::interpretPopShort_;
push eax;
mov eax, ecx;
call fo::funcoffs::interpretPopLong_;
push eax;
movzx eax, word ptr[esp + 12];
cmp eax, VAR_TYPE_INT;
jne fail;
movzx eax, word ptr[esp + 20];
cmp eax, VAR_TYPE_INT;
jne fail;
movzx eax, word ptr ds:[esp + 4];
cmp eax, VAR_TYPE_STR2;
je next1;
cmp eax, VAR_TYPE_STR;
jne fail;
next1:
movzx eax, word ptr ds:[esp + 28];
cmp eax, VAR_TYPE_STR2;
je next2;
cmp eax, VAR_TYPE_STR;
jne fail;
next2:
mov eax, ecx;
mov edx, [esp + 28];
mov ebx, [esp + 24];
call fo::funcoffs::interpretGetString_;
push eax;
mov eax, [esp + 20];
push eax;
mov eax, [esp + 16];
push eax;
mov eax, ecx;
mov edx, [esp + 16];
mov ebx, [esp + 12];
call fo::funcoffs::interpretGetString_;
push eax;
call SetFakePerk;
fail:
add esp, 32;
popad;
retn;
} }
} }
void __declspec(naked) op_set_fake_trait() { void sf_set_fake_trait_npc(OpcodeContext& ctx) {
__asm { auto obj = ctx.arg(0).asObject();
push ebx; if (obj->Type() == fo::ObjType::OBJ_TYPE_CRITTER && fo::func::isPartyMember(obj)) {
push ecx; Perks::SetFakeTrait(ctx.arg(1).strValue(), ctx.arg(2).rawValue(), ctx.arg(3).rawValue(), ctx.arg(4).strValue(), (obj->id != PLAYER_ID) ? obj->id : 0);
push edx; } else {
push edi; ctx.printOpcodeError(notPartyMemberErr, ctx.getMetaruleName());
push esi;
mov ecx, eax;
call fo::funcoffs::interpretPopShort_;
push eax;
mov eax, ecx;
call fo::funcoffs::interpretPopLong_;
push eax;
mov eax, ecx;
call fo::funcoffs::interpretPopShort_;
push eax;
mov eax, ecx;
call fo::funcoffs::interpretPopLong_;
push eax;
mov eax, ecx;
call fo::funcoffs::interpretPopShort_;
push eax;
mov eax, ecx;
call fo::funcoffs::interpretPopLong_;
push eax;
mov eax, ecx;
call fo::funcoffs::interpretPopShort_;
push eax;
mov eax, ecx;
call fo::funcoffs::interpretPopLong_;
push eax;
movzx eax, word ptr[esp + 12];
cmp eax, VAR_TYPE_INT;
jne fail;
movzx eax, word ptr[esp + 20];
cmp eax, VAR_TYPE_INT;
jne fail;
movzx eax, word ptr ds:[esp + 4];
cmp eax, VAR_TYPE_STR2;
je next1;
cmp eax, VAR_TYPE_STR;
jne fail;
next1:
movzx eax, word ptr ds:[esp + 28];
cmp eax, VAR_TYPE_STR2;
je next2;
cmp eax, VAR_TYPE_STR;
jne fail;
next2:
mov eax, ecx;
mov edx, [esp + 28];
mov ebx, [esp + 24];
call fo::funcoffs::interpretGetString_;
push eax;
mov eax, [esp + 20];
push eax;
mov eax, [esp + 16];
push eax;
mov eax, ecx;
mov edx, [esp + 16];
mov ebx, [esp + 12];
call fo::funcoffs::interpretGetString_;
push eax;
call SetFakeTrait;
fail:
add esp, 32;
pop esi;
pop edi;
pop edx;
pop ecx;
pop ebx;
retn;
} }
} }
@@ -402,28 +227,24 @@ void __declspec(naked) op_set_perkbox_title() {
__asm { __asm {
push ebx; push ebx;
push ecx; push ecx;
push edx; mov ecx, eax;
push edi;
mov edi, eax;
call fo::funcoffs::interpretPopShort_; call fo::funcoffs::interpretPopShort_;
mov edx, eax; mov edx, eax;
mov eax, edi; mov eax, ecx;
call fo::funcoffs::interpretPopLong_; call fo::funcoffs::interpretPopLong_;
cmp dx, VAR_TYPE_STR2; cmp dx, VAR_TYPE_STR2;
jz next; jz next;
cmp dx, VAR_TYPE_STR; cmp dx, VAR_TYPE_STR;
jnz end; jnz end;
next: next:
mov ebx, eax; mov ebx, eax;
mov eax, edi; mov eax, ecx;
call fo::funcoffs::interpretGetString_; call fo::funcoffs::interpretGetString_;
push eax; push eax;
call SetPerkboxTitle; call SetPerkboxTitle;
end: end:
pop edi; pop ecx;
pop edx; pop ebx;
pop ecx;
pop ebx;
retn; retn;
} }
} }
@@ -456,43 +277,33 @@ void __declspec(naked) op_clear_selectable_perks() {
} }
void sf_has_fake_perk(OpcodeContext& ctx) { void sf_has_fake_perk(OpcodeContext& ctx) {
ctx.setReturn(HasFakePerk(ctx.arg(0).asString(), ctx.arg(0).asInt())); ctx.setReturn(Perks::HasFakePerk(ctx.arg(0).asString(), ctx.arg(0).asInt()));
} }
void __declspec(naked) op_has_fake_trait() { void sf_has_fake_trait(OpcodeContext& ctx) {
__asm { ctx.setReturn(Perks::HasFakeTrait(ctx.arg(0).strValue()));
push ebx; }
push ecx;
push edx; void sf_has_fake_perk_npc(OpcodeContext& ctx) {
push edi; long result = 0;
mov edi, eax; auto obj = ctx.arg(0).asObject();
call fo::funcoffs::interpretPopShort_; if (obj->Type() == fo::ObjType::OBJ_TYPE_CRITTER && fo::func::isPartyMember(obj)) {
mov edx, eax; result = Perks::HasFakePerkOwner(ctx.arg(1).strValue(), (obj->id != PLAYER_ID) ? obj->id : 0);
mov eax, edi; } else {
call fo::funcoffs::interpretPopLong_; ctx.printOpcodeError(notPartyMemberErr, ctx.getMetaruleName());
cmp dx, VAR_TYPE_STR2;
jz next;
cmp dx, VAR_TYPE_STR;
jnz end;
next:
mov ebx, eax;
mov eax, edi;
call fo::funcoffs::interpretGetString_;
push eax;
call HasFakeTrait;
end:
mov edx, eax;
mov eax, edi;
call fo::funcoffs::interpretPushLong_;
mov eax, edi;
mov edx, VAR_TYPE_INT;
call fo::funcoffs::interpretPushShort_;
pop edi;
pop edx;
pop ecx;
pop ebx;
retn;
} }
ctx.setReturn(result);
}
void sf_has_fake_trait_npc(OpcodeContext& ctx) {
long result = 0;
auto obj = ctx.arg(0).asObject();
if (obj->Type() == fo::ObjType::OBJ_TYPE_CRITTER && fo::func::isPartyMember(obj)) {
result = Perks::HasFakeTraitOwner(ctx.arg(1).strValue(), (obj->id != PLAYER_ID) ? obj->id : 0);
} else {
ctx.printOpcodeError(notPartyMemberErr, ctx.getMetaruleName());
}
ctx.setReturn(result);
} }
void __declspec(naked) op_perk_add_mode() { void __declspec(naked) op_perk_add_mode() {
+14 -4
View File
@@ -37,11 +37,17 @@ void __declspec() op_set_perk_desc();
void __declspec() op_set_perk_value(); void __declspec() op_set_perk_value();
void __declspec() op_set_selectable_perk(); void sf_set_selectable_perk(OpcodeContext&);
void __declspec() op_set_fake_perk(); void sf_set_fake_perk(OpcodeContext&);
void __declspec() op_set_fake_trait(); void sf_set_fake_trait(OpcodeContext&);
void sf_set_selectable_perk_npc(OpcodeContext&);
void sf_set_fake_perk_npc(OpcodeContext&);
void sf_set_fake_trait_npc(OpcodeContext&);
void __declspec() op_set_perkbox_title(); void __declspec() op_set_perkbox_title();
@@ -53,7 +59,11 @@ void __declspec() op_clear_selectable_perks();
void sf_has_fake_perk(OpcodeContext&); void sf_has_fake_perk(OpcodeContext&);
void __declspec() op_has_fake_trait(); void sf_has_fake_trait(OpcodeContext&);
void sf_has_fake_perk_npc(OpcodeContext&);
void sf_has_fake_trait_npc(OpcodeContext&);
void __declspec() op_perk_add_mode(); void __declspec() op_perk_add_mode();
+4 -4
View File
@@ -86,7 +86,11 @@ static SfallOpcodeInfo opcodeInfoArray[] = {
{0x1a5, "inc_npc_level", sf_inc_npc_level, 1, false, {ARG_INTSTR}}, {0x1a5, "inc_npc_level", sf_inc_npc_level, 1, false, {ARG_INTSTR}},
{0x1ac, "get_ini_setting", sf_get_ini_setting, 1, true, {ARG_STRING}}, {0x1ac, "get_ini_setting", sf_get_ini_setting, 1, true, {ARG_STRING}},
{0x1bb, "set_fake_perk", sf_set_fake_perk, 4, false, {ARG_STRING, ARG_INT, ARG_INT, ARG_STRING}},
{0x1bc, "set_fake_trait", sf_set_fake_trait, 4, false, {ARG_STRING, ARG_INT, ARG_INT, ARG_STRING}},
{0x1bd, "set_selectable_perk", sf_set_selectable_perk, 4, false, {ARG_STRING, ARG_INT, ARG_INT, ARG_STRING}},
{0x1c1, "has_fake_perk", sf_has_fake_perk, 1, true, {ARG_INTSTR}}, {0x1c1, "has_fake_perk", sf_has_fake_perk, 1, true, {ARG_INTSTR}},
{0x1c2, "has_fake_trait", sf_has_fake_trait, 1, true, {ARG_STRING}},
{0x1dc, "show_iface_tag", sf_show_iface_tag, 1, false, {ARG_INT}}, {0x1dc, "show_iface_tag", sf_show_iface_tag, 1, false, {ARG_INT}},
{0x1dd, "hide_iface_tag", sf_hide_iface_tag, 1, false, {ARG_INT}}, {0x1dd, "hide_iface_tag", sf_hide_iface_tag, 1, false, {ARG_INT}},
@@ -330,13 +334,9 @@ void InitNewOpcodes() {
opcodes[0x1b8] = op_set_pc_stat_min; opcodes[0x1b8] = op_set_pc_stat_min;
opcodes[0x1b9] = op_set_npc_stat_max; opcodes[0x1b9] = op_set_npc_stat_max;
opcodes[0x1ba] = op_set_npc_stat_min; opcodes[0x1ba] = op_set_npc_stat_min;
opcodes[0x1bb] = op_set_fake_perk;
opcodes[0x1bc] = op_set_fake_trait;
opcodes[0x1bd] = op_set_selectable_perk;
opcodes[0x1be] = op_set_perkbox_title; opcodes[0x1be] = op_set_perkbox_title;
opcodes[0x1bf] = op_hide_real_perks; opcodes[0x1bf] = op_hide_real_perks;
opcodes[0x1c0] = op_show_real_perks; opcodes[0x1c0] = op_show_real_perks;
opcodes[0x1c2] = op_has_fake_trait;
opcodes[0x1c3] = op_perk_add_mode; opcodes[0x1c3] = op_perk_add_mode;
opcodes[0x1c4] = op_clear_selectable_perks; opcodes[0x1c4] = op_clear_selectable_perks;
opcodes[0x1c5] = op_set_critter_hit_chance_mod; opcodes[0x1c5] = op_set_critter_hit_chance_mod;