void A_MakePod (AActor *actor) { APod *mo; fixed_t x; fixed_t y; fixed_t z; if (actor->special1 == MAX_GEN_PODS) { // Too many generated pods return; } x = actor->x; y = actor->y; z = actor->z; mo = Spawn<APod> (x, y, ONFLOORZ, ALLOW_REPLACE); if (P_CheckPosition (mo, x, y) == false) { // Didn't fit mo->Destroy (); return; } mo->SetState (&APod::States[S_POD_GROW]); P_ThrustMobj (mo, pr_makepod()<<24, (fixed_t)(4.5*FRACUNIT)); S_Sound (mo, CHAN_BODY, "world/podgrow", 1, ATTN_IDLE); actor->special1++; // Increment generated pod count mo->Generator = actor; // Link the generator to the pod return; }
boolean G_CheckSpot(int playernum, mapthing_t * mthing) { fixed_t x, y; subsector_t *ss; unsigned an; mobj_t *mo; x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; players[playernum].mo->flags2 &= ~MF2_PASSMOBJ; if (!P_CheckPosition(players[playernum].mo, x, y)) { players[playernum].mo->flags2 |= MF2_PASSMOBJ; return false; } players[playernum].mo->flags2 |= MF2_PASSMOBJ; // spawn a teleport fog ss = R_PointInSubsector(x, y); an = ((unsigned) ANG45 * (mthing->angle / 45)) >> ANGLETOFINESHIFT; mo = P_SpawnMobj(x + 20 * finecosine[an], y + 20 * finesine[an], ss->sector->floorheight + TELEFOGHEIGHT, MT_TFOG); if (players[consoleplayer].viewz != 1) S_StartSound(mo, sfx_telept); // don't start sound on first frame return true; }
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MakePod) { ACTION_PARAM_START(1); ACTION_PARAM_CLASS(podtype, 0); AActor *mo; fixed_t x; fixed_t y; fixed_t z; if (self->special1 == MAX_GEN_PODS) { // Too many generated pods return; } x = self->x; y = self->y; z = self->z; mo = Spawn(podtype, x, y, ONFLOORZ, ALLOW_REPLACE); if (!P_CheckPosition (mo, x, y)) { // Didn't fit mo->Destroy (); return; } mo->SetState (mo->FindState("Grow")); P_ThrustMobj (mo, pr_makepod()<<24, (fixed_t)(4.5*FRACUNIT)); S_Sound (mo, CHAN_BODY, self->AttackSound, 1, ATTN_IDLE); self->special1++; // Increment generated pod count mo->master = self; // Link the generator to the pod return; }
void A_RestoreSpecialPosition (AActor *self) { // Move item back to its original location fixed_t _x, _y; sector_t *sec; _x = self->SpawnPoint[0] << FRACBITS; _y = self->SpawnPoint[1] << FRACBITS; sec = R_PointInSubsector (_x, _y)->sector; self->SetOrigin (_x, _y, sec->floorplane.ZatPoint (_x, _y)); P_CheckPosition (self, _x, _y); if (self->flags & MF_SPAWNCEILING) { self->z = self->ceilingz - self->height - (self->SpawnPoint[2] << FRACBITS); } else if (self->flags2 & MF2_SPAWNFLOAT) { fixed_t space = self->ceilingz - self->height - self->floorz; if (space > 48*FRACUNIT) { space -= 40*FRACUNIT; self->z = ((space * pr_restore())>>8) + self->floorz + 40*FRACUNIT; }
bool P_Thing_CanRaise(AActor *thing) { FState * RaiseState = thing->GetRaiseState(); if (RaiseState == NULL) { return false; } AActor *info = thing->GetDefault(); // Check against real height and radius ActorFlags oldflags = thing->flags; double oldheight = thing->Height; double oldradius = thing->radius; thing->flags |= MF_SOLID; thing->Height = info->Height; thing->radius = info->radius; bool check = P_CheckPosition (thing, thing->Pos()); // Restore checked properties thing->flags = oldflags; thing->radius = oldradius; thing->Height = oldheight; if (!check) { return false; } return true; }
// // [Toke - CTF] CTF_MoveFlag // Moves the flag that is linked to a player // void CTF_MoveFlags () { // denis - flag is now a boolean for(size_t i = 0; i < NUMFLAGS; i++) { if(CTFdata[i].flagger && CTFdata[i].actor) { player_t &player = idplayer(CTFdata[i].flagger); AActor *flag = CTFdata[i].actor; if(!player.mo) { flag->UnlinkFromWorld (); return; } extern fixed_t tmfloorz; extern fixed_t tmceilingz; unsigned an = player.mo->angle >> ANGLETOFINESHIFT; fixed_t x = (player.mo->x + FixedMul (-2*FRACUNIT, finecosine[an])); fixed_t y = (player.mo->y + FixedMul (-2*FRACUNIT, finesine[an])); P_CheckPosition (player.mo, player.mo->x, player.mo->y); flag->UnlinkFromWorld (); flag->x = x; flag->y = y; flag->z = player.mo->z; flag->floorz = tmfloorz; flag->ceilingz = tmceilingz; flag->LinkToWorld (); } }
// [RH] We absolutely do not want to pick things up here. The bot code is // executed apart from all the other simulation code, so we don't want it // creating side-effects during gameplay. bool DCajunMaster::SafeCheckPosition (AActor *actor, fixed_t x, fixed_t y) { int savedFlags = actor->flags; actor->flags &= ~MF_PICKUP; bool res = P_CheckPosition (actor, x, y) ? true : false; actor->flags = savedFlags; return res; }
// [RH] We absolutely do not want to pick things up here. The bot code is // executed apart from all the other simulation code, so we don't want it // creating side-effects during gameplay. bool FCajunMaster::SafeCheckPosition (AActor *actor, fixed_t x, fixed_t y, FCheckPosition &tm) { ActorFlags savedFlags = actor->flags; actor->flags &= ~MF_PICKUP; bool res = P_CheckPosition (actor, x, y, tm); actor->flags = savedFlags; return res; }
bool P_Thing_Raise(AActor *thing) { if (thing == NULL) return false; // not valid if (!(thing->flags & MF_CORPSE) ) return true; // not a corpse if (thing->tics != -1) return true; // not lying still yet FState * RaiseState = thing->FindState(NAME_Raise); if (RaiseState == NULL) return true; // monster doesn't have a raise state AActor *info = thing->GetDefault (); thing->velx = thing->vely = 0; // [RH] Check against real height and radius fixed_t oldheight = thing->height; fixed_t oldradius = thing->radius; int oldflags = thing->flags; thing->flags |= MF_SOLID; thing->height = info->height; // [RH] Use real height thing->radius = info->radius; // [RH] Use real radius if (!P_CheckPosition (thing, thing->x, thing->y)) { thing->flags = oldflags; thing->radius = oldradius; thing->height = oldheight; return false; } S_Sound (thing, CHAN_BODY, "vile/raise", 1, ATTN_IDLE); thing->SetState (RaiseState); thing->flags = info->flags; thing->flags2 = info->flags2; thing->flags3 = info->flags3; thing->flags4 = info->flags4; thing->flags5 = info->flags5; thing->flags6 = info->flags6; thing->health = info->health; thing->target = NULL; thing->lastenemy = NULL; // [RH] If it's a monster, it gets to count as another kill if (thing->CountsAsKill()) { level.total_monsters++; } return true; }
// // PIT_VileCheck // // Detect a corpse that could be raised. // bool PIT_VileCheck(Mobj *thing) { int maxdist; bool check; int vileType = E_SafeThingType(MT_VILE); if(!(thing->flags & MF_CORPSE)) return true; // not a monster if(thing->tics != -1) return true; // not lying still yet if(thing->info->raisestate == NullStateNum) return true; // monster doesn't have a raise state maxdist = thing->info->radius + mobjinfo[vileType]->radius; if(D_abs(thing->x-viletryx) > maxdist || D_abs(thing->y-viletryy) > maxdist) return true; // not actually touching // Check to see if the radius and height are zero. If they are // phares // then this is a crushed monster that has been turned into a // | // gib. One of the options may be to ignore this guy. // V // Option 1: the original, buggy method, -> ghost (compatibility) // Option 2: resurrect the monster, but not as a ghost // Option 3: ignore the gib // if (Option3) // ^ // if ((thing->height == 0) && (thing->radius == 0)) // | // return true; // phares corpsehit = thing; corpsehit->momx = corpsehit->momy = 0; if(comp[comp_vile]) { // phares corpsehit->height <<= 2; // V // haleyjd 11/11/04: this is also broken by Lee's change to // PIT_CheckThing when not in demo_compatibility. if(demo_version >= 331) corpsehit->flags |= MF_SOLID; check = P_CheckPosition(corpsehit, corpsehit->x, corpsehit->y); if(demo_version >= 331) corpsehit->flags &= ~MF_SOLID; corpsehit->height >>= 2; } else {
dboolean G_CheckSpot(int playernum, mapthing_t* mthing) { fixed_t x; fixed_t y; subsector_t* ss; angle_t an; mobj_t* mo; int i; if(!players[playernum].mo) { // first spawn of level, before corpses for(i = 0; i < playernum; i++) { if((players[i].mo->x == INT2F(mthing->x)) && (players[i].mo->y == INT2F(mthing->y))) { return false; } } return true; } x = INT2F(mthing->x); y = INT2F(mthing->y); if(!P_CheckPosition(players[playernum].mo, x, y)) { return false; } // flush an old corpse if needed if(bodyqueslot >= BODYQUESIZE) { P_RemoveMobj(bodyque[bodyqueslot % BODYQUESIZE]); } bodyque[bodyqueslot%BODYQUESIZE] = players[playernum].mo; bodyqueslot++; // spawn a teleport fog ss = R_PointInSubsector(x, y); // 20120402 villsa - force angle_t typecast to avoid issues on 64-bit machines an = ANG45 * (angle_t)(mthing->angle / 45); mo = P_SpawnMobj( x + 20*dcos(an), y + 20*dsin(an), ss->sector->floorheight, MT_TELEPORTFOG ); if(players[playernum].viewz != 1) { S_StartSound(mo, sfx_telept); // don't start sound on first frame } return true; }
bool P_Thing_Raise(AActor *thing, AActor *raiser, int flags) { if (!thing) return false; FState * RaiseState = thing->GetRaiseState(); if (RaiseState == NULL) { return false; // monster doesn't have a raise state } AActor *info = thing->GetDefault (); thing->Vel.X = thing->Vel.Y = 0; // [RH] Check against real height and radius double oldheight = thing->Height; double oldradius = thing->radius; ActorFlags oldflags = thing->flags; thing->flags |= MF_SOLID; thing->Height = info->Height; // [RH] Use real height thing->radius = info->radius; // [RH] Use real radius if (!(flags & RF_NOCHECKPOSITION) && !P_CheckPosition (thing, thing->Pos())) { thing->flags = oldflags; thing->radius = oldradius; thing->Height = oldheight; return false; } if (!P_CanResurrect(raiser, thing)) return false; S_Sound (thing, CHAN_BODY, "vile/raise", 1, ATTN_IDLE); thing->Revive(); if ((flags & RF_TRANSFERFRIENDLINESS) && raiser != nullptr) { // Let's copy the friendliness of the one who raised it. thing->CopyFriendliness(raiser, false); } thing->SetState (RaiseState); return true; }
bool P_Thing_Raise(AActor *thing, AActor *raiser) { FState * RaiseState = thing->GetRaiseState(); if (RaiseState == NULL) { return true; // monster doesn't have a raise state } AActor *info = thing->GetDefault (); thing->Vel.X = thing->Vel.Y = 0; // [RH] Check against real height and radius double oldheight = thing->Height; double oldradius = thing->radius; ActorFlags oldflags = thing->flags; thing->flags |= MF_SOLID; thing->Height = info->Height; // [RH] Use real height thing->radius = info->radius; // [RH] Use real radius if (!P_CheckPosition (thing, thing->Pos())) { thing->flags = oldflags; thing->radius = oldradius; thing->Height = oldheight; return false; } S_Sound (thing, CHAN_BODY, "vile/raise", 1, ATTN_IDLE); thing->Revive(); if (raiser != NULL) { // Let's copy the friendliness of the one who raised it. thing->CopyFriendliness(raiser, false); } thing->SetState (RaiseState); return true; }
boolean G_CheckSpot (int playernum, mapthing_t *mthing) { fixed_t x,y; subsector_t *ss; int an; mobj_t *mo; x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; if (!P_CheckPosition (players[playernum].mo, x, y) ) return false; ss = R_PointInSubsector (x,y); an = ( ANG45 * (mthing->angle/45) ) >> ANGLETOFINESHIFT; /* spawn a teleport fog */ mo = P_SpawnMobj (x+20*finecosine[an], y+20*finesine[an], ss->sector->floorheight , MT_TFOG); S_StartSound (mo, sfx_telept); return true; }
static int mobj_set(lua_State *L) { mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); enum mobj_e field = Lua_optoption(L, 2, mobj_opt[0], mobj_opt); lua_settop(L, 3); if (!mo) return LUA_ErrInvalid(L, "mobj_t"); if (hud_running) return luaL_error(L, "Do not alter mobj_t in HUD rendering code!"); switch(field) { case mobj_valid: return NOSET; case mobj_x: return NOSETPOS; case mobj_y: return NOSETPOS; case mobj_z: { // z doesn't cross sector bounds so it's okay. mobj_t *ptmthing = tmthing; mo->z = (fixed_t)luaL_checkinteger(L, 3); P_CheckPosition(mo, mo->x, mo->y); mo->floorz = tmfloorz; mo->ceilingz = tmceilingz; P_SetTarget(&tmthing, ptmthing); break; } case mobj_snext: return NOSETPOS; case mobj_sprev: return UNIMPLEMENTED; case mobj_angle: mo->angle = (angle_t)luaL_checkinteger(L, 3); if (mo->player == &players[displayplayer]) localangle = mo->angle; else if (mo->player == &players[secondarydisplayplayer]) localangle2 = mo->angle; break; case mobj_sprite: mo->sprite = luaL_checkinteger(L, 3); break; case mobj_frame: mo->frame = (UINT32)luaL_checkinteger(L, 3); break; case mobj_touching_sectorlist: return UNIMPLEMENTED; case mobj_subsector: return NOSETPOS; case mobj_floorz: return NOSETPOS; case mobj_ceilingz: return NOSETPOS; case mobj_radius: { mobj_t *ptmthing = tmthing; mo->radius = (fixed_t)luaL_checkinteger(L, 3); if (mo->radius < 0) mo->radius = 0; P_CheckPosition(mo, mo->x, mo->y); mo->floorz = tmfloorz; mo->ceilingz = tmceilingz; P_SetTarget(&tmthing, ptmthing); break; } case mobj_height: { mobj_t *ptmthing = tmthing; mo->height = (fixed_t)luaL_checkinteger(L, 3); if (mo->height < 0) mo->height = 0; P_CheckPosition(mo, mo->x, mo->y); mo->floorz = tmfloorz; mo->ceilingz = tmceilingz; P_SetTarget(&tmthing, ptmthing); break; } case mobj_momx: mo->momx = (fixed_t)luaL_checkinteger(L, 3); break; case mobj_momy: mo->momy = (fixed_t)luaL_checkinteger(L, 3); break; case mobj_momz: mo->momz = (fixed_t)luaL_checkinteger(L, 3); break; case mobj_pmomz: mo->pmomz = (fixed_t)luaL_checkinteger(L, 3); break; case mobj_tics: mo->tics = luaL_checkinteger(L, 3); break; case mobj_state: // set state by enum if (mo->player) P_SetPlayerMobjState(mo, luaL_checkinteger(L, 3)); else P_SetMobjState(mo, luaL_checkinteger(L, 3)); break; case mobj_flags: // special handling for MF_NOBLOCKMAP and MF_NOSECTOR { UINT32 flags = luaL_checkinteger(L, 3); if ((flags & (MF_NOBLOCKMAP|MF_NOSECTOR)) != (mo->flags & (MF_NOBLOCKMAP|MF_NOSECTOR))) { P_UnsetThingPosition(mo); mo->flags = flags; if (flags & MF_NOSECTOR && sector_list) { P_DelSeclist(sector_list); sector_list = NULL; } mo->snext = NULL, mo->sprev = NULL; mo->bnext = NULL, mo->bprev = NULL; P_SetThingPosition(mo); } else mo->flags = flags; break; } case mobj_flags2: mo->flags2 = (UINT32)luaL_checkinteger(L, 3); break; case mobj_eflags: mo->eflags = (UINT32)luaL_checkinteger(L, 3); break; case mobj_skin: // set skin by name { INT32 i; char skin[SKINNAMESIZE+1]; // all skin names are limited to this length strlcpy(skin, luaL_checkstring(L, 3), sizeof skin); strlwr(skin); // all skin names are lowercase for (i = 0; i < numskins; i++) if (fastcmp(skins[i].name, skin)) { mo->skin = &skins[i]; return 0; } return luaL_error(L, "mobj.skin '%s' not found!", skin); } case mobj_color: mo->color = ((UINT8)luaL_checkinteger(L, 3)) % MAXSKINCOLORS; break; case mobj_bnext: return NOSETPOS; case mobj_bprev: return UNIMPLEMENTED; case mobj_hnext: mo->hnext = luaL_checkudata(L, 3, META_MOBJ); break; case mobj_hprev: mo->hprev = luaL_checkudata(L, 3, META_MOBJ); break; case mobj_type: // yeah sure, we'll let you change the mobj's type. { mobjtype_t newtype = luaL_checkinteger(L, 3); if (newtype > MT_LASTFREESLOT) return luaL_error(L, "mobj.type %u is out of bounds.", newtype); mo->type = newtype; mo->info = &mobjinfo[newtype]; P_SetScale(mo, mo->scale); break; } case mobj_info: return NOSET; case mobj_health: mo->health = luaL_checkinteger(L, 3); break; case mobj_movedir: mo->movedir = (angle_t)luaL_checkinteger(L, 3); break; case mobj_movecount: mo->movecount = luaL_checkinteger(L, 3); break; case mobj_target: if (lua_isnil(L, 3)) P_SetTarget(&mo->target, NULL); else { mobj_t *target = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); P_SetTarget(&mo->target, target); } break; case mobj_reactiontime: mo->reactiontime = luaL_checkinteger(L, 3); break; case mobj_threshold: mo->threshold = luaL_checkinteger(L, 3); break; case mobj_player: return NOSET; case mobj_lastlook: mo->lastlook = luaL_checkinteger(L, 3); break; case mobj_spawnpoint: if (lua_isnil(L, 3)) mo->spawnpoint = NULL; else { mapthing_t *spawnpoint = *((mapthing_t **)luaL_checkudata(L, 3, META_MAPTHING)); mo->spawnpoint = spawnpoint; } break; case mobj_tracer: if (lua_isnil(L, 3)) P_SetTarget(&mo->tracer, NULL); else { mobj_t *tracer = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); P_SetTarget(&mo->tracer, tracer); } break; case mobj_friction: mo->friction = (fixed_t)luaL_checkinteger(L, 3); break; case mobj_movefactor: mo->movefactor = (fixed_t)luaL_checkinteger(L, 3); break; case mobj_fuse: mo->fuse = luaL_checkinteger(L, 3); break; case mobj_watertop: mo->watertop = (fixed_t)luaL_checkinteger(L, 3); break; case mobj_waterbottom: mo->waterbottom = (fixed_t)luaL_checkinteger(L, 3); break; case mobj_mobjnum: return UNIMPLEMENTED; case mobj_scale: { fixed_t scale = (fixed_t)luaL_checkinteger(L, 3); if (scale < FRACUNIT/100) scale = FRACUNIT/100; mo->destscale = scale; P_SetScale(mo, scale); break; } case mobj_destscale: { fixed_t scale = (fixed_t)luaL_checkinteger(L, 3); if (scale < FRACUNIT/100) scale = FRACUNIT/100; mo->destscale = scale; break; } case mobj_scalespeed: mo->scalespeed = (fixed_t)luaL_checkinteger(L, 3); break; case mobj_extravalue1: mo->extravalue1 = luaL_checkinteger(L, 3); break; case mobj_extravalue2: mo->extravalue2 = luaL_checkinteger(L, 3); break; case mobj_cusval: mo->cusval = luaL_checkinteger(L, 3); break; case mobj_cvmem: mo->cvmem = luaL_checkinteger(L, 3); break; default: lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS); I_Assert(lua_istable(L, -1)); lua_pushlightuserdata(L, mo); lua_rawget(L, -2); if (lua_isnil(L, -1)) { // This index doesn't have a table for extra values yet, let's make one. lua_pop(L, 1); CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; adding it as Lua data.\n"), "mobj_t", lua_tostring(L, 2)); lua_newtable(L); lua_pushlightuserdata(L, mo); lua_pushvalue(L, -2); // ext value table lua_rawset(L, -4); // LREG_EXTVARS table } lua_pushvalue(L, 2); // key lua_pushvalue(L, 3); // value to store lua_settable(L, -3); lua_pop(L, 2); break; } return 0; }
// // 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); }
// // 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); }
//=========================================================================== // P_CheckSpot // Returns false if the player cannot be respawned // at the given mapthing_t spot because something is occupying it // FIXME: Quite a mess! //=========================================================================== boolean P_CheckSpot(int playernum, mapthing_t * mthing, boolean doTeleSpark) { fixed_t x; fixed_t y; unsigned an; mobj_t *mo; #if __JDOOM__ || __JHEXEN__ subsector_t *ss; #endif #if __JDOOM__ int i; #endif #if __JHERETIC__ || __JHEXEN__ mapthing_t faraway; boolean using_dummy = false; #endif #if __JDOOM__ if(!players[playernum].plr->mo) { // first spawn of level, before corpses for(i = 0; i < playernum; i++) { if(players[i].plr->mo && players[i].plr->mo->x == mthing->x << FRACBITS && players[i].plr->mo->y == mthing->y << FRACBITS) return false; } return true; } #endif x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; #if __JHERETIC__ || __JHEXEN__ if(!players[playernum].plr->mo) { // The player doesn't have a mobj. Let's create a dummy. faraway.x = faraway.y = DDMAXSHORT; P_SpawnPlayer(&faraway, playernum); using_dummy = true; } players[playernum].plr->mo->flags2 &= ~MF2_PASSMOBJ; #endif if(!P_CheckPosition(players[playernum].plr->mo, x, y)) { #if __JHERETIC__ || __JHEXEN__ players[playernum].plr->mo->flags2 |= MF2_PASSMOBJ; if(using_dummy) { P_RemoveMobj(players[playernum].plr->mo); players[playernum].plr->mo = NULL; } #endif return false; } #if __JHERETIC__ players[playernum].plr->mo->flags2 |= MF2_PASSMOBJ; #endif #if __JHERETIC__ || __JHEXEN__ if(using_dummy) { P_RemoveMobj(players[playernum].plr->mo); players[playernum].plr->mo = NULL; } #endif #if __JDOOM__ G_QueueBody(players[playernum].plr->mo); #endif if(doTeleSpark) { // spawn a teleport fog an = (ANG45 * (mthing->angle / 45)) >> ANGLETOFINESHIFT; #if __JDOOM__ || __JHEXEN__ ss = R_PointInSubsector(x, y); mo = P_SpawnMobj(x + 20 * finecosine[an], y + 20 * finesine[an], ss->sector->floorheight, MT_TFOG); #else // __JHERETIC__ mo = P_SpawnTeleFog(x + 20 * finecosine[an], y + 20 * finesine[an]); #endif // don't start sound on first frame if(players[consoleplayer].plr->viewz != 1) { #ifdef __JHEXEN__ S_StartSound(SFX_TELEPORT, mo); #else S_StartSound(sfx_telept, mo); #endif } } return true; }
// // 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); }
// add_to_pid_list // The routine add_to_pid_list() does a lot. It walks the // pid mobj linked list to check an actual process versus the // Doom monster status. It is sorted in ascending pid order. // If this process is not in the list, a monster is spawned // before linking it into the list. Unset the delete flag to // ensure the process is not deleted from the list during cleanup. // If this process is already in the list, unset the flag that says // "delete me from the list during next list cleanup" and update // the pid monster's name. If the process is in the list and Doom // killed it since the last list cleanup, resurrect the monster like // the archvile does (because the process didn't really die). // If we can't resurrect it in that case, remove the body and spawn // a new monster. void add_to_pid_list(int pid, const char *name, int demon) { mobj_t *new_mobj = NULL; int name_length = 0; boolean position_ok = false; // If the list isn't empty and the new pid is larger than the largest // pid currently in the list, spawn the mobj and link it as the tail // of the list if we placed it on the map without a collision. if ( pid_list_tail && pid > pid_list_tail->m_pid ) { if ( (new_mobj = add_new_process(pid, name, demon)) != NULL ) { new_mobj->ppid = pid_list_tail; new_mobj->npid = NULL; pid_list_tail->npid = new_mobj; pid_list_tail = new_mobj; new_mobj->m_del_from_pid_list = false; } // If the list isn't empty and the new pid is smaller than the smallest // pid currently in the list, spawn the mobj and link it as the head // of the list if we placed it on the map without a collision. } else if ( pid_list_head && pid < pid_list_head->m_pid ) { if ( (new_mobj = add_new_process(pid, name, demon)) != NULL ) { new_mobj->ppid = NULL; new_mobj->npid = pid_list_head; pid_list_head->ppid = new_mobj; pid_list_head = new_mobj; new_mobj->m_del_from_pid_list = false; } // If the read-in pid is not larger or smaller than the extremes of // the list, walk down the list until the current pointer is at the // mobj with the pid ahead of the read-in pid. } else { pid_list_pos = pid_list_head; while ( pid_list_pos != NULL && pid > pid_list_pos->m_pid ) { // NOTE: // If we were guaranteed that the pid's were coming in ascending order // from ps, we could do the deletion of unused nodes here and the code // would be much more efficient. However, we sort ps output by the // process start time. This could lead to smaller pid's coming first // when the pid counter wraps from the max back to smaller numbers. pid_list_pos = pid_list_pos->npid; } // end while // Now, check why we stopped the walk down the list. // First, check to see if this is an empty list. If it isn't empty, // check whether the mobj's pid is equal or if it's larger than the // read-in pid. // If the list is completely empty, spawn the mobj and make it the // only member of the list. if ( pid_list_pos != NULL ) { // if list isn't empty if ( pid == pid_list_pos->m_pid ) { // if the read-in pid is same as mobj's pid, set the // delete flag to false so the mobj is not unlinked // from the list during cleanup. pid_list_pos->m_del_from_pid_list = false; // copy the incoming pid's name over the mobj's name // in case an exec() was called by the process. // ie. mingetty --> bash // TODO: Make name change conditional? Or is memcpy() fast enough // that we can do it every time? name_length = strlen( name ); if ( name_length <= 7 ) { memcpy(pid_list_pos->m_pname, name, 8); } else { memcpy(pid_list_pos->m_pname, name + name_length - 7, 8); } // if the process is still running on the machine, but // the mobj has been killed in Doom (ie. the process // trapped the kill signal or the user didn't have permission // to kill the process), do an archvile-like resurrection // on the mobj. if we can't do the resurrection, remove the // body and re-spawn the mobj normally. // much of the following code is taken from the routines // PIT_VileCheck() and A_VileChase() in p_enemy.c if ( !(pid_list_pos->m_draw_pid_info) ) { // if Doom thinks // the process is // dead // ability to resurrect monster (from PIT_VileCheck). pid_list_pos->momx = pid_list_pos->momy = 0; pid_list_pos->height <<= 2; position_ok = P_CheckPosition(pid_list_pos, pid_list_pos->x, pid_list_pos->y); pid_list_pos->height >>= 2; // if any of these conditions, we CAN'T resurrect if ( !(pid_list_pos->flags & MF_CORPSE) || (pid_list_pos->tics != -1) || (pid_list_pos->info->raisestate == S_NULL) || !(position_ok) ) { // can't raise it: delete and respawn // print status msg fprintf(stderr, " process %d [%s] monster delete/respawn\n", pid_list_pos->m_pid, pid_list_pos->m_pname); // In this case, we need to respawn the monster // since we can't resurrect it. We delete the mobj // from the pid linked list so it will re-spawn on // the next call to add_to_pid_list(). pid_list_pos->m_del_from_pid_list = true; // trick cleanup_pid_list() into thinking it needs // to remove this body pid_list_pos->m_draw_pid_info = true; // remove this mobj from pid list (and remove body) cleanup_pid_list(pid_list_pos); // try to respawn monster add_to_pid_list(pid, name, demon); } else { // we can raise the monster's body // print status msg fprintf(stderr, " process %d [%s] monster resurrect\n", pid_list_pos->m_pid, pid_list_pos->m_pname); // most of this is from A_VileChase() P_SetMobjState(pid_list_pos, pid_list_pos->info->raisestate); pid_list_pos->height <<= 2; pid_list_pos->flags = pid_list_pos->info->flags; pid_list_pos->health = pid_list_pos->info->spawnhealth; pid_list_pos->target = NULL; // draw the pid info again pid_list_pos->m_draw_pid_info = true; // need to unset the flag (again) to not count this // monster in end-of-level kill % -- it was reset when // the mobj flags were copied from the info record above pid_list_pos->flags &= ~MF_COUNTKILL; } } // end 'if the monster's dead but not the process.' } else { // the read-in pid is smaller than the currently // pointed to mobj. spawn a new mobj and link it // into the list if it is placed without a collision. if ( (new_mobj = add_new_process(pid, name, demon)) != NULL ) {
if(demo_version >= 331) corpsehit->flags &= ~MF_SOLID; corpsehit->height >>= 2; } else { int height,radius; height = corpsehit->height; // save temporarily radius = corpsehit->radius; // save temporarily corpsehit->height = P_ThingInfoHeight(corpsehit->info); corpsehit->radius = corpsehit->info->radius; corpsehit->flags |= MF_SOLID; check = P_CheckPosition(corpsehit,corpsehit->x,corpsehit->y); corpsehit->height = height; // restore corpsehit->radius = radius; // restore // ^ corpsehit->flags &= ~MF_SOLID; } // | // phares if(!check) return true; // doesn't fit here return false; // got one, so stop checking } // // A_VileChase // // Check for ressurecting a body //