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:
NovaRain
2019-04-16 20:33:00 +08:00
parent e92b8021c0
commit 4cdc028cb7
7 changed files with 88 additions and 22 deletions
+5 -2
View File
@@ -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
View File
@@ -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();
+8
View File
@@ -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 {
+46 -1
View File
@@ -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
//}
}
}
+3
View File
@@ -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},
+9 -1
View File
@@ -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);
}
}