diff -urN sourceold/AntiSpawnKill/AntiSpawnKill.vcxproj source/AntiSpawnKill/AntiSpawnKill.vcxproj --- sourceold/AntiSpawnKill/AntiSpawnKill.vcxproj 2018-10-27 22:04:54.438400000 +1000 +++ source/AntiSpawnKill/AntiSpawnKill.vcxproj 2020-09-26 09:00:03.253003000 +1000 @@ -20,13 +20,13 @@ DynamicLibrary MultiByte false - v110_xp + v110 DynamicLibrary MultiByte true - v110_xp + v110 @@ -108,6 +108,7 @@ MachineX86 ..\bin\release SSGM;..\bin\release false + 6.01 if defined RenPath ( @@ -185,6 +186,7 @@ MachineX86 ..\bin\debug SSGM;..\bin\debug false + 6.01 if defined RenPath ( diff -urN sourceold/CTF/ctf.vcxproj source/CTF/ctf.vcxproj --- sourceold/CTF/ctf.vcxproj 2018-10-27 22:04:54.445400000 +1000 +++ source/CTF/ctf.vcxproj 2020-09-26 09:00:03.254025700 +1000 @@ -20,13 +20,13 @@ DynamicLibrary MultiByte false - v110_xp + v110 DynamicLibrary MultiByte true - v110_xp + v110 @@ -108,6 +108,7 @@ MachineX86 ..\bin\release SSGM;..\bin\release false + 6.01 if defined RenPath ( @@ -185,6 +186,7 @@ MachineX86 ..\bin\debug SSGM;..\bin\debug false + 6.01 if defined RenPath ( diff -urN sourceold/CharacterRefund/CharacterRefund.vcxproj source/CharacterRefund/CharacterRefund.vcxproj --- sourceold/CharacterRefund/CharacterRefund.vcxproj 2018-10-27 22:04:54.449400000 +1000 +++ source/CharacterRefund/CharacterRefund.vcxproj 2020-09-26 09:00:03.254025700 +1000 @@ -20,13 +20,13 @@ DynamicLibrary MultiByte false - v110_xp + v110 DynamicLibrary MultiByte true - v110_xp + v110 @@ -108,6 +108,7 @@ MachineX86 ..\bin\release SSGM;..\bin\release false + 6.01 if defined RenPath ( @@ -185,6 +186,7 @@ MachineX86 ..\bin\debug SSGM;..\bin\debug false + 6.01 if defined RenPath ( diff -urN sourceold/ExtraConsoleCommands/ExtraConsoleCommands.vcxproj source/ExtraConsoleCommands/ExtraConsoleCommands.vcxproj --- sourceold/ExtraConsoleCommands/ExtraConsoleCommands.vcxproj 2018-10-27 22:04:54.455400000 +1000 +++ source/ExtraConsoleCommands/ExtraConsoleCommands.vcxproj 2020-09-26 09:00:03.255035400 +1000 @@ -20,13 +20,13 @@ DynamicLibrary MultiByte false - v110_xp + v110 DynamicLibrary MultiByte true - v110_xp + v110 @@ -108,6 +108,7 @@ MachineX86 ..\bin\release SSGM;..\bin\release false + 6.01 if defined RenPath ( @@ -185,6 +186,7 @@ MachineX86 ..\bin\debug SSGM;..\bin\debug false + 6.01 if defined RenPath ( diff -urN sourceold/FirstBlood/FirstBlood.vcxproj source/FirstBlood/FirstBlood.vcxproj --- sourceold/FirstBlood/FirstBlood.vcxproj 2018-10-27 22:04:54.460400000 +1000 +++ source/FirstBlood/FirstBlood.vcxproj 2020-09-26 09:00:03.255035400 +1000 @@ -20,13 +20,13 @@ DynamicLibrary MultiByte false - v110_xp + v110 DynamicLibrary MultiByte true - v110_xp + v110 @@ -108,6 +108,7 @@ MachineX86 ..\bin\release SSGM;..\bin\release false + 6.01 if defined RenPath ( @@ -185,6 +186,7 @@ MachineX86 ..\bin\debug SSGM;..\bin\debug false + 6.01 if defined RenPath ( diff -urN sourceold/MemoryManager/MemoryManager.vcxproj source/MemoryManager/MemoryManager.vcxproj --- sourceold/MemoryManager/MemoryManager.vcxproj 2018-10-27 22:04:54.620400000 +1000 +++ source/MemoryManager/MemoryManager.vcxproj 2020-09-26 09:00:03.260402700 +1000 @@ -28,7 +28,7 @@ DynamicLibrary Unicode true - v110_xp + v110 DynamicLibrary @@ -40,7 +40,7 @@ DynamicLibrary Unicode true - v110_xp + v110 DynamicLibrary @@ -134,6 +134,7 @@ false true true + 6.01 if defined RenPath ( @@ -186,6 +187,7 @@ Windows $(OutDir)$(TargetName)$(TargetExt) false + 6.01 @@ -225,6 +227,7 @@ false true $(TargetDir)$(TargetName).map + 6.01 if defined RenPath ( @@ -276,6 +279,7 @@ true $(OutDir)$(TargetName)$(TargetExt) false + 6.01 diff -urN sourceold/Mute/Mute.vcxproj source/Mute/Mute.vcxproj --- sourceold/Mute/Mute.vcxproj 2018-10-27 22:04:54.636400000 +1000 +++ source/Mute/Mute.vcxproj 2020-09-26 09:00:03.260402700 +1000 @@ -20,13 +20,13 @@ DynamicLibrary MultiByte false - v110_xp + v110 DynamicLibrary MultiByte true - v110_xp + v110 @@ -108,6 +108,7 @@ MachineX86 ..\bin\release SSGM;..\bin\release false + 6.01 if defined RenPath ( @@ -185,6 +186,7 @@ MachineX86 ..\bin\debug SSGM;..\bin\debug false + 6.01 if defined RenPath ( diff -urN sourceold/NoPoints/NoPoints.vcxproj source/NoPoints/NoPoints.vcxproj --- sourceold/NoPoints/NoPoints.vcxproj 2018-10-27 22:04:54.641400000 +1000 +++ source/NoPoints/NoPoints.vcxproj 2020-09-26 09:00:03.261400000 +1000 @@ -20,13 +20,13 @@ DynamicLibrary MultiByte false - v110_xp + v110 DynamicLibrary MultiByte true - v110_xp + v110 @@ -108,6 +108,7 @@ MachineX86 ..\bin\release SSGM;..\bin\release false + 6.01 if defined RenPath ( @@ -185,6 +186,7 @@ MachineX86 ..\bin\debug SSGM;..\bin\debug false + 6.01 if defined RenPath ( diff -urN sourceold/PointsDistribution/PointsDistribution.vcxproj source/PointsDistribution/PointsDistribution.vcxproj --- sourceold/PointsDistribution/PointsDistribution.vcxproj 2018-10-27 22:04:54.652400000 +1000 +++ source/PointsDistribution/PointsDistribution.vcxproj 2020-09-26 09:00:03.262426400 +1000 @@ -20,13 +20,13 @@ DynamicLibrary MultiByte false - v110_xp + v110 DynamicLibrary MultiByte true - v110_xp + v110 @@ -108,6 +108,7 @@ MachineX86 ..\bin\release SSGM;..\bin\release false + 6.01 if defined RenPath ( @@ -185,6 +186,7 @@ MachineX86 ..\bin\debug SSGM;..\bin\debug false + 6.01 if defined RenPath ( diff -urN sourceold/Spectate/Spectate.vcxproj source/Spectate/Spectate.vcxproj --- sourceold/Spectate/Spectate.vcxproj 2018-10-27 22:04:54.657400000 +1000 +++ source/Spectate/Spectate.vcxproj 2020-09-26 09:00:03.263394900 +1000 @@ -20,13 +20,13 @@ DynamicLibrary MultiByte false - v110_xp + v110 DynamicLibrary MultiByte true - v110_xp + v110 @@ -108,6 +108,7 @@ MachineX86 ..\bin\release SSGM;..\bin\release false + 6.01 if defined RenPath ( @@ -185,6 +186,7 @@ MachineX86 ..\bin\debug SSGM;..\bin\debug false + 6.01 if defined RenPath ( diff -urN sourceold/SuddenDeath/SuddenDeath.vcxproj source/SuddenDeath/SuddenDeath.vcxproj --- sourceold/SuddenDeath/SuddenDeath.vcxproj 2018-10-27 22:04:54.663400000 +1000 +++ source/SuddenDeath/SuddenDeath.vcxproj 2020-09-26 09:00:03.263394900 +1000 @@ -20,13 +20,13 @@ DynamicLibrary MultiByte false - v110_xp + v110 DynamicLibrary MultiByte true - v110_xp + v110 @@ -108,6 +108,7 @@ MachineX86 ..\bin\release SSGM;..\bin\release false + 6.01 if defined RenPath ( @@ -185,6 +186,7 @@ MachineX86 ..\bin\debug SSGM;..\bin\debug false + 6.01 if defined RenPath ( diff -urN sourceold/bansystem/bansystem.vcxproj source/bansystem/bansystem.vcxproj --- sourceold/bansystem/bansystem.vcxproj 2018-10-27 22:04:54.675400000 +1000 +++ source/bansystem/bansystem.vcxproj 2020-09-26 09:00:03.268381300 +1000 @@ -20,13 +20,13 @@ DynamicLibrary MultiByte false - v110_xp + v110 DynamicLibrary MultiByte true - v110_xp + v110 @@ -108,6 +108,7 @@ MachineX86 ..\bin\release SSGM;..\bin\release false + 6.01 if defined RenPath ( @@ -185,6 +186,7 @@ MachineX86 ..\bin\debug SSGM;..\bin\debug false + 6.01 if defined RenPath ( diff -urN sourceold/crates/crates.vcxproj source/crates/crates.vcxproj --- sourceold/crates/crates.vcxproj 2018-10-27 22:04:54.685400000 +1000 +++ source/crates/crates.vcxproj 2020-09-26 09:00:03.269381100 +1000 @@ -20,13 +20,13 @@ DynamicLibrary MultiByte false - v110_xp + v110 DynamicLibrary MultiByte true - v110_xp + v110 @@ -108,6 +108,7 @@ MachineX86 ..\bin\release SSGM;..\bin\release false + 6.01 if defined RenPath ( @@ -185,6 +186,7 @@ MachineX86 ..\bin\debug SSGM;..\bin\debug false + 6.01 if defined RenPath ( diff -urN sourceold/example-plugin/example-plugin.vcxproj source/example-plugin/example-plugin.vcxproj --- sourceold/example-plugin/example-plugin.vcxproj 2018-10-27 22:04:56.127400000 +1000 +++ source/example-plugin/example-plugin.vcxproj 2020-09-26 09:00:03.271374200 +1000 @@ -20,13 +20,13 @@ DynamicLibrary MultiByte false - v110_xp + v110 DynamicLibrary MultiByte true - v110_xp + v110 @@ -93,6 +93,7 @@ MachineX86 ..\bin\debug SSGM;..\bin\debug false + 6.01 if defined RenPath ( @@ -159,6 +160,7 @@ MachineX86 ..\bin\release SSGM;..\bin\release false + 6.01 if defined RenPath ( diff -urN sourceold/randomstartingcredits/RandomStartingCredits.vcxproj source/randomstartingcredits/RandomStartingCredits.vcxproj --- sourceold/randomstartingcredits/RandomStartingCredits.vcxproj 2018-10-27 22:04:56.159400000 +1000 +++ source/randomstartingcredits/RandomStartingCredits.vcxproj 2020-09-26 09:00:03.274365300 +1000 @@ -20,14 +20,14 @@ DynamicLibrary MultiByte false - v110_xp + v110 DynamicLibrary false MultiByte true - v110_xp + v110 @@ -109,6 +109,7 @@ MachineX86 ..\bin\release SSGM;..\bin\release false + 6.01 if defined RenPath ( @@ -186,6 +187,7 @@ MachineX86 ..\bin\debug SSGM;..\bin\debug false + 6.01 if defined RenPath ( diff -urN sourceold/scripts/ArmedGameObj.h source/scripts/ArmedGameObj.h --- sourceold/scripts/ArmedGameObj.h 2018-11-17 10:23:56.953600000 +1000 +++ source/scripts/ArmedGameObj.h 2020-09-10 09:08:27.944914000 +1000 @@ -39,6 +39,10 @@ virtual const Matrix3D &Get_Muzzle( int index = 0 ); void Start_Recoil( int muzzle_index,float recoil_scale,float recoil_time ); float Get_Weapon_Error( void ) { return Get_Definition().WeaponError; } + float Get_Weapon_Turn_Min(void) { return Get_Definition().WeaponTurnMin; } + float Get_Weapon_Turn_Max(void) { return Get_Definition().WeaponTurnMax; } + float Get_Weapon_Tilt_Min(void) { return Get_Definition().WeaponTiltMin; } + float Get_Weapon_Tilt_Max(void) { return Get_Definition().WeaponTiltMax; } Vector3 Get_Targeting_Pos( void ) { return TargetingPos; } virtual bool Set_Targeting( const Vector3 & pos, bool do_tilt = true ); virtual ArmedGameObj *As_ArmedGameObj( void ) { return this; } diff -urN sourceold/scripts/ArmedGameObjDef.h source/scripts/ArmedGameObjDef.h --- sourceold/scripts/ArmedGameObjDef.h 2018-11-17 10:23:56.954600000 +1000 +++ source/scripts/ArmedGameObjDef.h 2020-03-28 21:10:59.007874300 +1000 @@ -18,6 +18,8 @@ ArmedGameObjDef( void ); virtual bool Save( ChunkSaveClass &csave ); virtual bool Load( ChunkLoadClass &cload ); + int Get_Weapon_Def_ID() const { return WeaponDefID; } + int Get_Secondary_Weapon_Def_ID() const { return SecondaryWeaponDefID; } #ifdef DDBEDIT virtual void Dump (FileClass &file); #endif diff -urN sourceold/scripts/AudibleSoundDefinitionClass.cpp source/scripts/AudibleSoundDefinitionClass.cpp --- sourceold/scripts/AudibleSoundDefinitionClass.cpp 2018-11-17 10:23:56.956600000 +1000 +++ source/scripts/AudibleSoundDefinitionClass.cpp 2020-09-10 09:08:27.944914000 +1000 @@ -31,7 +31,7 @@ AudibleSoundDefinitionClass::AudibleSoundDefinitionClass() : m_Priority(0.5), m_Volume(1), m_VolumeRandomizer(0), m_Pan(0.5), m_LoopCount(1), m_VirtualChannel(0), m_DropoffRadius(40), m_MaxVolRadius(20), m_Is3DSound(true), m_Type(1), m_StartOffset(0), m_PitchFactor(1), m_PitchFactorRandomizer(0), m_LogicalType(0), m_LogicalNotifDelay(2.0), m_LogicalDropoffRadius(-1.0), m_CreateLogicalSound(false), m_SphereColor(0,0.75,0.75) { #ifdef PARAM_EDITING_ON - NAMED_EDITABLE_PARAM(AudibleSoundDefinitionClass,ParameterClass::TYPE_FILENAME,m_Filename,"Filename"); + NAMED_EDITABLE_PARAM(AudibleSoundDefinitionClass,ParameterClass::TYPE_SOUND_FILENAME,m_Filename,"Filename"); INT_EDITABLE_PARAM(AudibleSoundDefinitionClass,m_VirtualChannel,0,100); NAMED_EDITABLE_PARAM(AudibleSoundDefinitionClass,ParameterClass::TYPE_FLOAT,m_DropoffRadius,"Drop-off Radius"); NAMED_EDITABLE_PARAM(AudibleSoundDefinitionClass,ParameterClass::TYPE_FLOAT,m_MaxVolRadius,"Max-Vol Radius"); diff -urN sourceold/scripts/BeaconGameObjDef.h source/scripts/BeaconGameObjDef.h --- sourceold/scripts/BeaconGameObjDef.h 2018-11-17 10:23:56.961600000 +1000 +++ source/scripts/BeaconGameObjDef.h 2020-09-10 09:08:27.945919000 +1000 @@ -26,6 +26,7 @@ PersistClass* Create() const; int Is_Nuke() const {return IsNuke;} bool Requires_Silo() const {return RequiresSilo;} + int Get_Explosion_Obj_Def() const {return ExplosionObjDef;} #ifdef DDBEDIT virtual void Dump (FileClass &file); #endif diff -urN sourceold/scripts/BuildingGameObj.h source/scripts/BuildingGameObj.h --- sourceold/scripts/BuildingGameObj.h 2018-11-17 10:23:56.965600000 +1000 +++ source/scripts/BuildingGameObj.h 2020-03-28 21:10:59.007874300 +1000 @@ -107,6 +107,7 @@ #endif SCRIPTS_API void Find_Closest_Poly (const Vector3 &pos, float *distance2); float Find_Closest_Poly(const Vector3 &pos) { float distance2; Find_Closest_Poly(pos,&distance2); return distance2; } + void Find_Closest_Poly(const Vector3& pos, float* distance2, Vector3* polyPos); int Building_In_Range(const Vector3 &point, float range); //return 0 for no, 1 for yes and 2 for MCT in range bool Is_In_Range_Coarse(const Vector3& point, float range_sq); bool Cast_Ray(RayCollisionTestClass& raytest); @@ -145,7 +146,7 @@ void Add_Aggregate(BuildingAggregateClass * aggregate); void Remove_Aggregate(BuildingAggregateClass * aggregate); void Add_Light(LightPhysClass * light); - void Find_Closest_Poly_For_Model (RenderObjClass *model, const Vector3 &pos, float *distance2); + void Find_Closest_Poly_For_Model (RenderObjClass *model, const Vector3 &pos, float *distance2, Vector3* polyPos = NULL); void Update_State(bool force_update = false); void Enable_Alternate_Materials(RefMultiListClass & models, bool onoff); void Enable_Alternate_Materials(RenderObjClass * model,bool onoff); diff -urN sourceold/scripts/Defines.h source/scripts/Defines.h --- sourceold/scripts/Defines.h 2018-11-17 10:23:56.993600000 +1000 +++ source/scripts/Defines.h 2020-09-26 09:00:03.275362600 +1000 @@ -30,6 +30,7 @@ #pragma warning(disable:4251) #define WIN32_LEAN_AND_MEAN +#define _WIN32_WINNT 0x0601 #define _USE_MATH_DEFINES // breakpoint diff -urN sourceold/scripts/Doxyfile source/scripts/Doxyfile --- sourceold/scripts/Doxyfile 2018-11-17 10:23:57.001600000 +1000 +++ source/scripts/Doxyfile 2020-04-02 12:02:44.436401100 +1000 @@ -32,7 +32,7 @@ # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 4.6 +PROJECT_NUMBER = 4.7 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer # a quick idea about the purpose of the project. Keep the description short. diff -urN sourceold/scripts/HumanStateClass.h source/scripts/HumanStateClass.h --- sourceold/scripts/HumanStateClass.h 2018-11-17 10:23:57.015600000 +1000 +++ source/scripts/HumanStateClass.h 2020-09-10 09:08:27.945919000 +1000 @@ -160,6 +160,7 @@ void Update_Recoil(WeaponClass * weapon); void Begin_Jump( void ); void Complete_Jump( void ); + void GetLegAndHoldStyle (int *leg_style,int *hold_style); }; diff -urN sourceold/scripts/LineSegClass.cpp source/scripts/LineSegClass.cpp --- sourceold/scripts/LineSegClass.cpp 2018-11-17 10:23:57.023600000 +1000 +++ source/scripts/LineSegClass.cpp 2020-09-10 09:08:27.946909600 +1000 @@ -34,6 +34,7 @@ Matrix3D::Transform_Vector(transform, object.P1, &P1); DP = P1 - P0; Matrix3D::Rotate_Vector(transform, object.Dir, &Dir); + Length = object.Length; } bool LineSegClass::Find_Intersection(const LineSegClass &other_line, Vector3 *p1, float *fraction1, Vector3 *p2, float *fraction2) const diff -urN sourceold/scripts/ObjectLibraryManager.cpp source/scripts/ObjectLibraryManager.cpp --- sourceold/scripts/ObjectLibraryManager.cpp 1970-01-01 10:00:00.000000000 +1000 +++ source/scripts/ObjectLibraryManager.cpp 2020-03-28 21:10:59.056743700 +1000 @@ -0,0 +1,31 @@ +#include "general.h" + +#include "ObjectLibraryManager.h" +#include "DefinitionMgrClass.h" +#include "Definition.h" +PhysicalGameObj* ObjectLibraryManager::Create_Object + (const char* cPresetName) +{ + // const DefinitionClass* oDefinition = DefinitionMgrClass::Find_Typed_Definition (cPresetName, 12288, true); + DefinitionClass* oDefinition = DefinitionMgrClass::Find_Named_Definition (cPresetName, true); + + StringClass oError; + if (!oDefinition || !oDefinition->Is_Valid_Config (oError)) + return 0; + + return (PhysicalGameObj *)oDefinition->Create(); +} + + + +PhysicalGameObj* ObjectLibraryManager::Create_Object + (uint32 uDefinitionID) +{ + DefinitionClass* oDefinition = DefinitionMgrClass::Find_Definition (uDefinitionID, true); + + StringClass oError; + if (!oDefinition || !oDefinition->Is_Valid_Config (oError)) + return 0; + + return (PhysicalGameObj *)oDefinition->Create(); +} diff -urN sourceold/scripts/ObjectLibraryManager.h source/scripts/ObjectLibraryManager.h --- sourceold/scripts/ObjectLibraryManager.h 1970-01-01 10:00:00.000000000 +1000 +++ source/scripts/ObjectLibraryManager.h 2020-03-28 21:10:59.056743700 +1000 @@ -0,0 +1,16 @@ +#ifndef TT_INCLUDE__OBJECTLIBRARYMANAGER_H +#define TT_INCLUDE__OBJECTLIBRARYMANAGER_H +#include "Persist.h" +class PhysicalGameObj; +class ObjectLibraryManager +{ + +public: + + static PhysicalGameObj* Create_Object (const char* cPresetName); + static PhysicalGameObj* Create_Object (uint32 uDefinitionID); + +}; + + +#endif diff -urN sourceold/scripts/PhysicsSceneClass.h source/scripts/PhysicsSceneClass.h --- sourceold/scripts/PhysicsSceneClass.h 2019-06-22 07:43:44.222400000 +1000 +++ source/scripts/PhysicsSceneClass.h 2020-03-28 21:10:59.011863900 +1000 @@ -393,10 +393,6 @@ static bool AllowCollisionFlags[NUM_COLLISION_FLAGS]; int DynamicPolyBudget; int StaticPolyBudget; -#ifdef TT_EXPORTS - float mapStaticPolyBudget; - float mapDynamicPolyBudget; -#endif RefMultiListClass ObjList; RefMultiListClass StaticObjList; RefMultiListClass StaticLightList; @@ -417,5 +413,9 @@ #endif friend class WW3D; friend class VisOptimizationContextClass; +#ifdef TT_EXPORTS + float mapStaticPolyBudget; + float mapDynamicPolyBudget; +#endif }; // 792, WIN: 700 #endif diff -urN sourceold/scripts/RefineryGameObj.h source/scripts/RefineryGameObj.h --- sourceold/scripts/RefineryGameObj.h 2018-11-17 10:23:57.068600000 +1000 +++ source/scripts/RefineryGameObj.h 2020-09-10 09:08:27.946909600 +1000 @@ -61,6 +61,7 @@ { AllowHarvesterSpawn = true; } + static float HarvesterDumpRate; private: void Load_Variables (ChunkLoadClass &cload); HarvesterClass * Harvester; @@ -75,6 +76,8 @@ AudibleSoundClass * MoneyTrickleSound; bool AllowHarvesterSpawn; ReferencerClass HarvesterVehicle; + float accumulatedDumpCredits; + float DumpRate; }; // 2232, RH7 2252 diff -urN sourceold/scripts/RefineryGameObjDef.h source/scripts/RefineryGameObjDef.h --- sourceold/scripts/RefineryGameObjDef.h 2018-11-17 10:23:57.068600000 +1000 +++ source/scripts/RefineryGameObjDef.h 2020-03-28 21:10:59.012889300 +1000 @@ -22,6 +22,8 @@ ~RefineryGameObjDef (void); uint32 Get_Class_ID (void) const; PersistClass * Create (void) const; + float Get_Funds_Gathered() const { return FundsGathered; } + float Get_Funds_Distributed_Per_Sec() const { return FundsDistributedPerSec; } bool Save (ChunkSaveClass &csave); bool Load (ChunkLoadClass &cload); const PersistFactoryClass & Get_Factory (void) const; diff -urN sourceold/scripts/SmartGameObjDef.h source/scripts/SmartGameObjDef.h --- sourceold/scripts/SmartGameObjDef.h 2018-11-17 10:23:57.086600000 +1000 +++ source/scripts/SmartGameObjDef.h 2020-09-10 09:08:27.947906000 +1000 @@ -26,6 +26,12 @@ virtual bool Save( ChunkSaveClass &csave ); virtual bool Load( ChunkLoadClass &cload ); bool Is_Stealthed() const {return IsStealthUnit;} + /* Modifies the sight range of the object. SightRange is used by AI code only. */ + void Set_Sight_Range (const float range) { SightRange = range; } + float Get_Sight_Range() const {return SightRange;} + /* Modifies the sight arc of the object. SightArc is used by AI code only. */ + void Set_Sight_Arc (const float arc) { SightArc = arc; } + float Get_Sight_Arc() const {return SightArc;} #ifdef DDBEDIT virtual void Dump (FileClass &file); #endif diff -urN sourceold/scripts/SoldierGameObj.h source/scripts/SoldierGameObj.h --- sourceold/scripts/SoldierGameObj.h 2019-06-22 07:31:28.791400000 +1000 +++ source/scripts/SoldierGameObj.h 2020-09-10 09:08:27.947906000 +1000 @@ -202,6 +202,9 @@ bool Get_Use_Stock_Ghost_Behavior(){return useStockGhostBehavior;} void Set_Override_Muzzle_Direction(bool override){OverrideMuzzleDirection = override; Set_Object_Dirty_Bit(BIT_RARE, true);}; bool Get_Override_Muzzle_Direction(){return OverrideMuzzleDirection;}; + void Set_Bot_Tag(const char* tag) { botTag = tag; Set_Object_Dirty_Bit(BIT_RARE, true); } + const WideStringClass& Get_Bot_Tag() { return botTag; } + bool Is_Bot() { return botTag.Get_Length() > 0; } virtual int Get_Contact_Surface_Type(); virtual float Get_Skeleton_Heigth( void ); virtual void Set_Skeleton_Height( float height ); @@ -288,6 +291,8 @@ float lastSkeletonWidth; int overrideWeaponHoldStyleId; bool enableHumanAnimOverride; + WideStringClass botTag; + int sight_bone; TT_DEPRECATED("Do not use") int Check(void); }; // size: 3404 diff -urN sourceold/scripts/SoundSceneObjClass.h source/scripts/SoundSceneObjClass.h --- sourceold/scripts/SoundSceneObjClass.h 2018-10-27 22:04:56.326400000 +1000 +++ source/scripts/SoundSceneObjClass.h 2020-03-28 21:10:59.014855700 +1000 @@ -18,6 +18,9 @@ #include "audiocallback.h" #include "Persist.h" #include "Matrix3D.h" +#if !defined(W3DVIEWER) && !defined(TTLE_EXPORTS) +#include "HashTemplateClass.h" +#endif class SoundSceneClass; class SoundCullObjClass; class Sound3DClass; @@ -28,6 +31,7 @@ class RenderObjClass; const uint32 SOUND_OBJ_DEFAULT_ID = 0; const uint32 SOUND_OBJ_START_ID = 1000000000; + class SoundSceneObjClass : public MultiListObjectClass, public PersistClass, public RefCountClass { public: @@ -87,9 +91,23 @@ int m_AttachedBone; // 0030 0048 uint32 m_UserData; // 0034 004C RefCountClass * m_UserObj; // 0038 0050 + static uint32 m_NextAvailableID; static DynamicVectorClass m_GlobalSoundList; static CriticalSectionClass m_IDListMutex; + + // Added by TT +#if !defined(W3DVIEWER) && !defined(TTLE_EXPORTS) +public: + static void Associate_Server_ID(SoundSceneObjClass* sound_obj, uint32 server_id); + +protected: + static HashTemplateClass m_ServerGlobalSoundList; + static HashTemplateClass m_ReversedServerGlobalSoundList; + static CriticalSectionClass m_ServerIDListMutex; + + static bool Find_Server_Sound_Object(uint32 server_id_to_find, SoundSceneObjClass*& sound_obj); +#endif }; // 003C 0054 #endif diff -urN sourceold/scripts/SysTimeClass.cpp source/scripts/SysTimeClass.cpp --- sourceold/scripts/SysTimeClass.cpp 2018-11-17 10:23:57.099600000 +1000 +++ source/scripts/SysTimeClass.cpp 2020-09-10 09:08:27.948915200 +1000 @@ -32,7 +32,15 @@ this->Reset(); } - return timeGetTime() - this->uTimeInit; + unsigned int u = timeGetTime(); + if (u <= uTimeInit) + { + return uTimeInitNeg + u; + } + else + { + return u - uTimeInit; + } } diff -urN sourceold/scripts/TwiddlerClass.h source/scripts/TwiddlerClass.h --- sourceold/scripts/TwiddlerClass.h 2018-11-17 10:23:57.112600000 +1000 +++ source/scripts/TwiddlerClass.h 2020-03-28 21:10:59.014855700 +1000 @@ -19,6 +19,7 @@ virtual DefinitionClass *Twiddle() const; PersistClass *Create() const; const PersistFactoryClass &Get_Factory() const; + const DynamicVectorClass& Get_Definition_List() { return m_DefinitionList; } bool Save(ChunkSaveClass &csave); bool Load(ChunkLoadClass &cload); bool Save_Variables(ChunkSaveClass &csave); diff -urN sourceold/scripts/Vector3.h source/scripts/Vector3.h --- sourceold/scripts/Vector3.h 2018-11-17 10:23:57.113600000 +1000 +++ source/scripts/Vector3.h 2020-09-10 09:08:27.948915200 +1000 @@ -327,9 +327,11 @@ TT_INLINE static float Distance(const Vector3 &p1, const Vector3 &p2) { - Vector3 temp; - temp = p1 - p2; - return (temp.Length()); + return (p1 - p2).Length(); + } + TT_INLINE static float Distance_Squared(const Vector3 &p1, const Vector3 &p2) + { + return (p1 - p2).Length2(); } TT_INLINE static void Lerp(const Vector3 &a, const Vector3 &b, float alpha,Vector3 *set_result) { diff -urN sourceold/scripts/VehicleGameObj.h source/scripts/VehicleGameObj.h --- sourceold/scripts/VehicleGameObj.h 2019-06-22 07:31:28.793400000 +1000 +++ source/scripts/VehicleGameObj.h 2020-03-28 21:10:59.015853000 +1000 @@ -98,6 +98,7 @@ void Update_Damage_Meshes( void ); float Get_Squish_Velocity( void) { return Get_Definition().SquishVelocity; } void Script_Enable_Transitions( bool enable ) { TransitionsEnabled = enable; Create_And_Destroy_Transitions(); } + bool Get_Transitions_Enabled ( void ) { return TransitionsEnabled; } static void Set_Precision(void); static bool Toggle_Target_Steering( void ); static void Set_Target_Steering( bool onoff ); diff -urN sourceold/scripts/WWAudioClass.h source/scripts/WWAudioClass.h --- sourceold/scripts/WWAudioClass.h 2018-10-27 22:04:56.358400000 +1000 +++ source/scripts/WWAudioClass.h 2020-03-28 21:10:59.016850200 +1000 @@ -198,6 +198,10 @@ AudibleSoundClass * Create_Sound (int definition_id, RefCountClass *user_obj = NULL, uint32 user_data = 0, int classid_hint = CLASSID_3D); AudibleSoundClass * Create_Sound (const char *def_name, RefCountClass *user_obj = NULL, uint32 user_data = 0, int classid_hint = CLASSID_3D); SoundSceneObjClass * Find_Sound_Object (uint32 sound_obj_id); +#if !defined(W3DVIEWER) && !defined(TTLE_EXPORTS) + SoundSceneObjClass* Find_Server_Sound_Object(uint32 server_sound_obj_id); // Added by TT + uint32 Get_New_Server_Sound_ID(); // Added by TT +#endif SoundSceneClass * Get_Sound_Scene (void) const { return m_SoundScene; } bool Set_Cache_Size (int kbytes = DEF_CACHE_SIZE) { m_MaxCacheSize = (kbytes * 1024); } int Get_Cache_Size (void) const { return m_MaxCacheSize / 1024; } diff -urN sourceold/scripts/anticheat.ini source/scripts/anticheat.ini --- sourceold/scripts/anticheat.ini 2018-11-17 10:23:37.857600000 +1000 +++ source/scripts/anticheat.ini 2020-09-26 08:59:57.386159600 +1000 @@ -134,3 +134,63 @@ 185315cb0070e52ab9c89d95d06f05e5=C&C_Complex.ldd 11fc8b1d6d70fbacbb18181618fc3964=c&c_field.mix b94a4486508afdc014c1ff3ea4f3d455=c&c_field.ldd +b3b5a7faa502f747d3bc8ff5c63a99cb=M00_Tutorial.mix +5da07b82073c698031b3bacdf286709c=M02.mix +ceb5f647bec120fedffc9d9fc70f9ae6=M04.mix +77e35ed03742c2a3916cae9baf6b119a=M07.mix +72d92296beb9b14c1cd227e8ee592e19=M08.mix +b3a1e43b578cd1f1899d920d9502b4e3=always.dat +bbcd3fe6b90f81db7a55a1a214a75368=always.dbs +f89d34c3bc56931a98aab08ad58d8ef1=c&c_city_flying.lsd +7ddf27c53b4ff6e2a359f7e1b0fb9d2c=c&c_glacier_flying.ddb +840a735015e5a5f97f9b595d27d6939e=c&c_glacier_flying.ldd +9d5a1a6534e87623734592583ebd7514=c&c_glacier_flying.lsd +908f10aa21b880481f00df979ee9ffc3=c&c_walls_flying.lsd +e8a85eab76883e81ddf00c8a3832e62b=m09.dep +d42dde72d9b33d70e27186d8576f7f28=m09.ldd +3f313b1d45c289b4315b849613e24d5d=m09.lsd +8a73e57ed8328458fc5b8e188431b58a=c&c_canyon.ldd +3c2948416ae9ef87576244334dd96dcc=c&c_canyon.lsd +fa8ec7d845fc98fa4e251c47ddda08ab=C&C_Canyon.mix +b707c64d4ecbd8852a9203194ea870d6=c&c_city.ldd +06cea509a508dbbe2a77a20837d8af1a=c&c_city.lsd +66653f776fc48d86fab9bd4e7a79fa50=C&C_City.mix +8980464e3794ee7814fa8e628a6bf03f=c&c_city_flying.ldd +1d9c1184dcf889db9e89fa0f4cbbc2f3=c&c_city_flying.lsd +3ae55a803f618419613d4f9449621311=C&C_City_Flying.mix +e579475a79eb6064e850540dcdbc93db=c&c_complex.ldd +1f65b69504fc5900583038f4878395b5=c&c_complex.lsd +4874ba832f9244cec2fdb06298d84f28=C&C_Complex.mix +1f384b687a76243972d041416e971dd7=c&c_field.ldd +09c11621c186be319abc9c67bfb6c851=c&c_field.lsd +48bff89bfedbe2dec0bed18d30419a5f=C&C_Field.mix +3a15d5bee28c4d1efb49a80da9912971=c&c_glacier_flying.ddb +ce8e22aafb5d126384ecde5d424c774c=c&c_glacier_flying.ldd +10a0a9086ccb7885c6140f98f099084a=c&c_glacier_flying.lsd +5fb74b0a88a3d17296ceb7eb01b48ecf=C&C_Glacier_Flying.mix +2c827469432c744858076605522f3179=c&c_hourglass.ldd +d165cb79cb5928e4235d325296affebd=c&c_hourglass.lsd +df78d1b07d1a9e6982a2b059687a35be=C&C_Hourglass.mix +22bb4baf876ba7dbd3500e7f7a6b06b4=c&c_islands.ldd +0250e5ff5fc14d206b6047c8ce878fe9=c&c_islands.lsd +4189d8309dd8af379cd6059c4161001b=C&C_Islands.mix +d274bd131570e2c86ca9c1283740c316=c&c_mesa.ldd +ae9f30a84b0addad158b9607d650d1a6=c&c_mesa.lsd +1093a6bfa25597ae0b092e2ff0841e55=C&C_Mesa.mix +b4b62db6b2b678e6280788c31be801a4=c&c_under.ldd +d52da922114ee3815e3af8e14f8f3407=c&c_under.lsd +5ff1b5861853e4dda9193f0de21c72ca=C&C_Under.mix +681e7516692cb3b2573591f74b5a9d18=c&c_volcano.ldd +b3fa999e7d40b378d57d7dacfba87f36=c&c_volcano.lsd +0eb0f530b48926241cbea44a24ef6a6e=C&C_Volcano.mix +c6e8f0e037a922caa4aeeed7d9e51400=C&C_Walls.ldd +a44fe08c4400d45dfc7c26e545cc1c44=C&C_Walls.lsd +3e9c2babf700a495f8403303ef6e1707=C&C_Walls.mix +49cadbf6942f619922e2d9ef03b58e0e=C&C_Walls_Flying.ldd +779dbe4cc96b4b75be0189699eeab597=C&C_Walls_Flying.lsd +cedd5f9edf76b92a5f8af4099c1e2e0e=C&C_Walls_Flying.mix +dbcbf16ad119e54b3f11d6fa44de2fcc=m09.dep +504fa186ffab468a37a64fbd3ab26b37=m09.ldd +9a1b58b2327389f8065f704dd6e4d8a0=m09.lsd +9be4d74ee0deff8204e7091df81eeff4=M09.mix +3cedfb2b7c127d456c37ff10c7cc65a8=always3.dat diff -urN sourceold/scripts/dllmain.cpp source/scripts/dllmain.cpp --- sourceold/scripts/dllmain.cpp 2019-06-22 07:43:44.225400000 +1000 +++ source/scripts/dllmain.cpp 2020-09-26 08:59:57.387156900 +1000 @@ -334,6 +334,9 @@ Retrieve_Waypaths = (rwpa)Address(tt,"Retrieve_Waypaths"); Retrieve_Waypoints = (rwpo)Address(tt,"Retrieve_Waypoints"); Get_Waypoint_Position = (gwp)Address(tt,"Get_Waypoint_Position"); + Test_Raycast_Collision = (trc)Address(tt,"Test_Raycast_Collision"); + Is_Inside_AABox = (iib)Address(tt,"Is_Inside_AABox"); + Can_Generic_Soldier_Teleport = (cgst)Address(tt,"Can_Generic_Soldier_Teleport"); Create_Lightning = (cl)Address(tt,"Create_Lightning"); Set_Global_Stealth_Disable = (smie)Address(tt,"Set_Global_Stealth_Disable"); Get_Clouds = (gc) Address(tt, "Get_Clouds"); @@ -378,6 +381,39 @@ Cancel_Get_Pathfind_Distance = (cgpd)Address(tt,"Cancel_Get_Pathfind_Distance"); Get_Pathfind_Distance_Async = (gpda)Address(tt, "Get_Pathfind_Distance_Async"); Get_Pathfind_Distance_Blocking = (gpdb)Address(tt, "Get_Pathfind_Distance_Blocking"); + Get_Multiplayer_Spawn_Location = (gmsl)Address(tt, "Get_Multiplayer_Spawn_Location"); + Enable_Spawners_By_Name = (esbn)Address(tt, "Enable_Spawners_By_Name"); + Is_Pathfind_Generated = (ipg)Address(tt, "Is_Pathfind_Generated"); + Get_Closest_Pathfind_Spot = (gcps)Address(tt, "Get_Closest_Pathfind_Spot"); + Get_Closest_Pathfind_Spot_Size = (gcpss)Address(tt, "Get_Closest_Pathfind_Spot_Size"); + Get_Radio_Command_String = (grcs)Address(tt, "Get_Radio_Command_String"); + Set_Emot_Icon = (sei)Address(tt, "Set_Emot_Icon"); + Kill_Messages_Disabled = (kmd)Address(tt, "Kill_Messages_Disabled"); + Is_Sidebar_Enabled = (ise)Address(tt, "Is_Sidebar_Enabled"); + Is_Extras_Enabled = (iee)Address(tt, "Is_Extras_Enabled"); + Can_Build_Ground = (cbg)Address(tt, "Can_Build_Ground"); + Can_Build_Air = (cba)Address(tt, "Can_Build_Air"); + Can_Build_Naval = (cbn)Address(tt, "Can_Build_Naval"); + Is_Soldier_Busy = (isb)Address(tt, "Is_Soldier_Busy"); + Is_On_Enemy_Pedestal = (ioep)Address(tt, "Is_On_Enemy_Pedestal"); + Find_Closest_Poly_Position = (fcpp)Address(tt, "Find_Closest_Poly_Position"); + Say_Dynamic_Dialogue = (sdd)Address(tt, "Say_Dynamic_Dialogue"); + Say_Dynamic_Dialogue_Player = (sddp)Address(tt, "Say_Dynamic_Dialogue_Player"); + Say_Dynamic_Dialogue_Team = (sddt)Address(tt, "Say_Dynamic_Dialogue_Team"); + Enable_Letterbox_Player = (elp)Address(tt, "Enable_Letterbox_Player"); + Create_Sound_Team = (cst)Address(tt, "Create_Sound_Team"); + Create_2D_Sound_Team = (c2dst)Address(tt, "Create_2D_Sound_Team"); + Create_2D_WAV_Sound_Team = (c2dwst)Address(tt, "Create_2D_WAV_Sound_Team"); + Create_2D_WAV_Sound_Team_Dialog = (c2dwstd)Address(tt, "Create_2D_WAV_Sound_Team_Dialog"); + Create_2D_WAV_Sound_Team_Cinematic = (c2dwstc)Address(tt, "Create_2D_WAV_Sound_Team_Cinematic"); + Create_3D_WAV_Sound_At_Bone_Team = (c3dwsbt)Address(tt, "Create_3D_WAV_Sound_At_Bone_Team"); + Create_3D_Sound_At_Bone_Team = (c3dsbt)Address(tt, "Create_3D_Sound_At_Bone_Team"); + Stop_Sound_Player = (_Stop_Sound_Player)Address(tt, "Stop_Sound_Player"); + Stop_Sound_Team = (_Stop_Sound_Team)Address(tt, "Stop_Sound_Team"); + Set_Subobject_Animation = (ssa)Address(tt,"Set_Subobject_Animation"); + Set_Time_Scale = (sts)Address(tt,"Set_Time_Scale"); + Set_Subobject_Animation_Player = (ssap)Address(tt,"Set_Subobject_Animation_Player"); + Write_File_Async = (wfa)Address(tt, "Write_File_Async"); #ifdef SSGM SSGMGameManager::Init(); diff -urN sourceold/scripts/dp88_ar.cpp source/scripts/dp88_ar.cpp --- sourceold/scripts/dp88_ar.cpp 2018-11-17 10:23:57.137600000 +1000 +++ source/scripts/dp88_ar.cpp 2020-09-10 09:08:27.950898100 +1000 @@ -14,6 +14,7 @@ #include "scripts.h" #include "engine.h" #include "dp88_ar.h" +#include "ms.h" #include "Definition.h" #include "PurchaseSettingsDefClass.h" #include "SoldierGameObj.h" @@ -1031,6 +1032,7 @@ // Grant money to team and reset ore load level Commands->Give_Money ( obj, (float)m_oreValue, true ); + MS_AccessHelper::Give_Bot_Credits(Get_Object_Type(obj), (float)m_oreValue); m_oreMined = 0; m_oreValue = 0; @@ -1453,7 +1455,7 @@ // OK, got a candidate zone, can we chronoshift here? Vector3 zonePos = Commands->Get_Position(zone); - if ( Commands->Get_Distance(zonePos,refineryPos) > maxDist || !CanChronoshiftToLocation(obj, zonePos) ) + if (Vector3::Distance_Squared(zonePos, refineryPos) > maxDist * maxDist || !CanChronoshiftToLocation(obj, zonePos) ) continue; // Is this zone in use for another chronoshift operation? If so then we cannot use it @@ -3276,7 +3278,7 @@ { // If we recieve a stop charging message from the tower we are currently // charging then we should stop all actions - if ( type == CUSTOM_PRISMTOWER_STOP_CHARGING && isAssistingTower && Commands->Get_ID(sender) == targetID ) + if ( type == CUSTOM_PRISMTOWER_STOP_CHARGING && isAssistingTower && sender == m_target ) StopAssisting(obj); @@ -3286,12 +3288,12 @@ else if ( type == CUSTOM_PRISMTOWER_REQUEST_CHARGING ) { // Are we idle? If so then there's no reason not to simply start charging immediatly - if ( targetID == 0 ) + if ( !m_target ) StartAssisting(obj, sender, (float)param); // Is this request from the tower we are currently charging? If so then update the last seen // time and priority and forward the assistance request to any other adjacent towers - else if ( isAssistingTower && targetID == Commands->Get_ID(sender) ) + else if ( isAssistingTower && m_target == sender ) { targetLastSeen = (int)time(NULL); targetPriority = (float)param; @@ -3319,7 +3321,7 @@ * Can this screw up the timings between charging towers and the attacking tower? Need to think * this through sometime and possibly do some experimentation... */ - if ( targetID ) + if ( m_target ) SendAssistanceRequests(obj); /* Refill a single unit of charge if depleted */ @@ -3327,7 +3329,7 @@ Set_Current_Clip_Bullets(obj,1); /* If current bullets > 1 and no enemy seen recently then additional charge is lost */ - if ( Get_Current_Bullets(obj) > 1 && targetID == 0 ) + if ( Get_Current_Bullets(obj) > 1 && !m_target ) Set_Current_Bullets(obj,1); } @@ -3342,7 +3344,7 @@ { // If the target is the tower we are currently charging then return // the priority of that charging sequence - if ( Commands->Get_ID(target) == targetID && isAssistingTower ) + if ( m_target == target && isAssistingTower ) return targetPriority; // Otherwise run the normal priority calculation @@ -3354,7 +3356,7 @@ bool dp88_AR_Prism_Tower::checkTeam( GameObject *obj, GameObject *target ) { // Return true for the tower we are charging, even though it is on the same team as us - if ( Commands->Get_ID(target) == targetID && isAssistingTower ) + if ( m_target == target && isAssistingTower ) return true; // Otherwise run the normal check team function @@ -3408,7 +3410,7 @@ void dp88_AR_Prism_Tower::StartAssisting(GameObject* obj, GameObject* tower, float priority) { // Set our new target ID and priority - targetID = Commands->Get_ID(tower); + m_target = tower; targetPriority = priority; targetLastSeen = (int)time(NULL); isAssistingTower = true; @@ -3427,7 +3429,7 @@ { if ( isAssistingTower ) { - targetID = NULL; + m_target = nullptr; targetPriority = 0; isAssistingTower = false; Commands->Action_Reset(obj, 101.0f); @@ -3454,7 +3456,7 @@ // Send out assistance requests to all adjacent towers except the one we are charging, if any for ( int i = 0; i < adjacentTowerCount; ++i ) { - if ( adjacentTowers[i] != targetID && Commands->Find_Object(adjacentTowers[i]) != obj) + if ( adjacentTowers[i] != m_target->Get_ID() && Commands->Find_Object(adjacentTowers[i]) != obj) Commands->Send_Custom_Event(obj, Commands->Find_Object(adjacentTowers[i]), CUSTOM_PRISMTOWER_REQUEST_CHARGING, (int)targetPriority, 0.0f ); } } diff -urN sourceold/scripts/dp88_buildingScripts.cpp source/scripts/dp88_buildingScripts.cpp --- sourceold/scripts/dp88_buildingScripts.cpp 2018-11-17 10:23:57.142600000 +1000 +++ source/scripts/dp88_buildingScripts.cpp 2020-03-28 21:10:59.018844900 +1000 @@ -15,6 +15,7 @@ #include "engine.h" #include "dp88_custom_timer_defines.h" #include "dp88_buildingScripts.h" +#include "ms.h" #include "definition.h" #include "BaseControllerClass.h" #include "WarFactoryGameObj.h" @@ -1078,6 +1079,8 @@ int team = Get_Object_Type(obj); if ( team == 0 || team == 1 ) { + MS_AccessHelper::Give_Bot_Credits(team, Get_Float_Parameter("creditsPerSec")); + // NB: Calling Give_Money with the building controller as a parameter doesn't seem // to give anyone any money, so get the first player on the team and use them as // the target for Give_Money (true as third param to give to whole team) @@ -1102,6 +1105,8 @@ { if (team == 0 || team == 1) { + MS_AccessHelper::Give_Bot_Credits(team, m_credits); + GameObject* pFirstPlayer = Find_First_Player(team); if(pFirstPlayer) { diff -urN sourceold/scripts/dp88_customAI.cpp source/scripts/dp88_customAI.cpp --- sourceold/scripts/dp88_customAI.cpp 2019-06-22 07:31:28.796400000 +1000 +++ source/scripts/dp88_customAI.cpp 2020-09-10 09:08:27.951896300 +1000 @@ -34,7 +34,7 @@ void dp88_customAI::Timer_Expired(GameObject *obj, int number) { if (TIMER_AI_THINK == number) - Commands->Start_Timer(obj, this, 0.10f, TIMER_AI_THINK); + Commands->Start_Timer(obj, this, thinkTime, TIMER_AI_THINK); } // ------------------------------------------------------------------------------------------------- @@ -45,7 +45,8 @@ { m_bAiEnabled = false; AIStateChanged(pObj, false); - targetID = 0; + m_target = nullptr; + hasTarget = false; targetPriority = 0.0f; targetLastSeen = 0; } @@ -53,11 +54,17 @@ else if ( message == CUSTOM_AI_ENABLEAI && !m_bAiEnabled ) { m_bAiEnabled = true; - targetID = 0; + m_target = nullptr; + hasTarget = false; targetPriority = 0.0f; targetLastSeen = 0; AIStateChanged(pObj, true); } + + else if (message == CUSTOM_AI_RESET_ACTIONS) + { + ResetAllActions(pObj); + } } // ------------------------------------------------------------------------------------------------- @@ -85,7 +92,8 @@ { if ( action_id == 2 ) { - targetID = 0; + m_target = nullptr; + hasTarget = false; targetPriority = 0.0f; Commands->Action_Reset( obj, 100 ); } @@ -104,19 +112,21 @@ // Set default values m_bAiEnabled = true; - targetID = 0; + m_target = nullptr; + hasTarget = false; targetLastSeen = 0; targetPriority = 0.0f; m_bTargetPrimaryFire = true; + thinkTime = 1.0f; // Set state Commands->Enable_Hibernation(obj, false); Commands->Innate_Enable(obj); Commands->Enable_Enemy_Seen(obj, true); - // Commands->Enable_Vehicle_Transitions(obj, false); + Commands->Enable_Vehicle_Transitions(obj, false); // Start timer which runs for the lifetime of this object - Commands->Start_Timer ( obj, this, 0.10f, TIMER_AI_THINK ); + Commands->Start_Timer ( obj, this, 1.0, TIMER_AI_THINK ); } // ------------------------------------------------------------------------------------------------- @@ -176,17 +186,19 @@ float dp88_customAI::getBasePriority(GameObject *target) { - if ( Get_Vehicle_Mode(target) == VEHICLE_TYPE_FLYING || (target->As_SoldierGameObj() && (Get_Fly_Mode(target)||Find_Script_On_Object(target,"dp88_AR_Paradrop")) ) ) - return priority_VTOL; - if ( target->As_SoldierGameObj() ) - return priority_infantry; - if ( target->As_VehicleGameObj() && Is_Script_Attached ( target, "dp88_AI_heavyVehicleMarker" ) ) - return priority_heavyVehicle; - if ( target->As_VehicleGameObj() ) - return priority_lightVehicle; - if ( target->As_BuildingGameObj() ) - return priority_building; - + switch (GetTargetType(target)) + { + case SOLDIER: + return priority_infantry; + case LIGHT_VEHICLE: + return priority_lightVehicle; + case HEAVY_VEHICLE: + return priority_heavyVehicle; + case FLYING: + return priority_VTOL; + case BUILDING: + return priority_building; + } return 0; } @@ -200,9 +212,8 @@ if ( debug ) fprintf ( debugFile, "Calculating priority of %d (%s)\n", Commands->Get_ID(target), Commands->Get_Preset_Name(target) ); // Priority is 0 if the unit is dead or not on teams 0 or 1 - if ( ( Commands->Get_Health ( target ) + Commands->Get_Shield_Strength ( target ) ) == 0 - || ( Commands->Get_Player_Type ( target ) == -2) ) - //|| ( Commands->Get_Player_Type ( target ) != 0 && Commands->Get_Player_Type ( target ) != 1 ) ) + if ( ( Commands->Get_Health ( target ) + Commands->Get_Shield_Strength ( target ) ) == 0 + || Commands->Get_Player_Type ( target ) == SCRIPT_PLAYERTYPE_NEUTRAL || Commands->Get_Player_Type ( target ) == SCRIPT_PLAYERTYPE_SPECTATOR ) { if ( debug ) fprintf ( debugFile, "Target %d is dead or unteamed, ignoring\n", Commands->Get_ID(target)); return 0.0; @@ -214,7 +225,7 @@ return 0.0; } - if ( !m_bCanDetectStealth && target->As_SmartGameObj() && target->As_SmartGameObj()->Is_Stealthed() ) + if ( !m_bCanDetectStealth && target->As_SmartGameObj() && target->As_SmartGameObj()->Is_Stealthed() && getDistance(obj, target) > target->As_SmartGameObj()->Get_Stealth_Fade_Distance() ) { if ( debug ) fprintf ( debugFile, "Target %d is currently stealthed and stealth detection is disabled\n", Commands->Get_ID(target)); return 0.0; @@ -238,7 +249,7 @@ // cost to purchase - not applicable to buildings) if ( !target->As_BuildingGameObj() ) { - int cost = Get_Team_Cost( Commands->Get_Preset_Name ( target ), Commands->Get_Player_Type ( target ) ); + int cost = Get_Team_Cost( Commands->Get_Preset_ID ( target ), Commands->Get_Player_Type ( target ) ); priority += ((float)cost/10.0f) * modifier_target_value; if ( debug ) fprintf ( debugFile, "\tTarget Value Modifier: Adding %.4f priority ((Value %d /10) * modifier %.2f)\n", ((float)cost/10.0f)*modifier_target_value, cost, modifier_target_value ); @@ -287,14 +298,19 @@ bool dp88_customAI::getPrimary ( GameObject *target ) { - if ( target->As_SoldierGameObj() ) - return primary_infantry; - else if ( Get_Vehicle_Mode ( target ) == VEHICLE_TYPE_FLYING ) - return primary_VTOL; - else if ( target->As_VehicleGameObj() ) - return (Is_Script_Attached(target,"dp88_AI_heavyVehicleMarker")) ? primary_heavyVehicle : primary_lightVehicle; - else if ( target->As_BuildingGameObj() ) - return primary_building; + switch (GetTargetType(target)) + { + case SOLDIER: + return primary_infantry; + case LIGHT_VEHICLE: + return primary_lightVehicle; + case HEAVY_VEHICLE: + return primary_heavyVehicle; + case FLYING: + return primary_VTOL; + case BUILDING: + return primary_building; + } return true; } @@ -318,17 +334,65 @@ return (vobj->Get_Action()->Is_Acting()); } +// ------------------------------------------------------------------------------------------------- + +dp88_customAI::TargetType dp88_customAI::GetTargetType(GameObject* target) +{ + if (target->As_BuildingGameObj() || Is_Script_Attached(target, "dp88_AI_Marker_Building")) + return BUILDING; + if (Is_Script_Attached(target, "JFW_Deployable_Aircraft_Deployed")) + return LIGHT_VEHICLE; + if ((Get_Vehicle_Mode(target) == VEHICLE_TYPE_FLYING) || (target->As_SoldierGameObj() && (Get_Fly_Mode(target) || Find_Script_On_Object(target, "MS_Paradrop") || Find_Script_On_Object(target, "dp88_AR_Paradrop")))) + return FLYING; + if (target->As_SoldierGameObj()) + return SOLDIER; + if (target->As_VehicleGameObj() && (Is_Script_Attached(target, "dp88_AI_Marker_HeavyVehicle") || Is_Script_Attached ( target, "dp88_AI_heavyVehicleMarker"))) + return HEAVY_VEHICLE; + if (Is_Script_Attached(target, "dp88_AI_Marker_Repairable")) + return REPAIRABLE; + if (target->As_VehicleGameObj()) + return LIGHT_VEHICLE; + + return UNKNOWN; +} + + +/*------------------------ +Deprecated heavy vehicle marker script +--------------------------*/ +void dp88_AI_heavyVehicleMarker::Created(GameObject* obj) +{ + Console_Output("[%d:%hs:%hs] This script is deprecated, use dp88_AI_Marker_HeavyVehicle instead\n", Commands->Get_ID(obj), Commands->Get_Preset_Name(obj), this->Get_Name()); + Attach_Script_V(obj,"dp88_AI_Marker_HeavyVehicle","0"); + Destroy_Script(); +} +/*------------------------ +Repairable marker script +--------------------------*/ +void dp88_AI_Marker_Repairable::Created(GameObject* obj) +{ + pathfindDistance = Get_Float_Parameter("Pathfind_Distance"); +} +// ------------------------------------------------------------------------------------------------- +float dp88_AI_Marker_Repairable::Get_Distance_From_Pathfind() +{ + return pathfindDistance; +} /*------------------------ Unit AI base class --------------------------*/ +DynamicVectorClass dp88_AI_Unit::ListOfAIUnits; + +// ------------------------------------------------------------------------------------------------- + void dp88_AI_Unit::Created(GameObject* obj) { // Base class should not be instantiated @@ -345,6 +409,23 @@ m_bMovingToTarget = false; m_bMovingToObjective = false; m_pCurrentObjective = NULL; + ListOfAIUnits.Add(this); +} + +// ------------------------------------------------------------------------------------------------- + +void dp88_AI_Unit::Detach(GameObject* obj) +{ + ListOfAIUnits.DeleteObj(this); + dp88_customAI::Detach(obj); +} + +// ------------------------------------------------------------------------------------------------- + +void dp88_AI_Unit::Force_Clear_Current_Objective() +{ + m_pCurrentObjective = nullptr; + m_bMovingToObjective = false; } // ------------------------------------------------------------------------------------------------- @@ -354,16 +435,14 @@ // Check target is still alive, still an enemy (eg: stolen vehicles) and in range if (TIMER_AI_THINK == number) { - GameObject* target = (NULL != targetID) ? Commands->Find_Object(targetID) : NULL; - // Check the current objective, if any, is still valid if (NULL != m_pCurrentObjective && !dp88_AI_Objective::IsValidObjective(m_pCurrentObjective)) { m_pCurrentObjective = NULL; if (m_bMovingToObjective) { - if (NULL != target && IsValidTarget(obj, target)) - AttackTarget(obj, target); + if (m_target && IsValidTarget(obj, m_target)) + AttackTarget(obj, m_target); else ResetAllActions(obj); } @@ -373,23 +452,24 @@ if (NULL == m_pCurrentObjective) { m_pCurrentObjective = ChooseNewObjective(obj); - if (NULL != m_pCurrentObjective && (NULL == target || !ShouldPursueTarget(obj, target))) + if (NULL != m_pCurrentObjective && (!m_target || !ShouldPursueTarget(obj, m_target))) GoToObjective(obj); } // If we have a target check it is still valid - if (NULL != targetID) + if (m_target) { - if (NULL == target || !IsValidTarget(obj, target) || (int)time(NULL) - targetLastSeen > 3) + if (!IsValidTarget(obj, m_target) || (int)time(NULL) - targetLastSeen > 3) { - targetID = NULL; + m_target = nullptr; + hasTarget = false; ResetAllActions(obj); } // Check if we need to move closer to our target - else if (!m_bMovingToTarget && ShouldPursueTarget(obj, target) && getDistance(obj, target) > GetPreferredAttackRange(obj, target)) + else if (!m_bMovingToTarget && ShouldPursueTarget(obj, m_target) && getDistance(obj, m_target) > GetPreferredAttackRange(obj, m_target)) { - AttackTarget(obj, target); // Will modify the action with movement parameters + AttackTarget(obj, m_target); // Will modify the action with movement parameters } } @@ -409,7 +489,10 @@ ResetAllActions(obj); if (MOVEMENT_COMPLETE_ARRIVED == reason && action_id == ACTION_ID_ATTACK_TARGET) - AttackTarget(obj, Commands->Find_Object(targetID)); + { + if (m_target) + AttackTarget(obj, m_target); + } } // ------------------------------------------------------------------------------------------------- @@ -431,7 +514,7 @@ // ------------------------------------------------------------------------------------------------- -void dp88_AI_Unit::GoToObjective(GameObject *obj) +void dp88_AI_Unit::GoToObjective(GameObject *obj, float speed) { if (NULL == m_pCurrentObjective) return; @@ -439,7 +522,7 @@ ActionParamsStruct params; bool bModifyAction = false; - if (NULL == targetID || !obj->As_SmartGameObj()->Get_Action()->Is_Acting()) + if (!m_target || !obj->As_SmartGameObj()->Get_Action()->Is_Acting()) { ResetAllActions(obj); params.Set_Basic(this, 80, ACTION_ID_MOVE_TO_OBJECTIVE); @@ -453,9 +536,10 @@ // Setup the movement parameters int arrivalRange = m_pCurrentObjective->GetRange(); - m_bMovingToObjective = arrivalRange < getDistance(obj, m_pCurrentObjective->GetGameObject()); + // Fix arrival range by letting it 1 meter further than wanted, because soldiers keep calling action_complete when 1.58m away than 1.0 wanted. + m_bMovingToObjective = (arrivalRange + 1) < getDistance(obj, m_pCurrentObjective->GetGameObject()); if (m_bMovingToObjective) - params.Set_Movement(m_pCurrentObjective->GetGameObject(), 1.0f, (float)arrivalRange); + params.Set_Movement(m_pCurrentObjective->GetGameObject(), speed, (float)arrivalRange); else { // Already in range of the objective @@ -463,6 +547,9 @@ return; } + if (GetTargetType(obj) == FLYING) + params.MovePathfind = false; + // Commence the action if (bModifyAction) Commands->Modify_Action(obj, params.ActionID, params, true, false); @@ -491,13 +578,14 @@ } // Setup parameters to track state - targetID = Commands->Get_ID(target); + m_target = target; + hasTarget = true; m_bTargetPrimaryFire = getPrimary(target); targetPriority = getPriority(obj, target); targetLastSeen = (int)time(NULL); // Setup the attack parameters - params.Set_Attack(target, (float)((m_bTargetPrimaryFire)?primary_maxRange:secondary_maxRange), 0.0, true); + params.Set_Attack(target, (float)((m_bTargetPrimaryFire)?primary_maxRange:secondary_maxRange), 0.0, m_bTargetPrimaryFire); params.AttackCheckBlocked = false; // Setup the movement parameters if we want to persue the target @@ -569,16 +657,20 @@ //fprintf( debugFile, "Seen enemy %s\n", Commands->Get_Preset_Name(enemy) ); // If this is our current target update it's last seen time and priority - if (Commands->Get_ID(enemy) == targetID) + if (enemy == m_target) { targetLastSeen = (int)time(NULL); - targetPriority = getPriority(obj, targetID); + targetPriority = getPriority(obj, m_target); return; } + // Update current target priority (needed due to linked hp objects) + if (m_target) + targetPriority = getPriority(obj, m_target); + // Get priority for seen object and return if 0 or lower than current target float seenPriority = getPriority( obj, enemy ); - if (seenPriority == 0.0 || (targetID!=0 && seenPriority <= targetPriority)) + if (seenPriority == 0.0 || (m_target && seenPriority <= targetPriority)) return; //fprintf( debugFile, "Higher priority than existing target... attacking!\n" ); @@ -588,6 +680,9 @@ return; // All good, attack the enemy + m_target = enemy; + hasTarget = true; + targetLastSeen = (int)time(NULL); AttackTarget(obj, enemy); } @@ -608,8 +703,8 @@ int maxRange = attackPrimary ? primary_maxRange : secondary_maxRange; return 0.0f < Commands->Get_Health(target) - && 2 != Commands->Get_Player_Type(target) - && Commands->Get_Player_Type(target) != Commands->Get_Player_Type(obj) + && SCRIPT_PLAYERTYPE_NEUTRAL != Get_Object_Type(target) + && (Get_Object_Type(target) != Get_Object_Type(obj) || GetTargetType(target) == REPAIRABLE) && targetDistance >= minRange && (ShouldPursueTarget(obj, target) || targetDistance <= maxRange); } @@ -618,9 +713,10 @@ dp88_AI_Objective* dp88_AI_Tank_Offensive::ChooseNewObjective(GameObject* obj) { - dp88_AI_Objective* pObjective = dp88_AI_Objective::GetBestObjective(obj, dp88_AI_Objective::TYPE_OFFENSIVE, modifier_distance); + DynamicVectorClass ignoredObjectives; + dp88_AI_Objective* pObjective = dp88_AI_Objective::GetBestObjective(obj, dp88_AI_Objective::TYPE_OFFENSIVE, modifier_distance, ignoredObjectives); if (NULL == pObjective) - pObjective = dp88_AI_Objective::GetBestObjective(obj, dp88_AI_Objective::TYPE_DEFENSIVE, modifier_distance); + pObjective = dp88_AI_Objective::GetBestObjective(obj, dp88_AI_Objective::TYPE_DEFENSIVE, modifier_distance, ignoredObjectives); return pObjective; } @@ -688,7 +784,7 @@ if ( debug ) fprintf( debugFile, "Seen an enemy: %d (%s)\n", Commands->Get_ID(enemy), Commands->Get_Preset_Name(enemy) ); // If this is our current target update last seen time and priority - if ( Commands->Get_ID ( enemy ) == targetID ) + if ( enemy == m_target ) { if ( debug ) fprintf( debugFile, "Enemy is current target, last seen time and priority updated\n" ); targetLastSeen = (int)time(NULL); @@ -724,12 +820,13 @@ // If this is a higher priority than our current target attack it - if ( targetID == 0 || enemyPriority > targetPriority ) + if ( !m_target || enemyPriority > targetPriority ) { - if ( debug && targetID == 0 ) fprintf ( debugFile, "No current target to compare with, attacking enemy!\n" ); + if ( debug && !m_target ) fprintf ( debugFile, "No current target to compare with, attacking enemy!\n" ); else if ( debug ) fprintf ( debugFile, "New enemy has a higher priority than current target, attacking enemy\n" ); - targetID = Commands->Get_ID ( enemy ); + m_target = enemy; + hasTarget = true; targetLastSeen = (int)time(NULL); targetPriority = enemyPriority; m_bTargetPrimaryFire = attackPrimary; @@ -768,18 +865,18 @@ // Check target is still alive, still an enemy (eg: stolen vehicles) and in range if ( number == TIMER_AI_THINK ) { - if ( targetID != 0 ) + if ( hasTarget ) { - GameObject *target = Commands->Find_Object ( targetID ); - if (!target || !checkPowerState(obj) - || ( Commands->Get_Health ( target ) + Commands->Get_Shield_Strength ( target ) <= 0 ) - || !checkTeam ( obj, target ) - || !checkRange ( obj, target, m_bTargetPrimaryFire ) + if (!m_target || !checkPowerState(obj) + || ( Commands->Get_Health ( m_target ) + Commands->Get_Shield_Strength ( m_target ) <= 0 ) + || !checkTeam ( obj, m_target ) + || !checkRange ( obj, m_target, m_bTargetPrimaryFire ) || (int)time(NULL) - targetLastSeen > 3 - || ( target->As_VehicleGameObj() && !IsVehicleAIEnabled(target->As_VehicleGameObj()) && IsVehicleEmpty(target->As_VehicleGameObj()) )) + || ( m_target->As_VehicleGameObj() && !IsVehicleAIEnabled(m_target->As_VehicleGameObj()) && IsVehicleEmpty(m_target->As_VehicleGameObj()) )) { - if ( debug ) fprintf ( debugFile, "Target %d no longer valid, ceasing attack.\n", targetID); - targetID = 0; + if ( debug ) fprintf ( debugFile, "Target %d no longer valid, ceasing attack.\n", m_target->Get_ID()); + m_target = nullptr; + hasTarget = false; targetPriority = 0.0f; targetLastSeen = 0; stopAttacking(obj); @@ -787,15 +884,15 @@ // Otherwise we are OK to continue attacking... if this is an infantry unit // and splash targetting is enabled then update targetting position - else if ( splashInfantry && target->As_SoldierGameObj()) + else if ( splashInfantry && m_target->As_SoldierGameObj()) { - if(obj->As_SmartGameObj()->Is_Splash_Possible(target->As_PhysicalGameObj())) + if(obj->As_SmartGameObj()->Is_Splash_Possible(m_target->As_PhysicalGameObj())) { - attackLocation ( obj, Commands->Get_Position(target), m_bTargetPrimaryFire ); + attackLocation ( obj, Commands->Get_Position(m_target), m_bTargetPrimaryFire ); } else { - attackLocation ( obj, target->As_SoldierGameObj()->Get_Bullseye_Position(), m_bTargetPrimaryFire ); + attackLocation ( obj, m_target->As_SoldierGameObj()->Get_Bullseye_Position(), m_bTargetPrimaryFire ); } } } @@ -969,11 +1066,11 @@ if ( number == TIMER_AI_THINK && m_deploymentState == STATE_DEPLOYED ) { // If we have no target and have reached the undeploy timeout then trigger undeployment - if ( targetID == 0 && time(NULL) > m_undeployTime ) + if ( !m_target && time(NULL) > m_undeployTime ) Undeploy(pSelf); // Else, if we have an active target, update the undeployment timeout time - else if ( targetID != 0 ) + else if ( m_target ) m_undeployTime = time(NULL)+Get_Int_Parameter("Deploy_Timeout"); } @@ -1008,7 +1105,8 @@ // Reset targetting parameters, otherwise the next Enemy_Seen call will think we are already attacking // an enemy and not trigger the appropriate actions we are depending upon - targetID = 0; + m_target = nullptr; + hasTarget = false; } else if ( m_deploymentState == STATE_UNDEPLOYING ) m_deploymentState = STATE_UNDEPLOYED; @@ -1185,7 +1283,7 @@ // todo: set bpreloading as appropriate - if (NULL != targetID) + if (m_target) StartCharging(pSelf); else ApplyIdleAnimation(pSelf); @@ -1193,7 +1291,7 @@ // Has our target already died or ran like a coward before we could empty our clip? If so then // reset and trigger a reload (so we don't have a partial charge next time round) - else if (NULL == targetID) + else if (!m_target) { m_bIsDischarging = false; Set_Current_Bullets(pSelf, 0); @@ -1208,7 +1306,7 @@ if (number == TIMER_AI_CHARGE_PRERELOAD_COMPLETE && m_bIsPreReloading) { m_bIsPreReloading = false; - if (NULL != targetID) + if (m_target) StartCharging(pSelf); } @@ -1289,7 +1387,7 @@ { // If we are not charging, not discharging, powered and have a target then we can start a new // charging cycle - if (!m_bIsPreReloading && !m_bIsCharging && !m_bIsDischarging && checkPowerState(pSelf) && targetID != NULL) + if (!m_bIsPreReloading && !m_bIsCharging && !m_bIsDischarging && checkPowerState(pSelf) && m_target) { m_bIsCharging = true; @@ -1315,18 +1413,15 @@ m_bIsCharging = false; // Got an enemy? Also double check power state whilst we are here, just to be sure - if (targetID != NULL && checkPowerState(pSelf)) + if (m_target && checkPowerState(pSelf)) { - if (GameObject* pTarget = Commands->Find_Object(targetID)) - { m_bIsDischarging = true; // Call into the base class and let it do it's thing - if (splashInfantry && pTarget->As_SoldierGameObj()) - dp88_AI_Turret::attackLocation(pSelf, Commands->Get_Position(pTarget), m_bTargetPrimaryFire); + if (splashInfantry && m_target->As_SoldierGameObj()) + dp88_AI_Turret::attackLocation(pSelf, Commands->Get_Position(m_target), m_bTargetPrimaryFire); else - dp88_AI_Turret::attackTarget(pSelf, pTarget, m_bTargetPrimaryFire); - } + dp88_AI_Turret::attackTarget(pSelf, m_target, m_bTargetPrimaryFire); } // If we didn't find anything to shoot at then apply the idle animation again @@ -1429,13 +1524,17 @@ void dp88_AI_Objective::Created ( GameObject* obj ) { // Register objective - m_objID = Commands->Get_ID(obj); + //m_objID = Commands->Get_ID(obj); Objectives.Add(this); // Store data - m_type = (unsigned char)Get_Int_Parameter("Type"); + m_type = (unsigned int)Get_Int_Parameter("Type"); m_range = Get_Int_Parameter("Range"); m_team = Get_Int_Parameter("Team"); + m_debugTag = Get_Parameter("Debug_Tag"); + if (strlen(m_debugTag) == 0) { + m_debugTag = "No Tag"; + } m_priority[UNITTYPE_SOLDIER] = Get_Int_Parameter("Priority_Soldier"); m_priority[UNITTYPE_LVEHICLE] = Get_Int_Parameter("Priority_Light_Vehicle"); @@ -1451,13 +1550,24 @@ // De-register objective if (Exe != EXE_LEVELEDIT) Objectives.DeleteObj(this); + + // delete references to this objective from AI units so they don't try to access our memory after it's freed + for (int i = 0; i < dp88_AI_Unit::ListOfAIUnits.Count(); i++) + { + dp88_AI_Unit *unit = dp88_AI_Unit::ListOfAIUnits[i]; + if (unit->Get_Current_Objective() == this) + unit->Force_Clear_Current_Objective(); + } } // ------------------------------------------------------------------------------------------------- GameObject* dp88_AI_Objective::GetGameObject() { - return Commands->Find_Object(m_objID); + // NOTE: We no longer need to store object IDs since the objective script itself is destroyed when its owner is destroyed anyways. + // The objective is removed from all AI units when destroyed (see Detach()), so we don't need to do lookups at all. + return Owner(); + // return Commands->Find_Object(m_objID); } // ------------------------------------------------------------------------------------------------- @@ -1472,7 +1582,7 @@ if (obj->As_VehicleGameObj()) { - if (Is_Script_Attached(obj, "dp88_AI_heavyVehicleMarker")) + if (Is_Script_Attached(obj, "dp88_AI_heavyVehicleMarker") || Is_Script_Attached(obj, "dp88_AI_Marker_HeavyVehicle")) return UNITTYPE_HVEHICLE; return UNITTYPE_LVEHICLE; } @@ -1500,22 +1610,25 @@ // ------------------------------------------------------------------------------------------------- -dp88_AI_Objective* dp88_AI_Objective::GetBestObjective(GameObject* obj, unsigned char objective_type, float distance_modifier) +dp88_AI_Objective* dp88_AI_Objective::GetBestObjective(GameObject* obj, unsigned int objective_type, float distance_modifier, DynamicVectorClass ignoredObjectives) { dp88_AI_Objective* result = NULL; float top_priority = 0.0f; + float best_distance = FLT_MAX; int team = Get_Object_Type(obj); for ( int i = 0; i < Objectives.Count(); ++i ) { int objTeam = Objectives[i]->GetTeam(); - if (objective_type != Objectives[i]->GetType() || (objTeam != 2 && team != objTeam)) + if (objective_type != Objectives[i]->GetType() || (objTeam != 2 && team != objTeam) || (ignoredObjectives.Length() && ignoredObjectives.ID(Objectives[i]->GetGameObject()->Get_ID()) != -1)) continue; float priority = Objectives[i]->GetPriority(obj, distance_modifier); - if( priority > top_priority ) + float distance = Vector3::Distance_Squared(Commands->Get_Position(obj), Commands->Get_Position(Objectives[i]->GetGameObject())); + if( priority > top_priority || (priority > 0 && priority == top_priority && distance < best_distance) ) { top_priority = priority; + best_distance = distance; result = Objectives[i]; } } @@ -1525,6 +1638,40 @@ // ------------------------------------------------------------------------------------------------- +int dp88_AI_Objective::CountObjectives(int team, unsigned int objective_type) +{ + int count = 0; + + for (int i = 0; i < Objectives.Count(); ++i) + { + int objTeam = Objectives[i]->GetTeam(); + if (objective_type != Objectives[i]->GetType() || (objTeam != 2 && team != objTeam)) + continue; + count++; + } + + return count; +} + +// ------------------------------------------------------------------------------------------------- + +int dp88_AI_Objective::CountUnitObjectives(int team, unsigned int objective_type, GameObject* obj, float distance_modifier) +{ + int count = 0; + + for (int i = 0; i < Objectives.Count(); ++i) + { + int objTeam = Objectives[i]->GetTeam(); + if (objective_type != Objectives[i]->GetType() || (objTeam != 2 && team != objTeam) || Objectives[i]->GetPriority(obj, distance_modifier) == 0) + continue; + count++; + } + + return count; +} + +// ------------------------------------------------------------------------------------------------- + bool dp88_AI_Objective::IsValidObjective(dp88_AI_Objective* pObjective) { for ( int i = 0; i < Objectives.Count(); ++i ) @@ -1546,7 +1693,8 @@ "Priority_Soldier=1:int," "Priority_Light_Vehicle=1:int," "Priority_Heavy_Vehicle=1:int," - "Priority_Aircraft=1:int"); + "Priority_Aircraft=1:int," + "Debug_Tag:string"); @@ -1557,9 +1705,18 @@ // Script Registrants // ------------------------------------------------------------------------------------------------- -// Heavy vehicle marker (dummy script) +// Heavy vehicle marker (dummy script, deprecated ) ScriptRegistrant dp88_AI_heavyVehicleMarker_Registrant("dp88_AI_heavyVehicleMarker",""); +// Building marker (dummy script) +ScriptRegistrant dp88_AI_Marker_Building_Registrant("dp88_AI_Marker_Building",""); + +// Heavy vehicle marker (dummy script) +ScriptRegistrant dp88_AI_Marker_HeavyVehicle_Registrant("dp88_AI_Marker_HeavyVehicle",""); + +// Repair target marker (dummy script) +ScriptRegistrant dp88_AI_Marker_Repairable_Registrant("dp88_AI_Marker_Repairable","Pathfind_Distance=5.0:float"); + ScriptRegistrant dp88_AI_Turret_Registrant("dp88_AI_Turret","Priority_Infantry=1.0:float,Weapon_Infantry=1:int,Splash_Infantry=0:int,Priority_Light_Vehicle=5.0:float,Weapon_Light_Vehicle=1:int,Priority_Heavy_Vehicle=7.0:float,Weapon_Heavy_Vehicle=1:int,Priority_VTOL=5.0:float,Weapon_VTOL=1:int,Min_Attack_Range=0:int,Max_Attack_Range=150:int,Min_Attack_Range_Secondary=0:int,Max_Attack_Range_Secondary=150:int,Modifier_Distance=0.25:float,Modifier_Target_Damage=0.1:float,Modifier_Target_Value=0.05:float,Requires_Power=0:int,Debug=0:int,Detects_Stealth=1:int"); ScriptRegistrant dp88_AI_PopupTurret_Registrant("dp88_AI_PopupTurret","Priority_Infantry=1.0:float,Weapon_Infantry=1:int,Splash_Infantry=0:int,Priority_Light_Vehicle=5.0:float,Weapon_Light_Vehicle=1:int,Priority_Heavy_Vehicle=7.0:float,Weapon_Heavy_Vehicle=1:int,Priority_VTOL=5.0:float,Weapon_VTOL=1:int,Min_Attack_Range=0:int,Max_Attack_Range=150:int,Min_Attack_Range_Secondary=0:int,Max_Attack_Range_Secondary=150:int,Deploy_Animation:string,Deploy_Animation_Frames:int,Deploy_Sound:string,Deploy_Timeout:int,Spotter_Preset:string,Modifier_Distance=0.25:float,Modifier_Target_Damage=0.1:float,Modifier_Target_Value=0.05:float,Requires_Power=0:int,Debug=0:int,Detects_Stealth=1:int"); ScriptRegistrant dp88_AI_PopupTurret_Spotter_Registrant("dp88_AI_PopupTurret_Spotter","tId:int"); diff -urN sourceold/scripts/dp88_customAI.h source/scripts/dp88_customAI.h --- sourceold/scripts/dp88_customAI.h 2018-11-17 10:23:57.146600000 +1000 +++ source/scripts/dp88_customAI.h 2020-09-10 09:08:27.952893600 +1000 @@ -13,8 +13,24 @@ #include "LoopedAnimationController.h" #include "ObserverImpClass.h" +#include "ReferencerClass.h" + +class ActionParamsStruct; + +class Pathfind_Help_Implementer +{ +public: + virtual ~Pathfind_Help_Implementer() {}; + virtual bool Should_Ignore_Blocked_Checking(GameObject *obj) = 0; + virtual void Prepare_Getting_Around(GameObject *obj) = 0; + virtual void Stop_Getting_Around(GameObject *obj) = 0; + virtual void On_Unable_To_Get_Unstuck(GameObject *obj) = 0; + // Modify action params during getting unstuck to include target shooting, if any exist + virtual ActionParamsStruct Get_Param_Attack_Modifications(ActionParamsStruct params) = 0; +}; // Forward declaration +class VehicleGameObj; class dp88_AI_Objective; class dp88_AI_ChargedTurret_AnimationObserver; @@ -72,11 +88,16 @@ int secondary_minRange, secondary_maxRange; // Current target state - int targetID; + //int targetID; + ReferencerClass m_target; + bool hasTarget; int targetLastSeen; float targetPriority; bool m_bTargetPrimaryFire; + // Brain speed + float thinkTime; + // Other settings bool m_bAiEnabled; bool m_bCanDetectStealth; @@ -85,6 +106,16 @@ bool debug; FILE* debugFile; + // Target types + enum TargetType { + SOLDIER = 0, + LIGHT_VEHICLE, + HEAVY_VEHICLE, + FLYING, + BUILDING, + REPAIRABLE, + UNKNOWN + }; @@ -126,11 +157,40 @@ /* Utility functions for both priority calculations and AI scripts to utilise */ virtual bool IsVehicleEmpty( VehicleGameObj* vobj ); virtual bool IsVehicleAIEnabled( VehicleGameObj* vobj ); + + // "Global" decider about what a unit type is + static TargetType GetTargetType(GameObject* obj); +}; + +// ------------------------------------------------------------------------------------------------- + +/*! +* \brief danpaul88's Custom AI Heavy Vehicle Marker +* \author Daniel Paul (danpaul88@yahoo.co.uk) +* +* This is a dummy script with no functionality which can be attached to an object to indicate all of +* my custom AI scripts should treat this as a heavy vehicle. Any vehicle without this script will be +* considered to be a light vehicle. +*/ +class dp88_AI_heavyVehicleMarker : public ScriptImpClass +{ + void Created(GameObject* obj); }; // ------------------------------------------------------------------------------------------------- /*! +* \brief danpaul88's Custom AI Building Marker +* \author Daniel Paul (danpaul88@yahoo.co.uk) +* +* This is a dummy script with no functionality which can be attached to an object to indicate all of +* my custom AI scripts should treat this as a building. +*/ +class dp88_AI_Marker_Building : public ScriptImpClass {}; + +// ------------------------------------------------------------------------------------------------- + +/*! * \brief danpaul88's Custom AI Heavy Vehicle Marker * \author Daniel Paul (danpaul88@yahoo.co.uk) * @@ -138,7 +198,25 @@ * my custom AI scripts should treat this as a heavy vehicle. Any vehicle without this script will be * considered to be a light vehicle. */ -class dp88_AI_heavyVehicleMarker : public ScriptImpClass{}; +class dp88_AI_Marker_HeavyVehicle : public ScriptImpClass {}; + +// ------------------------------------------------------------------------------------------------- + +/*! +* \brief danpaul88's Custom AI Repair Target Marker +* \author Daniel Paul (danpaul88@yahoo.co.uk) +* +* This is a dummy script with no functionality which can be attached to an object to indicate all of +* my custom AI scripts should treat this as a repair target. +*/ +class dp88_AI_Marker_Repairable : public ScriptImpClass +{ +public: + void Created(GameObject* obj); + float Get_Distance_From_Pathfind(); +protected: + float pathfindDistance; +}; // ------------------------------------------------------------------------------------------------- @@ -154,6 +232,7 @@ public: // Game Events void Created(GameObject *obj); + void Detach(GameObject *obj); void Timer_Expired(GameObject *obj, int number); void Action_Complete(GameObject *obj, int action_id, ActionCompleteReason reason); @@ -161,6 +240,12 @@ virtual void Init(GameObject *obj); virtual void loadSettings(GameObject *obj, bool loadSecondaryFireSettings, bool loadBuildingTargetSettings); + virtual void Force_Clear_Current_Objective(); + dp88_AI_Objective* Get_Current_Objective() { return m_pCurrentObjective; } + + // used in combination with Force_Clear_Current_Objective() to invalidate references to objectives when they are deleted (prevents use-after-free bugs) + static DynamicVectorClass ListOfAIUnits; + protected: static const int ACTION_ID_MOVE_TO_OBJECTIVE = 7850001; static const int ACTION_ID_ATTACK_TARGET = 7850002; @@ -169,7 +254,7 @@ void ResetAllActions(GameObject* obj); // Go to the location of the current objective - virtual void GoToObjective(GameObject *obj); + virtual void GoToObjective(GameObject *obj, float speed = 1.0f); // Attack the specified target virtual void AttackTarget(GameObject *obj, GameObject *target); @@ -746,9 +831,10 @@ GameObject* GetGameObject(); - unsigned char GetType() { return m_type; } + unsigned int GetType() { return m_type; } int GetTeam() { return m_team; } int GetRange() { return m_range; } + const char* GetDebugTag() { return m_debugTag; } /*! Get the priority of this objective for the specified AI unit */ float GetPriority(GameObject* obj, float distance_modifier); @@ -757,16 +843,26 @@ * Finds the most suitable objective of a given type for the specified unit, based on the distance * to the objective and their distance modifier */ - static dp88_AI_Objective* GetBestObjective ( GameObject* obj, unsigned char objective_type, float distance_modifier ); + static dp88_AI_Objective* GetBestObjective ( GameObject* obj, unsigned int objective_type, float distance_modifier, DynamicVectorClass ignoredObjectives ); + + /*! + * Counts the existing objectives of a given type for the specified team + */ + static int CountObjectives( int team, unsigned int objective_type ); + + /*! + * Counts the existing valid objectives of a given type for the specified unit + */ + static int CountUnitObjectives( int team, unsigned int objective_type, GameObject* obj, float distance_modifier ); /*! Checks if the specified objective is still valid */ static bool IsValidObjective ( dp88_AI_Objective* pObjective ); /*! \name Objective types */ /*! @{ */ - const static unsigned char TYPE_OFFENSIVE = 1; - const static unsigned char TYPE_DEFENSIVE = 2; - const static unsigned char TYPE_ENGINEERING = 3; + const static unsigned int TYPE_OFFENSIVE = 1; + const static unsigned int TYPE_DEFENSIVE = 2; + const static unsigned int TYPE_ENGINEERING = 3; /*! @} */ protected: @@ -783,14 +879,15 @@ /*! Get the unit type of the specified unit */ unsigned char GetUnitType(GameObject* obj); - int m_objID;; + //int m_objID;; /*! \name Cached Script Parameters */ /*! @{ */ - unsigned char m_type; + unsigned int m_type; int m_priority[UNITTYPE_MAX + 1]; int m_range; int m_team; + const char* m_debugTag; /*! @} */ static DynamicVectorClass Objectives; diff -urN sourceold/scripts/dp88_custom_timer_defines.h source/scripts/dp88_custom_timer_defines.h --- sourceold/scripts/dp88_custom_timer_defines.h 2018-11-17 10:23:57.147600000 +1000 +++ source/scripts/dp88_custom_timer_defines.h 2020-09-10 09:08:27.952893600 +1000 @@ -46,6 +46,7 @@ #define CUSTOM_ROCKETEER_VEHICLEKILLED (DP88_CUSTOM|MISC|0x03) //!< Used by dp88_AR_Rocketeer to notify itself when the flight vehicle dies (via JFW_Death_Send_Custom) #define CUSTOM_VEHICLE_DEPLOY (DP88_CUSTOM|MISC|0x04) //!< Used by deployable vehicle scripts to notify other scripts of a change in the deployment state, 0 = undeployed, 1 = deploying, 2 = deployed, 3 = undeploying #define CUSTOM_RADAR_JAM (DP88_CUSTOM|MISC|0x05) //!< Used by new Radar Jammer scripts to switch radar off and on and also play jamming sounds, 0 = radar off, 1 = radar on +#define CUSTOM_DEPLOY_STATE_CHANGED (DP88_CUSTOM|MISC|0x07) //!< Used by deployable scripts to notify other scripts of a change in the deployment state, 0 = undeployed, 1 = deployed #define TIMER_MISC_TICK (DP88_TIMER|MISC|0x01) //!< Miscellaneous tick timer for generic use by scripts that implement on-tick events #define TIMER_RANDOMWEATHER (DP88_TIMER|MISC|0x02) //!< Used by dp88_randomWeather to do a weather update @@ -136,6 +137,7 @@ //#define CUSTOM_TURRETAI_ANIMATIONCOMPLETE (DP88_CUSTOM|AI|0x02) //!< Sent from dp88_AI_ChargeTurret_Animation to dp88_AI_ChargeTurret #define CUSTOM_AI_DISABLEAI (DP88_CUSTOM|AI|0x03) //!< Custom message that can be sent to a turret AI to disable it #define CUSTOM_AI_ENABLEAI (DP88_CUSTOM|AI|0x04) //!< Custom message that can be sent to a turret AI to enable it +#define CUSTOM_AI_RESET_ACTIONS (DP88_CUSTOM|AI|0x05) //!< Custom message that can be sent to an AI to reset its current actions #define TIMER_AI_THINK (DP88_TIMER|AI|0x01) //!< Fires every second to process AI actions such as checking target status #define TIMER_AI_CHARGE_PRERELOAD_COMPLETE (DP88_TIMER|AI|0x02) //!< Used by dp88_AI_ChargedTurret to indicate when pre-reloading is complete @@ -171,6 +173,10 @@ #define CUSTOM_PRISMTOWER_STOP_CHARGING 1144060002 +// Custom for changing bot count on a map +#define CUSTOM_AI_CHANGE_BOTCOUNT 1144062001 +#define CUSTOM_AI_CHANGE_BOTCOUNTTEAM 1144062002 + #define TIMER_CLEG_PHASEDEATH 10055222 #define TIMER_CLEG_CHECKDROPOBJ 10055223 #define TIMER_CLEG_CHECKRELEASETARGET 10055224 diff -urN sourceold/scripts/engine_common.h source/scripts/engine_common.h --- sourceold/scripts/engine_common.h 2018-11-17 10:23:57.154600000 +1000 +++ source/scripts/engine_common.h 2020-04-02 12:02:44.438361500 +1000 @@ -15,7 +15,7 @@ // (float) is merely there to make sure that it uses the float overloads to send the version over network. // and to make sure we do not forget the f suffix on the version number. #define TT_VERSION_MAGIC '!TT!' -#define TT_VERSION ((float)4.6f) +#define TT_VERSION ((float)4.7f) #define SAFE_DELETE_ARRAY(p) { delete[] p; p = NULL; } #define SAFE_DELETE(p) { delete p; p = NULL; } diff -urN sourceold/scripts/engine_dmg.cpp source/scripts/engine_dmg.cpp --- sourceold/scripts/engine_dmg.cpp 2018-11-17 10:23:57.156600000 +1000 +++ source/scripts/engine_dmg.cpp 2020-09-10 09:08:27.953899600 +1000 @@ -161,6 +161,20 @@ Commands->Set_Health(obj,health); } +void SCRIPTS_API Set_Max_Health_Without_Healing(GameObject *obj,float health) +{ + if (!obj) + { + return; + } + DamageableGameObj *o = obj->As_DamageableGameObj(); + if (!o) + { + return; + } + o->Get_Defense_Object()->Set_Health_Max(health); +} + void SCRIPTS_API Set_Max_Shield_Strength(GameObject *obj,float shieldstrength) { if (!obj) @@ -176,6 +190,20 @@ Commands->Set_Shield_Strength(obj,shieldstrength); } +void SCRIPTS_API Set_Max_Shield_Strength_Without_Healing(GameObject *obj,float shieldstrength) +{ + if (!obj) + { + return; + } + DamageableGameObj *o = obj->As_DamageableGameObj(); + if (!o) + { + return; + } + o->Get_Defense_Object()->Set_Shield_Strength_Max(shieldstrength); +} + const char SCRIPTS_API *Get_Shield_Type(GameObject *obj) { if (!obj) @@ -226,6 +254,8 @@ { return; } + Vector3 TestPosition = Position; + TestPosition.Z = 0; SLNode *x = GameObjManager::VehicleGameObjList.Head(); while (x) { @@ -233,10 +263,9 @@ if (obj) { Vector3 ObjPosition = Commands->Get_Position(obj); - Vector3 TestPosition = Position; + ObjPosition.Z = 0; - TestPosition.Z = 0; - if ((Commands->Get_Distance(ObjPosition,TestPosition) <= Distance) && (Commands->Get_ID(obj) != Commands->Get_ID(Host))) + if ((Vector3::Distance_Squared(ObjPosition, TestPosition) <= Distance * Distance) && (Commands->Get_ID(obj) != Commands->Get_ID(Host))) { Commands->Apply_Damage(obj,Damage,Warhead,Damager); } @@ -251,6 +280,8 @@ { return; } + Vector3 TestPosition = Position; + TestPosition.Z = 0; SLNode *x = GameObjManager::GameObjList.Head(); while (x) { @@ -263,10 +294,8 @@ if (o2) { Vector3 ObjPosition = Commands->Get_Position(o2); - Vector3 TestPosition = Position; ObjPosition.Z = 0; - TestPosition.Z = 0; - if ((Commands->Get_Distance(ObjPosition,TestPosition) <= Distance) && (Commands->Get_ID(o2) != Commands->Get_ID(Host))) + if ((Vector3::Distance_Squared(ObjPosition, TestPosition) <= Distance * Distance) && (Commands->Get_ID(o2) != Commands->Get_ID(Host))) { Commands->Apply_Damage(o2,Damage,Warhead,Damager); } @@ -289,7 +318,7 @@ { Vector3 ObjPosition = Commands->Get_Position(o); Vector3 TestPosition = Position; - if (Commands->Get_Distance(ObjPosition,TestPosition) <= Distance) + if (Vector3::Distance_Squared(ObjPosition, TestPosition) <= Distance * Distance) { Commands->Apply_Damage(o,Damage,Warhead,Damager); } @@ -316,9 +345,7 @@ Vector3 pos1 = Commands->Get_Position(o); Vector3 pos2 = Location; - float Distance = Commands->Get_Distance(pos1,pos2); - - if (Distance <= DamageRadius) + if (Vector3::Distance_Squared(pos1, pos2) <= DamageRadius * DamageRadius) { Commands->Apply_Damage(o,Damage,Warhead,Damager); } @@ -377,9 +404,7 @@ Vector3 pos1 = Commands->Get_Position(o); Vector3 pos2 = Location; - float Distance = Commands->Get_Distance(pos1,pos2); - - if (Distance <= DamageRadius) + if (Vector3::Distance_Squared(pos1, pos2) <= DamageRadius * DamageRadius) { float Max_Health = Commands->Get_Max_Health(o); float Damage = Max_Health*Percentage; @@ -409,8 +434,7 @@ { Vector3 pos1 = Commands->Get_Position(o); Vector3 pos2 = Location; - float Distance = Commands->Get_Distance(pos1,pos2); - if (Distance <= DamageRadius) + if (Vector3::Distance_Squared(pos1, pos2) <= DamageRadius * DamageRadius) { Commands->Apply_Damage(o,Damage,Warhead,Damager); } @@ -472,8 +496,7 @@ { Vector3 pos1 = Commands->Get_Position(o); Vector3 pos2 = Location; - float Distance = Commands->Get_Distance(pos1,pos2); - if (Distance <= DamageRadius) + if (Vector3::Distance_Squared(pos1, pos2) <= DamageRadius * DamageRadius) { float Max_Health = Commands->Get_Max_Health(o); float Damage = Max_Health*Percentage; @@ -517,8 +540,8 @@ { Vector3 pos1 = Commands->Get_Position(o); Vector3 pos2 = Location; - float Distance = Commands->Get_Distance(pos1,pos2); - if (Distance <= DamageRadius) + float Distance = Vector3::Distance_Squared(pos1, pos2); + if (Distance <= DamageRadius * DamageRadius) { float Max_Health = Commands->Get_Max_Health(o); float Max_Shield = Commands->Get_Max_Shield_Strength(o); @@ -576,8 +599,8 @@ { Vector3 pos1 = Commands->Get_Position(o); Vector3 pos2 = Location; - float Distance = Commands->Get_Distance(pos1,pos2); - if (Distance <= Radius) + float Distance = Vector3::Distance_Squared(pos1, pos2); + if (Distance <= Radius * Radius) { Commands->Set_Health(o,(amount+Health)); } @@ -719,8 +742,8 @@ { Vector3 pos1 = Commands->Get_Position(o); Vector3 pos2 = Location; - float Distance = Commands->Get_Distance(pos1,pos2); - if (Distance <= DamageRadius) + float Distance = Vector3::Distance_Squared(pos1, pos2); + if (Distance <= DamageRadius * DamageRadius) { float Max_Health = Commands->Get_Max_Health(o); float Max_Shield = Commands->Get_Max_Shield_Strength(o); @@ -767,8 +790,8 @@ { Vector3 pos1 = Commands->Get_Position(o); Vector3 pos2 = Location; - float Distance = Commands->Get_Distance(pos1, pos2); - if (Distance <= DamageRadius) + float Distance = Vector3::Distance_Squared(pos1, pos2); + if (Distance <= DamageRadius * DamageRadius) { float Max_Health = Commands->Get_Max_Health(o); float Max_Shield = Commands->Get_Max_Shield_Strength(o); diff -urN sourceold/scripts/engine_dmg.h source/scripts/engine_dmg.h --- sourceold/scripts/engine_dmg.h 2016-10-31 07:17:12.471013500 +1000 +++ source/scripts/engine_dmg.h 2020-03-30 20:42:37.433301100 +1000 @@ -15,7 +15,9 @@ void SCRIPTS_API Repair_All_Buildings_By_Team(int Team,int ConstructionYardID,float Health); //repairs all buildings for the team except the passed in ConstructionYardID,0 = Nod,1 = GDI void SCRIPTS_API Repair_All_Static_Vehicles_By_Team(int Team,int type); //sends a custom to all vechicles of the team with the DecorationPhys physics type (i.e. all base defense vechicles etc),0 = Nod,1 = GDI,Message is the message to send. Use with JFW_Repair_On_Custom on the vechicles you want repaired to do the actual repairing void SCRIPTS_API Set_Max_Health(GameObject *obj,float health); //set the max health of obj +void SCRIPTS_API Set_Max_Health_Without_Healing(GameObject *obj,float health); //set the max health of obj without setting the actual health to maximum void SCRIPTS_API Set_Max_Shield_Strength(GameObject *obj,float shieldstrength); //set the max shield strength of obj +void SCRIPTS_API Set_Max_Shield_Strength_Without_Healing(GameObject *obj,float shieldstrength); //set the max shield strength of obj without setting the actual health to maximum const char SCRIPTS_API *Get_Shield_Type(GameObject *obj); //gets the shield type of obj const char SCRIPTS_API *Get_Skin(GameObject *obj); //gets the skin type of obj void SCRIPTS_API Set_Skin(GameObject *obj,const char *Skintype); //sets the skin type of obj diff -urN sourceold/scripts/engine_io.cpp source/scripts/engine_io.cpp --- sourceold/scripts/engine_io.cpp 2018-11-17 10:23:57.160600000 +1000 +++ source/scripts/engine_io.cpp 2020-09-10 09:08:27.953899600 +1000 @@ -565,6 +565,26 @@ strtrim(result); return (int)strlen(result); } +int INIClass::Get_String_Advanced(char const *section,char const *entry,char const *defaultvalue,char *result,int size,bool updateIfNotFound) const +{ + if (!result || size <= 1 || !section || !entry) + return 0; + INIEntry *Entry = Find_Entry(section,entry); + const char *value = defaultvalue; + if (Entry && Entry->Value) + value = Entry->Value; + if ((!Entry || !Entry->Value) && !updateIfNotFound) + return 0; + if (!value) + { + result[0] = 0; + return 0; + } + strncpy(result, value, size); + result[size - 1] = 0; + strtrim(result); + return (int)strlen(result); +} int INIClass::Entry_Count(char const *section) const { INISection *Section = Find_Section(section); diff -urN sourceold/scripts/engine_io.h source/scripts/engine_io.h --- sourceold/scripts/engine_io.h 2018-11-17 10:23:57.161600000 +1000 +++ source/scripts/engine_io.h 2020-09-10 09:08:27.954910800 +1000 @@ -132,6 +132,7 @@ float Get_Float(char const *section,char const *entry,float defaultvalue) const; bool Get_Bool(char const *section,char const *entry,bool defaultvalue) const; int Get_String(char const *section,char const *entry,char const *defaultvalue,char *result,int size) const; + int Get_String_Advanced(char const *section,char const *entry,char const *defaultvalue,char *result,int size,bool writeIfNotFound) const; StringClass &Get_String(StringClass &str, const char* section, const char* entry, const char* default = 0) const; WideStringClass &Get_Wide_String(WideStringClass &,char const*,char const*,wchar_t const*) const; bool Put_Wide_String(const char* section, const char* entry, const wchar_t* string); diff -urN sourceold/scripts/engine_obj.cpp source/scripts/engine_obj.cpp --- sourceold/scripts/engine_obj.cpp 2018-11-17 10:23:57.163600000 +1000 +++ source/scripts/engine_obj.cpp 2020-09-10 09:08:27.954910800 +1000 @@ -403,7 +403,7 @@ GameObject SCRIPTS_API *Find_Closest_Non_Building_Object_By_Team(int Team,Vector3 position) { - float closestdist = FLT_MAX; + float closestdist_sq = FLT_MAX; GameObject *closest = 0; SLNode *x = GameObjManager::GameObjList.Head(); while (x) @@ -419,10 +419,10 @@ if ((Get_Object_Type(o2) == Team) && !o2->As_BuildingGameObj()) { Vector3 pos = Commands->Get_Position(o2); - float dist = Commands->Get_Distance(pos,position); - if (dist < closestdist) + float dist_sq = Vector3::Distance_Squared(pos, position); + if (dist_sq < closestdist_sq) { - closestdist = dist; + closestdist_sq = dist_sq; closest = o2; } } @@ -434,7 +434,7 @@ GameObject SCRIPTS_API *Find_Closest_Preset_By_Team(int Team,const Vector3 &pos,const char *Preset) { - float closestdist = 9999.0f; + float closestdist_sq = FLT_MAX; GameObject *closest = 0; SLNode *x = GameObjManager::GameObjList.Head(); while (x) @@ -449,10 +449,10 @@ { if ((Get_Object_Type(o2) == Team || Team == 2) && !_stricmp(Commands->Get_Preset_Name(o2),Preset)) { - float dist = Commands->Get_Distance(Commands->Get_Position(o2),pos); - if (dist < closestdist) + float dist_sq = Vector3::Distance_Squared(Commands->Get_Position(o2), pos); + if (dist_sq < closestdist_sq) { - closestdist = dist; + closestdist_sq = dist_sq; closest = o2; } } @@ -558,6 +558,7 @@ GameObject SCRIPTS_API *Find_Nearest_Preset(Vector3 position, const char *preset) { GameObject *object = 0; + float min_dist_sq = FLT_MAX; SLNode *x = GameObjManager::GameObjList.Head(); while (x) { @@ -571,18 +572,13 @@ { if (!_stricmp(Commands->Get_Preset_Name(o2),preset)) { - if (object) - { - Vector3 obj_pos = Commands->Get_Position(object); - Vector3 o_pos = Commands->Get_Position(o2); - if (Commands->Get_Distance(position, o_pos) < Commands->Get_Distance(position, obj_pos)) - { - object = o2; - } - } - else + Vector3 pos; + o2->Get_Position(&pos); + float dist_sq = Vector3::Distance_Squared(position, pos); + if (dist_sq < min_dist_sq) { object = o2; + min_dist_sq = dist_sq; } } } @@ -689,6 +685,8 @@ { return; } + Vector3 TestPosition = Position; + TestPosition.Z = 0; SLNode *x = GameObjManager::GameObjList.Head(); while (x) { @@ -701,10 +699,8 @@ if (o2) { Vector3 ObjPosition = Commands->Get_Position(o2); - Vector3 TestPosition = Position; ObjPosition.Z = 0; - TestPosition.Z = 0; - if ((Commands->Get_Distance(ObjPosition,TestPosition) <= Distance)) + if (Vector3::Distance_Squared(ObjPosition, TestPosition) <= Distance * Distance) { if ((Get_Object_Type(o2) == team) || (team == 2)) { @@ -787,7 +783,7 @@ Vector3 pos = Commands->Get_Position(o2); pos.Z = 0; location.Z = 0; - if (Commands->Get_Distance(pos,location) <= range) + if (Vector3::Distance_Squared(pos, location) <= range * range) { if (o2->As_VehicleGameObj() && !empty) { @@ -909,7 +905,7 @@ GameObject SCRIPTS_API *Get_Closest_Armed_Object_To_Object( GameObject* obj, int team ) { - float closestdist = FLT_MAX; + float closestdist_sq = FLT_MAX; GameObject *closest = 0; Vector3 position = Commands->Get_Position(obj); SLNode *x = GameObjManager::GameObjList.Head(); @@ -926,10 +922,10 @@ if ((team == 2 || Get_Object_Type(o2) == team) && o2->As_PhysicalGameObj() && o2->As_PhysicalGameObj()->As_ArmedGameObj()) { Vector3 pos = Commands->Get_Position(o2); - float dist = Commands->Get_Distance(pos,position); - if (dist < closestdist) + float dist_sq = Vector3::Distance_Squared(pos, position); + if (dist_sq < closestdist_sq) { - closestdist = dist; + closestdist_sq = dist_sq; closest = o2; } } diff -urN sourceold/scripts/engine_obj2.cpp source/scripts/engine_obj2.cpp --- sourceold/scripts/engine_obj2.cpp 2018-11-17 10:23:57.165600000 +1000 +++ source/scripts/engine_obj2.cpp 2020-09-10 09:08:27.955908400 +1000 @@ -33,14 +33,14 @@ AT2(0x006C6420,0x006C5CC0); ScriptZoneGameObj *ScriptZoneGameObj::Find_Closest_Zone(Vector3 &Location,ZoneConstants::ZoneType Type) { - float closest = 999999; + float closest = FLT_MAX; ScriptZoneGameObj *closestzone = 0; for (SLNode* node = GameObjManager::ScriptZoneGameObjList.Head(); node; node = node->Next()) { ScriptZoneGameObj *zone = node->Data(); if (zone->Get_Definition().Get_Type() == Type) { - float distance = Vector3::Distance(zone->Get_Bounding_Box().Center,Location); + float distance = Vector3::Distance_Squared(zone->Get_Bounding_Box().Center,Location); if (distance < closest) { closest = distance; diff -urN sourceold/scripts/engine_phys.cpp source/scripts/engine_phys.cpp --- sourceold/scripts/engine_phys.cpp 2018-11-17 10:23:57.167600000 +1000 +++ source/scripts/engine_phys.cpp 2020-09-10 09:08:27.956842600 +1000 @@ -150,15 +150,15 @@ void SCRIPTS_API Create_Effect_All_Stealthed_Objects_Area(const Vector3 &Position,float Distance,const char *object,const Vector3 &offset,int team) { + Vector3 TestPosition = Position; + TestPosition.Z = 0; SLNode *x = GameObjManager::SmartGameObjList.Head(); while (x) { SmartGameObj *obj = x->Data(); Vector3 ObjPosition = Commands->Get_Position(obj); - Vector3 TestPosition = Position; ObjPosition.Z = 0; - TestPosition.Z = 0; - if ((Commands->Get_Distance(ObjPosition,TestPosition) <= Distance)) + if ((Vector3::Distance_Squared(ObjPosition,TestPosition) <= Distance * Distance)) { if ((Get_Object_Type(obj) == team) || (team == 2)) { diff -urN sourceold/scripts/engine_player.cpp source/scripts/engine_player.cpp --- sourceold/scripts/engine_player.cpp 2018-11-17 10:23:57.169600000 +1000 +++ source/scripts/engine_player.cpp 2020-03-28 21:10:59.023831800 +1000 @@ -76,10 +76,14 @@ { return newstr("None"); } - if (!((cPlayer *)o->Get_Player_Data())) + if (!((cPlayer *)o->Get_Player_Data()) && o->Get_Bot_Tag().Is_Empty()) { return newstr("None"); } + if (!o->Get_Bot_Tag().Is_Empty()) + { + return WideCharToChar(o->Get_Bot_Tag()); + } return WideCharToChar(((cPlayer *)o->Get_Player_Data())->Get_Name()); } @@ -504,10 +508,14 @@ { return L"None"; } - if (!((cPlayer *)o->Get_Player_Data())) + if (!((cPlayer *)o->Get_Player_Data()) && o->Get_Bot_Tag().Is_Empty()) { return L"None"; } + if (!o->Get_Bot_Tag().Is_Empty()) + { + return o->Get_Bot_Tag().Peek_Buffer(); + } return ((cPlayer *)o->Get_Player_Data())->Get_Name().Peek_Buffer(); } diff -urN sourceold/scripts/engine_pt.cpp source/scripts/engine_pt.cpp --- sourceold/scripts/engine_pt.cpp 2018-11-17 10:23:57.171600000 +1000 +++ source/scripts/engine_pt.cpp 2020-09-10 09:08:27.956842600 +1000 @@ -15,10 +15,9 @@ #include "engine_def.h" #include "engine_obj2.h" -unsigned int SCRIPTS_API Get_Team_Cost(const char *preset,unsigned int team) +unsigned int SCRIPTS_API Get_Team_Cost(int def_id,unsigned int team) { - int ID = Get_Definition_ID(preset); - if (TeamPurchaseSettingsDefClass::Get_Definition((TeamPurchaseSettingsDefClass::TEAM)PTTEAM(team))->Get_Beacon_Definition() == ID) + if (TeamPurchaseSettingsDefClass::Get_Definition((TeamPurchaseSettingsDefClass::TEAM)PTTEAM(team))->Get_Beacon_Definition() == def_id) { return TeamPurchaseSettingsDefClass::Get_Definition((TeamPurchaseSettingsDefClass::TEAM)PTTEAM(team))->Get_Beacon_Cost(); } @@ -29,7 +28,7 @@ { for (unsigned int j = 0;j < 10;j++) { - if ((p->Get_Definition(j) == ID) || (p->Get_Alt_Definition(j,0) == ID) || (p->Get_Alt_Definition(j,1) == ID) || (p->Get_Alt_Definition(j,2) == ID)) + if ((p->Get_Definition(j) == def_id) || (p->Get_Alt_Definition(j,0) == def_id) || (p->Get_Alt_Definition(j,1) == def_id) || (p->Get_Alt_Definition(j,2) == def_id)) { return p->Get_Cost(j); } @@ -39,16 +38,26 @@ return 0; } -unsigned int SCRIPTS_API Get_Cost(const char *preset) +unsigned int SCRIPTS_API Get_Team_Cost(const char *preset,unsigned int team) +{ + return Get_Team_Cost(Get_Definition_ID(preset), team); +} + +unsigned int SCRIPTS_API Get_Cost(int def_id) { - unsigned int cost = Get_Team_Cost(preset,0); + unsigned int cost = Get_Team_Cost(def_id,0); if (!cost) { - cost = Get_Team_Cost(preset,1); + cost = Get_Team_Cost(def_id,1); } return cost; } +unsigned int SCRIPTS_API Get_Cost(const char *preset) +{ + return Get_Cost(Get_Definition_ID(preset)); +} + void SCRIPTS_API Disable_Preset_By_Name(unsigned int Team,const char *Name, bool enable) { int ID = Get_Definition_ID(Name); diff -urN sourceold/scripts/engine_pt.h source/scripts/engine_pt.h --- sourceold/scripts/engine_pt.h 2018-11-17 10:23:57.172600000 +1000 +++ source/scripts/engine_pt.h 2020-09-10 09:08:27.957841300 +1000 @@ -14,7 +14,9 @@ #include "BuildingGameObjDef.h" using namespace BuildingConstants; unsigned int SCRIPTS_API Get_Team_Cost(const char *preset,unsigned int team); //Get the cost of a preset for a given team. Returns zero if the preset is not found in any of the purchase terminal data or if it is one of the free units. +unsigned int SCRIPTS_API Get_Team_Cost(int def_id,unsigned int team); //Get the cost of a preset for a given team. Returns zero if the preset is not found in any of the purchase terminal data or if it is one of the free units. unsigned int SCRIPTS_API Get_Cost(const char *preset); //Get the cost of a preset. Returns zero if the preset is not found in any of the purchase terminal data or if it is one of the free units. +unsigned int SCRIPTS_API Get_Cost(int def_id); //Get the cost of a preset. Returns zero if the preset is not found in any of the purchase terminal data or if it is one of the free units. void SCRIPTS_API Disable_Preset_By_Name(unsigned int Team,const char *Name, bool enable); //Disable a preset by name void SCRIPTS_API Hide_Preset_By_Name(unsigned int Team,const char *Name, bool enable); //Hides a preset by name void SCRIPTS_API Busy_Preset_By_Name(unsigned int Team,const char *Name, bool enable); //Marks a preset as busy by name diff -urN sourceold/scripts/engine_script.cpp source/scripts/engine_script.cpp --- sourceold/scripts/engine_script.cpp 2018-11-17 10:23:57.173600000 +1000 +++ source/scripts/engine_script.cpp 2020-09-10 09:08:27.958838700 +1000 @@ -11,6 +11,7 @@ */ #include "general.h" #include "scripts.h" +#include "engine_script.h" #include "engine_vector.h" #include "ScriptableGameObj.h" #include "slist.h" @@ -418,7 +419,7 @@ SCRIPTS_API GameObject *Find_Closest_Object_With_Script(const char *script, Vector3 pos) { - float closestdist = 0.0f; + float closestdist = FLT_MAX; GameObject *closest = NULL; SLNode *x = GameObjManager::GameObjList.Head(); while (x) @@ -433,8 +434,8 @@ { if (Is_Script_Attached(o2, script)) { - float dist = Commands->Get_Distance(Commands->Get_Position(o2),pos); - if (closest == NULL || dist < closestdist) + float dist = Vector3::Distance_Squared(Commands->Get_Position(o2), pos); + if (dist < closestdist) { closestdist = dist; closest = o2; @@ -514,6 +515,50 @@ delete d->Data(); } +SCRIPTS_API void Find_All_Vehicles_By_Distance(SList& objects, Vector3 position) +{ + objects.Remove_All(); + + // Internal list of distances, in the same order as GameObjects in objects + SList distances; + + for ( SLNode* objNode = GameObjManager::GameObjList.Head(); objNode != NULL; objNode = objNode->Next() ) + { + ScriptableGameObj* obj = (objNode->Data()) ? objNode->Data()->As_ScriptableGameObj() : NULL; + if ( obj && obj->As_VehicleGameObj() ) + { + // SList cannot contain non-pointer types... stupid thing! + float* distance = new float; + *distance = Commands->Get_Distance(Commands->Get_Position(obj), position); + + SLNode* d = distances.Head(); + for ( SLNode* o = objects.Head(); + d != NULL; + d = d->Next(), o = o->Next() ) + { + if ( *distance < *d->Data() ) + { + objects.insertBefore(obj, *o); + distances.insertBefore(distance, *d); + distance = NULL; + break; + } + } + + // OK, all existing objects are closer than this one so add it to the end of the list + if ( distance != NULL ) + { + objects.Add_Tail(obj); + distances.Add_Tail(distance); + } + } + } + + // Clean up memory since SList insists on having heap objects... + for ( SLNode* d = distances.Head(); d != NULL; d = d->Next() ) + delete d->Data(); +} + SCRIPTS_API void Send_Custom_Event_To_Objects_With_Script( GameObject *sender, const char *script, int message, int param, float delay ) { if (!sender) @@ -560,7 +605,7 @@ { if ( Is_Script_Attached( o2, script ) && Commands->Get_ID ( sender ) != Commands->Get_ID ( o2 ) - && Commands->Get_Distance ( Commands->Get_Position ( sender ), Commands->Get_Position ( o2 ) ) <= range ) + && Vector3::Distance_Squared ( Commands->Get_Position ( sender ), Commands->Get_Position ( o2 ) ) <= range * range ) { Commands->Send_Custom_Event(sender,o2,message,param,delay); } @@ -627,4 +672,48 @@ va_start ( vargs, params ); Attach_Script_V(pObj,script,params,vargs); va_end(vargs); -} \ No newline at end of file +} + +int Get_Param_Type(const char *str) +{ + for (int i = 0; i < PARAM_TYPE_COUNT; i++) + { + if (!lstrcmpiA(str, PARAM_TYPE_STRINGS[i])) + { + return i; + } + } + return 0; +} + +SCRIPTS_API void Get_Script_Parameters(const char *script, DynamicVectorClass ¶meters) +{ + parameters.Delete_All(); + auto factory = ScriptRegistrar::GetScriptFactory(script); + if (!factory) + { + return; + } + char* working = newstr(factory->GetParamDescription()); + char *param = strtok(working, ","); + while (param) + { + char *sname = param; + char *type = strchr(param, ':'); + type[0] = '\0'; + type++; + char *value = strrchr(param, '='); + if (value) + { + value[0] = '\0'; + value++; + } + ScriptParameter p; + p.name = sname; + p.value = value; + p.type = Get_Param_Type(type); + parameters.Add(p); + param = strtok(nullptr, ","); + } + delete[] working; +} diff -urN sourceold/scripts/engine_script.h source/scripts/engine_script.h --- sourceold/scripts/engine_script.h 2018-11-17 10:23:57.173600000 +1000 +++ source/scripts/engine_script.h 2020-03-28 21:10:59.024829200 +1000 @@ -12,6 +12,7 @@ #ifndef SCRIPTS_INCLUDE__ENGINE_SCRIPT_H #define SCRIPTS_INCLUDE__ENGINE_SCRIPT_H #include "scripts.h" +#include "engine_string.h" #include "SList.h" SCRIPTS_API void Remove_Script(GameObject *obj,const char *script); //removes all copies of