Step one towards vector based projectiles

git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@5106 4a71c877-e1ca-e34f-864e-861f7616d084
master
Dennis Schridde 2008-05-13 23:32:07 +00:00
parent 974b5aacaa
commit 202ebc32fb
6 changed files with 143 additions and 132 deletions

View File

@ -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);
/* 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);
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, miss, NULL, psTarget->player == selectedPlayer, false, weapon_slot);
}
return;
}

View File

@ -55,26 +55,26 @@
BOOL sendBuildStarted(STRUCTURE *psStruct, DROID *psDroid)
{
NETbeginEncode(NET_BUILD, NET_ALL_PLAYERS);
// Who is building it
NETuint8_t(&psDroid->player);
// What they are building
NETuint32_t(&psDroid->psTarStats->ref);
// Where it is being built
NETuint16_t(&psDroid->orderX);
NETuint16_t(&psDroid->orderY);
// The droid building it
NETuint32_t(&psDroid->id);
// The ID assigned to the structure being built
NETuint32_t(&psStruct->id);
// The droids order
NETint32_t(&psDroid->order);
if (psDroid->psTarget
&& psDroid->psTarget->type == OBJ_STRUCTURE)
{
@ -85,7 +85,7 @@ BOOL sendBuildStarted(STRUCTURE *psStruct, DROID *psDroid)
{
NETnull();
}
// Z coord
NETuint16_t(&psStruct->pos.z);
@ -129,16 +129,16 @@ BOOL recvBuildStarted()
if (getDroidDestination((BASE_STATS *) psStats, x, y, &actionX, &actionY))
{
psDroid->order = order;
if (psDroid->order == DORDER_LINEBUILD)
{
psDroid->order = DORDER_BUILD;
}
psDroid->orderX = x;
psDroid->orderY = y;
psDroid->psTarStats = (BASE_STATS *) psStats;
if (targetId)
{
setDroidTarget(psDroid, IdToPointer(targetId, ANYPLAYER));
@ -165,18 +165,18 @@ BOOL recvBuildStarted()
((STRUCTURE *) psDroid->psTarget)->id = structId;
}
}
return true;
}
// ////////////////////////////////////////////////////////////////////////////
// INFORM others that a building has been completed.
BOOL SendBuildFinished(STRUCTURE *psStruct)
{
{
NETbeginEncode(NET_BUILDFINISHED, NET_ALL_PLAYERS);
// ID of building
NETuint32_t(&psStruct->id);
// Along with enough info to build it (if needed)
NETuint32_t(&psStruct->pStructureType->ref);
NETuint16_t(&psStruct->pos.x);
@ -244,7 +244,7 @@ BOOL recvBuildFinished()
}
// Build the structure
psStruct = buildStructure(&(asStructureStats[typeindex]), x, y, player, true);
if (psStruct)
{
psStruct->id = structId;
@ -257,7 +257,7 @@ BOOL recvBuildFinished()
{
NETlogEntry("had to plonk down a building, BUT FAILED OH S**T." ,0,player);
}
return false;
}
@ -266,8 +266,8 @@ BOOL recvBuildFinished()
// demolish message.
BOOL SendDemolishFinished(STRUCTURE *psStruct, DROID *psDroid)
{
NETbeginEncode(NET_DEMOLISH, NET_ALL_PLAYERS);
NETbeginEncode(NET_DEMOLISH, NET_ALL_PLAYERS);
// Send what is being demolish and who is doing it
NETuint32_t(&psStruct->id);
NETuint32_t(&psDroid->id);
@ -303,7 +303,7 @@ BOOL recvDemolishFinished()
psDroid->psTarStats = NULL;
}
}
return true;
}
@ -331,7 +331,7 @@ BOOL recvDestroyStructure()
NETbeginDecode(NET_STRUCTDEST);
NETuint32_t(&structID);
NETend();
// Struct to destory
psStruct = IdToStruct(structID,ANYPLAYER);
@ -344,7 +344,7 @@ BOOL recvDestroyStructure()
// NOTE: I do not think this should be here!
technologyGiveAway(psStruct);
}
return true;
}
@ -370,7 +370,7 @@ BOOL recvLasSat()
UBYTE player,targetplayer;
STRUCTURE *psStruct;
uint32_t id,targetid;
NETbeginDecode(NET_LASSAT);
NETuint8_t(&player);
NETuint32_t(&id);
@ -378,18 +378,24 @@ BOOL recvLasSat()
NETuint8_t(&targetplayer);
NETend();
psStruct = IdToStruct (id, player);
psObj = IdToPointer(targetid, targetplayer);
if( psStruct && psObj)
{
// 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);
// Play 5 second countdown message
audio_QueueTrackPos( ID_SOUND_LAS_SAT_COUNTDOWN, psObj->pos.x, psObj->pos.y,
psObj->pos.z);
}
psStruct = IdToStruct (id, player);
psObj = IdToPointer(targetid, targetplayer);
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, 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);
}
return true;
}

View File

@ -4183,34 +4183,39 @@ BOOL getFactoryState(STRUCTURE *psStruct, SECONDARY_ORDER sec, SECONDARY_STATE *
//lasSat structure can select a target
void orderStructureObj(UDWORD player, BASE_OBJECT *psObj)
{
STRUCTURE *psStruct;
UDWORD firePause, damLevel;
STRUCTURE *psStruct;
for (psStruct = apsStructLists[player]; psStruct; psStruct = psStruct->psNext)
{
if (lasSatStructSelected(psStruct))
{
//there will only be the one!
firePause = weaponFirePause(&asWeaponStats[psStruct->asWeaps[0].
nStat], (UBYTE)player);
damLevel = PERCENT(psStruct->body, structureBody(psStruct));
if (damLevel < HEAVY_DAMAGE_LEVEL)
{
firePause += firePause;
}
if (isHumanPlayer(player)
for (psStruct = apsStructLists[player]; psStruct; psStruct = psStruct->psNext)
{
if (lasSatStructSelected(psStruct))
{
Vector3i pos;
//there will only be the one!
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;
/* 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);
//set up last fires time
psStruct->asWeaps[0].lastFired = gameTime;
//play 5 second countdown message
//ok to fire - so fire away
proj_SendProjectile(&psStruct->asWeaps[0], NULL,
player, pos, psObj, true, false, 0);
//set up last fires time
psStruct->asWeaps[0].lastFired = gameTime;
//play 5 second countdown message
audio_QueueTrackPos( ID_SOUND_LAS_SAT_COUNTDOWN,
psObj->pos.x, psObj->pos.y, psObj->pos.z );
@ -4222,8 +4227,8 @@ void orderStructureObj(UDWORD player, BASE_OBJECT *psObj)
}
break;
}
}
}
}
}
const char* getDroidOrderName(DROID_ORDER order)

View File

@ -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
{
@ -1965,7 +1964,7 @@ UDWORD calcDamage(UDWORD baseDamage, WEAPON_EFFECT weaponEffect, BASE_OBJECT *ps
{
damage = baseDamage;
}
// A little fail safe!
if (damage == 0 && baseDamage != 0)
{

View File

@ -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);

View File

@ -6359,11 +6359,11 @@ BOOL scrGetDroidCount(void)
// fire a weapon stat at an object
BOOL scrFireWeaponAtObj(void)
{
SDWORD wIndex;
BASE_OBJECT *psTarget;
WEAPON sWeapon;
Vector3i target;
BASE_OBJECT *psTarget;
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;
}
@ -11512,7 +11511,7 @@ BOOL scrAssembleWeaponTemplate(void)
// add template to player template list
pNewTemplate->psNext = apsDroidTemplates[player];
apsDroidTemplates[player] = pNewTemplate; //apsTemplateList?
if (bMultiPlayer)
{
sendTemplate(pNewTemplate);