Backported "item_make_explosive" script function

Updated documents for the function.
Removed deprecated "register" keyword.
This commit is contained in:
NovaRain
2023-03-10 21:08:05 +08:00
parent 13445a1b83
commit 736c2cb6fe
10 changed files with 214 additions and 7 deletions
+1
View File
@@ -348,6 +348,7 @@
#define intface_redraw sfall_func0("intface_redraw")
#define intface_show sfall_func0("intface_show")
#define inventory_redraw(invSide) sfall_func1("inventory_redraw", invSide)
#define item_make_explosive(pid, activePid, min, max) sfall_func4("item_make_explosive", pid, activePid, min, max)
#define item_weight(obj) sfall_func1("item_weight", obj)
#define lock_is_jammed(obj) sfall_func1("lock_is_jammed", obj)
#define loot_obj sfall_func0("loot_obj")
+12 -1
View File
@@ -286,7 +286,7 @@ FUNCTION REFERENCE
-----
##### `array get_explosion_damage(itemPid)`
- Returns an array of the minimum and maximum damage of Dynamite or Plastic Explosives.
- Returns an array of the minimum and maximum damage of the explosive item.
-----
##### `void set_dynamite_damage(minDmg, maxDmg)`
@@ -682,6 +682,17 @@ sfall_funcX metarule functions
- Redraws inventory list in the inventory/use inventory item on/loot/barter screens
- `invSide` specifies which side needs to be redrawn: 0 - the player, 1 - target (container/NPC in loot/barter screens), -1 - both sides (same as without argument)
----
#### item_make_explosive
`void sfall_func3("item_make_explosive", int pid, int activePid, int damage)`\
`void sfall_func4("item_make_explosive", int pid, int activePid, int min, int max)`
- Makes the specified item (pid) an explosive item like Dynamite or Plastic Explosives
- `activePid` is for an item with an active timer, can be the same as the `pid` argument
- The item proto must be the **Misc Item** type and have the **Use** action flag
- `min` and `max` are the minimum and maximum explosion damage
- Using the function on an item that is already set as an explosive will override its previous settings
- __NOTE:__ this function does not work for pid's of Dynamite and Plastic Explosives
----
#### get_string_pointer
`int sfall_func1("get_string_pointer", string text)`
+171
View File
@@ -16,6 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <vector>
#include "..\main.h"
#include "..\FalloutEngine\Fallout2.h"
@@ -31,6 +33,15 @@ namespace sfall
using namespace fo::Fields;
struct explosiveInfo {
DWORD pid;
DWORD pidActive;
DWORD minDamage;
DWORD maxDamage;
};
std::vector<explosiveInfo> explosives;
static bool lightingEnabled = false;
static bool explosionsMetaruleReset = false;
static bool explosionsDamageReset = false;
@@ -152,6 +163,162 @@ static void __declspec(naked) fire_dance_lighting_fix1() {
}
}
////////////////////////////////////////////////////////////////////////////////
static DWORD __fastcall CheckExplosives(DWORD pid) {
for (std::vector<explosiveInfo>::const_iterator it = explosives.begin(); it != explosives.end(); ++it) {
if (it->pid == pid) return it->pidActive;
}
return 0;
}
static DWORD __fastcall CheckActiveExplosives(DWORD pid) {
for (std::vector<explosiveInfo>::const_iterator it = explosives.begin(); it != explosives.end(); ++it) {
if (it->pidActive == pid) return 0;
}
return 1;
}
static DWORD __fastcall GetDamage(DWORD pid, DWORD &min, DWORD &max) {
DWORD result = 0;
for (std::vector<explosiveInfo>::const_iterator it = explosives.begin(); it != explosives.end(); ++it) {
if (it->pidActive == pid) {
min = it->minDamage;
max = it->maxDamage;
result = 1;
break;
}
}
return result;
}
static DWORD __fastcall SetQueueExplosionDamage(DWORD pid) {
DWORD min, max;
DWORD result = GetDamage(pid, min, max);
if (result) {
__asm mov edx, min;
__asm mov ecx, max;
}
return result;
}
static void __declspec(naked) obj_use_explosive_hack() {
using namespace fo;
__asm {
cmp edx, PID_PLASTIC_EXPLOSIVES;
jz end;
// end engine code
push edx;
mov ecx, edx;
call CheckExplosives;
pop edx;
test eax, eax;
jnz end;
retn;
end:
mov dword ptr [esp], 0x49BCE0;
retn;
}
}
static void __declspec(naked) obj_use_explosive_active_hack() {
using namespace fo;
__asm {
cmp eax, PID_PLASTIC_EXPLOSIVES;
jz end;
// end engine code
mov ecx, eax;
call CheckExplosives;
test eax, eax;
jz skipSet;
mov dword ptr [esi + protoId], eax; // change item pid to active;
skipSet:
mov dword ptr [esp], 0x49BD62;
end:
retn;
}
}
static void __declspec(naked) queue_do_explosion_hack() {
using namespace fo;
__asm {
cmp edx, PID_ACTIVE_DYNAMITE;
jz dynamite;
cmp edx, PID_ACTIVE_PLASTIC_EXPLOSIVE;
jz end;
push edx;
mov ecx, edx;
call SetQueueExplosionDamage;
test eax, eax;
mov ebx, edx;
pop edx;
jz end;
mov dword ptr [esp], 0x4A2888;
end:
retn;
dynamite:
mov dword ptr [esp], 0x4A2872;
retn;
}
}
static void __declspec(naked) inven_action_cursor_drop_hack() {
using namespace fo;
__asm {
cmp ebx, PID_ACTIVE_PLASTIC_EXPLOSIVE;
jz end;
// end engine code
push eax;
mov ecx, ebx;
call CheckActiveExplosives;
test eax, eax; // check in engine
pop eax;
end:
retn;
}
}
static void __declspec(naked) protinstTestDroppedExplosive_hack() {
__asm {
jz end;
mov ecx, edx;
call CheckActiveExplosives;
test eax, eax;
jz end;
mov dword ptr [esp], 0x49C112; // exit, no active explosive item
end:
retn;
}
}
static void apply_expl_hack() {
MakeCall(0x49BCC7, obj_use_explosive_hack); // check explosives
MakeCall(0x49BD56, obj_use_explosive_active_hack); // set active explosive
MakeCall(0x4A2865, queue_do_explosion_hack); // set damage explosive
MakeCall(0x4737F2, inven_action_cursor_drop_hack, 1); // check drop explosives
MakeCall(0x49C005, protinstTestDroppedExplosive_hack, 1); // check drop explosives
}
void Explosions::AddToExplosives(DWORD pid, DWORD activePid, DWORD minDmg, DWORD maxDmg) {
static bool onlyOnce = false;
for (unsigned int i = 0; i < explosives.size(); i++) {
if (explosives[i].pid == pid) {
explosives.erase(explosives.begin() + i);
break;
}
}
explosiveInfo expl = { pid, activePid, minDmg, maxDmg };
explosives.push_back(expl);
if (!onlyOnce) {
apply_expl_hack();
onlyOnce = true;
}
}
////////////////////////////////////////////////////////////////////////////////
static const DWORD explosion_dmg_check_adr[] = {0x411709, 0x4119FC, 0x411C08, 0x4517C1, 0x423BC8, 0x42381A};
static const DWORD explosion_art_adr[] = {0x411A19, 0x411A29, 0x411A35, 0x411A3C};
static const DWORD explosion_art_defaults[] = {10, 2, 31, 29};
@@ -203,6 +370,8 @@ static int GetExplosionDamage(int pid) {
min = *(DWORD*)plastic_min_dmg_addr;
max = *(DWORD*)plastic_max_dmg_addr;
break;
default:
GetDamage(pid, min, max);
}
DWORD arrayId = script::CreateTempArray(2, 0);
@@ -298,6 +467,8 @@ void ResetExplosionRadius() {
}
static void ResetExplosionDamage() {
explosives.clear();
if (!explosionsDamageReset) return;
SafeWrite32(dynamite_min_dmg_addr, dynamite_minDmg);
SafeWrite32(dynamite_max_dmg_addr, dynamite_maxDmg);
+2
View File
@@ -27,6 +27,8 @@ public:
static void init();
static void OnGameLoad();
static void AddToExplosives(DWORD pid, DWORD activePid, DWORD minDmg, DWORD maxDmg);
};
void ResetExplosionSettings();
+3 -3
View File
@@ -11,7 +11,7 @@ namespace sfall
{
// The hook is executed twice when entering the barter screen and after transaction: the first time is for the player; the second time is for NPC
static DWORD __fastcall BarterPriceHook_Script(register fo::GameObject* source, register fo::GameObject* target, DWORD callAddr) {
static DWORD __fastcall BarterPriceHook_Script(fo::GameObject* source, fo::GameObject* target, DWORD callAddr) {
bool barterIsParty = (*fo::ptr::dialog_target_is_party != 0);
long computeCost = fo::func::barter_compute_value(source, target);
@@ -100,7 +100,7 @@ void SourceUseSkillOnInit() { sourceSkillOn = *fo::ptr::obj_dude; }
static char resultSkillOn; // -1 - cancel handler, 1 - replace user
static long bakupCombatState;
static void __fastcall UseSkillOnHook_Script(DWORD source, DWORD target, register DWORD skillId) {
static void __fastcall UseSkillOnHook_Script(DWORD source, DWORD target, DWORD skillId) {
BeginHook();
argCount = 3;
@@ -389,7 +389,7 @@ static void __declspec(naked) CarTravelHack() {
}
}
static long __fastcall GlobalVarHook_Script(register DWORD number, register int value) {
static long __fastcall GlobalVarHook_Script(DWORD number, int value) {
int old = (*fo::ptr::game_global_vars)[number];
if (IsGameLoaded() && HookScripts::HookHasScript(HOOK_SETGLOBALVAR)) { // IsGameLoaded - don't execute hook until loading sfall scripts
+1 -1
View File
@@ -683,7 +683,7 @@ static void InterfaceWindowPatch() {
// Increase the max text width of the information card on the character screen
const DWORD drawCardAddr[] = {0x43ACD5, 0x43DD37}; // 136, 133 (DrawCard_, DrawCard2_)
SafeWriteBatch<BYTE>(145, drawCardAddr);
SafeWriteBatch<BYTE>(146, drawCardAddr);
// Increase the width of the mouse drop area from 64px to 80px for the PC's and NPC's inventory on the barter screen
// barter_move_from_table_inventory_
+1 -1
View File
@@ -42,7 +42,7 @@ static void __stdcall CombatLoop() { // OnCombatLoop
}
static void __stdcall AfterCombatAttack() { // OnAfterCombatAttack
ResetExplosionSettings();
ResetExplosionSettings(); // after each combat attack, reset metarule_explosions settings
}
static void __declspec(naked) MainGameLoopHook() {
@@ -109,6 +109,7 @@ static const SfallMetarule metarules[] = {
{"intface_redraw", mf_intface_redraw, 0, 1},
{"intface_show", mf_intface_show, 0, 0},
{"inventory_redraw", mf_inventory_redraw, 0, 1, -1, {ARG_INT}},
{"item_make_explosive", mf_item_make_explosive, 3, 4, -1, {ARG_INT, ARG_INT, ARG_INT, ARG_INT}},
{"item_weight", mf_item_weight, 1, 1, 0, {ARG_OBJECT}},
{"lock_is_jammed", mf_lock_is_jammed, 1, 1, 0, {ARG_OBJECT}},
{"loot_obj", mf_get_loot_object, 0, 0},
@@ -398,6 +398,25 @@ void mf_set_unjam_locks_time(OpcodeContext& ctx) {
}
}
void mf_item_make_explosive(OpcodeContext& ctx) {
DWORD pid = ctx.arg(0).rawValue();
DWORD pidActive = ctx.arg(1).rawValue();
DWORD min = ctx.arg(2).rawValue();
DWORD max = (ctx.numArgs() == 4) ? ctx.arg(3).rawValue() : min;
if (min > max) {
max = min;
ctx.printOpcodeError("%s() - Warning: value of max argument is less than the min argument.", ctx.getMetaruleName());
}
if (pid > 0 && pidActive > 0) {
Explosions::AddToExplosives(pid, pidActive, min, max);
} else {
ctx.printOpcodeError("%s() - invalid PID number, must be greater than 0.", ctx.getMetaruleName());
ctx.setReturn(-1);
}
}
void mf_get_dialog_object(OpcodeContext& ctx) {
ctx.setReturn(InDialog() ? *fo::ptr::dialog_target : 0);
}
@@ -79,6 +79,8 @@ void mf_unjam_lock(OpcodeContext&);
void mf_set_unjam_locks_time(OpcodeContext&);
void mf_item_make_explosive(OpcodeContext&);
void mf_get_dialog_object(OpcodeContext&);
void mf_obj_under_cursor(OpcodeContext&);