예제 #1
0
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;
}
예제 #2
0
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;
}
예제 #3
0
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;
}
예제 #4
0
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;
		}
예제 #5
0
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;
}
예제 #6
0
//
//	[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 ();
		}
	}
예제 #7
0
// [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;
}
예제 #8
0
// [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;
}
예제 #9
0
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;
}
예제 #10
0
//
// 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
   {
예제 #11
0
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;
}
예제 #12
0
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;
}
예제 #13
0
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;
}
예제 #14
0
파일: g_game.c 프로젝트: Arc0re/jaguardoom
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; 
} 
예제 #15
0
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;
}
예제 #16
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);
}
예제 #17
0
//
// 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);
}
예제 #18
0
//===========================================================================
// 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;
}
예제 #19
0
//
// 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);
}
예제 #20
0
// 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 ) {
예제 #21
0
      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
//