Step one towards vector based projectiles
git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@5106 4a71c877-e1ca-e34f-864e-861f7616d084master
parent
974b5aacaa
commit
202ebc32fb
51
src/combat.c
51
src/combat.c
|
@ -98,16 +98,12 @@ void combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget, in
|
|||
WEAPON_STATS *psStats;
|
||||
UDWORD xDiff, yDiff, distSquared;
|
||||
UDWORD dice, damLevel;
|
||||
SDWORD missDir, missDist, missX,missY;
|
||||
SDWORD resultHitChance=0,baseHitChance=0,fireChance;
|
||||
UDWORD firePause;
|
||||
SDWORD targetDir,dirDiff;
|
||||
SDWORD longRange;
|
||||
DROID *psDroid = NULL;
|
||||
int minOffset = 5;
|
||||
//Watermelon:predicted X,Y offset per sec
|
||||
SDWORD predictX;
|
||||
SDWORD predictY;
|
||||
SDWORD dist;
|
||||
|
||||
CHECK_OBJECT(psAttacker);
|
||||
|
@ -351,29 +347,35 @@ void combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget, in
|
|||
// see if we were lucky to hit the target
|
||||
if (dice <= resultHitChance)
|
||||
{
|
||||
//Watermelon:predicted X,Y offset per sec
|
||||
Vector3i predict;
|
||||
|
||||
/* Kerrrbaaang !!!!! a hit */
|
||||
//Watermelon:Target prediction
|
||||
if(psTarget->type == OBJ_DROID)
|
||||
{
|
||||
predictX = (SDWORD)(trigSin( ((DROID *)psTarget)->sMove.moveDir ) * ((DROID *)psTarget)->sMove.speed * dist / psStats->flightSpeed );
|
||||
predictX += psTarget->pos.x;
|
||||
predictY = (SDWORD)(trigCos( ((DROID *)psTarget)->sMove.moveDir ) * ((DROID *)psTarget)->sMove.speed * dist / psStats->flightSpeed );
|
||||
predictY += psTarget->pos.y;
|
||||
predict.x = trigSin( ((DROID *)psTarget)->sMove.moveDir ) * ((DROID *)psTarget)->sMove.speed * dist / psStats->flightSpeed;
|
||||
predict.x += psTarget->pos.x;
|
||||
predict.y = trigCos( ((DROID *)psTarget)->sMove.moveDir ) * ((DROID *)psTarget)->sMove.speed * dist / psStats->flightSpeed;
|
||||
predict.y += psTarget->pos.y;
|
||||
|
||||
// Make sure we don't pass any negative or out of bounds numbers to proj_SendProjectile
|
||||
predictX = MAX(predictX, 0);
|
||||
predictX = MIN(predictX, world_coord(mapWidth - 1));
|
||||
predictY = MAX(predictY, 0);
|
||||
predictY = MIN(predictY, world_coord(mapHeight - 1));
|
||||
predict.x = MAX(predict.x, 0);
|
||||
predict.x = MIN(predict.x, world_coord(mapWidth - 1));
|
||||
predict.y = MAX(predict.y, 0);
|
||||
predict.y = MIN(predict.y, world_coord(mapHeight - 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
predictX = psTarget->pos.x;
|
||||
predictY = psTarget->pos.y;
|
||||
predict.x = psTarget->pos.x;
|
||||
predict.y = psTarget->pos.y;
|
||||
}
|
||||
|
||||
predict.z = psTarget->pos.z;
|
||||
|
||||
debug(LOG_SENSOR, "combFire: Accurate prediction range (%d)", dice);
|
||||
if (!proj_SendProjectile(psWeap, psAttacker, psAttacker->player,
|
||||
predictX, predictY, psTarget->pos.z, psTarget, false, false, weapon_slot))
|
||||
predict, psTarget, false, false, weapon_slot))
|
||||
{
|
||||
/* Out of memory - we can safely ignore this */
|
||||
debug(LOG_ERROR, "Out of memory");
|
||||
|
@ -392,19 +394,20 @@ void combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget, in
|
|||
|
||||
missed:
|
||||
/* Deal with a missed shot */
|
||||
{
|
||||
int missDir = rand() % BUL_MAXSCATTERDIR, missDist = 2 * (100 - resultHitChance);
|
||||
Vector3i miss = {
|
||||
aScatterDir[missDir].x * missDist + psTarget->pos.x + minOffset,
|
||||
aScatterDir[missDir].y * missDist + psTarget->pos.y + minOffset,
|
||||
psTarget->pos.z
|
||||
};
|
||||
|
||||
missDist = 2 * (100 - resultHitChance);
|
||||
missDir = rand() % BUL_MAXSCATTERDIR;
|
||||
missX = aScatterDir[missDir].x * missDist + psTarget->pos.x + minOffset;
|
||||
missY = aScatterDir[missDir].y * missDist + psTarget->pos.y + minOffset;
|
||||
|
||||
debug(LOG_NEVER, "combFire: Missed shot (%d) ended up at (%4d,%4d)", dice, missX, missY);
|
||||
debug(LOG_NEVER, "combFire: Missed shot (%d) ended up at (%4d,%4d)", dice, miss.x, miss.y);
|
||||
|
||||
/* Fire off the bullet to the miss location. The miss is only visible if the player owns
|
||||
* the target. (Why? - Per) */
|
||||
proj_SendProjectile(psWeap, psAttacker, psAttacker->player, missX,missY, psTarget->pos.z, NULL,
|
||||
psTarget->player == selectedPlayer, false, weapon_slot);
|
||||
|
||||
proj_SendProjectile(psWeap, psAttacker, psAttacker->player, miss, NULL, psTarget->player == selectedPlayer, false, weapon_slot);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -383,9 +383,15 @@ BOOL recvLasSat()
|
|||
|
||||
if( psStruct && psObj)
|
||||
{
|
||||
Vector3i pos;
|
||||
|
||||
// FIXME HACK Needed since we got those ugly Vector3uw floating around in BASE_OBJECT...
|
||||
Vector3i_Set(&pos, psObj->pos.x, psObj->pos.y, psObj->pos.z);
|
||||
|
||||
|
||||
// Give enemy no quarter, unleash the lasat
|
||||
proj_SendProjectile(&psStruct->asWeaps[0], NULL, player, psObj->pos.x,
|
||||
psObj->pos.y, psObj->pos.z, psObj, true, false, 0);
|
||||
proj_SendProjectile(&psStruct->asWeaps[0], NULL, player, pos, psObj, true, false, 0);
|
||||
|
||||
// Play 5 second countdown message
|
||||
audio_QueueTrackPos( ID_SOUND_LAS_SAT_COUNTDOWN, psObj->pos.x, psObj->pos.y,
|
||||
psObj->pos.z);
|
||||
|
|
15
src/order.c
15
src/order.c
|
@ -4184,29 +4184,34 @@ BOOL getFactoryState(STRUCTURE *psStruct, SECONDARY_ORDER sec, SECONDARY_STATE *
|
|||
void orderStructureObj(UDWORD player, BASE_OBJECT *psObj)
|
||||
{
|
||||
STRUCTURE *psStruct;
|
||||
UDWORD firePause, damLevel;
|
||||
|
||||
for (psStruct = apsStructLists[player]; psStruct; psStruct = psStruct->psNext)
|
||||
{
|
||||
if (lasSatStructSelected(psStruct))
|
||||
{
|
||||
Vector3i pos;
|
||||
//there will only be the one!
|
||||
firePause = weaponFirePause(&asWeaponStats[psStruct->asWeaps[0].
|
||||
nStat], (UBYTE)player);
|
||||
damLevel = PERCENT(psStruct->body, structureBody(psStruct));
|
||||
unsigned int firePause = weaponFirePause(&asWeaponStats[psStruct->asWeaps[0].nStat], (UBYTE)player);
|
||||
unsigned int damLevel = PERCENT(psStruct->body, structureBody(psStruct));
|
||||
|
||||
// FIXME HACK Needed since we got those ugly Vector3uw floating around in BASE_OBJECT...
|
||||
Vector3i_Set(&pos, psObj->pos.x, psObj->pos.y, psObj->pos.z);
|
||||
|
||||
if (damLevel < HEAVY_DAMAGE_LEVEL)
|
||||
{
|
||||
firePause += firePause;
|
||||
}
|
||||
|
||||
if (isHumanPlayer(player)
|
||||
&& (gameTime - psStruct->asWeaps[0].lastFired <= firePause) )
|
||||
{
|
||||
/* Too soon to fire again */
|
||||
break;
|
||||
}
|
||||
|
||||
//ok to fire - so fire away
|
||||
proj_SendProjectile(&psStruct->asWeaps[0], NULL,
|
||||
player, psObj->pos.x, psObj->pos.y, psObj->pos.z, psObj, true, false, 0);
|
||||
player, pos, psObj, true, false, 0);
|
||||
//set up last fires time
|
||||
psStruct->asWeaps[0].lastFired = gameTime;
|
||||
|
||||
|
|
|
@ -338,8 +338,7 @@ static void proj_UpdateKills(PROJECTILE *psObj, float experienceInc)
|
|||
|
||||
/***************************************************************************/
|
||||
|
||||
BOOL proj_SendProjectile(WEAPON *psWeap, BASE_OBJECT *psAttacker, int player, int tarX, int tarY, int tarZ,
|
||||
BASE_OBJECT *psTarget, BOOL bVisible, BOOL bPenetrate, int weapon_slot)
|
||||
BOOL proj_SendProjectile(WEAPON *psWeap, BASE_OBJECT *psAttacker, int player, Vector3i target, BASE_OBJECT *psTarget, BOOL bVisible, BOOL bPenetrate, int weapon_slot)
|
||||
{
|
||||
PROJECTILE *psObj = malloc(sizeof(PROJECTILE));
|
||||
SDWORD tarHeight, srcHeight, iMinSq;
|
||||
|
@ -358,9 +357,7 @@ BOOL proj_SendProjectile(WEAPON *psWeap, BASE_OBJECT *psAttacker, int player, in
|
|||
{
|
||||
// if there isn't an attacker just start at the target position
|
||||
// NB this is for the script function to fire the las sats
|
||||
muzzle.x = (SDWORD)tarX;
|
||||
muzzle.y = (SDWORD)tarY;
|
||||
muzzle.z = (SDWORD)tarZ;
|
||||
muzzle = target;
|
||||
}
|
||||
else if (psAttacker->type == OBJ_DROID && weapon_slot >= 0)
|
||||
{
|
||||
|
@ -383,13 +380,11 @@ BOOL proj_SendProjectile(WEAPON *psWeap, BASE_OBJECT *psAttacker, int player, in
|
|||
psObj->type = OBJ_PROJECTILE;
|
||||
psObj->state = PROJ_INFLIGHT;
|
||||
psObj->psWStats = asWeaponStats + psWeap->nStat;
|
||||
psObj->pos.x = (UWORD)muzzle.x;
|
||||
psObj->pos.y = (UWORD)muzzle.y;
|
||||
psObj->pos.z = (UWORD)muzzle.z;
|
||||
Vector3uw_Set(&psObj->pos, muzzle.x, muzzle.y, muzzle.z);
|
||||
psObj->startX = muzzle.x;
|
||||
psObj->startY = muzzle.y;
|
||||
psObj->tarX = tarX;
|
||||
psObj->tarY = tarY;
|
||||
psObj->tarX = target.x;
|
||||
psObj->tarY = target.y;
|
||||
psObj->targetRadius = (psTarget ? establishTargetRadius(psTarget) : 0); // needed to backtrack FX
|
||||
psObj->born = gameTime;
|
||||
psObj->player = (UBYTE)player;
|
||||
|
@ -405,7 +400,7 @@ BOOL proj_SendProjectile(WEAPON *psWeap, BASE_OBJECT *psAttacker, int player, in
|
|||
|
||||
/* If target is a VTOL or higher than ground, it is an air target. */
|
||||
if ((psTarget != NULL && psTarget->type == OBJ_DROID && vtolDroid((DROID*)psTarget))
|
||||
|| (psTarget == NULL && (SDWORD)tarZ > map_Height(tarX,tarY)))
|
||||
|| (psTarget == NULL && target.z > map_Height(target.x, target.y)))
|
||||
{
|
||||
psObj->airTarget = true;
|
||||
}
|
||||
|
@ -472,7 +467,7 @@ BOOL proj_SendProjectile(WEAPON *psWeap, BASE_OBJECT *psAttacker, int player, in
|
|||
}
|
||||
else
|
||||
{
|
||||
tarHeight = (SDWORD)tarZ;
|
||||
tarHeight = target.z;
|
||||
scoreUpdateVar(WD_SHOTS_OFF_TARGET);
|
||||
}
|
||||
|
||||
|
@ -872,20 +867,22 @@ static void proj_InFlightDirectFunc( PROJECTILE *psObj )
|
|||
|
||||
if (bPenetrate)
|
||||
{
|
||||
SDWORD TargetX, TargetY;
|
||||
// Determine position to fire a missile at
|
||||
// (must be at least 0 because we don't use signed integers
|
||||
// this shouldn't be larger than the height and width of the map either)
|
||||
Vector3i target = {
|
||||
psObj->startX + extendRad * dx / rad,
|
||||
psObj->startY + extendRad * dy / rad,
|
||||
psObj->pos.z
|
||||
};
|
||||
target.x = clip(target.x, 0, world_coord(mapWidth - 1));
|
||||
target.y = clip(target.y, 0, world_coord(mapHeight - 1));
|
||||
|
||||
asWeap.nStat = psObj->psWStats - asWeaponStats;
|
||||
//Watermelon:just assume we damaged the chosen target
|
||||
setProjectileDamaged(psObj, psNewTarget);
|
||||
|
||||
// Determine position to fire a missile at
|
||||
// (must be at least 0 because we don't use signed integers
|
||||
// this shouldn't be larger than the height and width of the map either)
|
||||
TargetX = psObj->startX + extendRad * dx / rad;
|
||||
TargetY = psObj->startY + extendRad * dy / rad;
|
||||
CLIP(TargetX, 0, world_coord(mapWidth - 1));
|
||||
CLIP(TargetY, 0, world_coord(mapHeight - 1));
|
||||
proj_SendProjectile( &asWeap, (BASE_OBJECT*)psObj, psObj->player, TargetX, TargetY, psObj->pos.z, NULL, true, bPenetrate, -1 );
|
||||
proj_SendProjectile( &asWeap, (BASE_OBJECT*)psObj, psObj->player, target, NULL, true, bPenetrate, -1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1120,20 +1117,22 @@ static void proj_InFlightIndirectFunc( PROJECTILE *psObj )
|
|||
|
||||
if (bPenetrate)
|
||||
{
|
||||
SDWORD TargetX, TargetY;
|
||||
// Determine position to fire a missile at
|
||||
// (must be at least 0 because we don't use signed integers
|
||||
// this shouldn't be larger than the height and width of the map either)
|
||||
Vector3i target = {
|
||||
psObj->startX + extendRad * dx / iRad,
|
||||
psObj->startY + extendRad * dy / iRad,
|
||||
psObj->pos.z
|
||||
};
|
||||
target.x = clip(target.x, 0, world_coord(mapWidth - 1));
|
||||
target.y = clip(target.y, 0, world_coord(mapHeight - 1));
|
||||
|
||||
asWeap.nStat = psObj->psWStats - asWeaponStats;
|
||||
//Watermelon:just assume we damaged the chosen target
|
||||
setProjectileDamaged(psObj, psNewTarget);
|
||||
|
||||
// Determine position to fire a missile at
|
||||
// (must be at least 0 because we don't use signed integers
|
||||
// this shouldn't be larger than the height and width of the map either)
|
||||
TargetX = MAX(psObj->startX + extendRad * dx / iRad, 0);
|
||||
TargetX = MIN(TargetX, world_coord(mapWidth - 1));
|
||||
TargetY = MAX(psObj->startY + extendRad * dy / iRad, 0);
|
||||
TargetY = MIN(TargetY, world_coord(mapHeight - 1));
|
||||
proj_SendProjectile( &asWeap, (BASE_OBJECT*)psObj, psObj->player, TargetX, TargetY, psObj->pos.z, NULL, true, bPenetrate, -1 );
|
||||
proj_SendProjectile( &asWeap, (BASE_OBJECT*)psObj, psObj->player, target, NULL, true, bPenetrate, -1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -56,8 +56,7 @@ PROJECTILE *proj_GetNext(void); ///< Get next projectile in the list.
|
|||
void proj_FreeAllProjectiles(void); ///< Free all projectiles in the list.
|
||||
|
||||
/** Send a single projectile against the given target. */
|
||||
BOOL proj_SendProjectile(WEAPON *psWeap, BASE_OBJECT *psAttacker, int player, int tarX, int tarY, int tarZ,
|
||||
BASE_OBJECT *psTarget, BOOL bVisible, BOOL bPenetrate, int weapon_slot);
|
||||
BOOL proj_SendProjectile(WEAPON *psWeap, BASE_OBJECT *psAttacker, int player, Vector3i target, BASE_OBJECT *psTarget, BOOL bVisible, BOOL bPenetrate, int weapon_slot);
|
||||
|
||||
/** Return whether a weapon is direct or indirect. */
|
||||
bool proj_Direct(const WEAPON_STATS* psStats);
|
||||
|
|
|
@ -6359,11 +6359,11 @@ BOOL scrGetDroidCount(void)
|
|||
// fire a weapon stat at an object
|
||||
BOOL scrFireWeaponAtObj(void)
|
||||
{
|
||||
SDWORD wIndex;
|
||||
Vector3i target;
|
||||
BASE_OBJECT *psTarget;
|
||||
WEAPON sWeapon;
|
||||
WEAPON sWeapon = {0, 0, 0, 0, 0};
|
||||
|
||||
if (!stackPopParams(2, ST_WEAPON, &wIndex, ST_BASEOBJECT, &psTarget))
|
||||
if (!stackPopParams(2, ST_WEAPON, &sWeapon.nStat, ST_BASEOBJECT, &psTarget))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -6374,11 +6374,11 @@ BOOL scrFireWeaponAtObj(void)
|
|||
return false;
|
||||
}
|
||||
|
||||
memset(&sWeapon, 0, sizeof(WEAPON));
|
||||
sWeapon.nStat = wIndex;
|
||||
// FIXME HACK Needed since we got those ugly Vector3uw floating around in BASE_OBJECT...
|
||||
Vector3i_Set(&target, psTarget->pos.x, psTarget->pos.y, psTarget->pos.z);
|
||||
|
||||
// send the projectile using the selectedPlayer so that it can always be seen
|
||||
proj_SendProjectile(&sWeapon, NULL, selectedPlayer, psTarget->pos.x,psTarget->pos.y,psTarget->pos.z, psTarget, true, false, 0);
|
||||
proj_SendProjectile(&sWeapon, NULL, selectedPlayer, target, psTarget, true, false, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -6386,19 +6386,18 @@ BOOL scrFireWeaponAtObj(void)
|
|||
// fire a weapon stat at a location
|
||||
BOOL scrFireWeaponAtLoc(void)
|
||||
{
|
||||
SDWORD wIndex, x,y;
|
||||
WEAPON sWeapon;
|
||||
Vector3i target;
|
||||
WEAPON sWeapon = {0, 0, 0, 0, 0};
|
||||
|
||||
if (!stackPopParams(3, ST_WEAPON, &wIndex, VAL_INT, &x, VAL_INT, &y))
|
||||
if (!stackPopParams(3, ST_WEAPON, &sWeapon.nStat, VAL_INT, &target.x, VAL_INT, &target.y))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&sWeapon, 0, sizeof(WEAPON));
|
||||
sWeapon.nStat = wIndex;
|
||||
target.z = map_Height(target.x, target.y);
|
||||
|
||||
// send the projectile using the selectedPlayer so that it can always be seen
|
||||
proj_SendProjectile(&sWeapon, NULL, selectedPlayer, x,y,map_Height(x,y), NULL, true, false, 0);
|
||||
proj_SendProjectile(&sWeapon, NULL, selectedPlayer, target, NULL, true, false, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue