-replaced some numbers scattered across the code with defines
-when looking for a new target droids/structures will now take into consideration targets of the friendly droids/structures nearby -droids/structures are now constantly looking for the best target - will no longer lock on decoys/walls and other crappy targets forever -ALT+Space now opens a special debug window - set window text with setDebugMenuEntry() -minor cleanups git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@905 4a71c877-e1ca-e34f-864e-861f7616d084master
parent
1cb603a445
commit
bd2dd39e56
28
src/action.c
28
src/action.c
|
@ -1218,9 +1218,9 @@ static void actionUpdateTransporter( DROID *psDroid )
|
|||
{
|
||||
if (psDroid->asWeaps[i].nStat > 0)
|
||||
{
|
||||
if (psDroid->psActionTarget[0] == NULL)
|
||||
if (psDroid->psActionTarget[0] == NULL && CAN_UPDATE_NAYBORS(psDroid))
|
||||
{
|
||||
aiBestNearestTarget(psDroid, &psDroid->psActionTarget[0], i);
|
||||
(void)aiBestNearestTarget(psDroid, &psDroid->psActionTarget[0], i);
|
||||
}
|
||||
|
||||
if ( psDroid->psActionTarget[0] != NULL )
|
||||
|
@ -1461,7 +1461,7 @@ void actionUpdateDroid(DROID *psDroid)
|
|||
UDWORD tlx,tly;
|
||||
STRUCTURE *psStruct;
|
||||
STRUCTURE_STATS *psStructStats;
|
||||
BASE_OBJECT *psTarget;//, *psObj;
|
||||
BASE_OBJECT *psTarget;
|
||||
WEAPON_STATS *psWeapStats;
|
||||
SDWORD targetDir, dirDiff, pbx,pby;
|
||||
SDWORD xdiff,ydiff, rangeSq;
|
||||
|
@ -1704,7 +1704,8 @@ void actionUpdateDroid(DROID *psDroid)
|
|||
psDroid->asWeaps[i].nStat > 0 &&
|
||||
psWeapStats->rotate &&
|
||||
psWeapStats->fireOnMove != FOM_NO &&
|
||||
aiBestNearestTarget(psDroid, &psDroid->psActionTarget[0], 0))
|
||||
CAN_UPDATE_NAYBORS(psDroid) &&
|
||||
(aiBestNearestTarget(psDroid, &psDroid->psActionTarget[0], i) >= 0))
|
||||
{
|
||||
if (secondaryGetState(psDroid, DSO_ATTACK_LEVEL, &state))
|
||||
{
|
||||
|
@ -1755,7 +1756,7 @@ void actionUpdateDroid(DROID *psDroid)
|
|||
}
|
||||
else
|
||||
{
|
||||
vtResult = 1;
|
||||
vtResult = INVALID_TARGET;
|
||||
}
|
||||
|
||||
// firing on something while moving
|
||||
|
@ -1765,7 +1766,7 @@ void actionUpdateDroid(DROID *psDroid)
|
|||
psDroid->action = DACTION_NONE;
|
||||
}
|
||||
else if ((psDroid->psActionTarget[0] == NULL) ||
|
||||
(vtResult == 1) ||
|
||||
(vtResult == INVALID_TARGET) ||
|
||||
(secondaryGetState(psDroid, DSO_ATTACK_LEVEL, &state) && (state != DSS_ALEV_ALWAYS)))
|
||||
{
|
||||
// Target lost
|
||||
|
@ -1788,6 +1789,7 @@ void actionUpdateDroid(DROID *psDroid)
|
|||
}
|
||||
else
|
||||
{
|
||||
/* Deal with target */
|
||||
if (visibleObject((BASE_OBJECT*)psDroid, psDroid->psActionTarget[0]))
|
||||
{
|
||||
for(i = 0;i < psDroid->numWeaps;i++)
|
||||
|
@ -1797,12 +1799,6 @@ void actionUpdateDroid(DROID *psDroid)
|
|||
//Watermelon:to fix a AA-weapon attack ground unit exploit
|
||||
if ( (num_weapons & (1 << (i+1))) && (vtResult & (1 << (i+1))) )
|
||||
{
|
||||
/*if (actionTargetTurret((BASE_OBJECT*)psDroid, psDroid->psActionTarget,
|
||||
&(psDroid->turretRotation), &(psDroid->turretPitch),
|
||||
psDroid->turretRotRate, (SWORD)(psDroid->turretRotRate/2),
|
||||
//asWeaponStats[psDroid->asWeaps->nStat].direct))
|
||||
proj_Direct(&asWeaponStats[psDroid->asWeaps->nStat]),
|
||||
bInvert))*/
|
||||
if (actionTargetTurret((BASE_OBJECT*)psDroid, psDroid->psActionTarget[0],
|
||||
&(psDroid->turretRotation[i]), &(psDroid->turretPitch[i]),
|
||||
&asWeaponStats[psDroid->asWeaps[i].nStat],
|
||||
|
@ -1852,7 +1848,7 @@ void actionUpdateDroid(DROID *psDroid)
|
|||
|
||||
//check the target hasn't become one the same player ID - Electronic Warfare
|
||||
if ((electronicDroid(psDroid) && (psDroid->player == psDroid->psActionTarget[0]->player)) ||
|
||||
(vtResult == 1) )// ||
|
||||
(vtResult == INVALID_TARGET) )// ||
|
||||
// (secondaryGetState(psDroid, DSO_ATTACK_LEVEL, &state) && (state != DSS_ALEV_ALWAYS)))
|
||||
{
|
||||
psDroid->psActionTarget[0] = NULL;
|
||||
|
@ -2048,7 +2044,7 @@ void actionUpdateDroid(DROID *psDroid)
|
|||
}
|
||||
else
|
||||
{
|
||||
vtResult = 1;
|
||||
vtResult = INVALID_TARGET;
|
||||
}
|
||||
|
||||
avtResult = actionVisibleTarget(psDroid, psDroid->psActionTarget[0]);
|
||||
|
@ -2058,7 +2054,7 @@ void actionUpdateDroid(DROID *psDroid)
|
|||
(psDroid->psActionTarget[0] == NULL) ||
|
||||
//check the target hasn't become one the same player ID - Electronic Warfare
|
||||
(electronicDroid(psDroid) && (psDroid->player == psDroid->psActionTarget[0]->player)) ||
|
||||
(vtResult == 1) )// ||
|
||||
(vtResult == INVALID_TARGET) )// ||
|
||||
// (secondaryGetState(psDroid, DSO_ATTACK_LEVEL, &state) && (state != DSS_ALEV_ALWAYS)))
|
||||
{
|
||||
moveToRearm(psDroid);
|
||||
|
@ -2172,7 +2168,7 @@ void actionUpdateDroid(DROID *psDroid)
|
|||
|
||||
//check the target hasn't become one the same player ID - Electronic Warfare
|
||||
if ((electronicDroid(psDroid) && (psDroid->player == psDroid->psActionTarget[0]->player)) ||
|
||||
(vtResult == 1) )// ||
|
||||
(vtResult == INVALID_TARGET) )// ||
|
||||
// (secondaryGetState(psDroid, DSO_ATTACK_LEVEL, &state) && (state != DSS_ALEV_ALWAYS)))
|
||||
{
|
||||
for (i = 0;i < psDroid->numWeaps;i++)
|
||||
|
|
15
src/action.h
15
src/action.h
|
@ -130,6 +130,21 @@ extern BOOL actionRouteBlockingPos(DROID *psDroid, SDWORD x, SDWORD y);
|
|||
// choose a landing position for a VTOL when it goes to rearm
|
||||
extern BOOL actionVTOLLandingPos(DROID *psDroid, UDWORD *px, UDWORD *py);
|
||||
|
||||
// Try to find a better target
|
||||
extern BOOL updateAttackTarget(BASE_OBJECT * psAttacker, SDWORD weapon_slot);
|
||||
|
||||
//How many frames to skip before updating naybors
|
||||
#define NAYBOR_SKIP_FRAMES 8
|
||||
|
||||
/* How many frames to skip before looking for a better target */
|
||||
#define TARGET_UPD_SKIP_FRAMES 1000
|
||||
|
||||
#define INVALID_TARGET 1
|
||||
|
||||
/* Macro to check if it's time to update naybor list */
|
||||
#define CAN_UPDATE_NAYBORS(object)\
|
||||
(((object)->id % NAYBOR_SKIP_FRAMES) == (frameGetFrameNumber() % NAYBOR_SKIP_FRAMES))
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
467
src/ai.c
467
src/ai.c
|
@ -19,6 +19,9 @@
|
|||
#include "projectile.h"
|
||||
#include "visibility.h"
|
||||
|
||||
/* Calculates attack priority for a certain target */
|
||||
SDWORD targetAttackWeight(BASE_OBJECT *psTarget, BASE_OBJECT *psAttacker, SDWORD weapon_slot);
|
||||
|
||||
// alliances
|
||||
UBYTE alliances[MAX_PLAYERS][MAX_PLAYERS];
|
||||
|
||||
|
@ -69,36 +72,31 @@ BOOL aiShutdown(void)
|
|||
}
|
||||
|
||||
// Find the best nearest target for a droid
|
||||
BOOL aiBestNearestTarget(DROID *psDroid, BASE_OBJECT **ppsObj, int weapon_slot)
|
||||
// Returns integer representing target priority, -1 if failed
|
||||
SDWORD aiBestNearestTarget(DROID *psDroid, BASE_OBJECT **ppsObj, int weapon_slot)
|
||||
{
|
||||
UDWORD i;
|
||||
SDWORD bestMod,newMod,damage,targetTypeBonus;
|
||||
BASE_OBJECT *psTarget, *psObj, *bestTarget;
|
||||
BOOL electronic = FALSE;
|
||||
WEAPON_EFFECT weaponEffect;
|
||||
UDWORD i;
|
||||
SDWORD bestMod,newMod,failure=-1;
|
||||
BASE_OBJECT *psTarget,*friendlyObj,*bestTarget,*targetInQuestion,*tempTarget;
|
||||
BOOL electronic = FALSE;
|
||||
STRUCTURE *targetStructure;
|
||||
DROID *targetDroid;
|
||||
WEAPON_EFFECT weaponEffect;
|
||||
DROID *friendlyDroid;
|
||||
|
||||
if ((psDroid->id % 8) == (frameGetFrameNumber() % 8))
|
||||
{
|
||||
droidGetNaybors(psDroid);
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//don't bother looking if empty vtol droid
|
||||
if (vtolEmpty(psDroid))
|
||||
{
|
||||
return FALSE;
|
||||
return failure;
|
||||
}
|
||||
|
||||
/* Return if have no weapons */
|
||||
// Watermelon:added a protection against no weapon droid 'numWeaps'
|
||||
// The ai orders a non-combat droid to patrol = crash without it...
|
||||
if(psDroid->asWeaps[0].nStat == 0 || psDroid->numWeaps == 0)
|
||||
return FALSE;
|
||||
return failure;
|
||||
|
||||
droidGetNaybors(psDroid);
|
||||
|
||||
//weaponMod = asWeaponModifier[weaponEffect][(asPropulsionStats + ((DROID*)psObj)->asBits[COMP_PROPULSION].nStat)->propulsionType];
|
||||
weaponEffect = ((WEAPON_STATS *)(asWeaponStats + psDroid->asWeaps[weapon_slot].nStat))->weaponEffect;
|
||||
|
@ -110,161 +108,132 @@ BOOL aiBestNearestTarget(DROID *psDroid, BASE_OBJECT **ppsObj, int weapon_slot)
|
|||
bestMod = 0;
|
||||
for (i=0; i< numNaybors; i++)
|
||||
{
|
||||
if (asDroidNaybors[i].psObj->player != psDroid->player &&
|
||||
(asDroidNaybors[i].psObj->type == OBJ_DROID ||
|
||||
asDroidNaybors[i].psObj->type == OBJ_STRUCTURE) &&
|
||||
asDroidNaybors[i].psObj->visible[psDroid->player] &&
|
||||
!aiCheckAlliances(asDroidNaybors[i].psObj->player,psDroid->player))
|
||||
friendlyObj = NULL;
|
||||
targetInQuestion = asDroidNaybors[i].psObj;
|
||||
|
||||
/* This is a friendly unit, check if we can reuse its target */
|
||||
if(targetInQuestion->player == psDroid->player ||
|
||||
aiCheckAlliances(targetInQuestion->player,psDroid->player))
|
||||
{
|
||||
psObj = asDroidNaybors[i].psObj;
|
||||
if ( validTarget((BASE_OBJECT *)psDroid, psObj) == 1)
|
||||
friendlyObj = targetInQuestion;
|
||||
targetInQuestion = NULL;
|
||||
|
||||
/* Can we see what it is doing? */
|
||||
if(friendlyObj->visible[psDroid->player])
|
||||
{
|
||||
if(friendlyObj->type == OBJ_DROID)
|
||||
{
|
||||
friendlyDroid = ((DROID *)friendlyObj);
|
||||
|
||||
/* See if friendly droid has a target */
|
||||
tempTarget = friendlyDroid->psActionTarget[0];
|
||||
if(tempTarget != NULL)
|
||||
{
|
||||
//make sure a weapon droid is targeting it
|
||||
if(friendlyDroid->numWeaps > 0)
|
||||
{
|
||||
// make sure this target wasn't assigned explicitly to this droid
|
||||
if(friendlyDroid->order != DORDER_ATTACK)
|
||||
{
|
||||
//(WEAPON_STATS *)(asWeaponStats + ((DROID *)friendlyObj)->asWeaps[0].nStat)->;
|
||||
|
||||
// make sure target is near enough
|
||||
if(dirtySqrt(psDroid->x,psDroid->y,tempTarget->x,tempTarget->y)
|
||||
< (psDroid->sensorRange * 2))
|
||||
{
|
||||
targetInQuestion = tempTarget; //consider this target
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(friendlyObj->type == OBJ_STRUCTURE)
|
||||
{
|
||||
targetInQuestion = ((STRUCTURE *)friendlyObj)->psTarget[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (targetInQuestion != NULL &&
|
||||
targetInQuestion != (BASE_OBJECT *)psDroid && //in case friendly unit had me as target
|
||||
(targetInQuestion->type == OBJ_DROID ||
|
||||
targetInQuestion->type == OBJ_STRUCTURE) &&
|
||||
targetInQuestion->visible[psDroid->player] &&
|
||||
targetInQuestion->player != psDroid->player &&
|
||||
!aiCheckAlliances(targetInQuestion->player,psDroid->player))
|
||||
{
|
||||
|
||||
if ( validTarget((BASE_OBJECT *)psDroid, targetInQuestion) == INVALID_TARGET)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (psObj->type == OBJ_DROID)
|
||||
else if (targetInQuestion->type == OBJ_DROID)
|
||||
{
|
||||
//in multiPlayer - don't attack Transporters with EW
|
||||
if (bMultiPlayer)
|
||||
{
|
||||
//if not electronic then valid target
|
||||
if (!electronic OR (electronic AND ((DROID *)psObj)->
|
||||
if (!electronic OR (electronic AND ((DROID *)targetInQuestion)->
|
||||
droidType != DROID_TRANSPORTER))
|
||||
{
|
||||
//only a valid target if NOT a transporter
|
||||
psTarget = psObj;
|
||||
// break;
|
||||
psTarget = targetInQuestion;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
psTarget = psObj;
|
||||
//break;
|
||||
psTarget = targetInQuestion;
|
||||
}
|
||||
}
|
||||
else if (psObj->type == OBJ_STRUCTURE)
|
||||
else if (targetInQuestion->type == OBJ_STRUCTURE)
|
||||
{
|
||||
if (electronic)
|
||||
{
|
||||
/*don't want to target structures with resistance of zero if
|
||||
using electronic warfare*/
|
||||
// if (((STRUCTURE *)psObj)->pStructureType->resistance != 0)// AND
|
||||
//((STRUCTURE *)psObj)->resistance >= (SDWORD)(((STRUCTURE *)
|
||||
//psObj)->pStructureType->resistance))
|
||||
//((STRUCTURE *)psObj)->resistance >= (SDWORD)
|
||||
//structureResistance(((STRUCTURE *)psObj)->pStructureType,
|
||||
//psObj->player))
|
||||
if (validStructResistance((STRUCTURE *)psObj))
|
||||
// if (((STRUCTURE *)targetInQuestion)->pStructureType->resistance != 0)// AND
|
||||
//((STRUCTURE *)targetInQuestion)->resistance >= (SDWORD)(((STRUCTURE *)
|
||||
//targetInQuestion)->pStructureType->resistance))
|
||||
//((STRUCTURE *)targetInQuestion)->resistance >= (SDWORD)
|
||||
//structureResistance(((STRUCTURE *)targetInQuestion)->pStructureType,
|
||||
//targetInQuestion->player))
|
||||
if (validStructResistance((STRUCTURE *)targetInQuestion))
|
||||
{
|
||||
psTarget = psObj;
|
||||
//break;
|
||||
psTarget = targetInQuestion;
|
||||
}
|
||||
}
|
||||
//else if (((STRUCTURE *)psObj)->numWeaps > 0)
|
||||
else if (((STRUCTURE *)psObj)->asWeaps[weapon_slot].nStat > 0)
|
||||
//else if (((STRUCTURE *)targetInQuestion)->numWeaps > 0)
|
||||
else if (((STRUCTURE *)targetInQuestion)->asWeaps[weapon_slot].nStat > 0)
|
||||
{
|
||||
// structure with weapons - go for this
|
||||
psTarget = psObj;
|
||||
//break;
|
||||
psTarget = targetInQuestion;
|
||||
}
|
||||
else if ( ( ((STRUCTURE *)psObj)->pStructureType->type != REF_WALL
|
||||
&&((STRUCTURE *)psObj)->pStructureType->type != REF_WALLCORNER
|
||||
else if ( ( ((STRUCTURE *)targetInQuestion)->pStructureType->type != REF_WALL
|
||||
&&((STRUCTURE *)targetInQuestion)->pStructureType->type != REF_WALLCORNER
|
||||
)
|
||||
|| driveModeActive()
|
||||
|| (bMultiPlayer && game.type == SKIRMISH && !isHumanPlayer(psDroid->player))
|
||||
)
|
||||
{
|
||||
psTarget = psObj;
|
||||
psTarget = targetInQuestion;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if our weapon is most effective against this object */
|
||||
if(psTarget != NULL && psTarget == psObj) //was assigned?
|
||||
if(psTarget != NULL && psTarget == targetInQuestion) //was assigned?
|
||||
{
|
||||
targetTypeBonus = 0; //Sensors/ecm droids, non-military structures get lower priority
|
||||
|
||||
if(psTarget->type == OBJ_DROID)
|
||||
{
|
||||
targetDroid = (DROID *)psTarget;
|
||||
|
||||
/* Calculate damage this target suffered */
|
||||
damage = targetDroid->originalBody - targetDroid->body;
|
||||
|
||||
/* See if this type of a droid should be prioritized */
|
||||
switch (targetDroid->droidType)
|
||||
{
|
||||
case DROID_CYBORG:
|
||||
case DROID_WEAPON:
|
||||
case DROID_CYBORG_SUPER:
|
||||
case DROID_COMMAND: //or should it get more priority?
|
||||
targetTypeBonus = WEIGHT_WEAPON_DROIDS;
|
||||
break;
|
||||
|
||||
case DROID_CONSTRUCT:
|
||||
case DROID_REPAIR:
|
||||
case DROID_CYBORG_CONSTRUCT:
|
||||
case DROID_CYBORG_REPAIR:
|
||||
targetTypeBonus = WEIGHT_SERVICE_DROIDS;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Now calculate the overall weight */
|
||||
newMod = asWeaponModifier[weaponEffect][(asPropulsionStats + targetDroid->asBits[COMP_PROPULSION].nStat)->propulsionType] //Weapon effect
|
||||
- (WEIGHT_DIST_TILE_DROID * (dirtySqrt(psDroid->x, psDroid->y,targetDroid->x,targetDroid->y) >> TILE_SHIFT) ) //substract WEIGHT_DIST_TILE_DROID per tile, 128 world units in a tile
|
||||
+ (damage * 10 / targetDroid->originalBody ) * WEIGHT_HEALTH_DROID //we prefer damaged droids
|
||||
+ targetTypeBonus; //some droid types have higher priority
|
||||
}
|
||||
else if (psTarget->type == OBJ_STRUCTURE)
|
||||
{
|
||||
targetStructure = (STRUCTURE *)psTarget;
|
||||
|
||||
/* Calculate damage this target suffered */
|
||||
damage = structureBody(targetStructure) - targetStructure->body;
|
||||
|
||||
/* See if this type of a structure should be prioritized */
|
||||
switch(targetStructure->pStructureType->type)
|
||||
{
|
||||
case REF_DEFENSE:
|
||||
targetTypeBonus = WEIGHT_WEAPON_STRUCT;
|
||||
break;
|
||||
|
||||
case REF_FACTORY:
|
||||
case REF_CYBORG_FACTORY:
|
||||
case REF_REPAIR_FACILITY:
|
||||
targetTypeBonus = WEIGHT_MILITARY_STRUCT;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Now calculate the overall weight */
|
||||
newMod = asStructStrengthModifier[weaponEffect][targetStructure->pStructureType->strength] //Weapon effect
|
||||
- (WEIGHT_DIST_TILE_STRUCT * (dirtySqrt(psDroid->x, psDroid->y,targetStructure->x,targetStructure->y) >> TILE_SHIFT) ) //substract WEIGHT_DIST_TILE_STRUCT per tile, 128 world units in a tile
|
||||
+ (damage * 10 / structureBody(targetStructure) ) * WEIGHT_HEALTH_STRUCT //we prefer damaged structures
|
||||
+ targetTypeBonus; //some structure types have higher priority
|
||||
|
||||
/* Go for unfinished structures only if nothing else found (same for non-visible structures) */
|
||||
if(targetStructure->status != SS_BUILT) //a decoy?
|
||||
newMod /= WEIGHT_STRUCT_NOTBUILT_F;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We prefer objects we can see and can attack immediately */
|
||||
if(!visibleObjWallBlock((BASE_OBJECT *)psDroid, psTarget))
|
||||
{
|
||||
newMod /= WEIGHT_NOT_VISIBLE_F;
|
||||
}
|
||||
newMod = targetAttackWeight(psTarget, (BASE_OBJECT *)psDroid, weapon_slot);
|
||||
|
||||
/* Remember this one if it's our best target so far */
|
||||
if( newMod > bestMod || bestTarget == NULL)
|
||||
if( newMod >= 0 && (newMod > bestMod || bestTarget == NULL))
|
||||
{
|
||||
bestMod = newMod;
|
||||
bestTarget = psObj;
|
||||
bestTarget = psTarget;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (bestTarget)
|
||||
|
@ -280,10 +249,118 @@ BOOL aiBestNearestTarget(DROID *psDroid, BASE_OBJECT **ppsObj, int weapon_slot)
|
|||
}
|
||||
|
||||
*ppsObj = bestTarget;
|
||||
return TRUE;
|
||||
return bestMod;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
return failure;
|
||||
}
|
||||
|
||||
/* Calculates attack priority for a certain target */
|
||||
SDWORD targetAttackWeight(BASE_OBJECT *psTarget, BASE_OBJECT *psAttacker, SDWORD weapon_slot)
|
||||
{
|
||||
SDWORD targetTypeBonus,damage,attackWeight=0,noTarget=-1;
|
||||
DROID *targetDroid;
|
||||
STRUCTURE *targetStructure;
|
||||
WEAPON_EFFECT weaponEffect;
|
||||
|
||||
if(psTarget == NULL || psAttacker == NULL){
|
||||
return noTarget;
|
||||
}
|
||||
|
||||
targetTypeBonus = 0; //Sensors/ecm droids, non-military structures get lower priority
|
||||
|
||||
/* Get attacker weapon effect */
|
||||
if(psAttacker->type == OBJ_DROID){
|
||||
weaponEffect = ((WEAPON_STATS *)(asWeaponStats + ((DROID *)psAttacker)->asWeaps[weapon_slot].nStat))->weaponEffect;
|
||||
}else if(psAttacker->type == OBJ_STRUCTURE){
|
||||
weaponEffect = ((WEAPON_STATS *)(asWeaponStats + ((STRUCTURE *)psAttacker)->asWeaps[weapon_slot].nStat))->weaponEffect;
|
||||
}
|
||||
else /* feature */
|
||||
{
|
||||
ASSERT(FALSE, "targetAttackWeight: Invalid attacker object type");
|
||||
return noTarget;
|
||||
}
|
||||
|
||||
/* Calculate attack weight */
|
||||
if(psTarget->type == OBJ_DROID)
|
||||
{
|
||||
targetDroid = (DROID *)psTarget;
|
||||
|
||||
/* Calculate damage this target suffered */
|
||||
damage = targetDroid->originalBody - targetDroid->body;
|
||||
|
||||
/* See if this type of a droid should be prioritized */
|
||||
switch (targetDroid->droidType)
|
||||
{
|
||||
case DROID_CYBORG:
|
||||
case DROID_WEAPON:
|
||||
case DROID_CYBORG_SUPER:
|
||||
case DROID_COMMAND: //or should it get more priority?
|
||||
targetTypeBonus = WEIGHT_WEAPON_DROIDS;
|
||||
break;
|
||||
|
||||
case DROID_CONSTRUCT:
|
||||
case DROID_REPAIR:
|
||||
case DROID_CYBORG_CONSTRUCT:
|
||||
case DROID_CYBORG_REPAIR:
|
||||
targetTypeBonus = WEIGHT_SERVICE_DROIDS;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Now calculate the overall weight */
|
||||
attackWeight = asWeaponModifier[weaponEffect][(asPropulsionStats + targetDroid->asBits[COMP_PROPULSION].nStat)->propulsionType] //Weapon effect
|
||||
- (WEIGHT_DIST_TILE_DROID * (dirtySqrt(psAttacker->x, psAttacker->y,targetDroid->x,targetDroid->y) >> TILE_SHIFT) ) //substract WEIGHT_DIST_TILE_DROID per tile, 128 world units in a tile
|
||||
+ (damage * 10 / targetDroid->originalBody ) * WEIGHT_HEALTH_DROID //we prefer damaged droids
|
||||
+ targetTypeBonus; //some droid types have higher priority
|
||||
}
|
||||
else if(psTarget->type == OBJ_STRUCTURE)
|
||||
{
|
||||
targetStructure = (STRUCTURE *)psTarget;
|
||||
|
||||
/* Calculate damage this target suffered */
|
||||
damage = structureBody(targetStructure) - targetStructure->body;
|
||||
|
||||
/* See if this type of a structure should be prioritized */
|
||||
switch(targetStructure->pStructureType->type)
|
||||
{
|
||||
case REF_DEFENSE:
|
||||
targetTypeBonus = WEIGHT_WEAPON_STRUCT;
|
||||
break;
|
||||
|
||||
case REF_RESOURCE_EXTRACTOR:
|
||||
targetTypeBonus = WEIGHT_DERRICK_STRUCT;
|
||||
break;
|
||||
|
||||
case REF_FACTORY:
|
||||
case REF_CYBORG_FACTORY:
|
||||
case REF_REPAIR_FACILITY:
|
||||
targetTypeBonus = WEIGHT_MILITARY_STRUCT;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Now calculate the overall weight */
|
||||
attackWeight = asStructStrengthModifier[weaponEffect][targetStructure->pStructureType->strength] //Weapon effect
|
||||
- (WEIGHT_DIST_TILE_STRUCT * (dirtySqrt(psAttacker->x, psAttacker->y,targetStructure->x,targetStructure->y) >> TILE_SHIFT) ) //substract WEIGHT_DIST_TILE_STRUCT per tile, 128 world units in a tile
|
||||
+ (damage * 10 / structureBody(targetStructure) ) * WEIGHT_HEALTH_STRUCT //we prefer damaged structures
|
||||
+ targetTypeBonus; //some structure types have higher priority
|
||||
|
||||
/* Go for unfinished structures only if nothing else found (same for non-visible structures) */
|
||||
if(targetStructure->status != SS_BUILT) //a decoy?
|
||||
attackWeight /= WEIGHT_STRUCT_NOTBUILT_F;
|
||||
|
||||
}
|
||||
else //a feature
|
||||
{
|
||||
return noTarget;
|
||||
}
|
||||
|
||||
/* We prefer objects we can see and can attack immediately */
|
||||
if(!visibleObjWallBlock((BASE_OBJECT *)psAttacker, psTarget))
|
||||
{
|
||||
attackWeight /= WEIGHT_NOT_VISIBLE_F;
|
||||
}
|
||||
|
||||
return attackWeight;
|
||||
}
|
||||
|
||||
|
||||
|
@ -336,7 +413,7 @@ static BOOL aiObjIsWall(BASE_OBJECT *psObj)
|
|||
/* See if there is a target in range */
|
||||
// Watermelon:to accept another int value weapon_slot
|
||||
BOOL aiChooseTarget(BASE_OBJECT *psObj,
|
||||
BASE_OBJECT **ppsTarget,int weapon_slot)
|
||||
BASE_OBJECT **ppsTarget,int weapon_slot, BOOL bUpdateTarget)
|
||||
{
|
||||
UDWORD radSquared;
|
||||
// UDWORD player;
|
||||
|
@ -348,6 +425,8 @@ BOOL aiChooseTarget(BASE_OBJECT *psObj,
|
|||
DROID *psCommander;
|
||||
BOOL bCommanderBlock;
|
||||
UDWORD sensorRange;
|
||||
SECONDARY_STATE state;
|
||||
SDWORD curTargetWeight=-1,newTargetWeight;
|
||||
//Watermelon:weapon_slot to store which turrent is InAttackRange
|
||||
|
||||
/* Get the sensor range */
|
||||
|
@ -398,7 +477,19 @@ BOOL aiChooseTarget(BASE_OBJECT *psObj,
|
|||
/* See if there is a something in range */
|
||||
if (psObj->type == OBJ_DROID)
|
||||
{
|
||||
if (aiBestNearestTarget((DROID *)psObj, &psTarget, weapon_slot))
|
||||
/* find a new target */
|
||||
newTargetWeight = aiBestNearestTarget((DROID *)psObj, &psTarget, weapon_slot);
|
||||
|
||||
/* Calculate weight of the current target of updating */
|
||||
if(bUpdateTarget){
|
||||
curTargetWeight = targetAttackWeight(((DROID *)psObj)->psActionTarget[0], psObj, weapon_slot);
|
||||
}
|
||||
|
||||
if (newTargetWeight >= 0 && //found a new target
|
||||
(!bUpdateTarget || //choosing a new target, don't care if current one is better
|
||||
(curTargetWeight <= 0) || //attacker had no valid target, use new one
|
||||
(newTargetWeight > (curTargetWeight + OLD_TARGET_THRESHOLD)) //updating and new target is better
|
||||
))
|
||||
{
|
||||
/*check its a valid target*/
|
||||
//Watermelon:Greater than 1 for now
|
||||
|
@ -407,7 +498,9 @@ BOOL aiChooseTarget(BASE_OBJECT *psObj,
|
|||
/* See if in sensor range */
|
||||
xdiff = psTarget->x - psObj->x;
|
||||
ydiff = psTarget->y - psObj->y;
|
||||
if (xdiff*xdiff + ydiff*ydiff < (SDWORD)radSquared)
|
||||
if ((xdiff*xdiff + ydiff*ydiff < (SDWORD)radSquared) || //target is within our sensor range
|
||||
(secondaryGetState((DROID *)psObj, DSO_HALTTYPE, &state) && //in case we got this target from a friendly unit see if can pursue it
|
||||
(state != DSS_HALT_HOLD))) //make sure it's guard or pursue
|
||||
{
|
||||
*ppsTarget = psTarget;
|
||||
return TRUE;
|
||||
|
@ -473,7 +566,7 @@ BOOL aiChooseTarget(BASE_OBJECT *psObj,
|
|||
{
|
||||
/*check its a valid target*/
|
||||
//Watermelon:Greater than 1 for now
|
||||
if ( (validTarget(psObj, psCStruct->psTarget[0]) > 1) &&
|
||||
if ( (validTarget(psObj, psCStruct->psTarget[0]) > INVALID_TARGET) &&
|
||||
aiStructHasRange((STRUCTURE *)psObj, psCStruct->psTarget[0], weapon_slot))
|
||||
{
|
||||
xdiff = (SDWORD)psCStruct->psTarget[0]->x - (SDWORD)psObj->x;
|
||||
|
@ -491,7 +584,7 @@ BOOL aiChooseTarget(BASE_OBJECT *psObj,
|
|||
psCStruct->psTarget[0] != NULL)
|
||||
{
|
||||
/*check its a valid target*/
|
||||
if ( (validTarget(psObj, psCStruct->psTarget[0]) > 1) &&
|
||||
if ( (validTarget(psObj, psCStruct->psTarget[0]) > INVALID_TARGET) &&
|
||||
aiStructHasRange((STRUCTURE *)psObj, psCStruct->psTarget[0], weapon_slot))
|
||||
{
|
||||
xdiff = (SDWORD)psCStruct->psTarget[0]->x - (SDWORD)psObj->x;
|
||||
|
@ -524,7 +617,7 @@ BOOL aiChooseTarget(BASE_OBJECT *psObj,
|
|||
{
|
||||
/*check its a valid target*/
|
||||
//Watermelon:Greater than 1 for now
|
||||
if ( (validTarget(psObj, psCurr) > 1) &&
|
||||
if ( (validTarget(psObj, psCurr) > INVALID_TARGET) &&
|
||||
!aiObjIsWall(psCurr))
|
||||
{
|
||||
// See if in sensor range and visible
|
||||
|
@ -650,9 +743,9 @@ BOOL aiChooseSensorTarget(BASE_OBJECT *psObj, BASE_OBJECT **ppsTarget)
|
|||
}
|
||||
|
||||
/* See if there is a something in range */
|
||||
if (psObj->type == OBJ_DROID)
|
||||
if (psObj->type == OBJ_DROID && CAN_UPDATE_NAYBORS( (DROID *)psObj ))
|
||||
{
|
||||
if (aiBestNearestTarget((DROID *)psObj, &psTarget, 0))
|
||||
if (aiBestNearestTarget((DROID *)psObj, &psTarget, 0) >= 0)
|
||||
{
|
||||
/* See if in sensor range */
|
||||
xdiff = psTarget->x - psObj->x;
|
||||
|
@ -761,17 +854,20 @@ void aiUpdateDroid(DROID *psDroid)
|
|||
//Watermelon:psTarget Array
|
||||
BASE_OBJECT *psTarget[DROID_MAXWEAPS];
|
||||
SECONDARY_STATE state;
|
||||
BOOL lookForTarget;
|
||||
BOOL lookForTarget,updateTarget;
|
||||
// BOOL bTemp;
|
||||
|
||||
ASSERT( PTRVALID(psDroid, sizeof(DROID)),
|
||||
"updateUnitAI: invalid Unit pointer" );
|
||||
|
||||
lookForTarget = TRUE;
|
||||
updateTarget = TRUE;
|
||||
|
||||
// don't look for a target if sulking
|
||||
if (psDroid->action == DACTION_SULK)
|
||||
{
|
||||
lookForTarget = FALSE;
|
||||
updateTarget = FALSE;
|
||||
}
|
||||
// don't look for a target if doing something else
|
||||
if (!orderState(psDroid, DORDER_NONE) &&
|
||||
|
@ -779,11 +875,32 @@ void aiUpdateDroid(DROID *psDroid)
|
|||
{
|
||||
lookForTarget = FALSE;
|
||||
}
|
||||
|
||||
/* Only try to update target if already have some target */
|
||||
if (psDroid->action != DACTION_ATTACK &&
|
||||
psDroid->action != DACTION_ATTACK_M &&
|
||||
psDroid->action != DACTION_MOVEFIRE &&
|
||||
psDroid->action != DACTION_MOVETOATTACK &&
|
||||
psDroid->action != DACTION_ROTATETOATTACK)
|
||||
{
|
||||
updateTarget = FALSE;
|
||||
}
|
||||
|
||||
/* Don't update target if we are sent to attack and reached
|
||||
attack destination (attacking our target) */
|
||||
if((orderState(psDroid, DORDER_ATTACK) || orderState(psDroid, DORDER_ATTACK_M))
|
||||
&& (psDroid->psActionTarget[0] == psDroid->psTarget[0]))
|
||||
{
|
||||
updateTarget = FALSE;
|
||||
}
|
||||
|
||||
// don't look for a target if there are any queued orders
|
||||
if (psDroid->listSize > 0)
|
||||
{
|
||||
lookForTarget = FALSE;
|
||||
updateTarget = FALSE;
|
||||
}
|
||||
|
||||
// horrible check to stop droids looking for a target if
|
||||
// they would switch to the guard order in the order update loop
|
||||
if ((psDroid->order == DORDER_NONE) &&
|
||||
|
@ -793,6 +910,7 @@ void aiUpdateDroid(DROID *psDroid)
|
|||
(state == DSS_HALT_GUARD))
|
||||
{
|
||||
lookForTarget = FALSE;
|
||||
updateTarget = FALSE;
|
||||
}
|
||||
|
||||
// don't allow units to start attacking if they will switch to guarding the commander
|
||||
|
@ -800,14 +918,15 @@ void aiUpdateDroid(DROID *psDroid)
|
|||
psDroid->psGroup->type == GT_COMMAND)
|
||||
{
|
||||
lookForTarget = FALSE;
|
||||
updateTarget = FALSE;
|
||||
}
|
||||
|
||||
if(bMultiPlayer && vtolDroid(psDroid) && isHumanPlayer(psDroid->player))
|
||||
{
|
||||
lookForTarget = FALSE;
|
||||
updateTarget = FALSE;
|
||||
}
|
||||
|
||||
|
||||
// do not choose another target if doing anything while guarding
|
||||
if (orderState(psDroid, DORDER_GUARD) &&
|
||||
(psDroid->action != DACTION_NONE))
|
||||
|
@ -823,14 +942,16 @@ void aiUpdateDroid(DROID *psDroid)
|
|||
// do not look for a target if droid is currently under direct control.
|
||||
if(driveModeActive() && (psDroid == driveGetDriven())) {
|
||||
lookForTarget = FALSE;
|
||||
updateTarget = FALSE;
|
||||
}
|
||||
|
||||
// only computer senosr droids in the single player game aquire targets
|
||||
// only computer sensor droids in the single player game aquire targets
|
||||
if ((psDroid->droidType == DROID_SENSOR && psDroid->player == selectedPlayer)
|
||||
&& !bMultiPlayer
|
||||
)
|
||||
{
|
||||
lookForTarget = FALSE;
|
||||
updateTarget = FALSE;
|
||||
}
|
||||
|
||||
// do not attack if the attack level is wrong
|
||||
|
@ -842,10 +963,32 @@ void aiUpdateDroid(DROID *psDroid)
|
|||
}
|
||||
}
|
||||
|
||||
/* Null target - see if there is an enemy to attack */
|
||||
if (lookForTarget &&
|
||||
aiChooseTarget((BASE_OBJECT *)psDroid, &psTarget[0], 0))
|
||||
/* Don't rebuild 'Naybor' list too often */
|
||||
if(!CAN_UPDATE_NAYBORS(psDroid))
|
||||
{
|
||||
lookForTarget = FALSE;
|
||||
}
|
||||
|
||||
/* For commanders and non-assigned non-commanders:
|
||||
look for a better target once in a while */
|
||||
if(!lookForTarget && updateTarget)
|
||||
{
|
||||
if((psDroid->numWeaps > 0) && ((psDroid->droidType == DROID_COMMAND) ||
|
||||
!(psDroid->psGroup && (psDroid->psGroup->type == GT_COMMAND)))) //not assigned to commander
|
||||
{
|
||||
if((psDroid->id % TARGET_UPD_SKIP_FRAMES) ==
|
||||
(frameGetFrameNumber() % TARGET_UPD_SKIP_FRAMES))
|
||||
{
|
||||
(void)updateAttackTarget((BASE_OBJECT*)psDroid, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Null target - see if there is an enemy to attack */
|
||||
if (lookForTarget && !updateTarget &&
|
||||
aiChooseTarget((BASE_OBJECT *)psDroid, &psTarget[0], 0, FALSE))
|
||||
{
|
||||
//console("Choosing first-time target");
|
||||
// my_error("",0,"","Droid(%s) attacking : %d\n",
|
||||
// psDroid->pName, psTarget->id );
|
||||
|
||||
|
@ -871,7 +1014,7 @@ can fire on the propulsion type of the target*/
|
|||
int validTarget(BASE_OBJECT *psObject, BASE_OBJECT *psTarget)
|
||||
{
|
||||
//Watermelon:return value int
|
||||
int ValidTarget = 1;
|
||||
int ValidTarget = INVALID_TARGET;
|
||||
int i;
|
||||
BOOL bTargetInAir;
|
||||
//BOOL bTargetInAir, bValidTarget;
|
||||
|
@ -975,3 +1118,43 @@ int validTarget(BASE_OBJECT *psObject, BASE_OBJECT *psTarget)
|
|||
|
||||
return ValidTarget;
|
||||
}
|
||||
|
||||
/* Make droid/structure look for a better target */
|
||||
BOOL updateAttackTarget(BASE_OBJECT * psAttacker, SDWORD weapon_slot)
|
||||
{
|
||||
BASE_OBJECT *psBetterTarget=NULL;
|
||||
DROID *psDroid;
|
||||
|
||||
psBetterTarget = NULL;
|
||||
|
||||
if(aiChooseTarget(psAttacker, &psBetterTarget, weapon_slot, TRUE)) //update target
|
||||
{
|
||||
//if(psAttacker->player == selectedPlayer)
|
||||
// console("GOT A NEW TARGET");
|
||||
|
||||
if(psAttacker->type == OBJ_DROID)
|
||||
{
|
||||
psDroid = (DROID *)psAttacker;
|
||||
if( orderState(psDroid, DORDER_NONE) ||
|
||||
orderState(psDroid, DORDER_GUARD) ||
|
||||
orderState(psDroid, DORDER_ATTACKTARGET))
|
||||
{
|
||||
orderDroidObj((DROID *)psAttacker, DORDER_ATTACKTARGET, psBetterTarget);
|
||||
}
|
||||
else //can't override current order
|
||||
{
|
||||
//psDroid->action = DACTION_MOVEFIRE;
|
||||
psDroid->psActionTarget[0] = psBetterTarget;
|
||||
}
|
||||
}
|
||||
else if (psAttacker->type == OBJ_STRUCTURE)
|
||||
{
|
||||
((STRUCTURE *)psAttacker)->psTarget[weapon_slot] = psBetterTarget;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
|
38
src/ai.h
38
src/ai.h
|
@ -20,22 +20,27 @@
|
|||
#define ALLIANCES_TEAMS 2 //locked teams
|
||||
//#define GROUP_WINS 2
|
||||
|
||||
/* Weights used for target selection code */
|
||||
#define WEIGHT_DIST_TILE 11 //In points used in weaponmodifier.txt and structuremodifier.txt
|
||||
#define WEIGHT_DIST_TILE_DROID WEIGHT_DIST_TILE //How much weight a distance of 1 tile (128 world units) has when looking for the best nearest target
|
||||
#define WEIGHT_DIST_TILE_STRUCT WEIGHT_DIST_TILE
|
||||
#define WEIGHT_HEALTH_DROID WEIGHT_DIST_TILE //How much weight unit damage has (per 10% of damage, ie for each 10% of damage we add WEIGHT_HEALTH_DROID)
|
||||
//~100% damage should be ~8 tiles (max sensor range)
|
||||
#define WEIGHT_HEALTH_STRUCT WEIGHT_DIST_TILE
|
||||
/* Weights used for target selection code,
|
||||
* target distance is used as 'common currency'
|
||||
*/
|
||||
#define WEIGHT_DIST_TILE 11 //In points used in weaponmodifier.txt and structuremodifier.txt
|
||||
#define WEIGHT_DIST_TILE_DROID WEIGHT_DIST_TILE //How much weight a distance of 1 tile (128 world units) has when looking for the best nearest target
|
||||
#define WEIGHT_DIST_TILE_STRUCT WEIGHT_DIST_TILE
|
||||
#define WEIGHT_HEALTH_DROID WEIGHT_DIST_TILE //How much weight unit damage has (per 10% of damage, ie for each 10% of damage we add WEIGHT_HEALTH_DROID)
|
||||
//~100% damage should be ~8 tiles (max sensor range)
|
||||
#define WEIGHT_HEALTH_STRUCT WEIGHT_DIST_TILE
|
||||
|
||||
#define WEIGHT_NOT_VISIBLE_F 10 //We really don't like objects we can't see
|
||||
#define WEIGHT_NOT_VISIBLE_F 10 //We really don't like objects we can't see
|
||||
|
||||
#define WEIGHT_SERVICE_DROIDS (WEIGHT_DIST_TILE_DROID * 5) //We don't want them to be repairing droids or structures while we are after them
|
||||
#define WEIGHT_WEAPON_DROIDS (WEIGHT_DIST_TILE_DROID * 3) //We prefer to go after anything that has a gun and can hurt us
|
||||
#define WEIGHT_MILITARY_STRUCT WEIGHT_DIST_TILE_STRUCT //Droid/cyborg factories, repair facility; shouldn't have too much weight
|
||||
#define WEIGHT_WEAPON_STRUCT WEIGHT_WEAPON_DROIDS //Same as weapon droids (?)
|
||||
#define WEIGHT_SERVICE_DROIDS (WEIGHT_DIST_TILE_DROID * 5) //We don't want them to be repairing droids or structures while we are after them
|
||||
#define WEIGHT_WEAPON_DROIDS (WEIGHT_DIST_TILE_DROID * 3) //We prefer to go after anything that has a gun and can hurt us
|
||||
#define WEIGHT_MILITARY_STRUCT WEIGHT_DIST_TILE_STRUCT //Droid/cyborg factories, repair facility; shouldn't have too much weight
|
||||
#define WEIGHT_WEAPON_STRUCT WEIGHT_WEAPON_DROIDS //Same as weapon droids (?)
|
||||
#define WEIGHT_DERRICK_STRUCT (WEIGHT_WEAPON_STRUCT + WEIGHT_DIST_TILE_STRUCT * 4) //Even if it's 4 tiles further away than defenses we still choose it
|
||||
|
||||
#define WEIGHT_STRUCT_NOTBUILT_F 8 //Humans won't fool us anymore!
|
||||
#define WEIGHT_STRUCT_NOTBUILT_F 8 //Humans won't fool us anymore!
|
||||
|
||||
#define OLD_TARGET_THRESHOLD (WEIGHT_DIST_TILE * 4) //it only makes sense to switch target if new one is 4+ tiles closer
|
||||
|
||||
// alliances
|
||||
extern UBYTE alliances[MAX_PLAYERS][MAX_PLAYERS];
|
||||
|
@ -55,12 +60,13 @@ extern BOOL aiInitDroid(DROID *psDroid);
|
|||
/* Do the AI for a droid */
|
||||
extern void aiUpdateDroid(DROID *psDroid);
|
||||
|
||||
// Find the nearest target to a droid added int weapon_slot
|
||||
extern BOOL aiBestNearestTarget(DROID *psDroid, BASE_OBJECT **ppsObj, int weapon_slot);
|
||||
// Find the nearest best target for a droid
|
||||
// returns integer representing quality of choice, -1 if failed
|
||||
extern SDWORD aiBestNearestTarget(DROID *psDroid, BASE_OBJECT **ppsObj, int weapon_slot);
|
||||
|
||||
/* See if there is a target in range added int weapon_slot*/
|
||||
extern BOOL aiChooseTarget(BASE_OBJECT *psObj,
|
||||
BASE_OBJECT **ppsTarget, int weapon_slot);
|
||||
BASE_OBJECT **ppsTarget, int weapon_slot, BOOL bUpdateTarget);
|
||||
|
||||
/*set the droid to attack if wihin range otherwise move to target*/
|
||||
extern void attackTarget(DROID *psDroid, BASE_OBJECT *psTarget);
|
||||
|
|
|
@ -129,7 +129,7 @@ void combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget, in
|
|||
psStats = asWeaponStats + psWeap->nStat;
|
||||
|
||||
//check valid weapon/prop combination
|
||||
if (validTarget(psAttacker, psTarget) == 1)
|
||||
if (validTarget(psAttacker, psTarget) == INVALID_TARGET)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
12
src/droid.c
12
src/droid.c
|
@ -208,18 +208,13 @@ BOOL droidDamage(DROID *psDroid, UDWORD damage, UDWORD weaponClass, UDWORD weapo
|
|||
//TOP
|
||||
if (angle == HIT_ANGLE_TOP)
|
||||
{
|
||||
impact_side = HIT_SIDE_TOP; //4
|
||||
impact_side = HIT_SIDE_TOP; //4
|
||||
}
|
||||
//BOTTOM
|
||||
else if (angle == HIT_ANGLE_BOTTOM)
|
||||
{
|
||||
impact_side = HIT_SIDE_BOTTOM; //5
|
||||
}
|
||||
//FRONT
|
||||
else if (angle <= 45 || angle >= 315)
|
||||
{
|
||||
impact_side = HIT_SIDE_FRONT; //0
|
||||
}
|
||||
//RIGHT
|
||||
else if (angle > 45 && angle < 135)
|
||||
{
|
||||
|
@ -235,6 +230,11 @@ BOOL droidDamage(DROID *psDroid, UDWORD damage, UDWORD weaponClass, UDWORD weapo
|
|||
{
|
||||
impact_side = HIT_SIDE_LEFT; //2
|
||||
}
|
||||
//FRONT - default
|
||||
else //if (angle <= 45 || angle >= 315)
|
||||
{
|
||||
impact_side = HIT_SIDE_FRONT; //0
|
||||
}
|
||||
|
||||
debug( LOG_ATTACK, "unitDamage(%d): body %d armour %d damage: %d\n",
|
||||
psDroid->id, psDroid->body, psDroid->armour[impact_side][WC_KINETIC], damage);
|
||||
|
|
|
@ -31,7 +31,7 @@ extern DROID_TEMPLATE *apsDroidTemplates[MAX_PLAYERS];
|
|||
|
||||
|
||||
/* The range for neighbouring objects */
|
||||
#define NAYBOR_RANGE (TILE_UNITS*8)
|
||||
#define NAYBOR_RANGE (TILE_UNITS*9) //range of lancer, BB, TK etc
|
||||
|
||||
//used to stop structures being built too near the edge and droids being placed down - pickATile
|
||||
#define TOO_NEAR_EDGE 3
|
||||
|
@ -52,7 +52,7 @@ typedef enum
|
|||
} PICKTILE;
|
||||
|
||||
/* Store for the objects near the droid currently being updated */
|
||||
#define MAX_NAYBORS 100
|
||||
#define MAX_NAYBORS 120
|
||||
extern NAYBOR_INFO asDroidNaybors[MAX_NAYBORS];
|
||||
extern UDWORD numNaybors;
|
||||
|
||||
|
|
|
@ -632,6 +632,12 @@ void kf_ToggleCamera( void )
|
|||
camToggleStatus();
|
||||
}
|
||||
|
||||
/* Toggle 'watch' window on/off */
|
||||
void kf_ToggleWatchWindow( void )
|
||||
{
|
||||
(void)addDebugMenu(!DebugMenuUp);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/* Simulates a close down */
|
||||
|
|
|
@ -207,6 +207,8 @@ extern void kf_NormalSpeed( void );
|
|||
void kf_ToggleRadarTerrain( void ); //radar terrain
|
||||
void kf_ToggleRadarAllyEnemy( void ); //enemy/ally color toggle
|
||||
|
||||
extern void kf_ToggleWatchWindow( void );
|
||||
|
||||
extern int fogCol;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -158,7 +158,6 @@ _keymapsave keyMapSaveTable[] =
|
|||
kf_SelectAllUnits,
|
||||
kf_SelectAllVTOLs,
|
||||
kf_SelectAllWheeled,
|
||||
kf_FinishResearch,
|
||||
kf_FrameRate,
|
||||
kf_SelectAllSameType,
|
||||
kf_SelectNextFactory,
|
||||
|
@ -224,6 +223,7 @@ _keymapsave keyMapSaveTable[] =
|
|||
kf_DownDroidScale,
|
||||
kf_RaiseGamma,
|
||||
kf_LowerGamma,
|
||||
kf_ToggleWatchWindow,
|
||||
|
||||
NULL // last function!
|
||||
};
|
||||
|
@ -424,6 +424,7 @@ void keyInitMappings( BOOL bForceDefaults )
|
|||
keyAddMapping(KEYMAP__DEBUG,KEY_LCTRL,KEY_G,KEYMAP_PRESSED,kf_ToggleGodMode, "Toggle god Mode Status");
|
||||
keyAddMapping(KEYMAP__DEBUG,KEY_LCTRL,KEY_O,KEYMAP_PRESSED,kf_ChooseOptions, "Display Options Screen");
|
||||
keyAddMapping(KEYMAP__DEBUG,KEY_LCTRL,KEY_X,KEYMAP_PRESSED,kf_FinishResearch, "Complete current research");
|
||||
keyAddMapping(KEYMAP__DEBUG,KEY_LALT,KEY_SPACE,KEYMAP_PRESSED,kf_ToggleWatchWindow, "Toggle watch window");
|
||||
|
||||
saveKeyMap(); // save out the default key mappings.
|
||||
|
||||
|
|
|
@ -1120,9 +1120,31 @@ void addMultiPlayer(UDWORD player,UDWORD pos)
|
|||
}
|
||||
}
|
||||
|
||||
/* Output some text to the debug menu */
|
||||
void setDebugMenuEntry(char *entry, SDWORD index)
|
||||
{
|
||||
BOOL bAddingNew = FALSE;
|
||||
|
||||
/* New one? */
|
||||
if(!strcmp(debugMenuEntry[index],""))
|
||||
{
|
||||
bAddingNew = TRUE;
|
||||
}
|
||||
|
||||
/* Set */
|
||||
strcpy(debugMenuEntry[index], entry);
|
||||
|
||||
/* Re-open it if already open to recalculate height */
|
||||
if(DebugMenuUp && bAddingNew)
|
||||
{
|
||||
intCloseDebugMenuNoAnim();
|
||||
(void)addDebugMenu(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
void intCloseDebugMenuNoAnim(void)
|
||||
{
|
||||
widgDelete(psWScreen, DEBUGMENU_CLOSE);
|
||||
//widgDelete(psWScreen, DEBUGMENU_CLOSE);
|
||||
widgDelete(psWScreen, DEBUGMENU);
|
||||
DebugMenuUp = FALSE;
|
||||
//intMode = INT_NORMAL;
|
||||
|
@ -1192,7 +1214,7 @@ BOOL addDebugMenu(BOOL bAdd)
|
|||
}
|
||||
|
||||
// Add the close button.
|
||||
memset(&sButInit, 0, sizeof(W_BUTINIT));
|
||||
/* memset(&sButInit, 0, sizeof(W_BUTINIT));
|
||||
sButInit.formID = DEBUGMENU;
|
||||
sButInit.id = DEBUGMENU_CLOSE;
|
||||
sButInit.style = WBUT_PLAIN;
|
||||
|
@ -1207,7 +1229,7 @@ BOOL addDebugMenu(BOOL bAdd)
|
|||
if (!widgAddButton(psWScreen, &sButInit))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
} */
|
||||
|
||||
DebugMenuUp = TRUE;
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ extern BOOL intAddMultiMenu (void);
|
|||
|
||||
extern BOOL addDebugMenu (BOOL bAdd);
|
||||
extern void intCloseDebugMenuNoAnim (void);
|
||||
extern void setDebugMenuEntry(char *entry, SDWORD index);
|
||||
|
||||
extern BOOL MultiMenuUp;
|
||||
extern BOOL ClosingMultiMenu;
|
||||
|
@ -31,13 +32,13 @@ extern BOOL DebugMenuUp;
|
|||
|
||||
//extern void intDisplayMiniMultiMenu (void);
|
||||
|
||||
#define MULTIMENU 10600
|
||||
#define MULTIMENU_FORM MULTIMENU
|
||||
#define MULTIMENU 10600
|
||||
#define MULTIMENU_FORM MULTIMENU
|
||||
|
||||
#define DEBUGMENU 106000
|
||||
#define DEBUGMENU_CLOSE (DEBUGMENU+1)
|
||||
#define DEBUGMENU_CLOSE (DEBUGMENU+1)
|
||||
#define DEBUGMENU_MAX_ENTRIES 10
|
||||
#define DEBUGMENU_BUTTON (DEBUGMENU_CLOSE + DEBUGMENU_MAX_ENTRIES)
|
||||
#define DEBUGMENU_BUTTON (DEBUGMENU_CLOSE + DEBUGMENU_MAX_ENTRIES)
|
||||
|
||||
extern char debugMenuEntry[DEBUGMENU_MAX_ENTRIES][MAX_STR_LENGTH];
|
||||
|
||||
|
|
17
src/order.c
17
src/order.c
|
@ -101,6 +101,7 @@ void initRunData(void)
|
|||
}
|
||||
}
|
||||
|
||||
//FIXME: unit doesn't shoot while returning to the guard position
|
||||
// check whether a droid has to move back to the thing it is guarding
|
||||
void orderCheckGuardPosition(DROID *psDroid, SDWORD range)
|
||||
{
|
||||
|
@ -580,9 +581,9 @@ if(!bMultiPlayer || myResponsibility(psDroid->player))
|
|||
case DORDER_SCOUT:
|
||||
case DORDER_PATROL:
|
||||
// if there is an enemy around, attack it
|
||||
if ( (psDroid->action == DACTION_MOVE) &&
|
||||
(secondaryGetState(psDroid, DSO_ATTACK_LEVEL, &state) && (state == DSS_ALEV_ALWAYS)) &&
|
||||
aiBestNearestTarget(psDroid, &psObj, 0) )
|
||||
if ( (psDroid->action == DACTION_MOVE) && CAN_UPDATE_NAYBORS(psDroid) &&
|
||||
(secondaryGetState(psDroid, DSO_ATTACK_LEVEL, &state) && (state == DSS_ALEV_ALWAYS)) &&
|
||||
aiBestNearestTarget(psDroid, &psObj, 0) >= 0 )
|
||||
{
|
||||
switch (psDroid->droidType)
|
||||
{
|
||||
|
@ -643,11 +644,11 @@ if(!bMultiPlayer || myResponsibility(psDroid->player))
|
|||
}
|
||||
}
|
||||
break;
|
||||
case DORDER_CIRCLE:
|
||||
case DORDER_CIRCLE:
|
||||
// if there is an enemy around, attack it
|
||||
if ( (psDroid->action == DACTION_MOVE) &&
|
||||
(secondaryGetState(psDroid, DSO_ATTACK_LEVEL, &state) && (state == DSS_ALEV_ALWAYS)) &&
|
||||
aiBestNearestTarget(psDroid, &psObj, 0) )
|
||||
if ( (psDroid->action == DACTION_MOVE) && CAN_UPDATE_NAYBORS(psDroid) &&
|
||||
(secondaryGetState(psDroid, DSO_ATTACK_LEVEL, &state) && (state == DSS_ALEV_ALWAYS)) &&
|
||||
aiBestNearestTarget(psDroid, &psObj, 0) >= 0)
|
||||
{
|
||||
switch (psDroid->droidType)
|
||||
{
|
||||
|
@ -3249,7 +3250,7 @@ DROID_ORDER chooseOrderObj(DROID *psDroid, BASE_OBJECT *psObj)
|
|||
&& !aiCheckAlliances(psObj->player , psDroid->player) )
|
||||
{
|
||||
//check valid weapon/prop combination
|
||||
if (validTarget((BASE_OBJECT *)psDroid, psObj) == 1)
|
||||
if (validTarget((BASE_OBJECT *)psDroid, psObj) == INVALID_TARGET)
|
||||
{
|
||||
order = DORDER_NONE;
|
||||
}
|
||||
|
|
|
@ -1690,7 +1690,7 @@ BOOL scrSkVtolEnableCheck(void)
|
|||
// ********************************************************************************************
|
||||
BOOL scrSkGetFactoryCapacity(void)
|
||||
{
|
||||
SDWORD count=0,structure;
|
||||
SDWORD count=0;
|
||||
STRUCTURE *psStructure;
|
||||
|
||||
if (!stackPopParams(1,ST_STRUCTURE, &psStructure))
|
||||
|
|
|
@ -10590,7 +10590,6 @@ BOOL scrDebugMenu(void)
|
|||
BOOL scrSetDebugMenuEntry(void)
|
||||
{
|
||||
SDWORD index;
|
||||
BOOL bAddingNew = FALSE;
|
||||
|
||||
if (!stackPopParams(2, VAL_STRING, &strParam1, VAL_INT, &index))
|
||||
{
|
||||
|
@ -10598,21 +10597,7 @@ BOOL scrSetDebugMenuEntry(void)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
/* New one? */
|
||||
if(!strcmp(debugMenuEntry[index],""))
|
||||
{
|
||||
bAddingNew = TRUE;
|
||||
}
|
||||
|
||||
/* Set */
|
||||
strcpy(debugMenuEntry[index], strParam1);
|
||||
|
||||
/* Re-open it if already open to recalculate height */
|
||||
if(DebugMenuUp && bAddingNew)
|
||||
{
|
||||
intCloseDebugMenuNoAnim();
|
||||
(void)addDebugMenu(TRUE);
|
||||
}
|
||||
setDebugMenuEntry(strParam1, index);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -3995,7 +3995,7 @@ static void aiUpdateStructure(STRUCTURE *psStructure)
|
|||
{
|
||||
if ((psStructure->id % 20) == (frameGetFrameNumber() % 20))
|
||||
{
|
||||
if (aiChooseTarget((BASE_OBJECT *)psStructure, &psChosenObj, i))
|
||||
if (aiChooseTarget((BASE_OBJECT *)psStructure, &psChosenObj, i, TRUE)) //structures always update their targets
|
||||
{
|
||||
debug( LOG_ATTACK, "Struct(%d) attacking : %d\n",
|
||||
psStructure->id, psChosenObj->id );
|
||||
|
|
Loading…
Reference in New Issue