|
Note: Wait! Stop! You do not need to copy this actor's code into your project! Here's why:
- This actor is already defined in GZDoom, there's no reason to define it again.
- In fact, trying to define an actor with the same name will cause an error (because it already exists).
- If you want to make your own version of this actor, use inheritance.
- Definitions for existing actors are put on the wiki for reference purpose only.
|
Marine
|
Actor type
|
Monster
|
Game
|
(Doom)
|
DoomEd Number
|
9100
|
Class Name
|
ScriptedMarine
|
Spawn ID
|
151
|
Identifier
|
T_SCRIPTEDMARINE
|
Classes: ScriptedMarine
→MarineBFG
→MarineBerserk
→MarineChaingun
→MarineChainsaw
→MarineFist
→MarinePistol
→MarinePlasma
→MarineRailgun
→MarineRocket
→MarineSSG
→MarineShotgun
The Scripted Marine is a duplication of the Doom player which can be controlled via scripting during cutscenes or gameplay, to simulate the player or other marines wearing the same armor. Though the actor has several attacks coded, he does not actually ever use any by default. These attack states are used, however, by its children classes.
As with all marines, you can use the special ACS functions SetMarineSprite and SetMarineWeapon to change this actor's appearance and weapon.
|
Note: The ZScript definition below is for reference and may be different in the current version of GZDoom.The most up-to-date version of this code can be found on GZDoom GitHub.
|
class ScriptedMarine : Actor
{
const MARINE_PAIN_CHANCE = 160;
enum EMarineWeapon
{
WEAPON_Dummy,
WEAPON_Fist,
WEAPON_BerserkFist,
WEAPON_Chainsaw,
WEAPON_Pistol,
WEAPON_Shotgun,
WEAPON_SuperShotgun,
WEAPON_Chaingun,
WEAPON_RocketLauncher,
WEAPON_PlasmaRifle,
WEAPON_Railgun,
WEAPON_BFG
};
struct WeaponStates
{
state melee;
state missile;
}
int CurrentWeapon;
SpriteID SpriteOverride;
Default
{
Health 100;
Radius 16;
Height 56;
Mass 100;
Speed 8;
Painchance MARINE_PAIN_CHANCE;
MONSTER;
-COUNTKILL
Translation 0;
Damage 100;
DeathSound "*death";
PainSound "*pain50";
}
States
{
Spawn:
PLAY A 4 A_MarineLook;
PLAY A 4 A_MarineNoise;
Loop;
Idle:
PLAY A 4 A_MarineLook;
PLAY A 4 A_MarineNoise;
PLAY A 4 A_MarineLook;
PLAY B 4 A_MarineNoise;
PLAY B 4 A_MarineLook;
PLAY B 4 A_MarineNoise;
Loop;
See:
PLAY ABCD 4 A_MarineChase;
Loop;
Melee.Fist:
PLAY E 4 A_FaceTarget;
PLAY E 4 A_M_Punch(1);
PLAY A 9;
PLAY A 0 A_M_Refire(1, "FistEnd");
Loop;
FistEnd:
PLAY A 5 A_FaceTarget;
Goto See;
Melee.Berserk:
PLAY E 4 A_FaceTarget;
PLAY E 4 A_M_Punch(10);
PLAY A 9;
PLAY A 0 A_M_Refire(1, "FistEnd");
Loop;
Melee.Chainsaw:
PLAY E 4 A_MarineNoise;
PLAY E 4 A_M_Saw;
PLAY E 0 A_M_SawRefire;
goto Melee.Chainsaw+1;
Missile:
Missile.None:
PLAY E 12 A_FaceTarget;
Goto Idle;
PLAY F 6 BRIGHT;
Loop;
Missile.Pistol:
PLAY E 4 A_FaceTarget;
PLAY F 6 BRIGHT A_M_FirePistol(1);
PLAY A 4 A_FaceTarget;
PLAY A 0 A_M_Refire(0, "ShootEnd");
Goto Fireloop.Pistol;
ShootEnd:
PLAY A 5;
Goto See;
Fireloop.Pistol:
PLAY F 6 BRIGHT A_M_FirePistol(0);
PLAY A 4 A_FaceTarget;
PLAY A 0 A_M_Refire(0, "ShootEnd");
Goto Fireloop.Pistol;
Missile.Shotgun:
PLAY E 3 A_M_CheckAttack;
PLAY F 7 BRIGHT A_M_FireShotgun;
Goto See;
Missile.SSG:
PLAY E 3 A_M_CheckAttack;
PLAY F 7 BRIGHT A_M_FireShotgun2;
Goto See;
Missile.Chaingun:
PLAY E 4 A_FaceTarget;
PLAY FF 4 BRIGHT A_M_FireCGun(1);
PLAY FF 4 BRIGHT A_M_FireCGun(0);
PLAY A 0 A_M_Refire(0, "See");
Goto Missile.Chaingun+3;
Missile.Rocket:
PLAY E 8;
PLAY F 6 BRIGHT A_M_FireMissile;
PLAY E 6;
PLAY A 0 A_M_Refire(0, "See");
Loop;
Missile.Plasma:
PLAY E 2 A_FaceTarget;
PLAY E 0 A_FaceTarget;
PLAY F 3 BRIGHT A_M_FirePlasma;
PLAY A 0 A_M_Refire(0, "See");
Goto Missile.Plasma+1;
Missile.Railgun:
PLAY E 4 A_M_CheckAttack;
PLAY F 6 BRIGHT A_M_FireRailgun;
Goto See;
Missile.BFG:
PLAY E 5 A_M_BFGSound;
PLAY EEEEE 5 A_FaceTarget;
PLAY F 6 BRIGHT A_M_FireBFG;
PLAY A 4 A_FaceTarget;
PLAY A 0 A_M_Refire(0, "See");
Loop;
SkipAttack:
PLAY A 1;
Goto See;
Pain:
PLAY G 4;
PLAY G 4 A_Pain;
Goto Idle;
Death:
PLAY H 10;
PLAY I 10 A_Scream;
PLAY J 10 A_NoBlocking;
PLAY KLM 10;
PLAY N -1;
Stop;
XDeath:
PLAY O 5;
PLAY P 5 A_XScream;
PLAY Q 5 A_NoBlocking;
PLAY RSTUV 5;
PLAY W -1;
Stop;
Raise:
PLAY MLKJIH 5;
Goto See;
}
//============================================================================
//
//
//
//============================================================================
private bool GetWeaponStates(int weap, out WeaponStates wstates)
{
static const statelabel MeleeNames[] =
{
"Melee.None", "Melee.Fist", "Melee.Berserk", "Melee.Chainsaw", "Melee.Pistol", "Melee.Shotgun",
"Melee.SSG", "Melee.Chaingun", "Melee.Rocket", "Melee.Plasma", "Melee.Railgun", "Melee.BFG"
};
static const statelabel MissileNames[] =
{
"Missile.None", "Missile.Fist", "Missile.Berserk", "Missile.Chainsaw", "Missile.Pistol", "Missile.Shotgun",
"Missile.SSG", "Missile.Chaingun", "Missile.Rocket", "Missile.Plasma", "Missile.Railgun", "Missile.BFG"
};
if (weap < WEAPON_Dummy || weap > WEAPON_BFG) weap = WEAPON_Dummy;
wstates.melee = FindState(MeleeNames[weap], true);
wstates.missile = FindState(MissileNames[weap], true);
return wstates.melee != null || wstates.missile != null;
}
//============================================================================
//
//
//
//============================================================================
override void BeginPlay ()
{
Super.BeginPlay ();
// Set the current weapon
for(int i = WEAPON_Dummy; i <= WEAPON_BFG; i++)
{
WeaponStates wstates;
if (GetWeaponStates(i, wstates))
{
if (wstates.melee == MeleeState && wstates.missile == MissileState)
{
CurrentWeapon = i;
}
}
}
}
//============================================================================
//
//
//
//============================================================================
override void Tick ()
{
Super.Tick ();
// Override the standard sprite, if desired
if (SpriteOverride != 0 && sprite == SpawnState.sprite)
{
sprite = SpriteOverride;
}
if (special1 != 0)
{
if (CurrentWeapon == WEAPON_SuperShotgun)
{ // Play SSG reload sounds
int ticks = level.maptime - special1;
if (ticks < 47)
{
switch (ticks)
{
case 14:
A_StartSound ("weapons/sshoto", CHAN_WEAPON);
break;
case 28:
A_StartSound ("weapons/sshotl", CHAN_WEAPON);
break;
case 41:
A_StartSound ("weapons/sshotc", CHAN_WEAPON);
break;
}
}
else
{
special1 = 0;
}
}
else
{ // Wait for a long refire time
if (level.maptime >= special1)
{
special1 = 0;
}
else
{
bJustAttacked = true;
}
}
}
}
//============================================================================
//
// A_M_Refire
//
//============================================================================
void A_M_Refire (bool ignoremissile = false, statelabel jumpto = null)
{
if (target == null || target.health <= 0)
{
if (MissileState && random[SMarineRefire]() < 160)
{ // Look for a new target most of the time
if (LookForPlayers (true) && CheckMissileRange ())
{ // Found somebody new and in range, so don't stop shooting
return;
}
}
if (jumpto != null) SetStateLabel (jumpto);
else SetState(CurState + 1);
return;
}
if (((ignoremissile || MissileState == null) && !CheckMeleeRange ()) ||
!CheckSight (target) || random[SMarineRefire]() < 4) // Small chance of stopping even when target not dead
{
if (jumpto != null) SetStateLabel (jumpto);
else SetState(CurState + 1);
}
}
//============================================================================
//
// A_M_SawRefire
//
//============================================================================
void A_M_SawRefire ()
{
if (target == null || target.health <= 0 || !CheckMeleeRange ())
{
SetStateLabel ("See");
}
}
//============================================================================
//
// A_MarineNoise
//
//============================================================================
void A_MarineNoise ()
{
if (CurrentWeapon == WEAPON_Chainsaw)
{
A_StartSound ("weapons/sawidle", CHAN_WEAPON);
}
}
//============================================================================
//
// A_MarineChase
//
//============================================================================
void A_MarineChase ()
{
A_MarineNoise();
A_Chase ();
}
//============================================================================
//
// A_MarineLook
//
//============================================================================
void A_MarineLook ()
{
A_MarineNoise();
A_Look();
}
//============================================================================
//
// A_M_Punch (also used in the rocket attack.)
//
//============================================================================
void A_M_Punch(int damagemul)
{
FTranslatedLineTarget t;
if (target == null)
return;
int damage = (random[SMarinePunch](1, 10) << 1) * damagemul;
A_FaceTarget ();
double ang = angle + random2[SMarinePunch]() * (5.625 / 256);
double pitch = AimLineAttack (ang, DEFMELEERANGE);
LineAttack (ang, DEFMELEERANGE, pitch, damage, 'Melee', "BulletPuff", true, t);
// turn to face target
if (t.linetarget)
{
A_StartSound ("*fist", CHAN_WEAPON);
angle = t.angleFromSource;
}
}
//============================================================================
//
// P_GunShot2
//
//============================================================================
private void GunShot2 (bool accurate, double pitch, class<Actor> pufftype)
{
int damage = 5 * random[SMarineGunshot](1,3);
double ang = angle;
if (!accurate)
{
ang += Random2[SMarineGunshot]() * (5.625 / 256);
}
LineAttack (ang, MISSILERANGE, pitch, damage, 'Hitscan', pufftype);
}
//============================================================================
//
// A_M_FirePistol
//
//============================================================================
void A_M_FirePistol (bool accurate)
{
if (target == null)
return;
A_StartSound ("weapons/pistol", CHAN_WEAPON);
A_FaceTarget ();
GunShot2 (accurate, AimLineAttack (angle, MISSILERANGE), "BulletPuff");
}
//============================================================================
//
// A_M_FireShotgun
//
//============================================================================
void A_M_FireShotgun ()
{
if (target == null)
return;
A_StartSound ("weapons/shotgf", CHAN_WEAPON);
A_FaceTarget ();
double pitch = AimLineAttack (angle, MISSILERANGE);
for (int i = 0; i < 7; ++i)
{
GunShot2 (false, pitch, "BulletPuff");
}
special1 = level.maptime + 27;
}
//============================================================================
//
// A_M_CheckAttack
//
//============================================================================
void A_M_CheckAttack ()
{
if (special1 != 0 || target == null)
{
SetStateLabel ("SkipAttack");
}
else
{
A_FaceTarget ();
}
}
//============================================================================
//
// A_M_FireShotgun2
//
//============================================================================
void A_M_FireShotgun2 ()
{
if (target == null)
return;
A_StartSound ("weapons/sshotf", CHAN_WEAPON);
A_FaceTarget ();
double pitch = AimLineAttack (angle, MISSILERANGE);
for (int i = 0; i < 20; ++i)
{
int damage = 5*(random[SMarineFireSSG](1, 3));
double ang = angle + Random2[SMarineFireSSG]() * (11.25 / 256);
LineAttack (ang, MISSILERANGE, pitch + Random2[SMarineFireSSG]() * (7.097 / 256), damage, 'Hitscan', "BulletPuff");
}
special1 = level.maptime;
}
//============================================================================
//
// A_M_FireCGun
//
//============================================================================
void A_M_FireCGun(bool accurate)
{
if (target == null)
return;
A_StartSound ("weapons/chngun", CHAN_WEAPON);
A_FaceTarget ();
GunShot2 (accurate, AimLineAttack (angle, MISSILERANGE), "BulletPuff");
}
//============================================================================
//
// A_M_FireMissile
//
// Giving a marine a rocket launcher is probably a bad idea unless you pump
// up his health, because he's just as likely to kill himself as he is to
// kill anything else with it.
//
//============================================================================
void A_M_FireMissile ()
{
if (target == null)
return;
if (CheckMeleeRange ())
{ // If too close, punch it
A_M_Punch(1);
}
else
{
A_FaceTarget ();
SpawnMissile (target, "Rocket");
}
}
//============================================================================
//
// A_M_FireRailgun
//
//============================================================================
void A_M_FireRailgun ()
{
if (target == null)
return;
A_MonsterRail();
special1 = level.maptime + 50;
}
//============================================================================
//
// A_M_FirePlasma
//
//============================================================================
void A_M_FirePlasma ()
{
if (target == null)
return;
A_FaceTarget ();
SpawnMissile (target, "PlasmaBall");
special1 = level.maptime + 20;
}
//============================================================================
//
// A_M_BFGsound
//
//============================================================================
void A_M_BFGsound ()
{
if (target == null)
return;
if (special1 != 0)
{
SetState (SeeState);
}
else
{
A_FaceTarget ();
A_StartSound ("weapons/bfgf", CHAN_WEAPON);
// Don't interrupt the firing sequence
PainChance = 0;
}
}
//============================================================================
//
// A_M_FireBFG
//
//============================================================================
void A_M_FireBFG ()
{
if (target == null)
return;
A_FaceTarget ();
SpawnMissile (target, "BFGBall");
special1 = level.maptime + 30;
PainChance = MARINE_PAIN_CHANCE;
}
//---------------------------------------------------------------------------
final void SetWeapon (int type)
{
WeaponStates wstates;
if (GetWeaponStates(type, wstates))
{
static const class<Actor> classes[] = {
"ScriptedMarine",
"MarineFist",
"MarineBerserk",
"MarineChainsaw",
"MarinePistol",
"MarineShotgun",
"MarineSSG",
"MarineChaingun",
"MarineRocket",
"MarinePlasma",
"MarineRailgun",
"MarineBFG"
};
MeleeState = wstates.melee;
MissileState = wstates.missile;
DecalGenerator = GetDefaultByType(classes[type]).DecalGenerator;
}
}
final void SetSprite (class<Actor> source)
{
if (source == null)
{ // A valid actor class wasn't passed, so use the standard sprite
SpriteOverride = sprite = SpawnState.sprite;
// Copy the standard scaling
Scale = Default.Scale;
}
else
{ // Use the same sprite and scaling the passed class spawns with
readonly<Actor> def = GetDefaultByType (source);
SpriteOverride = sprite = def.SpawnState.sprite;
Scale = def.Scale;
}
}
}
|
Note: This is legacy code, kept for archival purposes only. DECORATE is deprecated in GZDoom and is completely superseded by ZScript. GZDoom internally uses the ZScript definition above.
|
ACTOR ScriptedMarine native
{
Health 100
Radius 16
Height 56
Mass 100
Speed 8
PainChance 160
Monster
-COUNTKILL
Translation 0
Damage 100
DeathSound "*death"
PainSound "*pain50"
action native A_M_Refire(bool ignoremissile=false);
action native A_M_CheckAttack();
action native A_MarineChase();
action native A_MarineLook();
action native A_MarineNoise();
action native A_M_Punch(int force);
action native A_M_SawRefire();
action native A_M_FirePistol(bool accurate);
action native A_M_FireShotgun();
action native A_M_FireShotgun2();
action native A_M_FireCGun(bool accurate);
action native A_M_FireMissile();
action native A_M_FirePlasma();
action native A_M_FireRailgun();
action native A_M_BFGSound();
action native A_M_FireBFG();
States
{
Spawn:
PLAY A 4 A_MarineLook
PLAY A 4 A_MarineNoise
Loop
Idle:
PLAY A 4 A_MarineLook
PLAY A 4 A_MarineNoise
PLAY A 4 A_MarineLook
PLAY B 4 A_MarineNoise
PLAY B 4 A_MarineLook
PLAY B 4 A_MarineNoise
Loop
See:
PLAY ABCD 4 A_MarineChase
Loop
Melee.Fist:
PLAY E 4 A_FaceTarget
PLAY E 4 A_M_Punch(1)
PLAY A 9
PLAY A 0 A_M_Refire(1)
Loop
PLAY A 5 A_FaceTarget
Goto See
Melee.Berserk:
PLAY E 4 A_FaceTarget
PLAY E 4 A_M_Punch(10)
PLAY A 9
PLAY A 0 A_M_Refire(1)
Loop
PLAY A 5 A_FaceTarget
Goto See
Melee.Chainsaw:
PLAY E 4 A_MarineNoise
PLAY E 4 A_M_Saw
PLAY E 0 A_M_SawRefire
Goto Melee.Chainsaw+1
PLAY A 0
Goto See
Missile:
Missile.None:
PLAY E 12 A_FaceTarget
Goto Idle
PLAY F 6 Bright
Loop
Missile.Pistol:
PLAY E 4 A_FaceTarget
PLAY F 6 Bright A_M_FirePistol(1)
PLAY A 4 A_FaceTarget
PLAY A 0 A_M_Refire
PLAY A 5
Goto See
Fireloop.Pistol:
PLAY F 6 Bright A_M_FirePistol(0)
PLAY A 4 A_FaceTarget
PLAY A 0 A_M_Refire
Goto Fireloop.Pistol
PLAY A 5
Goto See
Missile.Shotgun:
PLAY E 3 A_M_CheckAttack
PLAY F 7 Bright A_M_FireShotgun
Goto See
Missile.SSG:
PLAY E 3 A_M_CheckAttack
PLAY F 7 Bright A_M_FireShotgun2
Goto See
Missile.Chaingun:
PLAY E 4 A_FaceTarget
PLAY FF 4 Bright A_M_FireCGun(1)
PLAY FF 4 Bright A_M_FireCGun(0)
PLAY A 0 A_M_Refire
Goto Missile.Chaingun+3
PLAY A 0
Goto See
Missile.Rocket:
PLAY E 8
PLAY F 6 Bright A_M_FireMissile
PLAY E 6
PLAY A 0 A_M_Refire
Loop
PLAY A 0
Goto See
Missile.Plasma:
PLAY E 2 A_FaceTarget
PLAY E 0 A_FaceTarget
PLAY F 3 Bright A_M_FirePlasma
PLAY A 0 A_M_Refire
Goto Missile.Plasma+1
PLAY A 0
Goto See
Missile.Railgun:
PLAY E 4 A_M_CheckAttack
PLAY F 6 Bright A_M_FireRailgun
Goto See
Missile.BFG:
PLAY E 5 A_M_BFGSound
PLAY EEEEE 5 A_FaceTarget
PLAY F 6 Bright A_M_FireBFG
PLAY A 4 A_FaceTarget
PLAY A 0 A_M_Refire
Loop
PLAY A 0
Goto See
SkipAttack:
PLAY A 1
Goto See
Pain:
PLAY G 4
PLAY G 4 A_Pain
Goto Idle
Death:
PLAY H 10
PLAY I 10 A_Scream
PLAY J 10 A_NoBlocking
PLAY KLM 10
PLAY N -1
Stop
XDeath:
PLAY O 5
PLAY P 5 A_XScream
PLAY Q 5 A_NoBlocking
PLAY RSTUV 5
PLAY W -1
Stop
Raise:
PLAY MLKJIH 5
Goto See
}
}