// // A_PainShootSkull // Spawn a lost soul and launch it at the target // void A_PainShootSkull (AActor *self, angle_t angle, const PClass *spawntype, int flags = 0, int limit = -1) { fixed_t x, y, z; AActor *other; angle_t an; int prestep; if (spawntype == NULL) return; if (self->DamageType==NAME_Massacre) return; // [RH] check to make sure it's not too close to the ceiling if (self->z + self->height + 8*FRACUNIT > self->ceilingz) { if (self->flags & MF_FLOAT) { self->velz -= 2*FRACUNIT; self->flags |= MF_INFLOAT; self->flags4 |= MF4_VFRICTION; } return; } // [RH] make this optional if (limit == -1 && (i_compatflags & COMPATF_LIMITPAIN)) limit = 21; if (limit) { // count total number of skulls currently on the level // if there are already 21 skulls on the level, don't spit another one int count = limit; FThinkerIterator iterator (spawntype); DThinker *othink; while ( (othink = iterator.Next ()) ) { if (--count == 0) return; } } // okay, there's room for another one an = angle >> ANGLETOFINESHIFT; prestep = 4*FRACUNIT + 3*(self->radius + GetDefaultByType(spawntype)->radius)/2; x = self->x + FixedMul (prestep, finecosine[an]); y = self->y + FixedMul (prestep, finesine[an]); z = self->z + 8*FRACUNIT; // Check whether the Lost Soul is being fired through a 1-sided // phares // wall or an impassible line, or a "monsters can't cross" line.// | // If it is, then we don't allow the spawn. // V FBoundingBox box(MIN(self->x, x), MIN(self->y, y), MAX(self->x, x), MAX(self->y, y)); FBlockLinesIterator it(box); line_t *ld; while ((ld = it.Next())) { if (!(ld->flags & ML_TWOSIDED) || (ld->flags & (ML_BLOCKING|ML_BLOCKMONSTERS|ML_BLOCKEVERYTHING))) { if (!(box.Left() > ld->bbox[BOXRIGHT] || box.Right() < ld->bbox[BOXLEFT] || box.Top() < ld->bbox[BOXBOTTOM] || box.Bottom() > ld->bbox[BOXTOP])) { if (P_PointOnLineSide(self->x,self->y,ld) != P_PointOnLineSide(x,y,ld)) return; // line blocks trajectory // ^ } } } other = Spawn (spawntype, x, y, z, ALLOW_REPLACE); // Check to see if the new Lost Soul's z value is above the // ceiling of its new sector, or below the floor. If so, kill it. if ((other->z > (other->Sector->ceilingplane.ZatPoint (other->x, other->y) - other->height)) || (other->z < other->Sector->floorplane.ZatPoint (other->x, other->y))) { // kill it immediately P_DamageMobj (other, self, self, TELEFRAG_DAMAGE, NAME_None);// ^ return; // | } // phares // Check for movements. if (!P_CheckPosition (other, other->x, other->y)) { // kill it immediately P_DamageMobj (other, self, self, TELEFRAG_DAMAGE, NAME_None); return; } // [RH] Lost souls hate the same things as their pain elementals other->CopyFriendliness (self, !(flags & PAF_NOTARGET)); if (!(flags & PAF_NOSKULLATTACK)) A_SkullAttack(other, SKULLSPEED); }
// // A_PainShootSkull // Spawn a lost soul and launch it at the target // void A_PainShootSkull (AActor *self, angle_t angle, PClassActor *spawntype, int flags = 0, int limit = -1) { AActor *other; int prestep; if (spawntype == NULL) return; if (self->DamageType == NAME_Massacre) return; // [RH] check to make sure it's not too close to the ceiling if (self->Top() + 8*FRACUNIT > self->ceilingz) { if (self->flags & MF_FLOAT) { self->velz -= 2*FRACUNIT; self->flags |= MF_INFLOAT; self->flags4 |= MF4_VFRICTION; } return; } // [RH] make this optional if (limit == -1 && (i_compatflags & COMPATF_LIMITPAIN)) limit = 21; if (limit) { // count total number of skulls currently on the level // if there are already 21 skulls on the level, don't spit another one int count = limit; FThinkerIterator iterator (spawntype); DThinker *othink; while ( (othink = iterator.Next ()) ) { if (--count == 0) return; } } // okay, there's room for another one prestep = 4*FRACUNIT + 3*(self->radius + GetDefaultByType(spawntype)->radius)/2; // NOTE: The following code contains some advance work for line-to-line portals which is currenty inactive. fixedvec2 dist = Vec2Angle(prestep, angle); fixedvec3 pos = self->Vec3Offset(dist.x, dist.y, 8 * FRACUNIT, true); fixedvec3 src = self->Pos(); for (int i = 0; i < 2; i++) { // Check whether the Lost Soul is being fired through a 1-sided // phares // wall or an impassible line, or a "monsters can't cross" line.// | // If it is, then we don't allow the spawn. // V FBoundingBox box(MIN(src.x, pos.x), MIN(src.y, pos.y), MAX(src.x, pos.x), MAX(src.y, pos.y)); FBlockLinesIterator it(box); line_t *ld; bool inportal = false; while ((ld = it.Next())) { if (ld->isLinePortal() && i == 0) { if (P_PointOnLineSidePrecise(src.x, src.y, ld) == 0 && P_PointOnLineSidePrecise(pos.x, pos.y, ld) == 1) { // crossed a portal line from front to back, we need to repeat the check on the other side as well. inportal = true; } } else if (!(ld->flags & ML_TWOSIDED) || (ld->flags & (ML_BLOCKING | ML_BLOCKMONSTERS | ML_BLOCKEVERYTHING))) { if (!(box.Left() > ld->bbox[BOXRIGHT] || box.Right() < ld->bbox[BOXLEFT] || box.Top() < ld->bbox[BOXBOTTOM] || box.Bottom() > ld->bbox[BOXTOP])) { if (P_PointOnLineSidePrecise(src.x, src.y, ld) != P_PointOnLineSidePrecise(pos.x, pos.y, ld)) return; // line blocks trajectory // ^ } } } if (!inportal) break; // recalculate position and redo the check on the other side of the portal pos = self->Vec3Offset(dist.x, dist.y, 8 * FRACUNIT, false); src.x = pos.x - dist.x; src.y = pos.y - dist.y; } other = Spawn (spawntype, pos.x, pos.y, pos.z, ALLOW_REPLACE); // Check to see if the new Lost Soul's z value is above the // ceiling of its new sector, or below the floor. If so, kill it. if ((other->Z() > (other->Sector->HighestCeiling(other) - other->height)) || (other->Z() < other->Sector->LowestFloor(other))) { // kill it immediately P_DamageMobj (other, self, self, TELEFRAG_DAMAGE, NAME_None);// ^ return; // | } // phares // Check for movements. if (!P_CheckPosition (other, other->Pos())) { // kill it immediately P_DamageMobj (other, self, self, TELEFRAG_DAMAGE, NAME_None); return; } // [RH] Lost souls hate the same things as their pain elementals other->CopyFriendliness (self, !(flags & PAF_NOTARGET)); if (!(flags & PAF_NOSKULLATTACK)) A_SkullAttack(other, SKULLSPEED); }
// // A_PainShootSkull // Spawn a lost soul and launch it at the target // void A_PainShootSkull (AActor *self, angle_t angle) { fixed_t x, y, z; AActor *other; angle_t an; int prestep; // [BC] Spawning of additional lost souls is server-side. if ( NETWORK_GetState( ) == NETSTATE_CLIENT ) return; const PClass *spawntype = NULL; int index=CheckIndex(1, NULL); if (index>=0) { spawntype = PClass::FindClass((ENamedName)StateParameters[index]); } if (spawntype == NULL) spawntype = RUNTIME_CLASS(ALostSoul); // [RH] check to make sure it's not too close to the ceiling if (self->z + self->height + 8*FRACUNIT > self->ceilingz) { if (self->flags & MF_FLOAT) { self->momz -= 2*FRACUNIT; self->flags |= MF_INFLOAT; self->flags4 |= MF4_VFRICTION; } return; } // [RH] make this optional if (i_compatflags & COMPATF_LIMITPAIN) { // count total number of skulls currently on the level // if there are already 20 skulls on the level, don't spit another one int count = 20; FThinkerIterator iterator (spawntype); DThinker *othink; while ( (othink = iterator.Next ()) ) { if (--count == 0) return; } } // okay, there's room for another one an = angle >> ANGLETOFINESHIFT; prestep = 4*FRACUNIT + 3*(self->radius + GetDefaultByType(spawntype)->radius)/2; x = self->x + FixedMul (prestep, finecosine[an]); y = self->y + FixedMul (prestep, finesine[an]); z = self->z + 8*FRACUNIT; // Check whether the Lost Soul is being fired through a 1-sided // phares // wall or an impassible line, or a "monsters can't cross" line.// | // If it is, then we don't allow the spawn. // V if (Check_Sides (self, x, y)) { return; } other = Spawn (spawntype, x, y, z, ALLOW_REPLACE); // [BC] If we're the server, tell clients to spawn the actor. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_SpawnThing( other ); // Check to see if the new Lost Soul's z value is above the // ceiling of its new sector, or below the floor. If so, kill it. if ((other->z > (other->Sector->ceilingplane.ZatPoint (other->x, other->y) - other->height)) || (other->z < other->Sector->floorplane.ZatPoint (other->x, other->y))) { // kill it immediately P_DamageMobj (other, self, self, 1000000, MOD_UNKNOWN); // ^ return; // | } // phares // Check for movements. if (!P_CheckPosition (other, other->x, other->y)) { // kill it immediately P_DamageMobj (other, self, self, 1000000, MOD_UNKNOWN); return; } // [RH] Lost souls hate the same things as their pain elementals other->CopyFriendliness (self, true); A_SkullAttack (other); }