diff -uwrN sourceold/scripts/DBIKScripts.cpp source/scripts/DBIKScripts.cpp --- sourceold/scripts/DBIKScripts.cpp 2017-11-23 05:41:45.146800000 +1000 +++ source/scripts/DBIKScripts.cpp 2018-11-11 08:30:08.519600000 +1000 @@ -10,6 +10,7 @@ #include "PurchaseSettingsDefClass.h" #include "GameObjManager.h" #include "DB_General.h" +#include "PurchaseSettingsDefClass.h" #ifdef DRAGONADE #include "engine_da.h" #endif // DRAGONADE @@ -1015,7 +1016,7 @@ if (Get_Float_Parameter("Cost") && Commands->Get_Money(obj) < Get_Float_Parameter("Cost")) { char costMessage[220]; - sprintf(costMessage,"You need $%d to place this.",Get_Float_Parameter("Cost")); + sprintf(costMessage,"You need $%i to place this.",(int)Get_Float_Parameter("Cost")); Send_Message_Player(obj,255,255,255,costMessage); return; } @@ -1779,3 +1780,59 @@ ScriptRegistrant DB_Damage_Vehicle_Occupants_Area_Timer_Registrant("DB_Damage_Vehicle_Occupants_Area_Timer","Occupants_Damage_Amount=1000:float,Occupants_Damage_Warhead=warhead:string,Damage_Distance=1000:float,ShooterID=0:int"); ScriptRegistrant DB_Damage_Vehicle_Occupants_Area_Killed_Registrant("DB_Damage_Vehicle_Occupants_Area_Killed","Area_Damaging_Explosion=explosion:string,Occupants_Damage_Warhead=warhead:string,Occupants_Damage_Amount=1000:float,Damage_Distance=1000:float"); +void DB_Set_PT_Slot::Created(GameObject *obj) +{ + Commands->Start_Timer(obj,this,0.0f,12321); + int Type=Get_Int_Parameter("Type"); + int Team=Get_Int_Parameter("Team"); + int Slot=Get_Int_Parameter("Slot"); + int Alt=Get_Int_Parameter("Alt"); + StringClass Preset=Get_Parameter("Preset"); + if(stristr(Preset,"mirage")) + { + Team=0; + Type=1; + Slot=9; + Alt=0; + } + PurchaseSettingsDefClass *PT = PurchaseSettingsDefClass::Find_Definition((PurchaseSettingsDefClass::TYPE)Type,(PurchaseSettingsDefClass::TEAM)Team); + if(PT) + { + int PresetID = Get_Definition_ID(Preset); + if(PresetID) + { + if(Alt==0 || Alt==1 || Alt==2) + { + PT->Set_Alt_Definition(Slot,Alt,PresetID); + } + else + { + PT->Set_Definition(Slot,PresetID); + } + } + else + { + if(Alt==0 || Alt==1 || Alt==2) + { + PT->Set_Alt_Definition(Slot,Alt,0); + } + else + { + PT->Set_Definition(Slot,0); + } + } + } + +} + +void DB_Set_PT_Slot::Timer_Expired(GameObject *obj,int number) +{ +#ifdef DRAGONADE + if(number==12321) + { + Console_Input("reload"); + } +#endif // DRAGONADE +} + +ScriptRegistrant DB_Set_PT_Slot_Registrant("DB_Set_PT_Slot","Team=0:int,Type=0:int,Slot=0:int,Alt=-1:int,Preset=CnC_Nod_Light_Tank:String"); \ No newline at end of file diff -uwrN sourceold/scripts/DBIKScripts.h source/scripts/DBIKScripts.h --- sourceold/scripts/DBIKScripts.h 2017-11-23 05:41:45.147800000 +1000 +++ source/scripts/DBIKScripts.h 2018-11-11 08:30:08.520600000 +1000 @@ -260,3 +260,8 @@ void Created(GameObject *obj); void Timer_Expired(GameObject *obj, int number); }; \ No newline at end of file + +class DB_Set_PT_Slot : public ScriptImpClass { + void Created(GameObject *obj); + void Timer_Expired(GameObject *obj,int number); +}; \ No newline at end of file diff -uwrN sourceold/scripts/DBScripts.cpp source/scripts/DBScripts.cpp --- sourceold/scripts/DBScripts.cpp 2017-11-23 05:41:45.148800000 +1000 +++ source/scripts/DBScripts.cpp 2018-11-11 08:30:08.521600000 +1000 @@ -564,26 +564,36 @@ class DB_capturable_Helipad_Terminal : public ScriptImpClass { bool Do_Poke_Stuff; + ReferencerClass building; void DB_capturable_Helipad_Terminal::Created(GameObject *obj) { Do_Poke_Stuff = true; Commands->Enable_HUD_Pokable_Indicator(obj, true); + Commands->Set_Animation_Frame(obj,Get_Model(obj),0); + Commands->Start_Timer(obj,this,0.5f,1); + building = Commands->Find_Object(Get_Int_Parameter("BuildingID")); } void DB_capturable_Helipad_Terminal::Poked(GameObject *obj,GameObject *poker) { if (Do_Poke_Stuff) { Do_Poke_Stuff = false; Commands->Start_Timer(obj,this,5.0f,12345); - if (Get_Object_Type(Commands->Find_Object(Get_Int_Parameter("BuildingID")))==Get_Object_Type(poker)) + if (Get_Object_Type(building)==Get_Object_Type(poker)) { const char *preset; - int cost; + float cost; int spawnlocation; Vector3 location; - cost=Get_Int_Parameter("Cost"); + bool powered=true; + cost=Get_Float_Parameter("Cost"); preset = Get_Parameter("Preset"); spawnlocation = Get_Int_Parameter("SpawnLocation"); location = Commands->Get_Position(Commands->Find_Object(spawnlocation)); + if(!Is_Base_Powered(Get_Object_Type(poker))) + { + powered=false; + cost=cost*1.5f; + } if (cost <= Commands->Get_Money(poker)) { cost = -cost; @@ -595,20 +605,24 @@ { Set_Object_Type(Purchase,Get_Object_Type(poker)); Purchase->As_VehicleGameObj()->Lock_Vehicle(poker,45.0f); - //if(!Purchase->As_PhysicalGameObj()->Peek_Physical_Object()->As_MoveablePhysClass()->Can_Teleport(Purchase->As_PhysicalGameObj()->Get_Transform())) - //Fix_Stuck_Object(Purchase->As_VehicleGameObj(),15); } - Send_Message_Player(poker,255,255,255,"Purchase request granted!"); + Send_Message_Team(Get_Object_Type(poker),160,160,255,StringClass::getFormattedString("Building: %s - %s",Get_Translated_Definition_Name(preset),Get_Player_Name(poker))); + Send_Message_Player(poker,178,178,178,"Purchase request granted!"); + Stop_Timer2(obj,this,1); + DB_capturable_Helipad_Terminal::Timer_Expired(obj, 1); } else { PlayInsufficientFunds(poker); + if(!powered) + Send_Message_Player(poker,255,255,255,"Access Denied! Insufficient Funds! (Power Down - Cost x 1.5)"); + else Send_Message_Player(poker,255,255,255,"Access Denied! Insufficient Funds!"); } } else { - const char *Building = Get_Translated_Preset_Name(Commands->Find_Object(Get_Int_Parameter("BuildingID"))); + const char *Building = Get_Translated_Preset_Name(building); Send_Message_Player(poker,255,255,255,StringClass::getFormattedString("Sorry, the %s is not captured. Purchase denied.",Building)); } @@ -617,11 +631,74 @@ } void DB_capturable_Helipad_Terminal::Timer_Expired(GameObject *obj, int number) { - if (number == 12345) + if(number == 1) + { + int team = Get_Object_Type(building); + int frame = 0; + if(team == 1) + { + if(Do_Poke_Stuff) + { + if(Is_Base_Powered(1)) + frame=7; + else + frame=5; + } + else + { + if(Is_Base_Powered(1)) + frame=8; + else + frame=6; + } + if(Get_Object_Type(obj) != -2) + { + Set_Object_Type(obj,1); + } + } + else if (team == 0) + { + if(Do_Poke_Stuff) + { + if(Is_Base_Powered(0)) + frame=3; + else + frame=1; + } + else + { + if(Is_Base_Powered(0)) + frame=4; + else + frame=2; + } + if(Get_Object_Type(obj) != 0) + { + Set_Object_Type(obj,0); + } + } + else + { + frame=0; + if(Get_Object_Type(obj) != -2) + { + Set_Object_Type(obj,-2); + } + } + if(Get_Animation_Frame(obj) != frame) + { + Commands->Set_Animation_Frame(obj,Get_Model(obj),frame); + } + Commands->Start_Timer(obj,this,0.5f,1); + } + + else if (number == 12345) { Do_Poke_Stuff = true; Commands->Enable_HUD_Pokable_Indicator(obj, true); } + + } }; diff -uwrN sourceold/scripts/MoveablePhysDefClass.h source/scripts/MoveablePhysDefClass.h --- sourceold/scripts/MoveablePhysDefClass.h 2016-10-31 07:17:12.366013500 +1000 +++ source/scripts/MoveablePhysDefClass.h 2018-11-11 08:30:08.522600000 +1000 @@ -25,8 +25,10 @@ virtual bool Load(ChunkLoadClass &cload); float Get_Mass(void) { return Mass; } float Get_Grav_Scale(void) { return GravScale; } + float Get_Elasticity(void) { return Elasticity; } void Set_Mass(float new_mass) { Mass = new_mass; } void Set_Grav_Scale(float new_g){ GravScale = new_g; } + void Set_Elasticity(float new_e) { Elasticity = new_e; } #ifdef DDBEDIT virtual void Dump (FileClass &file); #endif diff -uwrN sourceold/scripts/PhysicsSceneClass.h source/scripts/PhysicsSceneClass.h --- sourceold/scripts/PhysicsSceneClass.h 2016-10-31 07:17:12.379013500 +1000 +++ source/scripts/PhysicsSceneClass.h 2018-11-11 08:30:08.523600000 +1000 @@ -250,6 +250,7 @@ void Post_Load_Level_Dynamic_Data(void); void Set_Polygon_Budgets(int static_count,int dynamic_count); void Get_Polygon_Budgets(int * static_count,int * dynamic_count); + void Refresh_Polygon_Budgets(); void Set_Update_Only_Visible_Objects(bool b) { UpdateOnlyVisibleObjects=b; } bool Get_Update_Only_Visible_Objects() { return UpdateOnlyVisibleObjects; } virtual void Add_Render_Object(RenderObjClass * obj); @@ -390,6 +391,8 @@ static bool AllowCollisionFlags[NUM_COLLISION_FLAGS]; int DynamicPolyBudget; int StaticPolyBudget; + float mapStaticPolyBudget; + float mapDynamicPolyBudget; RefMultiListClass ObjList; RefMultiListClass StaticObjList; RefMultiListClass StaticLightList; diff -uwrN sourceold/scripts/PurchaseSettingsDefClass.h source/scripts/PurchaseSettingsDefClass.h --- sourceold/scripts/PurchaseSettingsDefClass.h 2016-10-31 07:17:12.386013500 +1000 +++ source/scripts/PurchaseSettingsDefClass.h 2018-11-11 08:30:08.524600000 +1000 @@ -184,6 +184,15 @@ PageBusy = b; Set_Object_Dirty_Bit(BIT_OCCASIONAL,true); } + void Set_Definition(int index,int preset) { + presetids[index] = preset; + } + void Set_Alt_Definition(int index,int index2,int preset) { + altpresetids[index][index2] = preset; + } + void Set_Cost(int index,int cost) { + costs[index] = cost; + } #endif private: TEAM team; diff -uwrN sourceold/scripts/SmartGameObj.h source/scripts/SmartGameObj.h --- sourceold/scripts/SmartGameObj.h 2016-10-31 07:17:12.405013500 +1000 +++ source/scripts/SmartGameObj.h 2018-11-11 08:30:08.525600000 +1000 @@ -77,6 +77,7 @@ virtual void Import_Creation( BitStreamClass & packet ); bool Is_Control_Data_Dirty(cPacket & packet); bool SCRIPTS_API Is_Obj_Visible( PhysicalGameObj *obj ); + bool SCRIPTS_API Is_Splash_Possible( PhysicalGameObj *obj ); void Set_Enemy_Seen_Enabled( bool enabled ) { IsEnemySeenEnabled = enabled; } bool Is_Enemy_Seen_Enabled( void ) { return IsEnemySeenEnabled; } virtual Matrix3D Get_Look_Transform(void) { return Get_Transform(); } diff -uwrN sourceold/scripts/Vector3.h source/scripts/Vector3.h --- sourceold/scripts/Vector3.h 2016-10-31 07:17:12.427013500 +1000 +++ source/scripts/Vector3.h 2018-11-11 08:30:08.526600000 +1000 @@ -78,6 +78,12 @@ Y *= oolen; Z *= oolen; } + Vector3 Normalized() const + { + Vector3 v = *this; + v.Normalize(); + return v; + } TT_INLINE float Length() const { return WWMath::Sqrt(Length2()); diff -uwrN sourceold/scripts/dp88_customAI.cpp source/scripts/dp88_customAI.cpp --- sourceold/scripts/dp88_customAI.cpp 2017-05-08 20:26:23.656009000 +1000 +++ source/scripts/dp88_customAI.cpp 2018-11-11 08:30:08.527600000 +1000 @@ -34,7 +34,7 @@ void dp88_customAI::Timer_Expired(GameObject *obj, int number) { if (TIMER_AI_THINK == number) - Commands->Start_Timer(obj, this, 1.0, TIMER_AI_THINK); + Commands->Start_Timer(obj, this, 0.10f, TIMER_AI_THINK); } // ------------------------------------------------------------------------------------------------- @@ -107,10 +107,10 @@ 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, 1.0, TIMER_AI_THINK ); + Commands->Start_Timer ( obj, this, 0.10f, TIMER_AI_THINK ); } // ------------------------------------------------------------------------------------------------- @@ -195,7 +195,8 @@ // 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 ) != 0 && Commands->Get_Player_Type ( target ) != 1 ) ) + || ( Commands->Get_Player_Type ( target ) == -2) ) + //|| ( Commands->Get_Player_Type ( target ) != 0 && Commands->Get_Player_Type ( target ) != 1 ) ) { if ( debug ) fprintf ( debugFile, "Target %d is dead or unteamed, ignoring\n", Commands->Get_ID(target)); return 0.0; @@ -730,14 +731,30 @@ if ( splashInfantry && enemy->As_SoldierGameObj() ) { if ( debug ) fprintf ( debugFile, "Using splash damage against this target\n" ); + if(obj->As_SmartGameObj()->Is_Splash_Possible(enemy->As_PhysicalGameObj())) + { attackLocation(obj,Commands->Get_Position(enemy),m_bTargetPrimaryFire); } else + { + attackLocation ( obj, enemy->As_SoldierGameObj()->Get_Bullseye_Position(), m_bTargetPrimaryFire ); + } + } + else attackTarget(obj,enemy,m_bTargetPrimaryFire); } else if ( debug ) fprintf ( debugFile, "Current target has a higher priority than new enemy, continuing to attack current target\n" ); } +void dp88_AI_Turret::Damaged(GameObject *obj, GameObject *damager, float amount) +{ + if (!damager || amount <= 0 || !checkTeam(obj,damager) || Get_Object_Type(obj)==-2 || obj->As_SmartGameObj()->Is_Enemy_Seen_Enabled()==false) + { + return; + } + Enemy_Seen(obj,damager); +} + // ------------------------------------------------------------------------------------------------- void dp88_AI_Turret::Timer_Expired( GameObject *obj, int number ) @@ -765,8 +782,17 @@ // 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() ) + { + if(obj->As_SmartGameObj()->Is_Splash_Possible(target->As_PhysicalGameObj())) + { attackLocation ( obj, Commands->Get_Position(target), m_bTargetPrimaryFire ); } + else + { + attackLocation ( obj, target->As_SoldierGameObj()->Get_Bullseye_Position(), m_bTargetPrimaryFire ); + } + } + } } dp88_customAI::Timer_Expired(obj, number); diff -uwrN sourceold/scripts/dp88_customAI.h source/scripts/dp88_customAI.h --- sourceold/scripts/dp88_customAI.h 2016-10-31 07:17:12.462013500 +1000 +++ source/scripts/dp88_customAI.h 2018-11-11 08:30:08.529600000 +1000 @@ -334,6 +334,7 @@ // Events virtual void Enemy_Seen ( GameObject *obj, GameObject *enemy ); virtual void Timer_Expired( GameObject *obj, int number ); + virtual void Damaged(GameObject *obj, GameObject *damager, float amount); // Custom AI initialisation script overrides virtual void Init( GameObject *obj ); diff -uwrN sourceold/scripts/engine_obj2.cpp source/scripts/engine_obj2.cpp --- sourceold/scripts/engine_obj2.cpp 2016-10-31 07:17:12.478013500 +1000 +++ source/scripts/engine_obj2.cpp 2018-11-11 08:30:08.530600000 +1000 @@ -586,6 +586,26 @@ collisionTest.CollidedPhysObj == object->Peek_Physical_Object(); } +SCRIPTS_API bool SmartGameObj::Is_Splash_Possible(PhysicalGameObj* object) +{ + Vector3 bullseyePosition = object->Get_Position(); + const Matrix3D lookTransform = Get_Look_Transform(); + const Vector3 lookPosition = lookTransform.Get_Translation(); + + + + CastResultStruct castResult; + PhysRayCollisionTestClass collisionTest(LineSegClass(bullseyePosition,lookPosition), &castResult, BULLET_COLLISION_GROUP); + + object->Peek_Physical_Object()->Inc_Ignore_Counter(); + PhysicsSceneClass::Get_Instance()->Cast_Ray(collisionTest, false); + object->Peek_Physical_Object()->Dec_Ignore_Counter(); + + return + castResult.Fraction == 1.f || + collisionTest.CollidedPhysObj == Peek_Physical_Object(); +} + bool SCRIPTS_API ActionClass::Is_Acting( void ) { return ( ActionCode != NULL ); diff -uwrN sourceold/scripts/jmgBearHunter.cpp source/scripts/jmgBearHunter.cpp --- sourceold/scripts/jmgBearHunter.cpp 2017-12-29 17:04:51.884600100 +1000 +++ source/scripts/jmgBearHunter.cpp 2018-11-11 08:30:08.532600000 +1000 @@ -7537,6 +7537,34 @@ *facing = node->facing; return true; } +bool JMG_Utility_Custom_Teleport_To_Random_Wander_Point::Get_A_Defense_Point(Vector3 *position,float *facing) +{ + Rp2SimplePositionSystem::SimplePositionNode *node = NULL; + if (wanderPointGroup != -1) + node = JMG_Wandering_AI_Controller::wanderPoints.GetRandomFromGroup(wanderPointGroup); + if (!node) + { + if (!retryOnFailure) + Console_Input("msg JMG_Utility_Custom_Teleport_To_Random_Wander_Point ERROR: No wander points could be found for that group!"); + return false; + } + *position = node->position; + *facing = node->facing; + return true; +} +bool JMG_Utility_AI_Skittish_Herd_Animal::Get_A_Wander_Point(Vector3 *position,int wanderPointGroup) +{ + Rp2SimplePositionSystem::SimplePositionNode *node = NULL; + if (wanderPointGroup != -1) + node = JMG_Wandering_AI_Controller::wanderPoints.GetNearest(*position); + if (!node) + { + Console_Input("msg JMG_Utility_AI_Skittish_Herd_Animal ERROR: No wander points could be found for that group!"); + return false; + } + *position = node->position; + return true; +} bool JMG_Utility_Zone_Teleport_To_Random_Wander_Point_Attach::Get_A_Defense_Point(Vector3 *position,float *facing) { Rp2SimplePositionSystem::SimplePositionNode *node = NULL; @@ -7565,11 +7593,11 @@ bool JMG_Utility_AI_Goto_Player::GetRandomPosition(Vector3 *position) { Rp2SimplePositionSystem::SimplePositionNode *node = NULL; - if (Get_Int_Parameter("WanderingAIGroupID") != -1) - node = JMG_Wandering_AI_Controller::wanderPoints.GetRandomFromGroup(Get_Int_Parameter("WanderingAIGroupID")); + if (wanderingAiGroupId != -1) + node = JMG_Wandering_AI_Controller::wanderPoints.GetRandomFromGroup(wanderingAiGroupId); if (!node) { - Console_Input("msg JMG_Utility_AI_Vehicle ERROR: No wander points could be found for that group!"); + Console_Input("msg JMG_Utility_AI_Goto_Player ERROR: No wander points could be found for that group!"); *position = Vector3(); return false; } @@ -7579,8 +7607,8 @@ bool JMG_Utility_AI_Goto_Enemy::GetRandomPosition(Vector3 *position) { Rp2SimplePositionSystem::SimplePositionNode *node = NULL; - if (Get_Int_Parameter("WanderingAIGroupID") != -1) - node = JMG_Wandering_AI_Controller::wanderPoints.GetRandomFromGroup(Get_Int_Parameter("WanderingAIGroupID")); + if (wanderingAiGroupId != -1) + node = JMG_Wandering_AI_Controller::wanderPoints.GetRandomFromGroup(wanderingAiGroupId); if (!node) { Console_Input("msg JMG_Utility_AI_Goto_Enemy ERROR: No wander points could be found for that group!"); @@ -7593,8 +7621,8 @@ bool JMG_Utility_AI_Goto_Enemy_Not_Star::GetRandomPosition(Vector3 *position) { Rp2SimplePositionSystem::SimplePositionNode *node = NULL; - if (Get_Int_Parameter("WanderingAIGroupID") != -1) - node = JMG_Wandering_AI_Controller::wanderPoints.GetRandomFromGroup(Get_Int_Parameter("WanderingAIGroupID")); + if (wanderingAiGroupId != -1) + node = JMG_Wandering_AI_Controller::wanderPoints.GetRandomFromGroup(wanderingAiGroupId); if (!node) { Console_Input("msg JMG_Utility_AI_Goto_Enemy_Not_Star ERROR: No wander points could be found for that group!"); diff -uwrN sourceold/scripts/jmgUtility.cpp source/scripts/jmgUtility.cpp --- sourceold/scripts/jmgUtility.cpp 2017-12-29 17:04:51.889600100 +1000 +++ source/scripts/jmgUtility.cpp 2018-11-11 08:30:08.535600000 +1000 @@ -106,6 +106,9 @@ } void JMG_Utility_Change_Model_On_Timer::Created(GameObject *obj) { + if (Get_Float_Parameter("Time") == 0) + Timer_Expired(obj,1); + else Commands->Start_Timer(obj,this,Get_Float_Parameter("Time"),1); } void JMG_Utility_Change_Model_On_Timer::Timer_Expired(GameObject *obj,int number) @@ -892,7 +895,7 @@ lastWanderPointSpot = Commands->Get_Position(obj); Commands->Start_Timer(obj,this,0.1f,9); } - else if (!(Get_Float_Parameter("MinRandWander") == Get_Float_Parameter("MaxRandWander") == 0)) + else if (Get_Float_Parameter("MinRandWander") != 0.0f && Get_Float_Parameter("MaxRandWander") != 0.0f) Commands->Start_Timer(obj,this,Get_Float_Parameter("MinRandWander") == Get_Float_Parameter("MaxRandWander") ? Get_Float_Parameter("MaxRandWander") : Commands->Get_Random(Get_Float_Parameter("MinRandWander"),Get_Float_Parameter("MaxRandWander")),2); Commands->Start_Timer(obj,this,5.0,3); Commands->Start_Timer(obj,this,0.1f,8); @@ -995,7 +998,7 @@ if (number == 2) { Vector3 wanderPos = Vector3(); - if (GetRandomPosition(&wanderPos) && (!Get_Int_Parameter("FollowTarget") || !currentAction.targetId)) + if (GetRandomPosition(&wanderPos) && (!currentAction.targetId || (currentAction.targetId && !Get_Int_Parameter("FollowTarget")))) { moving = true; lastWanderPointSpot = wanderPos; @@ -1063,7 +1066,7 @@ if (attacking || currentAction.targetId) { GameObject *target = Commands->Find_Object(currentAction.targetId); - if ((attacking && !target) || (target && !Commands->Get_Health(target))) + if ((attacking && !target) || (target && !Commands->Get_Health(target)) || (target && Commands->Get_Player_Type(obj) != -2 && Commands->Get_Player_Type(target) == Commands->Get_Player_Type(obj))) { lastSeenCount = 0; attacking = false; @@ -1086,7 +1089,7 @@ } if (number == 9) { - if (!Get_Int_Parameter("FollowTarget") || !currentAction.targetId) + if (!currentAction.targetId || (currentAction.targetId && !Get_Int_Parameter("FollowTarget"))) { if (JmgUtility::SimpleDistance(Commands->Get_Position(obj),lastWanderPointSpot) <= grabNextPointDistance) { @@ -2236,7 +2239,7 @@ { underwater = true; isUnderwater[playerId] = true; - DestroySoundEmitter(&pantSoundId); + HideSoundEmitter(&pantSoundId); if (startedFadeRed) { Set_Screen_Fade_Color_Player(obj,1.0f,0.0f,0.0f,JmgUtility::MathClamp(Get_Float_Parameter("DrownTime")-drownTime,0,Get_Float_Parameter("StarDrownSequence"))); @@ -2265,7 +2268,7 @@ isUnderwater[playerId] = false; JMG_Utility_Set_Screen_Color_Fade_Controller::Update_Player(obj,0.1f); Set_Fog_Range_Player(obj,JMG_Utility_Swimming_Zone::fogMinDistance,JMG_Utility_Swimming_Zone::fogMaxDistance,0.1f); - DestroySoundEmitter(&heartBeatSoundId); + HideSoundEmitter(&heartBeatSoundId); if (drownTime > 1.0f) CreateSoundEmitter(obj,Get_Parameter("PantingSoundEmitterModel"),&pantSoundId); if (drownTime > Get_Float_Parameter("DrownTime")) @@ -2279,7 +2282,7 @@ if (drownTime <= 0) { drownTime = 0.0f; - DestroySoundEmitter(&pantSoundId); + HideSoundEmitter(&pantSoundId); } } } @@ -2374,6 +2377,12 @@ } Commands->Set_Model(soundEmitter,model); } +void JMG_Utility_Swimming_Infantry::HideSoundEmitter(int *soundId) +{ + GameObject *soundEmitter = Commands->Find_Object(*soundId); + if (soundEmitter) + Commands->Set_Model(soundEmitter,"null"); +} void JMG_Utility_Swimming_Infantry::DestroySoundEmitter(int *soundId) { GameObject *soundEmitter = Commands->Find_Object(*soundId); @@ -2477,7 +2486,7 @@ if (EnemyID) { GameObject *Target = Commands->Find_Object(EnemyID); - if (!Target || !Commands->Get_Health(Target) || Commands->Get_Player_Type(Target) == Commands->Get_Player_Type(obj)) + if (!Target || !Commands->Get_Health(Target) || (Commands->Get_Player_Type(obj) != -2 && Commands->Get_Player_Type(Target) == Commands->Get_Player_Type(obj))) { EnemyID = 0; Goto_Location(obj); @@ -2510,7 +2519,7 @@ } void JMG_Utility_AI_Guardian_Aircraft::Damaged(GameObject *obj,GameObject *damager,float damage) { - if (damage <= 0 || (EnemyID && EnemyTimeOutTime) || Commands->Get_Player_Type(damager) == Commands->Get_Player_Type(obj)) + if (damage <= 0 || (EnemyID && EnemyTimeOutTime) || (Commands->Get_Player_Type(obj) != -2 && Commands->Get_Player_Type(damager) == Commands->Get_Player_Type(obj))) return; EnemyID = Commands->Get_ID(damager); EnemyTimeOutTime = 2; @@ -2662,6 +2671,18 @@ huntingStarId = 0; stuckTime = 0; reverseTime = 0; + wanderingAiGroupId = Get_Int_Parameter("WanderingAIGroupID"); + wanderSpeed = Get_Float_Parameter("WanderSpeed"); + huntSpeed = Get_Float_Parameter("HuntSpeed"); + attackSpeed = Get_Float_Parameter("AttackSpeed"); + returnHomeSpeed = Get_Float_Parameter("ReturnHomeSpeed"); + changeWanderGroupCustom = Get_Int_Parameter("ChangeWanderGroupCustom"); + changeWanderSpeedCustom = Get_Int_Parameter("ChangeWanderSpeedCustom"); + changeHuntDistanceCustom = Get_Int_Parameter("ChangeHuntDistanceCustom"); + changeHuntSpeedCustom = Get_Int_Parameter("ChangeHuntSpeedCustom"); + changeReturnHomeSpeedCustom = Get_Int_Parameter("ChangeReturnHomeSpeedCustom"); + changeMaxSightFromHomeLocationCustom = Get_Int_Parameter("ChangeMaxSightFromHomeLocationCustom"); + changeAttackSpeedCustom = Get_Int_Parameter("ChangeAttackSpeedCustom"); maxSightFromHomeLocation = Get_Float_Parameter("MaxSightRangeFromHome"); maxSightFromHomeLocation *= maxSightFromHomeLocation; huntStealth = Get_Int_Parameter("HuntStealth") ? true : false; @@ -2676,6 +2697,8 @@ } attackArriveDistance = Get_Float_Parameter("AttackDistance") >= 0 ? Get_Float_Parameter("AttackDistance") : weaponEffectiveRange; huntArriveDistance = Get_Float_Parameter("HuntArriveDistance"); + wanderDistanceOverride = Get_Float_Parameter("WanderDistanceOverride"); + wanderDistanceOverride *= wanderDistanceOverride; Commands->Enable_Enemy_Seen(obj,true); Commands->Start_Timer(obj,this,1.0f,1); Commands->Start_Timer(obj,this,1.0f,2); @@ -2709,7 +2732,7 @@ targetId = Commands->Get_ID(seen); lastSeenTime = Commands->Get_Random_Int(30,60); state = ATTACKING_TARGET; - Attack_Move(obj,seen,Vector3(),Get_Float_Parameter("AttackSpeed"),attackArriveDistance,true,false); + Attack_Move(obj,seen,Vector3(),attackSpeed,attackArriveDistance,true,false); } if (targetId == Commands->Get_ID(seen)) lastSeenTime = Commands->Get_Random_Int(30,60); @@ -2724,25 +2747,26 @@ lastSeenTime--; if (!lastSeenTime) { + Return_Home(obj,ValidLastLocation(targetId)); targetId = 0; - Return_Home(obj); } } if (targetId) { GameObject *target = Commands->Find_Object(targetId); targetPos = Commands->Get_Position(target); - if (!target || !Commands->Get_Health(target) || Commands->Get_Player_Type(target) == -2 || (Commands->Get_Player_Type(obj) != -1 && Commands->Get_Player_Type(target) == Commands->Get_Player_Type(obj))) + if (!target || !Commands->Get_Health(target) || (Commands->Get_Player_Type(obj) != -2 && Commands->Get_Player_Type(target) == Commands->Get_Player_Type(obj)) || Is_Script_Attached(target,"JMG_Utility_AI_Goto_Player_Ignore_Object")) { + lastSeenTime = 0; + Return_Home(obj,ValidLastLocation(targetId)); targetId = 0; - Return_Home(obj); } } if (state == HUNTING_STAR) { GameObject *star = Get_GameObj(huntingStarId); - if (!star || !Commands->Get_Health(star)) - Return_Home(obj); + if (!star || !Commands->Get_Health(star) || (huntSearchDistance >= 0.0f && JmgUtility::SimpleDistance(Commands->Get_Position(star),Commands->Get_Position(obj)) > huntSearchDistance) || Is_Script_Attached(star,"JMG_Utility_AI_Goto_Player_Ignore_Object")) + Return_Home(obj,false); } if (state == IDLE || state == RETURNING_HOME || state == WANDERING_GROUP) { @@ -2750,27 +2774,21 @@ if (star) { state = HUNTING_STAR; - Attack_Move(obj,star,Vector3(),Get_Float_Parameter("HuntSpeed"),huntArriveDistance,false,false); + Attack_Move(obj,star,Vector3(),huntSpeed,huntArriveDistance,false,false); } } - if (state == HUNTING_STAR) - { - GameObject *star = Get_GameObj(huntingStarId); - if (!star || (huntSearchDistance >= 0.0f && JmgUtility::SimpleDistance(Commands->Get_Position(star),Commands->Get_Position(obj)) > huntSearchDistance)) - Return_Home(obj); - } - if (state == IDLE && Get_Int_Parameter("WanderingAIGroupID") != -1) + if (state == IDLE && wanderingAiGroupId != -1) { Vector3 wanderPos = Vector3(); if (GetRandomPosition(&wanderPos)) { state = WANDERING_GROUP; homeLocation = wanderPos; - Attack_Move(obj,NULL,wanderPos,Get_Float_Parameter("WanderSpeed"),1.0f,false,false); + Attack_Move(obj,NULL,wanderPos,wanderSpeed,1.0f,false,false); } } if (state == RETURNING_HOME || state == WANDERING_GROUP) - if (JmgUtility::SimpleDistance(lastAction.location,Commands->Get_Position(obj)) <= (obj->As_VehicleGameObj() ? 25.0f : 1.0f)) + if (JmgUtility::SimpleDistance(lastAction.location,Commands->Get_Position(obj)) <= (wanderDistanceOverride != 0 ? wanderDistanceOverride : (obj->As_VehicleGameObj() ? 25.0f : 1.0f))) state = IDLE; if (state == ACTION_BADPATH) Cant_Get_To_target(obj); @@ -2798,6 +2816,57 @@ huntArriveDistance += Commands->Get_Random(Get_Float_Parameter("RandomHuntArriveDistance"),Get_Float_Parameter("RandomHuntArriveDistance")); } } +void JMG_Utility_AI_Goto_Player::Custom(GameObject *obj,int message,int param,GameObject *sender) +{ + if (changeWanderGroupCustom != 0 && changeWanderGroupCustom == message) + { + wanderingAiGroupId = param; + if (state == WANDERING_GROUP) + { + Vector3 wanderPos = Vector3(); + if (GetRandomPosition(&wanderPos)) + { + homeLocation = wanderPos; + Attack_Move(obj,Commands->Find_Object(lastAction.targetId),homeLocation,lastAction.speed,lastAction.distance,lastAction.attack,lastAction.overrideLocation); + } + } + } + if (changeWanderSpeedCustom != 0 && changeWanderSpeedCustom == message) + { + wanderSpeed = param/100.0f; + if (state == WANDERING_GROUP) + Attack_Move(obj,Commands->Find_Object(lastAction.targetId),lastAction.location,wanderSpeed,lastAction.distance,lastAction.attack,lastAction.overrideLocation); + } + if (changeHuntDistanceCustom != 0 && changeHuntDistanceCustom == message) + { + huntSearchDistance = param/100.0f; + if (huntSearchDistance > 0) + huntSearchDistance *= huntSearchDistance; + } + if (changeHuntSpeedCustom != 0 && changeHuntSpeedCustom == message) + { + huntSpeed = param/100.0f; + if (state == HUNTING_STAR) + Attack_Move(obj,Commands->Find_Object(lastAction.targetId),lastAction.location,huntSpeed,lastAction.distance,lastAction.attack,lastAction.overrideLocation); + } + if (changeReturnHomeSpeedCustom != 0 && changeReturnHomeSpeedCustom == message) + { + returnHomeSpeed = param/100.0f; + if (state == RETURNING_HOME) + Attack_Move(obj,Commands->Find_Object(lastAction.targetId),lastAction.location,returnHomeSpeed,lastAction.distance,lastAction.attack,lastAction.overrideLocation); + } + if (changeMaxSightFromHomeLocationCustom != 0 && changeMaxSightFromHomeLocationCustom == message) + { + maxSightFromHomeLocation = param/100.0f; + maxSightFromHomeLocation *= maxSightFromHomeLocation; + } + if (changeAttackSpeedCustom != 0 && changeAttackSpeedCustom == message) + { + attackSpeed = param/100.0f; + if (state == ATTACKING_TARGET) + Attack_Move(obj,Commands->Find_Object(lastAction.targetId),lastAction.location,attackSpeed,lastAction.distance,lastAction.attack,lastAction.overrideLocation); + } +} void JMG_Utility_AI_Goto_Player::Action_Complete(GameObject *obj,int action_id,ActionCompleteReason reason) { if (reason == ACTION_COMPLETE_PATH_BAD_DEST) @@ -2824,7 +2893,7 @@ targetId = Commands->Get_ID(damager); lastSeenTime = Commands->Get_Random_Int(30,60); state = ATTACKING_TARGET; - Attack_Move(obj,damager,Vector3(),Get_Float_Parameter("AttackSpeed"),attackArriveDistance,true,false); + Attack_Move(obj,damager,Vector3(),attackSpeed,attackArriveDistance,true,false); } } void JMG_Utility_AI_Goto_Player::Attack_Move(GameObject *obj,GameObject *target,Vector3 location,float speed,float distance,bool attack,bool overrideLocation) @@ -2861,7 +2930,7 @@ { GameObject *nearest = NULL; float nearDist = -1.0f; - Vector3 pos = maxSightFromHomeLocation > 0 ? homeLocation : Commands->Get_Position(obj); + Vector3 pos = Commands->Get_Position(obj); for (int x = 1;x < 128;x++) { GameObject *player = Get_GameObj(x); @@ -2877,6 +2946,8 @@ else if (player->As_SmartGameObj() && player->As_SmartGameObj()->Is_Stealthed()) continue; } + if (maxSightFromHomeLocation > 0 && JmgUtility::SimpleDistance(homeLocation,Commands->Get_Position(player)) > maxSightFromHomeLocation) + continue; float tempDist = JmgUtility::SimpleDistance(pos,Commands->Get_Position(player)); if (huntSearchDistance >= 0.0f && tempDist > huntSearchDistance) continue; @@ -2889,18 +2960,23 @@ } return nearest; } -void JMG_Utility_AI_Goto_Player::Return_Home(GameObject *obj) +void JMG_Utility_AI_Goto_Player::Return_Home(GameObject *obj,ValidLastLocation goNearLastWanderPoint) { - Vector3 wanderPos = Vector3(); - if (Get_Int_Parameter("WanderingAIGroupID") != -1 && GetRandomPosition(&wanderPos)) + Vector3 wanderPos; + if (goNearLastWanderPoint.valid && Commands->Get_Random(0.0f,1.0f) < Get_Float_Parameter("ChanceToInvestigateLastSeenLocation")) { state = WANDERING_GROUP; - Attack_Move(obj,NULL,wanderPos,Get_Float_Parameter("WanderSpeed"),1.0f,false,false); + Attack_Move(obj,NULL,goNearLastWanderPoint.location,wanderSpeed,1.0f,false,false); + } + else if (wanderingAiGroupId != -1 && GetRandomPosition(&wanderPos)) + { + state = WANDERING_GROUP; + Attack_Move(obj,NULL,wanderPos,wanderSpeed,1.0f,false,false); } else if (Get_Int_Parameter("ReturnHome")) { state = RETURNING_HOME; - Attack_Move(obj,NULL,homeLocation,Get_Float_Parameter("ReturnHomeSpeed"),1.0f,false,false); + Attack_Move(obj,NULL,homeLocation,returnHomeSpeed,1.0f,false,false); } else { @@ -2954,17 +3030,17 @@ if (star) { state = HUNTING_STAR; - Attack_Move(obj,Commands->Find_Object(lastAction.targetId),Commands->Get_Position(star),Get_Float_Parameter("HuntSpeed"),huntArriveDistance,true,true); + Attack_Move(obj,Commands->Find_Object(lastAction.targetId),Commands->Get_Position(star),huntSpeed,huntArriveDistance,true,true); } - else if (Get_Int_Parameter("WanderingAIGroupID") != -1 && GetRandomPosition(&wanderPos)) + else if (wanderingAiGroupId != -1 && GetRandomPosition(&wanderPos)) { state = WANDERING_GROUP; - Attack_Move(obj,Commands->Find_Object(lastAction.targetId),wanderPos,Get_Float_Parameter("WanderSpeed"),1.0f,true,true); + Attack_Move(obj,NULL,wanderPos,wanderSpeed,1.0f,true,true); } else { state = RETURNING_HOME; - Attack_Move(obj,Commands->Find_Object(lastAction.targetId),homeLocation,Get_Float_Parameter("ReturnHomeSpeed"),1.0f,true,true); + Attack_Move(obj,NULL,homeLocation,returnHomeSpeed,1.0f,true,true); } } bool JMG_Utility_AI_Goto_Player::Choose_Target(GameObject *obj,GameObject *target) @@ -2977,6 +3053,17 @@ return true; return false; } +JMG_Utility_AI_Goto_Player::ValidLastLocation::ValidLastLocation(int enemyId) +{ + GameObject *target = Commands->Find_Object(enemyId); + if (!target || !Commands->Get_Health(target)) + { + this->valid = false; + return; + } + this->location = Commands->Get_Position(target); + this->valid = true; +} AggressiveAttackSpotSystem *aggressiveAttackSpotSystemControl = NULL; void JMG_Utility_AI_Aggressive_Attack_Spot_Control::Created(GameObject *obj) { @@ -3113,7 +3200,7 @@ { GameObject *target = Commands->Find_Object(targetId); targetPos = Commands->Get_Position(target); - if (!target || !Commands->Get_Health(target) || Commands->Get_Player_Type(target) == -2 || Commands->Get_Player_Type(target) == Commands->Get_Player_Type(obj)) + if (!target || !Commands->Get_Health(target) || (Commands->Get_Player_Type(obj) != -2 && Commands->Get_Player_Type(target) == Commands->Get_Player_Type(obj))) { targetId = 0; IdleChoice(obj,true); @@ -3377,7 +3464,8 @@ { if (message == Get_Int_Parameter("TriggerCustom")) { - Send_Custom_Event_To_Object(obj,Get_Parameter("Preset"),Get_Int_Parameter("Custom"),Get_Int_Parameter("Param"),Get_Float_Parameter("Delay")); + int Param = Get_Int_Parameter("Param"); + Send_Custom_Event_To_Object(obj,Get_Parameter("Preset"),Get_Int_Parameter("Custom"),Param == -1 ? param : Param,Get_Float_Parameter("Delay")); } } void JMG_Utility_Basic_Spawner_Attach_Script::Created(GameObject *obj) @@ -3959,7 +4047,7 @@ if (EnemyID) { GameObject *Target = Commands->Find_Object(EnemyID); - if (!Target || !Commands->Get_Health(Target) || Commands->Get_Player_Type(Target) == Commands->Get_Player_Type(obj)) + if (!Target || !Commands->Get_Health(Target) || (Commands->Get_Player_Type(obj) != -2 && Commands->Get_Player_Type(Target) == Commands->Get_Player_Type(obj))) { EnemyID = 0; Goto_Location(obj); @@ -3992,7 +4080,7 @@ } void JMG_Utility_AI_Guardian_Infantry::Damaged(GameObject *obj,GameObject *damager,float damage) { - if (damage <= 0 || (EnemyID && EnemyTimeOutTime) || Commands->Get_Player_Type(damager) == Commands->Get_Player_Type(obj)) + if (damage <= 0 || (EnemyID && EnemyTimeOutTime) || (Commands->Get_Player_Type(obj) != -2 && Commands->Get_Player_Type(damager) == Commands->Get_Player_Type(obj))) return; EnemyID = Commands->Get_ID(damager); EnemyTimeOutTime = Commands->Get_Random_Int(2,5); @@ -4420,7 +4508,7 @@ } void JMG_Utility_Zone_Teleport_To_Random_Wander_Point::Entered(GameObject *obj,GameObject *enter) { - if (CheckPlayerType(enter,playerType) || Commands->Get_Player_Type(enter) == -4) + if (CheckPlayerType(enter,playerType)) return; Grab_Teleport_Spot(enter,5); } @@ -4428,11 +4516,9 @@ { if (The_Game()->Get_Game_Duration_S() < 1.0f) { - { char params[220]; sprintf(params,"%d,%.2f",wanderPointGroup,safeTeleportDistance); Commands->Attach_Script(enter,"JMG_Utility_Zone_Teleport_To_Random_Wander_Point_Attach",params); - } return false; } if (!attempts) @@ -4486,7 +4572,10 @@ Vector3 targetPos; float facing; if (!Get_A_Defense_Point(&targetPos,&facing)) + { + Commands->Start_Timer(obj,this,0.25f,1); return; + } MoveablePhysClass *mphys = obj->As_PhysicalGameObj() ? obj->As_PhysicalGameObj()->Peek_Physical_Object()->As_MoveablePhysClass() : NULL; if (mphys && mphys->Find_Teleport_Location(targetPos,safeTeleportDistance,&targetPos)) { @@ -5003,7 +5092,10 @@ int id = Get_Int_Parameter("ID"); GameObject *object = id ? (id == -1 ? sender : Commands->Find_Object(id)) : obj; if (object) - Commands->Send_Custom_Event(obj,object,Get_Int_Parameter("SendCustom"),Get_Int_Parameter("Param"),Get_Float_Parameter("Delay")); + { + int Param = Get_Int_Parameter("Param"); + Commands->Send_Custom_Event(obj,object,Get_Int_Parameter("SendCustom"),Param == -1 ? param : Param,Get_Float_Parameter("Delay")); + } } } void JMG_Utility_Custom_Destroy_Self::Created(GameObject *obj) @@ -5115,6 +5207,18 @@ huntStealth = Get_Int_Parameter("HuntStealth") ? true : false; removeIgnoreTime = 0; ignoreEnemyId = 0; + wanderingAiGroupId = Get_Int_Parameter("WanderingAIGroupID"); + wanderSpeed = Get_Float_Parameter("WanderSpeed"); + huntSpeed = Get_Float_Parameter("HuntSpeed"); + attackSpeed = Get_Float_Parameter("AttackSpeed"); + returnHomeSpeed = Get_Float_Parameter("ReturnHomeSpeed"); + changeWanderGroupCustom = Get_Int_Parameter("ChangeWanderGroupCustom"); + changeWanderSpeedCustom = Get_Int_Parameter("ChangeWanderSpeedCustom"); + changeHuntDistanceCustom = Get_Int_Parameter("ChangeHuntDistanceCustom"); + changeHuntSpeedCustom = Get_Int_Parameter("ChangeHuntSpeedCustom"); + changeReturnHomeSpeedCustom = Get_Int_Parameter("ChangeReturnHomeSpeedCustom"); + changeMaxSightFromHomeLocationCustom = Get_Int_Parameter("ChangeMaxSightFromHomeLocationCustom"); + changeAttackSpeedCustom = Get_Int_Parameter("ChangeAttackSpeedCustom"); maxSightFromHomeLocation = Get_Float_Parameter("MaxSightRangeFromHome"); maxSightFromHomeLocation *= maxSightFromHomeLocation; huntSearchDistance = Get_Float_Parameter("HuntSearchDistance") < 0.0f ? Get_Float_Parameter("HuntSearchDistance") : Get_Float_Parameter("HuntSearchDistance")*Get_Float_Parameter("HuntSearchDistance"); @@ -5126,6 +5230,8 @@ } attackArriveDistance = Get_Float_Parameter("AttackDistance") >= 0 ? Get_Float_Parameter("AttackDistance") : weaponEffectiveRange; huntArriveDistance = Get_Float_Parameter("HuntArriveDistance"); + wanderDistanceOverride = Get_Float_Parameter("WanderDistanceOverride"); + wanderDistanceOverride *= wanderDistanceOverride; Commands->Enable_Enemy_Seen(obj,true); Commands->Start_Timer(obj,this,1.0f,1); Commands->Start_Timer(obj,this,1.0f,2); @@ -5159,11 +5265,62 @@ targetId = Commands->Get_ID(seen); lastSeenTime = Commands->Get_Random_Int(30,60); state = ATTACKING_TARGET; - Attack_Move(obj,seen,Vector3(),Get_Float_Parameter("AttackSpeed"),attackArriveDistance,true,false); + Attack_Move(obj,seen,Vector3(),attackSpeed,attackArriveDistance,true,false); } if (targetId == Commands->Get_ID(seen)) lastSeenTime = Commands->Get_Random_Int(30,60); } +void JMG_Utility_AI_Goto_Enemy::Custom(GameObject *obj,int message,int param,GameObject *sender) +{ + if (changeWanderGroupCustom != 0 && changeWanderGroupCustom == message) + { + wanderingAiGroupId = param; + if (state == WANDERING_GROUP) + { + Vector3 wanderPos = Vector3(); + if (GetRandomPosition(&wanderPos)) + { + homeLocation = wanderPos; + Attack_Move(obj,Commands->Find_Object(lastAction.targetId),homeLocation,lastAction.speed,lastAction.distance,lastAction.attack,lastAction.overrideLocation); + } + } + } + if (changeWanderSpeedCustom != 0 && changeWanderSpeedCustom == message) + { + wanderSpeed = param/100.0f; + if (state == WANDERING_GROUP) + Attack_Move(obj,Commands->Find_Object(lastAction.targetId),lastAction.location,wanderSpeed,lastAction.distance,lastAction.attack,lastAction.overrideLocation); + } + if (changeHuntDistanceCustom != 0 && changeHuntDistanceCustom == message) + { + huntSearchDistance = param/100.0f; + if (huntSearchDistance > 0) + huntSearchDistance *= huntSearchDistance; + } + if (changeHuntSpeedCustom != 0 && changeHuntSpeedCustom == message) + { + huntSpeed = param/100.0f; + if (state == HUNTING_STAR) + Attack_Move(obj,Commands->Find_Object(lastAction.targetId),lastAction.location,huntSpeed,lastAction.distance,lastAction.attack,lastAction.overrideLocation); + } + if (changeReturnHomeSpeedCustom != 0 && changeReturnHomeSpeedCustom == message) + { + returnHomeSpeed = param/100.0f; + if (state == RETURNING_HOME) + Attack_Move(obj,Commands->Find_Object(lastAction.targetId),lastAction.location,returnHomeSpeed,lastAction.distance,lastAction.attack,lastAction.overrideLocation); + } + if (changeMaxSightFromHomeLocationCustom != 0 && changeMaxSightFromHomeLocationCustom == message) + { + maxSightFromHomeLocation = param/100.0f; + maxSightFromHomeLocation *= maxSightFromHomeLocation; + } + if (changeAttackSpeedCustom != 0 && changeAttackSpeedCustom == message) + { + attackSpeed = param/100.0f; + if (state == ATTACKING_TARGET) + Attack_Move(obj,Commands->Find_Object(lastAction.targetId),lastAction.location,attackSpeed,lastAction.distance,lastAction.attack,lastAction.overrideLocation); + } +} void JMG_Utility_AI_Goto_Enemy::Timer_Expired(GameObject *obj,int number) { if (number == 1) @@ -5174,25 +5331,26 @@ lastSeenTime--; if (!lastSeenTime) { + Return_Home(obj,ValidLastLocation(targetId)); targetId = 0; - Return_Home(obj); } } if (targetId) { GameObject *target = Commands->Find_Object(targetId); targetPos = Commands->Get_Position(target); - if (!target || !Commands->Get_Health(target) || Commands->Get_Player_Type(target) == -2 || (Commands->Get_Player_Type(obj) != -1 && Commands->Get_Player_Type(target) == Commands->Get_Player_Type(obj))) + if (!target || !Commands->Get_Health(target) || (Commands->Get_Player_Type(obj) != -2 && Commands->Get_Player_Type(target) == Commands->Get_Player_Type(obj)) || Is_Script_Attached(target,"JMG_Utility_AI_Goto_Enemy_Ignore_Object")) { + lastSeenTime = 0; + Return_Home(obj,ValidLastLocation(targetId)); targetId = 0; - Return_Home(obj); } } if (state == HUNTING_STAR) { GameObject *star = Commands->Find_Object(huntingEnemyId); - if (!star || !Commands->Get_Health(star)) - Return_Home(obj); + if (!star || !Commands->Get_Health(star) || (huntSearchDistance >= 0.0f && JmgUtility::SimpleDistance(Commands->Get_Position(star),Commands->Get_Position(obj)) > huntSearchDistance) || Is_Script_Attached(star,"JMG_Utility_AI_Goto_Enemy_Ignore_Object")) + Return_Home(obj,false); } if (state == IDLE || state == RETURNING_HOME || state == WANDERING_GROUP) { @@ -5200,27 +5358,21 @@ if (star) { state = HUNTING_STAR; - Attack_Move(obj,star,Vector3(),Get_Float_Parameter("HuntSpeed"),huntArriveDistance,false,false); + Attack_Move(obj,star,Vector3(),huntSpeed,huntArriveDistance,false,false); } } - if (state == HUNTING_STAR) - { - GameObject *star = Commands->Find_Object(huntingEnemyId); - if (!star || (huntSearchDistance >= 0.0f && JmgUtility::SimpleDistance(Commands->Get_Position(star),Commands->Get_Position(obj)) > huntSearchDistance)) - Return_Home(obj); - } - if (state == IDLE && Get_Int_Parameter("WanderingAIGroupID") != -1) + if (state == IDLE && wanderingAiGroupId != -1) { Vector3 wanderPos = Vector3(); if (GetRandomPosition(&wanderPos)) { state = WANDERING_GROUP; homeLocation = wanderPos; - Attack_Move(obj,NULL,wanderPos,Get_Float_Parameter("WanderSpeed"),1.0f,false,false); + Attack_Move(obj,NULL,wanderPos,wanderSpeed,1.0f,false,false); } } if (state == RETURNING_HOME || state == WANDERING_GROUP) - if (JmgUtility::SimpleDistance(lastAction.location,Commands->Get_Position(obj)) <= (obj->As_VehicleGameObj() ? 25.0f : 1.0f)) + if (JmgUtility::SimpleDistance(lastAction.location,Commands->Get_Position(obj)) <= (wanderDistanceOverride != 0 ? wanderDistanceOverride : (obj->As_VehicleGameObj() ? 25.0f : 1.0f))) state = IDLE; if (state == ACTION_BADPATH) Cant_Get_To_target(obj); @@ -5276,7 +5428,7 @@ targetId = Commands->Get_ID(damager); lastSeenTime = Commands->Get_Random_Int(30,60); state = ATTACKING_TARGET; - Attack_Move(obj,damager,Vector3(),Get_Float_Parameter("AttackSpeed"),attackArriveDistance,true,false); + Attack_Move(obj,damager,Vector3(),attackSpeed,attackArriveDistance,true,false); } } void JMG_Utility_AI_Goto_Enemy::Attack_Move(GameObject *obj,GameObject *target,Vector3 location,float speed,float distance,bool attack,bool overrideLocation) @@ -5315,7 +5467,7 @@ return NULL; GameObject *nearest = NULL; float nearDist = -1.0f; - Vector3 pos = maxSightFromHomeLocation > 0 ? homeLocation : Commands->Get_Position(obj); + Vector3 pos = Commands->Get_Position(obj); int myPlayerType = Commands->Get_Player_Type(obj); for (SLNode *current = GameObjManager::SmartGameObjList.Head();current;current = current->Next()) { @@ -5338,6 +5490,8 @@ else if (o->As_SmartGameObj() && o->As_SmartGameObj()->Is_Stealthed()) continue; } + if (maxSightFromHomeLocation > 0 && JmgUtility::SimpleDistance(homeLocation,Commands->Get_Position(o)) > maxSightFromHomeLocation) + continue; float tempDist = JmgUtility::SimpleDistance(pos,Commands->Get_Position(o)); if (huntSearchDistance >= 0.0f && tempDist > huntSearchDistance) continue; @@ -5350,18 +5504,23 @@ } return nearest; } -void JMG_Utility_AI_Goto_Enemy::Return_Home(GameObject *obj) +void JMG_Utility_AI_Goto_Enemy::Return_Home(GameObject *obj,ValidLastLocation goNearLastWanderPoint) { - Vector3 wanderPos = Vector3(); - if (Get_Int_Parameter("WanderingAIGroupID") != -1 && GetRandomPosition(&wanderPos)) + Vector3 wanderPos; + if (goNearLastWanderPoint.valid && Commands->Get_Random(0.0f,1.0f) < Get_Float_Parameter("ChanceToInvestigateLastSeenLocation")) { state = WANDERING_GROUP; - Attack_Move(obj,NULL,wanderPos,Get_Float_Parameter("WanderSpeed"),1.0f,false,false); + Attack_Move(obj,NULL,goNearLastWanderPoint.location,wanderSpeed,1.0f,false,false); + } + else if (wanderingAiGroupId != -1 && GetRandomPosition(&wanderPos)) + { + state = WANDERING_GROUP; + Attack_Move(obj,NULL,wanderPos,wanderSpeed,1.0f,false,false); } else if (Get_Int_Parameter("ReturnHome")) { state = RETURNING_HOME; - Attack_Move(obj,NULL,homeLocation,Get_Float_Parameter("ReturnHomeSpeed"),1.0f,false,false); + Attack_Move(obj,NULL,homeLocation,returnHomeSpeed,1.0f,false,false); } else { @@ -5415,17 +5574,17 @@ if (star && Commands->Get_ID(star) != ignoreEnemyId) { state = HUNTING_STAR; - Attack_Move(obj,Commands->Find_Object(lastAction.targetId),Commands->Get_Position(star),Get_Float_Parameter("HuntSpeed"),huntArriveDistance,true,true); + Attack_Move(obj,Commands->Find_Object(lastAction.targetId),Commands->Get_Position(star),huntSpeed,huntArriveDistance,true,true); } - else if (Get_Int_Parameter("WanderingAIGroupID") != -1 && GetRandomPosition(&wanderPos)) + else if (wanderingAiGroupId != -1 && GetRandomPosition(&wanderPos)) { state = WANDERING_GROUP; - Attack_Move(obj,Commands->Find_Object(lastAction.targetId),wanderPos,Get_Float_Parameter("WanderSpeed"),1.0f,true,true); + Attack_Move(obj,NULL,wanderPos,wanderSpeed,1.0f,true,true); } else { state = RETURNING_HOME; - Attack_Move(obj,Commands->Find_Object(lastAction.targetId),homeLocation,Get_Float_Parameter("ReturnHomeSpeed"),1.0f,true,true); + Attack_Move(obj,NULL,homeLocation,returnHomeSpeed,1.0f,true,true); } } bool JMG_Utility_AI_Goto_Enemy::Choose_Target(GameObject *obj,GameObject *target) @@ -5438,6 +5597,17 @@ return true; return false; } +JMG_Utility_AI_Goto_Enemy::ValidLastLocation::ValidLastLocation(int enemyId) +{ + GameObject *target = Commands->Find_Object(enemyId); + if (!target || !Commands->Get_Health(target)) + { + this->valid = false; + return; + } + this->location = Commands->Get_Position(target); + this->valid = true; +} void JMG_Utility_AI_Goto_Enemy_Not_Star::Created(GameObject *obj) { state = IDLE; @@ -5451,6 +5621,18 @@ huntStealth = Get_Int_Parameter("HuntStealth") ? true : false; removeIgnoreTime = 0; ignoreEnemyId = 0; + wanderingAiGroupId = Get_Int_Parameter("WanderingAIGroupID"); + wanderSpeed = Get_Float_Parameter("WanderSpeed"); + huntSpeed = Get_Float_Parameter("HuntSpeed"); + attackSpeed = Get_Float_Parameter("AttackSpeed"); + returnHomeSpeed = Get_Float_Parameter("ReturnHomeSpeed"); + changeWanderGroupCustom = Get_Int_Parameter("ChangeWanderGroupCustom"); + changeWanderSpeedCustom = Get_Int_Parameter("ChangeWanderSpeedCustom"); + changeHuntDistanceCustom = Get_Int_Parameter("ChangeHuntDistanceCustom"); + changeHuntSpeedCustom = Get_Int_Parameter("ChangeHuntSpeedCustom"); + changeReturnHomeSpeedCustom = Get_Int_Parameter("ChangeReturnHomeSpeedCustom"); + changeMaxSightFromHomeLocationCustom = Get_Int_Parameter("ChangeMaxSightFromHomeLocationCustom"); + changeAttackSpeedCustom = Get_Int_Parameter("ChangeAttackSpeedCustom"); maxSightFromHomeLocation = Get_Float_Parameter("MaxSightRangeFromHome"); maxSightFromHomeLocation *= maxSightFromHomeLocation; huntSearchDistance = Get_Float_Parameter("HuntSearchDistance") < 0.0f ? Get_Float_Parameter("HuntSearchDistance") : Get_Float_Parameter("HuntSearchDistance")*Get_Float_Parameter("HuntSearchDistance"); @@ -5462,6 +5644,8 @@ } attackArriveDistance = Get_Float_Parameter("AttackDistance") >= 0 ? Get_Float_Parameter("AttackDistance") : weaponEffectiveRange; huntArriveDistance = Get_Float_Parameter("HuntArriveDistance"); + wanderDistanceOverride = Get_Float_Parameter("WanderDistanceOverride"); + wanderDistanceOverride *= wanderDistanceOverride; Commands->Enable_Enemy_Seen(obj,true); Commands->Start_Timer(obj,this,1.0f,1); Commands->Start_Timer(obj,this,1.0f,2); @@ -5495,7 +5679,7 @@ targetId = Commands->Get_ID(seen); lastSeenTime = Commands->Get_Random_Int(30,60); state = ATTACKING_TARGET; - Attack_Move(obj,seen,Vector3(),Get_Float_Parameter("AttackSpeed"),attackArriveDistance,true,false); + Attack_Move(obj,seen,Vector3(),attackSpeed,attackArriveDistance,true,false); } if (targetId == Commands->Get_ID(seen)) lastSeenTime = Commands->Get_Random_Int(30,60); @@ -5510,25 +5694,26 @@ lastSeenTime--; if (!lastSeenTime) { + Return_Home(obj,ValidLastLocation(targetId)); targetId = 0; - Return_Home(obj); } } if (targetId) { GameObject *target = Commands->Find_Object(targetId); targetPos = Commands->Get_Position(target); - if (!target || !Commands->Get_Health(target) || Commands->Get_Player_Type(target) == -2 || (Commands->Get_Player_Type(obj) != -1 && Commands->Get_Player_Type(target) == Commands->Get_Player_Type(obj))) + if (!target || !Commands->Get_Health(target) || (Commands->Get_Player_Type(obj) != -2 && Commands->Get_Player_Type(target) == Commands->Get_Player_Type(obj)) || Is_Script_Attached(target,"JMG_Utility_AI_Goto_Enemy_Not_Star_Ignore_Object")) { + lastSeenTime = 0; + Return_Home(obj,ValidLastLocation(targetId)); targetId = 0; - Return_Home(obj); } } if (state == HUNTING_STAR) { GameObject *star = Commands->Find_Object(huntingEnemyId); - if (!star || !Commands->Get_Health(star)) - Return_Home(obj); + if (!star || !Commands->Get_Health(star) || (huntSearchDistance >= 0.0f && JmgUtility::SimpleDistance(Commands->Get_Position(star),Commands->Get_Position(obj)) > huntSearchDistance) || Is_Script_Attached(star,"JMG_Utility_AI_Goto_Enemy_Not_Star_Ignore_Object")) + Return_Home(obj,false); } if (state == IDLE || state == RETURNING_HOME || state == WANDERING_GROUP) { @@ -5536,27 +5721,21 @@ if (star) { state = HUNTING_STAR; - Attack_Move(obj,star,Vector3(),Get_Float_Parameter("HuntSpeed"),huntArriveDistance,false,false); + Attack_Move(obj,star,Vector3(),huntSpeed,huntArriveDistance,false,false); } } - if (state == HUNTING_STAR) - { - GameObject *star = Commands->Find_Object(huntingEnemyId); - if (!star || (huntSearchDistance >= 0.0f && JmgUtility::SimpleDistance(Commands->Get_Position(star),Commands->Get_Position(obj)) > huntSearchDistance)) - Return_Home(obj); - } - if (state == IDLE && Get_Int_Parameter("WanderingAIGroupID") != -1) + if (state == IDLE && wanderingAiGroupId != -1) { Vector3 wanderPos = Vector3(); if (GetRandomPosition(&wanderPos)) { state = WANDERING_GROUP; homeLocation = wanderPos; - Attack_Move(obj,NULL,wanderPos,Get_Float_Parameter("WanderSpeed"),1.0f,false,false); + Attack_Move(obj,NULL,wanderPos,wanderSpeed,1.0f,false,false); } } if (state == RETURNING_HOME || state == WANDERING_GROUP) - if (JmgUtility::SimpleDistance(lastAction.location,Commands->Get_Position(obj)) <= (obj->As_VehicleGameObj() ? 25.0f : 1.0f)) + if (JmgUtility::SimpleDistance(lastAction.location,Commands->Get_Position(obj)) <= (wanderDistanceOverride != 0 ? wanderDistanceOverride : (obj->As_VehicleGameObj() ? 25.0f : 1.0f))) state = IDLE; if (state == ACTION_BADPATH) Cant_Get_To_target(obj); @@ -5585,6 +5764,57 @@ huntArriveDistance += Commands->Get_Random(Get_Float_Parameter("RandomHuntArriveDistance"),Get_Float_Parameter("RandomHuntArriveDistance")); } } +void JMG_Utility_AI_Goto_Enemy_Not_Star::Custom(GameObject *obj,int message,int param,GameObject *sender) +{ + if (changeWanderGroupCustom != 0 && changeWanderGroupCustom == message) + { + wanderingAiGroupId = param; + if (state == WANDERING_GROUP) + { + Vector3 wanderPos = Vector3(); + if (GetRandomPosition(&wanderPos)) + { + homeLocation = wanderPos; + Attack_Move(obj,Commands->Find_Object(lastAction.targetId),homeLocation,lastAction.speed,lastAction.distance,lastAction.attack,lastAction.overrideLocation); + } + } + } + if (changeWanderSpeedCustom != 0 && changeWanderSpeedCustom == message) + { + wanderSpeed = param/100.0f; + if (state == WANDERING_GROUP) + Attack_Move(obj,Commands->Find_Object(lastAction.targetId),lastAction.location,wanderSpeed,lastAction.distance,lastAction.attack,lastAction.overrideLocation); + } + if (changeHuntDistanceCustom != 0 && changeHuntDistanceCustom == message) + { + huntSearchDistance = param/100.0f; + if (huntSearchDistance > 0) + huntSearchDistance *= huntSearchDistance; + } + if (changeHuntSpeedCustom != 0 && changeHuntSpeedCustom == message) + { + huntSpeed = param/100.0f; + if (state == HUNTING_STAR) + Attack_Move(obj,Commands->Find_Object(lastAction.targetId),lastAction.location,huntSpeed,lastAction.distance,lastAction.attack,lastAction.overrideLocation); + } + if (changeReturnHomeSpeedCustom != 0 && changeReturnHomeSpeedCustom == message) + { + returnHomeSpeed = param/100.0f; + if (state == RETURNING_HOME) + Attack_Move(obj,Commands->Find_Object(lastAction.targetId),lastAction.location,returnHomeSpeed,lastAction.distance,lastAction.attack,lastAction.overrideLocation); + } + if (changeMaxSightFromHomeLocationCustom != 0 && changeMaxSightFromHomeLocationCustom == message) + { + maxSightFromHomeLocation = param/100.0f; + maxSightFromHomeLocation *= maxSightFromHomeLocation; + } + if (changeAttackSpeedCustom != 0 && changeAttackSpeedCustom == message) + { + attackSpeed = param/100.0f; + if (state == ATTACKING_TARGET) + Attack_Move(obj,Commands->Find_Object(lastAction.targetId),lastAction.location,attackSpeed,lastAction.distance,lastAction.attack,lastAction.overrideLocation); + } +} void JMG_Utility_AI_Goto_Enemy_Not_Star::Action_Complete(GameObject *obj,int action_id,ActionCompleteReason reason) { if (reason == ACTION_COMPLETE_PATH_BAD_DEST) @@ -5612,7 +5842,7 @@ targetId = Commands->Get_ID(damager); lastSeenTime = Commands->Get_Random_Int(30,60); state = ATTACKING_TARGET; - Attack_Move(obj,damager,Vector3(),Get_Float_Parameter("AttackSpeed"),attackArriveDistance,true,false); + Attack_Move(obj,damager,Vector3(),attackSpeed,attackArriveDistance,true,false); } } void JMG_Utility_AI_Goto_Enemy_Not_Star::Attack_Move(GameObject *obj,GameObject *target,Vector3 location,float speed,float distance,bool attack,bool overrideLocation) @@ -5651,7 +5881,7 @@ return NULL; GameObject *nearest = NULL; float nearDist = -1.0f; - Vector3 pos = maxSightFromHomeLocation > 0 ? homeLocation : Commands->Get_Position(obj); + Vector3 pos = Commands->Get_Position(obj); int myPlayerType = Commands->Get_Player_Type(obj); for (SLNode *current = GameObjManager::SmartGameObjList.Head();current;current = current->Next()) { @@ -5674,6 +5904,8 @@ else if (o->As_SmartGameObj() && o->As_SmartGameObj()->Is_Stealthed()) continue; } + if (maxSightFromHomeLocation > 0 && JmgUtility::SimpleDistance(homeLocation,Commands->Get_Position(o)) > maxSightFromHomeLocation) + continue; float tempDist = JmgUtility::SimpleDistance(pos,Commands->Get_Position(o)); if (huntSearchDistance >= 0.0f && tempDist > huntSearchDistance) continue; @@ -5686,18 +5918,23 @@ } return nearest; } -void JMG_Utility_AI_Goto_Enemy_Not_Star::Return_Home(GameObject *obj) +void JMG_Utility_AI_Goto_Enemy_Not_Star::Return_Home(GameObject *obj,ValidLastLocation goNearLastWanderPoint) { - Vector3 wanderPos = Vector3(); - if (Get_Int_Parameter("WanderingAIGroupID") != -1 && GetRandomPosition(&wanderPos)) + Vector3 wanderPos; + if (goNearLastWanderPoint.valid && Commands->Get_Random(0.0f,1.0f) < Get_Float_Parameter("ChanceToInvestigateLastSeenLocation")) { state = WANDERING_GROUP; - Attack_Move(obj,NULL,wanderPos,Get_Float_Parameter("WanderSpeed"),1.0f,false,false); + Attack_Move(obj,NULL,goNearLastWanderPoint.location,wanderSpeed,1.0f,false,false); + } + else if (wanderingAiGroupId != -1 && GetRandomPosition(&wanderPos)) + { + state = WANDERING_GROUP; + Attack_Move(obj,NULL,wanderPos,wanderSpeed,1.0f,false,false); } else if (Get_Int_Parameter("ReturnHome")) { state = RETURNING_HOME; - Attack_Move(obj,NULL,homeLocation,Get_Float_Parameter("ReturnHomeSpeed"),1.0f,false,false); + Attack_Move(obj,NULL,homeLocation,returnHomeSpeed,1.0f,false,false); } else { @@ -5751,17 +5988,17 @@ if (star && Commands->Get_ID(star) != ignoreEnemyId) { state = HUNTING_STAR; - Attack_Move(obj,Commands->Find_Object(lastAction.targetId),Commands->Get_Position(star),Get_Float_Parameter("HuntSpeed"),huntArriveDistance,true,true); + Attack_Move(obj,Commands->Find_Object(lastAction.targetId),Commands->Get_Position(star),huntSpeed,huntArriveDistance,true,true); } - else if (Get_Int_Parameter("WanderingAIGroupID") != -1 && GetRandomPosition(&wanderPos)) + else if (wanderingAiGroupId != -1 && GetRandomPosition(&wanderPos)) { state = WANDERING_GROUP; - Attack_Move(obj,Commands->Find_Object(lastAction.targetId),wanderPos,Get_Float_Parameter("WanderSpeed"),1.0f,true,true); + Attack_Move(obj,NULL,wanderPos,wanderSpeed,1.0f,true,true); } else { state = RETURNING_HOME; - Attack_Move(obj,Commands->Find_Object(lastAction.targetId),homeLocation,Get_Float_Parameter("ReturnHomeSpeed"),1.0f,true,true); + Attack_Move(obj,NULL,homeLocation,returnHomeSpeed,1.0f,true,true); } } bool JMG_Utility_AI_Goto_Enemy_Not_Star::Choose_Target(GameObject *obj,GameObject *target) @@ -5774,6 +6011,17 @@ return true; return false; } +JMG_Utility_AI_Goto_Enemy_Not_Star::ValidLastLocation::ValidLastLocation(int enemyId) +{ + GameObject *target = Commands->Find_Object(enemyId); + if (!target || !Commands->Get_Health(target)) + { + this->valid = false; + return; + } + this->location = Commands->Get_Position(target); + this->valid = true; +} void JMG_Utility_Grant_Key_On_Create::Created(GameObject *obj) { Commands->Grant_Key(obj,Get_Int_Parameter("Key"),Get_Int_Parameter("Grant") ? true : false); @@ -5781,14 +6029,21 @@ void JMG_Utility_Custom_Send_Custom::Created(GameObject *obj) { recieveMessage = Get_Int_Parameter("Custom"); + id = Get_Int_Parameter("ID"); + custom = Get_Int_Parameter("SendCustom"); + Param = Get_Int_Parameter("Param"); + delay = Get_Float_Parameter("Delay"); + randomDelay = Get_Float_Parameter("RandomDelay"); + randomChance = Get_Float_Parameter("RandomChance"); } void JMG_Utility_Custom_Send_Custom::Custom(GameObject *obj,int message,int param,GameObject *sender) { if (message == recieveMessage) { - int id = Get_Int_Parameter("ID"); + if (randomChance && randomChance < Commands->Get_Random(0.0f,1.0f)) + return; GameObject *object = id ? (id == -1 ? sender : Commands->Find_Object(id)) : obj; - Commands->Send_Custom_Event(obj,object,Get_Int_Parameter("SendCustom"),Get_Int_Parameter("Param"),Get_Float_Parameter("Delay")); + Commands->Send_Custom_Event(obj,object,custom,Param == -1 ? param : Param,delay+(randomDelay > 0 ? Commands->Get_Random(0.0f,randomDelay) : 0.0f)); } } void JMG_Utility_Damage_Unoccupied_Vehicle::Created(GameObject *obj) @@ -5887,7 +6142,7 @@ if (EnemyID) { GameObject *Target = Commands->Find_Object(EnemyID); - if (!Target || !Commands->Get_Health(Target) || Commands->Get_Player_Type(Target) == Commands->Get_Player_Type(obj)) + if (!Target || !Commands->Get_Health(Target) || (Commands->Get_Player_Type(obj) != -2 && Commands->Get_Player_Type(Target) == Commands->Get_Player_Type(obj))) { EnemyID = 0; Goto_Location(obj); @@ -5948,7 +6203,7 @@ } void JMG_Utility_AI_Guardian_Vehicle::Damaged(GameObject *obj,GameObject *damager,float damage) { - if (damage <= 0 || (EnemyID && EnemyTimeOutTime) || Commands->Get_Player_Type(damager) == Commands->Get_Player_Type(obj)) + if (damage <= 0 || (EnemyID && EnemyTimeOutTime) || (Commands->Get_Player_Type(obj) != -2 && Commands->Get_Player_Type(damager) == Commands->Get_Player_Type(obj))) return; EnemyID = Commands->Get_ID(damager); EnemyTimeOutTime = Commands->Get_Random_Int(2,5); @@ -7195,7 +7450,7 @@ if (dist > warnDistance) { screenEffectOn[x] = true; - float TempDistCalc = 1-(dist-maxSurviveDistance)/(warnDistance-maxSurviveDistance); + float TempDistCalc = min(1-(dist-maxSurviveDistance)/(warnDistance-maxSurviveDistance),1.0f); float inverted = 1-TempDistCalc; Set_Screen_Fade_Color_Player(player,JMG_Utility_Set_Screen_Color_Fade_Controller::color[x].X*inverted+screenFadeColor.X,JMG_Utility_Set_Screen_Color_Fade_Controller::color[x].Y*inverted+screenFadeColor.Y,JMG_Utility_Set_Screen_Color_Fade_Controller::color[x].Z*inverted+screenFadeColor.Z,0.1f); Set_Screen_Fade_Opacity_Player(player,JMG_Utility_Set_Screen_Color_Fade_Controller::opacity[x]*inverted+TempDistCalc,0.1f); @@ -7221,7 +7476,7 @@ if (dist > aircraftWarnDistance) { screenEffectOn[x] = true; - float TempDistCalc = 1-(dist-maxSurviveDistance)/(aircraftWarnDistance-maxSurviveDistance); + float TempDistCalc = min(1-(dist-maxSurviveDistance)/(aircraftWarnDistance-maxSurviveDistance),1.0f); float inverted = 1-TempDistCalc; Set_Screen_Fade_Color_Player(player,JMG_Utility_Set_Screen_Color_Fade_Controller::color[x].X*inverted+screenFadeColor.X,JMG_Utility_Set_Screen_Color_Fade_Controller::color[x].Y*inverted+screenFadeColor.Y,JMG_Utility_Set_Screen_Color_Fade_Controller::color[x].Z*inverted+screenFadeColor.Z,0.1f); Set_Screen_Fade_Opacity_Player(player,JMG_Utility_Set_Screen_Color_Fade_Controller::opacity[x]*inverted+TempDistCalc,0.1f); @@ -7243,7 +7498,7 @@ if (dist > vehicleWarnDistance) { screenEffectOn[x] = true; - float TempDistCalc = 1-(dist-maxSurviveDistance)/(vehicleWarnDistance-maxSurviveDistance); + float TempDistCalc = min(1-(dist-maxSurviveDistance)/(vehicleWarnDistance-maxSurviveDistance),1.0f); float inverted = 1-TempDistCalc; Set_Screen_Fade_Color_Player(player,JMG_Utility_Set_Screen_Color_Fade_Controller::color[x].X*inverted+screenFadeColor.X,JMG_Utility_Set_Screen_Color_Fade_Controller::color[x].Y*inverted+screenFadeColor.Y,JMG_Utility_Set_Screen_Color_Fade_Controller::color[x].Z*inverted+screenFadeColor.Z,0.1f); Set_Screen_Fade_Opacity_Player(player,JMG_Utility_Set_Screen_Color_Fade_Controller::opacity[x]*inverted+TempDistCalc,0.1f); @@ -7470,7 +7725,10 @@ int id = Get_Int_Parameter("ID"); GameObject *object = id ? (id == -1 ? sender : Commands->Find_Object(id)) : obj; if (object) - Commands->Send_Custom_Event(obj,object,Get_Int_Parameter("SendCustom"),Get_Int_Parameter("Param"),Get_Float_Parameter("Delay")); + { + int Param = Get_Int_Parameter("Param"); + Commands->Send_Custom_Event(obj,object,Get_Int_Parameter("SendCustom"),Param == -1 ? param : Param,Get_Float_Parameter("Delay")); + } this->Destroy_Script(); } } @@ -7531,7 +7789,10 @@ int id = Get_Int_Parameter("ID"); GameObject *object = id ? (id == -1 ? sender : Commands->Find_Object(id)) : obj; if (object) - Commands->Send_Custom_Event(obj,object,Get_Int_Parameter("SendCustom"),Get_Int_Parameter("Param"),Get_Float_Parameter("Delay")); + { + int Param = Get_Int_Parameter("Param"); + Commands->Send_Custom_Event(obj,object,Get_Int_Parameter("SendCustom"),Param == -1 ? param : Param,Get_Float_Parameter("Delay")); + } this->Destroy_Script(); } } @@ -7704,10 +7965,13 @@ { if (message == custom) { + if (BasicObjectiveSystem.Get_Objective_Status(Get_Int_Parameter("ObjectiveID")) != NewObjectiveSystem::Accomplished) + { BasicObjectiveSystem.Add_Objective(Get_Int_Parameter("ObjectiveID"),NewObjectiveSystem::Primary,NewObjectiveSystem::Hidden,0,"",0); BasicObjectiveSystem.Set_Objective_Status(Get_Int_Parameter("ObjectiveID"),NewObjectiveSystem::Failed); } } +} void JMG_Utility_Force_Player_Team_At_Gameover::Created(GameObject *obj) { team = Get_Int_Parameter("Team"); @@ -7759,7 +8023,7 @@ if (EnemyID) { GameObject *Target = Commands->Find_Object(EnemyID); - if (!Target || !Commands->Get_Health(Target) || Commands->Get_Player_Type(Target) == Commands->Get_Player_Type(obj)) + if (!Target || !Commands->Get_Health(Target) || (Commands->Get_Player_Type(obj) != -2 && Commands->Get_Player_Type(Target) == Commands->Get_Player_Type(obj))) { EnemyID = 0; Goto_Location(obj); @@ -7793,7 +8057,7 @@ } void JMG_Utility_AI_Guardian_Generic::Damaged(GameObject *obj,GameObject *damager,float damage) { - if (damage <= 0 || (EnemyID && EnemyTimeOutTime) || Commands->Get_Player_Type(damager) == Commands->Get_Player_Type(obj)) + if (damage <= 0 || (EnemyID && EnemyTimeOutTime) || (Commands->Get_Player_Type(obj) != -2 && Commands->Get_Player_Type(damager) == Commands->Get_Player_Type(obj))) return; EnemyID = Commands->Get_ID(damager); EnemyTimeOutTime = Commands->Get_Random_Int(2,5); @@ -8302,7 +8566,7 @@ rate = Get_Float_Parameter("Rate"); repeat = Get_Int_Parameter("Repeat") ? true : false; id = Get_Int_Parameter("ID"); - message = Get_Int_Parameter("Message"); + custom = Get_Int_Parameter("Message"); param = Get_Int_Parameter("Param"); enabled = Get_Int_Parameter("StartsEnabled") ? true : false; enableCustom = Get_Int_Parameter("EnableCustom"); @@ -8330,7 +8594,7 @@ { GameObject *object = !id ? obj : Commands->Find_Object(id); if (object) - Commands->Send_Custom_Event(obj,object,message,param,0); + Commands->Send_Custom_Event(obj,object,custom,param,0); if (!repeat) { Destroy_Script(); @@ -8348,7 +8612,7 @@ rate = Get_Float_Parameter("Rate"); repeat = Get_Int_Parameter("Repeat") ? true : false; id = Get_Int_Parameter("ID"); - message = Get_Int_Parameter("Message"); + custom = Get_Int_Parameter("Message"); param = Get_Int_Parameter("Param"); enabled = Get_Int_Parameter("StartsEnabled") ? true : false; enableCustom = Get_Int_Parameter("EnableCustom"); @@ -8376,7 +8640,7 @@ { GameObject *object = !id ? obj : Commands->Find_Object(id); if (object) - Commands->Send_Custom_Event(obj,object,message,param,0); + Commands->Send_Custom_Event(obj,object,custom,param,0); if (!repeat) { Destroy_Script(); @@ -8401,7 +8665,7 @@ rate = Get_Float_Parameter("Rate"); repeat = Get_Int_Parameter("Repeat") ? true : false; id = Get_Int_Parameter("ID"); - message = Get_Int_Parameter("Message"); + custom = Get_Int_Parameter("Message"); param = Get_Int_Parameter("Param"); enabled = Get_Int_Parameter("StartsEnabled") ? true : false; enableCustom = Get_Int_Parameter("EnableCustom"); @@ -8458,7 +8722,7 @@ { GameObject *object = !id ? obj : Commands->Find_Object(id); if (object) - Commands->Send_Custom_Event(obj,object,message,param == -1 ? paramOverride : param,0); + Commands->Send_Custom_Event(obj,object,custom,param == -1 ? paramOverride : param,0); if (!repeat) Destroy_Script(); } @@ -8609,7 +8873,7 @@ lastTriggerTime = currentTime; GameObject *object = id ? (id == -1 ? sender : Commands->Find_Object(id)) : obj; if (object) - Commands->Send_Custom_Event(obj,object,sendCustom,params,delay); + Commands->Send_Custom_Event(obj,object,sendCustom,params == -1 ? param : params,delay); } if (message == enableCustom) { @@ -9041,6 +9305,1075 @@ Commands->Set_Facing(newObject,Commands->Get_Facing(obj)); Commands->Destroy_Object(obj); } +SList JMG_Utility_Basic_Spawner_In_Radius::spawnObjectNodeList; +void JMG_Utility_Basic_Spawner_In_Radius::Created(GameObject *obj) +{ + scriptId = Get_Int_Parameter("Script_ID"); + if (scriptId == -1) + scriptId = this->Get_ID(); + spawnedObjects = 0; + spawnLocation = Get_Vector3_Parameter("Spawn_Location"); + if (spawnLocation.X == -1.0f && spawnLocation.Y == -1.0f) + { + Vector3 mypos = Commands->Get_Position(obj); + spawnLocation.X = mypos.X; + spawnLocation.Y = mypos.Y; + if (spawnLocation.Z == -1.0f) + spawnLocation.Z = mypos.Z; + } + spawnAtATime = Get_Int_Parameter("Spawn_At_A_Time"); + spawnLimit = Get_Int_Parameter("Spawn_Limit"); + minRadius = Get_Float_Parameter("Min_Spawn_Radius"); + maxRadius = Get_Float_Parameter("Max_Spawn_Radius"); + initialSpawnHeight = Get_Float_Parameter("Initial_Spawn_Height"); + xMultiplier = Get_Float_Parameter("X_Multiplier"); + yMultiplier = Get_Float_Parameter("Y_Multiplier"); + rate = Get_Float_Parameter("Spawn_Rate"); + randomRate = Get_Float_Parameter("Random_Spawn_Rate"); + collisionCheck = Get_Int_Parameter("Collision_Check")?true:false; + retryAttempts = Get_Int_Parameter("Collision_Retry_Attempts"); + addHeight = Get_Float_Parameter("Collision_Add_Height"); + changeSpawnCapCustom = Get_Int_Parameter("Change_Spawn_Cap_Custom"); + sprintf(preset,Get_Parameter("Spawn_Preset")); + spawnCount = 0; + int initialSpawn = Get_Int_Parameter("Initial_Spawn"); + if (initialSpawn == -1) + initialSpawn = spawnAtATime; + pointMustBeInPathfind = Get_Int_Parameter("Point_Must_Be_In_Pathfind")?true:false; + manualFacing = Get_Int_Parameter("Manual_Facing")?true:false; + faceLocation = Get_Vector3_Parameter("Face_Location"); + faceDirection = Get_Float_Parameter("Face_Direction"); + ignoreRayCastFailure = Get_Int_Parameter("Ignore_Ray_Cast_Failure")?true:false; + minDistanceBetweenObjects = Get_Float_Parameter("Min_Distance_Between_Objects"); + minDistanceBetweenObjects *= minDistanceBetweenObjects; + spawnGroupId = Get_Int_Parameter("Spawn_Group_ID"); + for (int x = 0;x < initialSpawn;x++) + for (int y = 0;y < 5;y++) + { + JMG_Utility_Basic_Spawner_In_Radius::SpawnFailureTypes spawnResult = AttemptSpawn(obj); + if (spawnResult == SpawnFailureTypes::SUCCESS) + break; + if (spawnResult == SpawnFailureTypes::LIMIT_REACHED) + x = initialSpawn+1; + } + Commands->Start_Timer(obj,this,rate+(randomRate ? Commands->Get_Random(-randomRate,randomRate) : 0.0f),1); +} +void JMG_Utility_Basic_Spawner_In_Radius::Timer_Expired(GameObject *obj,int number) +{ + if (number == 1 && !The_Game()->Is_Game_Over()) + { + JMG_Utility_Basic_Spawner_In_Radius::SpawnFailureTypes spawnResult = AttemptSpawn(obj); + if (spawnResult == SpawnFailureTypes::SPAWN_BLOCKED) + { + Commands->Start_Timer(obj,this,0.1f,1); + return; + } + if (spawnResult == SpawnFailureTypes::SUCCESS) + Commands->Start_Timer(obj,this,rate+(randomRate ? Commands->Get_Random(-randomRate,randomRate) : 0.0f),1); + } +} +void JMG_Utility_Basic_Spawner_In_Radius::Custom(GameObject *obj,int message,int param,GameObject *sender) +{ + if (changeSpawnCapCustom == -1 && message == changeSpawnCapCustom) + { + spawnAtATime = param; + } + if (message == 6873523 && param == scriptId) + { + spawnedObjects++; + } + if (message == 6873524 && param == scriptId) + { + spawnedObjects--; + Commands->Send_Custom_Event(obj,obj,6873525,scriptId,rate+(randomRate ? Commands->Get_Random(-randomRate,randomRate) : 0.0f)); + } + if (message == 6873525 && param == scriptId) + { + if (AttemptSpawn(obj) == SpawnFailureTypes::SPAWN_BLOCKED) + Commands->Send_Custom_Event(obj,obj,6873525,scriptId,0.1f); + } +} +JMG_Utility_Basic_Spawner_In_Radius::SpawnFailureTypes JMG_Utility_Basic_Spawner_In_Radius::AttemptSpawn(GameObject *obj) +{ + if (!(spawnedObjects < spawnAtATime)) + return SpawnFailureTypes::LIMIT_REACHED; + if (!((spawnLimit >= 0 && spawnCount < spawnLimit) || spawnLimit < 0)) + return SpawnFailureTypes::LIMIT_REACHED; + float distance = (minRadius < maxRadius ? Commands->Get_Random(minRadius,maxRadius) : minRadius); + float facing = Commands->Get_Random(-180.0f,180.0f); + Vector3 topRay = spawnLocation,bottomRay; + topRay.X = spawnLocation.X+cos(facing)*(distance*xMultiplier); + topRay.Y = spawnLocation.Y+sin(facing)*(distance*yMultiplier); + bottomRay = topRay; + topRay.Z = spawnLocation.Z; + Vector3 bottom,top; + PhysicsSceneClass::Get_Instance()->Get_Level_Extents(bottom,top); + if (spawnLocation.Z < bottom.Z) + bottomRay.Z = top.Z+1.0f; + else + bottomRay.Z = bottom.Z-1.0f; + CastResultStruct res; + res.ComputeContactPoint = true; + LineSegClass ray(topRay,bottomRay); + PhysRayCollisionTestClass coltest(ray, &res, TERRAIN_ONLY_COLLISION_GROUP); + PhysicsSceneClass::Get_Instance()->Cast_Ray(coltest,false); + if (coltest.CollidedRenderObj && Vector3::Dot_Product(res.Normal,ray.Get_Dir()) <= 0) + { + bottomRay.Z = res.ContactPoint.Z+initialSpawnHeight; + Vector3 unneeded; + if (pointMustBeInPathfind && !Get_Random_Pathfind_Spot(bottomRay,0.0f,&unneeded)) + return SpawnFailureTypes::SPAWN_BLOCKED; + if (CheckIfObjectIsNearAnotherObject(bottomRay)) + return SpawnFailureTypes::SPAWN_BLOCKED; + GameObject *spawned = Commands->Create_Object(preset,bottomRay); + if (!spawned) + { + char errorMsg[220]; + sprintf(errorMsg,"msg JMG_Utility_Basic_Spawner_In_Radius_Attached ERROR: Preset %s not found!",preset); + Console_Input(errorMsg); + return SpawnFailureTypes::SPAWN_CODE_ERROR; + } + if (manualFacing) + { + if (JmgUtility::SimpleDistance(Vector3(0.0f,0.0f,0.0f),faceLocation) > 0.0f) + { + Vector3 facePos = faceLocation; + facePos.X -= bottomRay.X; + facePos.Y -= bottomRay.Y; + SetFacing(spawned,atan2(facePos.Y,facePos.X)*(180.0f/PI)); + } + else + SetFacing(spawned,faceDirection); + } + else + SetFacing(spawned,Commands->Get_Random(-180.0f,180.0f)); + if (collisionCheck) + { + for (int x = 0;x <= retryAttempts;x++) + { + MoveablePhysClass *mphys = spawned->As_PhysicalGameObj() ? spawned->As_PhysicalGameObj()->Peek_Physical_Object()->As_MoveablePhysClass() : nullptr; + if (!mphys) + { + Console_Input("msg JMG_Utility_Basic_Spawner_In_Radius ERROR: Collision check is turned on but the created object isn't a PhysicalGameObj!"); + Destroy_Script(); + return SpawnFailureTypes::SPAWN_CODE_ERROR; + } + if (!mphys->Can_Teleport(Matrix3D(bottomRay)) || (pointMustBeInPathfind && !Get_Random_Pathfind_Spot(bottomRay,0.0f,&unneeded))) + { + if (x >= retryAttempts) + { + Commands->Destroy_Object(spawned); + return SpawnFailureTypes::SPAWN_BLOCKED; + } + bottomRay.Z += addHeight; + } + } + Commands->Set_Position(spawned,bottomRay); + } + spawnCount++; + char params[32]; + sprintf(params,"%d,%d,%d",Commands->Get_ID(obj),scriptId,spawnGroupId); + Commands->Attach_Script(spawned,"JMG_Utility_Basic_Spawner_In_Radius_Attached",params); + Commands->Send_Custom_Event(spawned,obj,6873522,6873522,0.0f); + return SpawnFailureTypes::SUCCESS; + } + if (!ignoreRayCastFailure) + { + Console_Input("msg JMG_Utility_Basic_Spawner_In_Radius_Attached ERROR: Failed to cast Ray!"); + return SpawnFailureTypes::SPAWN_CODE_ERROR; + } + return SpawnFailureTypes::SPAWN_BLOCKED; +} +bool JMG_Utility_Basic_Spawner_In_Radius::CheckIfObjectIsNearAnotherObject(Vector3 pos) +{ + if (minDistanceBetweenObjects <= 0) + return false; + for (SLNode *node = spawnObjectNodeList.Head();node != NULL;node = node->Next()) + { + if (SpawnObjectNode *data = node->Data()) + { + if (!data->obj || (spawnGroupId > 0 && spawnGroupId != data->groupId)) + continue; + if (JmgUtility::SimpleDistance(Commands->Get_Position(data->obj),pos) <= minDistanceBetweenObjects) + return true; + } + } + return false; +} +void JMG_Utility_Basic_Spawner_In_Radius::SetFacing(GameObject *obj,float facing) +{ + if (obj->As_SoldierGameObj()) + { + char params[220]; + sprintf(params,"0.1,%.2f",facing); + Commands->Attach_Script(obj,"JMG_Utility_Delay_Then_Rotate_Camera",params); + } + else + Commands->Set_Facing(obj,facing); +} +void JMG_Utility_Basic_Spawner_In_Radius_Attached::Created(GameObject *obj) +{ + GameObject *controller = Commands->Find_Object(Get_Int_Parameter("Controller_ID")); + if (controller) + Commands->Send_Custom_Event(obj,controller,6873523,Get_Int_Parameter("Script_ID"),0.0f); + AddSpawnedObjectToGroup(obj); +} +void JMG_Utility_Basic_Spawner_In_Radius_Attached::Destroyed(GameObject *obj) +{ + GameObject *controller = Commands->Find_Object(Get_Int_Parameter("Controller_ID")); + if (controller) + Commands->Send_Custom_Event(obj,controller,6873524,Get_Int_Parameter("Script_ID"),0.0f); +} +void JMG_Utility_Basic_Spawner_In_Radius_Attached::AddSpawnedObjectToGroup(GameObject *spawned) +{ + int spawnGroupId = Get_Int_Parameter("Spawn_Group_ID"); + if (spawnGroupId == 0) + return; + for (SLNode *node = JMG_Utility_Basic_Spawner_In_Radius::spawnObjectNodeList.Head();node != NULL;node = node->Next()) + { + if (JMG_Utility_Basic_Spawner_In_Radius::SpawnObjectNode *data = node->Data()) + { + if (data->obj) + continue; + data->obj = spawned; + data->groupId = spawnGroupId; + return; + } + } + JMG_Utility_Basic_Spawner_In_Radius::SpawnObjectNode *node = new JMG_Utility_Basic_Spawner_In_Radius::SpawnObjectNode(spawned,spawnGroupId); + JMG_Utility_Basic_Spawner_In_Radius::spawnObjectNodeList.Add_Tail(node); +} +void JMG_Utility_Flying_Vehicle_Crash_Apply_Damage::Created(GameObject *obj) +{ + subtractMinSpeed = Get_Int_Parameter("Subtract_Min_Speed")?true:false; + minCollisionSpeed = Get_Float_Parameter("Min_Collision_Speed"); + maxCollisionSpeed = Get_Float_Parameter("Max_Collision_Speed"); + sprintf(collisionSound,Get_Parameter("Collision_Sound")); + sprintf(explosionPreset,Get_Parameter("Explosion_Preset")); + allowCrash = false; + if (!obj->As_VehicleGameObj()) + { + Console_Input("msg JMG_Utility_Flying_Vehicle_Crash_Apply_Damage ERROR: Must be attached to a vehicle"); + Destroy_Script(); + return; + } + Commands->Start_Timer(obj,this,0.1f,1); +} +void JMG_Utility_Flying_Vehicle_Crash_Apply_Damage::Timer_Expired(GameObject *obj,int number) +{ + if (number == 1) + { + if (!obj->As_PhysicalGameObj()->Is_Attached_To_An_Object()) + { + Vector3 tempSpeed,futurePos; + obj->As_VehicleGameObj()->Get_Velocity(tempSpeed); + float speed = tempSpeed.Length2()-(subtractMinSpeed?minCollisionSpeed:0.0f); + futurePos = Commands->Get_Position(obj); + if ((subtractMinSpeed && speed > 0.0f) || speed > minCollisionSpeed) + { + float facing = Commands->Get_Facing(obj); + float positionOffset = (speed/202.336f)*15.0f; + futurePos.X += cos(facing*PI180)*positionOffset; + futurePos.Y += sin(facing*PI180)*positionOffset; + MoveablePhysClass *mphys = obj->As_PhysicalGameObj() ? obj->As_PhysicalGameObj()->Peek_Physical_Object()->As_MoveablePhysClass() : NULL; + if (!mphys || mphys->Can_Teleport(Matrix3D(futurePos))) + { + if (allowCrash) + { + allowCrash = false; + Commands->Apply_Damage(obj,(speed/maxCollisionSpeed*(Commands->Get_Max_Health(obj)+Commands->Get_Max_Shield_Strength(obj))*0.5f),"None",obj); + Commands->Create_Sound(collisionSound,Commands->Get_Position(obj),obj); + if (!Commands->Get_Health(obj)) + Commands->Create_Explosion(explosionPreset,Commands->Get_Position(obj),obj); + } + } + else + allowCrash = true; + } + } + Commands->Start_Timer(obj,this,0.1f,1); + } +} +void JMG_Utility_Enemy_Seen_Send_Custom::Created(GameObject *obj) +{ + lastEnemyId = 0; + seenTime = 0; + enemyPresetId = Get_Int_Parameter("Enemy_Preset_ID"); + id = Get_Int_Parameter("ID"); + visibleMessage = Get_Int_Parameter("Visible_Message"); + notVisibleMessage = Get_Int_Parameter("Not_Visible_Message"); + visibleParam = Get_Int_Parameter("Visible_Param"); + notVisibleParam = Get_Int_Parameter("Not_Visible_Param"); + maxNotSeenTime = (int)(Get_Float_Parameter("Max_Lost_Sight_Time")*10); + Commands->Enable_Enemy_Seen(obj,true); + Commands->Start_Timer(obj,this,0.1f,1); +} +void JMG_Utility_Enemy_Seen_Send_Custom::Enemy_Seen(GameObject *obj,GameObject *seen) +{ + if (!JmgUtility::CanSeeStealth(0,obj,seen)) + return; + if (enemyPresetId && enemyPresetId != Commands->Get_Preset_ID(seen)) + return; + if (Is_Script_Attached(seen,"JMG_Utility_Enemy_Seen_Send_Custom_Ignore")) + return; + int seenId = Commands->Get_ID(seen); + if (!seenTime) + { + GameObject *object = !id ? obj : (id == -1 ? seen : Commands->Find_Object(id)); + if (object) + Commands->Send_Custom_Event(obj,object,visibleMessage,visibleParam,0); + lastEnemyId = seenId; + } + if (lastEnemyId == seenId) + seenTime = maxNotSeenTime; + +} +void JMG_Utility_Enemy_Seen_Send_Custom::Timer_Expired(GameObject *obj,int number) +{ + if (number == 1) + { + if (seenTime) + { + seenTime--; + if (!seenTime) + { + GameObject *object = !id ? obj : (id == -1 ? Commands->Find_Object(lastEnemyId) : Commands->Find_Object(id)); + if (object) + Commands->Send_Custom_Event(obj,object,notVisibleMessage,notVisibleParam,0); + } + } + Commands->Start_Timer(obj,this,0.1f,1); + } +} +void JMG_Utility_Custom_Send_Custom_If_Script_Attached::Created(GameObject *obj) +{ + recieveMessage = Get_Int_Parameter("Custom"); + sprintf(script,"%s",Get_Parameter("Script")); +} +void JMG_Utility_Custom_Send_Custom_If_Script_Attached::Custom(GameObject *obj,int message,int param,GameObject *sender) +{ + if (message == recieveMessage) + { + if (!Is_Script_Attached(obj,script)) + return; + int id = Get_Int_Parameter("ID"); + GameObject *object = id ? (id == -1 ? sender : Commands->Find_Object(id)) : obj; + int Param = Get_Int_Parameter("Param"); + Commands->Send_Custom_Event(obj,object,Get_Int_Parameter("SendCustom"),Param == -1 ? param : Param,Get_Float_Parameter("Delay")); + } +} +void JMG_Utility_Custom_Send_Custom_If_Script_Not_Attached::Created(GameObject *obj) +{ + recieveMessage = Get_Int_Parameter("Custom"); + sprintf(script,"%s",Get_Parameter("Script")); +} +void JMG_Utility_Custom_Send_Custom_If_Script_Not_Attached::Custom(GameObject *obj,int message,int param,GameObject *sender) +{ + if (message == recieveMessage) + { + if (Is_Script_Attached(obj,script)) + return; + int id = Get_Int_Parameter("ID"); + GameObject *object = id ? (id == -1 ? sender : Commands->Find_Object(id)) : obj; + int Param = Get_Int_Parameter("Param"); + Commands->Send_Custom_Event(obj,object,Get_Int_Parameter("SendCustom"),Param == -1 ? param : Param,Get_Float_Parameter("Delay")); + } +} +void JMG_Utility_Basic_Spawner_In_Radius_Controller::Destroyed(GameObject *obj) +{ + JMG_Utility_Basic_Spawner_In_Radius::spawnObjectNodeList.Remove_All(); +} +void JMG_Utility_Custom_Set_Engine::Created(GameObject *obj) +{ + custom = Get_Int_Parameter("Custom"); + enable = Get_Int_Parameter("Enable"); +} +void JMG_Utility_Custom_Set_Engine::Custom(GameObject *obj,int message,int param,GameObject *sender) +{ + if (message == custom) + { + Commands->Enable_Engine(obj,(enable == -1 ? param : enable) != 0 ? true : false); + } +} +void JMG_Utility_Send_Custom_Player_Count_Matches_Preset_Count::Created(GameObject *obj) +{ + presetId = Get_Int_Parameter("Preset_ID"); + id = Get_Int_Parameter("ID"); + custom = Get_Int_Parameter("Message"); + param = Get_Int_Parameter("Param"); + delay = Get_Float_Parameter("Delay"); + rate = Get_Float_Parameter("Rate"); + minPlayers = Get_Int_Parameter("Min_Player_Count"); + maxPlayers = Get_Int_Parameter("Max_Player_Count"); + repeat = Get_Int_Parameter("Repeat") == 0 ? false : true; + Commands->Start_Timer(obj,this,rate,1); +} +void JMG_Utility_Send_Custom_Player_Count_Matches_Preset_Count::Timer_Expired(GameObject *obj,int number) +{ + if (number == 1) + { + int playerCount = Get_Player_Count(); + if ((minPlayers == -1 || playerCount >= minPlayers) && (maxPlayers == -1 || playerCount <= maxPlayers)) + { + int count = 0; + for (SLNode *current = GameObjManager::GameObjList.Head();current;current = current->Next()) + { + GameObject* o = current->Data()->As_ScriptableGameObj(); + if (Commands->Get_Preset_ID(o) == presetId) + count++; + } + if (count == playerCount) + { + GameObject *object = !id ? obj : Commands->Find_Object(id); + if (object) + Commands->Send_Custom_Event(obj,object,custom,param,delay); + if (!repeat) + { + Destroy_Script(); + return; + } + } + } + Commands->Start_Timer(obj,this,rate,1); + } +} +void JMG_Utility_Custom_Set_Position::Created(GameObject *obj) +{ + custom = Get_Int_Parameter("Custom"); + position = Get_Vector3_Parameter("Position"); +} +void JMG_Utility_Custom_Set_Position::Custom(GameObject *obj,int message,int param,GameObject *sender) +{ + if (message == custom) + { + Commands->Set_Position(obj,position); + if (obj->As_ScriptZoneGameObj()) + { + OBBoxClass *zone = Get_Zone_Box(obj); + zone->Center = position; + JmgUtility::RotateZoneBox(Commands->Get_Facing(obj),zone->Basis); + Set_Zone_Box(obj,*zone); + } + } +} +void JMG_Utility_Custom_Delay_Send_Custom::Created(GameObject *obj) +{ + watchMessage = Get_Int_Parameter("Custom"); + id = Get_Int_Parameter("ID"); + sendMessage = Get_Int_Parameter("SendCustom"); + Param = Get_Int_Parameter("Param"); + delay = Get_Float_Parameter("Delay"); + randomDelay = Get_Float_Parameter("RandomDelay"); + cancelCustom = Get_Int_Parameter("CancelCustom"); + lastSender = NULL; +} +void JMG_Utility_Custom_Delay_Send_Custom::Custom(GameObject *obj,int message,int param,GameObject *sender) +{ + if (message == watchMessage) + { + Stop_Timer2(obj,this,1); + lastSender = sender; + lastParam = param; + Commands->Start_Timer(obj,this,delay+(randomDelay ? Commands->Get_Random(0.0f,randomDelay) : 0.0f),1); + } + if (message == cancelCustom) + { + Stop_Timer2(obj,this,1); + } +} +void JMG_Utility_Custom_Delay_Send_Custom::Timer_Expired(GameObject *obj,int number) +{ + if (number == 1) + { + GameObject *object = id ? (id == -1 ? lastSender : Commands->Find_Object(id)) : obj; + Commands->Send_Custom_Event(obj,object,sendMessage,Param == -1 ? lastParam : Param,0); + } +} +void JMG_Utility_Scale_HP_By_Player_Count::Created(GameObject *obj) +{ + maxPlayerCount = Get_Int_Parameter("Max_Player_Count"); + lastPlayerCount = 1; + originalHealth = Commands->Get_Max_Health(obj); + originalArmor = Commands->Get_Max_Shield_Strength(obj);; + healthMultiplier = Get_Float_Parameter("Health_Multiplier"); + armorMultiplier = Get_Float_Parameter("Armor_Multiplier"); + repeat = Get_Int_Parameter("Repeat") == 0 ? false : true; + updateScaleCustom = Get_Int_Parameter("UpdateScaleCustom"); + Commands->Start_Timer(obj,this,0.1f,1); +} +void JMG_Utility_Scale_HP_By_Player_Count::Timer_Expired(GameObject *obj,int number) +{ + if (number == 1) + { + RescaleHP(obj); + if (!repeat) + { + Destroy_Script(); + return; + } + Commands->Start_Timer(obj,this,0.1f,1); + } +} +void JMG_Utility_Scale_HP_By_Player_Count::Custom(GameObject *obj,int message,int param,GameObject *sender) +{ + if (updateScaleCustom && message == updateScaleCustom) + { + RescaleHP(obj); + } +} +void JMG_Utility_Scale_HP_By_Player_Count::RescaleHP(GameObject *obj) +{ + int playerCount = maxPlayerCount == -1 ? Get_Player_Count() : min(maxPlayerCount,Get_Player_Count()); + if (playerCount && lastPlayerCount != playerCount) + { + float healthRatio = Commands->Get_Health(obj)/Commands->Get_Max_Health(obj); + float armorRatio = Commands->Get_Shield_Strength(obj)/Commands->Get_Max_Shield_Strength(obj); + Set_Max_Health(obj,healthMultiplier*playerCount*originalHealth); + Set_Max_Shield_Strength(obj,armorMultiplier*playerCount*originalArmor); + Commands->Set_Health(obj,Commands->Get_Max_Health(obj)*healthRatio); + Commands->Set_Shield_Strength(obj,Commands->Get_Max_Shield_Strength(obj)*armorRatio); + lastPlayerCount = playerCount; + } +} +void JMG_Utility_Custom_Send_Custom_To_All_Objects::Created(GameObject *obj) +{ + recieveMessage = Get_Int_Parameter("Custom"); + team = Get_Int_Parameter("Team"); + custom = Get_Int_Parameter("SendCustom"); + Param = Get_Int_Parameter("Param"); + delay = Get_Float_Parameter("Delay"); +} +void JMG_Utility_Custom_Send_Custom_To_All_Objects::Custom(GameObject *obj,int message,int param,GameObject *sender) +{ + if (message == recieveMessage) + { + for (SLNode *current = GameObjManager::GameObjList.Head();current;current = current->Next()) + { + GameObject* o = current->Data()->As_ScriptableGameObj(); + if (o && (team == 2 || CheckPlayerType(o,team))) + Commands->Send_Custom_Event(obj,o,custom,Param == -1 ? param : Param,delay); + } + } +} +void JMG_Utility_Enemy_Seen_Send_Custom_Ignore::Created(GameObject *obj) +{ +} +void JMG_Utility_In_Line_Of_Sight_Send_Custom::Created(GameObject *obj) +{ + lastEnemyId = 0; + enemyPresetId = Get_Int_Parameter("Enemy_Preset_ID"); + id = Get_Int_Parameter("ID"); + visibleMessage = Get_Int_Parameter("Visible_Message"); + notVisibleMessage = Get_Int_Parameter("Not_Visible_Message"); + visibleParam = Get_Int_Parameter("Visible_Param"); + notVisibleParam = Get_Int_Parameter("Not_Visible_Param"); + rate = Get_Float_Parameter("Scan_Rate"); + enemyOnly = Get_Int_Parameter("Enemy_Only") == 0 ? false : true; + Commands->Start_Timer(obj,this,rate,1); +} +void JMG_Utility_In_Line_Of_Sight_Send_Custom::Timer_Expired(GameObject *obj,int number) +{ + if (number == 1) + { + bool objectSeen = false; + for (SLNode *node = GameObjManager::SmartGameObjList.Head();node;node = node->Next()) + { + SmartGameObj* object = node->Data(); + if (object == obj) + continue; + if ((!enemyOnly || obj->As_SmartGameObj()->Is_Enemy(object)) && object->Is_Visible() && obj->As_SmartGameObj()->Is_Obj_Visible(object)) + { + if (object->Peek_Physical_Object()) + { + RenderObjClass* model = object->Peek_Physical_Object()->Peek_Model(); + if (model && model->Is_Hidden()) + continue; + } + if (Test_Line_Of_Sight(obj,object)) + objectSeen = true; + } + } + if (!objectSeen && lastEnemyId) + { + GameObject *object = !id ? obj : (id == -1 ? Commands->Find_Object(lastEnemyId) : Commands->Find_Object(id)); + if (object) + Commands->Send_Custom_Event(obj,object,notVisibleMessage,notVisibleParam,0); + lastEnemyId = 0; + } + Commands->Start_Timer(obj,this,rate,1); + } +} +bool JMG_Utility_In_Line_Of_Sight_Send_Custom::Test_Line_Of_Sight(GameObject *obj,GameObject *seen) +{ + if (!JmgUtility::CanSeeStealth(0,obj,seen)) + return false; + if (enemyPresetId && enemyPresetId != Commands->Get_Preset_ID(seen)) + return false; + if (Is_Script_Attached(seen,"JMG_Utility_In_Line_Of_Sight_Send_Custom_Ignore")) + return false; + int seenId = Commands->Get_ID(seen); + if (!lastEnemyId) + { + GameObject *object = !id ? obj : (id == -1 ? seen : Commands->Find_Object(id)); + if (object) + Commands->Send_Custom_Event(obj,object,visibleMessage,visibleParam,0); + lastEnemyId = seenId; + return true; + } + if (lastEnemyId == seenId) + return true; + return false; +} +void JMG_Utility_In_Line_Of_Sight_Send_Custom_Ignore::Created(GameObject *obj) +{ +} +void JMG_Utility_Timer_Trigger_Enemy_Seen::Created(GameObject *obj) +{ + rate = Get_Float_Parameter("Scan_Rate"); + Commands->Start_Timer(obj,this,rate,1); +} +void JMG_Utility_Timer_Trigger_Enemy_Seen::Timer_Expired(GameObject *obj,int number) +{ + if (number == 1) + { + for (SLNode *node = GameObjManager::SmartGameObjList.Head();node;node = node->Next()) + { + SmartGameObj* object = node->Data(); + if (object == obj) + continue; + if (obj->As_SmartGameObj()->Is_Enemy(object) && object->Is_Visible() && obj->As_SmartGameObj()->Is_Obj_Visible(object)) + { + if (object->Peek_Physical_Object()) + { + RenderObjClass* model = object->Peek_Physical_Object()->Peek_Model(); + if (model && model->Is_Hidden()) + continue; + } + const SimpleDynVecClass & observer_list = obj->Get_Observers(); + for(int index = 0;index < observer_list.Count();index++) + observer_list[index]->Enemy_Seen(obj,object); + } + } + Commands->Start_Timer(obj,this,rate,1); + } +} +void JMG_Utility_Custom_Teleport_To_Random_Wander_Point::Created(GameObject *obj) +{ + custom = Get_Int_Parameter("Custom"); + retryOnFailure = Get_Int_Parameter("RetryOnFailure") ? true : false; + safeTeleportDistance = Get_Float_Parameter("SafeTeleportDistance"); + wanderPointGroup = Get_Int_Parameter("WanderingAIGroupID"); +} +void JMG_Utility_Custom_Teleport_To_Random_Wander_Point::Custom(GameObject *obj,int message,int param,GameObject *sender) +{ + if (message == custom) + { + Grab_Teleport_Spot(obj,5); + } +} +bool JMG_Utility_Custom_Teleport_To_Random_Wander_Point::Grab_Teleport_Spot(GameObject *enter,int attempts) +{ + if (The_Game()->Get_Game_Duration_S() < 1.0f) + { + char params[220]; + sprintf(params,"%d,%.2f",wanderPointGroup,safeTeleportDistance); + Commands->Attach_Script(enter,"JMG_Utility_Zone_Teleport_To_Random_Wander_Point_Attach",params); + return false; + } + if (!attempts) + { + if (retryOnFailure) + { + char params[220]; + sprintf(params,"%d,%.2f",wanderPointGroup,safeTeleportDistance); + Commands->Attach_Script(enter,"JMG_Utility_Zone_Teleport_To_Random_Wander_Point_Attach",params); + } + return false; + } + attempts--; + Vector3 targetPos; + float facing; + if (!Get_A_Defense_Point(&targetPos,&facing)) + { + char errormsg[220]; + sprintf(errormsg,"msg JMG_Utility_Custom_Teleport_To_Random_Wander_Point ERROR: No wander points found for group %d!",wanderPointGroup); + Console_Input(errormsg); + return false; + } + MoveablePhysClass *mphys = enter->As_PhysicalGameObj() ? enter->As_PhysicalGameObj()->Peek_Physical_Object()->As_MoveablePhysClass() : NULL; + if (mphys && mphys->Find_Teleport_Location(targetPos,safeTeleportDistance,&targetPos)) + { + Toggle_Fly_Mode(enter); + Commands->Set_Position(enter,targetPos); + Force_Position_Update(enter); + Toggle_Fly_Mode(enter); + char params[220]; + sprintf(params,"0.1,%.2f",facing); + Commands->Attach_Script(enter,"JMG_Utility_Delay_Then_Rotate_Camera",params); + return true; + } + else + { + Commands->Set_Position(enter,targetPos); + return Grab_Teleport_Spot(enter,attempts); + } +} +void JMG_Utility_Send_Custom_If_Not_Moving_Enough::Created(GameObject *obj) +{ + resetTime = time = (int)(Get_Float_Parameter("Time")*10); + distance = Get_Float_Parameter("Distance"); + distance *= distance; + lastPos = Commands->Get_Position(obj); + id = Get_Int_Parameter("ID"); + custom = Get_Int_Parameter("SendCustom"); + Param = Get_Int_Parameter("Param"); + delay = Get_Float_Parameter("Delay"); + Commands->Start_Timer(obj,this,0.1f,1); +} +void JMG_Utility_Send_Custom_If_Not_Moving_Enough::Timer_Expired(GameObject *obj,int number) +{ + if (number == 1) + { + if (JmgUtility::SimpleDistance(Commands->Get_Position(obj),lastPos) < distance) + { + time--; + if (!time) + { + GameObject *object = id ? Commands->Find_Object(id) : obj; + Commands->Send_Custom_Event(obj,object,custom,Param,delay); + } + if (time < 0) + time = resetTime; + } + else + { + lastPos = Commands->Get_Position(obj); + time = resetTime; + } + Commands->Start_Timer(obj,this,0.1f,1); + } +} +JMG_Utility_AI_Skittish_Herd_Animal::HerdAnimalPositionSystem JMG_Utility_AI_Skittish_Herd_Animal::HerdAnimalPositionControl[128] = {HerdAnimalPositionSystem()}; +void JMG_Utility_AI_Skittish_Herd_Animal::Created(GameObject *obj) +{ + weaponRange = 3.75; + sprintf(defaultWeapon,"%s",Get_Current_Weapon(obj)); + int minHerdId = Get_Int_Parameter("MinHerdID"); + int maxHerdId = Get_Int_Parameter("MaxHerdID"); + wanderPointGroup = Get_Int_Parameter("WanderGroupID"); + if (minHerdId > 128 || maxHerdId > 128) + { + Console_Input("msg JMG_Utility_AI_Skittish_Herd_Animal ERROR: Herd ID must not exceed 128!"); + Destroy_Script(); + return; + } + minRetreatRange = Get_Float_Parameter("MinRetreatRange"); + maxRetreatRange = Get_Float_Parameter("MaxRetreatRange"); + wanderRadiusAroundHerdCenter = Get_Float_Parameter("WanderRadiusAroundHerdCenter"); + wanderRadiusAroundHerdCenterSq = wanderRadiusAroundHerdCenter+10.0f; + wanderRadiusAroundHerdCenterSq *= wanderRadiusAroundHerdCenterSq; + minWanderFrequency = Get_Float_Parameter("MinWanderFrequency"); + maxWanderFrequency = Get_Float_Parameter("MaxWanderFrequency"); + minRetreatTime = Get_Float_Parameter("MinRetreatTime")*1000.0f; + maxRetreatTime = Get_Float_Parameter("MaxRetreatTime")*1000.0f; + minUpdateHerdCenter = Get_Float_Parameter("MinUpdateHerdCenter")*1000.0f; + maxUpdateHerdCenter = Get_Float_Parameter("MaxUpdateHerdCenter")*1000.0f; + runTowardThreatChance = Get_Float_Parameter("RunTowardThreatChance"); + herdId = minHerdId == maxHerdId ? maxHerdId : Commands->Get_Random_Int(minHerdId,maxHerdId); + HerdPositionNode = HerdAnimalPositionControl[herdId].AddNode(obj); + Commands->Enable_Enemy_Seen(obj,true); + Commands->Start_Timer(obj,this,1.1f,1); + Commands->Start_Timer(obj,this,1.1f,2); +} +void JMG_Utility_AI_Skittish_Herd_Animal::Enemy_Seen(GameObject *obj,GameObject *seen) +{ + if (((HerdAnimalPositionControl[herdId].checkRetreatCloseEnough() || difftime(clock(),HerdAnimalPositionControl[herdId].herdRetreatStart) > HerdAnimalPositionControl[herdId].herdRetreatTime))) + setRetreatLocation(obj,seen); +} +void JMG_Utility_AI_Skittish_Herd_Animal::Timer_Expired(GameObject *obj,int number) +{ + if (number == 1 && Commands->Get_Health(obj)) + { + if (HerdPositionNode) + HerdPositionNode->pos = Commands->Get_Position(obj); + if (difftime(clock(),HerdAnimalPositionControl[herdId].herdRetreatStart) < HerdAnimalPositionControl[herdId].herdRetreatTime) + { + Vector3 pos = Commands->Get_Position(obj); + if (JmgUtility::SimpleDistance(pos,HerdAnimalPositionControl[herdId].herdRetreatLocation) < wanderRadiusAroundHerdCenterSq) + { + pos = HerdAnimalPositionControl[herdId].herdRetreatLocation; + float randomRot = Commands->Get_Random(-180.0f,180.0f); + float dist = Commands->Get_Random(0.0f,wanderRadiusAroundHerdCenter); + pos.X += cos(randomRot)*dist; + pos.Y += sin(randomRot)*dist; + Vector3 finalPos; + if (Get_Random_Pathfind_Spot(pos,wanderRadiusAroundHerdCenter,&finalPos)) + pos = finalPos; + } + else + pos = HerdAnimalPositionControl[herdId].herdRetreatLocation; + GotoLocation(obj,pos,NULL,1.25f); + if (HerdAnimalPositionControl[herdId].checkRetreatSuccessful()) + HerdAnimalPositionControl[herdId].herdRetreatTime = 0; + } + Commands->Start_Timer(obj,this,1.0f,1); + } + if (number == 2) + { + if (difftime(clock(),HerdAnimalPositionControl[herdId].herdRetreatStart) > HerdAnimalPositionControl[herdId].herdRetreatTime) + { + const char *weap = Get_Current_Weapon(obj); + if (weap && !_stricmp(weap,defaultWeapon)) + { + Commands->Select_Weapon(obj,""); + Commands->Select_Weapon(obj,defaultWeapon); + } + } + Vector3 pos = HerdAnimalPositionControl[herdId].getCenterLocation(true,wanderPointGroup,minUpdateHerdCenter,maxUpdateHerdCenter); + float randomRot = Commands->Get_Random(-180.0f,180.0f); + float dist = Commands->Get_Random(0.0f,wanderRadiusAroundHerdCenter); + pos.X += cos(randomRot)*dist; + pos.Y += sin(randomRot)*dist; + Vector3 finalPos; + if (Get_Random_Pathfind_Spot(pos,wanderRadiusAroundHerdCenter,&finalPos)) + GotoLocation(obj,finalPos,NULL); + else + GotoLocation(obj,pos,NULL); + Commands->Start_Timer(obj,this,Commands->Get_Random(minWanderFrequency,maxWanderFrequency),2); + } +} +void JMG_Utility_AI_Skittish_Herd_Animal::Damaged(GameObject *obj,GameObject *damager,float damage) +{ + if (damager && damage > 0 && (herdId && (HerdAnimalPositionControl[herdId].checkRetreatCloseEnough() || difftime(clock(),HerdAnimalPositionControl[herdId].herdRetreatStart) > HerdAnimalPositionControl[herdId].herdRetreatTime))) + setRetreatLocation(obj,damager); +} +void JMG_Utility_AI_Skittish_Herd_Animal::Destroyed(GameObject *obj) +{ + HerdAnimalPositionControl[herdId] -= obj; +} +void JMG_Utility_AI_Skittish_Herd_Animal::GotoLocation(GameObject *obj,const Vector3 &pos,GameObject *Enemy,float speed) +{ + ActionParamsStruct params; + Commands->Get_Action_Params(obj,params); + params.Set_Basic(this,100,1); + params.Set_Movement(pos,speed ? speed : (Enemy ? 1.0f : Commands->Get_Random(0.25f,1.0f)),Enemy ? weaponRange*Commands->Get_Random(0.01f,1.0f) : 1.0f,false); + params.MovePathfind = true; + Vector3 mypos = Commands->Get_Position(obj); + if (!speed && JmgUtility::SimpleDistance(mypos,pos) < 625 && Commands->Get_Random(0.0f,1.0f) < 0.25f) + { + params.MoveCrouched = true; + params.AttackCrouched = true; + } + Commands->Action_Goto(obj,params); +} +void JMG_Utility_AI_Skittish_Herd_Animal::setRetreatLocation(GameObject *obj,GameObject *enemy) +{ + Vector3 pos = Commands->Get_Position(obj); + Vector3 mypos = Commands->Get_Position(enemy); + pos.X -= mypos.X; + pos.Y -= mypos.Y; + float TempRotation = atan2(pos.Y,pos.X); + float dist = Commands->Get_Random(minRetreatRange,maxRetreatRange); + if (Commands->Get_Random(0.0f,1.0f) < runTowardThreatChance) + dist *= -1.0f; + pos.X += cos(TempRotation)*dist; + pos.Y += sin(TempRotation)*dist; + if (Get_A_Wander_Point(&pos,wanderPointGroup)) + { + HerdAnimalPositionControl[herdId].herdRetreatLocation = pos; + HerdAnimalPositionControl[herdId].herdRetreatTime = Commands->Get_Random(minRetreatTime,maxRetreatTime); + HerdAnimalPositionControl[herdId].herdRetreatStart = clock(); + } + GotoLocation(obj,pos,NULL,1.25f); +} +Vector3 JMG_Utility_AI_Skittish_Herd_Animal::HerdAnimalPositionSystem::getCenterLocation(bool allowWander,int wanderPointGroup,float minUpdateHerdCenter,float maxUpdateHerdCenter) +{ + if (difftime(clock(),herdRetreatStart) < herdRetreatTime) + return herdRetreatLocation; + if (difftime(clock(),lastPosCalcTime) < minUpdateDelay && hascalculatedPos) + return centerPos; + minUpdateDelay = Commands->Get_Random(minUpdateHerdCenter,maxUpdateHerdCenter); + hascalculatedPos = true; + lastPosCalcTime = clock(); + if (allowWander && Commands->Get_Random(0.00,1.00) < 0.1f && JMG_Utility_AI_Skittish_Herd_Animal::Get_A_Wander_Point(¢erPos,wanderPointGroup)) + return centerPos; + HerdPositionNode *Current = HerdPositionNodeList; + Vector3 activePos; + int activeCount = 0; + while (Current) + { + if (Current->alive) + { + activeCount++; + activePos += Current->pos; + } + Current = Current->next; + } + if (!activeCount) + { + JMG_Utility_AI_Skittish_Herd_Animal::Get_A_Wander_Point(¢erPos,wanderPointGroup); + return centerPos; + } + centerPos.X = activePos.X/activeCount; + centerPos.Y = activePos.Y/activeCount; + centerPos.Z = activePos.Z/activeCount; + return centerPos; +} +void JMG_Utility_AI_Skittish_Herd_Animal_Ignore::Created(GameObject *obj) +{ +} +void JMG_Utility_AI_Skittish_Herd_Animal_Controller::Destroyed(GameObject *obj) +{ + for (int x = 0;x < 128;x++) + JMG_Utility_AI_Skittish_Herd_Animal::HerdAnimalPositionControl[x].Empty_List(); +} +void JMG_Utility_Custom_Display_Dialog_Box::Created(GameObject *obj) +{ + custom = Get_Int_Parameter("Custom"); + textMessage = newstr(Get_Parameter("Message")); + char delim = Get_Parameter("Delim")[0]; + unsigned int length = strlen(textMessage); + for (unsigned int x = 0;x < length;x++) + if (textMessage[x] == delim) + textMessage[x] = ','; +} +void JMG_Utility_Custom_Display_Dialog_Box::Custom(GameObject *obj,int message,int param,GameObject *sender) +{ + if (message == custom) + { + char dialog[1000]; + sprintf(dialog,"pamsg %d %s",JmgUtility::JMG_Get_Player_ID(obj),textMessage); + Console_Input(dialog); + } +} +void JMG_Utility_Custom_Send_Custom_On_Preset_Count::Created(GameObject *obj) +{ + recieveMessage = Get_Int_Parameter("Custom"); + presetId = Get_Int_Parameter("PresetID"); + minCount = Get_Int_Parameter("MinCount"); + maxCount = Get_Int_Parameter("MaxCount"); + id = Get_Int_Parameter("ID"); + custom = Get_Int_Parameter("SendCustom"); + Param = Get_Int_Parameter("Param"); + delay = Get_Float_Parameter("Delay"); +} +void JMG_Utility_Custom_Send_Custom_On_Preset_Count::Custom(GameObject *obj,int message,int param,GameObject *sender) +{ + if (message == recieveMessage) + { + int count = 0; + for (SLNode *current = GameObjManager::GameObjList.Head();current;current = current->Next()) + { + GameObject* o = current->Data()->As_ScriptableGameObj(); + if (Commands->Get_Preset_ID(o) == presetId) + count++; + } + if (count >= minCount && (maxCount == -1 || count <= maxCount)) + { + GameObject *object = id ? (id == -1 ? sender : Commands->Find_Object(id)) : obj; + Commands->Send_Custom_Event(obj,object,custom,Param == -1 ? param : Param,delay); + } + } +} +void JMG_Utility_Custom_Send_Custom_On_Script_Count::Created(GameObject *obj) +{ + recieveMessage = Get_Int_Parameter("Custom"); + sprintf(script,"%s",Get_Parameter("Script")); + minCount = Get_Int_Parameter("MinCount"); + maxCount = Get_Int_Parameter("MaxCount"); + id = Get_Int_Parameter("ID"); + custom = Get_Int_Parameter("SendCustom"); + Param = Get_Int_Parameter("Param"); + delay = Get_Float_Parameter("Delay"); +} +void JMG_Utility_Custom_Send_Custom_On_Script_Count::Custom(GameObject *obj,int message,int param,GameObject *sender) +{ + if (message == recieveMessage) + { + int count = 0; + for (SLNode *current = GameObjManager::GameObjList.Head();current;current = current->Next()) + { + GameObject* o = current->Data()->As_ScriptableGameObj(); + if (Is_Script_Attached(o,script)) + count++; + } + if (count >= minCount && (maxCount == -1 || count <= maxCount)) + { + GameObject *object = id ? (id == -1 ? sender : Commands->Find_Object(id)) : obj; + Commands->Send_Custom_Event(obj,object,custom,Param == -1 ? param : Param,delay); + } + } +} + +void JMG_Utility_Poke_Send_Custom_From_Poker::Created(GameObject *obj) +{ + Commands->Enable_HUD_Pokable_Indicator(obj,true); +} +void JMG_Utility_Poke_Send_Custom_From_Poker::Poked(GameObject *obj, GameObject *poker) +{ + if (CheckPlayerType(poker,Get_Int_Parameter("PlayerType")) || Commands->Get_Player_Type(poker) == -4) + return; + int id = Get_Int_Parameter("ID"); + GameObject *object = id ? (id == -1 ? poker : Commands->Find_Object(id)) : obj; + if (object) + Commands->Send_Custom_Event(poker,object,Get_Int_Parameter("Custom"),Get_Int_Parameter("Param"),Get_Float_Parameter("Delay")); + if (Get_Int_Parameter("TriggerOnce")) + { + Commands->Enable_HUD_Pokable_Indicator(obj,false); + Destroy_Script(); + } +} +void JMG_Utility_Custom_Grant_Scaled_Score::Created(GameObject *obj) +{ + maxPlayerCount = Get_Int_Parameter("MaxPlayerCount"); + lastPlayerCount = 1; + theScore = score = Get_Float_Parameter("Score"); + scoreMultiplier = Get_Float_Parameter("ScoreMultiplier"); + repeat = Get_Int_Parameter("Repeat") == 0 ? false : true; + grantCustom = Get_Int_Parameter("GrantCustom"); + updateScaleCustom = Get_Int_Parameter("UpdateScaleCustom"); + stopUpdateCustom = Get_Int_Parameter("StopUpdateCustom"); + grantToSender = Get_Int_Parameter("GrantToSender") == 0 ? false : true; + entireTeam = Get_Int_Parameter("EntireTeam") == 0 ? false : true; + Commands->Start_Timer(obj,this,0.1f,1); +} +void JMG_Utility_Custom_Grant_Scaled_Score::Timer_Expired(GameObject *obj,int number) +{ + if (number == 1) + { + RescaleScore(obj); + if (!repeat) + { + Destroy_Script(); + return; + } + Commands->Start_Timer(obj,this,0.1f,1); + } +} +void JMG_Utility_Custom_Grant_Scaled_Score::Custom(GameObject *obj,int message,int param,GameObject *sender) +{ + if (grantCustom && message == grantCustom) + { + Commands->Give_Points(grantToSender ? sender : obj,theScore,entireTeam); + } + if (updateScaleCustom && message == updateScaleCustom) + { + RescaleScore(obj); + } + if (stopUpdateCustom && message == stopUpdateCustom) + { + Stop_Timer2(obj,this,1); + } +} +void JMG_Utility_Custom_Grant_Scaled_Score::RescaleScore(GameObject *obj) +{ + int playerCount = maxPlayerCount == -1 ? Get_Player_Count() : min(maxPlayerCount,Get_Player_Count()); + if (playerCount && lastPlayerCount != playerCount) + { + theScore = score*scoreMultiplier*playerCount; + lastPlayerCount = playerCount; + } +} ScriptRegistrant JMG_Utility_Check_If_Script_Is_In_Library_Registrant("JMG_Utility_Check_If_Script_Is_In_Library","ScriptName:string,CppName:string"); ScriptRegistrant JMG_Send_Custom_When_Custom_Sequence_Matched_Registrant("JMG_Send_Custom_When_Custom_Sequence_Matched","Success_Custom=0:int,Correct_Step_Custom=0:int,Partial_Failure_Custom=0:int,Failure_Custom=0:int,Send_To_ID=0:int,Custom_0=0:int,Custom_1=0:int,Custom_2=0:int,Custom_3=0:int,Custom_4=0:int,Custom_5=0:int,Custom_6=0:int,Custom_7=0:int,Custom_8=0:int,Custom_9=0:int,Disable_On_Success=1:int,Disable_On_Failure=0:int,Starts_Enabled=1:int,Enable_Custom=0:int,Correct_Step_Saftey=0:int,Failure_Saftey=1:int,Max_Failures=1:int"); ScriptRegistrant JMG_Utility_Change_Model_On_Timer_Registrant("JMG_Utility_Change_Model_On_Timer","Model=null:string,Time=0:float"); @@ -9089,7 +10422,7 @@ ScriptRegistrant JMG_Utility_Send_Custom_When_Near_Building_Registrant("JMG_Utility_Send_Custom_When_Near_Building","SendCustomObjectID=0:int,NearToBuildingCustom:int,FarFromBuildingCustom:int,CloseToBuildingDistance=1.0:float,BuildingPlayerType=2:int,CheckDeadBuildings=1:int,CheckRate=0.25:float"); ScriptRegistrant JMG_Utility_AI_Engineer_Repair_Target_Registrant("JMG_Utility_AI_Engineer_Repair_Target",""); ScriptRegistrant JMG_Utility_Reset_Screen_Fade_And_Fog_On_Destroy_Registrant("JMG_Utility_Reset_Screen_Fade_And_Fog_On_Destroy",""); -ScriptRegistrant JMG_Utility_AI_Goto_Player_Registrant("JMG_Utility_AI_Goto_Player","HuntSearchDistance=-1.0:float,HuntSpeed=1.0:float,HuntArriveDistance=1.0:float,RandomHuntArriveDistance=0.0:float,HuntStealth=0:int,AttackSpeed=1.0:float,AttackDistance=-1.0:float,RandomAttackDistance=0.0:float,ReturnHome=1:int,ReturnHomeSpeed=1.0:float,WanderingAIGroupID=-1:int,WanderSpeed=1.0:float,CanSeeStealth=1:int,ShutdownEngineOnArrival=0:int,AttackCheckBlocked=1:int,MaxSightRangeFromHome=0.0:float"); +ScriptRegistrant JMG_Utility_AI_Goto_Player_Registrant("JMG_Utility_AI_Goto_Player","HuntSearchDistance=-1.0:float,HuntSpeed=1.0:float,HuntArriveDistance=1.0:float,RandomHuntArriveDistance=0.0:float,HuntStealth=0:int,AttackSpeed=1.0:float,AttackDistance=-1.0:float,RandomAttackDistance=0.0:float,ReturnHome=1:int,ReturnHomeSpeed=1.0:float,WanderingAIGroupID=-1:int,WanderSpeed=1.0:float,CanSeeStealth=1:int,ShutdownEngineOnArrival=0:int,AttackCheckBlocked=1:int,MaxSightRangeFromHome=0.0:float,WanderDistanceOverride=0.0:float,ChangeWanderGroupCustom=0:int,ChangeWanderSpeedCustom=0:int,ChangeHuntDistanceCustom=0:int,ChangeHuntSpeedCustom=0:int,ChangeReturnHomeSpeedCustom=0:int,ChangeMaxSightFromHomeLocationCustom=0:int,ChangeAttackSpeedCustom=0:int,ChanceToInvestigateLastSeenLocation=0.66:float"); ScriptRegistrant JMG_Utility_AI_Aggressive_Attack_Spot_Control_Registrant("JMG_Utility_AI_Aggressive_Attack_Spot_Control",""); ScriptRegistrant JMG_Utility_AI_Aggressive_Attack_Spot_Point_Registrant("JMG_Utility_AI_Aggressive_Attack_Spot_Point","GroupId=0:int,AttackOffset=0.0 0.0 0.0:Vector3"); ScriptRegistrant JMG_Utility_AI_Aggressive_Attack_Spot_Point2_Registrant("JMG_Utility_AI_Aggressive_Attack_Spot_Point2","GroupId=0:int,AbsolutePosition=0.0 0.0 0.0:Vector3,ObjectID=0:int"); @@ -9165,10 +10498,10 @@ ScriptRegistrant JMG_Utility_Set_Collision_Group_Registrant("JMG_Utility_Set_Collision_Group","CollisionGroupID:int"); ScriptRegistrant JMG_Utility_Cap_Credits_Registrant("JMG_Utility_Cap_Credits","Credits:float,Team=2:int,Custom=0:int"); ScriptRegistrant JMG_Utility_Custom_Apply_Damage_Registrant("JMG_Utility_Custom_Apply_Damage","Custom:int,ID=0:int,Damage:float,Warhead=None:string,DamagerID=0:int"); -ScriptRegistrant JMG_Utility_AI_Goto_Enemy_Registrant("JMG_Utility_AI_Goto_Enemy","HuntSearchDistance=-1.0:float,HuntSpeed=1.0:float,HuntArriveDistance=1.0:float,RandomHuntArriveDistance=0.0:float,HuntStealth=0:int,AttackSpeed=1.0:float,AttackDistance=-1.0:float,RandomAttackDistance=0.0:float,ReturnHome=1:int,ReturnHomeSpeed=1.0:float,WanderingAIGroupID=-1:int,WanderSpeed=1.0:float,CanSeeStealth=1:int,ShutdownEngineOnArrival=0:int,AttackCheckBlocked=1:int,MaxSightRangeFromHome=0.0:float"); -ScriptRegistrant JMG_Utility_AI_Goto_Enemy_Not_Star_Registrant("JMG_Utility_AI_Goto_Enemy_Not_Star","HuntSearchDistance=-1.0:float,HuntSpeed=1.0:float,HuntArriveDistance=1.0:float,RandomHuntArriveDistance=0.0:float,HuntStealth=0:int,AttackSpeed=1.0:float,AttackDistance=-1.0:float,RandomAttackDistance=0.0:float,ReturnHome=1:int,ReturnHomeSpeed=1.0:float,WanderingAIGroupID=-1:int,WanderSpeed=1.0:float,CanSeeStealth=1:int,ShutdownEngineOnArrival=0:int,AttackCheckBlocked=1:int,MaxSightRangeFromHome=0.0:float"); +ScriptRegistrant JMG_Utility_AI_Goto_Enemy_Registrant("JMG_Utility_AI_Goto_Enemy","HuntSearchDistance=-1.0:float,HuntSpeed=1.0:float,HuntArriveDistance=1.0:float,RandomHuntArriveDistance=0.0:float,HuntStealth=0:int,AttackSpeed=1.0:float,AttackDistance=-1.0:float,RandomAttackDistance=0.0:float,ReturnHome=1:int,ReturnHomeSpeed=1.0:float,WanderingAIGroupID=-1:int,WanderSpeed=1.0:float,CanSeeStealth=1:int,ShutdownEngineOnArrival=0:int,AttackCheckBlocked=1:int,MaxSightRangeFromHome=0.0:float,WanderDistanceOverride=0.0:float,ChangeWanderGroupCustom=0:int,ChangeWanderSpeedCustom=0:int,ChangeHuntDistanceCustom=0:int,ChangeHuntSpeedCustom=0:int,ChangeReturnHomeSpeedCustom=0:int,ChangeMaxSightFromHomeLocationCustom=0:int,ChangeAttackSpeedCustom=0:int,ChanceToInvestigateLastSeenLocation=0.66:float"); +ScriptRegistrant JMG_Utility_AI_Goto_Enemy_Not_Star_Registrant("JMG_Utility_AI_Goto_Enemy_Not_Star","HuntSearchDistance=-1.0:float,HuntSpeed=1.0:float,HuntArriveDistance=1.0:float,RandomHuntArriveDistance=0.0:float,HuntStealth=0:int,AttackSpeed=1.0:float,AttackDistance=-1.0:float,RandomAttackDistance=0.0:float,ReturnHome=1:int,ReturnHomeSpeed=1.0:float,WanderingAIGroupID=-1:int,WanderSpeed=1.0:float,CanSeeStealth=1:int,ShutdownEngineOnArrival=0:int,AttackCheckBlocked=1:int,MaxSightRangeFromHome=0.0:float,WanderDistanceOverride=0.0:float,ChangeWanderGroupCustom=0:int,ChangeWanderSpeedCustom=0:int,ChangeHuntDistanceCustom=0:int,ChangeHuntSpeedCustom=0:int,ChangeReturnHomeSpeedCustom=0:int,ChangeMaxSightFromHomeLocationCustom=0:int,ChangeAttackSpeedCustom=0:int,ChanceToInvestigateLastSeenLocation=0.66:float"); ScriptRegistrant JMG_Utility_Grant_Key_On_Create_Registrant("JMG_Utility_Grant_Key_On_Create","Key:int,Grant=1:int"); -ScriptRegistrant JMG_Utility_Custom_Send_Custom_Registrant("JMG_Utility_Custom_Send_Custom","Custom:int,ID=0:int,SendCustom:int,Param:int,Delay:float"); +ScriptRegistrant JMG_Utility_Custom_Send_Custom_Registrant("JMG_Utility_Custom_Send_Custom","Custom:int,ID=0:int,SendCustom:int,Param:int,Delay=0.0:float,RandomDelay=0.0:float,RandomChance=0.0:float"); ScriptRegistrant JMG_Utility_Damage_Unoccupied_Vehicle_Registrant("JMG_Utility_Damage_Unoccupied_Vehicle","Rate=0.1:float,Delay=60.0:float,DecreaseTick=0.1:float,IncreaseTick=0.1:float,Damage=1.0:float,Warhead=None:string"); ScriptRegistrant JMG_Utility_Custom_Damage_All_Soldiers_On_Team_Registrant("JMG_Utility_Custom_Damage_All_Soldiers_On_Team","Custom:int,Team:int,Damage:float,Warhead=None:string"); ScriptRegistrant JMG_Utility_AI_Guardian_Vehicle_Registrant("JMG_Utility_AI_Guardian_Vehicle","WanderingAIGroupID:int,WanderSpeed=1.0:float,FireRange=100.0:float,FaceTarget=1:int,CheckBlocked=1:int,AimAtFeet=1:int,TurnOffEngineOnArrival=1:int,StealthModeOverride=0:int"); @@ -9268,7 +10601,34 @@ ScriptRegistrant JMG_Utility_Send_Custom_On_Deaths_Reporter_Zone_Registrant("JMG_Utility_Send_Custom_On_Deaths_Reporter_Zone",""); ScriptRegistrant JMG_Utility_Killed_Give_Money_Registrant("JMG_Utility_Killed_Give_Money","Money:float"); ScriptRegistrant JMG_Utility_Created_Set_Damage_And_Death_Points_Registrant("JMG_Utility_Created_Set_Damage_And_Death_Points","Damage_Points=-1.0:float,DeathPoints=-1.0:float"); -ScriptRegistrant JMG_Utility_Detect_AFK_Controller_Registrant("JMG_Utility_Detect_AFK_Controller","AFKThreshold"); +ScriptRegistrant JMG_Utility_Detect_AFK_Controller_Registrant("JMG_Utility_Detect_AFK_Controller","AFKThreshold:int"); ScriptRegistrant JMG_Utility_Credit_Trickle_When_Not_AFK_Registrant("JMG_Utility_Credit_Trickle_When_Not_AFK","Credits=1.0:float,Rate=1.0:float,TrickleCap=0.0:float,Team=2:int,Custom=0:int"); ScriptRegistrant JMG_Utility_Killed_Create_Object_Registrant("JMG_Utility_Killed_Create_Object","Preset:string"); ScriptRegistrant JMG_Utility_Damaged_Create_Object_When_Shield_Zero_Registrant("JMG_Utility_Damaged_Create_Object_When_Shield_Zero","Preset:string"); +ScriptRegistrant JMG_Utility_Basic_Spawner_In_Radius_Registrant("JMG_Utility_Basic_Spawner_In_Radius","Spawn_Preset:string,Spawn_Rate:float,Random_Spawn_Rate:float,Spawn_At_A_Time:int,Min_Spawn_Radius:float,Max_Spawn_Radius:float,Initial_Spawn_Height=0.0:float,Spawn_Limit=-1:int,Spawn_Location=-1.0 -1.0 -1.0:Vector3,X_Multiplier=1.0:float,Y_Multiplier=1.0:float,Collision_Check=1:int,Collision_Retry_Attempts=3:int,Collision_Add_Height=1.0:float,Change_Spawn_Cap_Custom=-1:int,Initial_Spawn=-1:int,Script_ID=-1:int,Point_Must_Be_In_Pathfind=1:int,Manual_Facing=0:int,Face_Location=0.0 0.0 0.0:vector3,Face_Direction=0.0:float,Ignore_Ray_Cast_Failure=0:int,Min_Distance_Between_Objects=0.0:float,Spawn_Group_ID=0:int"); +ScriptRegistrant JMG_Utility_Basic_Spawner_In_Radius_Attached_Registrant("JMG_Utility_Basic_Spawner_In_Radius_Attached","Controller_ID:int,Script_ID:int,Spawn_Group_ID:int"); +ScriptRegistrant JMG_Utility_Flying_Vehicle_Crash_Apply_Damage_Registrant("JMG_Utility_Flying_Vehicle_Crash_Apply_Damage","Min_Collision_Speed=33.528:float,Max_Collision_Speed=42.4688:float,Collision_Sound=vehicle_collide_01:string,Explosion_Preset=Plane_Air_Collision:string,Subtract_Min_Speed=0:int"); +ScriptRegistrant JMG_Utility_Enemy_Seen_Send_Custom_Registrant("JMG_Utility_Enemy_Seen_Send_Custom","Enemy_Preset_ID:int,ID:int,Visible_Message:int,Visible_Param:int,Not_Visible_Message:int,Not_Visible_Param:int,Max_Lost_Sight_Time=2.5:float"); +ScriptRegistrant JMG_Utility_Custom_Send_Custom_If_Script_Attached_Registrant("JMG_Utility_Custom_Send_Custom_If_Script_Attached","Custom:int,Script:string,ID=0:int,SendCustom:int,Param:int,Delay:float"); +ScriptRegistrant JMG_Utility_Custom_Send_Custom_If_Script_Not_Attached_Registrant("JMG_Utility_Custom_Send_Custom_If_Script_Not_Attached","Custom:int,Script:string,ID=0:int,SendCustom:int,Param:int,Delay:float"); +ScriptRegistrant JMG_Utility_Basic_Spawner_In_Radius_Controller_Registrant("JMG_Utility_Basic_Spawner_In_Radius_Controller",""); +ScriptRegistrant JMG_Utility_Custom_Set_Engine_Registrant("JMG_Utility_Custom_Set_Engine","Custom:int,Enable:int"); +ScriptRegistrant JMG_Utility_Send_Custom_Player_Count_Matches_Preset_Count_Registrant("JMG_Utility_Send_Custom_Player_Count_Matches_Preset_Count","Preset_ID:int,ID:int,Message:int,Param:int,Delay:float,Min_Player_Count=1:int,Max_Player_Count=-1:int,Rate=0.1:float,Repeat=0:int"); +ScriptRegistrant JMG_Utility_Custom_Set_Position_Registrant("JMG_Utility_Custom_Set_Position","Custom:int,Position:Vector3"); +ScriptRegistrant JMG_Utility_Custom_Delay_Send_Custom_Registrant("JMG_Utility_Custom_Delay_Send_Custom","Custom:int,ID=0:int,SendCustom:int,Param:int,Delay:float,RandomDelay:float,CancelCustom=0:int"); +ScriptRegistrant JMG_Utility_Scale_HP_By_Player_Count_Registrant("JMG_Utility_Scale_HP_By_Player_Count","Health_Multiplier=1.0:float,Armor_Multiplier=1.0:float,Max_Player_Count=-1:int,Repeat=1:int,UpdateScaleCustom=0:int"); +ScriptRegistrant JMG_Utility_Custom_Send_Custom_To_All_Objects_Registrant("JMG_Utility_Custom_Send_Custom_To_All_Objects","Custom:int,SendCustom:int,Param:int,Team=2:int,Delay=0.0:float"); +ScriptRegistrant JMG_Utility_Enemy_Seen_Send_Custom_Ignore_Registrant("JMG_Utility_Enemy_Seen_Send_Custom_Ignore",""); +ScriptRegistrant JMG_Utility_In_Line_Of_Sight_Send_Custom_Registrant("JMG_Utility_In_Line_Of_Sight_Send_Custom","Enemy_Preset_ID:int,ID:int,Visible_Message:int,Visible_Param:int,Not_Visible_Message:int,Not_Visible_Param:int,Scan_Rate=0.1:float,Enemy_Only=1:int"); +ScriptRegistrant JMG_Utility_In_Line_Of_Sight_Send_Custom_Ignore_Registrant("JMG_Utility_In_Line_Of_Sight_Send_Custom_Ignore",""); +ScriptRegistrant JMG_Utility_Timer_Trigger_Enemy_Seen_Registrant("JMG_Utility_Timer_Trigger_Enemy_Seen","Scan_Rate=0.1:float"); +ScriptRegistrant JMG_Utility_Custom_Teleport_To_Random_Wander_Point_Registrant("JMG_Utility_Custom_Teleport_To_Random_Wander_Point","Custom:int,WanderingAIGroupID=-1:int,SafeTeleportDistance=1.5:float,RetryOnFailure=0:int"); +ScriptRegistrant JMG_Utility_Send_Custom_If_Not_Moving_Enough_Registrant("JMG_Utility_Send_Custom_If_Not_Moving_Enough","Time:float,Distance:float,ID=0:int,SendCustom:int,Param:int,Delay=0.0:float"); +ScriptRegistrant JMG_Utility_AI_Skittish_Herd_Animal_Registrant("JMG_Utility_AI_Skittish_Herd_Animal","MinHerdID=0:int,MaxHerdID=0:int,WanderGroupID=0:int,WanderRadiusAroundHerdCenter=25.0:float,MinWanderFrequency=5.0:float,MaxWanderFrequency=30.0:float,MinRetreatRange=50.0:float,MaxRetreatRange=200.0:float,MinRetreatTime=6.0:float,MaxRetreatTime=24.0:float,MinUpdateHerdCenter=10.0:float,MaxUpdateHerdCenter=25.0:float,RunTowardThreatChance=0.0:float"); +ScriptRegistrant JMG_Utility_AI_Skittish_Herd_Animal_Ignore_Registrant("JMG_Utility_AI_Skittish_Herd_Animal_Ignore",""); +ScriptRegistrant JMG_Utility_AI_Skittish_Herd_Animal_Controller_Registrant("JMG_Utility_AI_Skittish_Herd_Animal_Controller",""); +ScriptRegistrant JMG_Utility_Custom_Display_Dialog_Box_Registrant("JMG_Utility_Custom_Display_Dialog_Box","Custom:int,Message:string,Delim=@:string"); +ScriptRegistrant JMG_Utility_Custom_Send_Custom_On_Preset_Count_Registrant("JMG_Utility_Custom_Send_Custom_On_Preset_Count","Custom:int,PresetID:int,MinCount=1,MaxCount=-1,ID=0:int,SendCustom:int,Param:int,Delay=0.0:float"); +ScriptRegistrant JMG_Utility_Custom_Send_Custom_On_Script_Count_Registrant("JMG_Utility_Custom_Send_Custom_On_Script_Count","Custom:int,Script:string,MinCount=1,MaxCount=-1,ID=0:int,SendCustom:int,Param:int,Delay=0.0:float"); +ScriptRegistrant JMG_Utility_Poke_Send_Custom_From_Poker_Registrant("JMG_Utility_Poke_Send_Custom_From_Poker","ID=0:int,Custom=0:int,Param=0:int,Delay=0.0:float,TriggerOnce=1:int,PlayerType=2:int"); +ScriptRegistrant JMG_Utility_Custom_Grant_Scaled_Score_Registrant("JMG_Utility_Custom_Grant_Scaled_Score","GrantCustom:int,Score:float,ScoreMultiplier:float,EntireTeam=0:int,MaxPlayerCount=-1:int,Repeat=1:int,GrantToSender=0:int,UpdateScaleCustom=0:int,StopUpdateCustom=0:int"); diff -uwrN sourceold/scripts/jmgUtility.h source/scripts/jmgUtility.h --- sourceold/scripts/jmgUtility.h 2017-11-23 09:14:58.449800000 +1000 +++ source/scripts/jmgUtility.h 2018-11-11 08:30:08.537600000 +1000 @@ -265,7 +265,7 @@ } static char *JMG_Get_Compass_Directions(float compassDegree) { - static char name[4]; + static char name[6]; sprintf(name,"%s",compassDegree <= -168.75 ? "W": compassDegree <= -146.25 ? "WSW": compassDegree <= -123.75 ? "SW": @@ -2079,6 +2079,7 @@ void Detach(GameObject *obj); void CreateSoundEmitter(GameObject *obj,const char *model,int *soundId); void DestroySoundEmitter(int *soundId); + void HideSoundEmitter(int *soundId); public: static bool isUnderwater[128]; static bool isInWater[128]; @@ -2226,6 +2227,15 @@ * \ShutdownEngineOnArrival - Used for vehicles, turn on if you have issues with your vehicle rolling away from its move positions after it arrives * \AttackCheckBlocked - Defines whether they should check if they can actually hit the player before shooting * \MaxSightRangeFromHome - Maximum range the AI can see from its nearest wander point/home location, useful to keep them from wandering off after a trail of enemies, 0 to not use +* \WanderDistanceOverride - Overrides the default wander arrive distance (1 meter for infantry and 5 for vehicles) +* \ChangeWanderGroupCustom - If this custom is received the wander group will be set to the param, -1 param to disable the wander group code +* \ChangeWanderSpeedCustom - If this custom is received the wander speed will be updated to the param/100 +* \ChangeHuntDistanceCustom - If this custom is received the hunt range will be updated to the param/100 (-1 means infinite range) +* \ChangeHuntSpeedCustom - If this custom is received the hunt speed will be updated to the param/100 +* \ChangeReturnHomeSpeedCustom - If this custom is received the return home speed will be updated to the param/100 +* \ChangeMaxSightFromHomeLocationCustom - If this custom is received the AI won't be able to see targets past the specified range of the param/100, 0 means don't use +* \ChangeAttackSpeedCustom - If this custom is received the attack speed will be updated to the param/100 +* \ChanceToInvestigateLastSeenLocation - The percent chance (0.0-1.0) of checking out the last spot an enemy/target was seen * \author jgray * \ingroup JmgUtility */ @@ -2252,6 +2262,16 @@ this->overrideLocation = overrideLocation; } }; + struct ValidLastLocation + { + bool valid; + Vector3 location; + ValidLastLocation(bool valid) + { + this->valid = valid; + } + ValidLastLocation(int enemyId); + }; float maxSightFromHomeLocation; LastAction lastAction; aiState state; @@ -2270,14 +2290,28 @@ int reverseTime; Vector3 lastPosition; bool moveBackward; + float wanderDistanceOverride; + int wanderingAiGroupId; + float wanderSpeed; + float huntSpeed; + float attackSpeed; + float returnHomeSpeed; + int changeWanderGroupCustom; + int changeWanderSpeedCustom; + int changeHuntDistanceCustom; + int changeReturnHomeSpeedCustom; + int changeHuntSpeedCustom; + int changeMaxSightFromHomeLocationCustom; + int changeAttackSpeedCustom; void Created(GameObject *obj); void Enemy_Seen(GameObject *obj,GameObject *seen); void Timer_Expired(GameObject *obj,int number); void Action_Complete(GameObject *obj,int action_id,ActionCompleteReason reason); + void Custom(GameObject *obj,int message,int param,GameObject *sender); void Damaged(GameObject *obj,GameObject *damager,float damage); void Attack_Move(GameObject *obj,GameObject *target,Vector3 location,float speed,float distance,bool attack,bool overrideLocation); GameObject *findClosestStar(GameObject *obj); - void Return_Home(GameObject *obj); + void Return_Home(GameObject *obj,ValidLastLocation goNearLastWanderPoint); void Stuck_Check(GameObject *obj,Vector3 targetPos); void Cant_Get_To_target(GameObject *obj); bool GetRandomPosition(Vector3 *position); @@ -2569,7 +2603,7 @@ * \TriggerCustom - Custom to trigger the script on * \Preset - Preset group to send the message too * \Custom - Custom to send to the presets -* \Param - Param to send to the presets +* \Param - Param to send to the presets, -1 uses the param of the trigger custom * \Delay - Delay to add to the message before sending * \author jgray * \ingroup JmgUtility @@ -3636,7 +3670,7 @@ * \Count - how many customs needed * \ID - ID to send to, 0 sends to self, -1 sends to sender * \SendCustom - custom to send -* \Param - param to send +* \Param - param to send (-1 sends the param that was received) * \Delay - delay to add * \ResetCustom - custom to reset the count * \author jgray @@ -3751,6 +3785,15 @@ * \ShutdownEngineOnArrival - Used for vehicles, turn on if you have issues with your vehicle rolling away from its move positions after it arrives * \AttackCheckBlocked - Defines whether they should check if they can actually hit the player before shooting * \MaxSightRangeFromHome - Maximum range the AI can see from its nearest wander point/home location, useful to keep them from wandering off after a trail of enemies, 0 to not use +* \WanderDistanceOverride - Overrides the default wander arrive distance (1 meter for infantry and 5 for vehicles) +* \ChangeWanderGroupCustom - If this custom is received the wander group will be set to the param, -1 param to disable the wander group code +* \ChangeWanderSpeedCustom - If this custom is received the wander speed will be updated to the param/100 +* \ChangeHuntDistanceCustom - If this custom is received the hunt range will be updated to the param/100 (-1 means infinite range) +* \ChangeHuntSpeedCustom - If this custom is received the hunt speed will be updated to the param/100 +* \ChangeReturnHomeSpeedCustom - If this custom is received the return home speed will be updated to the param/100 +* \ChangeMaxSightFromHomeLocationCustom - If this custom is received the AI won't be able to see targets past the specified range of the param/100, 0 means don't use +* \ChangeAttackSpeedCustom - If this custom is received the attack speed will be updated to the param/100 +* \ChanceToInvestigateLastSeenLocation - The percent chance (0.0-1.0) of checking out the last spot an enemy/target was seen * \author jgray * \ingroup JmgUtility */ @@ -3781,6 +3824,16 @@ return (targetId == l.targetId && JmgUtility::SimpleDistance(location,l.location) <= 0.0f && speed == l.speed && distance == l.distance && attack == l.attack && overrideLocation == l.overrideLocation); } }; + struct ValidLastLocation + { + bool valid; + Vector3 location; + ValidLastLocation(bool valid) + { + this->valid = valid; + } + ValidLastLocation(int enemyId); + }; LastAction lastAction; aiState state; Vector3 homeLocation; @@ -3800,14 +3853,28 @@ int reverseTime; Vector3 lastPosition; bool moveBackward; + float wanderDistanceOverride; + int wanderingAiGroupId; + float wanderSpeed; + float huntSpeed; + float attackSpeed; + float returnHomeSpeed; + int changeWanderGroupCustom; + int changeWanderSpeedCustom; + int changeHuntDistanceCustom; + int changeReturnHomeSpeedCustom; + int changeHuntSpeedCustom; + int changeMaxSightFromHomeLocationCustom; + int changeAttackSpeedCustom; void Created(GameObject *obj); void Enemy_Seen(GameObject *obj,GameObject *seen); void Timer_Expired(GameObject *obj,int number); + void Custom(GameObject *obj,int message,int param,GameObject *sender); void Action_Complete(GameObject *obj,int action_id,ActionCompleteReason reason); void Damaged(GameObject *obj,GameObject *damager,float damage); void Attack_Move(GameObject *obj,GameObject *target,Vector3 location,float speed,float distance,bool attack,bool overrideLocation); GameObject *findClosestStar(GameObject *obj); - void Return_Home(GameObject *obj); + void Return_Home(GameObject *obj,ValidLastLocation goNearLastWanderPoint); void Stuck_Check(GameObject *obj,Vector3 targetPos); void Cant_Get_To_target(GameObject *obj); bool GetRandomPosition(Vector3 *position); @@ -3832,6 +3899,15 @@ * \ShutdownEngineOnArrival - Used for vehicles, turn on if you have issues with your vehicle rolling away from its move positions after it arrives * \AttackCheckBlocked - Defines whether they should check if they can actually hit the player before shooting * \MaxSightRangeFromHome - Maximum range the AI can see from its nearest wander point/home location, useful to keep them from wandering off after a trail of enemies, 0 to not use +* \WanderDistanceOverride - Overrides the default wander arrive distance (1 meter for infantry and 5 for vehicles) +* \ChangeWanderGroupCustom - If this custom is received the wander group will be set to the param, -1 param to disable the wander group code +* \ChangeWanderSpeedCustom - If this custom is received the wander speed will be updated to the param/100 +* \ChangeHuntDistanceCustom - If this custom is received the hunt range will be updated to the param/100 (-1 means infinite range) +* \ChangeHuntSpeedCustom - If this custom is received the hunt speed will be updated to the param/100 +* \ChangeReturnHomeSpeedCustom - If this custom is received the return home speed will be updated to the param/100 +* \ChangeMaxSightFromHomeLocationCustom - If this custom is received the AI won't be able to see targets past the specified range of the param/100, 0 means don't use +* \ChangeAttackSpeedCustom - If this custom is received the attack speed will be updated to the param/100 +* \ChanceToInvestigateLastSeenLocation - The percent chance (0.0-1.0) of checking out the last spot an enemy/target was seen * \author jgray * \ingroup JmgUtility */ @@ -3858,6 +3934,16 @@ this->overrideLocation = overrideLocation; } }; + struct ValidLastLocation + { + bool valid; + Vector3 location; + ValidLastLocation(bool valid) + { + this->valid = valid; + } + ValidLastLocation(int enemyId); + }; float maxSightFromHomeLocation; LastAction lastAction; aiState state; @@ -3877,14 +3963,28 @@ int reverseTime; Vector3 lastPosition; bool moveBackward; + float wanderDistanceOverride; + int wanderingAiGroupId; + float wanderSpeed; + float huntSpeed; + float attackSpeed; + float returnHomeSpeed; + int changeWanderGroupCustom; + int changeWanderSpeedCustom; + int changeHuntDistanceCustom; + int changeReturnHomeSpeedCustom; + int changeHuntSpeedCustom; + int changeMaxSightFromHomeLocationCustom; + int changeAttackSpeedCustom; void Created(GameObject *obj); void Enemy_Seen(GameObject *obj,GameObject *seen); void Timer_Expired(GameObject *obj,int number); + void Custom(GameObject *obj,int message,int param,GameObject *sender); void Action_Complete(GameObject *obj,int action_id,ActionCompleteReason reason); void Damaged(GameObject *obj,GameObject *damager,float damage); void Attack_Move(GameObject *obj,GameObject *target,Vector3 location,float speed,float distance,bool attack,bool overrideLocation); GameObject *findClosestStar(GameObject *obj); - void Return_Home(GameObject *obj); + void Return_Home(GameObject *obj,ValidLastLocation goNearLastWanderPoint); void Stuck_Check(GameObject *obj,Vector3 targetPos); void Cant_Get_To_target(GameObject *obj); bool GetRandomPosition(Vector3 *position); @@ -3906,17 +4006,24 @@ /*! * \brief Sends a custom on a custom -* \Custom - Custom to count +* \Custom - Custom to watch for * \ID - ID to send to, 0 sends to self, -1 sends to sender * \SendCustom - custom to send -* \Param - param to send +* \Param - param to send (-1 sends the param that was received) * \Delay - delay to add -* \ResetCustom - custom to reset the count +* \RandomDelay - Max amount of random delay that can be added to the delay +* \RandomChance - If non-zero this will be the chance that the custom can send 0.0-1.0, 1 will always send * \author jgray * \ingroup JmgUtility */ class JMG_Utility_Custom_Send_Custom : public ScriptImpClass { int recieveMessage; + int id; + int custom; + int Param; + float delay; + float randomDelay; + float randomChance; void Created(GameObject *obj); void Custom(GameObject *obj,int message,int param,GameObject *sender); }; @@ -4835,7 +4942,7 @@ * \PlayerCount - added to the base count, multiplied by the number of players in game * \ID - ID to send to, 0 sends to self, -1 sends to sender * \SendCustom - custom to send -* \Param - param to send +* \Param - param to send (-1 sends the param that was received) * \Delay - delay to add * \ResetCustom - custom to reset the count * \author jgray @@ -4912,7 +5019,7 @@ * \PlayerCount - added to the base count, multiplied by the number of players in game * \ID - ID to send to, 0 sends to self, -1 sends to sender * \SendCustom - custom to send -* \Param - param to send +* \Param - param to send (-1 sends the param that was received) * \Delay - delay to add * \ResetCustom - custom to reset the count * \HudStringId - stringId for the string to be parsed and displayed on the HUD, formatting goes %d/%d (current count out of calculated total) @@ -5453,7 +5560,7 @@ class JMG_Utility_Send_Custom_When_Speed_Exceeds_Amount : public ScriptImpClass { float speed; int id; - int message; + int custom; int param; bool repeat; float rate; @@ -5480,7 +5587,7 @@ class JMG_Utility_Send_Custom_When_Speed_Below_Amount : public ScriptImpClass { float speed; int id; - int message; + int custom; int param; bool repeat; float rate; @@ -5513,7 +5620,7 @@ Vector3 velocityFBL; Vector3 velocityRUD; int id; - int message; + int custom; int param; bool repeat; float rate; @@ -5640,7 +5747,7 @@ * \Custom - Custom to trigger on * \ID - ID to send the custom to, 0 sends to self, -1 sends to sender * \SendCustom - Custom message to send -* \Param - Param to send +* \Param - Param to send (-1 sends the param that was received) * \Delay - Delay to add before sending custom * \IgnoreTime - Time during which customs can't be sent again * \StartsEnabled - Does the script start enabled @@ -5968,3 +6075,743 @@ class JMG_Utility_Damaged_Create_Object_When_Shield_Zero : public ScriptImpClass { void Damaged(GameObject *obj,GameObject *damager,float damage); }; \ No newline at end of file + +/*! +* \brief Spawns objects randomly in a circle using ray casts to find the ground around the location specified can have scripts attached to the spawned object with JMG_Utility_Basic_Spawner_Attach_Script +* \Spawn_Preset - Preset to create (can be a twiddler). +* \Spawn_Rate - Rate at which to spawn more objects (also used to respawn when an object is killed). +* \Random_Spawn_Rate - Random amount to add or subtract from the spawn time. +* \Spawn_At_A_Time - Number of instances of the spawned object can exist at once, for example in a traditional spawner only 1 can exist at a time. +* \Min_Spawn_Radius - The min size of the radius to spawn in, non-zero makes a torus basically +* \Max_Spawn_Radius - The max size of the radius to spawn in. +* \Initial_Spawn_Height - Adds this much to the Z axis on object creation. +* \Spawn_Limit - How many times can objects be spawned before being disabled, -1 means no limit. +* \Spawn_Location - Location in which to spawn the objects, -1 -1 ? (Last value is the height of which to start casting the ray from, -1 makes it the current position) +* \X_Multiplier - Multiply how the circle is shaped on the X coordinates, default is 1.0. +* \Y_Multiplier - Multiply how the circle is shaped on the Y coordinates, default is 1.0. +* \Collision_Check - Check if the spawn location is clear to create the object, 0 means it'll place even if blocked. +* \Collision_Retry_Attempts - How many times will the script "bump" the object if the collision is blocked. +* \Collision_Add_Height - Amount of height to add each time if blocked. +* \Initial_Spawn - Setting the value to -1 will spawn the Spawn_At_A_Time on create, any 0 or above will make the objects slowly spawn in at the spawn rate. +* \Script_ID - Set the id for this script, -1 uses default (only use this if you're going to need to manually add spawned objects to this spawner). +* \Point_Must_Be_In_Pathfind - Requires the created point to be in the pathfind field, if its outside of the field the point will not be created. +* \Manual_Facing - If true random facing will not be used, first it will attempt to use Face_Location and if that's all 0's Face_Direction +* \Face_Location - If anything besides 0,0,0 all objects created will attempt to face the point +* \Face_Direction - If Face_Location was 0,0,0 then Face_Direction will be used +* \Ignore_Ray_Cast_Failure - If a ray fails to cast the script will stop by default (this usually means that it cast beyond the terrain) turn this setting on to continue casting +* \Min_Distance_Between_Objects - If non-zero the script will place objects at least the specified distance away from other objects in the group +* \Spawn_Group_ID - The spawn group id which these objects belong to, if -1 or 0 the distance will be checked against all spawn groups (-1 adds the objects to a group, 0 does not) +* \ if the value is above 0 the objects will only be checked against other objects with the same value. +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Basic_Spawner_In_Radius : public ScriptImpClass { +public: + struct SpawnObjectNode + { + int groupId; + ReferencerClass obj; + SpawnObjectNode(GameObject *obj,int spawnGroupId) + { + this->obj = obj; + this->groupId = spawnGroupId; + } + }; + static SList spawnObjectNodeList; +private: + float minDistanceBetweenObjects; + int spawnGroupId; + int scriptId; + int spawnedObjects; + enum SpawnFailureTypes{SPAWN_BLOCKED, SUCCESS, LIMIT_REACHED, SPAWN_CODE_ERROR}; + Vector3 spawnLocation; + int spawnAtATime; + int spawnLimit; + float minRadius; + float maxRadius; + float xMultiplier; + float yMultiplier; + float addHeight; + float rate; + float randomRate; + char preset[128]; + int spawnCount; + bool collisionCheck; + int retryAttempts; + float initialSpawnHeight; + int changeSpawnCapCustom; + bool pointMustBeInPathfind; + bool manualFacing; + bool ignoreRayCastFailure; + Vector3 faceLocation; + float faceDirection; + void Created(GameObject *obj); + void Timer_Expired(GameObject *obj,int number); + void Custom(GameObject *obj,int message,int param,GameObject *sender); + SpawnFailureTypes AttemptSpawn(GameObject *obj); + bool CheckIfObjectIsNearAnotherObject(Vector3 pos); + void SetFacing(GameObject *obj,float facing); +}; + +/*! +* \brief Tells an object that it belongs to a group of the JMG_Utility_Basic_Spawner_In_Radius (normally attached by JMG_Utility_Basic_Spawner_In_Radius) +* \ A case where manually using this would make sense would be in a drop cinematic, you might have to define on the vehicle object it belongs to the spawn controller. +* \Controller_ID - ID of the object with JMG_Utility_Basic_Spawner_In_Radius attached. +* \Script_ID - Manually or automatically set Script_ID on JMG_Utility_Basic_Spawner_In_Radius. +* \Spawn_Group_ID - Manually or automatically set Spawn_Group_ID on JMG_Utility_Basic_Spawner_In_Radius. +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Basic_Spawner_In_Radius_Attached: public ScriptImpClass { + void Created(GameObject *obj); + void Destroyed(GameObject *obj); + void AddSpawnedObjectToGroup(GameObject *spawned); +}; + +/*! +* \brief Applies damage based on speed when a flying vehicle collides with terrain or another object +* \Min_Collision_Speed - Min speed in M/S to detect collisions +* \Max_Collision_Speed - Max speed a collision can happen and still survive (assuming full health) +* \Collision_Sound - Sound to play when colliding +* \Explosion_Preset - Explosion to create when the vehicle dies from a collision +* \Subtract_Min_Speed - Use this to subtract the min speed from the actual, thus reducing damage done and increasing the amount of speed needed to die +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Flying_Vehicle_Crash_Apply_Damage : public ScriptImpClass { + bool subtractMinSpeed; + char explosionPreset[128]; + char collisionSound[128]; + bool allowCrash; + float minCollisionSpeed; + float maxCollisionSpeed; + void Created(GameObject *obj); + void Timer_Expired(GameObject *obj,int number); +}; + +/*! +* \brief Sends a custom when an enemy is seen, sends a custom again after no enemy in the criteria is visible +* \Enemy_Preset_ID - Preset ID required to be seen to remove the script, if 0 any enemy will trigger the script +* \ID - Id of the object to send the custom to, 0 sends to itself, -1 sends to the seen object +* \Visible_Message - Custom to send when there is a target that is visible +* \Visible_Param - Param to send when there is a target that is visible +* \Not_Visible_Message - Custom sent when no preset is visible anymore +* \Not_Visible_Param - Param sent when no preset is visible anymore +* \Max_Lost_Sight_Time - This is the max amount of time an enmey can go without being seen before being lost, +* \ game scans at least once a second so I reccomend at least 2.5 seconds if not longer +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Enemy_Seen_Send_Custom : public ScriptImpClass { + int lastEnemyId; + int seenTime; + int enemyPresetId; + int id; + int visibleMessage; + int notVisibleMessage; + int visibleParam; + int notVisibleParam; + int maxNotSeenTime; + void Created(GameObject *obj); + void Timer_Expired(GameObject *obj,int number); + void Enemy_Seen(GameObject *obj,GameObject *seen); +}; + +/*! +* \brief Sends a custom on a custom if the specified script is attached +* \Custom - Custom to count +* \ID - ID to send to, 0 sends to self, -1 sends to sender +* \SendCustom - custom to send +* \Param - param to send (-1 sends the param that was received) +* \Delay - delay to add +* \Script - script that must be attached to this object in order to send the custom +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Custom_Send_Custom_If_Script_Attached : public ScriptImpClass { + char script[128]; + int recieveMessage; + void Created(GameObject *obj); + void Custom(GameObject *obj,int message,int param,GameObject *sender); +}; + +/*! +* \brief Sends a custom on a custom if the specified script is not attached +* \Custom - Custom to count +* \ID - ID to send to, 0 sends to self, -1 sends to sender +* \SendCustom - custom to send +* \Param - param to send (-1 sends the param that was received) +* \Delay - delay to add +* \Script - script that must not be attached to this object in order to send the custom +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Custom_Send_Custom_If_Script_Not_Attached : public ScriptImpClass { + char script[128]; + int recieveMessage; + void Created(GameObject *obj); + void Custom(GameObject *obj,int message,int param,GameObject *sender); +}; + +/*! +* \brief Place this script on an object that exists the duration of the map, all it does is deletes the spawn group nodes if you use them on game end. +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Basic_Spawner_In_Radius_Controller: public ScriptImpClass { + void Destroyed(GameObject *obj); +}; + +/*! +* \brief Enables or disables the attached vehicles engine on custom +* \Custom - Custom to trigger on +* \Enable - Whether to enable or disable the engine, -1 uses the param instead +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Custom_Set_Engine : public ScriptImpClass { + int custom; + int enable; + void Created(GameObject *obj); + void Custom(GameObject *obj,int message,int param,GameObject *sender); +}; + +/*! +* \brief Sends a custom when the count of presets on the map matches the player count +* \Preset_ID - Preset ID required to match the count of players on the map +* \ID - Id of the object to send the custom to, 0 sends to itself +* \Message - Custom to send when when the count matches +* \Param - Param to send when when the count matches +* \Delay - Time to wait before sending the message +* \Min_Player_Count - Min required players to trigger script, -1 any +* \Max_Player_Count - Max players allowed to trigger script, -1 any +* \Rate - Rate to scan for count changes (0.1 - 10 times a second by default). +* \Repeat - Can the script fire more than once. +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Send_Custom_Player_Count_Matches_Preset_Count : public ScriptImpClass { + int presetId; + int id; + int custom; + int param; + float delay; + float rate; + int minPlayers; + int maxPlayers; + bool repeat; + void Created(GameObject *obj); + void Timer_Expired(GameObject *obj,int number); +}; + + +/*! +* \brief Moves an object when a custom is received, works on zones +* \Custom - Custom to trigger on +* \Position - Spot to place object +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Custom_Set_Position : public ScriptImpClass { + int custom; + Vector3 position; + void Created(GameObject *obj); + void Custom(GameObject *obj,int message,int param,GameObject *sender); +}; + +/*! +* \brief Sends a custom after a delay, if the custom being watched for is received again the delay is reset before attempting to send again +* \Custom - Custom to watch for +* \ID - ID to send to, 0 sends to self, -1 sends to sender +* \SendCustom - custom to send +* \Param - param to send (-1 sends the param that was received) +* \Delay - delay to wait before sending +* \RandomDelay - Random amount of delay that can be added to the delay time +* \CancelCustom - If this custom is caught the pending custom will be canceled +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Custom_Delay_Send_Custom : public ScriptImpClass { + int watchMessage; + int id; + int Param; + ReferencerClass lastSender; + int sendMessage; + int lastParam; + float delay; + float randomDelay; + int cancelCustom; + void Created(GameObject *obj); + void Custom(GameObject *obj,int message,int param,GameObject *sender); + void Timer_Expired(GameObject *obj,int number); +}; + +/*! +* \brief Scales the HP and armor of the object as players join/leave the match (if no players are in game the HP/Armor is not updated from the last player count) +* \Health_Multiplier - Amount to multiply the health by per player (keep in mind the max value transmitted across the network is 10k). +* \Armor_Multiplier - Amount to multiply the armor by per player (keep in mind the max value transmitted across the network is 10k). +* \Max_Player_Count - Max player count allows you to specify a maximum amount of players the script should account for, any above it will be ignored. +* \Repeat - Should the script check multiple times for player count changes 1 - yes, 0 - no. +* \UpdateScaleCustom - If recieved the health will be updated +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Scale_HP_By_Player_Count : public ScriptImpClass { + int lastPlayerCount; + int maxPlayerCount; + float originalHealth; + float originalArmor; + float healthMultiplier; + float armorMultiplier; + int updateScaleCustom; + bool repeat; + void Created(GameObject *obj); + void Timer_Expired(GameObject *obj,int number); + void Custom(GameObject *obj,int message,int param,GameObject *sender); + void RescaleHP(GameObject *obj); +}; + +/*! +* \brief Sends a to all objects on the map +* \Custom - Custom to watch for +* \Team - Required team to send to, 2 for any +* \SendCustom - custom to send +* \Param - param to send (-1 sends the param that was received) +* \Delay - delay to add +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Custom_Send_Custom_To_All_Objects : public ScriptImpClass { + int recieveMessage; + int team; + int custom; + int Param; + float delay; + void Created(GameObject *obj); + void Custom(GameObject *obj,int message,int param,GameObject *sender); +}; + +/*! +* \brief Prevents JMG_Utility_Enemy_Seen_Send_Custom from seening the attached object +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Enemy_Seen_Send_Custom_Ignore : public ScriptImpClass { + void Created(GameObject *obj); +}; + +/*! +* \brief Sends a custom when an enemy is in the line of sight, sends a custom again after no enemy in the criteria is visible +* \Enemy_Preset_ID - Preset ID required to be seen to remove the script, if 0 any enemy will trigger the script +* \ID - Id of the object to send the custom to, 0 sends to itself, -1 sends to the seen object +* \Visible_Message - Custom to send when there is a target that is visible +* \Visible_Param - Param to send when there is a target that is visible +* \Not_Visible_Message - Custom sent when no preset is visible anymore +* \Not_Visible_Param - Param sent when no preset is visible anymore +* \Scan_Rate - This is how often to scan for enemies +* \Enemy_Only - Only detect enemies +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_In_Line_Of_Sight_Send_Custom : public ScriptImpClass { + int lastEnemyId; + int enemyPresetId; + int id; + int visibleMessage; + int notVisibleMessage; + int visibleParam; + int notVisibleParam; + bool enemyOnly; + float rate; + void Created(GameObject *obj); + void Timer_Expired(GameObject *obj,int number); + bool Test_Line_Of_Sight(GameObject *obj,GameObject *seen); +}; + +/*! +* \brief Prevents JMG_Utility_In_Line_Of_Sight_Send_Custom from seening the attached object +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_In_Line_Of_Sight_Send_Custom_Ignore : public ScriptImpClass { + void Created(GameObject *obj); +}; + +/*! +* \brief Forces the attached object to scan for enemies more often (server's default rate has a random of 0.5-1.0 seconds added to the last scan) +* \Scan_Rate - This is how often to scan for enemies +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Timer_Trigger_Enemy_Seen : public ScriptImpClass { + float rate; + void Created(GameObject *obj); + void Timer_Expired(GameObject *obj,int number); +}; + +/*! +* \brief Teleports the object that enters the zone to a random wander point +* \Custom - Custom to trigger the teleport +* \WanderingAIGroupID - Group of points to teleport to +* \SafeTeleportDistance - How far can infantry be moved if the spot is blocked +* \RetryOnFailure - If this is true a script will be attached that will continue to try to teleport the player until successful (Warning: Turning this on hides error messages) +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Custom_Teleport_To_Random_Wander_Point : public ScriptImpClass { + bool retryOnFailure; + int custom; + float safeTeleportDistance; + int wanderPointGroup; + void Created(GameObject *obj); + void Custom(GameObject *obj,int message,int param,GameObject *sender); + bool Get_A_Defense_Point(Vector3 *position,float *facing); + bool Grab_Teleport_Spot(GameObject *enter,int attempts); +}; + +/*! +* \brief Sends a custom if the unit doesn't manage to move more than the specified distance in the specified time +* \Time - amount of time the unit has to move +* \Distance - the distance the unit has to move +* \ID - ID to send to, 0 sends to self, -1 sends to sender +* \SendCustom - custom to send +* \Param - param to send (-1 sends the param that was received) +* \Delay - delay to add +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Send_Custom_If_Not_Moving_Enough : public ScriptImpClass { + int time; + int resetTime; + float distance; + int id; + int custom; + int Param; + float delay; + Vector3 lastPos; + void Created(GameObject *obj); + void Timer_Expired(GameObject *obj,int number); +}; + + +/*! +* \brief The AI attached to this script will flee enemies seen and combat (Like in Deer Hunter mode for ECW) +* \MinHerdID - Min Herd ID that this object will belong to (max of 128) +* \MaxHerdID - Max Herd ID that this object will belong to (max of 128) +* \WanderGroupID - The wander group network the herd will use to run from threats +* \WanderRadiusAroundHerdCenter - How far can the objects wander around the center of the herd +* \MinWanderFrequency - Min amount of time a member of the herd can hold still before moving +* \MaxWanderFrequency - Max amount of time a member of the herd can hold still before moving +* \MinRetreatTime - Min amount of time that the AI can flee +* \MaxRetreatTime - Max amount of time that the AI can flee +* \MinUpdateHerdCenter - Min amount of time required for the center point of the herd to reposition +* \MaxUpdateHerdCenter - Max amount of time required for the center point of the herd to reposition +* \RunTowardThreatChance - Chance that it'll flee on purpose toward the threat (0.0 - 1.0) +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_AI_Skittish_Herd_Animal : public ScriptImpClass { +public: + class HerdAnimalPositionSystem + { + public: + int animalCount; + struct HerdPositionNode + { + int id; + Vector3 pos; + bool alive; + struct HerdPositionNode *next; + HerdPositionNode(GameObject *obj) + { + this->id = Commands->Get_ID(obj); + this->pos = Commands->Get_Position(obj); + this->alive = true; + next = NULL; + } + }; + Vector3 herdRetreatLocation; + float herdRetreatTime; + time_t herdRetreatStart; + private: + Vector3 centerPos; + time_t lastPosCalcTime; + float minUpdateDelay; + bool hascalculatedPos; + HerdPositionNode *HerdPositionNodeList; + public: + HerdAnimalPositionSystem() + { + herdRetreatLocation = Vector3(0.0f,0.0f,0.0f); + herdRetreatTime = 0.0f; + herdRetreatStart = clock(); + minUpdateDelay = 10000.0f; + hascalculatedPos = false; + animalCount = 0; + centerPos = Vector3(0.0f,0.0f,0.0f); + lastPosCalcTime = clock(); + HerdPositionNodeList = NULL; + } + HerdPositionNode *AddNode(GameObject *obj) + { + int id = Commands->Get_ID(obj); + HerdPositionNode *Current = HerdPositionNodeList; + while (Current) + { + if (Current->id == id) + { + animalCount--; + return Current; + } + Current = Current->next; + } + animalCount++; + if (!HerdPositionNodeList) + return (HerdPositionNodeList = new HerdPositionNode(obj)); + Current = HerdPositionNodeList; + while (Current) + { + if (!Current->alive) + { + Current->id = Commands->Get_ID(obj); + Current->pos = Commands->Get_Position(obj); + Current->alive = true; + return Current; + } + if (!Current->next) + { + Current->next = new HerdPositionNode(obj); + return Current->next; + } + Current = Current->next; + } + return NULL; + } + HerdAnimalPositionSystem &operator -= (GameObject *obj) + { + int id = Commands->Get_ID(obj); + HerdPositionNode *Current = HerdPositionNodeList; + while (Current) + { + if (Current->id == id) + { + animalCount--; + Current->alive = false; + break; + } + Current = Current->next; + } + return *this; + } + Vector3 getCenterLocation(bool allowWander,int wanderPointGroup,float minUpdateHerdCenter,float maxUpdateHerdCenter); + bool checkRetreatSuccessful() + { + HerdPositionNode *Current = HerdPositionNodeList; + int retreatedCount = 0; + while (Current) + { + if (Current->alive && JmgUtility::SimpleDistance(Current->pos,herdRetreatLocation) < 2500) + retreatedCount++; + Current = Current->next; + } + if (animalCount == retreatedCount) + return true; + return false; + } + bool checkRetreatCloseEnough() + { + HerdPositionNode *Current = HerdPositionNodeList; + int retreatedCount = 0; + while (Current) + { + if (Current->alive && JmgUtility::SimpleDistance(Current->pos,herdRetreatLocation) < 2500) + retreatedCount++; + Current = Current->next; + } + if (animalCount*0.75 <= retreatedCount) + return true; + return false; + } + void Empty_List() + { + HerdPositionNode *temp = HerdPositionNodeList,*die; + while (temp) + { + die = temp; + temp = temp->next; + delete die; + } + HerdPositionNodeList = NULL; + } + }; + static HerdAnimalPositionSystem HerdAnimalPositionControl[128]; +private: + int herdId; + HerdAnimalPositionSystem::HerdPositionNode *HerdPositionNode; + int wanderPointGroup; + char defaultWeapon[128]; + float weaponRange; + float minRetreatRange; + float maxRetreatRange; + float minRetreatTime; + float maxRetreatTime; + float minUpdateHerdCenter; + float maxUpdateHerdCenter; + float wanderRadiusAroundHerdCenter; + float wanderRadiusAroundHerdCenterSq; + float minWanderFrequency; + float maxWanderFrequency; + float runTowardThreatChance; + void Created(GameObject *obj); + void Enemy_Seen(GameObject *obj,GameObject *seen); + void Timer_Expired(GameObject *obj,int number); + void Damaged(GameObject *obj,GameObject *damager,float damage); + void Destroyed(GameObject *obj); + void GotoLocation(GameObject *obj,const Vector3 &pos,GameObject *Enemy,float speed = 0); + void setRetreatLocation(GameObject *obj,GameObject *enemy); +public: + JMG_Utility_AI_Skittish_Herd_Animal() + { + herdId = 0; + HerdPositionNode = NULL; + } + static bool Get_A_Wander_Point(Vector3 *position,int wanderPointGroup); +}; +/*! +* \brief Prevents JMG_Utility_AI_Skittish_Herd_Animal from seening the attached object +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_AI_Skittish_Herd_Animal_Ignore : public ScriptImpClass { + void Created(GameObject *obj); +}; + +/*! +* \brief Just used to clean up JMG_Utility_AI_Skittish_Herd_Animal at game end, not required but nice to have +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_AI_Skittish_Herd_Animal_Controller : public ScriptImpClass { +public: + JMG_Utility_AI_Skittish_Herd_Animal_Controller() + { + for (int x = 0;x < 128;x++) + JMG_Utility_AI_Skittish_Herd_Animal::HerdAnimalPositionControl[x] = JMG_Utility_AI_Skittish_Herd_Animal::HerdAnimalPositionSystem(); + } + void Destroyed(GameObject *obj); +}; + +/*! +* \brief Displays a popup dialog to the attached player object +* \Custom - Custom to trigger the teleport +* \Message - Text message to display +* \Delim - Character to use to replace with ,'s +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Custom_Display_Dialog_Box : public ScriptImpClass { + int custom; + char *textMessage; + void Created(GameObject *obj); + void Custom(GameObject *obj,int message,int param,GameObject *sender); +}; + +/*! +* \brief Sends a custom if the specified preset ID is on the map +* \Custom - Custom to watch for +* \PresetID - Preset ID to check for +* \MinCount - Min number of presets that must exist +* \MaxCount - Max number of presets that can exist (-1 no limit) +* \ID - ID to send to, 0 sends to self, -1 sends to sender +* \SendCustom - custom to send +* \Param - param to send (-1 sends the param that was received) +* \Delay - delay to add +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Custom_Send_Custom_On_Preset_Count : public ScriptImpClass { + int recieveMessage; + int presetId; + int minCount; + int maxCount; + int id; + int custom; + int Param; + float delay; + void Created(GameObject *obj); + void Custom(GameObject *obj,int message,int param,GameObject *sender); +}; + +/*! +* \brief Sends a custom if the specified script is on a preset on the map +* \Custom - Custom to watch for +* \Script - Script to check for +* \MinCount - Min number of presets that must exist +* \MaxCount - Max number of presets that can exist (-1 no limit) +* \ID - ID to send to, 0 sends to self, -1 sends to sender +* \SendCustom - custom to send +* \Param - param to send (-1 sends the param that was received) +* \Delay - delay to add +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Custom_Send_Custom_On_Script_Count : public ScriptImpClass { + int recieveMessage; + char script[128]; + int minCount; + int maxCount; + int id; + int custom; + int Param; + float delay; + void Created(GameObject *obj); + void Custom(GameObject *obj,int message,int param,GameObject *sender); +}; + + +/*! +* \brief Sends a custom message on poke, also enables the pokable indicator icon, just like JMG_Utility_Poke_Send_Custom but sends from the poker +* \ID - ID to send the custom to, 0 sends to self, -1 sends to poker +* \Custom - Custom message to send +* \Param - Param to send +* \Delay - Delay to add before sending custom +* \TriggerOnce - Allows the script only to trigger the first time all customs are received +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Poke_Send_Custom_From_Poker : public ScriptImpClass { + void Created(GameObject *obj); + void Poked(GameObject *obj, GameObject *poker); +}; + +/*! +* \brief Scales the given score as players join/leave the match (if no players are in game the score is not updated from the last player count) +* \GrantCustom - Custom to trigger granting the score +* \Score - Score to give on custom +* \ScoreMultiplier - Amount to multiply the score by per player +* \EntireTeam - Give the score to the whole team 0 no 1 yes +* \MaxPlayerCount - Max player count allows you to specify a maximum amount of players the script should account for, any above it will be ignored. +* \Repeat - Should the script check multiple times for player count changes 1 - yes, 0 - no. +* \GrantToSender - The object to grant to, 0 is itself 1 is the sender +* \UpdateScaleCustom - If recieved the health will be updated +* \StopUpdateCustom - Custom to stop updating the score value +* \author jgray +* \ingroup JmgUtility +*/ +class JMG_Utility_Custom_Grant_Scaled_Score : public ScriptImpClass { + int lastPlayerCount; + int maxPlayerCount; + int grantCustom; + float score; + float scoreMultiplier; + int updateScaleCustom; + bool repeat; + bool grantToSender; + float theScore; + bool entireTeam; + int stopUpdateCustom; + void Created(GameObject *obj); + void Timer_Expired(GameObject *obj,int number); + void Custom(GameObject *obj,int message,int param,GameObject *sender); + void RescaleScore(GameObject *obj); +}; \ No newline at end of file diff -uwrN sourceold/scripts/weaponmgr.h source/scripts/weaponmgr.h --- sourceold/scripts/weaponmgr.h 2016-12-10 07:57:58.701001000 +1000 +++ source/scripts/weaponmgr.h 2018-11-11 08:30:08.538600000 +1000 @@ -96,7 +96,9 @@ safe_float TargetingRange;//new int C4Preset; bool DisableHitscan; - bool TrackingIgnoreTarget; + bool TrackingIgnoreVehicle; + bool TrackingIgnoreSoldier; + bool TrackingIgnoreVTOL; #if (PARAM_EDITING_ON) || (DDBEDIT) || (W3DVIEWER) Vector3 ProjectileExtent;