DEFINE_ACTION_FUNCTION(AActor, A_EntityAttack) { // Apparent Strife bug: Case 5 was unreachable because they used % 5 instead of % 6. // I've fixed that by making case 1 duplicate it, since case 1 did nothing. switch (pr_entity() % 5) { case 0: CALL_ACTION(A_SpotLightning, self); break; case 2: A_SpectralMissile (self, "SpectralLightningH3"); break; case 3: CALL_ACTION(A_Spectre3Attack, self); break; case 4: A_SpectralMissile (self, "SpectralLightningBigV2"); break; case 1: case 5: A_SpectralMissile (self, "SpectralLightningBigBall2"); break; } }
DEFINE_ACTION_FUNCTION(AActor, A_MarineLook) { PARAM_ACTION_PROLOGUE; CALL_ACTION(A_MarineNoise, self); CALL_ACTION(A_Look, self); return 0; }
DEFINE_ACTION_FUNCTION(AActor, A_MarineChase) { PARAM_ACTION_PROLOGUE; CALL_ACTION(A_MarineNoise, self); A_Chase (stack, self); return 0; }
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BridgeInit) { PARAM_ACTION_PROLOGUE; PARAM_CLASS_OPT(balltype, AActor) { balltype = NULL; } angle_t startangle; AActor *ball; if (balltype == NULL) { balltype = PClass::FindActor("BridgeBall"); } startangle = pr_orbit() << 24; // Spawn triad into world -- may be more than a triad now. int ballcount = self->args[2]==0 ? 3 : self->args[2]; for (int i = 0; i < ballcount; i++) { ball = Spawn(balltype, self->Pos(), ALLOW_REPLACE); ball->angle = startangle + (ANGLE_45/32) * (256/ballcount) * i; ball->target = self; CALL_ACTION(A_BridgeOrbit, ball); } return 0; }
bool ARaiseAlarm::TryPickup (AActor *&toucher) { P_NoiseAlert (toucher, toucher); CALL_ACTION(A_WakeOracleSpectre, toucher); GoAwayAndDie (); return true; }
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BridgeInit) { angle_t startangle; AActor *ball; fixed_t cx, cy, cz; ACTION_PARAM_START(1); ACTION_PARAM_CLASS(balltype, 0); if (balltype == NULL) balltype = PClass::FindClass("BridgeBall"); cx = self->x; cy = self->y; cz = self->z; startangle = pr_orbit() << 24; self->special1 = 0; // Spawn triad into world -- may be more than a triad now. int ballcount = self->args[2]==0 ? 3 : self->args[2]; for (int i = 0; i < ballcount; i++) { ball = Spawn(balltype, cx, cy, cz, ALLOW_REPLACE); ball->angle = startangle + (ANGLE_45/32) * (256/ballcount) * i; ball->target = self; CALL_ACTION(A_BridgeOrbit, ball); // [Dusk] bridge balls should not be included in full updates // as the bridge thing will spawn them instead. if (NETWORK_GetState() == NETSTATE_SERVER) ball->ulNetworkFlags |= NETFL_ALLOWCLIENTSPAWN; } }
DEFINE_ACTION_FUNCTION(AActor, A_KlaxonBlare) { if (--self->reactiontime < 0) { self->target = NULL; self->reactiontime = self->GetDefault()->reactiontime; CALL_ACTION(A_TurretLook, self); if (self->target == NULL) { self->SetIdle(); } else { self->reactiontime = 50; } } if (self->reactiontime == 2) { // [RH] Unalert monsters near the alarm and not just those in the same sector as it. P_NoiseAlert (NULL, self, false); } else if (self->reactiontime > 50) { S_Sound (self, CHAN_VOICE, "misc/alarm", 1, ATTN_NORM); } }
DEFINE_ACTION_FUNCTION(AActor, A_SerpentMeleeAttack) { // [BB] This is server-side. if (( NETWORK_GetState( ) == NETSTATE_CLIENT ) || ( CLIENTDEMO_IsPlaying( ))) { return; } if (!self->target) { return; } if (self->CheckMeleeRange ()) { int damage = pr_serpentmeattack.HitDice (5); P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (damage, self->target, self); S_Sound (self, CHAN_BODY, "SerpentMeleeHit", 1, ATTN_NORM); // [BB] If we're the server, tell the clients to play the sound. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_SoundActor( self, CHAN_BODY, "SerpentMeleeHit", 1, ATTN_NORM ); } if (pr_serpentmeattack() < 96) { CALL_ACTION(A_SerpentCheckForAttack, self); } }
DEFINE_ACTION_FUNCTION(AActor, A_Sor1Pain) { PARAM_ACTION_PROLOGUE; self->special1 = 20; // Number of steps to walk fast CALL_ACTION(A_Pain, self); return 0; }
DEFINE_ACTION_FUNCTION(AActor, A_PigPain) { CALL_ACTION(A_Pain, self); if (self->z <= self->floorz) { self->momz = FRACUNIT*7/2; } }
void Tick() // This function is needed for handling boss replacers { Super::Tick(); if (tracer == NULL || tracer->health <= 0) { CALL_ACTION(A_BossDeath, this); Destroy(); } }
bool P_MorphedDeath(AActor *actor, AActor **morphed, int *morphedstyle, int *morphedhealth) { // May be a morphed player if ((actor->player) && (actor->player->morphTics) && (actor->player->MorphStyle & MORPH_UNDOBYDEATH) && (actor->player->mo) && (actor->player->mo->tracer)) { AActor *realme = actor->player->mo->tracer; int realstyle = actor->player->MorphStyle; int realhealth = actor->health; if (P_UndoPlayerMorph(actor->player, actor->player, !!(actor->player->MorphStyle & MORPH_UNDOBYDEATHFORCED))) { *morphed = realme; *morphedstyle = realstyle; *morphedhealth = realhealth; return true; } return false; } // May be a morphed monster if (actor->GetClass()->IsDescendantOf(RUNTIME_CLASS(AMorphedMonster))) { AMorphedMonster *fakeme = static_cast<AMorphedMonster *>(actor); AActor *realme = fakeme->UnmorphedMe; if (realme != NULL) { if ((fakeme->UnmorphTime) && (fakeme->MorphStyle & MORPH_UNDOBYDEATH)) { int realstyle = fakeme->MorphStyle; int realhealth = fakeme->health; if (P_UndoMonsterMorph(fakeme, !!(fakeme->MorphStyle & MORPH_UNDOBYDEATHFORCED))) { *morphed = realme; *morphedstyle = realstyle; *morphedhealth = realhealth; return true; } } if (realme->flags4 & MF4_BOSSDEATH) { realme->health = 0; // make sure that A_BossDeath considers it dead. CALL_ACTION(A_BossDeath, realme); } } fakeme->flags3 |= MF3_STAYMORPHED; // moved here from AMorphedMonster::Die() return false; } // Not a morphed player or monster return false; }
DEFINE_ACTION_FUNCTION(AActor, A_M_FireRailgun) { PARAM_ACTION_PROLOGUE; if (self->target == NULL) return 0; CALL_ACTION(A_MonsterRail, self); self->special1 = level.maptime + 50; return 0; }
void Tick() // This function is needed for handling boss replacers { Super::Tick(); if (tracer == NULL || tracer->health <= 0) { // [BB] Don't do this on actors that already have been hidden by HideOrDestroyIfSafe() if ( ( this->ulSTFlags & STFL_HIDDEN_INSTEAD_OF_DESTROYED ) == false ) { CALL_ACTION(A_BossDeath, this); // [BB] Only destroy the actor if it's not needed for a map reset. Otherwise just hide it. HideOrDestroyIfSafe(); } } }
DEFINE_ACTION_FUNCTION(AActor, A_WizAtk3) { AActor *mo; CALL_ACTION(A_GhostOff, self); // [BB] This is server-side, the client only needs to run A_GhostOff. if (( NETWORK_GetState( ) == NETSTATE_CLIENT ) || ( CLIENTDEMO_IsPlaying( ))) { return; } if (!self->target) { return; } S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); // [BB] If we're the server, tell the clients to play the sound. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_SoundActor( self, CHAN_WEAPON, S_GetName( self->AttackSound ), 1, ATTN_NORM ); if (self->CheckMeleeRange()) { int damage = pr_wizatk3.HitDice (4); P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (damage, self->target, self); return; } const PClass *fx = PClass::FindClass("WizardFX1"); mo = P_SpawnMissile (self, self->target, fx); if (mo != NULL) { AActor *missile1 = P_SpawnMissileAngle(self, fx, mo->angle-(ANG45/8), mo->velz); AActor *missile2 = P_SpawnMissileAngle(self, fx, mo->angle+(ANG45/8), mo->velz); // [BB] If we're the server, tell the clients to spawn the missiles. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) { SERVERCOMMANDS_SpawnMissile( mo ); if ( missile1 ) SERVERCOMMANDS_SpawnMissile( missile1 ); if ( missile2 ) SERVERCOMMANDS_SpawnMissile( missile2 ); } } }
DEFINE_ACTION_FUNCTION(AActor, A_M_FireRailgun) { // [BC] Don't do this in client mode. if (( NETWORK_GetState( ) == NETSTATE_CLIENT ) || ( CLIENTDEMO_IsPlaying( ))) { return; } if (self->target == NULL) return; CALL_ACTION(A_MonsterRail, self); self->special1 = level.maptime + 50; }
DEFINE_ACTION_FUNCTION(AActor, A_IceGuyLook) { fixed_t dist; fixed_t an; CALL_ACTION(A_Look, self); if (pr_iceguylook() < 64) { dist = ((pr_iceguylook()-128)*self->radius)>>7; an = (self->angle+ANG90)>>ANGLETOFINESHIFT; Spawn (WispTypes[pr_iceguylook()&1], self->x+FixedMul(dist, finecosine[an]), self->y+FixedMul(dist, finesine[an]), self->z+60*FRACUNIT, ALLOW_REPLACE); }
DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckUpG) { player_t *player; if (NULL == (player = self->player)) { return; } if (player->ReadyWeapon->Ammo1->Amount <= 0) { P_SetPsprite (player, ps_weapon, player->ReadyWeapon->FindState ("Select")); } else { CALL_ACTION(A_Raise, self); } }
DEFINE_ACTION_FUNCTION(AActor, A_SerpentMeleeAttack) { if (!self->target) { return; } if (self->CheckMeleeRange ()) { int damage = pr_serpentmeattack.HitDice (5); int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); S_Sound (self, CHAN_BODY, "SerpentMeleeHit", 1, ATTN_NORM); } if (pr_serpentmeattack() < 96) { CALL_ACTION(A_SerpentCheckForAttack, self); } }
DEFINE_ACTION_FUNCTION(AActor, A_AcolyteBits) { if (self->SpawnFlags & MTF_SHADOW) { CALL_ACTION(A_BeShadowyFoe, self); } if (self->SpawnFlags & MTF_ALTSHADOW) { //self->flags |= MF_STRIFEx8000000; if (self->flags & MF_SHADOW) { // I dunno. } else { self->RenderStyle.BlendOp = STYLEOP_None; } } }
DEFINE_ACTION_FUNCTION(AActor, A_LightningZap) { PARAM_ACTION_PROLOGUE; PClassActor *lightning = PClass::FindActor(self->GetClass()->MissileName); AActor *mo; if (lightning == NULL) { lightning = PClass::FindActor(NAME_LightningZap); } CALL_ACTION(A_LightningClip, self); self->health -= 8; if (self->health <= 0) { self->SetState (self->FindState(NAME_Death)); return 0; } double deltaX = (pr_zap() - 128) * self->radius / 256; double deltaY = (pr_zap() - 128) * self->radius / 256; double deltaZ = (self->flags3 & MF3_FLOORHUGGER) ? 10 : -10; mo = Spawn(lightning, self->Vec3Offset(deltaX, deltaY, deltaZ), ALLOW_REPLACE); if (mo) { mo->lastenemy = self; mo->Vel.X = self->Vel.X; mo->Vel.Y = self->Vel.Y; mo->Vel.Z = (self->flags3 & MF3_FLOORHUGGER) ? 20 : -20; mo->target = self->target; } if ((self->flags3 & MF3_FLOORHUGGER) && pr_zapf() < 160) { S_Sound (self, CHAN_BODY, self->ActiveSound, 1, ATTN_NORM); } return 0; }
DEFINE_ACTION_FUNCTION(AActor, A_MinotaurRoam) { PARAM_ACTION_PROLOGUE; // In case pain caused him to skip his fade in. self->RenderStyle = STYLE_Normal; if (self->IsKindOf(RUNTIME_CLASS(AMinotaurFriend))) { AMinotaurFriend *self1 = static_cast<AMinotaurFriend *> (self); if (self1->StartTime >= 0 && (level.maptime - self1->StartTime) >= MAULATORTICS) { P_DamageMobj (self1, NULL, NULL, TELEFRAG_DAMAGE, NAME_None); return 0; } } if (pr_minotaurroam() < 30) CALL_ACTION(A_MinotaurLook, self); // adjust to closest target if (pr_minotaurroam() < 6) { //Choose new direction self->movedir = pr_minotaurroam() % 8; FaceMovementDirection (self); } if (!P_Move(self)) { // Turn if (pr_minotaurroam() & 1) self->movedir = (self->movedir + 1) % 8; else self->movedir = (self->movedir + 7) % 8; FaceMovementDirection (self); } return 0; }
DEFINE_ACTION_FUNCTION(AActor, A_AlienSpectreDeath) { AActor *player; char voc[32]; int log; int i; CALL_ACTION(A_NoBlocking, self); // [RH] Need this for Sigil rewarding if (!CheckBossDeath (self)) { return; } for (i = 0, player = NULL; i < MAXPLAYERS; ++i) { if (playeringame[i] && players[i].health > 0) { player = players[i].mo; break; } } if (player == NULL) { return; } switch (self->GetClass()->TypeName) { case NAME_AlienSpectre1: EV_DoFloor (DFloor::floorLowerToLowest, NULL, 999, FRACUNIT, 0, 0, 0, false); log = 95; break; case NAME_AlienSpectre2: C_MidPrint(SmallFont, GStrings("TXT_KILLED_BISHOP")); log = 74; player->GiveInventoryType (QuestItemClasses[20]); break; case NAME_AlienSpectre3: { C_MidPrint(SmallFont, GStrings("TXT_KILLED_ORACLE")); // If there are any Oracles still alive, kill them. TThinkerIterator<AActor> it(NAME_Oracle); AActor *oracle; while ( (oracle = it.Next()) != NULL) { if (oracle->health > 0) { oracle->health = 0; oracle->Die (self, self); } } player->GiveInventoryType (QuestItemClasses[22]); if (player->FindInventory (QuestItemClasses[20])) { // If the Bishop is dead, set quest item 22 player->GiveInventoryType (QuestItemClasses[21]); } if (player->FindInventory (QuestItemClasses[23]) == NULL) { // Macil is calling us back... log = 87; } else { // You wield the power of the complete Sigil. log = 85; } EV_DoDoor (DDoor::doorOpen, NULL, NULL, 222, 8*FRACUNIT, 0, 0, 0); break; } case NAME_AlienSpectre4: C_MidPrint(SmallFont, GStrings("TXT_KILLED_MACIL")); player->GiveInventoryType (QuestItemClasses[23]); if (player->FindInventory (QuestItemClasses[24]) == NULL) { // Richter has taken over. Macil is a snake. log = 79; } else { // Back to the factory for another Sigil! log = 106; } break; case NAME_AlienSpectre5: C_MidPrint(SmallFont, GStrings("TXT_KILLED_LOREMASTER")); ASigil *sigil; player->GiveInventoryType (QuestItemClasses[25]); if ( NETWORK_GetState( ) == NETSTATE_SINGLE ) { player->GiveInventoryType (RUNTIME_CLASS(AUpgradeStamina)); player->GiveInventoryType (RUNTIME_CLASS(AUpgradeAccuracy)); } sigil = player->FindInventory<ASigil>(); if (sigil != NULL && sigil->NumPieces == 5) { // You wield the power of the complete Sigil. log = 85; } else { // Another Sigil piece. Woohoo! log = 83; } EV_DoFloor (DFloor::floorLowerToLowest, NULL, 666, FRACUNIT, 0, 0, 0, false); break; default: return; } mysnprintf (voc, countof(voc), "svox/voc%d", log); S_Sound (CHAN_VOICE, voc, 1, ATTN_NORM); player->player->SetLogNumber (log); }
DEFINE_ACTION_FUNCTION(AActor, A_WizAtk1) { A_FaceTarget (self); CALL_ACTION(A_GhostOff, self); }
DEFINE_ACTION_FUNCTION(AActor, A_MarineChase) { CALL_ACTION(A_MarineNoise, self); A_Chase (self); }
DEFINE_ACTION_FUNCTION(AActor, A_MinotaurLook) { PARAM_ACTION_PROLOGUE; if (!self->IsKindOf(RUNTIME_CLASS(AMinotaurFriend))) { CALL_ACTION(A_Look, self); return 0; } AActor *mo = NULL; player_t *player; double dist; int i; AActor *master = self->tracer; self->target = NULL; if (deathmatch) // Quick search for players { for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) continue; player = &players[i]; mo = player->mo; if (mo == master) continue; if (mo->health <= 0) continue; dist = self->Distance2D(mo); if (dist > MINOTAUR_LOOK_DIST) continue; self->target = mo; break; } } if (!self->target) // Near player monster search { if (master && (master->health>0) && (master->player)) mo = P_RoughMonsterSearch(master, 20); else mo = P_RoughMonsterSearch(self, 20); self->target = mo; } if (!self->target) // Normal monster search { FActorIterator iterator (0); while ((mo = iterator.Next()) != NULL) { if (!(mo->flags3 & MF3_ISMONSTER)) continue; if (mo->health <= 0) continue; if (!(mo->flags & MF_SHOOTABLE)) continue; dist = self->Distance2D(mo); if (dist > MINOTAUR_LOOK_DIST) continue; if ((mo == master) || (mo == self)) continue; if ((mo->flags5 & MF5_SUMMONEDMONSTER) && (mo->tracer == master)) continue; self->target = mo; break; // Found actor to attack } } if (self->target) { self->SetState (self->SeeState, true); } else { self->SetState (self->FindState ("Roam"), true); } return 0; }
DEFINE_ACTION_FUNCTION(AActor, A_MarineLook) { CALL_ACTION(A_MarineNoise, self); CALL_ACTION(A_Look, self); }
DEFINE_ACTION_FUNCTION(AActor, A_MinotaurChase) { PARAM_ACTION_PROLOGUE; if (!self->IsKindOf(RUNTIME_CLASS(AMinotaurFriend))) { A_Chase (stack, self); return 0; } AMinotaurFriend *self1 = static_cast<AMinotaurFriend *> (self); // In case pain caused him to skip his fade in. self1->RenderStyle = STYLE_Normal; if (self1->StartTime >= 0 && (level.maptime - self1->StartTime) >= MAULATORTICS) { P_DamageMobj (self1, NULL, NULL, TELEFRAG_DAMAGE, NAME_None); return 0; } if (pr_minotaurchase() < 30) CALL_ACTION(A_MinotaurLook, self1); // adjust to closest target if (!self1->target || (self1->target->health <= 0) || !(self1->target->flags&MF_SHOOTABLE)) { // look for a new target self1->SetIdle(); return 0; } FaceMovementDirection (self1); self1->reactiontime = 0; // Melee attack if (self1->MeleeState && self1->CheckMeleeRange ()) { if (self1->AttackSound) { S_Sound (self1, CHAN_WEAPON, self1->AttackSound, 1, ATTN_NORM); } self1->SetState (self1->MeleeState); return 0; } // Missile attack if (self1->MissileState && P_CheckMissileRange(self1)) { self1->SetState (self1->MissileState); return 0; } // chase towards target if (!P_Move (self1)) { P_NewChaseDir (self1); FaceMovementDirection (self1); } // Active sound if (pr_minotaurchase() < 6) { self1->PlayActiveSound (); } return 0; }
DEFINE_ACTION_FUNCTION(AActor, A_GenericFreezeDeath) { self->Translation = TRANSLATION(TRANSLATION_Standard, 7); CALL_ACTION(A_FreezeDeath, self); }
DEFINE_ACTION_FUNCTION(AActor, A_Sor1Pain) { self->special1 = 20; // Number of steps to walk fast CALL_ACTION(A_Pain, self); }