📄 bullets.cpp
字号:
#include "bullets.h"
void addBullet(object *theWeapon, object *attacker, int y, int dy)
{
object *bullet;
signed char imageIndex;
int tempX, tempY, steps;
bullet = new object;
if (attacker == &player)
currentGame.shots++;
bullet->next = NULL;
bullet->active = 1;
bullet->x = attacker->x - ((attacker->image[0]->w / 2) * attacker->face);
bullet->y = attacker->y + y;
bullet->flags = theWeapon->flags;
bullet->shield = 300; // bullets live for (approximately) 5 seconds
// Timed explosions live between 1 and 3 seconds
if (bullet->flags & WF_TIMEDEXPLOSION)
bullet->shield = 60 + ((rand() % 3) * 60);
if (attacker->face == 0)
{
bullet->dx = theWeapon->speed;
if ((currentGame.area == 18) || (currentGame.area == 24))
bullet->dx += fabs(engine.ssx);
}
else
{
bullet->dx = (0 - theWeapon->speed);
}
if (bullet->flags & WF_VARIABLE_SPEED)
{
bullet->dx = Math::rrand(100, 200);
bullet->dx /= 10;
if (attacker->face == 1)
bullet->dx = 0 - bullet->dx;
}
bullet->dy = dy;
if (bullet->flags & WF_SCATTER)
{
bullet->dy = Math::rrand(-200, 200);
if (bullet->dy != 0)
bullet->dy /= 200;
}
if (attacker->flags & FL_WEAPCO)
bullet->flags += WF_WEAPCO;
else
bullet->flags += WF_FRIEND;
bullet->owner = attacker->owner;
bullet->id = theWeapon->id;
bullet->damage = theWeapon->damage;
if (bullet->id == WT_CHARGER)
{
bullet->damage = attacker->ammo[1];
if (bullet->damage < 50)
{
bullet->damage = 1;
bullet->id = WT_PLASMA;
}
}
bullet->target = NULL;
if (attacker->flags & FL_FRIEND)
imageIndex = 0;
else
imageIndex = 1;
// Use the enemy's images if applicable
if (bullet->id != WT_ROCKET)
bullet->image[0] = theWeapon->image[imageIndex];
else
bullet->image[0] = theWeapon->image[attacker->face];
if (bullet->flags & WF_AIMED)
{
tempX = (int)fabs(attacker->target->x - attacker->x);
tempY = (int)fabs(attacker->target->y - attacker->y);
steps = max(tempX, tempY);
if (steps == 0)
steps = 12;
if (!(bullet->flags & WF_TIMEDEXPLOSION))
steps /= 8;
else
steps /= 6 + (rand() % 6);
tempX = (int)(attacker->target->x - attacker->x);
tempY = (int)(attacker->target->y - attacker->y);
bullet->dx = tempX / steps;
bullet->dy = tempY / steps;
}
if (attacker->classDef == CD_ASTEROID)
{
bullet->dx = Math::rrand(-20, 20);
bullet->dy = Math::rrand(-20, 20);
bullet->image[0] = graphics.shape[4];
}
engine.bulletTail->next = bullet;
engine.bulletTail = bullet;
}
/*
Fill in later...
*/
void fireBullet(object *attacker, int weaponType)
{
if (attacker->reload[weaponType] > 0)
return;
int y = (attacker->image[0]->h) / 5;
// Remove some ammo from the player
if ((attacker == &player) && (weaponType == 1) && (!engine.cheatAmmo))
player.ammo[1]--;
object *theWeapon = &weapon[attacker->weaponType[weaponType]];
switch(theWeapon->id)
{
case WT_PLASMA:
case WT_SPREAD:
case WT_DIRECTIONAL:
playSound(SFX_PLASMA);
break;
case WT_ROCKET:
playSound(SFX_MISSILE);
break;
case WT_LASER:
playSound(SFX_LASER);
break;
case WT_CHARGER:
playSound(SFX_PLASMA3);
break;
}
if (theWeapon->flags & WF_STRAIGHT)
{
switch (theWeapon->ammo[0])
{
case 1:
addBullet(theWeapon, attacker, y * 3, 0);
break;
case 2:
addBullet(theWeapon, attacker, y * 2, 0);
addBullet(theWeapon, attacker, y * 4, 0);
break;
case 3:
addBullet(theWeapon, attacker, y * 2, 0);
addBullet(theWeapon, attacker, y * 3, 0);
addBullet(theWeapon, attacker, y * 4, 0);
break;
case 4:
addBullet(theWeapon, attacker, y, 0);
addBullet(theWeapon, attacker, y * 2, 0);
addBullet(theWeapon, attacker, y * 4, 0);
addBullet(theWeapon, attacker, y * 5, 0);
break;
case 5:
for (int i = 1 ; i < 6; i++)
addBullet(theWeapon, attacker, y * i, 0);
break;
}
}
else if (theWeapon->flags & WF_THIN_SPREAD)
{
addBullet(theWeapon, attacker, y * 2, -1);
if (theWeapon->ammo[0] == 3)
{
addBullet(theWeapon, attacker, y * 3, 0);
}
else
{
addBullet(theWeapon, attacker, y * 2, 0);
addBullet(theWeapon, attacker, y * 4, 0);
}
addBullet(theWeapon, attacker, y * 4, 1);
}
else if (theWeapon->flags & WF_WIDE_SPREAD)
{
addBullet(theWeapon, attacker, y * 1, -2);
addBullet(theWeapon, attacker, y * 2, -1);
addBullet(theWeapon, attacker, y * 3, 0);
addBullet(theWeapon, attacker, y * 4, 1);
addBullet(theWeapon, attacker, y * 5, 2);
}
// Reset the weapon reload time. Double it if it is not friendly or a boss or Kline
attacker->reload[weaponType] = theWeapon->reload[0];
if ((attacker->flags & FL_WEAPCO) && (attacker != &enemy[WC_BOSS]) && (attacker != &enemy[WC_KLINE]) && (theWeapon->id != W_LASER))
attacker->reload[weaponType] *= 2;
if ((engine.cheatAmmo) || (theWeapon->id == WT_LASER))
return;
if ((attacker == &player) && (weaponType == 0))
{
if (player.ammo[0] > 0)
{
player.ammo[0]--;
if (player.ammo[0] == 0)
{
player.weaponType[0] = W_PLAYER_WEAPON;
weapon[W_PLAYER_WEAPON2] = weapon[W_PLAYER_WEAPON]; // reset to weapon 1 defaults
}
}
}
}
/*
Used for homing missiles. When a missile is active and it is told to home in
on an enemy, it will attempt to randomly grab one every frame if it does not
already have a target. If the target it is currently chasing is killed, it will
begin to look for a new one (done in doBullets()). The homing missile will make
one attempt per call (one call per frame) to find a suitable target. If the target
it picks is dead or outside the screen range, then it returns NULL. A suitable
target will be returned as the object address.
*/
object *getRandomEnemy(object *bullet)
{
int i;
if (bullet->owner->flags & FL_WEAPCO)
{
i = (rand() % 10);
if (i < 1)
return &player;
}
i = rand() % MAX_ALIENS;
if ((enemy[i].shield < 1) || (!enemy[i].active))
return NULL;
if ((bullet->owner->flags & FL_WEAPCO) && (enemy[i].flags & FL_WEAPCO))
return NULL;
if ((bullet->owner->flags & FL_FRIEND) && (enemy[i].flags & FL_FRIEND))
return NULL;
if (abs((int)bullet->x - (int)enemy[i].target->x) > 800)
return NULL;
if (abs((int)bullet->y - (int)enemy[i].target->y) > 200)
return NULL;
return &enemy[i];
}
/*
Fill in later...
*/
void destroyAlien(object *bullet, object *theEnemy)
{
playSound(SFX_EXPLOSION);
// Chain reaction destruction if needed
if (theEnemy->flags & FL_DAMAGEOWNER)
{
theEnemy->owner->shield -= theEnemy->maxShield;
if (theEnemy->owner->shield < 1)
destroyAlien(bullet, theEnemy->owner);
}
if (theEnemy->flags & FL_FRIEND)
{
if (theEnemy->classDef == CD_PHOEBE)
currentGame.wingMate1Ejects++;
else if (theEnemy->classDef == CD_URSULA)
currentGame.wingMate2Ejects++;
// Phoebe cannot eject on the rescue mission
if (currentGame.area != 7)
{
if ((theEnemy->classDef == CD_PHOEBE) || (theEnemy->classDef == CD_URSULA))
setInfoLine(">> Ally has ejected! <<\n", FONT_RED);
else
setInfoLine(">> Friendly craft has been destroy!! <<\n", FONT_RED);
}
}
if (bullet->owner == &player)
{
// Once again, stop point leeching
if (currentGame.area != MAX_MISSIONS - 1)
currentGame.cash += theEnemy->score;
currentGame.cashEarned += theEnemy->score;
currentGame.totalKills++;
}
else if (bullet->owner->classDef == CD_PHOEBE)
{
currentGame.wingMate1Kills++;
}
else if (bullet->owner->classDef == CD_URSULA)
{
currentGame.wingMate2Kills++;
}
else
{
currentGame.totalOtherKills++;
}
if ((bullet->owner->classDef == CD_PHOEBE) || (bullet->owner->classDef == CD_URSULA))
{
if ((rand() % 8) == 0)
{
getKillMessage(bullet->owner);
}
}
updateMissionRequirements(M_DESTROY_TARGET_TYPE, theEnemy->classDef, 1);
updateMissionRequirements(M_PROTECT_TARGET, theEnemy->classDef, 1);
if (rand() % 100 <= theEnemy->collectChance)
{
unsigned char value;
if ((rand() % 10) == 0)
theEnemy->collectValue *= 2;
while (theEnemy->collectValue > 0)
{
value = (10 + (rand() % theEnemy->collectValue));
if (value > theEnemy->collectValue)
value =theEnemy->collectValue;
addCollectable(theEnemy->x, theEnemy->y, theEnemy->collectType, value, 600);
theEnemy->collectValue -= value;
}
}
// Make it explode immediately
if (theEnemy->classDef == CD_ASTEROID)
{
theEnemy->shield = -999;
if ((currentGame.area == 10) && (theEnemy != &enemy[0]) && (currentMission.completed1[0] == 0) && (currentMission.targetValue1[1] == 1))
engine.targetArrowTimer = 120;
}
if ((theEnemy->classDef == CD_KRASS) && (bullet->owner == &player))
setRadioMessage(FACE_CHRIS, "My NAME is CHRIS!!!!!!!!", 1);
if (theEnemy->classDef == CD_KLINE)
{
setRadioMessage(FACE_KLINE, "It was an honor... to have fought you...", 1);
theEnemy->dx = theEnemy->dy = 0;
theEnemy->maxShield = 1500;
theEnemy->shield = -200;
}
}
char checkPlayerShockDamage(float x, float y, int radius)
{
// Don't let the player be hurt by an explosion after they have completed
// all the mission objectives. That would be *really* annoying!
if ((engine.cheatShield) || (engine.missionCompleteTimer != 0))
return 0;
float distX = fabs(x - player.x);
float distY = fabs(y - player.y);
if ((distX <= 50) && (distY <= 50))
{
if (distX >= 1)
distX /= 5;
if (distY >= 1)
distY /= 5;
player.shield -= (int)(10 - distX);
player.shield -= (int)(10 - distY);
Math::limitInt(&player.shield, 0, player.maxShield);
player.hit = 10;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -