mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Further implementation of unique ID.
* weapons with knockback modifiers applied will have a special ID (negative value) that work as a temporary UID for the current game session. Added checks on object types to functions in Combat module. Added the second argument to set_unique_id script function.
This commit is contained in:
@@ -579,10 +579,13 @@ Some utility/math functions are available:
|
||||
1 - changes the duration of the addiction effect for the drug (a value of 1 = one game minute)
|
||||
|
||||
> int sfall_func1("set_unique_id", object)
|
||||
- assigns an unique ID number to the object and returns it. If an unique ID number has already been assigned to an object, then ID number is returned without reassignment
|
||||
> int sfall_func2("set_unique_id", object, int flag)
|
||||
- assigns a unique ID number to the object and returns it. If a unique ID number has already been assigned to an object, then ID number is returned without reassignment
|
||||
- items with unique IDs will not stack with other items of the same type in the inventory
|
||||
- to just get the current ID number of an object, use sfall_func2("get_object_data", object, OBJ_DATA_ID)
|
||||
- unique ID numbers are saved in your savegame, and have a range from 0x10000000 to 0x7FFFFFFF
|
||||
- there is also an unique ID number range for the player and party members from 18000 to 83535
|
||||
- there is also a unique ID number range for the player and party members from 18000 to 83535
|
||||
- to assign a new ID number generated by the engine to the object (i.e. unassign a unique ID), call the function with two arguments and pass -1 for the flag argument
|
||||
|
||||
------------------------
|
||||
------ MORE INFO -------
|
||||
|
||||
+16
-17
@@ -32,15 +32,9 @@ namespace sfall
|
||||
|
||||
static std::vector<long> noBursts; // object id
|
||||
|
||||
struct KnockbackModifier {
|
||||
long id;
|
||||
DWORD type;
|
||||
double value;
|
||||
};
|
||||
|
||||
static std::vector<KnockbackModifier> mTargets;
|
||||
static std::vector<KnockbackModifier> mAttackers;
|
||||
static std::vector<KnockbackModifier> mWeapons;
|
||||
std::vector<KnockbackModifier> Combat::mWeapons;
|
||||
|
||||
static std::vector<ChanceModifier> hitChanceMods;
|
||||
static ChanceModifier baseHitChance;
|
||||
@@ -168,7 +162,7 @@ static double ApplyModifiers(std::vector<KnockbackModifier>* mods, fo::GameObjec
|
||||
|
||||
static DWORD __fastcall CalcKnockbackMod(int knockValue, int damage, fo::GameObject* weapon, fo::GameObject* attacker, fo::GameObject* target) {
|
||||
double result = (double)damage / (double)knockValue;
|
||||
result = ApplyModifiers(&mWeapons, weapon, result);
|
||||
result = ApplyModifiers(&Combat::mWeapons, weapon, result);
|
||||
result = ApplyModifiers(&mAttackers, attacker, result);
|
||||
result = ApplyModifiers(&mTargets, target, result);
|
||||
return (DWORD)floor(result);
|
||||
@@ -250,19 +244,25 @@ void _stdcall KnockbackSetMod(fo::GameObject* object, DWORD type, float val, DWO
|
||||
std::vector<KnockbackModifier>* mods;
|
||||
switch (on) {
|
||||
case 0:
|
||||
mods = &mWeapons;
|
||||
if (object->Type() != fo::OBJ_TYPE_ITEM) return;
|
||||
mods = &Combat::mWeapons;
|
||||
break;
|
||||
case 1:
|
||||
if (object->Type() != fo::OBJ_TYPE_CRITTER) return;
|
||||
mods = &mTargets;
|
||||
break;
|
||||
case 2:
|
||||
if (object->Type() != fo::OBJ_TYPE_CRITTER) return;
|
||||
mods = &mAttackers;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
long id = Objects::SetObjectUniqueID(object);
|
||||
long id = (on == 0)
|
||||
? Objects::SetSpecialID(object)
|
||||
: Objects::SetObjectUniqueID(object);
|
||||
|
||||
KnockbackModifier mod = { id, type, (double)val };
|
||||
for (DWORD i = 0; i < mods->size(); i++) {
|
||||
if ((*mods)[i].id == id) {
|
||||
@@ -275,11 +275,9 @@ void _stdcall KnockbackSetMod(fo::GameObject* object, DWORD type, float val, DWO
|
||||
|
||||
void _stdcall KnockbackRemoveMod(fo::GameObject* object, DWORD on) {
|
||||
std::vector<KnockbackModifier>* mods;
|
||||
int id = object->id;
|
||||
switch (on) {
|
||||
case 0:
|
||||
object->id = fo::func::new_obj_id(); // revert to engine range id
|
||||
mods = &mWeapons;
|
||||
mods = &Combat::mWeapons;
|
||||
break;
|
||||
case 1:
|
||||
mods = &mTargets;
|
||||
@@ -291,8 +289,9 @@ void _stdcall KnockbackRemoveMod(fo::GameObject* object, DWORD on) {
|
||||
return;
|
||||
}
|
||||
for (DWORD i = 0; i < mods->size(); i++) {
|
||||
if ((*mods)[i].id == id) {
|
||||
if ((*mods)[i].id == object->id) {
|
||||
mods->erase(mods->begin() + i);
|
||||
if (on == 0) Objects::SetNewEngineID(object); // revert to engine range id
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -304,7 +303,7 @@ void _stdcall SetHitChanceMax(fo::GameObject* critter, DWORD maximum, DWORD mod)
|
||||
baseHitChance.mod = mod;
|
||||
return;
|
||||
}
|
||||
|
||||
if (critter->Type() != fo::OBJ_TYPE_CRITTER) return;
|
||||
long id = Objects::SetObjectUniqueID(critter);
|
||||
for (DWORD i = 0; i < hitChanceMods.size(); i++) {
|
||||
if (id == hitChanceMods[i].id) {
|
||||
@@ -317,7 +316,7 @@ void _stdcall SetHitChanceMax(fo::GameObject* critter, DWORD maximum, DWORD mod)
|
||||
}
|
||||
|
||||
void _stdcall SetNoBurstMode(fo::GameObject* critter, bool on) {
|
||||
if (critter == fo::var::obj_dude) return;
|
||||
if (critter == fo::var::obj_dude || critter->Type() != fo::OBJ_TYPE_CRITTER) return;
|
||||
|
||||
long id = Objects::SetObjectUniqueID(critter);
|
||||
for (size_t i = 0; i < noBursts.size(); i++) {
|
||||
@@ -393,7 +392,7 @@ static void Combat_OnGameLoad() {
|
||||
baseHitChance.SetDefault();
|
||||
mTargets.clear();
|
||||
mAttackers.clear();
|
||||
mWeapons.clear();
|
||||
Combat::mWeapons.clear();
|
||||
hitChanceMods.clear();
|
||||
noBursts.clear();
|
||||
disabledAS.clear();
|
||||
|
||||
@@ -23,10 +23,18 @@
|
||||
namespace sfall
|
||||
{
|
||||
|
||||
struct KnockbackModifier {
|
||||
long id;
|
||||
DWORD type;
|
||||
double value;
|
||||
};
|
||||
|
||||
class Combat : public Module {
|
||||
public:
|
||||
const char* name() { return "Combat"; }
|
||||
void init();
|
||||
|
||||
static std::vector<KnockbackModifier> mWeapons;
|
||||
};
|
||||
|
||||
struct ChanceModifier {
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "..\main.h"
|
||||
#include "..\FalloutEngine\Fallout2.h"
|
||||
#include "Combat.h"
|
||||
#include "LoadGameHook.h"
|
||||
|
||||
#include "Objects.h"
|
||||
@@ -28,7 +29,7 @@ namespace sfall
|
||||
static int unjamTimeState;
|
||||
static int maxCountProto = 512;
|
||||
|
||||
long Objects::uniqueID = UniqueID::Start; // saving to sfallgv.sav
|
||||
long Objects::uniqueID = UniqueID::Start; // current counter id, saving to sfallgv.sav
|
||||
|
||||
// Assigns a new unique identifier to an object if it has not been previously assigned
|
||||
// the identifier is saved with the object in the saved game and this can used in various script
|
||||
@@ -42,6 +43,46 @@ long Objects::SetObjectUniqueID(fo::GameObject* obj) {
|
||||
return uniqueID;
|
||||
}
|
||||
|
||||
// Assigns a unique ID in the negative range (0x8FFFFFFF - 0xFFFFFFFE)
|
||||
long Objects::SetSpecialID(fo::GameObject* obj) {
|
||||
long id = obj->id;
|
||||
if (id < -1 || id > UniqueID::Start) return id;
|
||||
|
||||
if ((DWORD)uniqueID >= UniqueID::End) uniqueID = UniqueID::Start;
|
||||
id = ++uniqueID + UniqueID::End;
|
||||
obj->id = id;
|
||||
return id;
|
||||
}
|
||||
|
||||
void Objects::SetNewEngineID(fo::GameObject* obj) {
|
||||
if (obj->id > UniqueID::Start) return;
|
||||
obj->id = fo::func::new_obj_id();
|
||||
}
|
||||
|
||||
static bool __fastcall CheckSpecialID(long id) {
|
||||
if (Combat::mWeapons.empty()) return false;
|
||||
for (auto& weapon : Combat::mWeapons) {
|
||||
if (id == weapon.id) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void __declspec(naked) item_identical_hack() {
|
||||
using namespace fo::Fields;
|
||||
__asm {
|
||||
mov ecx, [edi]; // item id
|
||||
cmp ecx, Start; // start unique ID
|
||||
jg notIdentical;
|
||||
call CheckSpecialID;
|
||||
test al, al;
|
||||
jnz notIdentical;
|
||||
mov eax, [esi + scriptId];
|
||||
cmp eax, ebx;
|
||||
notIdentical:
|
||||
retn; // if ZF == 0 then item is not identical
|
||||
}
|
||||
}
|
||||
|
||||
static void __declspec(naked) new_obj_id_hook() {
|
||||
__asm {
|
||||
mov eax, 83535;
|
||||
@@ -119,6 +160,10 @@ void Objects::init() {
|
||||
|
||||
HookCall(0x4A38A5, new_obj_id_hook);
|
||||
SafeWrite8(0x4A38B3, 0x90); // fix ID increment
|
||||
|
||||
//if (GetConfigInt("Misc", "StackableUniqueItems", 0) == 0) {
|
||||
MakeCall(0x477A0E, item_identical_hack); // don't put to item stack
|
||||
//}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@ public:
|
||||
static long uniqueID;
|
||||
|
||||
static long SetObjectUniqueID(fo::GameObject* obj);
|
||||
static long SetSpecialID(fo::GameObject* obj);
|
||||
static void SetNewEngineID(fo::GameObject* obj);
|
||||
|
||||
static void SetAutoUnjamLockTime(DWORD time);
|
||||
static void LoadProtoAutoMaxLimit();
|
||||
};
|
||||
|
||||
@@ -127,7 +127,7 @@ static const SfallMetarule metarules[] = {
|
||||
{"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_mode", sf_set_rest_mode, 1, 1, {ARG_INT}},
|
||||
{"set_unique_id", sf_set_unique_id, 1, 1, {ARG_OBJECT}},
|
||||
{"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}},
|
||||
{"spatial_radius", sf_spatial_radius, 1, 1, {ARG_OBJECT}},
|
||||
{"tile_refresh_display", sf_tile_refresh_display, 0, 0},
|
||||
|
||||
@@ -520,7 +520,15 @@ void sf_set_drugs_data(OpcodeContext& ctx) {
|
||||
}
|
||||
|
||||
void sf_set_unique_id(OpcodeContext& ctx) {
|
||||
ctx.setReturn(Objects::SetObjectUniqueID(ctx.arg(0).asObject()));
|
||||
fo::GameObject* obj = ctx.arg(0).asObject();
|
||||
long id;
|
||||
if (ctx.arg(1).asInt() == -1) {
|
||||
id = fo::func::new_obj_id();
|
||||
obj->id = id;
|
||||
} else {
|
||||
id = Objects::SetObjectUniqueID(obj);
|
||||
}
|
||||
ctx.setReturn(id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user