/*============================================================================= Tactics.c: Control Functions for Homeworld Tactics Created June 1998 Bryce =============================================================================*/ #include #include "tactics.h" #include "univupdate.h" #include "statscript.h" #include "region.h" #include "feflow.h" #include "mainrgn.h" #include "task.h" #include "universe.h" #include "physics.h" #include "classdefs.h" #include "types.h" #include "commandlayer.h" #include "tweak.h" #include "blobs.h" #include "proximitySensor.h" #include "formation.h" #include "fastmath.h" #include "repaircorvette.h" #include "flightman.h" #include "mouse.h" #include "salcapcorvette.h" #include "alliance.h" #include "Probe.h" #include "randy.h" #include "soundevent.h" #include "battle.h" //global data //special ops tweakables real32 kamikazeDamage[TOTAL_NUM_SHIPS]; real32 kamikazeSpeedBurst; real32 kamikazeFuelBurnMult; real32 speedBurstMaxVelocityMultiplier; real32 speedBurstThrustMult; real32 speedBurstDuration; real32 speedBurstFuelBurnMult; real32 speedBurstCoolDown; real32 burstRange; real32 burstChargeTime; real32 burstCoolDownTime; real32 burstDamageLo[NUM_RACES]; real32 burstDamageHi[NUM_RACES]; real32 burstSpeed; real32 oneOverburstSpeed; real32 burstRadius; real32 ATTACKING_FROM_ABOVE_MIN_DIST = 250.0f; real32 ATTACKING_FROM_ABOVE_MIN_RATIO = 2.0f; real32 OUT_OF_FUEL_VELOCITY_SLOWDOWN = 0.125f; real32 IONCANNON_TARGETS_FIGHTER_ANGLE = 0.99939f; real32 IONCANNON_TARGETS_CORVETTE_ANGLE = 0.99756f; real32 IONCANNON_TARGETS_FIGHTER_TRIGGERHAPPY = 0.99939f; real32 IONCANNON_TARGETS_CORVETTE_TRIGGERHAPPY = 0.99756f; real32 IONCANNON_TARGETS_FIGHTER_MAXANGLESPEED = 3.0f; real32 IONCANNON_TARGETS_CORVETTE_MAXANGLESPEED = 3.0f; real32 GLOBAL_SHIP_SPEED_MODIFIER = 1.0f; real32 DELAY_FORMTIGHTNESS_CHANGE = 5.0f; //local prototypes bool tacticsShipCanDodge(Ship *ship); bool tacticsShipIsAffectedByTactcis(Ship *ship); bool tacticsIsShipLookingForAnyOfThese(Ship *ship,SelectCommand *selection); bool tacticsAreEnemiesNearby(Ship *leadership, Ship *thisship,real32 retaliateZone); //special ops prototype void speedBurstUpdate(Ship *ship); scriptEntry TacticsInfotable[] = { { "EnemyNearZone" ,scriptSetReal32CB, &tacticsInfo.EnemyNearZone}, { "PassiveRetaliationFireTimeModifierLow" ,scriptSetReal32CB, &tacticsInfo.PassiveRetaliationFireTimeModifierLow}, { "PassiveRetaliationFireTimeModifierHi" ,scriptSetReal32CB, &tacticsInfo.PassiveRetaliationFireTimeModifierHi}, { "MenuFeedBack_X" ,scriptSetUdwordCB, &tacticsInfo.MenuFeedBack_X}, { "MenuFeedBack_Y" ,scriptSetUdwordCB, &tacticsInfo.MenuFeedBack_Y}, { "menuPopupTime" ,scriptSetReal32CB, &tacticsInfo.menuPopupTime}, makeEntry(ATTACKING_FROM_ABOVE_MIN_DIST,scriptSetReal32CB), makeEntry(ATTACKING_FROM_ABOVE_MIN_RATIO,scriptSetReal32CB), { "RetreatDistance[CLASS_Mothership]" ,scriptSetReal32SqrCB, &tacticsInfo.RetreatDistanceSqr[CLASS_Mothership]}, { "RetreatDistance[CLASS_HeavyCruiser]" ,scriptSetReal32SqrCB, &tacticsInfo.RetreatDistanceSqr[CLASS_HeavyCruiser]}, { "RetreatDistance[CLASS_Carrier]" ,scriptSetReal32SqrCB, &tacticsInfo.RetreatDistanceSqr[CLASS_Carrier]}, { "RetreatDistance[CLASS_Destroyer]" ,scriptSetReal32SqrCB, &tacticsInfo.RetreatDistanceSqr[CLASS_Destroyer]}, { "RetreatDistance[CLASS_Frigate]" ,scriptSetReal32SqrCB, &tacticsInfo.RetreatDistanceSqr[CLASS_Frigate]}, { "RetreatDistance[CLASS_Corvette]" ,scriptSetReal32SqrCB, &tacticsInfo.RetreatDistanceSqr[CLASS_Corvette]}, { "RetreatDistance[CLASS_Fighter]" ,scriptSetReal32SqrCB, &tacticsInfo.RetreatDistanceSqr[CLASS_Fighter]}, { "RetreatDistance[CLASS_Resource]" ,scriptSetReal32SqrCB, &tacticsInfo.RetreatDistanceSqr[CLASS_Resource]}, { "RetreatDistance[CLASS_NonCombat]" ,scriptSetReal32SqrCB, &tacticsInfo.RetreatDistanceSqr[CLASS_NonCombat]}, { "RetreatGetAwayDistance[CLASS_Mothership]" ,scriptSetReal32SqrCB, &tacticsInfo.RetreatGetAwayDistSqr[CLASS_Mothership]}, { "RetreatGetAwayDistance[CLASS_HeavyCruiser]" ,scriptSetReal32SqrCB, &tacticsInfo.RetreatGetAwayDistSqr[CLASS_HeavyCruiser]}, { "RetreatGetAwayDistance[CLASS_Carrier]" ,scriptSetReal32SqrCB, &tacticsInfo.RetreatGetAwayDistSqr[CLASS_Carrier]}, { "RetreatGetAwayDistance[CLASS_Destroyer]" ,scriptSetReal32SqrCB, &tacticsInfo.RetreatGetAwayDistSqr[CLASS_Destroyer]}, { "RetreatGetAwayDistance[CLASS_Frigate]" ,scriptSetReal32SqrCB, &tacticsInfo.RetreatGetAwayDistSqr[CLASS_Frigate]}, { "RetreatGetAwayDistance[CLASS_Corvette]" ,scriptSetReal32SqrCB, &tacticsInfo.RetreatGetAwayDistSqr[CLASS_Corvette]}, { "RetreatGetAwayDistance[CLASS_Fighter]" ,scriptSetReal32SqrCB, &tacticsInfo.RetreatGetAwayDistSqr[CLASS_Fighter]}, { "RetreatGetAwayDistance[CLASS_Resource]" ,scriptSetReal32SqrCB, &tacticsInfo.RetreatGetAwayDistSqr[CLASS_Resource]}, { "RetreatGetAwayDistance[CLASS_NonCombat]" ,scriptSetReal32SqrCB, &tacticsInfo.RetreatGetAwayDistSqr[CLASS_NonCombat]}, { "freeRetreatTime" ,scriptSetReal32CB, &tacticsInfo.freeRetreatTime}, { "AttackMemoryTimeOut" ,scriptSetReal32CB, &tacticsInfo.AttackMemoryTimeOut}, { "formationPadding[LooseFormation]",scriptSetReal32CB, &tacticsInfo.formationPadding[LooseFormation]}, { "formationPadding[TightFormation]",scriptSetReal32CB, &tacticsInfo.formationPadding[TightFormation]}, { "InterceptorVerticalMultiplier" ,scriptSetReal32CB, &tacticsInfo.InterceptorVerticalMultiplier}, { "DodgeLowAddTime" ,scriptSetReal32CB, &tacticsInfo.DodgeLowAddTime}, { "DodgeHighAddTime" ,scriptSetReal32CB, &tacticsInfo.DodgeHighAddTime}, { "DodgeInfo[DODGE_ONE_TIME][AttackBomber]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_ONE_TIME][AttackBomber]}, { "DodgeInfo[DODGE_TWO_TIME][AttackBomber]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_TWO_TIME][AttackBomber]}, { "DodgeInfo[DODGE_THRUST_MULT][AttackBomber]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_THRUST_MULT][AttackBomber]}, { "DodgeInfo[DODGE_WAIT][AttackBomber]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_WAIT][AttackBomber]}, { "DodgeInfo[DODGE_ONE_TIME][CloakedFighter]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_ONE_TIME][CloakedFighter]}, { "DodgeInfo[DODGE_TWO_TIME][CloakedFighter]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_TWO_TIME][CloakedFighter]}, { "DodgeInfo[DODGE_THRUST_MULT][CloakedFighter]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_THRUST_MULT][CloakedFighter]}, { "DodgeInfo[DODGE_WAIT][CloakedFighter]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_WAIT][CloakedFighter]}, { "DodgeInfo[DODGE_ONE_TIME][DefenseFighter]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_ONE_TIME][DefenseFighter]}, { "DodgeInfo[DODGE_TWO_TIME][DefenseFighter]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_TWO_TIME][DefenseFighter]}, { "DodgeInfo[DODGE_THRUST_MULT][DefenseFighter]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_THRUST_MULT][DefenseFighter]}, { "DodgeInfo[DODGE_WAIT][DefenseFighter]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_WAIT][DefenseFighter]}, { "DodgeInfo[DODGE_ONE_TIME][HeavyCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_ONE_TIME][HeavyCorvette]}, { "DodgeInfo[DODGE_TWO_TIME][HeavyCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_TWO_TIME][HeavyCorvette]}, { "DodgeInfo[DODGE_THRUST_MULT][HeavyCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_THRUST_MULT][HeavyCorvette]}, { "DodgeInfo[DODGE_WAIT][HeavyCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_WAIT][HeavyCorvette]}, { "DodgeInfo[DODGE_ONE_TIME][HeavyDefender]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_ONE_TIME][HeavyDefender]}, { "DodgeInfo[DODGE_TWO_TIME][HeavyDefender]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_TWO_TIME][HeavyDefender]}, { "DodgeInfo[DODGE_THRUST_MULT][HeavyDefender]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_THRUST_MULT][HeavyDefender]}, { "DodgeInfo[DODGE_WAIT][HeavyDefender]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_WAIT][HeavyDefender]}, { "DodgeInfo[DODGE_ONE_TIME][HeavyInterceptor]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_ONE_TIME][HeavyInterceptor]}, { "DodgeInfo[DODGE_TWO_TIME][HeavyInterceptor]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_TWO_TIME][HeavyInterceptor]}, { "DodgeInfo[DODGE_THRUST_MULT][HeavyInterceptor]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_THRUST_MULT][HeavyInterceptor]}, { "DodgeInfo[DODGE_WAIT][HeavyInterceptor]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_WAIT][HeavyInterceptor]}, { "DodgeInfo[DODGE_ONE_TIME][LightCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_ONE_TIME][LightCorvette]}, { "DodgeInfo[DODGE_TWO_TIME][LightCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_TWO_TIME][LightCorvette]}, { "DodgeInfo[DODGE_THRUST_MULT][LightCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_THRUST_MULT][LightCorvette]}, { "DodgeInfo[DODGE_WAIT][LightCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_WAIT][LightCorvette]}, { "DodgeInfo[DODGE_ONE_TIME][LightDefender]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_ONE_TIME][LightDefender]}, { "DodgeInfo[DODGE_TWO_TIME][LightDefender]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_TWO_TIME][LightDefender]}, { "DodgeInfo[DODGE_THRUST_MULT][LightDefender]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_THRUST_MULT][LightDefender]}, { "DodgeInfo[DODGE_WAIT][LightDefender]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_WAIT][LightDefender]}, { "DodgeInfo[DODGE_ONE_TIME][LightInterceptor]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_ONE_TIME][LightInterceptor]}, { "DodgeInfo[DODGE_TWO_TIME][LightInterceptor]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_TWO_TIME][LightInterceptor]}, { "DodgeInfo[DODGE_THRUST_MULT][LightInterceptor]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_THRUST_MULT][LightInterceptor]}, { "DodgeInfo[DODGE_WAIT][LightInterceptor]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_WAIT][LightInterceptor]}, { "DodgeInfo[DODGE_ONE_TIME][MinelayerCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_ONE_TIME][MinelayerCorvette]}, { "DodgeInfo[DODGE_TWO_TIME][MinelayerCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_TWO_TIME][MinelayerCorvette]}, { "DodgeInfo[DODGE_THRUST_MULT][MinelayerCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_THRUST_MULT][MinelayerCorvette]}, { "DodgeInfo[DODGE_WAIT][MinelayerCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_WAIT][MinelayerCorvette]}, { "DodgeInfo[DODGE_ONE_TIME][MultiGunCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_ONE_TIME][MultiGunCorvette]}, { "DodgeInfo[DODGE_TWO_TIME][MultiGunCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_TWO_TIME][MultiGunCorvette]}, { "DodgeInfo[DODGE_THRUST_MULT][MultiGunCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_THRUST_MULT][MultiGunCorvette]}, { "DodgeInfo[DODGE_WAIT][MultiGunCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_WAIT][MultiGunCorvette]}, { "DodgeInfo[DODGE_ONE_TIME][RepairCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_ONE_TIME][RepairCorvette]}, { "DodgeInfo[DODGE_TWO_TIME][RepairCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_TWO_TIME][RepairCorvette]}, { "DodgeInfo[DODGE_THRUST_MULT][RepairCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_THRUST_MULT][RepairCorvette]}, { "DodgeInfo[DODGE_WAIT][RepairCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_WAIT][RepairCorvette]}, { "DodgeInfo[DODGE_ONE_TIME][SalCapCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_ONE_TIME][SalCapCorvette]}, { "DodgeInfo[DODGE_TWO_TIME][SalCapCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_TWO_TIME][SalCapCorvette]}, { "DodgeInfo[DODGE_THRUST_MULT][SalCapCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_THRUST_MULT][SalCapCorvette]}, { "DodgeInfo[DODGE_WAIT][SalCapCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_WAIT][SalCapCorvette]}, { "DodgeInfo[DODGE_ONE_TIME][P1Fighter]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_ONE_TIME][P1Fighter]}, { "DodgeInfo[DODGE_TWO_TIME][P1Fighter]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_TWO_TIME][P1Fighter]}, { "DodgeInfo[DODGE_THRUST_MULT][P1Fighter]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_THRUST_MULT][P1Fighter]}, { "DodgeInfo[DODGE_WAIT][P1Fighter]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_WAIT][P1Fighter]}, { "DodgeInfo[DODGE_ONE_TIME][P1MissileCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_ONE_TIME][P1MissileCorvette]}, { "DodgeInfo[DODGE_TWO_TIME][P1MissileCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_TWO_TIME][P1MissileCorvette]}, { "DodgeInfo[DODGE_THRUST_MULT][P1MissileCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_THRUST_MULT][P1MissileCorvette]}, { "DodgeInfo[DODGE_WAIT][P1MissileCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_WAIT][P1MissileCorvette]}, { "DodgeInfo[DODGE_ONE_TIME][P1StandardCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_ONE_TIME][P1StandardCorvette]}, { "DodgeInfo[DODGE_TWO_TIME][P1StandardCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_TWO_TIME][P1StandardCorvette]}, { "DodgeInfo[DODGE_THRUST_MULT][P1StandardCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_THRUST_MULT][P1StandardCorvette]}, { "DodgeInfo[DODGE_WAIT][P1StandardCorvette]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_WAIT][P1StandardCorvette]}, { "DodgeInfo[DODGE_ONE_TIME][P2AdvanceSwarmer]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_ONE_TIME][P2AdvanceSwarmer]}, { "DodgeInfo[DODGE_TWO_TIME][P2AdvanceSwarmer]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_TWO_TIME][P2AdvanceSwarmer]}, { "DodgeInfo[DODGE_THRUST_MULT][P2AdvanceSwarmer]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_THRUST_MULT][P2AdvanceSwarmer]}, { "DodgeInfo[DODGE_WAIT][P2AdvanceSwarmer]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_WAIT][P2AdvanceSwarmer]}, { "DodgeInfo[DODGE_ONE_TIME][P2Swarmer]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_ONE_TIME][P2Swarmer]}, { "DodgeInfo[DODGE_TWO_TIME][P2Swarmer]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_TWO_TIME][P2Swarmer]}, { "DodgeInfo[DODGE_THRUST_MULT][P2Swarmer]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_THRUST_MULT][P2Swarmer]}, { "DodgeInfo[DODGE_WAIT][P2Swarmer]",scriptSetReal32CB, &tacticsInfo.DodgeInfo[DODGE_WAIT][P2Swarmer]}, { "MaxVelocityBonus[NO_ORDER_NO_ENEMY][Tactics_Fighter][Evasive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[NO_ORDER_NO_ENEMY][Tactics_Fighter][Evasive]}, { "MaxVelocityBonus[NO_ORDER_NO_ENEMY][Tactics_Fighter][Neutral]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[NO_ORDER_NO_ENEMY][Tactics_Fighter][Neutral]}, { "MaxVelocityBonus[NO_ORDER_NO_ENEMY][Tactics_Fighter][Aggressive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[NO_ORDER_NO_ENEMY][Tactics_Fighter][Aggressive]}, { "MaxVelocityBonus[NO_ORDER_ENEMY][Tactics_Fighter][Evasive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[NO_ORDER_ENEMY][Tactics_Fighter][Evasive]}, { "MaxVelocityBonus[NO_ORDER_ENEMY][Tactics_Fighter][Neutral]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[NO_ORDER_ENEMY][Tactics_Fighter][Neutral]}, { "MaxVelocityBonus[NO_ORDER_ENEMY][Tactics_Fighter][Aggressive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[NO_ORDER_ENEMY][Tactics_Fighter][Aggressive]}, { "MaxVelocityBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Fighter][Evasive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Fighter][Evasive]}, { "MaxVelocityBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Fighter][Neutral]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Fighter][Neutral]}, { "MaxVelocityBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Fighter][Aggressive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Fighter][Aggressive]}, { "MaxVelocityBonus[MOVE_ORDERS_ENEMY][Tactics_Fighter][Evasive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[MOVE_ORDERS_ENEMY][Tactics_Fighter][Evasive]}, { "MaxVelocityBonus[MOVE_ORDERS_ENEMY][Tactics_Fighter][Neutral]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[MOVE_ORDERS_ENEMY][Tactics_Fighter][Neutral]}, { "MaxVelocityBonus[MOVE_ORDERS_ENEMY][Tactics_Fighter][Aggressive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[MOVE_ORDERS_ENEMY][Tactics_Fighter][Aggressive]}, { "MaxVelocityBonus[ATTACK_ORDERS][Tactics_Fighter][Evasive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[ATTACK_ORDERS][Tactics_Fighter][Evasive]}, { "MaxVelocityBonus[ATTACK_ORDERS][Tactics_Fighter][Neutral]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[ATTACK_ORDERS][Tactics_Fighter][Neutral]}, { "MaxVelocityBonus[ATTACK_ORDERS][Tactics_Fighter][Aggressive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[ATTACK_ORDERS][Tactics_Fighter][Aggressive]}, { "MaxVelocityBonus[ATTACK_ORDERS_ENEMY][Tactics_Fighter][Evasive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[ATTACK_ORDERS_ENEMY][Tactics_Fighter][Evasive]}, { "MaxVelocityBonus[ATTACK_ORDERS_ENEMY][Tactics_Fighter][Neutral]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[ATTACK_ORDERS_ENEMY][Tactics_Fighter][Neutral]}, { "MaxVelocityBonus[ATTACK_ORDERS_ENEMY][Tactics_Fighter][Aggressive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[ATTACK_ORDERS_ENEMY][Tactics_Fighter][Aggressive]}, { "DamageBonus[Tactics_Fighter][Evasive]", scriptSetReal32CB, &tacticsInfo.DamageBonus[Tactics_Fighter][Evasive]}, { "DamageBonus[Tactics_Fighter][Neutral]", scriptSetReal32CB, &tacticsInfo.DamageBonus[Tactics_Fighter][Neutral]}, { "DamageBonus[Tactics_Fighter][Aggressive]", scriptSetReal32CB, &tacticsInfo.DamageBonus[Tactics_Fighter][Aggressive]}, { "BulletRangeBonus[Tactics_Fighter][Evasive]", scriptSetReal32CB, &tacticsInfo.BulletRangeBonus[Tactics_Fighter][Evasive]}, { "BulletRangeBonus[Tactics_Fighter][Neutral]", scriptSetReal32CB, &tacticsInfo.BulletRangeBonus[Tactics_Fighter][Neutral]}, { "BulletRangeBonus[Tactics_Fighter][Aggressive]", scriptSetReal32CB, &tacticsInfo.BulletRangeBonus[Tactics_Fighter][Aggressive]}, { "BulletSpeedBonus[Tactics_Fighter][Evasive]", scriptSetReal32CB, &tacticsInfo.BulletSpeedBonus[Tactics_Fighter][Evasive]}, { "BulletSpeedBonus[Tactics_Fighter][Neutral]", scriptSetReal32CB, &tacticsInfo.BulletSpeedBonus[Tactics_Fighter][Neutral]}, { "BulletSpeedBonus[Tactics_Fighter][Aggressive]", scriptSetReal32CB, &tacticsInfo.BulletSpeedBonus[Tactics_Fighter][Aggressive]}, { "MaxVelocityBonus[NO_ORDER_NO_ENEMY][Tactics_Corvette][Evasive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[NO_ORDER_NO_ENEMY][Tactics_Corvette][Evasive]}, { "MaxVelocityBonus[NO_ORDER_NO_ENEMY][Tactics_Corvette][Neutral]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[NO_ORDER_NO_ENEMY][Tactics_Corvette][Neutral]}, { "MaxVelocityBonus[NO_ORDER_NO_ENEMY][Tactics_Corvette][Aggressive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[NO_ORDER_NO_ENEMY][Tactics_Corvette][Aggressive]}, { "MaxVelocityBonus[NO_ORDER_ENEMY][Tactics_Corvette][Evasive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[NO_ORDER_ENEMY][Tactics_Corvette][Evasive]}, { "MaxVelocityBonus[NO_ORDER_ENEMY][Tactics_Corvette][Neutral]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[NO_ORDER_ENEMY][Tactics_Corvette][Neutral]}, { "MaxVelocityBonus[NO_ORDER_ENEMY][Tactics_Corvette][Aggressive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[NO_ORDER_ENEMY][Tactics_Corvette][Aggressive]}, { "MaxVelocityBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Corvette][Evasive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Corvette][Evasive]}, { "MaxVelocityBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Corvette][Neutral]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Corvette][Neutral]}, { "MaxVelocityBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Corvette][Aggressive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Corvette][Aggressive]}, { "MaxVelocityBonus[MOVE_ORDERS_ENEMY][Tactics_Corvette][Evasive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[MOVE_ORDERS_ENEMY][Tactics_Corvette][Evasive]}, { "MaxVelocityBonus[MOVE_ORDERS_ENEMY][Tactics_Corvette][Neutral]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[MOVE_ORDERS_ENEMY][Tactics_Corvette][Neutral]}, { "MaxVelocityBonus[MOVE_ORDERS_ENEMY][Tactics_Corvette][Aggressive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[MOVE_ORDERS_ENEMY][Tactics_Corvette][Aggressive]}, { "MaxVelocityBonus[ATTACK_ORDERS][Tactics_Corvette][Evasive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[ATTACK_ORDERS][Tactics_Corvette][Evasive]}, { "MaxVelocityBonus[ATTACK_ORDERS][Tactics_Corvette][Neutral]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[ATTACK_ORDERS][Tactics_Corvette][Neutral]}, { "MaxVelocityBonus[ATTACK_ORDERS][Tactics_Corvette][Aggressive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[ATTACK_ORDERS][Tactics_Corvette][Aggressive]}, { "MaxVelocityBonus[ATTACK_ORDERS_ENEMY][Tactics_Corvette][Evasive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[ATTACK_ORDERS_ENEMY][Tactics_Corvette][Evasive]}, { "MaxVelocityBonus[ATTACK_ORDERS_ENEMY][Tactics_Corvette][Neutral]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[ATTACK_ORDERS_ENEMY][Tactics_Corvette][Neutral]}, { "MaxVelocityBonus[ATTACK_ORDERS_ENEMY][Tactics_Corvette][Aggressive]", scriptSetReal32CB, &tacticsInfo.MaxVelocityBonus[ATTACK_ORDERS_ENEMY][Tactics_Corvette][Aggressive]}, { "DamageBonus[Tactics_Corvette][Evasive]", scriptSetReal32CB, &tacticsInfo.DamageBonus[Tactics_Corvette][Evasive]}, { "DamageBonus[Tactics_Corvette][Neutral]", scriptSetReal32CB, &tacticsInfo.DamageBonus[Tactics_Corvette][Neutral]}, { "DamageBonus[Tactics_Corvette][Aggressive]", scriptSetReal32CB, &tacticsInfo.DamageBonus[Tactics_Corvette][Aggressive]}, { "BulletRangeBonus[Tactics_Corvette][Evasive]", scriptSetReal32CB, &tacticsInfo.BulletRangeBonus[Tactics_Corvette][Evasive]}, { "BulletRangeBonus[Tactics_Corvette][Neutral]", scriptSetReal32CB, &tacticsInfo.BulletRangeBonus[Tactics_Corvette][Neutral]}, { "BulletRangeBonus[Tactics_Corvette][Aggressive]", scriptSetReal32CB, &tacticsInfo.BulletRangeBonus[Tactics_Corvette][Aggressive]}, { "BulletSpeedBonus[Tactics_Corvette][Evasive]", scriptSetReal32CB, &tacticsInfo.BulletSpeedBonus[Tactics_Corvette][Evasive]}, { "BulletSpeedBonus[Tactics_Corvette][Neutral]", scriptSetReal32CB, &tacticsInfo.BulletSpeedBonus[Tactics_Corvette][Neutral]}, { "BulletSpeedBonus[Tactics_Corvette][Aggressive]", scriptSetReal32CB, &tacticsInfo.BulletSpeedBonus[Tactics_Corvette][Aggressive]}, { "FuelBurnBonus[NO_ORDER_NO_ENEMY][Tactics_Corvette][Evasive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[NO_ORDER_NO_ENEMY][Tactics_Corvette][Evasive]}, { "FuelBurnBonus[NO_ORDER_NO_ENEMY][Tactics_Corvette][Neutral]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[NO_ORDER_NO_ENEMY][Tactics_Corvette][Neutral]}, { "FuelBurnBonus[NO_ORDER_NO_ENEMY][Tactics_Corvette][Aggressive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[NO_ORDER_NO_ENEMY][Tactics_Corvette][Aggressive]}, { "FuelBurnBonus[NO_ORDER_ENEMY][Tactics_Corvette][Evasive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[NO_ORDER_ENEMY][Tactics_Corvette][Evasive]}, { "FuelBurnBonus[NO_ORDER_ENEMY][Tactics_Corvette][Neutral]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[NO_ORDER_ENEMY][Tactics_Corvette][Neutral]}, { "FuelBurnBonus[NO_ORDER_ENEMY][Tactics_Corvette][Aggressive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[NO_ORDER_ENEMY][Tactics_Corvette][Aggressive]}, { "FuelBurnBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Corvette][Evasive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Corvette][Evasive]}, { "FuelBurnBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Corvette][Neutral]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Corvette][Neutral]}, { "FuelBurnBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Corvette][Aggressive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Corvette][Aggressive]}, { "FuelBurnBonus[MOVE_ORDERS_ENEMY][Tactics_Corvette][Evasive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[MOVE_ORDERS_ENEMY][Tactics_Corvette][Evasive]}, { "FuelBurnBonus[MOVE_ORDERS_ENEMY][Tactics_Corvette][Neutral]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[MOVE_ORDERS_ENEMY][Tactics_Corvette][Neutral]}, { "FuelBurnBonus[MOVE_ORDERS_ENEMY][Tactics_Corvette][Aggressive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[MOVE_ORDERS_ENEMY][Tactics_Corvette][Aggressive]}, { "FuelBurnBonus[ATTACK_ORDERS][Tactics_Corvette][Evasive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[ATTACK_ORDERS][Tactics_Corvette][Evasive]}, { "FuelBurnBonus[ATTACK_ORDERS][Tactics_Corvette][Neutral]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[ATTACK_ORDERS][Tactics_Corvette][Neutral]}, { "FuelBurnBonus[ATTACK_ORDERS][Tactics_Corvette][Aggressive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[ATTACK_ORDERS][Tactics_Corvette][Aggressive]}, { "FuelBurnBonus[ATTACK_ORDERS_ENEMY][Tactics_Corvette][Evasive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[ATTACK_ORDERS_ENEMY][Tactics_Corvette][Evasive]}, { "FuelBurnBonus[ATTACK_ORDERS_ENEMY][Tactics_Corvette][Neutral]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[ATTACK_ORDERS_ENEMY][Tactics_Corvette][Neutral]}, { "FuelBurnBonus[ATTACK_ORDERS_ENEMY][Tactics_Corvette][Aggressive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[ATTACK_ORDERS_ENEMY][Tactics_Corvette][Aggressive]}, { "FuelBurnBonus[NO_ORDER_NO_ENEMY][Tactics_Fighter][Evasive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[NO_ORDER_NO_ENEMY][Tactics_Fighter][Evasive]}, { "FuelBurnBonus[NO_ORDER_NO_ENEMY][Tactics_Fighter][Neutral]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[NO_ORDER_NO_ENEMY][Tactics_Fighter][Neutral]}, { "FuelBurnBonus[NO_ORDER_NO_ENEMY][Tactics_Fighter][Aggressive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[NO_ORDER_NO_ENEMY][Tactics_Fighter][Aggressive]}, { "FuelBurnBonus[NO_ORDER_ENEMY][Tactics_Fighter][Evasive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[NO_ORDER_ENEMY][Tactics_Fighter][Evasive]}, { "FuelBurnBonus[NO_ORDER_ENEMY][Tactics_Fighter][Neutral]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[NO_ORDER_ENEMY][Tactics_Fighter][Neutral]}, { "FuelBurnBonus[NO_ORDER_ENEMY][Tactics_Fighter][Aggressive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[NO_ORDER_ENEMY][Tactics_Fighter][Aggressive]}, { "FuelBurnBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Fighter][Evasive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Fighter][Evasive]}, { "FuelBurnBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Fighter][Neutral]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Fighter][Neutral]}, { "FuelBurnBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Fighter][Aggressive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Fighter][Aggressive]}, { "FuelBurnBonus[MOVE_ORDERS_ENEMY][Tactics_Fighter][Evasive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[MOVE_ORDERS_ENEMY][Tactics_Fighter][Evasive]}, { "FuelBurnBonus[MOVE_ORDERS_ENEMY][Tactics_Fighter][Neutral]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[MOVE_ORDERS_ENEMY][Tactics_Fighter][Neutral]}, { "FuelBurnBonus[MOVE_ORDERS_ENEMY][Tactics_Fighter][Aggressive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[MOVE_ORDERS_ENEMY][Tactics_Fighter][Aggressive]}, { "FuelBurnBonus[ATTACK_ORDERS][Tactics_Fighter][Evasive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[ATTACK_ORDERS][Tactics_Fighter][Evasive]}, { "FuelBurnBonus[ATTACK_ORDERS][Tactics_Fighter][Neutral]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[ATTACK_ORDERS][Tactics_Fighter][Neutral]}, { "FuelBurnBonus[ATTACK_ORDERS][Tactics_Fighter][Aggressive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[ATTACK_ORDERS][Tactics_Fighter][Aggressive]}, { "FuelBurnBonus[ATTACK_ORDERS_ENEMY][Tactics_Fighter][Evasive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[ATTACK_ORDERS_ENEMY][Tactics_Fighter][Evasive]}, { "FuelBurnBonus[ATTACK_ORDERS_ENEMY][Tactics_Fighter][Neutral]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[ATTACK_ORDERS_ENEMY][Tactics_Fighter][Neutral]}, { "FuelBurnBonus[ATTACK_ORDERS_ENEMY][Tactics_Fighter][Aggressive]", scriptSetReal32CB, &tacticsInfo.FuelBurnBonus[ATTACK_ORDERS_ENEMY][Tactics_Fighter][Aggressive]}, { "ManeuvBonus[NO_ORDER_NO_ENEMY][Tactics_Corvette][Evasive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[NO_ORDER_NO_ENEMY][Tactics_Corvette][Evasive]}, { "ManeuvBonus[NO_ORDER_NO_ENEMY][Tactics_Corvette][Neutral]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[NO_ORDER_NO_ENEMY][Tactics_Corvette][Neutral]}, { "ManeuvBonus[NO_ORDER_NO_ENEMY][Tactics_Corvette][Aggressive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[NO_ORDER_NO_ENEMY][Tactics_Corvette][Aggressive]}, { "ManeuvBonus[NO_ORDER_ENEMY][Tactics_Corvette][Evasive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[NO_ORDER_ENEMY][Tactics_Corvette][Evasive]}, { "ManeuvBonus[NO_ORDER_ENEMY][Tactics_Corvette][Neutral]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[NO_ORDER_ENEMY][Tactics_Corvette][Neutral]}, { "ManeuvBonus[NO_ORDER_ENEMY][Tactics_Corvette][Aggressive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[NO_ORDER_ENEMY][Tactics_Corvette][Aggressive]}, { "ManeuvBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Corvette][Evasive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Corvette][Evasive]}, { "ManeuvBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Corvette][Neutral]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Corvette][Neutral]}, { "ManeuvBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Corvette][Aggressive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Corvette][Aggressive]}, { "ManeuvBonus[MOVE_ORDERS_ENEMY][Tactics_Corvette][Evasive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[MOVE_ORDERS_ENEMY][Tactics_Corvette][Evasive]}, { "ManeuvBonus[MOVE_ORDERS_ENEMY][Tactics_Corvette][Neutral]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[MOVE_ORDERS_ENEMY][Tactics_Corvette][Neutral]}, { "ManeuvBonus[MOVE_ORDERS_ENEMY][Tactics_Corvette][Aggressive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[MOVE_ORDERS_ENEMY][Tactics_Corvette][Aggressive]}, { "ManeuvBonus[ATTACK_ORDERS][Tactics_Corvette][Evasive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[ATTACK_ORDERS][Tactics_Corvette][Evasive]}, { "ManeuvBonus[ATTACK_ORDERS][Tactics_Corvette][Neutral]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[ATTACK_ORDERS][Tactics_Corvette][Neutral]}, { "ManeuvBonus[ATTACK_ORDERS][Tactics_Corvette][Aggressive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[ATTACK_ORDERS][Tactics_Corvette][Aggressive]}, { "ManeuvBonus[ATTACK_ORDERS_ENEMY][Tactics_Corvette][Evasive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[ATTACK_ORDERS_ENEMY][Tactics_Corvette][Evasive]}, { "ManeuvBonus[ATTACK_ORDERS_ENEMY][Tactics_Corvette][Neutral]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[ATTACK_ORDERS_ENEMY][Tactics_Corvette][Neutral]}, { "ManeuvBonus[ATTACK_ORDERS_ENEMY][Tactics_Corvette][Aggressive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[ATTACK_ORDERS_ENEMY][Tactics_Corvette][Aggressive]}, { "ManeuvBonus[NO_ORDER_NO_ENEMY][Tactics_Fighter][Evasive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[NO_ORDER_NO_ENEMY][Tactics_Fighter][Evasive]}, { "ManeuvBonus[NO_ORDER_NO_ENEMY][Tactics_Fighter][Neutral]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[NO_ORDER_NO_ENEMY][Tactics_Fighter][Neutral]}, { "ManeuvBonus[NO_ORDER_NO_ENEMY][Tactics_Fighter][Aggressive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[NO_ORDER_NO_ENEMY][Tactics_Fighter][Aggressive]}, { "ManeuvBonus[NO_ORDER_ENEMY][Tactics_Fighter][Evasive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[NO_ORDER_ENEMY][Tactics_Fighter][Evasive]}, { "ManeuvBonus[NO_ORDER_ENEMY][Tactics_Fighter][Neutral]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[NO_ORDER_ENEMY][Tactics_Fighter][Neutral]}, { "ManeuvBonus[NO_ORDER_ENEMY][Tactics_Fighter][Aggressive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[NO_ORDER_ENEMY][Tactics_Fighter][Aggressive]}, { "ManeuvBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Fighter][Evasive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Fighter][Evasive]}, { "ManeuvBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Fighter][Neutral]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Fighter][Neutral]}, { "ManeuvBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Fighter][Aggressive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[MOVE_ORDERS_NO_ENEMY][Tactics_Fighter][Aggressive]}, { "ManeuvBonus[MOVE_ORDERS_ENEMY][Tactics_Fighter][Evasive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[MOVE_ORDERS_ENEMY][Tactics_Fighter][Evasive]}, { "ManeuvBonus[MOVE_ORDERS_ENEMY][Tactics_Fighter][Neutral]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[MOVE_ORDERS_ENEMY][Tactics_Fighter][Neutral]}, { "ManeuvBonus[MOVE_ORDERS_ENEMY][Tactics_Fighter][Aggressive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[MOVE_ORDERS_ENEMY][Tactics_Fighter][Aggressive]}, { "ManeuvBonus[ATTACK_ORDERS][Tactics_Fighter][Evasive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[ATTACK_ORDERS][Tactics_Fighter][Evasive]}, { "ManeuvBonus[ATTACK_ORDERS][Tactics_Fighter][Neutral]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[ATTACK_ORDERS][Tactics_Fighter][Neutral]}, { "ManeuvBonus[ATTACK_ORDERS][Tactics_Fighter][Aggressive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[ATTACK_ORDERS][Tactics_Fighter][Aggressive]}, { "ManeuvBonus[ATTACK_ORDERS_ENEMY][Tactics_Fighter][Evasive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[ATTACK_ORDERS_ENEMY][Tactics_Fighter][Evasive]}, { "ManeuvBonus[ATTACK_ORDERS_ENEMY][Tactics_Fighter][Neutral]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[ATTACK_ORDERS_ENEMY][Tactics_Fighter][Neutral]}, { "ManeuvBonus[ATTACK_ORDERS_ENEMY][Tactics_Fighter][Aggressive]", scriptSetReal32CB, &tacticsInfo.ManeuvBonus[ATTACK_ORDERS_ENEMY][Tactics_Fighter][Aggressive]}, { "tacticsGuardReturnToGuardingDistance", scriptSetReal32CB, &tacticsInfo.tacticsGuardReturnToGuardingDistance}, { "tacticsGuardConditionCheckRate", scriptSetReal32CB, &tacticsInfo.tacticsGuardConditionCheckRate}, { "tacticsGuardConditionCheckFrame", scriptSetReal32CB, &tacticsInfo.tacticsGuardConditionCheckFrame}, { "kamikazeDamage[AttackBomber]", scriptSetReal32CB, &kamikazeDamage[AttackBomber]}, { "kamikazeDamage[CloakedFighter]", scriptSetReal32CB, &kamikazeDamage[CloakedFighter]}, { "kamikazeDamage[DefenseFighter]", scriptSetReal32CB, &kamikazeDamage[DefenseFighter]}, { "kamikazeDamage[HeavyCorvette]", scriptSetReal32CB, &kamikazeDamage[HeavyCorvette]}, { "kamikazeDamage[HeavyDefender]", scriptSetReal32CB, &kamikazeDamage[HeavyDefender]}, { "kamikazeDamage[HeavyInterceptor]", scriptSetReal32CB, &kamikazeDamage[HeavyInterceptor]}, { "kamikazeDamage[LightCorvette]", scriptSetReal32CB, &kamikazeDamage[LightCorvette]}, { "kamikazeDamage[LightDefender]", scriptSetReal32CB, &kamikazeDamage[LightDefender]}, { "kamikazeDamage[LightInterceptor]", scriptSetReal32CB, &kamikazeDamage[LightInterceptor]}, { "kamikazeDamage[MinelayerCorvette]", scriptSetReal32CB, &kamikazeDamage[MinelayerCorvette]}, { "kamikazeDamage[MultiGunCorvette]", scriptSetReal32CB, &kamikazeDamage[MultiGunCorvette]}, { "kamikazeDamage[RepairCorvette]", scriptSetReal32CB, &kamikazeDamage[RepairCorvette]}, { "kamikazeDamage[ResourceCollector]", scriptSetReal32CB, &kamikazeDamage[ResourceCollector]}, { "kamikazeDamage[SalCapCorvette]", scriptSetReal32CB, &kamikazeDamage[SalCapCorvette]}, { "kamikazeDamage[P1Fighter]", scriptSetReal32CB, &kamikazeDamage[P1Fighter]}, { "kamikazeDamage[P2AdvanceSwarmer]", scriptSetReal32CB, &kamikazeDamage[P2AdvanceSwarmer]}, { "kamikazeDamage[P2FuelPod]", scriptSetReal32CB, &kamikazeDamage[P2FuelPod]}, { "kamikazeDamage[P2Swarmer]", scriptSetReal32CB, &kamikazeDamage[P2Swarmer]}, { "kamikazeSpeedBurst", scriptSetReal32CB, &kamikazeSpeedBurst}, { "kamikazeFuelBurnMult", scriptSetReal32CB, &kamikazeFuelBurnMult}, { "speedBurstMaxVelocityMultiplier", scriptSetReal32CB, &speedBurstMaxVelocityMultiplier}, { "speedBurstThrustMult", scriptSetReal32CB, &speedBurstThrustMult}, { "speedBurstDuration", scriptSetReal32CB, &speedBurstDuration}, { "speedBurstFuelBurnMult", scriptSetReal32CB, &speedBurstFuelBurnMult}, { "speedBurstCoolDown", scriptSetReal32CB, &speedBurstCoolDown}, { "burstRange", scriptSetReal32CB, &burstRange}, { "burstChargeTime", scriptSetReal32CB, &burstChargeTime}, { "burstCoolDownTime", scriptSetReal32CB, &burstCoolDownTime}, { "burstDamageLo[R1]", scriptSetReal32CB, &burstDamageLo[R1]}, { "burstDamageHi[R1]", scriptSetReal32CB, &burstDamageHi[R1]}, { "burstDamageLo[R2]", scriptSetReal32CB, &burstDamageLo[R2]}, { "burstDamageHi[R2]", scriptSetReal32CB, &burstDamageHi[R2]}, { "burstSpeed", scriptSetReal32CB, &burstSpeed}, { "burstRadius", scriptSetReal32CB, &burstRadius}, { "holdFormationDuringBattle[Evasive]", scriptSetSdwordCB, &tacticsInfo.holdFormationDuringBattle[Evasive]}, { "holdFormationDuringBattle[Neutral]", scriptSetSdwordCB, &tacticsInfo.holdFormationDuringBattle[Neutral]}, { "holdFormationDuringBattle[Aggressive]", scriptSetSdwordCB, &tacticsInfo.holdFormationDuringBattle[Aggressive]}, { "tacticsBurstFireTimeModifier[Evasive]", scriptSetReal32CB, &tacticsInfo.tacticsBurstFireTimeModifier[Evasive]}, { "tacticsBurstFireTimeModifier[Neutral]", scriptSetReal32CB, &tacticsInfo.tacticsBurstFireTimeModifier[Neutral]}, { "tacticsBurstFireTimeModifier[Aggressive]", scriptSetReal32CB, &tacticsInfo.tacticsBurstFireTimeModifier[Aggressive]}, { "tacticsBurstWaitTimeModifier[Evasive]", scriptSetReal32CB, &tacticsInfo.tacticsBurstWaitTimeModifier[Evasive]}, { "tacticsBurstWaitTimeModifier[Neutral]", scriptSetReal32CB, &tacticsInfo.tacticsBurstWaitTimeModifier[Neutral]}, { "tacticsBurstWaitTimeModifier[Aggressive]", scriptSetReal32CB, &tacticsInfo.tacticsBurstWaitTimeModifier[Aggressive]}, { "tacticsBurstFireTimeSphereModifier", scriptSetReal32CB, &tacticsInfo.tacticsBurstFireTimeSphereModifier}, { "tacticsBurstWaitTimeSphereModifier", scriptSetReal32CB, &tacticsInfo.tacticsBurstWaitTimeSphereModifier}, { "tacticsBurstFireTimeWingmanModifier", scriptSetReal32CB, &tacticsInfo.tacticsBurstFireTimeWingmanModifier}, { "tacticsBurstWaitTimeWingmanModifier", scriptSetReal32CB, &tacticsInfo.tacticsBurstWaitTimeWingmanModifier}, { "tacticsDamageMultiplierInFormation", scriptSetReal32CB, &tacticsInfo.tacticsDamageMultiplierInFormation}, { "tacticsDamageMultiplierInSphereFormation", scriptSetReal32CB, &tacticsInfo.tacticsDamageMultiplierInSphereFormation}, { "movingAttackTurnsIntoMoveCommandDistance", scriptSetReal32SqrCB, &tacticsInfo.movingAttackTurnsIntoMoveCommandDistanceSqr}, { "tacticsDamageModifierRed", scriptSetReal32CB, &tacticsInfo.tacticsDamageModifierRed}, { "tacticsDamageModifierYellow", scriptSetReal32CB, &tacticsInfo.tacticsDamageModifierYellow}, makeEntry(OUT_OF_FUEL_VELOCITY_SLOWDOWN,scriptSetReal32CB), makeEntry(IONCANNON_TARGETS_FIGHTER_ANGLE,scriptSetCosAngCB), makeEntry(IONCANNON_TARGETS_CORVETTE_ANGLE,scriptSetCosAngCB), makeEntry(IONCANNON_TARGETS_FIGHTER_TRIGGERHAPPY,scriptSetCosAngCB), makeEntry(IONCANNON_TARGETS_CORVETTE_TRIGGERHAPPY,scriptSetCosAngCB), makeEntry(IONCANNON_TARGETS_FIGHTER_MAXANGLESPEED,scriptSetAngCB), makeEntry(IONCANNON_TARGETS_CORVETTE_MAXANGLESPEED,scriptSetAngCB), makeEntry(GLOBAL_SHIP_SPEED_MODIFIER,scriptSetReal32CB), makeEntry(DELAY_FORMTIGHTNESS_CHANGE,scriptSetReal32CB), endEntry }; void tacticsStartUp() { sdword x,y,z; tacticsInfo.MenuFeedBack_X = 0; tacticsInfo.MenuFeedBack_Y = 0; tacticsInfo.EnemyNearZone = 0; for(x=0;x< NUM_TACTICS_SITUATIONS;x++) for(y=0;y< NUM_TACTICS_APPLICABLE;y++) for(z=0;z< NUM_TACTICS_TYPES;z++) tacticsInfo.MaxVelocityBonus[x][y][z] = 1.0f; for(x=0;x< NUM_TACTICS_SITUATIONS;x++) for(y=0;y< NUM_TACTICS_APPLICABLE;y++) for(z=0;z< NUM_TACTICS_TYPES;z++) tacticsInfo.FuelBurnBonus[x][y][z] = 1.0f; for(x=0;x< NUM_TACTICS_SITUATIONS;x++) for(y=0;y< NUM_TACTICS_APPLICABLE;y++) for(z=0;z< NUM_TACTICS_TYPES;z++) tacticsInfo.ManeuvBonus[x][y][z] = 1.0f; for(x=0;x< NUM_DODGE_INFO;x++) for(y=0;y< TOTAL_NUM_SHIPS;y++) tacticsInfo.DodgeInfo[x][y] = 0.0f; for(x=0;x< NUM_FORMATION_PADDINGS;x++) tacticsInfo.formationPadding[x] = 1.0f; for(x=0;x< NUM_TACTICS_APPLICABLE;x++) for(y=0;y< NUM_TACTICS_TYPES;y++) { tacticsInfo.DamageBonus[x][y] = 1.0f; tacticsInfo.BulletRangeBonus[x][y] = 1.0f; tacticsInfo.BulletSpeedBonus[x][y] = 1.0f; } #ifdef DEBUG_TACTICS if(!tacticsOn) return; #endif scriptSet(NULL,"Tactics.script",TacticsInfotable); //precalculate certain variables tacticsInfo.tacticsGuardReturnToGuardingDistanceSqr = tacticsInfo.tacticsGuardReturnToGuardingDistance*tacticsInfo.tacticsGuardReturnToGuardingDistance; oneOverburstSpeed = 1.0f/burstSpeed; tacticsFlashMenuBaby = NULL; tacticsMenuRegion = NULL; listInit(&universe.RetreatList); listInit(&universe.AttackMemory); } void tacticsShutDown() { if(tacticsFlashMenuBaby != NULL) { taskCallBackRemove(tacticsFlashMenuBaby); tacticsFlashMenuBaby = NULL; } if(tacticsMenuRegion != NULL) { feMenuDisappear(NULL,NULL); tacticsMenuRegion = NULL; } listDeleteAll(&universe.RetreatList); listDeleteAll(&universe.AttackMemory); } extern regionhandle ghMainRegion; bool tacticsDeleteMenu(udword num, void *data, struct BabyCallBack *baby) { #ifdef DEBUG_TACTICS dbgAssert(tacticsOn); #endif if(tacticsMenuRegion != NULL) { //only remove menu if it is up... feMenuDisappear(NULL,NULL); } tacticsFlashMenuBaby = NULL; return(TRUE); } void tacticsPopUpSetUp(TacticsType tacticstype) { fescreen *TacticsScreen = feScreenFind("Group_Tactics_submenu"); regionhandle regionptr; featom *babyspice, *atom; sdword index; #ifdef DEBUG_TACTICS if(!tacticsOn) return; #endif if(TacticsScreen == NULL) { dbgFatalf(DBG_Loc, "\nCouldn't find menu item for tactics craptics"); } //set the correct checked bit for tactics for (index = 0; index < TacticsScreen->nAtoms; index++) { //clear all atoms of the selected bit bitClear(TacticsScreen->atoms[index].status, FAS_Checked); } atom = feAtomFindInScreen(TacticsScreen, mrMenuItemByTactic[tacticstype]); dbgAssert(atom != NULL); bitSet(atom->status, FAS_Checked); if(tacticsFlashMenuBaby != NULL) { taskCallBackRemove(tacticsFlashMenuBaby); if(tacticsMenuRegion != NULL) { feMenuDisappear(NULL,NULL); tacticsMenuRegion = NULL; } tacticsFlashMenuBaby = NULL; } //store this pointer to set another pointer to delete it later...:) tacticsMenuRegion = feMenuStart(ghMainRegion,TacticsScreen, mouseCursorX(), mouseCursorY()); //disable proccessing functions regionptr = tacticsMenuRegion->child; while(regionptr != NULL) { babyspice = (featom *) regionptr->userID; regionptr->processFunction = ®NULLProcessFunction; regionptr = regionptr->next; } tacticsFlashMenuBaby = taskCallBackRegister(tacticsDeleteMenu, 0, NULL, tacticsInfo.menuPopupTime); /* switch(tacticstype) { case Evasive: break; case Neutral: break; case Aggressive: break; default: dbgAssert(FALSE); } */ } /*********************************************************************************************/ // tacticsSetSelectionToTactics(SelectCommand *selection,sdword order_type) // // Changes selections tactics_order type to order_type /********************************************************************************************/ void tacticsSetSelectionToTactics(SelectCommand *selection,udword orderFlag) { sdword i; switch(orderFlag) { case ORDER_TYPE_MOVE_ORDERS: break; } for(i=0;inumShips;i++) { selection->ShipPtr[i]->tactics_ordertype = orderFlag; } } void tacticsSetShipToDoDodge(Ship *ship) { #ifdef DEBUG_TACTICS dbgAssert(tacticsOn); #endif if(tacticsShipCanDodge(ship)) { CommandToDo *command = getShipAndItsCommand(&universe.mainCommandLayer,ship); if (command != NULL) { if(ship->shiptype == SalCapCorvette) { { if(command->ordertype.order == COMMAND_SPECIAL || command->ordertype.order == COMMAND_DOCK) { //don't let salcap dodge if this is the case return; } } } } if(ship->dockingship != NULL) { //don't dock if in this stage of docking! return; } if (ship->flags & SOF_Cloaked) { return; // cloaked ships don't dodge! } if (ship->specialFlags & SPECIAL_Kamikaze) { return; // kamikaze ships don't dodge! } if(ship->tacticstype != Evasive) { CommandToDo *command=getShipAndItsCommand(&universe.mainCommandLayer,ship); if(ship->shiptype != HeavyDefender) { if(command != NULL) { if(command->ordertype.attributes & COMMAND_IS_FORMATION) { //ship is in sphere..but is the sphere formed? if(command->formation.formationtype == SPHERE_FORMATION) { //as long as we aren't evassive, we shouldn't dodge return; } } } } } if(ship->isDodging == TRUE) { return; } else { //ship isn't currently dodging if(universe.totaltimeelapsed < ship->DodgeTime) return; //ship hasn't cooled down from dodge yet } if(ship->flightman != FLIGHTMAN_NULL) { //ship is performing a flightmaneuver...don't dodge if(ship->flightman != FLIGHTMAN_BARREL_ROLL) return; } ship->isDodging = TRUE; ship->DodgeTime = universe.totaltimeelapsed + tacticsInfo.DodgeInfo[DODGE_ONE_TIME][ship->staticinfo->shiptype]; ship->DodgeDir = (uword) randombetween(0,TRANS_LEFT); ship->DodgeFlag = 0; } } void tacticsDoDodge(Ship *ship) { ShipStaticInfo *shipstaticinfo=ship->staticinfo; #ifdef DEBUG_TACTICS dbgAssert(tacticsOn); #endif physApplyForceToObj((SpaceObj *)ship,ship->staticinfo->thruststrengthstat[ship->DodgeDir]*tacticsInfo.DodgeInfo[DODGE_THRUST_MULT][ship->staticinfo->shiptype],ship->DodgeDir); if(universe.totaltimeelapsed > ship->DodgeTime) { //dodge time elapsed...stop dodging if(ship->DodgeFlag == 1) { ship->isDodging = FALSE; ship->DodgeTime = universe.totaltimeelapsed + tacticsInfo.DodgeInfo[DODGE_WAIT][ship->staticinfo->shiptype]+frandombetween(tacticsInfo.DodgeLowAddTime,tacticsInfo.DodgeHighAddTime); return; } switch(ship->DodgeDir) { //toggle dodge direction to oposite way case TRANS_UP: ship->DodgeDir = TRANS_DOWN; break; case TRANS_DOWN: ship->DodgeDir = TRANS_UP; break; case TRANS_RIGHT: ship->DodgeDir = TRANS_LEFT; break; case TRANS_LEFT: ship->DodgeDir = TRANS_RIGHT; break; case TRANS_FORWARD: ship->DodgeDir = TRANS_BACKWARD; break; case TRANS_BACKWARD: ship->DodgeDir = TRANS_FORWARD; break; } ship->DodgeTime = universe.totaltimeelapsed + tacticsInfo.DodgeInfo[DODGE_TWO_TIME][ship->staticinfo->shiptype]; ship->DodgeFlag = 1; } } bool tacticsShipCanDodge(Ship *ship) { #ifdef DEBUG_TACTICS dbgAssert(tacticsOn); #endif if(tacticsInfo.DodgeInfo[DODGE_ONE_TIME][ship->staticinfo->shiptype] == 0.0f) { //ship has dodging turned off return FALSE; } if(ship->staticinfo->maxfuel != 0.0f) { //ship has fuel///lkets check it if(ship->fuel <= 0.0f) { //out of fuel...can't dodge return FALSE; } } return(tacticsShipIsAffectedByTactcis(ship)); } bool tacticsShipIsAffectedByTactcis(Ship *ship) { #ifdef DEBUG_TACTICS dbgAssert(tacticsOn); #endif if(ship->staticinfo->shipclass == CLASS_Fighter || ship->staticinfo->shipclass == CLASS_Corvette) { return(TRUE); } return(FALSE); } /******************************************************************************************* sdword tacticsGetFormationOptimalState(SelectCommand *selection); returns a type (formationLoose or formationTight) depending on rules for formation formation :) if any agressive pressent, go tight. That way slowest setting will not screw up formation **********************************************************************************************/ sdword tacticsGetFormationOptimalState(SelectCommand *selection) { sdword i; //sdword cA,cN,cE; //counters for different tactics settings in formation TacticsType grouptactics = selection->ShipPtr[0]->tacticstype; #ifdef DEBUG_TACTICS dbgAssert(tacticsOn); #endif //base formation on leaders tactical settings if(grouptactics != Aggressive) { //check ships for evvasive and neutral settings for(i=0;inumShips;i++) { //if non-strike craft in formation, maintain tight formation if(!tacticsShipIsAffectedByTactcis(selection->ShipPtr[i])) return(TightFormation); //for now, loose formations ONLY if ALL evasive...later we'll fix // if(selection->ShipPtr[i]->tacticstype == Aggressive || // selection->ShipPtr[i]->tacticstype == Neutral) // return(TightFormation); switch(selection->ShipPtr[i]->tactics_ordertype) { case MOVE_ORDERS_NO_ENEMY: case NO_ORDER_NO_ENEMY: //no enemy near this ship, so tightness is favourved break; case NO_ORDER_ENEMY: case MOVE_ORDERS_ENEMY: case ATTACK_ORDERS: case ATTACK_ORDERS_ENEMY: //if atleast 1 ship in formation has been told to attack //or is near an enemy, we want loose formations... return(LooseFormation); default: dbgFatalf(DBG_Loc,"\nUnkown tactical order state in ship."); } } } return(TightFormation); } void tacticsBeFairToRetreaters(Ship *ship, SelectCommand *targets) { AttackAtom *attackatom; Node *node; bool flagFreeBe; sdword i,j; node = universe.AttackMemory.head; //fix later: optimize by having a ship flag set whether or not //a ship is on the look out!!!! while(node != NULL) { attackatom = (AttackAtom *)listGetStructOfNode(node); //if a retreat occurred very soon, we won't look for them flagFreeBe = FALSE; if(attackatom->retreatTime > universe.totaltimeelapsed) { for(i=0;iattackerList.numShips;i++) { if(ship == attackatom->attackerList.ShipPtr[i]) { //ship is looking for something for(j=0;jnumShips;j++) { if(targets->ShipPtr[j] == attackatom->retreater) { clRemoveShipFromSelection((SelectCommand *)targets,attackatom->retreater); //fix later...might be able to //goto next node here, can a ship be in multiple attacklists? break; } } } } } nextnode: node = node->next; } } void BreakUpShipsIntoAttackCapable(SelectCommand *selection, MaxSelection *attackSelection, MaxSelection *nonAttackSelection) { sdword i; Ship *ship; for (i=0;inumShips;i++) { ship = selection->ShipPtr[i]; if (isShipAttackCapable(ship)) { attackSelection->ShipPtr[attackSelection->numShips++] = ship; } else { nonAttackSelection->ShipPtr[nonAttackSelection->numShips++] = ship; } } #if 0 // Bryce, this wasn't consistent with the isShipAttackCapable code in shipselect.h, and caused bugs sdword i,j,k; j=k=0; for(i = 0;inumShips;i++) { switch(selection->ShipPtr[i]->staticinfo->shipclass) { case CLASS_HeavyCruiser: case CLASS_Carrier: case CLASS_Destroyer: case CLASS_Frigate: case CLASS_Corvette: case CLASS_Fighter: attackSelection->ShipPtr[j] = selection->ShipPtr[i]; attackSelection->numShips++; j++; break; default: nonAttackSelection->ShipPtr[k] = selection->ShipPtr[k]; nonAttackSelection->numShips++; k++; break; } } #endif } #define SPEECH_RETALIATE_REPEAT 15.0f void tacticsSpeechForRetaliation(Ship *ship) { if(ship->retaliateSpeechTime <= universe.totaltimeelapsed) { if(ship->playerowner == universe.curPlayerPtr) { if(!selAnyHotKeyTest(ship)) { if(ship->retaliateSpeechVar == FALSE) { if (battleCanChatterAtThisTime(BCE_STAT_Grp_AttackRetaliate, ship)) { battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_STAT_Grp_AttackRetaliate, ship, SOUND_EVENT_DEFAULT); ship->retaliateSpeechVar = TRUE; ship->retaliateSpeechTime = universe.totaltimeelapsed + SPEECH_RETALIATE_REPEAT; } } else { if (battleCanChatterAtThisTime(BCE_STAT_Grp_AttackRetaliate_Repeat, ship)) { battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_STAT_Grp_AttackRetaliate_Repeat, ship, SOUND_EVENT_DEFAULT); ship->retaliateSpeechVar = FALSE; ship->retaliateSpeechTime = universe.totaltimeelapsed + SPEECH_RETALIATE_REPEAT; } } } else { if(ship->retaliateSpeechVar == FALSE) { if (battleCanChatterAtThisTime(BCE_STAT_AssGrp_AttackRetaliate, ship)) { battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_STAT_AssGrp_AttackRetaliate, ship, selHotKeyGroupNumberTest(ship)); ship->retaliateSpeechVar = TRUE; ship->retaliateSpeechTime = universe.totaltimeelapsed + SPEECH_RETALIATE_REPEAT; } } else { if (battleCanChatterAtThisTime(BCE_STAT_AssGrp_AttackRetaliate_Repeat, ship)) { battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_STAT_AssGrp_AttackRetaliate_Repeat, ship, selHotKeyGroupNumberTest(ship)); ship->retaliateSpeechVar = FALSE; ship->retaliateSpeechTime = universe.totaltimeelapsed + SPEECH_RETALIATE_REPEAT; } } } } } } void tacticsDelegateAttackCommand(Ship *ship,CommandToDo *command, AttackCommand *attack, bool gettingRocked,bool doingSomething) { //ship is in retreat list...so attack it... // //****************** //should probably delete that attackmemory item...or at least //certain ships from it...will lookinto that //******************************* MaxSelection attackSelection,nonAttackSelection; attackSelection.numShips = 0; nonAttackSelection.numShips = 0; //As long as we're not getting hit right now, we'll //give retreaters a chance to getaway. if(!gettingRocked) { #ifdef DEBUG_TACTICS // dbgMessagef("\nBeing Fair to possible Retreaters."); #endif tacticsBeFairToRetreaters(ship,(SelectCommand *)attack); if(attack->numTargets < 1) return; } //if we're busy, can only passive attack if(doingSomething) { //ship is doing something (moving,docking) //so only passive attack if(command->selection->ShipPtr[0]->tacticstype != Evasive) { if (canChangeOrderToPassiveAttack(command,attack)) { ChangeOrderToPassiveAttack(command,attack); } } return; } //if ships aren't doing something //AND ships are actually 'on the lookout' for some of these target //we'll full on attack those beeyatches...otherwise..we'll go through //normal passive attacking procedures. if(!doingSomething && tacticsIsShipLookingForAnyOfThese(ship,(SelectCommand *)attack) && ship->shiptype != Mothership) // don't want to ChangeOrderToAttack for Mothership { #ifdef DEBUG_TACTICS dbgMessagef("\nAttacking Previous Retreaters"); #endif BreakUpShipsIntoAttackCapable(command->selection,&attackSelection,&nonAttackSelection); if(attackSelection.numShips == command->selection->numShips) { ChangeOrderToAttack(command,attack); } else if(attackSelection.numShips > 0) { RemoveShipsFromDoingStuff(&universe.mainCommandLayer,(SelectCommand *)&nonAttackSelection); dbgAssert(command->selection->numShips > 0); ChangeOrderToAttack(command,attack); } return; } switch(ship->tacticstype) { case Aggressive: //give counter attack order #ifdef DEBUG_TACTICS if(doingSomething) { dbgFatalf(DBG_Loc,"\ndoingsomething == TRUE, allowed to retask to full attack! BAD!"); } #endif if (ship->shiptype == Mothership) { goto neutralstuff; // don't want to ChangeOrderToAttack for Mothership } /* //not needed anymore..ships can't fullout attack during movements,docks if(command->ordertype.order == COMMAND_DOCK) { //ships are docking, so only passive attack... if (canChangeOrderToPassiveAttack(command,attack)) { ChangeOrderToPassiveAttack(command,attack); } break; } */ BreakUpShipsIntoAttackCapable(command->selection,&attackSelection,&nonAttackSelection); if(attackSelection.numShips == command->selection->numShips) { ChangeOrderToAttack(command,attack); } else if(attackSelection.numShips > 0) { RemoveShipsFromDoingStuff(&universe.mainCommandLayer,(SelectCommand *)&nonAttackSelection); dbgAssert(command->selection->numShips > 0); ChangeOrderToAttack(command,attack); } break; case Neutral: neutralstuff: //passive attack if (canChangeOrderToPassiveAttack(command,attack)) { ChangeOrderToPassiveAttack(command,attack); } tacticsSpeechForRetaliation(ship); break; case Evasive: //doc de la design says no passive retaliation at ALL for //evassive tacticized ships //not doing this anymore // if (canChangeOrderToPassiveAttack(command,attack)) // { // ChangeOrderToPassiveAttack(command,attack); // } // tacticsSpeechForRetaliation(ship); break; } } void tacticsDelegateSingleAttack(Ship *ship,CommandLayer *comlayer,SelectCommand *selectone,AttackCommand *attack, bool gettingRocked) { CommandToDo *cmtest; if(!gettingRocked) { #ifdef DEBUG_TACTICS // dbgMessagef("\nBeing Fair to possible Retreaters."); #endif tacticsBeFairToRetreaters(ship,(SelectCommand *)attack); if(attack->numTargets < 1) return; } if(tacticsIsShipLookingForAnyOfThese(ship,(SelectCommand *)attack)) { clAttack(comlayer,selectone,attack); #ifdef DEBUG_TACTICS dbgMessagef("\nAttacking Previous Retreaters"); #endif return; } if(isCapitalShip(ship)) { //capital ships only passive attack if(ship->tacticstype != Evasive) { //don't passive retaliate in evassive clPassiveAttack(comlayer,selectone,attack); } return; } switch(ship->tacticstype) { case Aggressive: //give counter attack order cmtest = getShipAndItsCommand(comlayer,ship); if(cmtest != NULL) { if(cmtest->ordertype.order == COMMAND_DOCK) { //passive attack clPassiveAttack(comlayer,selectone,attack); break; } } clAttack(comlayer,selectone,attack); break; case Neutral: //passive attack clPassiveAttack(comlayer,selectone,attack); tacticsSpeechForRetaliation(ship); break; case Evasive: //don't passive retaliate any more //later don't passive retaliate...simply dodge for now, do it though //clPassiveAttack(comlayer,selectone,attack); //tacticsSpeechForRetaliation(ship); break; } } //name: tacticsRemoveRetreat // //desc: Removes and deletes the retreat order 'r' from the tactics retreat list void tacticsRemoveRetreat(RetreatAtom *r) { listDeleteNode(&r->retreatLink); } //name: tacticsShipIsRetreatingFromThisCommand // //desc: checks to see if this ship is retreating from this command RetreatAtom *tacticsShipIsRetreatingFromThisCommand(Ship *ship, CommandToDo *command) { Node *link; RetreatAtom *r; link = universe.RetreatList.head; while(link != NULL) { r = (RetreatAtom *)listGetStructOfNode(link); if(r->retreater == ship) { //found ship if(r->fleeingfrom == command) { //found command... return(r); } } link = link->next; } return(NULL); } //Name: tacticsSetRetreatFrom // //Description: Calculates the average location of a group of ships // void setAveragePosition(vector *vec, SelectCommand *selection) { udword i; real32 oneOverShips; vec->x = 0.0f; vec->y = 0.0f; vec->z = 0.0f; for(i = 0; i < selection->numShips; i++) { vecAddTo(*vec,selection->ShipPtr[i]->posinfo.position); } oneOverShips = 1.0f/selection->numShips; vecScalarMultiply(*vec,*vec,oneOverShips); } //Name: tacticsReportMove // //Description: Function scans todo list and deals with any commands with attackinfo // dealing with the ships in selection. void tacticsReportMove(CommandLayer *comlayer,SelectCommand *selection) { Node *curnode; CommandToDo *command; sdword i,j; vector testdistvec; curnode = comlayer->todolist.head; #ifdef DEBUG_TACTICS if(noRetreat) return; #endif while (curnode != NULL) { command = (CommandToDo *)listGetStructOfNode(curnode); if(command->ordertype.order == COMMAND_ATTACK) { if(command->selection->ShipPtr[0]->tacticstype == Aggressive) { //command is set to agressive so ships can't retreat. goto nextnode; } if (command->ordertype.attributes & COMMAND_IS_FORMATION) { if(!command->formation.doneInitialAttack) { //group of ships hasn't attacked yet...so //don't register a retreat yet! goto nextnode; } } else { //ship(s) aren't in formation... //mustn't let ships retreat if not close enough! //!!! Ships must be within RetreatGetAwayDistSqr vecSub(testdistvec,command->selection->ShipPtr[0]->posinfo.position,selection->ShipPtr[0]->posinfo.position); if(vecMagnitudeSquared(testdistvec) > tacticsInfo.RetreatGetAwayDistSqr[selection->ShipPtr[0]->staticinfo->shipclass]) { //too far away to be considered for retreating goto nextnode; } } for(i=0;i<((SelectCommand *)command->attack)->numShips;i++) { for(j=0;jnumShips;j++) { if(selection->ShipPtr[j] == ((SelectCommand *)command->attack)->ShipPtr[i]) { //ship that has been given move command is also //being attacked by this command. So //set retreat conditions and do check somewheres vector tempvec,tempRetFrom;//,oldvec; real32 tempdistanceStartSqr;//,olddistanceStartSqr; RetreatAtom *newRetreat,*oldretreat; setAveragePosition(&tempRetFrom, (SelectCommand *)command->attack); vecSub(tempvec,selection->ShipPtr[j]->posinfo.position,tempRetFrom); tempdistanceStartSqr = vecMagnitudeSquared(tempvec); oldretreat = tacticsShipIsRetreatingFromThisCommand(selection->ShipPtr[j], command); if(oldretreat != NULL) { //ship is currently retreating from this command, so don't do anything continue; //ship is currently retreating from this command (amongst others possibly) //lets choose the more advantagous retreat plan. /* vecSub(oldvec,selection->ShipPtr[j]->posinfo.position,oldretreat->retreatFrom); olddistanceStartSqr = vecMagnitudeSquared(tempvec); if(olddistanceStartSqr < oldretreat->distanceStartSqr) { continue; } else { //cancel current ships retreat from this //command, and lets create a new one #ifdef DEBUG_TACTICS dbgMessagef("\nremoving old retreat in favour of a better one"); #endif tacticsRemoveRetreat(oldretreat); } */ } newRetreat = (RetreatAtom *) memAlloc(sizeof(RetreatAtom),"Retreat Data", NonVolatile); newRetreat->retreater = selection->ShipPtr[j]; newRetreat->fleeingfrom = command; newRetreat->retreatFrom = tempRetFrom; newRetreat->distanceStartSqr = tempdistanceStartSqr; listAddNode(&universe.RetreatList,&newRetreat->retreatLink,newRetreat); #ifdef bpasechn #ifdef DEBUG_TACTICS dbgMessagef("\nRetreat Registered."); #endif #endif //maybe make a retreat list that we update //in tactics update every Xth frame //we also remove references as ships die n such. //pain in ass, but efficient //when retreat conditions are met, ship //is added to a ship 'memory' list. This //list will contain ships that must be attacked //if ships come within range. Checked in //tacticsDelegateAttack. //ship memory lists must be checked and //cleaned up as ships die //and must also have expiry times on entries. } } } } nextnode: curnode = curnode->next; } } //Name: tacticsShipDied // //Desc: A ship has died, so we need to remove certain references // from our tactics data structures void tacticsShipDied(Ship *ship) { sdword i; Node *link,*templink; RetreatAtom *r; AttackAtom *a; #ifdef DEBUG_TACTICS if(!tacticsOn) return; #endif link = universe.RetreatList.head; while(link != NULL) { r = (RetreatAtom *) listGetStructOfNode(link); if(r->retreater == ship) { templink = link->next; listDeleteNode(link); link = templink; continue; } link = link->next; } link = universe.AttackMemory.head; while(link != NULL) { a = (AttackAtom *) listGetStructOfNode(link); if(a->retreater == ship) { goto deleteNode; } for(i=0;iattackerList.numShips;i++) { if(ship == a->attackerList.ShipPtr[i]) { a->attackerList.numShips--; if(a->attackerList.numShips == 0) goto deleteNode; a->attackerList.ShipPtr[i] = a->attackerList.ShipPtr[a->attackerList.numShips]; return; } } link = link->next; continue; deleteNode: templink = link->next; listDeleteNode(link); link = templink; return; } } //name tacticsSelCopy(&newattackatom->attackList,lookers); // //desc: copies contents of one selection to the other void tacticsSelCopy(SelectCommand *other,SelectCommand *one) { sdword i; for(i=0;inumShips;i++) { other->ShipPtr[i] = one->ShipPtr[i]; } other->numShips = one->numShips; } //Name: tacticsAttackCommandVoided // //desc: An attack command has been cleared, we need to remove // references to it void tacticsAttackCommandVoided(CommandToDo *command) { Node *link,*templink; RetreatAtom *r; #ifdef DEBUG_TACTICS if(!tacticsOn) return; #endif link = universe.RetreatList.head; while(link != NULL) { r = (RetreatAtom *) listGetStructOfNode(link); if(r->fleeingfrom == command) { templink = link->next; listDeleteNode(link); link = templink; continue; } link = link->next; } } //Name: tacticsPutOnLookOutfor(Ship *looker, Ship *retreater) // //desc: Sets the 'looker' ship to be on attack lookout for // retreater. If, after tunable time (in tactics.script) // retreater comes within looker's passive retaliation zone // and looker isn't doing anything (except waiting to passvie attack // looker will recieve full attack orders to attack retreater. void tacticsPutOnLookOutFor(SelectCommand *lookers, Ship *retreater) { AttackAtom *newattackatom; udword sizeofmem; //calculate memory needs cleverly sizeofmem = sizeof(AttackAtom) + sizeof(ShipPtr)*(lookers->numShips-1); newattackatom = (AttackAtom *)memAlloc(sizeofmem,"tacticsattackmemory",NonVolatile); newattackatom->retreater = retreater; newattackatom->expirytime = universe.totaltimeelapsed+tacticsInfo.AttackMemoryTimeOut; newattackatom->retreatTime = universe.totaltimeelapsed+tacticsInfo.freeRetreatTime; tacticsSelCopy(&newattackatom->attackerList,lookers); listAddNode(&universe.AttackMemory,&newattackatom->attackLink,newattackatom); } //This function will make all ships in selection stop being on the //lookout for otherships void tacticsMakeShipsNotLookForOtherShips(SelectCommand *selection) { AttackAtom *attackatom; Node *node,*tempnode; sdword i,j; node = universe.AttackMemory.head; while(node != NULL) { attackatom = (AttackAtom *)listGetStructOfNode(node); for(j=0;jnumShips;j++) { Ship *ship = selection->ShipPtr[j]; for(i=0;iattackerList.numShips;i++) { if(ship == attackatom->attackerList.ShipPtr[i]) { //ship is looking for something //remove it from list attackatom->attackerList.numShips--; attackatom->attackerList.ShipPtr[i] = attackatom->attackerList.ShipPtr[attackatom->attackerList.numShips]; if(attackatom->attackerList.numShips == 0) { tempnode = node->next; listDeleteNode(node); //delete node+memory node = tempnode; goto nextnode; } break; } } } node = node->next; nextnode: continue; } } //returns true if at least 1 of the ships in list is on the ships target list bool tacticsIsShipLookingForAnyOfThese(Ship *ship,SelectCommand *selection) { AttackAtom *attackatom; Node *node; sdword i,j; node = universe.AttackMemory.head; while(node != NULL) { attackatom = (AttackAtom *)listGetStructOfNode(node); for(i=0;iattackerList.numShips;i++) { if(ship == attackatom->attackerList.ShipPtr[i]) { //ship is looking for something for(j=0;jnumShips;j++) { if(selection->ShipPtr[j] == attackatom->retreater) return TRUE; } } } node = node->next; } return FALSE; } bool tacticsAreStrikeCraftInSelection(SelectCommand *selection) { sdword i; for(i = 0; i< selection->numShips; i++) { if(selection->ShipPtr[i]->objtype == OBJ_ShipType) { if(selection->ShipPtr[i]->staticinfo->shipclass == CLASS_Fighter || selection->ShipPtr[i]->staticinfo->shipclass == CLASS_Corvette) { return TRUE; } } } return FALSE; } //name : tacticsMaxDistToTarget // //desc: returns the distance from the furthest ship, to the target // Used to determine flyin distance for defenders real32 tacticsMaxDistToTarget(SelectCommand *selection,SpaceObjRotImpTarg *target) { sdword i; real32 maxdistsqr,newdistsqr; vector tempvec; //fix later : could do optimally by analysing formation type, and determining the //furthest ship and looking at just it..but for now, we brute force it //could use camera distacne squared maybe? vecSub(tempvec,selection->ShipPtr[0]->posinfo.position,target->posinfo.position); maxdistsqr = vecMagnitudeSquared(tempvec); for(i=1;inumShips;i++) { vecSub(tempvec,selection->ShipPtr[i]->posinfo.position,target->posinfo.position); newdistsqr = vecMagnitudeSquared(tempvec); if(newdistsqr > maxdistsqr) { maxdistsqr = newdistsqr; } } return(fsqrt(maxdistsqr)); } bool tacticsIsShipLookingForShip(Ship *ship,Ship *target) { AttackAtom *attackatom; Node *node; sdword i; node = universe.AttackMemory.head; while(node != NULL) { attackatom = (AttackAtom *)listGetStructOfNode(node); if(target == attackatom->retreater) { for(i=0;iattackerList.numShips;i++) { if(ship == attackatom->attackerList.ShipPtr[i]) return TRUE; } } node = node->next; } return FALSE; } //function to perform dodging perhaps bad place... void tacticsDodgeUpdate(Ship *ship) { if(ship->isDodging) { tacticsDoDodge(ship); } else { if(ship->tacticstype != Aggressive) { //do we need to dodge? switch(ship->tactics_ordertype) { case MOVE_ORDERS_NO_ENEMY: case NO_ORDER_NO_ENEMY: case ATTACK_ORDERS: //no enemy near this ship, so no dodging break; case MOVE_ORDERS_ENEMY: case NO_ORDER_ENEMY: tacticsSetShipToDoDodge(ship); break; case ATTACK_ORDERS_ENEMY: //both neutral and evasive tactics dodge during attacks tacticsSetShipToDoDodge(ship); break; } } } } //function to determine if enemy ships are nearby and to determine //a ships order type in terms of tactics functions void tacticsUpdateOrderStatus(Ship *ship) { CommandToDo *command; udword enemyalready; sdword oldOrder = ship->tactics_ordertype; command = getShipAndItsCommand(&universe.mainCommandLayer,ship); //scan to see if enemies are near by if((universe.univUpdateCounter & EnemyNearByCheckRate) == EnemyNearByCheckFrame) { if(command != NULL) { if(command->tacticalupdatetime < universe.totaltimeelapsed) { command->tacticalupdatetime = universe.totaltimeelapsed; if(tacticsAreEnemiesNearby(command->selection->ShipPtr[0],ship,tacticsInfo.EnemyNearZone)) { //enemies near by..later scan them, but not now enemyalready = ORDER_TYPE_ENEMY_MASK; } else { enemyalready = 0; } } else { enemyalready = command->selection->ShipPtr[0]->tactics_ordertype & ORDER_TYPE_ENEMY_MASK; } } else { if(tacticsAreEnemiesNearby(ship,ship,tacticsInfo.EnemyNearZone)) { //enemies near by..later scan them, but not now enemyalready = ORDER_TYPE_ENEMY_MASK; } else { enemyalready = 0; } } } else { enemyalready = ship->tactics_ordertype & ORDER_TYPE_ENEMY_MASK; } //set tacitcs_ordertype variable utilizing enemyalready flag set above if (command != NULL) { switch(command->ordertype.order) { case COMMAND_NULL: case COMMAND_MILITARYPARADE: ship->tactics_ordertype = ORDER_TYPE_NO_ORDERS + enemyalready; break; case COMMAND_MOVE: case COMMAND_DOCK: case COMMAND_LAUNCHSHIP: case COMMAND_HALT: ship->tactics_ordertype = ORDER_TYPE_MOVE_ORDERS + enemyalready; break; case COMMAND_ATTACK: //ship->tactics_ordertype = ORDER_TYPE_ATTACK_ORDERS; ship->tactics_ordertype = ORDER_TYPE_ATTACK_ORDERS + enemyalready; break; case COMMAND_SPECIAL: if(ship->shiptype == RepairCorvette) { if( ((RepairCorvetteSpec *)ship->ShipSpecifics)->repairState > REPAIR_Dock1) ship->tactics_ordertype = ORDER_TYPE_MOVE_ORDERS; //force not to dodge else ship->tactics_ordertype = ORDER_TYPE_MOVE_ORDERS + enemyalready; } else { ship->tactics_ordertype = ORDER_TYPE_MOVE_ORDERS + enemyalready; } break; default: break; } //set command leaders tacticstype to the correct one so we can reference it later when we don't //update the command structure enemy nearby status. command->selection->ShipPtr[0]->tactics_ordertype = ship->tactics_ordertype; //possibly redundant if(ship->tactics_ordertype != oldOrder) { //order has changed if(command->ordertype.attributes & COMMAND_IS_FORMATION) { //command is in formation setFormationTravelVelocity(command); } } } else { //ship isn't doing anything anymore...but are enemies near by? //use old info until new info is pumped in ship->tactics_ordertype = ORDER_TYPE_NO_ORDERS + enemyalready; } } //update ships thrusterinfo based on there order type void tacticsManeuvUpdate(Ship *ship) { sdword i; sdword classType; ShipStaticInfo *shipstaticinfo = ship->staticinfo; real32 manMult; manMult = 1.0f; if(shipstaticinfo->shipclass == CLASS_Fighter) { if(bitTest(ship->specialFlags,SPECIAL_SpeedBurst)) manMult = speedBurstThrustMult; classType = Tactics_Fighter; } else { classType = Tactics_Corvette; } for(i=0;inonstatvars.thruststrength[i] = shipstaticinfo->thruststrengthstat[i]*tacticsInfo.ManeuvBonus[ship->tactics_ordertype][classType][ship->tacticstype]*manMult; } for(i=0;inonstatvars.rotstrength[i] = shipstaticinfo->rotstrengthstat[i]*tacticsInfo.ManeuvBonus[ship->tactics_ordertype][classType][ship->tacticstype]*manMult; } for(i=0;inonstatvars.turnspeed[i] = shipstaticinfo->turnspeedstat[i]*tacticsInfo.ManeuvBonus[ship->tactics_ordertype][classType][ship->tacticstype]*manMult; } } //Name: tacticsUpdate // //Description: Called from univupdate.c, this function performs // any tactics related code for this ship void tacticsUpdate(Ship *ship) { sdword oldstate; #ifdef DEBUG_TACTICS if(!tacticsOn) return; #endif //maybe only do this check every so often... if(ship->staticinfo->shipclass != CLASS_Fighter && ship->staticinfo->shipclass != CLASS_Corvette) { //ship is a NON strike craft... //don't bother updating crap for it then... return; } /***********************************/ //strike craft ONLY proccessed beyond this point!!!! /***********************************/ //Update status of special Ops speed Burst speedBurstUpdate(ship); //update ships thrusterinfo based on there order type tacticsManeuvUpdate(ship); //update strike crafts dodging tacticsDodgeUpdate(ship); //update ships enemy + order status tacticsUpdateOrderStatus(ship); if(ship->formationcommand != NULL) { //ship is in formation, so set formation //check if we haven't processed this formation yet if(universe.totaltimeelapsed > (ship->formationcommand->formation.tacticsUpdate + DELAY_FORMTIGHTNESS_CHANGE)) { //set formation update time ship->formationcommand->formation.tacticsUpdate = universe.totaltimeelapsed; //set formation type based on contents...should add elsewhere later...so isn't called all the time oldstate = ship->formationcommand->formation.tacticalState; ship->formationcommand->formation.tacticalState = tacticsGetFormationOptimalState(ship->formationcommand->selection); if((oldstate != ship->formationcommand->formation.tacticalState) && (ship->formationcommand->formation.formationtype != CUSTOM_FORMATION)) FormationCalculateOffsets(ship->formationcommand); } } } //Name: TacticsGlobalUpdate() // //Desc: Performs any global tactics functions, such as retreat monitoring // void tacticsGlobalUpdate() { Node *rnode,*tempnode; AttackAtom *attackatom; RetreatAtom *ratom; Ship *retreater, *retreatedFrom; #ifdef DEBUG_TACTICS if(!tacticsOn) return; #endif //Deal with retreats here: if((universe.univUpdateCounter & RetreatCheckRate) == RetreatCheckFrame) { //time to do tactics update vector tempvec2; real32 distsqr; rnode = universe.RetreatList.head; while(rnode != NULL) { ratom = (RetreatAtom *) listGetStructOfNode(rnode); retreater = ratom->retreater; //tacticsSetRetreatFrom(&tempvec, (SelectCommand *)ratom->fleeingfrom->attack); //vecSub(tempvec2,tempvec,retreater->posinfo.position); vecSub(tempvec2,retreater->posinfo.position,ratom->retreatFrom); distsqr = vecMagnitudeSquared(tempvec2); if((distsqr - ratom->distanceStartSqr) > tacticsInfo.RetreatDistanceSqr[retreater->staticinfo->shipclass]) { vector retreatFromAvgPos; vector tmpvec3; real32 gotawaydistsqr; setAveragePosition(&retreatFromAvgPos, (SelectCommand *)ratom->fleeingfrom->selection); vecSub(tmpvec3,retreatFromAvgPos,retreater->posinfo.position); gotawaydistsqr = vecMagnitudeSquared(tmpvec3); if (gotawaydistsqr > tacticsInfo.RetreatGetAwayDistSqr[retreater->staticinfo->shipclass]) { #ifdef bpasechn #ifdef DEBUG_TACTICS dbgMessagef("\nRetreat Satisfied..."); #endif #endif ////////////////////// //Retreat successful speech event! if(retreater->playerowner->playerIndex == universe.curPlayerIndex) { //local machines ships RETREATED //use event num: //STAT_Grp_RetreatSuccessful //or STAT_AssGrp_RetreatSuccessful //battlechatter if(selHotKeyGroupNumberTest(retreater) == SEL_InvalidHotKey) { //not in a group! if (battleCanChatterAtThisTime(BCE_STAT_Grp_RetreatSuccessful, retreater)) { battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_STAT_Grp_RetreatSuccessful, retreater, SOUND_EVENT_DEFAULT); } } else { if (battleCanChatterAtThisTime(BCE_STAT_AssGrp_RetreatSuccessful, retreater)) { battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_STAT_AssGrp_RetreatSuccessful, retreater, selHotKeyGroupNumberTest(retreater)); } } //// } else { //local machines enemy retreated FROM //local player! //use event number //STAT_Grp_EnemyRetreated //or STAT_AssGrp_EnemyRetreated retreatedFrom = ((SelectCommand *)ratom->fleeingfrom->selection)->ShipPtr[0]; if(selHotKeyGroupNumberTest(retreatedFrom) == SEL_InvalidHotKey) { //not in a group! if (battleCanChatterAtThisTime(BCE_STAT_Grp_EnemyRetreated, retreatedFrom)) { battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_STAT_Grp_EnemyRetreated, retreatedFrom, SOUND_EVENT_DEFAULT); } } else { if (battleCanChatterAtThisTime(BCE_STAT_AssGrp_EnemyRetreated, retreatedFrom)) { battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_STAT_AssGrp_EnemyRetreated, retreatedFrom, selHotKeyGroupNumberTest(retreatedFrom)); } } } if (clRemoveShipFromSelection((SelectCommand *)ratom->fleeingfrom->attack,retreater)) { RemoveAttackTargetFromExtraAttackInfo((SpaceObjRotImpTarg *)retreater,ratom->fleeingfrom); } //put retreater into a ship memory list...and then, we check thta list for each ship passive attacking //if the retreater is in the list along with the passive attacker, we issue an attack command... //as long as this updata function hasn't killed the memory due to a time out. tacticsPutOnLookOutFor(ratom->fleeingfrom->selection,retreater); tempnode = rnode->next; tacticsRemoveRetreat(ratom); rnode = tempnode; continue; } } rnode = rnode->next; } } if((universe.univUpdateCounter & ATTACKMEMORY_CLEANUP_RATE) == ATTACKMEMORY_CLEANUP_FRAME) { //perform attackmemory cleanups... rnode = universe.AttackMemory.head; while(rnode != NULL) { attackatom = (AttackAtom *)listGetStructOfNode(rnode); if(attackatom->expirytime < universe.totaltimeelapsed) { #ifdef DEBUG_TACTICS dbgMessagef("\nAttack Lookout timed out"); #endif tempnode = rnode->next; listDeleteNode(rnode); rnode = tempnode; continue; } rnode = rnode->next; } } } bool tacticsAreEnemiesNearby(Ship *leadership,Ship *thisship, real32 retaliateZone) { Player *playerowner = thisship->playerowner; blob *thisblob = thisship->collMyBlob; sdword objindex = 0; SelectCommand *blobships = thisblob->blobShips; udword num = blobships->numShips; udword shipIndex = 0; Ship *ship; vector diff; real32 timesincecloak; real32 negRetaliateZone = -retaliateZone; if ((thisship->shiptype == FloatingCity) || (thisship->shiptype == TargetDrone) || (bitTest(thisship->specialFlags, SPECIAL_FriendlyStatus|SPECIAL_Hyperspacing))) { return FALSE; // traders get special status, not considered enemy to anyone } while (objindex < num) { ship = blobships->ShipPtr[objindex]; if ((allianceIsShipAlly(ship, playerowner))) { goto nextnode; // must be enemy ship } if ((ship->shiptype == FloatingCity) || (ship->shiptype == TargetDrone) || (bitTest(ship->specialFlags, SPECIAL_FriendlyStatus|SPECIAL_Hyperspacing))) { goto nextnode; // traders get special status, not considered enemy to anyone } if (bitTest(ship->flags,SOF_Cloaked)) { if(!proximityCanPlayerSeeShip(thisship->playerowner,ship)) { goto nextnode; // if ship is cloaked, and can't be seen by that ships player.. } } timesincecloak = universe.totaltimeelapsed - ship->shipDeCloakTime; if(timesincecloak <= TW_SECOND_SEE_TIME) { if(timesincecloak < TW_NOONE_SEE_TIME) { //ship being considered has decloaked so recently that 'thisship' couldn't //possibly see it yet goto nextnode; } else if(timesincecloak < TW_FIRST_SEE_TIME) { //ship has decloaked so long ago that only a small percentage could see it now if(randombetween(0,100) > TW_FIRST_SEE_PERCENTAGE) { goto nextnode; } } else if(timesincecloak < TW_SECOND_SEE_TIME) { //ship has decloaked a fair ammount of time ago, and some more ships are likely to see it now if(randombetween(0,100) > TW_SECOND_SEE_PERCENTAGE) { goto nextnode; } } } if(bitTest(ship->flags,SOF_Disabled|SOF_Hide)) { //don't attack disabled ships. goto nextnode; } vecSub(diff,ship->posinfo.position,leadership->posinfo.position); if (isBetweenExclusive(diff.x,negRetaliateZone,retaliateZone) && isBetweenExclusive(diff.y,negRetaliateZone,retaliateZone) && isBetweenExclusive(diff.z,negRetaliateZone,retaliateZone) ) { return TRUE; } nextnode: objindex++; } return FALSE; } void speedBurstUpdate(Ship *ship) { if(bitTest(ship->specialFlags,SPECIAL_SpeedBurst)) { if(ship->speedBurstTime < universe.totaltimeelapsed) { bitClear(ship->specialFlags,SPECIAL_SpeedBurst); bitSet(ship->specialFlags,SPECIAL_SpeedBurstCooling); ship->speedBurstTime = universe.totaltimeelapsed+speedBurstCoolDown; } } else if(bitTest(ship->specialFlags,SPECIAL_SpeedBurstCooling)) { if(ship->speedBurstTime < universe.totaltimeelapsed) { bitClear(ship->specialFlags,SPECIAL_SpeedBurstCooling); } } } /*----------------------------------------------------------------------------- Name : tacticsCheckGuardConditionsDuringAttack Description : returns TRUE if command needs to cancel its attack and return to guarding ship Inputs : command in question Outputs : Return : as above ----------------------------------------------------------------------------*/ bool tacticsCheckGuardConditionsDuringAttack(CommandToDo *command) { sdword i; real32 distSqr,tempreal; vector distVec,protectAv,defendAv; dbgAssert(command->ordertype.attributes * COMMAND_IS_PROTECTING); //get average position of defenders vecSet(defendAv,0.0f,0.0f,0.0f); for(i=0;iselection->numShips;i++) { vecAddTo(defendAv,command->selection->ShipPtr[i]->posinfo.position); } tempreal = 1.0f/((real32)i); vecScalarMultiply(defendAv,defendAv,tempreal); //get average position of ships needing protection... vecSet(protectAv,0.0f,0.0f,0.0f); for(i=0;iprotect->numShips;i++) { vecAddTo(protectAv,command->protect->ShipPtr[i]->posinfo.position); } tempreal = 1.0f/((real32)i); vecScalarMultiply(protectAv,protectAv,tempreal); vecSub(distVec, protectAv, defendAv); distSqr = vecMagnitudeSquared(distVec); if(distSqr > tacticsInfo.tacticsGuardReturnToGuardingDistanceSqr) { //guarding ship has #ifdef DEBUG_TACTICS dbgMessagef("\nShips guarding a ship cancelling attack and returning to guard duty."); #endif return TRUE; } return FALSE; } real32 tacticsGetShipsMaxVelocity(Ship *ship) { real32 speedmult = 1.0f; if(ship->objtype != OBJ_ShipType) { return(ship->staticinfo->staticheader.maxvelocity); } if (ship->shiptype == Probe) { return ProbeGetMaxVelocity(ship); } if(bitTest(ship->specialFlags,SPECIAL_Kamikaze)) { //ship is in kamikaze mode if(bitTest(ship->specialFlags,SPECIAL_KamikazeCrazyFast)) { //in a state where extra speed boost is needed speedmult = kamikazeSpeedBurst; } } if(bitTest(ship->specialFlags,SPECIAL_SpeedBurst)) { speedmult *= speedBurstMaxVelocityMultiplier; } else if(bitTest(ship->specialFlags,SPECIAL_SpeedBurstCooling)) { //slow deceleration real32 temp; temp = speedBurstMaxVelocityMultiplier*(ship->speedBurstTime/universe.totaltimeelapsed); if(temp < 1.0f) temp = 1.0f; speedmult *= temp; } if (ship->staticinfo->maxfuel != 0.0f) { // ship burns fuel if (ship->fuel <= 0.0f) { speedmult = OUT_OF_FUEL_VELOCITY_SLOWDOWN; } } if (bitTest(ship->specialFlags,SPECIAL_SinglePlayerLimitSpeed)) { //Falko: removed because we want to be able to increase the maximum speed // of ships as well as decreasing it. // if (ship->singlePlayerSpeedLimiter < ship->staticinfo->staticheader.maxvelocity) // { return ship->singlePlayerSpeedLimiter; // deliberately override other considerations - we want this to be the final word // } } if(bitTest(ship->specialFlags,SPECIAL_SalvagerHasSomethingAttachedAndIsDoingSomethingElse)) { SalCapCorvetteStatics *salcapcorvettestatics = ((ShipStaticInfo *)(ship->staticinfo))->custstatinfo; return(salcapcorvettestatics->maxPushingVelocitySingle); } switch(ship->staticinfo->shipclass) { case CLASS_Fighter: return(ship->staticinfo->staticheader.maxvelocity*tacticsInfo.MaxVelocityBonus[ship->tactics_ordertype][Tactics_Fighter][ship->tacticstype]*speedmult); case CLASS_Corvette: return(ship->staticinfo->staticheader.maxvelocity*tacticsInfo.MaxVelocityBonus[ship->tactics_ordertype][Tactics_Corvette][ship->tacticstype]*speedmult); default: return(ship->staticinfo->staticheader.maxvelocity*speedmult); } } /*----------------------------------------------------------------------------- Name : tacticsHasShipRetreatedFromShip Description : returns TRUE if: 1 -shipA isn't attacking shipB 2 - ship is listed in the has retreated list Need two checks because ship can be in retreated list, but still be getting attack :( will return true if shipA has retreated and shipB is still on lookout for shipA...so time dependant Inputs : Outputs : Return : as above ----------------------------------------------------------------------------*/ bool tacticsHasShipRetreatedFromShip(Ship *shipA, Ship *shipB) { CommandToDo *attackerCommand; Node *node; AttackAtom *aAtom; attackerCommand = getShipAndItsCommand(&universe.mainCommandLayer,shipB); if(attackerCommand != NULL) { SelectCommand sel; sel.numShips = 1; sel.ShipPtr[0] = shipA; if(TheseShipsAreInSelection((SelectCommand *)attackerCommand->attack,&sel)) { //ship is a target, so ship hasn't retreated return FALSE; } } //shipB isn't attacking shipA, so lets see //if ship is in retreat node = universe.AttackMemory.head; while(node != NULL) { aAtom = (AttackAtom *) listGetStructOfNode(node); if(aAtom->retreater == shipA) { //ship has retreated from something SelectCommand sel; sel.numShips = 1; sel.ShipPtr[0] = shipB; if(TheseShipsAreInSelection(&aAtom->attackerList,&sel)) { //ship has retreated return TRUE; } } node = node->next; } return FALSE; }