コード例 #1
0
void A_VolcBallImpact (AActor *ball)
{
	int i;
	AActor *tiny;
	angle_t angle;

	if (ball->z <= ball->floorz)
	{
		ball->flags |= MF_NOGRAVITY;
		ball->gravity = FRACUNIT;
		ball->z += 28*FRACUNIT;
		//ball->momz = 3*FRACUNIT;
	}
	P_RadiusAttack (ball, ball->target, 25, 25, NAME_Fire, true);
	for (i = 0; i < 4; i++)
	{
		tiny = Spawn<AVolcanoTBlast> (ball->x, ball->y, ball->z, ALLOW_REPLACE);
		tiny->target = ball;
		angle = i*ANG90;
		tiny->angle = angle;
		angle >>= ANGLETOFINESHIFT;
		tiny->momx = FixedMul (FRACUNIT*7/10, finecosine[angle]);
		tiny->momy = FixedMul (FRACUNIT*7/10, finesine[angle]);
		tiny->momz = FRACUNIT + (pr_impact() << 9);
		P_CheckMissileSpawn (tiny);
	}
}
コード例 #2
0
DEFINE_ACTION_FUNCTION(AActor, A_VolcBallImpact)
{
	unsigned int i;
	AActor *tiny;
	angle_t angle;

	if (self->z <= self->floorz)
	{
		self->flags |= MF_NOGRAVITY;
		self->gravity = FRACUNIT;
		self->z += 28*FRACUNIT;
		//self->velz = 3*FRACUNIT;
	}
	P_RadiusAttack (self, self->target, 25, 25, NAME_Fire, RADF_HURTSOURCE);
	for (i = 0; i < 4; i++)
	{
		tiny = Spawn("VolcanoTBlast", self->x, self->y, self->z, ALLOW_REPLACE);
		tiny->target = self;
		angle = i*ANG90;
		tiny->angle = angle;
		angle >>= ANGLETOFINESHIFT;
		tiny->velx = FixedMul (FRACUNIT*7/10, finecosine[angle]);
		tiny->vely = FixedMul (FRACUNIT*7/10, finesine[angle]);
		tiny->velz = FRACUNIT + (pr_volcimpact() << 9);
		P_CheckMissileSpawn (tiny, self->radius);
	}
}
コード例 #3
0
ファイル: a_sentinel.cpp プロジェクト: Accusedbold/zdoom
DEFINE_ACTION_FUNCTION(AActor, A_SentinelAttack)
{
	PARAM_ACTION_PROLOGUE;

	AActor *missile, *trail;

	// [BB] Without a target the P_SpawnMissileZAimed call will crash.
	if (!self->target)
	{
		return 0;
	}

	missile = P_SpawnMissileZAimed (self, self->Z() + 32, self->target, PClass::FindActor("SentinelFX2"));

	if (missile != NULL && (missile->Vel.X != 0 || missile->Vel.Y != 0))
	{
		for (int i = 8; i > 1; --i)
		{
			trail = Spawn("SentinelFX1",
				self->Vec3Angle(missile->radius*i, missile->Angles.Yaw, 32 + missile->Vel.Z / 4 * i), ALLOW_REPLACE);
			if (trail != NULL)
			{
				trail->target = self;
				trail->Vel = missile->Vel;
				P_CheckMissileSpawn (trail, self->radius);
			}
		}
		missile->AddZ(missile->Vel.Z / 4);
	}
	return 0;
}
コード例 #4
0
ファイル: a_strifeweapons.cpp プロジェクト: Edward850/zdoom
AActor *P_SpawnSubMissile (AActor *source, PClassActor *type, AActor *target)
{
	AActor *other = Spawn (type, source->Pos(), ALLOW_REPLACE);

	if (other == NULL)
	{
		return NULL;
	}

	other->target = target;
	other->angle = source->angle;

	other->velx = FixedMul (other->Speed, finecosine[source->angle >> ANGLETOFINESHIFT]);
	other->vely = FixedMul (other->Speed, finesine[source->angle >> ANGLETOFINESHIFT]);

	if (other->flags4 & MF4_SPECTRAL)
	{
		if (source->flags & MF_MISSILE && source->flags4 & MF4_SPECTRAL)
		{
			other->FriendPlayer = source->FriendPlayer;
		}
		else
		{
			other->SetFriendPlayer(target->player);
		}
	}

	if (P_CheckMissileSpawn (other, source->radius))
	{
		angle_t pitch = P_AimLineAttack (source, source->angle, 1024*FRACUNIT);
		other->velz = FixedMul (-finesine[pitch>>ANGLETOFINESHIFT], other->Speed);
		return other;
	}
コード例 #5
0
AActor *P_SpawnSubMissile (AActor *source, PClassActor *type, AActor *target)
{
	AActor *other = Spawn (type, source->Pos(), ALLOW_REPLACE);

	if (other == NULL)
	{
		return NULL;
	}

	other->target = target;
	other->Angles.Yaw = source->Angles.Yaw;
	other->VelFromAngle();

	if (other->flags4 & MF4_SPECTRAL)
	{
		if (source->flags & MF_MISSILE && source->flags4 & MF4_SPECTRAL)
		{
			other->FriendPlayer = source->FriendPlayer;
		}
		else
		{
			other->SetFriendPlayer(target->player);
		}
	}

	if (P_CheckMissileSpawn (other, source->radius))
	{
		DAngle pitch = P_AimLineAttack (source, source->Angles.Yaw, 1024.);
		other->Vel.Z = -other->Speed * pitch.Sin();
		return other;
	}
	return NULL;
}
コード例 #6
0
ファイル: p_pspr.c プロジェクト: Mistranger/prboom-plus
void A_FireOldBFG(player_t *player, pspdef_t *psp)
{
  int type = MT_PLASMA1;

  if (compatibility_level < mbf_compatibility)
    return;

  CHECK_WEAPON_CODEPOINTER("A_FireOldBFG", player);

  if (weapon_recoil && !(player->mo->flags & MF_NOCLIP))
    P_Thrust(player, ANG180 + player->mo->angle,
    512*recoil_values[wp_plasma]);

  player->ammo[weaponinfo[player->readyweapon].ammo]--;

  player->extralight = 2;

  do
  {
    mobj_t *th, *mo = player->mo;
    angle_t an = mo->angle;
    angle_t an1 = ((P_Random(pr_bfg)&127) - 64) * (ANG90/768) + an;
    angle_t an2 = ((P_Random(pr_bfg)&127) - 64) * (ANG90/640) + ANG90;
    extern int autoaim;

    if (autoaim/* || !beta_emulation*/)
    {
      // killough 8/2/98: make autoaiming prefer enemies
      uint_64_t mask = mbf_features ? MF_FRIEND : 0;
      fixed_t slope;
      do
      {
        slope = P_AimLineAttack(mo, an, 16*64*FRACUNIT, mask);
        if (!linetarget)
          slope = P_AimLineAttack(mo, an += 1<<26, 16*64*FRACUNIT, mask);
        if (!linetarget)
          slope = P_AimLineAttack(mo, an -= 2<<26, 16*64*FRACUNIT, mask);
        if (!linetarget)
          slope = 0, an = mo->angle;
      }
      while (mask && (mask=0, !linetarget));     // killough 8/2/98
      an1 += an - mo->angle;
      an2 += tantoangle[slope >> DBITS];
    }

    th = P_SpawnMobj(mo->x, mo->y, mo->z + 62*FRACUNIT - player->psprites[ps_weapon].sy, type);
    P_SetTarget(&th->target, mo);
    th->angle = an1;
    th->momx = finecosine[an1>>ANGLETOFINESHIFT] * 25;
    th->momy = finesine[an1>>ANGLETOFINESHIFT] * 25;
    th->momz = finetangent[an2>>ANGLETOFINESHIFT] * 25;
    P_CheckMissileSpawn(th);
  }
  while ((type != MT_PLASMA2) && (type = MT_PLASMA2)); //killough: obfuscated!
}
コード例 #7
0
void A_SpectralMissile (AActor *self, const char *missilename)
{
	if (self->target != NULL)
	{
		AActor *missile = P_SpawnMissileXYZ (self->x, self->y, self->z + 32*FRACUNIT, 
			self, self->target, PClass::FindClass(missilename), false);
		if (missile != NULL)
		{
			missile->tracer = self->target;
			P_CheckMissileSpawn(missile);
		}
	}
}
コード例 #8
0
dd_bool EV_ThingProjectile(byte* args, dd_bool gravity)
{
    uint an;
    int tid, searcher;
    angle_t angle;
    coord_t speed, vspeed;
    mobjtype_t moType;
    mobj_t* mobj, *newMobj;
    dd_bool success;

    success = false;
    searcher = -1;
    tid = args[0];
    moType = TranslateThingType[args[1]];
    if(G_Ruleset_NoMonsters() && (MOBJINFO[moType].flags & MF_COUNTKILL))
    {
        // Don't spawn monsters if -nomonsters
        return false;
    }

    angle = (int) args[2] << 24;
    an = angle >> ANGLETOFINESHIFT;
    speed = FIX2FLT((int) args[3] << 13);
    vspeed = FIX2FLT((int) args[4] << 13);
    while((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
    {
        if((newMobj = P_SpawnMobj(moType, mobj->origin, angle, 0)))
        {
            if(newMobj->info->seeSound)
                S_StartSound(newMobj->info->seeSound, newMobj);

            newMobj->target = mobj; // Originator
            newMobj->mom[MX] = speed * FIX2FLT(finecosine[an]);
            newMobj->mom[MY] = speed * FIX2FLT(finesine[an]);
            newMobj->mom[MZ] = vspeed;
            newMobj->flags2 |= MF2_DROPPED; // Don't respawn
            if(gravity == true)
            {
                newMobj->flags &= ~MF_NOGRAVITY;
                newMobj->flags2 |= MF2_LOGRAV;
            }

            if(P_CheckMissileSpawn(newMobj) == true)
            {
                success = true;
            }
        }
    }

    return success;
}
コード例 #9
0
ファイル: p_things.cpp プロジェクト: WChrisK/OdaStats
BOOL P_Thing_Projectile (int tid, int type, angle_t angle,
						 fixed_t speed, fixed_t vspeed, BOOL gravity)
{
	int rtn = 0;
	int kind;
	AActor *spot = NULL, *mobj;

	if (type >= NumSpawnableThings)
		return false;

	if ( (kind = SpawnableThings[type]) == 0)
		return false;

	if ((mobjinfo[kind].flags & MF_COUNTKILL) && sv_nomonsters)
		return false;

	while ( (spot = AActor::FindByTID (spot, tid)) )
	{
		if (spot->type != MT_MAPSPOT && spot->type != MT_MAPSPOTGRAVITY)
			continue;

		mobj = new AActor (spot->x, spot->y, spot->z, (mobjtype_t)kind);

		if (mobj)
		{
			if (mobj->info->seesound)
				S_Sound (mobj, CHAN_VOICE, mobj->info->seesound, 1, ATTN_NORM);
			if (gravity)
			{
				mobj->flags &= ~MF_NOGRAVITY;
				if (!(mobj->flags & MF_COUNTKILL))
					mobj->flags2 |= MF2_LOGRAV;
			}
			else
				mobj->flags |= MF_NOGRAVITY;
			mobj->target = spot->ptr();
			mobj->angle = angle;
			mobj->momx = FixedMul (speed, finecosine[angle>>ANGLETOFINESHIFT]);
			mobj->momy = FixedMul (speed, finesine[angle>>ANGLETOFINESHIFT]);
			mobj->momz = vspeed;
			mobj->flags |= MF_DROPPED;
			if (mobj->flags & MF_MISSILE)
				rtn = P_CheckMissileSpawn (mobj);
			else if (!P_TestMobjLocation (mobj))
				mobj->Destroy ();
		} 
	}

	return rtn;
}
コード例 #10
0
ファイル: P_things.c プロジェクト: amitahire/development
boolean EV_ThingProjectile(byte *args, boolean gravity)
{
	int     tid;
	angle_t angle;
	int     fineAngle;
	fixed_t speed;
	fixed_t vspeed;
	mobjtype_t moType;
	mobj_t *mobj;
	mobj_t *newMobj;
	int     searcher;
	boolean success;

	success = false;
	searcher = -1;
	tid = args[0];
	moType = TranslateThingType[args[1]];
	if(nomonsters && (mobjinfo[moType].flags & MF_COUNTKILL))
	{							// Don't spawn monsters if -nomonsters
		return false;
	}
	angle = (int) args[2] << 24;
	fineAngle = angle >> ANGLETOFINESHIFT;
	speed = (int) args[3] << 13;
	vspeed = (int) args[4] << 13;
	while((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
	{
		newMobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, moType);
		if(newMobj->info->seesound)
		{
			S_StartSound(newMobj->info->seesound, newMobj);
		}
		newMobj->target = mobj;	// Originator
		newMobj->angle = angle;
		newMobj->momx = FixedMul(speed, finecosine[fineAngle]);
		newMobj->momy = FixedMul(speed, finesine[fineAngle]);
		newMobj->momz = vspeed;
		newMobj->flags2 |= MF2_DROPPED;	// Don't respawn
		if(gravity == true)
		{
			newMobj->flags &= ~MF_NOGRAVITY;
			newMobj->flags2 |= MF2_LOGRAV;
		}
		if(P_CheckMissileSpawn(newMobj) == true)
		{
			success = true;
		}
	}
	return success;
}
コード例 #11
0
ファイル: a_minotaur.cpp プロジェクト: nano-bot/zdoom
DEFINE_ACTION_FUNCTION(AActor, A_MntrFloorFire)
{
    PARAM_ACTION_PROLOGUE;

    AActor *mo;

    self->SetZ(self->floorz);
    double x = pr_fire.Random2() / 64.;
    double y = pr_fire.Random2() / 64.;

    mo = Spawn("MinotaurFX3", self->Vec2OffsetZ(x, y, self->floorz), ALLOW_REPLACE);
    mo->target = self->target;
    mo->Vel.X = MinVel; // Force block checking
    P_CheckMissileSpawn (mo, self->radius);
    return 0;
}
コード例 #12
0
DEFINE_ACTION_FUNCTION(AActor, A_LichIceImpact)
{
	int i;
	angle_t angle;
	AActor *shard;

	for (i = 0; i < 8; i++)
	{
		shard = Spawn("HeadFX2", self->x, self->y, self->z, ALLOW_REPLACE);
		angle = i*ANG45;
		shard->target = self->target;
		shard->angle = angle;
		angle >>= ANGLETOFINESHIFT;
		shard->velx = FixedMul (shard->Speed, finecosine[angle]);
		shard->vely = FixedMul (shard->Speed, finesine[angle]);
		shard->velz = -FRACUNIT*6/10;
		P_CheckMissileSpawn (shard);
	}
}
コード例 #13
0
DEFINE_ACTION_FUNCTION(AActor, A_VolcanoBlast)
{
	int i;
	int count;
	AActor *blast;
	angle_t angle;

	count = 1 + (pr_blast() % 3);
	for (i = 0; i < count; i++)
	{
		blast = Spawn("VolcanoBlast", self->x, self->y,
			self->z + 44*FRACUNIT, ALLOW_REPLACE);
		blast->target = self;
		angle = pr_blast () << 24;
		blast->angle = angle;
		angle >>= ANGLETOFINESHIFT;
		blast->velx = FixedMul (1*FRACUNIT, finecosine[angle]);
		blast->vely = FixedMul (1*FRACUNIT, finesine[angle]);
		blast->velz = (FRACUNIT*5/2) + (pr_blast() << 10);
		S_Sound (blast, CHAN_BODY, "world/volcano/shoot", 1, ATTN_NORM);
		P_CheckMissileSpawn (blast, self->radius);
	}
}
コード例 #14
0
void A_VolcanoBlast (AActor *volcano)
{
	int i;
	int count;
	AActor *blast;
	angle_t angle;

	count = 1 + (pr_blast() % 3);
	for (i = 0; i < count; i++)
	{
		blast = Spawn<AVolcanoBlast> (volcano->x, volcano->y,
			volcano->z + 44*FRACUNIT, ALLOW_REPLACE);
		blast->target = volcano;
		angle = pr_blast () << 24;
		blast->angle = angle;
		angle >>= ANGLETOFINESHIFT;
		blast->momx = FixedMul (1*FRACUNIT, finecosine[angle]);
		blast->momy = FixedMul (1*FRACUNIT, finesine[angle]);
		blast->momz = (FRACUNIT*5/2) + (pr_blast() << 10);
		S_Sound (blast, CHAN_BODY, "world/volcano/shoot", 1, ATTN_NORM);
		P_CheckMissileSpawn (blast);
	}
}
コード例 #15
0
mobj_t *Mobj_ExplodeIfObstructed(mobj_t *mob)
{
    return P_CheckMissileSpawn(mob)? mob : nullptr;
}
コード例 #16
0
ファイル: p_things.cpp プロジェクト: usernameak/gzdoom
bool FLevelLocals::EV_Thing_Projectile (int tid, AActor *source, int type, const char *type_name, DAngle angle,
	double speed, double vspeed, int dest, AActor *forcedest, int gravity, int newtid,
	bool leadTarget)
{
	int rtn = 0;
	PClassActor *kind;
	AActor *spot, *mobj, *targ = forcedest;
	auto iterator = GetActorIterator(tid);
	int defflags3;

	if (type_name == NULL)
	{
		kind = P_GetSpawnableType(type);
	}
	else
	{
		kind = PClass::FindActor(type_name);
	}
	if (kind == NULL)
	{
		return false;
	}

	// Handle decorate replacements.
	kind = kind->GetReplacement(this);

	defflags3 = GetDefaultByType(kind)->flags3;
	if ((defflags3 & MF3_ISMONSTER) && 
		((dmflags & DF_NO_MONSTERS) || (flags2 & LEVEL2_NOMONSTERS)))
		return false;

	if (tid == 0)
	{
		spot = source;
	}
	else
	{
		spot = iterator.Next();
	}
	while (spot != NULL)
	{
		auto tit = GetActorIterator(dest);

		if (dest == 0 || (targ = tit.Next()))
		{
			do
			{
				double z = spot->Z();
				if (defflags3 & MF3_FLOORHUGGER)
				{
					z = ONFLOORZ;
				}
				else if (defflags3 & MF3_CEILINGHUGGER)
				{
					z = ONCEILINGZ;
				}
				else if (z != ONFLOORZ)
				{
					z -= spot->Floorclip;
				}
				mobj = Spawn (spot->Level, kind, spot->PosAtZ(z), ALLOW_REPLACE);

				if (mobj)
				{
					mobj->tid = newtid;
					mobj->AddToHash ();
					P_PlaySpawnSound(mobj, spot);
					if (gravity)
					{
						mobj->flags &= ~MF_NOGRAVITY;
						if (!(mobj->flags3 & MF3_ISMONSTER) && gravity == 1)
						{
							mobj->Gravity = 1./8;
						}
					}
					else
					{
						mobj->flags |= MF_NOGRAVITY;
					}
					mobj->target = spot;

					if (targ != nullptr)
					{
						VelIntercept(targ, mobj, speed, false, false, leadTarget);

						if (mobj->flags2 & MF2_SEEKERMISSILE)
						{
							mobj->tracer = targ;
						}
					}
					else
					{
						mobj->Angles.Yaw = angle;
						mobj->VelFromAngle(speed);
						mobj->Vel.Z = vspeed;
					}
					// Set the missile's speed to reflect the speed it was spawned at.
					if (mobj->flags & MF_MISSILE)
					{
						mobj->Speed = mobj->VelToSpeed();
					}
					// Hugger missiles don't have any vertical velocity
					if (mobj->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER))
					{
						mobj->Vel.Z = 0;
					}
					if (mobj->flags & MF_SPECIAL)
					{
						mobj->flags |= MF_DROPPED;
					}
					if (mobj->flags & MF_MISSILE)
					{
						if (P_CheckMissileSpawn (mobj, spot->radius))
						{
							rtn = true;
						}
					}
					else if (!P_TestMobjLocation (mobj))
					{
						// If this is a monster, subtract it from the total monster
						// count, because it already added to it during spawning.
						mobj->ClearCounters();
						mobj->Destroy ();
					}
					else
					{
						// It spawned fine.
						rtn = 1;
					}
				}
			} while (dest != 0 && (targ = tit.Next()));
		}
		spot = iterator.Next();
	}

	return rtn != 0;
}
コード例 #17
0
bool P_Thing_ProjectileEx (int tid, AActor *source, int type, const char *type_name, angle_t angle,
	fixed_t spawnx, fixed_t spawny, fixed_t spawnz,
	fixed_t speed, fixed_t vspeed, int dest, AActor *forcedest, int gravity, int newtid,
	bool leadTarget)
{
	int rtn = 0;
	const PClass *kind;
	AActor *spot, *mobj, *targ = forcedest;
	FActorIterator iterator (tid);
	double fspeed = speed;
	int defflags3;
	fixed_t x = 0;
	fixed_t y = 0;
	fixed_t z = 0;
	angle_t pitch;

	if (type_name == NULL)
	{
		kind = P_GetSpawnableType(type);
	}
	else
	{
		kind = PClass::FindClass(type_name);
	}
	if (kind == NULL || kind->ActorInfo == NULL)
	{
		return false;
	}

/*
// [RC] I'm sure there was reason for this code here, but I'm not sure why anymore. Possibly
// deprecated ThingProjectile code.
	if (type_name == NULL)
	{
		if (type >= MAX_SPAWNABLES)
			return false;

		if ((kind = SpawnableThings[type]) == NULL)
			return false;
	}
	else
	{
		if ((kind = PClass::FindClass(type_name)) == NULL || kind->ActorInfo == NULL)
			return false;
	}
*/

	// Handle decorate replacements.
	kind = kind->GetReplacement();

	defflags3 = GetDefaultByType (kind)->flags3;
	if ((defflags3 & MF3_ISMONSTER) && 
		((dmflags & DF_NO_MONSTERS) || (level.flags2 & LEVEL2_NOMONSTERS)))
		return false;

	if (tid == 0)
	{
		spot = source;
	}
	else
	{
		spot = iterator.Next();
	}
	while (spot != NULL)
	{
		FActorIterator tit (dest);

		if (dest == 0 || (targ = tit.Next()))
		{
			do
			{
				//fixed_t z = spot->z;
				z += spot->player->mo->z + (spot->player->mo->AttackZOffset+spawnz);//spot->player->mo->AttackZOffset;
				x += spot->player->mo->x + spawnx;
				y += spot->player->mo->y + spawny;
				pitch = spot->player->mo->pitch;

				if (defflags3 & MF3_FLOORHUGGER) z = ONFLOORZ;
				else if (defflags3 & MF3_CEILINGHUGGER) z = ONCEILINGZ;
				else if (z != ONFLOORZ)z -= spot->floorclip;
				if (z < spot->floorz) z = spot->floorz;

				mobj = Spawn (kind, x, y, z, ALLOW_REPLACE);

				if (mobj)
				{
					mobj->tid = newtid;
					mobj->AddToHash ();
					P_PlaySpawnSound(mobj, spot);
					if (gravity)
					{
						mobj->flags &= ~MF_NOGRAVITY;
						if (!(mobj->flags3 & MF3_ISMONSTER) && gravity == 1)
						{
							mobj->gravity = FRACUNIT/8;
						}
					}
					else
					{
						mobj->flags |= MF_NOGRAVITY;
					}
					mobj->target = spot;
					mobj->master = spot; //Ideally, give the projectile an owner. That being the player.
					
					mobj->angle = angle;
					mobj->velx = FixedMul(speed, finecosine[angle>>ANGLETOFINESHIFT]);
					mobj->vely = FixedMul(speed, finesine[angle>>ANGLETOFINESHIFT]);
					mobj->velz = vspeed;

					// Set the missile's speed to reflect the speed it was spawned at.
					if (mobj->flags & MF_MISSILE)
					{
						mobj->Speed = fixed_t (sqrt (double(mobj->velx)*mobj->velx + double(mobj->vely)*mobj->vely + double(mobj->velz)*mobj->velz));
					}
					// Hugger missiles don't have any vertical velocity
					if (mobj->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER))
					{
						mobj->velz = 0;
					}
					if (mobj->flags & MF_SPECIAL)
					{
						mobj->flags |= MF_DROPPED;
					}
					if (mobj->flags & MF_MISSILE)
					{
						if (P_CheckMissileSpawn (mobj))
						{
							rtn = true;
						}
					}
					else if (!P_TestMobjLocation (mobj))
					{
						// If this is a monster, subtract it from the total monster
						// count, because it already added to it during spawning.
						mobj->ClearCounters();
						mobj->Destroy ();
					}
					else
					{
						// It spawned fine.
						rtn = 1;
					}
				}
			} while (dest != 0 && (targ = tit.Next()));
		}
		spot = iterator.Next();
	}

	return rtn != 0;
}
コード例 #18
0
ファイル: a_randomspawner.cpp プロジェクト: WChrisK/Zandronum
	// The second half of random spawning. Now that the spawner is initialized, the
	// real actor can be created. If the following code were in BeginPlay instead,
	// missiles would not have yet obtained certain information that is absolutely
	// necessary to them -- such as their source and destination.
	void PostBeginPlay()
	{
		AActor * newmobj = NULL;
		bool boss = false;
		Super::PostBeginPlay();
		if (Species == NAME_None) { Destroy(); return; }
		const PClass * cls = PClass::FindClass(Species);
		if (this->flags & MF_MISSILE && target && target->target) // Attempting to spawn a missile.
		{
			if ((tracer == NULL) && (flags2 & MF2_SEEKERMISSILE)) tracer = target->target;
			newmobj = P_SpawnMissileXYZ(x, y, z, target, target->target, cls, false);
		}
		else newmobj = Spawn(cls, x, y, z, NO_REPLACE);
		if (newmobj != NULL)
		{
			// copy everything relevant
			newmobj->SpawnAngle = newmobj->angle = angle;
			newmobj->SpawnPoint[2] = SpawnPoint[2];
			newmobj->special    = special;
			newmobj->args[0]    = args[0];
			newmobj->args[1]    = args[1];
			newmobj->args[2]    = args[2];
			newmobj->args[3]    = args[3];
			newmobj->args[4]    = args[4];
			newmobj->special1   = special1;
			newmobj->special2   = special2;
			newmobj->SpawnFlags = SpawnFlags;
			newmobj->HandleSpawnFlags();
			newmobj->tid        = tid;
			newmobj->AddToHash();
			newmobj->velx = velx;
			newmobj->vely = vely;
			newmobj->velz = velz;
			newmobj->master = master;	// For things such as DamageMaster/DamageChildren, transfer mastery.
			newmobj->target = target;
			newmobj->tracer = tracer;
			newmobj->CopyFriendliness(this, false);
			// This handles things such as projectiles with the MF4_SPECTRAL flag that have
			// a health set to -2 after spawning, for internal reasons.
			if (health != SpawnHealth()) newmobj->health = health;
			if (!(flags & MF_DROPPED)) newmobj->flags &= ~MF_DROPPED;
			// Handle special altitude flags
			if (newmobj->flags & MF_SPAWNCEILING)
			{
				newmobj->z = newmobj->ceilingz - newmobj->height - SpawnPoint[2];
			}
			else if (newmobj->flags2 & MF2_SPAWNFLOAT) 
			{
				fixed_t space = newmobj->ceilingz - newmobj->height - newmobj->floorz;
				if (space > 48*FRACUNIT)
				{
					space -= 40*FRACUNIT;
					newmobj->z = MulScale8 (space, pr_randomspawn()) + newmobj->floorz + 40*FRACUNIT;
				}
				newmobj->z += SpawnPoint[2];
			}
			if (newmobj->flags & MF_MISSILE)
				P_CheckMissileSpawn(newmobj);
			// Bouncecount is used to count how many recursions we're in.
			if (newmobj->IsKindOf(PClass::FindClass("RandomSpawner")))
				newmobj->bouncecount = ++bouncecount;
			// If the spawned actor has either of those flags, it's a boss.
			if ((newmobj->flags4 & MF4_BOSSDEATH) || (newmobj->flags2 & MF2_BOSS))
				boss = true;
			// If a replaced actor has either of those same flags, it's also a boss.
			AActor * rep = GetDefaultByType(GetClass()->ActorInfo->GetReplacee()->Class);
			if (rep && ((rep->flags4 & MF4_BOSSDEATH) || (rep->flags2 & MF2_BOSS)))
				boss = true;

			// [BB] If we're the server, tell clients to spawn the actor.
			if ( NETWORK_GetState( ) == NETSTATE_SERVER )
			{
				SERVERCOMMANDS_SpawnThing( newmobj );
				// [BB] Also set the angle and momentum if necessary.
				SERVER_SetThingNonZeroAngleAndMomentum( newmobj );
			}
			// [BB] The client did the spawning, so this has to be a client side only actor.
			else if ( ( NETWORK_GetState( ) == NETSTATE_CLIENT ) || ( CLIENTDEMO_IsPlaying( ) ) )
				newmobj->ulNetworkFlags |= NETFL_CLIENTSIDEONLY;
		}
		if (boss) this->tracer = newmobj;
		// [BB] Only destroy the actor if it's not needed for a map reset. Otherwise just hide it.
		else HideOrDestroyIfSafe();	// "else" because a boss-replacing spawner must wait until it can call A_BossDeath.

		// [BB] Workaround to ensure that the spawner is properly reset in GAME_ResetMap.
		this->ulSTFlags |= STFL_POSITIONCHANGED;
	}
コード例 #19
0
bool P_Thing_Projectile (int tid, AActor *source, int type, const char *type_name, DAngle angle,
	double speed, double vspeed, int dest, AActor *forcedest, int gravity, int newtid,
	bool leadTarget)
{
	int rtn = 0;
	PClassActor *kind;
	AActor *spot, *mobj, *targ = forcedest;
	FActorIterator iterator (tid);
	int defflags3;

	if (type_name == NULL)
	{
		kind = P_GetSpawnableType(type);
	}
	else
	{
		kind = PClass::FindActor(type_name);
	}
	if (kind == NULL)
	{
		return false;
	}

	// Handle decorate replacements.
	kind = kind->GetReplacement();

	defflags3 = GetDefaultByType(kind)->flags3;
	if ((defflags3 & MF3_ISMONSTER) && 
		((dmflags & DF_NO_MONSTERS) || (level.flags2 & LEVEL2_NOMONSTERS)))
		return false;

	if (tid == 0)
	{
		spot = source;
	}
	else
	{
		spot = iterator.Next();
	}
	while (spot != NULL)
	{
		FActorIterator tit (dest);

		if (dest == 0 || (targ = tit.Next()))
		{
			do
			{
				double z = spot->Z();
				if (defflags3 & MF3_FLOORHUGGER)
				{
					z = ONFLOORZ;
				}
				else if (defflags3 & MF3_CEILINGHUGGER)
				{
					z = ONCEILINGZ;
				}
				else if (z != ONFLOORZ)
				{
					z -= spot->Floorclip;
				}
				mobj = Spawn (kind, spot->PosAtZ(z), ALLOW_REPLACE);

				if (mobj)
				{
					mobj->tid = newtid;
					mobj->AddToHash ();
					P_PlaySpawnSound(mobj, spot);
					if (gravity)
					{
						mobj->flags &= ~MF_NOGRAVITY;
						if (!(mobj->flags3 & MF3_ISMONSTER) && gravity == 1)
						{
							mobj->Gravity = 1./8;
						}
					}
					else
					{
						mobj->flags |= MF_NOGRAVITY;
					}
					mobj->target = spot;

					if (targ != NULL)
					{
						DVector3 aim = mobj->Vec3To(targ);
						aim.Z += targ->Height / 2;

						if (leadTarget && speed > 0 && !targ->Vel.isZero())
						{
							// Aiming at the target's position some time in the future
							// is basically just an application of the law of sines:
							//     a/sin(A) = b/sin(B)
							// Thanks to all those on the notgod phorum for helping me
							// with the math. I don't think I would have thought of using
							// trig alone had I been left to solve it by myself.

							DVector3 tvel = targ->Vel;
							if (!(targ->flags & MF_NOGRAVITY) && targ->waterlevel < 3)
							{ // If the target is subject to gravity and not underwater,
							  // assume that it isn't moving vertically. Thanks to gravity,
							  // even if we did consider the vertical component of the target's
							  // velocity, we would still miss more often than not.
								tvel.Z = 0.0;
								if (targ->Vel.X == 0 && targ->Vel.Y == 0)
								{
									goto nolead;
								}
							}
							double dist = aim.Length();
							double targspeed = tvel.Length();
							double ydotx = -aim | tvel;
							double a = g_acos (clamp (ydotx / targspeed / dist, -1.0, 1.0));
							double multiplier = double(pr_leadtarget.Random2())*0.1/255+1.1;
							double sinb = -clamp (targspeed*multiplier * g_sin(a) / speed, -1.0, 1.0);

							// Use the cross product of two of the triangle's sides to get a
							// rotation vector.
							DVector3 rv(tvel ^ aim);
							// The vector must be normalized.
							rv.MakeUnit();
							// Now combine the rotation vector with angle b to get a rotation matrix.
							DMatrix3x3 rm(rv, g_cos(g_asin(sinb)), sinb);
							// And multiply the original aim vector with the matrix to get a
							// new aim vector that leads the target.
							DVector3 aimvec = rm * aim;
							// And make the projectile follow that vector at the desired speed.
							mobj->Vel = aimvec * (speed / dist);
							mobj->AngleFromVel();
						}
						else
						{
nolead:
							mobj->Angles.Yaw = mobj->AngleTo(targ);
							mobj->Vel = aim.Resized (speed);
						}
						if (mobj->flags2 & MF2_SEEKERMISSILE)
						{
							mobj->tracer = targ;
						}
					}
					else
					{
						mobj->Angles.Yaw = angle;
						mobj->VelFromAngle(speed);
						mobj->Vel.Z = vspeed;
					}
					// Set the missile's speed to reflect the speed it was spawned at.
					if (mobj->flags & MF_MISSILE)
					{
						mobj->Speed = mobj->VelToSpeed();
					}
					// Hugger missiles don't have any vertical velocity
					if (mobj->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER))
					{
						mobj->Vel.Z = 0;
					}
					if (mobj->flags & MF_SPECIAL)
					{
						mobj->flags |= MF_DROPPED;
					}
					if (mobj->flags & MF_MISSILE)
					{
						if (P_CheckMissileSpawn (mobj, spot->radius))
						{
							rtn = true;
						}
					}
					else if (!P_TestMobjLocation (mobj))
					{
						// If this is a monster, subtract it from the total monster
						// count, because it already added to it during spawning.
						mobj->ClearCounters();
						mobj->Destroy ();
					}
					else
					{
						// It spawned fine.
						rtn = 1;
					}
				}
			} while (dest != 0 && (targ = tit.Next()));
		}
		spot = iterator.Next();
	}

	return rtn != 0;
}
コード例 #20
0
bool P_Thing_Projectile (int tid, AActor *source, int type, const char *type_name, angle_t angle,
	fixed_t speed, fixed_t vspeed, int dest, AActor *forcedest, int gravity, int newtid,
	bool leadTarget)
{
	int rtn = 0;
	const PClass *kind;
	AActor *spot, *mobj, *targ = forcedest;
	FActorIterator iterator (tid);
	double fspeed = speed;
	int defflags3;

	if (type_name == NULL)
	{
		if (type >= MAX_SPAWNABLES)
			return false;

		if ((kind = SpawnableThings[type]) == NULL)
			return false;
	}
	else
	{
		if ((kind = PClass::FindClass(type_name)) == NULL || kind->ActorInfo == NULL)
			return false;
	}


	// Handle decorate replacements.
	kind = kind->ActorInfo->GetReplacement()->Class;

	defflags3 = GetDefaultByType (kind)->flags3;
	if ((defflags3 & MF3_ISMONSTER) && 
		((dmflags & DF_NO_MONSTERS) || (level.flags2 & LEVEL2_NOMONSTERS)))
		return false;

	if (tid == 0)
	{
		spot = source;
	}
	else
	{
		spot = iterator.Next();
	}
	while (spot != NULL)
	{
		FActorIterator tit (dest);

		if (dest == 0 || (targ = tit.Next()))
		{
			do
			{
				fixed_t z = spot->z;
				if (defflags3 & MF3_FLOORHUGGER)
				{
					z = ONFLOORZ;
				}
				else if (defflags3 & MF3_CEILINGHUGGER)
				{
					z = ONCEILINGZ;
				}
				else if (z != ONFLOORZ)
				{
					z -= spot->floorclip;
				}
				mobj = Spawn (kind, spot->x, spot->y, z, ALLOW_REPLACE);

				if (mobj)
				{
					mobj->tid = newtid;
					mobj->AddToHash ();
					P_PlaySpawnSound(mobj, spot);
					if (gravity)
					{
						mobj->flags &= ~MF_NOGRAVITY;
						if (!(mobj->flags3 & MF3_ISMONSTER) && gravity == 1)
						{
							mobj->gravity = FRACUNIT/8;
						}
					}
					else
					{
						mobj->flags |= MF_NOGRAVITY;
					}
					mobj->target = spot;

					if (targ != NULL)
					{
						fixed_t spot[3] = { targ->x, targ->y, targ->z+targ->height/2 };
						FVector3 aim(float(spot[0] - mobj->x), float(spot[1] - mobj->y), float(spot[2] - mobj->z));

						if (leadTarget && speed > 0 && (targ->velx | targ->vely | targ->velz))
						{
							// Aiming at the target's position some time in the future
							// is basically just an application of the law of sines:
							//     a/sin(A) = b/sin(B)
							// Thanks to all those on the notgod phorum for helping me
							// with the math. I don't think I would have thought of using
							// trig alone had I been left to solve it by myself.

							FVector3 tvel(targ->velx, targ->vely, targ->velz);
							if (!(targ->flags & MF_NOGRAVITY) && targ->waterlevel < 3)
							{ // If the target is subject to gravity and not underwater,
							  // assume that it isn't moving vertically. Thanks to gravity,
							  // even if we did consider the vertical component of the target's
							  // velocity, we would still miss more often than not.
								tvel.Z = 0.0;
								if ((targ->velx | targ->vely) == 0)
								{
									goto nolead;
								}
							}
							double dist = aim.Length();
							double targspeed = tvel.Length();
							double ydotx = -aim | tvel;
							double a = acos (clamp (ydotx / targspeed / dist, -1.0, 1.0));
							double multiplier = double(pr_leadtarget.Random2())*0.1/255+1.1;
							double sinb = -clamp (targspeed*multiplier * sin(a) / fspeed, -1.0, 1.0);

							// Use the cross product of two of the triangle's sides to get a
							// rotation vector.
							FVector3 rv(tvel ^ aim);
							// The vector must be normalized.
							rv.MakeUnit();
							// Now combine the rotation vector with angle b to get a rotation matrix.
							FMatrix3x3 rm(rv, cos(asin(sinb)), sinb);
							// And multiply the original aim vector with the matrix to get a
							// new aim vector that leads the target.
							FVector3 aimvec = rm * aim;
							// And make the projectile follow that vector at the desired speed.
							double aimscale = fspeed / dist;
							mobj->velx = fixed_t (aimvec[0] * aimscale);
							mobj->vely = fixed_t (aimvec[1] * aimscale);
							mobj->velz = fixed_t (aimvec[2] * aimscale);
							mobj->angle = R_PointToAngle2 (0, 0, mobj->velx, mobj->vely);
						}
						else
						{
nolead:						mobj->angle = R_PointToAngle2 (mobj->x, mobj->y, targ->x, targ->y);
							aim.Resize (fspeed);
							mobj->velx = fixed_t(aim[0]);
							mobj->vely = fixed_t(aim[1]);
							mobj->velz = fixed_t(aim[2]);
						}
						if (mobj->flags2 & MF2_SEEKERMISSILE)
						{
							mobj->tracer = targ;
						}
					}
					else
					{
						mobj->angle = angle;
						mobj->velx = FixedMul (speed, finecosine[angle>>ANGLETOFINESHIFT]);
						mobj->vely = FixedMul (speed, finesine[angle>>ANGLETOFINESHIFT]);
						mobj->velz = vspeed;
					}
					// Set the missile's speed to reflect the speed it was spawned at.
					if (mobj->flags & MF_MISSILE)
					{
						mobj->Speed = fixed_t (sqrt (double(mobj->velx)*mobj->velx + double(mobj->vely)*mobj->vely + double(mobj->velz)*mobj->velz));
					}
					// Hugger missiles don't have any vertical velocity
					if (mobj->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER))
					{
						mobj->velz = 0;
					}
					if (mobj->flags & MF_SPECIAL)
					{
						mobj->flags |= MF_DROPPED;
					}
					if (mobj->flags & MF_MISSILE)
					{
						if (P_CheckMissileSpawn (mobj))
						{
							rtn = true;
						}
					}
					else if (!P_TestMobjLocation (mobj))
					{
						// If this is a monster, subtract it from the total monster
						// count, because it already added to it during spawning.
						if (mobj->CountsAsKill())
						{
							level.total_monsters--;
						}
						// Same, for items
						if (mobj->flags & MF_COUNTITEM)
						{
							level.total_items--;
						}
						mobj->Destroy ();
					}
					else
					{
						// It spawned fine.
						rtn = 1;
					}
				}
			} while (dest != 0 && (targ = tit.Next()));
		}
		spot = iterator.Next();
	}

	return rtn != 0;
}
コード例 #21
0
	// The second half of random spawning. Now that the spawner is initialized, the
	// real actor can be created. If the following code were in BeginPlay instead,
	// missiles would not have yet obtained certain information that is absolutely
	// necessary to them -- such as their source and destination.
	void PostBeginPlay()
	{
		AActor * newmobj = NULL;
		bool boss = false;
		Super::PostBeginPlay();
		if (Species == NAME_None) 
		{ 
			Destroy(); 
			return; 
		}
		const PClass * cls = PClass::FindClass(Species);
		if (this->flags & MF_MISSILE && target && target->target) // Attempting to spawn a missile.
		{
			if ((tracer == NULL) && (flags2 & MF2_SEEKERMISSILE)) tracer = target->target;
			newmobj = P_SpawnMissileXYZ(Pos(), target, target->target, cls, false);
		}
		else newmobj = Spawn(cls, Pos(), NO_REPLACE);
		if (newmobj != NULL)
		{
			// copy everything relevant
			newmobj->SpawnAngle = newmobj->angle = angle;
			newmobj->SpawnPoint[2] = SpawnPoint[2];
			newmobj->special    = special;
			newmobj->args[0]    = args[0];
			newmobj->args[1]    = args[1];
			newmobj->args[2]    = args[2];
			newmobj->args[3]    = args[3];
			newmobj->args[4]    = args[4];
			newmobj->special1   = special1;
			newmobj->special2   = special2;
			newmobj->SpawnFlags = SpawnFlags & ~MTF_SECRET;	// MTF_SECRET needs special treatment to avoid incrementing the secret counter twice. It had already been processed for the spawner itself.
			newmobj->HandleSpawnFlags();
			newmobj->SpawnFlags = SpawnFlags;
			newmobj->tid        = tid;
			newmobj->AddToHash();
			newmobj->velx = velx;
			newmobj->vely = vely;
			newmobj->velz = velz;
			newmobj->master = master;	// For things such as DamageMaster/DamageChildren, transfer mastery.
			newmobj->target = target;
			newmobj->tracer = tracer;
			newmobj->CopyFriendliness(this, false);
			// This handles things such as projectiles with the MF4_SPECTRAL flag that have
			// a health set to -2 after spawning, for internal reasons.
			if (health != SpawnHealth()) newmobj->health = health;
			if (!(flags & MF_DROPPED)) newmobj->flags &= ~MF_DROPPED;
			// Handle special altitude flags
			if (newmobj->flags & MF_SPAWNCEILING)
			{
				newmobj->SetZ(newmobj->ceilingz - newmobj->height - SpawnPoint[2]);
			}
			else if (newmobj->flags2 & MF2_SPAWNFLOAT) 
			{
				fixed_t space = newmobj->ceilingz - newmobj->height - newmobj->floorz;
				if (space > 48*FRACUNIT)
				{
					space -= 40*FRACUNIT;
					newmobj->SetZ(MulScale8 (space, pr_randomspawn()) + newmobj->floorz + 40*FRACUNIT);
				}
				newmobj->AddZ(SpawnPoint[2]);
			}
			if (newmobj->flags & MF_MISSILE)
				P_CheckMissileSpawn(newmobj, 0);
			// Bouncecount is used to count how many recursions we're in.
			if (newmobj->IsKindOf(PClass::FindClass("RandomSpawner")))
				newmobj->bouncecount = ++bouncecount;
			// If the spawned actor has either of those flags, it's a boss.
			if ((newmobj->flags4 & MF4_BOSSDEATH) || (newmobj->flags2 & MF2_BOSS))
				boss = true;
			// If a replaced actor has either of those same flags, it's also a boss.
			AActor * rep = GetDefaultByType(GetClass()->ActorInfo->GetReplacee()->Class);
			if (rep && ((rep->flags4 & MF4_BOSSDEATH) || (rep->flags2 & MF2_BOSS)))
				boss = true;
		}
		if (boss)
			this->tracer = newmobj;
		else	// "else" because a boss-replacing spawner must wait until it can call A_BossDeath.
			Destroy();
	}
コード例 #22
0
DEFINE_ACTION_FUNCTION(AActor, A_LichAttack)
{
	int i;
	AActor *fire;
	AActor *baseFire;
	AActor *mo;
	AActor *target;
	int randAttack;
	static const int atkResolve1[] = { 50, 150 };
	static const int atkResolve2[] = { 150, 200 };
	int dist;

	// Ice ball		(close 20% : far 60%)
	// Fire column	(close 40% : far 20%)
	// Whirlwind	(close 40% : far 20%)
	// Distance threshold = 8 cells

	target = self->target;
	if (target == NULL)
	{
		return;
	}
	A_FaceTarget (self);
	if (self->CheckMeleeRange ())
	{
		int damage = pr_atk.HitDice (6);
		P_DamageMobj (target, self, self, damage, NAME_Melee);
		P_TraceBleed (damage, target, self);
		return;
	}
	dist = P_AproxDistance (self->x-target->x, self->y-target->y)
		> 8*64*FRACUNIT;
	randAttack = pr_atk ();
	if (randAttack < atkResolve1[dist])
	{ // Ice ball
		P_SpawnMissile (self, target, PClass::FindClass("HeadFX1"));
		S_Sound (self, CHAN_BODY, "ironlich/attack2", 1, ATTN_NORM);
	}
	else if (randAttack < atkResolve2[dist])
	{ // Fire column
		baseFire = P_SpawnMissile (self, target, PClass::FindClass("HeadFX3"));
		if (baseFire != NULL)
		{
			baseFire->SetState (baseFire->FindState("NoGrow"));
			for (i = 0; i < 5; i++)
			{
				fire = Spawn("HeadFX3", baseFire->x, baseFire->y,
					baseFire->z, ALLOW_REPLACE);
				if (i == 0)
				{
					S_Sound (self, CHAN_BODY, "ironlich/attack1", 1, ATTN_NORM);
				}
				fire->target = baseFire->target;
				fire->angle = baseFire->angle;
				fire->velx = baseFire->velx;
				fire->vely = baseFire->vely;
				fire->velz = baseFire->velz;
				fire->Damage = 0;
				fire->health = (i+1) * 2;
				P_CheckMissileSpawn (fire);
			}
		}
	}
	else
	{ // Whirlwind
		mo = P_SpawnMissile (self, target, RUNTIME_CLASS(AWhirlwind));
		if (mo != NULL)
		{
			mo->z -= 32*FRACUNIT;
			mo->tracer = target;
			mo->special1 = 60;
			mo->special2 = 50; // Timer for active sound
			mo->health = 20*TICRATE; // Duration
			S_Sound (self, CHAN_BODY, "ironlich/attack3", 1, ATTN_NORM);
		}
	}
}