mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Backported "item_make_explosive" script function
Updated documents for the function. Removed deprecated "register" keyword.
This commit is contained in:
@@ -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")
|
||||
|
||||
@@ -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)`
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -27,6 +27,8 @@ public:
|
||||
static void init();
|
||||
|
||||
static void OnGameLoad();
|
||||
|
||||
static void AddToExplosives(DWORD pid, DWORD activePid, DWORD minDmg, DWORD maxDmg);
|
||||
};
|
||||
|
||||
void ResetExplosionSettings();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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&);
|
||||
|
||||
Reference in New Issue
Block a user