Merge branch 'gz-zscript'

This commit is contained in:
Christoph Oelckers 2016-12-06 22:47:37 +01:00
commit c3fb43db3a
701 changed files with 75689 additions and 59344 deletions

View file

@ -825,8 +825,8 @@ add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c ${CMAKE_CUR
DEPENDS lemon ${CMAKE_CURRENT_SOURCE_DIR}/xlat/xlat_parser.y )
add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h
COMMAND lemon -C${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/zscript/zcc-parse.lemon
DEPENDS lemon ${CMAKE_CURRENT_SOURCE_DIR}/zscript/zcc-parse.lemon )
COMMAND lemon -C${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/scripting/zscript/zcc-parse.lemon
DEPENDS lemon ${CMAKE_CURRENT_SOURCE_DIR}/scripting/zscript/zcc-parse.lemon )
add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h
COMMAND re2c --no-generation-date -s -o ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h ${CMAKE_CURRENT_SOURCE_DIR}/sc_man_scanner.re
@ -874,11 +874,8 @@ endif()
file( GLOB HEADER_FILES
${EXTRA_HEADER_DIRS}
fragglescript/*.h
g_doom/*.h
g_heretic/*.h
g_hexen/*.h
g_raven/*.h
g_shared/*.h
g_inventory/*.h
g_strife/*.h
intermission/*.h
menu/*.h
@ -888,13 +885,17 @@ file( GLOB HEADER_FILES
posix/cocoa/*.h
posix/sdl/*.h
r_data/*.h
rapidjson/*.h
resourcefiles/*.h
sfmt/*.h
sound/*.h
textures/*.h
thingdef/*.h
scripting/*.h
scripting/codegeneration/*.h
scripting/decorate/*.h
scripting/zscript/*.h
scripting/vm/*.h
xlat/*.h
zscript/*.h
gl/*.h
gl/api/*.h
gl/data/*.h
@ -919,86 +920,11 @@ set( NOT_COMPILED_SOURCE_FILES
${OTHER_SYSTEM_SOURCES}
sc_man_scanner.h
sc_man_scanner.re
g_doom/a_arachnotron.cpp
g_doom/a_archvile.cpp
g_doom/a_bossbrain.cpp
g_doom/a_bruiser.cpp
g_doom/a_cacodemon.cpp
g_doom/a_cyberdemon.cpp
g_doom/a_demon.cpp
g_doom/a_doomimp.cpp
g_doom/a_doomweaps.cpp
g_doom/a_fatso.cpp
g_doom/a_keen.cpp
g_doom/a_lostsoul.cpp
g_doom/a_painelemental.cpp
g_doom/a_possessed.cpp
g_doom/a_revenant.cpp
g_doom/a_scriptedmarine.cpp
g_doom/a_spidermaster.cpp
g_heretic/a_chicken.cpp
g_heretic/a_dsparil.cpp
g_heretic/a_hereticartifacts.cpp
g_heretic/a_hereticimp.cpp
g_heretic/a_hereticweaps.cpp
g_heretic/a_ironlich.cpp
g_heretic/a_knight.cpp
g_heretic/a_wizard.cpp
g_hexen/a_bats.cpp
g_hexen/a_bishop.cpp
g_hexen/a_blastradius.cpp
g_hexen/a_boostarmor.cpp
g_hexen/a_centaur.cpp
g_hexen/a_clericflame.cpp
g_hexen/a_clericholy.cpp
g_hexen/a_clericmace.cpp
g_hexen/a_clericstaff.cpp
g_hexen/a_dragon.cpp
g_hexen/a_fighteraxe.cpp
g_hexen/a_fighterhammer.cpp
g_hexen/a_fighterplayer.cpp
g_hexen/a_fighterquietus.cpp
g_hexen/a_firedemon.cpp
g_hexen/a_flechette.cpp
g_hexen/a_flies.cpp
g_hexen/a_fog.cpp
g_hexen/a_healingradius.cpp
g_hexen/a_heresiarch.cpp
g_hexen/a_hexenspecialdecs.cpp
g_hexen/a_iceguy.cpp
g_hexen/a_korax.cpp
g_hexen/a_magecone.cpp
g_hexen/a_magelightning.cpp
g_hexen/a_magestaff.cpp
g_hexen/a_pig.cpp
g_hexen/a_serpent.cpp
g_hexen/a_spike.cpp
g_hexen/a_summon.cpp
g_hexen/a_teleportother.cpp
g_hexen/a_wraith.cpp
g_strife/a_acolyte.cpp
g_strife/a_alienspectres.cpp
g_strife/a_coin.cpp
g_strife/a_crusader.cpp
g_strife/a_entityboss.cpp
g_strife/a_inquisitor.cpp
g_strife/a_loremaster.cpp
g_strife/a_oracle.cpp
g_strife/a_programmer.cpp
g_strife/a_reaver.cpp
g_strife/a_rebels.cpp
g_strife/a_sentinel.cpp
g_strife/a_spectral.cpp
g_strife/a_stalker.cpp
g_strife/a_strifeitems.cpp
g_strife/a_strifeweapons.cpp
g_strife/a_templar.cpp
g_strife/a_thingstoblowup.cpp
g_shared/sbarinfo_commands.cpp
xlat/xlat_parser.y
xlat_parser.c
xlat_parser.h
zscript/zcc-parse.lemon
scripting/zscript/zcc-parse.lemon
zcc-parse.c
zcc-parse.h
@ -1326,44 +1252,32 @@ set (PCH_SOURCES
w_wad.cpp
wi_stuff.cpp
zstrformat.cpp
g_doom/a_doommisc.cpp
g_heretic/a_hereticmisc.cpp
g_hexen/a_hexenmisc.cpp
g_raven/a_artitele.cpp
g_raven/a_minotaur.cpp
g_strife/a_strifestuff.cpp
g_inventory/a_ammo.cpp
g_inventory/a_armor.cpp
g_inventory/a_artifacts.cpp
g_inventory/a_health.cpp
g_inventory/a_keys.cpp
g_inventory/a_pickups.cpp
g_inventory/a_puzzleitems.cpp
g_inventory/a_weaponpiece.cpp
g_inventory/a_weapons.cpp
g_strife/strife_sbar.cpp
g_shared/a_action.cpp
g_shared/a_armor.cpp
g_shared/a_artifacts.cpp
g_shared/a_bridge.cpp
g_shared/a_camera.cpp
g_shared/a_debris.cpp
g_shared/a_decals.cpp
g_shared/a_fastprojectile.cpp
g_shared/a_flashfader.cpp
g_shared/a_fountain.cpp
g_shared/a_hatetarget.cpp
g_shared/a_keys.cpp
g_shared/a_lightning.cpp
g_shared/a_mapmarker.cpp
g_shared/a_morph.cpp
g_shared/a_movingcamera.cpp
g_shared/a_pickups.cpp
g_shared/a_puzzleitems.cpp
g_shared/a_quake.cpp
g_shared/a_randomspawner.cpp
g_shared/a_secrettrigger.cpp
g_shared/a_sectoraction.cpp
g_shared/a_setcolor.cpp
g_shared/a_skies.cpp
g_shared/a_soundenvironment.cpp
g_shared/a_soundsequence.cpp
g_shared/a_spark.cpp
g_shared/a_specialspot.cpp
g_shared/a_waterzone.cpp
g_shared/a_weaponpiece.cpp
g_shared/a_weapons.cpp
g_shared/hudmessages.cpp
g_shared/sbarinfo.cpp
g_shared/sbar_mugshot.cpp
@ -1399,14 +1313,6 @@ set (PCH_SOURCES
textures/texturemanager.cpp
textures/tgatexture.cpp
textures/warptexture.cpp
thingdef/olddecorations.cpp
thingdef/thingdef.cpp
thingdef/thingdef_data.cpp
thingdef/thingdef_exp.cpp
thingdef/thingdef_expression.cpp
thingdef/thingdef_parse.cpp
thingdef/thingdef_properties.cpp
thingdef/thingdef_states.cpp
xlat/parse_xlat.cpp
fragglescript/t_func.cpp
fragglescript/t_load.cpp
@ -1421,15 +1327,23 @@ set (PCH_SOURCES
r_data/voxels.cpp
r_data/renderstyle.cpp
r_data/r_interpolate.cpp
scripting/thingdef.cpp
scripting/thingdef_data.cpp
scripting/thingdef_properties.cpp
scripting/codegeneration/codegen.cpp
scripting/decorate/olddecorations.cpp
scripting/decorate/thingdef_exp.cpp
scripting/decorate/thingdef_parse.cpp
scripting/decorate/thingdef_states.cpp
scripting/vm/vmbuilder.cpp
scripting/vm/vmdisasm.cpp
scripting/vm/vmexec.cpp
scripting/vm/vmframe.cpp
scripting/zscript/ast.cpp
scripting/zscript/zcc_compile.cpp
scripting/zscript/zcc_expr.cpp
scripting/zscript/zcc_parser.cpp
sfmt/SFMT.cpp
zscript/ast.cpp
zscript/vmbuilder.cpp
zscript/vmdisasm.cpp
zscript/vmexec.cpp
zscript/vmframe.cpp
zscript/zcc_compile.cpp
zscript/zcc_expr.cpp
zscript/zcc_parser.cpp
)
enable_precompiled_headers( g_pch.h PCH_SOURCES )
@ -1455,6 +1369,8 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE
math/log10.c
math/mtherr.c
math/polevl.c
math/pow.c
math/powi.c
math/sin.c
math/sinh.c
math/sqrt.c
@ -1480,20 +1396,17 @@ endif()
target_link_libraries( zdoom ${ZDOOM_LIBS} gdtoa dumb lzma )
include_directories( .
g_doom
g_heretic
g_hexen
g_raven
g_strife
g_shared
g_inventory
oplsynth
sound
textures
thingdef
timidity
wildmidi
xlat
zscript
scripting
scripting/vm
../gdtoa
../dumb/include
${CMAKE_BINARY_DIR}/gdtoa
@ -1610,17 +1523,14 @@ source_group("Audio Files\\Timidity\\Headers" REGULAR_EXPRESSION "^${CMAKE_CURRE
source_group("Audio Files\\Timidity\\Source" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/timidity/.+\\.cpp$")
source_group("Audio Files\\WildMidi\\Headers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/wildmidi/.+\\.h$")
source_group("Audio Files\\WildMidi\\Source" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/wildmidi/.+\\.cpp$")
source_group("Decorate++" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/thingdef/.+")
source_group("External\\Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/math/.+")
source_group("External\\RapidJSON" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rapidjson/.+")
source_group("Externak\\SFMT" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sfmt/.+")
source_group("FraggleScript" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/fragglescript/.+")
source_group("Games\\Doom Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_doom/.+")
source_group("Games\\Heretic Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_heretic/.+")
source_group("Games\\Hexen Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_hexen/.+")
source_group("Games\\Raven Shared" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_raven/.+")
source_group("Games\\Strife Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_strife/.+")
source_group("Intermission" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/intermission/.+")
source_group("Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/math/.+")
source_group("Inventory" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_inventory/.+")
source_group("Menu" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/menu/.+")
source_group("RapidJSON" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rapidjson/.+")
source_group("OpenGL Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/.+")
source_group("OpenGL Renderer\\Data" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/data/.+")
source_group("OpenGL Renderer\\Dynamic Lights" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/dynlights/.+")
@ -1642,15 +1552,18 @@ source_group("Render Data\\Resource Sources" REGULAR_EXPRESSION "^${CMAKE_CURREN
source_group("Render Data\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/textures/.+")
source_group("Render Interface" FILES r_defs.h r_renderer.h r_sky.cpp r_sky.h r_state.h r_utility.cpp r_utility.h)
source_group("Resource Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/resourcefiles/.+")
source_group("POSIX Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/.+")
source_group("Cocoa Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/cocoa/.+")
source_group("OS X Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/osx/.+")
source_group("Unix Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/unix/.+")
source_group("SDL Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/sdl/.+")
source_group("SFMT" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sfmt/.+")
source_group("Platforms\\POSIX Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/.+")
source_group("Platforms\\Cocoa Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/cocoa/.+")
source_group("Platforms\\OS X Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/osx/.+")
source_group("Platforms\\Unix Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/unix/.+")
source_group("Platforms\\SDL Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/sdl/.+")
source_group("Platforms\\Win32 Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/win32/.+")
source_group("Scripting\\Decorate" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/decorate/.+")
source_group("Scripting\\ZScript" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/zscript/.+" FILES ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h)
source_group("Scripting\\Code Generation" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/codegeneration/.+")
source_group("Scripting\\VM" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/vm/.+")
source_group("Scripting" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/scripting/.+")
source_group("Shared Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_shared/.+")
source_group("Versioning" FILES version.h win32/zdoom.rc)
source_group("Win32 Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/win32/.+")
source_group("Xlat" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/xlat/.+" FILES ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.h)
source_group("ZScript" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/zscript/.+" FILES ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h)
source_group("Source Files" FILES ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h sc_man_scanner.re)

View file

@ -52,8 +52,8 @@
// a single section during the final link. (.rdata is the standard section
// for initialized read-only data.)
#pragma comment(linker, "/merge:.areg=.rdata /merge:.creg=.rdata /merge:.greg=.rdata")
#pragma comment(linker, "/merge:.yreg=.rdata")
#pragma comment(linker, "/merge:.areg=.rdata /merge:.creg=.rdata /merge:.freg=.rdata")
#pragma comment(linker, "/merge:.greg=.rdata /merge:.yreg=.rdata")
#pragma section(".areg$a",read)
__declspec(allocate(".areg$a")) void *const ARegHead = 0;
@ -61,6 +61,9 @@ __declspec(allocate(".areg$a")) void *const ARegHead = 0;
#pragma section(".creg$a",read)
__declspec(allocate(".creg$a")) void *const CRegHead = 0;
#pragma section(".freg$a",read)
__declspec(allocate(".freg$a")) void *const FRegHead = 0;
#pragma section(".greg$a",read)
__declspec(allocate(".greg$a")) void *const GRegHead = 0;
@ -97,6 +100,7 @@ __declspec(allocate(".yreg$a")) void *const YRegHead = 0;
void *const ARegHead __attribute__((section(SECTION_AREG))) = 0;
void *const CRegHead __attribute__((section(SECTION_CREG))) = 0;
void *const FRegHead __attribute__((section(SECTION_FREG))) = 0;
void *const GRegHead __attribute__((section(SECTION_GREG))) = 0;
void *const YRegHead __attribute__((section(SECTION_YREG))) = 0;

View file

@ -385,6 +385,8 @@ enum ActorFlag7
MF7_USEKILLSCRIPTS = 0x00800000, // [JM] Use "KILL" Script on death if not forced by GameInfo.
MF7_NOKILLSCRIPTS = 0x01000000, // [JM] No "KILL" Script on death whatsoever, even if forced by GameInfo.
MF7_SPRITEANGLE = 0x02000000, // [MC] Utilize the SpriteAngle property and lock the rotation to the degrees specified.
MF7_SMASHABLE = 0x04000000, // dies if hitting the floor.
MF7_NOSHIELDREFLECT = 0x08000000, // will not be reflected by shields.
};
// --- mobj.renderflags ---
@ -583,11 +585,13 @@ public:
AActor () throw();
AActor (const AActor &other) throw();
AActor &operator= (const AActor &other);
void Destroy ();
~AActor ();
void Serialize(FSerializer &arc);
void PostSerialize();
virtual void Destroy() override;
virtual void Serialize(FSerializer &arc) override;
virtual void PostSerialize() override;
virtual void PostBeginPlay() override; // Called immediately before the actor's first tick
virtual void Tick() override;
static AActor *StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t allowreplacement, bool SpawningMapThing = false);
@ -611,43 +615,50 @@ public:
bool CheckNoDelay();
virtual void BeginPlay(); // Called immediately after the actor is created
virtual void PostBeginPlay(); // Called immediately before the actor's first tick
virtual void LevelSpawned(); // Called after BeginPlay if this actor was spawned by the world
void CallBeginPlay();
void LevelSpawned(); // Called after BeginPlay if this actor was spawned by the world
virtual void HandleSpawnFlags(); // Translates SpawnFlags into in-game flags.
virtual void MarkPrecacheSounds() const; // Marks sounds used by this actor for precaching.
virtual void Activate (AActor *activator);
virtual void Deactivate (AActor *activator);
void CallActivate(AActor *activator);
virtual void Tick ();
virtual void Deactivate(AActor *activator);
void CallDeactivate(AActor *activator);
// Called when actor dies
virtual void Die (AActor *source, AActor *inflictor, int dmgflags = 0);
void CallDie(AActor *source, AActor *inflictor, int dmgflags = 0);
// Perform some special damage action. Returns the amount of damage to do.
// Returning -1 signals the damage routine to exit immediately
virtual int DoSpecialDamage (AActor *target, int damage, FName damagetype);
int CallDoSpecialDamage(AActor *target, int damage, FName damagetype);
// Like DoSpecialDamage, but called on the actor receiving the damage.
virtual int TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype);
int CallTakeSpecialDamage(AActor *inflictor, AActor *source, int damage, FName damagetype);
// Actor had MF_SKULLFLY set and rammed into something
// Returns false to stop moving and true to keep moving
virtual bool Slam(AActor *victim);
bool CallSlam(AActor *victim);
// Something just touched this actor.
virtual void Touch(AActor *toucher);
void CallTouch(AActor *toucher);
// Centaurs and ettins squeal when electrocuted, poisoned, or "holy"-ed
// Made a metadata property so no longer virtual
void Howl ();
// Actor just hit the floor
virtual void HitFloor ();
// plays bouncing sound
void PlayBounceSound(bool onfloor);
// Called when an actor with MF_MISSILE and MF2_FLOORBOUNCE hits the floor
virtual bool FloorBounceMissile (secplane_t &plane);
// Called when an actor is to be reflected by a disc of repulsion.
// Returns true to continue normal blast processing.
virtual bool SpecialBlastHandling (AActor *source, double strength);
bool FloorBounceMissile (secplane_t &plane);
// Called by RoughBlockCheck
bool IsOkayToAttack (AActor *target);
@ -655,27 +666,28 @@ public:
// Plays the actor's ActiveSound if its voice isn't already making noise.
void PlayActiveSound ();
// Actor had MF_SKULLFLY set and rammed into something
// Returns false to stop moving and true to keep moving
virtual bool Slam (AActor *victim);
void RestoreSpecialPosition();
// Called by PIT_CheckThing() and needed for some Hexen things.
// Returns -1 for normal behavior, 0 to return false, and 1 to return true.
// I'm not sure I like it this way, but it will do for now.
virtual int SpecialMissileHit (AActor *victim);
// (virtual on the script side only)
int SpecialMissileHit (AActor *victim);
// Returns true if it's okay to switch target to "other" after being attacked by it.
virtual bool OkayToSwitchTarget (AActor *other);
bool OkayToSwitchTarget (AActor *other);
// Something just touched this actor.
virtual void Touch (AActor *toucher);
// Note: Although some of the inventory functions are virtual, this
// is not exposed to scripts, as the only class overriding them is
// APlayerPawn for some specific handling for players. None of this
// should ever be overridden by custom classes.
// Adds the item to this actor's inventory and sets its Owner.
virtual void AddInventory (AInventory *item);
// Give an item to the actor and pick it up.
// Returns true if the item pickup succeeded.
virtual bool GiveInventory (PClassInventory *type, int amount, bool givecheat = false);
bool GiveInventory (PClassInventory *type, int amount, bool givecheat = false);
// Removes the item from the inventory list.
virtual void RemoveInventory (AInventory *item);
@ -689,7 +701,7 @@ public:
virtual bool UseInventory (AInventory *item);
// Tosses an item out of the inventory.
virtual AInventory *DropInventory (AInventory *item);
AInventory *DropInventory (AInventory *item);
// Removes all items from the inventory.
void ClearInventory();
@ -731,7 +743,7 @@ public:
void ObtainInventory (AActor *other);
// Die. Now.
virtual bool Massacre ();
bool Massacre ();
// Transforms the actor into a finely-ground paste
virtual bool Grind(bool items);
@ -753,10 +765,10 @@ public:
DVector3 GetPortalTransition(double byoffset, sector_t **pSec = NULL);
// What species am I?
virtual FName GetSpecies();
FName GetSpecies();
// set translation
void SetTranslation(const char *trname);
void SetTranslation(FName trname);
double GetBobOffset(double ticfrac = 0) const
{
@ -956,7 +968,7 @@ public:
{
SetOrigin(Pos() + vel, true);
}
virtual void SetOrigin(double x, double y, double z, bool moving);
void SetOrigin(double x, double y, double z, bool moving);
void SetOrigin(const DVector3 & npos, bool moving)
{
SetOrigin(npos.X, npos.Y, npos.Z, moving);
@ -968,7 +980,7 @@ public:
bool IsInsideVisibleAngles() const;
// Calculate amount of missile damage
virtual int GetMissileDamage(int mask, int add);
int GetMissileDamage(int mask, int add);
bool CanSeek(AActor *target) const;
@ -1366,7 +1378,7 @@ public:
Vel.Y = speed * Angles.Yaw.Sin();
}
void VelFromAngle(DAngle angle, double speed)
void VelFromAngle(double speed, DAngle angle)
{
Vel.X = speed * angle.Cos();
Vel.Y = speed * angle.Sin();
@ -1414,6 +1426,7 @@ public:
}
int ApplyDamageFactor(FName damagetype, int damage) const;
int GetModifiedDamage(FName damagetype, int damage, bool passive);
// begin of GZDoom specific additions
@ -1448,6 +1461,10 @@ public:
return base;
}
void Reinit()
{
base = nullptr;
}
private:
AActor *base;
int id;
@ -1531,6 +1548,7 @@ struct FTranslatedLineTarget
{
AActor *linetarget;
DAngle angleFromSource;
DAngle attackAngleFromSource;
bool unlinked; // found by a trace that went through an unlinked portal.
};

View file

@ -2968,8 +2968,8 @@ void AM_drawAuthorMarkers ()
// [RH] Draw any actors derived from AMapMarker on the automap.
// If args[0] is 0, then the actor's sprite is drawn at its own location.
// Otherwise, its sprite is drawn at the location of any actors whose TIDs match args[0].
TThinkerIterator<AMapMarker> it (STAT_MAPMARKER);
AMapMarker *mark;
TThinkerIterator<AActor> it ("MapMarker", STAT_MAPMARKER);
AActor *mark;
while ((mark = it.Next()) != NULL)
{

View file

@ -49,6 +49,10 @@ extern REGINFO ARegTail;
extern REGINFO CRegHead;
extern REGINFO CRegTail;
// List of class fields
extern REGINFO FRegHead;
extern REGINFO FRegTail;
// List of properties
extern REGINFO GRegHead;
extern REGINFO GRegTail;

View file

@ -15,14 +15,16 @@
#include "serializer.h"
#include "d_player.h"
IMPLEMENT_POINTY_CLASS(DBot)
DECLARE_POINTER(dest)
DECLARE_POINTER(prev)
DECLARE_POINTER(enemy)
DECLARE_POINTER(missile)
DECLARE_POINTER(mate)
DECLARE_POINTER(last_mate)
END_POINTERS
IMPLEMENT_CLASS(DBot, false, true)
IMPLEMENT_POINTERS_START(DBot)
IMPLEMENT_POINTER(dest)
IMPLEMENT_POINTER(prev)
IMPLEMENT_POINTER(enemy)
IMPLEMENT_POINTER(missile)
IMPLEMENT_POINTER(mate)
IMPLEMENT_POINTER(last_mate)
IMPLEMENT_POINTERS_END
DBot::DBot ()
: DThinker(STAT_BOT)

View file

@ -21,6 +21,8 @@
#include "d_event.h"
#include "d_player.h"
#include "vectors.h"
#include "a_ammo.h"
#include "a_health.h"
static FRandom pr_botmove ("BotMove");

View file

@ -65,6 +65,7 @@
#include "g_level.h"
#include "d_event.h"
#include "d_player.h"
#include "gstrings.h"
#include "c_consolebuffer.h"
#include "gi.h"
@ -1729,6 +1730,20 @@ void C_MidPrintBold (FFont *font, const char *msg)
}
}
DEFINE_ACTION_FUNCTION(DObject, C_MidPrint)
{
PARAM_PROLOGUE;
PARAM_STRING(font);
PARAM_STRING(text);
PARAM_BOOL_DEF(bold);
FFont *fnt = FFont::FindFont(font);
const char *txt = text[0] == '$'? GStrings(&text[1]) : text.GetChars();
if (!bold) C_MidPrint(fnt, txt);
else C_MidPrintBold(fnt, txt);
return 0;
}
/****** Tab completion code ******/
struct TabData

View file

@ -1093,7 +1093,7 @@ BitVal (bitval)
ECVarType FFlagCVar::GetRealType () const
{
return CVAR_Dummy;
return CVAR_DummyBool;
}
UCVarValue FFlagCVar::GetGenericRep (ECVarType type) const
@ -1197,7 +1197,7 @@ BitVal (bitval)
ECVarType FMaskCVar::GetRealType () const
{
return CVAR_Dummy;
return CVAR_DummyInt;
}
UCVarValue FMaskCVar::GetGenericRep (ECVarType type) const

View file

@ -81,13 +81,17 @@ enum ECVarType
CVAR_Float,
CVAR_String,
CVAR_Color, // stored as CVAR_Int
CVAR_Dummy, // just redirects to another cvar
CVAR_DummyBool, // just redirects to another cvar
CVAR_DummyInt, // just redirects to another cvar
CVAR_Dummy, // Unknown
CVAR_GUID
};
class FConfigFile;
class AActor;
class FxCVar;
class FBaseCVar
{
public:
@ -211,6 +215,7 @@ void C_DeinitConsole();
class FBoolCVar : public FBaseCVar
{
friend class FxCVar;
public:
FBoolCVar (const char *name, bool def, uint32 flags, void (*callback)(FBoolCVar &)=NULL);
@ -236,6 +241,7 @@ protected:
class FIntCVar : public FBaseCVar
{
friend class FxCVar;
public:
FIntCVar (const char *name, int def, uint32 flags, void (*callback)(FIntCVar &)=NULL);
@ -263,6 +269,7 @@ protected:
class FFloatCVar : public FBaseCVar
{
friend class FxCVar;
public:
FFloatCVar (const char *name, float def, uint32 flags, void (*callback)(FFloatCVar &)=NULL);
@ -289,6 +296,7 @@ protected:
class FStringCVar : public FBaseCVar
{
friend class FxCVar;
public:
FStringCVar (const char *name, const char *def, uint32 flags, void (*callback)(FStringCVar &)=NULL);
~FStringCVar ();
@ -315,6 +323,7 @@ protected:
class FColorCVar : public FIntCVar
{
friend class FxCVar;
public:
FColorCVar (const char *name, int def, uint32 flags, void (*callback)(FColorCVar &)=NULL);
@ -339,6 +348,7 @@ protected:
class FFlagCVar : public FBaseCVar
{
friend class FxCVar;
public:
FFlagCVar (const char *name, FIntCVar &realvar, uint32 bitval);
@ -367,6 +377,7 @@ protected:
class FMaskCVar : public FBaseCVar
{
friend class FxCVar;
public:
FMaskCVar (const char *name, FIntCVar &realvar, uint32 bitval);

View file

@ -187,7 +187,7 @@ static const char *KeyConfCommands[] =
// CODE --------------------------------------------------------------------
IMPLEMENT_CLASS (DWaitingCommand)
IMPLEMENT_CLASS(DWaitingCommand, false, false)
void DWaitingCommand::Serialize(FSerializer &arc)
{
@ -225,7 +225,7 @@ void DWaitingCommand::Tick ()
}
}
IMPLEMENT_CLASS (DStoredCommand)
IMPLEMENT_CLASS(DStoredCommand, false, false)
DStoredCommand::DStoredCommand ()
{

View file

@ -15,6 +15,7 @@
#include "cmdlib.h"
#include "i_system.h"
#include "v_text.h"
#include "sc_man.h"
#include <sys/types.h>
#include <sys/stat.h>
@ -324,7 +325,7 @@ FString ExtractFileBase (const char *path, bool include_extension)
//
//==========================================================================
int ParseHex (const char *hex)
int ParseHex (const char *hex, FScriptPosition *sc)
{
const char *str;
int num;
@ -342,7 +343,8 @@ int ParseHex (const char *hex)
else if (*str >= 'A' && *str <= 'F')
num += 10 + *str-'A';
else {
Printf ("Bad hex number: %s\n",hex);
if (!sc) Printf ("Bad hex number: %s\n",hex);
else sc->Message(MSG_WARNING, "Bad hex number: %s", hex);
return 0;
}
str++;
@ -351,21 +353,6 @@ int ParseHex (const char *hex)
return num;
}
//==========================================================================
//
// ParseNum
//
//==========================================================================
int ParseNum (const char *str)
{
if (str[0] == '$')
return ParseHex (str+1);
if (str[0] == '0' && str[1] == 'x')
return ParseHex (str+2);
return atol (str);
}
//==========================================================================
//
// IsNum
@ -632,7 +619,10 @@ int strbin (char *str)
if (*p >= '0' && *p <= '7')
c += *p-'0';
else
{
p--;
break;
}
p++;
}
*str++ = c;
@ -732,7 +722,10 @@ FString strbin1 (const char *start)
if (*p >= '0' && *p <= '7')
c += *p-'0';
else
{
p--;
break;
}
p++;
}
result << c;

View file

@ -33,8 +33,8 @@ void DefaultExtension (FString &path, const char *extension);
FString ExtractFilePath (const char *path);
FString ExtractFileBase (const char *path, bool keep_extension=false);
int ParseHex (const char *str);
int ParseNum (const char *str);
struct FScriptPosition;
int ParseHex(const char *str, FScriptPosition *sc = nullptr);
bool IsNum (const char *str); // [RH] added
char *copystring(const char *s);

View file

@ -31,6 +31,7 @@
#include "templates.h"
#include "d_net.h"
#include "d_event.h"
#include "a_armor.h"
#define QUEUESIZE 128
#define MESSAGESIZE 128

View file

@ -70,7 +70,13 @@
#include "doomerrors.h"
#include "p_effect.h"
#include "serializer.h"
#include "thingdef.h"
#include "info.h"
#include "v_text.h"
#include "vmbuilder.h"
#include "a_armor.h"
#include "a_ammo.h"
#include "a_health.h"
// [SO] Just the way Randy said to do it :)
// [RH] Made this CVAR_SERVERINFO
@ -163,36 +169,25 @@ static TArray<CodePointerAlias> MBFCodePointers;
struct AmmoPerAttack
{
VMNativeFunction **func;
ENamedName func;
int ammocount;
VMFunction *ptr;
};
DECLARE_ACTION(A_Punch)
DECLARE_ACTION(A_FirePistol)
DECLARE_ACTION(A_FireShotgun)
DECLARE_ACTION(A_FireShotgun2)
DECLARE_ACTION(A_FireCGun)
DECLARE_ACTION(A_FireMissile)
DECLARE_ACTION(A_Saw)
DECLARE_ACTION(A_FirePlasma)
DECLARE_ACTION(A_FireBFG)
DECLARE_ACTION(A_FireOldBFG)
DECLARE_ACTION(A_FireRailgun)
// Default ammo use of the various weapon attacks
static AmmoPerAttack AmmoPerAttacks[] = {
{ &A_Punch_VMPtr, 0},
{ &A_FirePistol_VMPtr, 1},
{ &A_FireShotgun_VMPtr, 1},
{ &A_FireShotgun2_VMPtr, 2},
{ &A_FireCGun_VMPtr, 1},
{ &A_FireMissile_VMPtr, 1},
{ &A_Saw_VMPtr, 0},
{ &A_FirePlasma_VMPtr, 1},
{ &A_FireBFG_VMPtr, -1}, // uses deh.BFGCells
{ &A_FireOldBFG_VMPtr, 1},
{ &A_FireRailgun_VMPtr, 1},
{ NULL, 0}
{ NAME_A_Punch, 0},
{ NAME_A_FirePistol, 1},
{ NAME_A_FireShotgun, 1},
{ NAME_A_FireShotgun2, 2},
{ NAME_A_FireCGun, 1},
{ NAME_A_FireMissile, 1},
{ NAME_A_Saw, 0},
{ NAME_A_FirePlasma, 1},
{ NAME_A_FireBFG, -1}, // uses deh.BFGCells
{ NAME_A_FireOldBFG, 1},
{ NAME_A_FireRailgun, 1},
{ NAME_None, 0}
};
@ -220,6 +215,12 @@ DehInfo deh =
40, // BFG cells per shot
};
DEFINE_FIELD_X(DehInfo, DehInfo, MaxSoulsphere)
DEFINE_FIELD_X(DehInfo, DehInfo, ExplosionStyle)
DEFINE_FIELD_X(DehInfo, DehInfo, ExplosionAlpha)
DEFINE_FIELD_X(DehInfo, DehInfo, NoAutofreeze)
DEFINE_FIELD_X(DehInfo, DehInfo, BFGCells)
// Doom identified pickup items by their sprites. ZDoom prefers to use their
// class type to identify them instead. To support the traditional Doom
// behavior, for every thing touched by dehacked that has the MF_PICKUP flag,
@ -227,9 +228,11 @@ DehInfo deh =
// from the original actor's defaults. The original actor is then changed to
// spawn the new class.
IMPLEMENT_POINTY_CLASS (ADehackedPickup)
DECLARE_POINTER (RealPickup)
END_POINTERS
IMPLEMENT_CLASS(ADehackedPickup, false, true)
IMPLEMENT_POINTERS_START(ADehackedPickup)
IMPLEMENT_POINTER(RealPickup)
IMPLEMENT_POINTERS_END
TArray<PClassActor *> TouchedActors;
@ -794,7 +797,7 @@ void SetDehParams(FState *state, int codepointer)
// Let's identify the codepointer we're dealing with.
PFunction *sym;
sym = dyn_cast<PFunction>(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(FName(MBFCodePointers[codepointer].name), true));
sym = dyn_cast<PFunction>(RUNTIME_CLASS(AStateProvider)->Symbols.FindSymbol(FName(MBFCodePointers[codepointer].name), true));
if (sym == NULL) return;
if (codepointer < 0 || (unsigned)codepointer >= countof(MBFCodePointerFactories))
@ -804,22 +807,26 @@ void SetDehParams(FState *state, int codepointer)
}
else
{
VMFunctionBuilder buildit;
int numargs = sym->GetImplicitArgs();
VMFunctionBuilder buildit(numargs);
// Allocate registers used to pass parameters in.
// self, stateowner, state (all are pointers)
buildit.Registers[REGT_POINTER].Get(NAP);
buildit.Registers[REGT_POINTER].Get(numargs);
// Emit code to pass the standard action function parameters.
for (int i = 0; i < NAP; i++)
for (int i = 0; i < numargs; i++)
{
buildit.Emit(OP_PARAM, 0, REGT_POINTER, i);
}
// Emit code for action parameters.
int argcount = MBFCodePointerFactories[codepointer](buildit, value1, value2);
buildit.Emit(OP_TAIL_K, buildit.GetConstantAddress(sym->Variants[0].Implementation, ATAG_OBJECT), NAP + argcount, 0);
buildit.Emit(OP_TAIL_K, buildit.GetConstantAddress(sym->Variants[0].Implementation, ATAG_OBJECT), numargs + argcount, 0);
// Attach it to the state.
VMScriptFunction *sfunc = buildit.MakeFunction();
sfunc->NumArgs = NAP;
VMScriptFunction *sfunc = new VMScriptFunction;
buildit.MakeFunction(sfunc);
sfunc->NumArgs = numargs;
sfunc->ImplicitArgs = numargs;
state->SetAction(sfunc);
sfunc->PrintableName.Format("Dehacked.%s.%d.%d", MBFCodePointers[codepointer].name.GetChars(), value1, value2);
}
}
@ -1466,15 +1473,16 @@ static int PatchFrame (int frameNum)
if (info != &dummy)
{
info->DefineFlags |= SDF_DEHACKED; // Signals the state has been modified by dehacked
info->StateFlags |= STF_DEHACKED; // Signals the state has been modified by dehacked
if ((unsigned)(frame & 0x7fff) > 63)
{
Printf ("Frame %d: Subnumber must be in range [0,63]\n", frameNum);
Printf("Frame %d: Subnumber must be in range [0,63]\n", frameNum);
}
info->Tics = tics;
info->Misc1 = misc1;
info->Frame = frame & 0x3f;
info->Fullbright = frame & 0x8000 ? true : false;
if (frame & 0x8000) info->StateFlags |= STF_FULLBRIGHT;
else info->StateFlags &= ~STF_FULLBRIGHT;
}
return result;
@ -2101,23 +2109,24 @@ static int PatchCodePtrs (int dummy)
if (!symname.CompareNoCase(MBFCodePointers[i].alias))
{
symname = MBFCodePointers[i].name;
Printf("%s --> %s\n", MBFCodePointers[i].alias, MBFCodePointers[i].name.GetChars());
DPrintf(DMSG_SPAMMY, "%s --> %s\n", MBFCodePointers[i].alias, MBFCodePointers[i].name.GetChars());
}
}
// This skips the action table and goes directly to the internal symbol table
// DEH compatible functions are easy to recognize.
PFunction *sym = dyn_cast<PFunction>(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(symname, true));
PFunction *sym = dyn_cast<PFunction>(RUNTIME_CLASS(AStateProvider)->Symbols.FindSymbol(symname, true));
if (sym == NULL)
{
Printf("Frame %d: Unknown code pointer '%s'\n", frame, Line2);
Printf(TEXTCOLOR_RED "Frame %d: Unknown code pointer '%s'\n", frame, Line2);
}
else
{
TArray<DWORD> &args = sym->Variants[0].ArgFlags;
if ((sym->Flags & (VARF_Method | VARF_Action)) != (VARF_Method | VARF_Action) || (args.Size() > NAP && !(args[NAP] & VARF_Optional)))
unsigned numargs = sym->GetImplicitArgs();
if ((sym->Variants[0].Flags & VARF_Virtual || (args.Size() > numargs && !(args[numargs] & VARF_Optional))))
{
Printf("Frame %d: Incompatible code pointer '%s'\n", frame, Line2);
Printf(TEXTCOLOR_RED "Frame %d: Incompatible code pointer '%s'\n", frame, Line2);
sym = NULL;
}
}
@ -2715,11 +2724,11 @@ static bool LoadDehSupp ()
}
else
{
// all relevant code pointers are either defined in AInventory
// all relevant code pointers are either defined in AStateProvider
// or AActor so this will find all of them.
FString name = "A_";
name << sc.String;
PFunction *sym = dyn_cast<PFunction>(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(name, true));
PFunction *sym = dyn_cast<PFunction>(RUNTIME_CLASS(AStateProvider)->Symbols.FindSymbol(name, true));
if (sym == NULL)
{
sc.ScriptError("Unknown code pointer '%s'", sc.String);
@ -2727,7 +2736,8 @@ static bool LoadDehSupp ()
else
{
TArray<DWORD> &args = sym->Variants[0].ArgFlags;
if ((sym->Flags & (VARF_Method|VARF_Action)) != (VARF_Method | VARF_Action) || (args.Size() > NAP && !(args[NAP] & VARF_Optional)))
unsigned numargs = sym->GetImplicitArgs();
if ((sym->Variants[0].Flags & VARF_Virtual || (args.Size() > numargs && !(args[numargs] & VARF_Optional))))
{
sc.ScriptMessage("Incompatible code pointer '%s'", sc.String);
}
@ -3075,9 +3085,14 @@ void FinishDehPatch ()
break; // State has already been checked so we reached a loop
}
StateVisited[state] = true;
for(unsigned j = 0; AmmoPerAttacks[j].func != NULL; j++)
for(unsigned j = 0; AmmoPerAttacks[j].func != NAME_None; j++)
{
if (state->ActionFunc == *AmmoPerAttacks[j].func)
if (AmmoPerAttacks[j].ptr == nullptr)
{
auto p = dyn_cast<PFunction>(RUNTIME_CLASS(AStateProvider)->Symbols.FindSymbol(AmmoPerAttacks[j].func, true));
if (p != nullptr) AmmoPerAttacks[j].ptr = p->Variants[0].Implementation;
}
if (state->ActionFunc == AmmoPerAttacks[j].ptr)
{
found = true;
int use = AmmoPerAttacks[j].ammocount;
@ -3131,7 +3146,7 @@ bool ADehackedPickup::TryPickup (AActor *&toucher)
return false;
}
const char *ADehackedPickup::PickupMessage ()
FString ADehackedPickup::PickupMessage ()
{
if (RealPickup != nullptr)
return RealPickup->PickupMessage ();
@ -3141,7 +3156,7 @@ const char *ADehackedPickup::PickupMessage ()
bool ADehackedPickup::ShouldStay ()
{
if (RealPickup != nullptr)
return RealPickup->ShouldStay ();
return RealPickup->CallShouldStay ();
else return true;
}

View file

@ -41,8 +41,8 @@ class ADehackedPickup : public AInventory
DECLARE_CLASS (ADehackedPickup, AInventory)
HAS_OBJECT_POINTERS
public:
void Destroy ();
const char *PickupMessage ();
void Destroy() override;
FString PickupMessage ();
bool ShouldRespawn ();
bool ShouldStay ();
bool TryPickup (AActor *&toucher);

View file

@ -193,10 +193,10 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize)
{
sc.MustGetStringName("=");
sc.MustGetString();
iwad->FgColor = V_GetColor(NULL, sc.String);
iwad->FgColor = V_GetColor(NULL, sc);
sc.MustGetStringName(",");
sc.MustGetString();
iwad->BkColor = V_GetColor(NULL, sc.String);
iwad->BkColor = V_GetColor(NULL, sc);
}
else if (sc.Compare("Load"))
{

View file

@ -1027,6 +1027,12 @@ void D_DoomLoop ()
}
D_ErrorCleanup ();
}
catch (CVMAbortException &error)
{
error.MaybePrintMessage();
Printf("%s", error.stacktrace);
D_ErrorCleanup();
}
}
}
@ -1838,10 +1844,10 @@ static FString ParseGameInfo(TArray<FString> &pwads, const char *fn, const char
else if (!nextKey.CompareNoCase("STARTUPCOLORS"))
{
sc.MustGetString();
DoomStartupInfo.FgColor = V_GetColor(NULL, sc.String);
DoomStartupInfo.FgColor = V_GetColor(NULL, sc);
sc.MustGetStringName(",");
sc.MustGetString();
DoomStartupInfo.BkColor = V_GetColor(NULL, sc.String);
DoomStartupInfo.BkColor = V_GetColor(NULL, sc);
}
else if (!nextKey.CompareNoCase("STARTUPTYPE"))
{
@ -2647,7 +2653,6 @@ void D_DoomMain (void)
}
D_DoomLoop (); // this only returns if a 'restart' CCMD is given.
maxberestart:
//
// Clean up after a restart
//

View file

@ -61,6 +61,7 @@
#include "p_spec.h"
#include "hardware.h"
#include "r_utility.h"
#include "a_keys.h"
#include "intermission/intermission.h"
EXTERN_CVAR (Int, disableautosave)

View file

@ -30,6 +30,7 @@
#include "doomstat.h"
#include "a_artifacts.h"
#include "a_weapons.h"
// The player data structure depends on a number
// of other structs: items (internal inventory),
@ -80,7 +81,6 @@ public:
FPlayerColorSet *GetColorSet(int setnum) { return ColorSets.CheckKey(setnum); }
void SetPainFlash(FName type, PalEntry color);
bool GetPainFlash(FName type, PalEntry *color) const;
virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass);
FString DisplayName; // Display name (used in menus, etc.)
FString SoundClass; // Sound class
@ -105,29 +105,36 @@ public:
virtual void Serialize(FSerializer &arc);
virtual void PostBeginPlay();
virtual void Tick();
virtual void AddInventory (AInventory *item);
virtual void RemoveInventory (AInventory *item);
virtual bool UseInventory (AInventory *item);
virtual void MarkPrecacheSounds () const;
virtual void PostBeginPlay() override;
virtual void Tick() override;
virtual void AddInventory (AInventory *item) override;
virtual void RemoveInventory (AInventory *item) override;
virtual bool UseInventory (AInventory *item) override;
virtual void MarkPrecacheSounds () const override;
virtual void BeginPlay () override;
virtual void Die (AActor *source, AActor *inflictor, int dmgflags) override;
virtual bool UpdateWaterLevel (bool splash) override;
virtual void PlayIdle ();
virtual void PlayRunning ();
virtual void ThrowPoisonBag ();
virtual void TweakSpeeds (double &forwardmove, double &sidemove);
virtual void MorphPlayerThink ();
virtual void ActivateMorphWeapon ();
bool ResetAirSupply (bool playgasp = true);
int GetMaxHealth() const;
void TweakSpeeds (double &forwardmove, double &sidemove);
void MorphPlayerThink ();
void ActivateMorphWeapon ();
AWeapon *PickNewWeapon (PClassAmmo *ammotype);
AWeapon *BestWeapon (PClassAmmo *ammotype);
void CheckWeaponSwitch(PClassAmmo *ammotype);
virtual void GiveDeathmatchInventory ();
virtual void FilterCoopRespawnInventory (APlayerPawn *oldplayer);
void GiveDeathmatchInventory ();
void FilterCoopRespawnInventory (APlayerPawn *oldplayer);
void SetupWeaponSlots ();
void GiveDefaultInventory ();
// These are virtual on the script side only.
void PlayIdle();
void PlayRunning();
void PlayAttacking ();
void PlayAttacking2 ();
const char *GetSoundClass () const;
enum EInvulState
@ -138,8 +145,6 @@ public:
INVUL_GetAlpha
};
void BeginPlay ();
void Die (AActor *source, AActor *inflictor, int dmgflags);
int crouchsprite;
int MaxHealth;
@ -171,10 +176,6 @@ public:
// [SP] ViewBob Multiplier
double ViewBob;
bool UpdateWaterLevel (bool splash);
bool ResetAirSupply (bool playgasp = true);
int GetMaxHealth() const;
};
class APlayerChunk : public APlayerPawn
@ -253,11 +254,10 @@ enum
WF_USER4OK = 1 << 11,
};
#define WPIECE1 1
#define WPIECE2 2
#define WPIECE3 4
#define WP_NOCHANGE ((AWeapon*)~0)
// The VM cannot deal with this as an invalid pointer because it performs a read barrier on every object pointer read.
// This doesn't have to point to a valid weapon, though, because WP_NOCHANGE is never dereferenced, but it must point to a valid object
// and the class descriptor just works fine for that.
#define WP_NOCHANGE ((AWeapon*)RUNTIME_CLASS_CASTLESS(AWeapon))
#define MAXPLAYERNAME 15

View file

@ -119,9 +119,11 @@ protected:
DDecalThinker () : DThinker (STAT_DECALTHINKER) {}
};
IMPLEMENT_POINTY_CLASS (DDecalThinker)
DECLARE_POINTER (TheDecal)
END_POINTERS
IMPLEMENT_CLASS(DDecalThinker, false, true)
IMPLEMENT_POINTERS_START(DDecalThinker)
IMPLEMENT_POINTER(TheDecal)
IMPLEMENT_POINTERS_END
void DDecalThinker::Serialize(FSerializer &arc)
{
@ -530,7 +532,7 @@ void FDecalLib::ParseDecal (FScanner &sc)
sc.MustGetString ();
if (!sc.Compare("BloodDefault"))
{
newdecal.ShadeColor = V_GetColor (NULL, sc.String);
newdecal.ShadeColor = V_GetColor (NULL, sc);
}
else
{
@ -545,8 +547,8 @@ void FDecalLib::ParseDecal (FScanner &sc)
case DECAL_COLORS:
DWORD startcolor, endcolor;
sc.MustGetString (); startcolor = V_GetColor (NULL, sc.String);
sc.MustGetString (); endcolor = V_GetColor (NULL, sc.String);
sc.MustGetString (); startcolor = V_GetColor (NULL, sc);
sc.MustGetString (); endcolor = V_GetColor (NULL, sc);
newdecal.Translation = GenerateTranslation (startcolor, endcolor)->Index;
break;
@ -817,7 +819,7 @@ void FDecalLib::ParseColorchanger (FScanner &sc)
else if (sc.Compare ("Color"))
{
sc.MustGetString ();
goal = V_GetColor (NULL, sc.String);
goal = V_GetColor (NULL, sc);
}
else
{
@ -1151,7 +1153,7 @@ FDecalAnimator::~FDecalAnimator ()
{
}
IMPLEMENT_CLASS (DDecalFader)
IMPLEMENT_CLASS(DDecalFader, false, false)
void DDecalFader::Serialize(FSerializer &arc)
{
@ -1200,7 +1202,7 @@ DThinker *FDecalFaderAnim::CreateThinker (DBaseDecal *actor, side_t *wall) const
return fader;
}
IMPLEMENT_CLASS (DDecalStretcher)
IMPLEMENT_CLASS(DDecalStretcher, false, false)
void DDecalStretcher::Serialize(FSerializer &arc)
{
@ -1288,7 +1290,7 @@ void DDecalStretcher::Tick ()
}
}
IMPLEMENT_CLASS (DDecalSlider)
IMPLEMENT_CLASS(DDecalSlider, false, false)
void DDecalSlider::Serialize(FSerializer &arc)
{
@ -1368,8 +1370,7 @@ FDecalAnimator *FDecalLib::FindAnimator (const char *name)
return NULL;
}
IMPLEMENT_CLASS (DDecalColorer)
IMPLEMENT_CLASS(DDecalColorer, false, false)
void DDecalColorer::Serialize(FSerializer &arc)
{

View file

@ -48,6 +48,7 @@
#include "a_sharedglobal.h"
#include "dsectoreffect.h"
#include "serializer.h"
#include "virtual.h"
//==========================================================================
//
@ -57,16 +58,21 @@
ClassReg DObject::RegistrationInfo =
{
NULL, // MyClass
"DObject", // Name
NULL, // ParentType
NULL, // Pointers
&DObject::InPlaceConstructor, // ConstructNative
sizeof(DObject), // SizeOf
CLASSREG_PClass, // MetaClassNum
nullptr, // MyClass
"DObject", // Name
nullptr, // ParentType
nullptr,
nullptr, // Pointers
&DObject::InPlaceConstructor, // ConstructNative
nullptr,
sizeof(DObject), // SizeOf
CLASSREG_PClass, // MetaClassNum
};
_DECLARE_TI(DObject)
// This bit is needed in the playsim - but give it a less crappy name.
DEFINE_FIELD_BIT(DObject,ObjectFlags, bDestroyed, OF_EuthanizeMe)
//==========================================================================
//
//
@ -349,6 +355,13 @@ void DObject::Destroy ()
ObjectFlags = (ObjectFlags & ~OF_Fixed) | OF_EuthanizeMe;
}
DEFINE_ACTION_FUNCTION(DObject, Destroy)
{
PARAM_SELF_PROLOGUE(DObject);
self->Destroy();
return 0;
}
//==========================================================================
//
//
@ -410,7 +423,7 @@ size_t DObject::PointerSubstitution (DObject *old, DObject *notOld)
//
//==========================================================================
size_t DObject::StaticPointerSubstitution (DObject *old, DObject *notOld)
size_t DObject::StaticPointerSubstitution (DObject *old, DObject *notOld, bool scandefaults)
{
DObject *probe;
size_t changed = 0;
@ -425,6 +438,20 @@ size_t DObject::StaticPointerSubstitution (DObject *old, DObject *notOld)
last = probe;
}
if (scandefaults)
{
for (auto p : PClassActor::AllActorClasses)
{
auto def = GetDefaultByType(p);
if (def != nullptr)
{
def->Class = p;
def->DObject::PointerSubstitution(old, notOld);
def->Class = nullptr; // reset pointer. Defaults should not have a valid class pointer.
}
}
}
// Go through the bodyque.
for (i = 0; i < BODYQUESIZE; ++i)
{

View file

@ -36,6 +36,7 @@
#include <stdlib.h>
#include "doomtype.h"
#include "i_system.h"
class PClass;
@ -109,8 +110,10 @@ struct ClassReg
PClass *MyClass;
const char *Name;
ClassReg *ParentType;
ClassReg *_VMExport;
const size_t *Pointers;
void (*ConstructNative)(void *);
void(*InitNatives)();
unsigned int SizeOf:28;
unsigned int MetaClassNum:4;
@ -124,8 +127,8 @@ enum EInPlace { EC_InPlace };
public: \
virtual PClass *StaticType() const; \
static ClassReg RegistrationInfo, * const RegistrationInfoPtr; \
private: \
typedef parent Super; \
private: \
typedef cls ThisClass;
#define DECLARE_ABSTRACT_CLASS_WITH_META(cls,parent,meta) \
@ -147,11 +150,6 @@ protected: \
#define HAS_OBJECT_POINTERS \
static const size_t PointerOffsets[];
// Taking the address of a field in an object at address 1 instead of
// address 0 keeps GCC from complaining about possible misuse of offsetof.
#define DECLARE_POINTER(field) (size_t)&((ThisClass*)1)->field - 1,
#define END_POINTERS ~(size_t)0 };
#if defined(_MSC_VER)
# pragma section(".creg$u",read)
# define _DECLARE_TI(cls) __declspec(allocate(".creg$u")) ClassReg * const cls::RegistrationInfoPtr = &cls::RegistrationInfo;
@ -159,36 +157,41 @@ protected: \
# define _DECLARE_TI(cls) ClassReg * const cls::RegistrationInfoPtr __attribute__((section(SECTION_CREG))) = &cls::RegistrationInfo;
#endif
#define _IMP_PCLASS(cls,ptrs,create) \
#define _IMP_PCLASS(cls, ptrs, create) \
ClassReg cls::RegistrationInfo = {\
NULL, \
nullptr, \
#cls, \
&cls::Super::RegistrationInfo, \
nullptr, \
ptrs, \
create, \
nullptr, \
sizeof(cls), \
cls::MetaClassNum }; \
_DECLARE_TI(cls) \
PClass *cls::StaticType() const { return RegistrationInfo.MyClass; }
#define _IMP_CREATE_OBJ(cls) \
void cls::InPlaceConstructor(void *mem) { new((EInPlace *)mem) cls; }
#define IMPLEMENT_CLASS(cls, isabstract, ptrs) \
_X_CONSTRUCTOR_##isabstract(cls) \
_IMP_PCLASS(cls, _X_POINTERS_##ptrs(cls), _X_ABSTRACT_##isabstract(cls))
#define IMPLEMENT_POINTY_CLASS(cls) \
_IMP_CREATE_OBJ(cls) \
_IMP_PCLASS(cls,cls::PointerOffsets,cls::InPlaceConstructor) \
const size_t cls::PointerOffsets[] = {
// Taking the address of a field in an object at address 1 instead of
// address 0 keeps GCC from complaining about possible misuse of offsetof.
#define IMPLEMENT_POINTERS_START(cls) const size_t cls::PointerOffsets[] = {
#define IMPLEMENT_POINTER(field) (size_t)&((ThisClass*)1)->field - 1,
#define IMPLEMENT_POINTERS_END ~(size_t)0 };
#define IMPLEMENT_CLASS(cls) \
_IMP_CREATE_OBJ(cls) \
_IMP_PCLASS(cls,NULL,cls::InPlaceConstructor)
#define IMPLEMENT_ABSTRACT_CLASS(cls) \
_IMP_PCLASS(cls,NULL,NULL)
#define IMPLEMENT_ABSTRACT_POINTY_CLASS(cls) \
_IMP_PCLASS(cls,cls::PointerOffsets,NULL) \
const size_t cls::PointerOffsets[] = {
// Possible arguments for the IMPLEMENT_CLASS macro
#define _X_POINTERS_true(cls) cls::PointerOffsets
#define _X_POINTERS_false(cls) nullptr
#define _X_FIELDS_true(cls) nullptr
#define _X_FIELDS_false(cls) nullptr
#define _X_CONSTRUCTOR_true(cls)
#define _X_CONSTRUCTOR_false(cls) void cls::InPlaceConstructor(void *mem) { new((EInPlace *)mem) cls; }
#define _X_ABSTRACT_true(cls) nullptr
#define _X_ABSTRACT_false(cls) cls::InPlaceConstructor
#define _X_VMEXPORT_true(cls) nullptr
#define _X_VMEXPORT_false(cls) nullptr
enum EObjectFlags
{
@ -201,7 +204,6 @@ enum EObjectFlags
OF_EuthanizeMe = 1 << 5, // Object wants to die
OF_Cleanup = 1 << 6, // Object is now being deleted by the collector
OF_YesReallyDelete = 1 << 7, // Object is being deleted outside the collector, and this is okay, so don't print a warning
OF_Transient = 1 << 11, // Object should not be archived (references to it will be nulled on disk)
OF_WhiteBits = OF_White0 | OF_White1,
OF_MarkBits = OF_WhiteBits | OF_Black,
@ -210,6 +212,8 @@ enum EObjectFlags
OF_JustSpawned = 1 << 8, // Thinker was spawned this tic
OF_SerialSuccess = 1 << 9, // For debugging Serialize() calls
OF_Sentinel = 1 << 10, // Object is serving as the sentinel in a ring list
OF_Transient = 1 << 11, // Object should not be archived (references to it will be nulled on disk)
OF_SuperCall = 1 << 12, // A super call from the VM is about to be performed
};
template<class T> class TObjPtr;
@ -472,13 +476,13 @@ public:
// that don't call their base class.
void CheckIfSerialized () const;
virtual void Destroy ();
virtual void Destroy();
// If you need to replace one object with another and want to
// change any pointers from the old object to the new object,
// use this method.
virtual size_t PointerSubstitution (DObject *old, DObject *notOld);
static size_t StaticPointerSubstitution (DObject *old, DObject *notOld);
static size_t StaticPointerSubstitution (DObject *old, DObject *notOld, bool scandefaults = false);
PClass *GetClass() const
{
@ -574,6 +578,8 @@ protected:
}
};
class AInventory;//
// When you write to a pointer to an Object, you must call this for
// proper bookkeeping in case the Object holding this pointer has
// already been processed by the GC.

View file

@ -124,7 +124,8 @@ public:
int PolyNum;
int SideNum;
};
IMPLEMENT_CLASS(DSectorMarker)
IMPLEMENT_CLASS(DSectorMarker, false, false)
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------

File diff suppressed because it is too large Load diff

View file

@ -5,20 +5,36 @@
#error You must #include "dobject.h" to get dobjtype.h
#endif
#include "vm.h"
typedef std::pair<const class PType *, unsigned> FTypeAndOffset;
#include "vm.h"
// Variable/parameter/field flags -------------------------------------------
// Making all these different storage types use a common set of flags seems
// like the simplest thing to do.
#define VARF_Optional (1<<0) // func param is optional
#define VARF_Method (1<<1) // func has an implied self parameter
#define VARF_Action (1<<2) // func has implied owner and state parameters
#define VARF_Native (1<<3) // func is native code/don't auto serialize field
#define VARF_ReadOnly (1<<4) // field is read only, do not write to it
enum
{
VARF_Optional = (1<<0), // func param is optional
VARF_Method = (1<<1), // func has an implied self parameter
VARF_Action = (1<<2), // func has implied owner and state parameters
VARF_Native = (1<<3), // func is native code, field is natively defined
VARF_ReadOnly = (1<<4), // field is read only, do not write to it
VARF_Private = (1<<5), // field is private to containing class
VARF_Protected = (1<<6), // field is only accessible by containing class and children.
VARF_Deprecated = (1<<7), // Deprecated fields should output warnings when used.
VARF_Virtual = (1<<8), // function is virtual
VARF_Final = (1<<9), // Function may not be overridden in subclasses
VARF_In = (1<<10),
VARF_Out = (1<<11),
VARF_Implicit = (1<<12), // implicitly created parameters (i.e. do not compare types when checking function signatures)
VARF_Static = (1<<13), // static class data (by necessity read only.)
VARF_InternalAccess = (1<<14), // overrides VARF_ReadOnly for internal script code.
VARF_Override = (1<<15), // overrides a virtual function from the parent class.
VARF_Ref = (1<<16), // argument is passed by reference.
VARF_Transient = (1<<17) // don't auto serialize field.
};
// Symbol information -------------------------------------------------------
@ -57,7 +73,6 @@ struct StateCallData;
class VMFrameStack;
struct VMValue;
struct VMReturn;
typedef int (*actionf_p)(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret);/*(VM_ARGS)*/
class VMFunction;
// A VM function ------------------------------------------------------------
@ -86,18 +101,6 @@ public:
PSymbolType() : PSymbol(NAME_None) {}
};
// A symbol for a compiler tree node ----------------------------------------
class PSymbolTreeNode : public PSymbol
{
DECLARE_CLASS(PSymbolTreeNode, PSymbol);
public:
struct ZCC_NamedNode *Node;
PSymbolTreeNode(FName name, struct ZCC_NamedNode *node) : PSymbol(name), Node(node) {}
PSymbolTreeNode() : PSymbol(NAME_None) {}
};
// A symbol table -----------------------------------------------------------
struct PSymbolTable
@ -111,6 +114,10 @@ struct PSymbolTable
// Sets the table to use for searches if this one doesn't contain the
// requested symbol.
void SetParentTable (PSymbolTable *parent);
PSymbolTable *GetParentTable() const
{
return ParentSymbolTable;
}
// Finds a symbol in the table, optionally searching parent tables
// as well.
@ -120,6 +127,7 @@ struct PSymbolTable
// specific symbol table the symbol was found in.
PSymbol *FindSymbolInTable(FName symname, PSymbolTable *&symtable);
// Places the symbol in the table and returns a pointer to it or NULL if
// a symbol with the same name is already in the table. This symbol is
// not copied and will be freed when the symbol table is destroyed.
@ -132,15 +140,33 @@ struct PSymbolTable
// Frees all symbols from this table.
void ReleaseSymbols();
private:
typedef TMap<FName, PSymbol *> MapType;
MapType::Iterator GetIterator()
{
return MapType::Iterator(Symbols);
}
private:
PSymbolTable *ParentSymbolTable;
MapType Symbols;
friend class DObject;
};
// A symbol for a compiler tree node ----------------------------------------
class PSymbolTreeNode : public PSymbol
{
DECLARE_CLASS(PSymbolTreeNode, PSymbol);
public:
struct ZCC_TreeNode *Node;
PSymbolTreeNode(FName name, struct ZCC_TreeNode *node) : PSymbol(name), Node(node) {}
PSymbolTreeNode() : PSymbol(NAME_None) {}
};
extern PSymbolTable GlobalSymbols;
// Basic information shared by all types ------------------------------------
@ -179,6 +205,7 @@ class PType : public PTypeBase
HAS_OBJECT_POINTERS;
protected:
enum { MetaClassNum = CLASSREG_PClassType };
public:
typedef PClassType MetaClass;
MetaClass *GetClass() const;
@ -196,10 +223,13 @@ public:
unsigned int Align; // this type's preferred alignment
PType *HashNext; // next type in this type table
PSymbolTable Symbols;
bool MemberOnly = false; // type may only be used as a struct/class member but not as a local variable or function argument.
FString mDescriptiveName;
BYTE loadOp, storeOp, moveOp, RegType, RegCount;
PType();
PType(unsigned int size, unsigned int align);
PType(unsigned int size = 1, unsigned int align = 1);
virtual ~PType();
virtual bool isNumeric() { return false; }
bool AddConversion(PType *target, void (*convertconst)(ZCC_ExprConstant *, class FSharedStringArena &));
@ -224,6 +254,7 @@ public:
// initialization when the object is created and destruction when the
// object is destroyed.
virtual void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special=NULL) const;
virtual void SetPointer(void *base, unsigned offset, TArray<size_t> *ptrofs = NULL) const;
// Initialize the value, if needed (e.g. strings)
virtual void InitializeValue(void *addr, const void *def) const;
@ -240,14 +271,33 @@ public:
virtual double GetValueFloat(void *addr) const;
// Gets the opcode to store from a register to memory
virtual int GetStoreOp() const;
int GetStoreOp() const
{
return storeOp;
}
// Gets the opcode to load from memory to a register
virtual int GetLoadOp() const;
int GetLoadOp() const
{
return loadOp;
}
// Gets the opcode to move from register to another register
int GetMoveOp() const
{
return moveOp;
}
// Gets the register type for this type
virtual int GetRegType() const;
int GetRegType() const
{
return RegType;
}
int GetRegCount() const
{
return RegCount;
}
// Returns true if this type matches the two identifiers. Referring to the
// above table, any type is identified by at most two characteristics. Each
// type that implements this function will cast these to the appropriate type.
@ -259,6 +309,8 @@ public:
// Get the type IDs used by IsMatch
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
const char *DescriptiveName() const;
size_t PropagateMark();
static void StaticInit();
@ -318,7 +370,7 @@ class PErrorType : public PType
{
DECLARE_CLASS(PErrorType, PType);
public:
PErrorType() : PType(0, 1) {}
PErrorType(int which = 1) : PType(0, which) {}
};
class PVoidType : public PType
@ -351,8 +403,12 @@ public:
PTypeBase *Outer; // object this type is contained within
FName TypeName; // this type's name
PNamedType() : Outer(NULL) {}
PNamedType(FName name, PTypeBase *outer) : Outer(outer), TypeName(name) {}
PNamedType() : Outer(NULL) {
mDescriptiveName = "NamedType";
}
PNamedType(FName name, PTypeBase *outer) : Outer(outer), TypeName(name) {
mDescriptiveName = name.GetChars();
}
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
@ -365,7 +421,7 @@ class PInt : public PBasicType
{
DECLARE_CLASS(PInt, PBasicType);
public:
PInt(unsigned int size, bool unsign);
PInt(unsigned int size, bool unsign, bool compatible = true);
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
@ -374,13 +430,13 @@ public:
virtual void SetValue(void *addr, double val);
virtual int GetValueInt(void *addr) const;
virtual double GetValueFloat(void *addr) const;
virtual int GetStoreOp() const;
virtual int GetLoadOp() const;
virtual int GetRegType() const;
virtual bool isNumeric() override { return IntCompatible; }
bool Unsigned;
bool IntCompatible;
protected:
PInt();
void SetOps();
};
class PBool : public PInt
@ -403,11 +459,10 @@ public:
virtual void SetValue(void *addr, double val);
virtual int GetValueInt(void *addr) const;
virtual double GetValueFloat(void *addr) const;
virtual int GetStoreOp() const;
virtual int GetLoadOp() const;
virtual int GetRegType() const;
virtual bool isNumeric() override { return true; }
protected:
PFloat();
void SetOps();
private:
struct SymbolInitF
{
@ -432,8 +487,6 @@ class PString : public PBasicType
public:
PString();
virtual int GetRegType() const;
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special=NULL) const override;
@ -463,6 +516,26 @@ public:
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
};
class PSpriteID : public PInt
{
DECLARE_CLASS(PSpriteID, PInt);
public:
PSpriteID();
void WriteValue(FSerializer &ar, const char *key, const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key, void *addr) const override;
};
class PTextureID : public PInt
{
DECLARE_CLASS(PTextureID, PInt);
public:
PTextureID();
void WriteValue(FSerializer &ar, const char *key, const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key, void *addr) const override;
};
class PColor : public PInt
{
DECLARE_CLASS(PColor, PInt);
@ -470,45 +543,48 @@ public:
PColor();
};
// Pointers -----------------------------------------------------------------
class PStatePointer : public PBasicType
class PStateLabel : public PInt
{
DECLARE_CLASS(PStatePointer, PBasicType);
DECLARE_CLASS(PStateLabel, PInt);
public:
PStatePointer();
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
virtual int GetStoreOp() const;
virtual int GetLoadOp() const;
virtual int GetRegType() const;
PStateLabel();
};
// Pointers -----------------------------------------------------------------
class PPointer : public PBasicType
{
DECLARE_CLASS(PPointer, PBasicType);
HAS_OBJECT_POINTERS;
public:
PPointer(PType *pointsat);
PPointer();
PPointer(PType *pointsat, bool isconst = false);
PType *PointedType;
virtual int GetStoreOp() const;
virtual int GetLoadOp() const;
virtual int GetRegType() const;
bool IsConst;
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
void SetPointer(void *base, unsigned offset, TArray<size_t> *special = NULL) const override;
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
protected:
PPointer();
void SetOps();
};
class PStatePointer : public PPointer
{
DECLARE_CLASS(PStatePointer, PPointer);
public:
PStatePointer();
void WriteValue(FSerializer &ar, const char *key, const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key, void *addr) const override;
};
class PClassPointer : public PPointer
{
DECLARE_CLASS(PClassPointer, PPointer);
@ -518,6 +594,9 @@ public:
class PClass *ClassRestriction;
// this is only here to block PPointer's implementation
void SetPointer(void *base, unsigned offset, TArray<size_t> *special = NULL) const override {}
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
protected:
@ -532,13 +611,12 @@ class PField : public PSymbol
DECLARE_CLASS(PField, PSymbol);
HAS_OBJECT_POINTERS
public:
PField(FName name, PType *type) : PSymbol(name), Offset(0), Type(type), Flags(0) {}
PField(FName name, PType *type, DWORD flags) : PSymbol(name), Offset(0), Type(type), Flags(flags) {}
PField(FName name, PType *type, DWORD flags, unsigned offset) : PSymbol(name), Offset(offset), Type(type), Flags(flags) {}
PField(FName name, PType *type, DWORD flags = 0, size_t offset = 0, int bitvalue = 0);
unsigned int Offset;
size_t Offset;
PType *Type;
DWORD Flags;
int BitValue;
protected:
PField();
};
@ -576,22 +654,12 @@ public:
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special) const override;
void SetPointer(void *base, unsigned offset, TArray<size_t> *special) const override;
protected:
PArray();
};
// A vector is an array with extra operations.
class PVector : public PArray
{
DECLARE_CLASS(PVector, PArray);
HAS_OBJECT_POINTERS;
public:
PVector(unsigned int size);
protected:
PVector();
};
class PDynArray : public PCompoundType
{
DECLARE_CLASS(PDynArray, PCompoundType);
@ -630,14 +698,17 @@ public:
PStruct(FName name, PTypeBase *outer);
TArray<PField *> Fields;
bool HasNativeFields;
virtual PField *AddField(FName name, PType *type, DWORD flags=0);
virtual PField *AddNativeField(FName name, PType *type, size_t address, DWORD flags = 0, int bitvalue = 0);
size_t PropagateMark();
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *specials) const override;
void SetPointer(void *base, unsigned offset, TArray<size_t> *specials) const override;
static void WriteFields(FSerializer &ar, const void *addr, const TArray<PField *> &fields);
bool ReadFields(FSerializer &ar, void *addr) const;
@ -645,6 +716,15 @@ protected:
PStruct();
};
// a native struct will always be abstract and cannot be instantiated. All variables are references.
// In addition, native structs can have methods (but no virtual ones.)
class PNativeStruct : public PStruct
{
DECLARE_CLASS(PNativeStruct, PStruct);
public:
PNativeStruct(FName name = NAME_None);
};
class PPrototype : public PCompoundType
{
DECLARE_CLASS(PPrototype, PCompoundType);
@ -668,19 +748,28 @@ class PFunction : public PSymbol
public:
struct Variant
{
//PPrototype *Proto;
PPrototype *Proto;
VMFunction *Implementation;
TArray<DWORD> ArgFlags; // Should be the same length as Proto->ArgumentTypes
TArray<FName> ArgNames; // we need the names to access them later when the function gets compiled.
uint32_t Flags;
int UseFlags;
PStruct *SelfClass;
};
TArray<Variant> Variants;
DWORD Flags;
PStruct *OwningClass = nullptr;
unsigned AddVariant(PPrototype *proto, TArray<DWORD> &argflags, VMFunction *impl);
unsigned AddVariant(PPrototype *proto, TArray<DWORD> &argflags, TArray<FName> &argnames, VMFunction *impl, int flags, int useflags);
int GetImplicitArgs()
{
if (Variants[0].Flags & VARF_Action) return 3;
else if (Variants[0].Flags & VARF_Method) return 1;
return 0;
}
size_t PropagateMark();
PFunction(FName name) : PSymbol(name), Flags(0) {}
PFunction() : PSymbol(NAME_None), Flags(0) {}
PFunction(PStruct *owner = nullptr, FName name = NAME_None) : PSymbol(name), OwningClass(owner) {}
};
// Meta-info for every class derived from DObject ---------------------------
@ -691,16 +780,17 @@ enum
};
class PClassClass;
class PClass : public PStruct
class PClass : public PNativeStruct
{
DECLARE_CLASS(PClass, PStruct);
DECLARE_CLASS(PClass, PNativeStruct);
HAS_OBJECT_POINTERS;
protected:
// We unravel _WITH_META here just as we did for PType.
enum { MetaClassNum = CLASSREG_PClassClass };
TArray<FTypeAndOffset> SpecialInits;
virtual void Derive(PClass *newclass);
void Derive(PClass *newclass, FName name);
void InitializeSpecials(void *addr) const;
void SetSuper();
public:
typedef PClassClass MetaClass;
MetaClass *GetClass() const;
@ -709,8 +799,10 @@ public:
void WriteAllFields(FSerializer &ar, const void *addr) const;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
bool ReadAllFields(FSerializer &ar, void *addr) const;
void InitializeDefaults();
int FindVirtualIndex(FName name, PPrototype *proto);
virtual void DeriveData(PClass *newclass);
virtual void DeriveData(PClass *newclass) {}
static void StaticInit();
static void StaticShutdown();
static void StaticBootstrap();
@ -721,6 +813,9 @@ public:
const size_t *FlatPointers; // object pointers defined by this class and all its superclasses; not initialized by default
BYTE *Defaults;
bool bRuntimeClass; // class was defined at run-time, not compile-time
bool bExported; // This type has been declared in a script
bool bDecorateClass; // may be subject to some idiosyncracies due to DECORATE backwards compatibility
TArray<VMFunction*> Virtuals; // virtual function table
void (*ConstructNative)(void *);
@ -764,7 +859,8 @@ public:
static PClassActor *FindActor(const FString &name) { return FindActor(FName(name, true)); }
static PClassActor *FindActor(ENamedName name) { return FindActor(FName(name)); }
static PClassActor *FindActor(FName name);
PClass *FindClassTentative(FName name, bool fatal = true); // not static!
static VMFunction *FindFunction(FName cls, FName func);
PClass *FindClassTentative(FName name);
static TArray<PClass *> AllClasses;
@ -777,7 +873,7 @@ class PClassType : public PClass
protected:
public:
PClassType();
virtual void Derive(PClass *newclass);
virtual void DeriveData(PClass *newclass);
PClass *TypeTableType; // The type to use for hashing into the type table
};
@ -799,17 +895,6 @@ inline PClass::MetaClass *PClass::GetClass() const
return static_cast<MetaClass *>(DObject::GetClass());
}
// A class that hasn't had its parent class defined yet ---------------------
class PClassWaitingForParent : public PClass
{
DECLARE_CLASS(PClassWaitingForParent, PClass);
public:
PClassWaitingForParent(FName myname, FName parentname);
FName ParentName;
};
// Type tables --------------------------------------------------------------
struct FTypeTable
@ -832,20 +917,20 @@ struct FTypeTable
extern FTypeTable TypeTable;
// Returns a type from the TypeTable. Will create one if it isn't present.
PVector *NewVector(unsigned int size);
PMap *NewMap(PType *keytype, PType *valuetype);
PArray *NewArray(PType *type, unsigned int count);
PDynArray *NewDynArray(PType *type);
PPointer *NewPointer(PType *type);
PPointer *NewPointer(PType *type, bool isconst = false);
PClassPointer *NewClassPointer(PClass *restrict);
PClassWaitingForParent *NewUnknownClass(FName myname, FName parentname);
PEnum *NewEnum(FName name, PTypeBase *outer);
PStruct *NewStruct(FName name, PTypeBase *outer);
PNativeStruct *NewNativeStruct(FName name, PTypeBase *outer);
PPrototype *NewPrototype(const TArray<PType *> &rettypes, const TArray<PType *> &argtypes);
// Built-in types -----------------------------------------------------------
extern PErrorType *TypeError;
extern PErrorType *TypeAuto;
extern PVoidType *TypeVoid;
extern PInt *TypeSInt8, *TypeUInt8;
extern PInt *TypeSInt16, *TypeUInt16;
@ -856,7 +941,15 @@ extern PString *TypeString;
extern PName *TypeName;
extern PSound *TypeSound;
extern PColor *TypeColor;
extern PTextureID *TypeTextureID;
extern PSpriteID *TypeSpriteID;
extern PStruct *TypeVector2;
extern PStruct *TypeVector3;
extern PStruct *TypeColorStruct;
extern PStruct *TypeStringStruct;
extern PStatePointer *TypeState;
extern PStateLabel *TypeStateLabel;
extern PPointer *TypeNullPtr;
// A constant value ---------------------------------------------------------

View file

@ -56,6 +56,12 @@ public:
strncpy (m_Message, message, MAX_ERRORTEXT-1);
m_Message[MAX_ERRORTEXT-1] = '\0';
}
void AppendMessage(const char *message)
{
size_t len = strlen(m_Message);
strncpy(m_Message + len, message, MAX_ERRORTEXT - 1 - len);
m_Message[MAX_ERRORTEXT - 1] = '\0';
}
const char *GetMessage (void) const
{
if (m_Message[0] != '\0')
@ -64,7 +70,7 @@ public:
return NULL;
}
private:
protected:
char m_Message[MAX_ERRORTEXT];
};

View file

@ -264,12 +264,14 @@ char ( &_ArraySizeHelper( T (&array)[N] ))[N];
#ifdef __MACH__
#define SECTION_AREG "__DATA,areg"
#define SECTION_CREG "__DATA,creg"
#define SECTION_FREG "__DATA,freg"
#define SECTION_GREG "__DATA,greg"
#define SECTION_MREG "__DATA,mreg"
#define SECTION_YREG "__DATA,yreg"
#else
#define SECTION_AREG "areg"
#define SECTION_CREG "creg"
#define SECTION_FREG "freg"
#define SECTION_GREG "greg"
#define SECTION_MREG "mreg"
#define SECTION_YREG "yreg"

View file

@ -31,7 +31,7 @@
#include "serializer.h"
#include "doomstat.h"
IMPLEMENT_CLASS (DSectorEffect)
IMPLEMENT_CLASS(DSectorEffect, false, false)
DSectorEffect::DSectorEffect ()
: DThinker(STAT_SECTOREFFECT)
@ -71,9 +71,11 @@ void DSectorEffect::Serialize(FSerializer &arc)
arc("sector", m_Sector);
}
IMPLEMENT_POINTY_CLASS (DMover)
DECLARE_POINTER(interpolation)
END_POINTERS
IMPLEMENT_CLASS(DMover, false, true)
IMPLEMENT_POINTERS_START(DMover)
IMPLEMENT_POINTER(interpolation)
IMPLEMENT_POINTERS_END
DMover::DMover ()
{
@ -106,9 +108,7 @@ void DMover::StopInterpolation(bool force)
}
}
IMPLEMENT_CLASS (DMovingFloor)
IMPLEMENT_CLASS(DMovingFloor, false, false)
DMovingFloor::DMovingFloor ()
{
@ -121,7 +121,7 @@ DMovingFloor::DMovingFloor (sector_t *sector)
interpolation = sector->SetInterpolation(sector_t::FloorMove, true);
}
IMPLEMENT_CLASS (DMovingCeiling)
IMPLEMENT_CLASS(DMovingCeiling, false, false)
DMovingCeiling::DMovingCeiling ()
{

View file

@ -12,7 +12,7 @@ public:
void Serialize(FSerializer &arc);
void Destroy();
void Destroy() override;
sector_t *GetSector() const { return m_Sector; }
@ -35,7 +35,7 @@ protected:
DMover ();
void Serialize(FSerializer &arc);
void Destroy();
void Destroy() override;
};
class DMovingFloor : public DMover

View file

@ -40,6 +40,7 @@
#include "doomerrors.h"
#include "serializer.h"
#include "d_player.h"
#include "virtual.h"
static cycle_t ThinkCycles;
@ -47,7 +48,7 @@ extern cycle_t BotSupportCycles;
extern cycle_t ActionCycles;
extern int BotWTG;
IMPLEMENT_CLASS (DThinker)
IMPLEMENT_CLASS(DThinker, false, false)
DThinker *NextToThink;
@ -55,6 +56,12 @@ FThinkerList DThinker::Thinkers[MAX_STATNUM+2];
FThinkerList DThinker::FreshThinkers[MAX_STATNUM+1];
bool DThinker::bSerialOverride = false;
//==========================================================================
//
//
//
//==========================================================================
void FThinkerList::AddTail(DThinker *thinker)
{
assert(thinker->PrevThinker == NULL && thinker->NextThinker == NULL);
@ -79,6 +86,12 @@ void FThinkerList::AddTail(DThinker *thinker)
GC::WriteBarrier(Sentinel, thinker);
}
//==========================================================================
//
//
//
//==========================================================================
DThinker *FThinkerList::GetHead() const
{
if (Sentinel == NULL || Sentinel->NextThinker == Sentinel)
@ -89,6 +102,12 @@ DThinker *FThinkerList::GetHead() const
return Sentinel->NextThinker;
}
//==========================================================================
//
//
//
//==========================================================================
DThinker *FThinkerList::GetTail() const
{
if (Sentinel == NULL || Sentinel->PrevThinker == Sentinel)
@ -98,11 +117,23 @@ DThinker *FThinkerList::GetTail() const
return Sentinel->PrevThinker;
}
//==========================================================================
//
//
//
//==========================================================================
bool FThinkerList::IsEmpty() const
{
return Sentinel == NULL || Sentinel->NextThinker == NULL;
}
//==========================================================================
//
//
//
//==========================================================================
void DThinker::SaveList(FSerializer &arc, DThinker *node)
{
if (node != NULL)
@ -233,6 +264,12 @@ void DThinker::Destroy ()
Super::Destroy();
}
//==========================================================================
//
//
//
//==========================================================================
void DThinker::Remove()
{
if (this == NextToThink)
@ -253,14 +290,53 @@ void DThinker::Remove()
PrevThinker = NULL;
}
//==========================================================================
//
//
//
//==========================================================================
void DThinker::PostBeginPlay ()
{
}
DEFINE_ACTION_FUNCTION(DThinker, PostBeginPlay)
{
PARAM_SELF_PROLOGUE(DThinker);
self->PostBeginPlay();
return 0;
}
void DThinker::CallPostBeginPlay()
{
IFVIRTUAL(DThinker, PostBeginPlay)
{
// Without the type cast this picks the 'void *' assignment...
VMValue params[1] = { (DObject*)this };
GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr);
}
else
{
PostBeginPlay();
}
}
//==========================================================================
//
//
//
//==========================================================================
void DThinker::PostSerialize()
{
}
//==========================================================================
//
//
//
//==========================================================================
DThinker *DThinker::FirstThinker (int statnum)
{
DThinker *node;
@ -281,6 +357,12 @@ DThinker *DThinker::FirstThinker (int statnum)
return node;
}
//==========================================================================
//
//
//
//==========================================================================
void DThinker::ChangeStatNum (int statnum)
{
FThinkerList *list;
@ -304,7 +386,19 @@ void DThinker::ChangeStatNum (int statnum)
list->AddTail(this);
}
DEFINE_ACTION_FUNCTION(DThinker, ChangeStatNum)
{
PARAM_SELF_PROLOGUE(DThinker);
PARAM_INT(stat);
self->ChangeStatNum(stat);
return 0;
}
//==========================================================================
//
// Mark the first thinker of each list
//
//==========================================================================
void DThinker::MarkRoots()
{
for (int i = 0; i <= MAX_STATNUM; ++i)
@ -315,7 +409,12 @@ void DThinker::MarkRoots()
GC::Mark(Thinkers[MAX_STATNUM+1].Sentinel);
}
//==========================================================================
//
// Destroy every thinker
//
//==========================================================================
void DThinker::DestroyAllThinkers ()
{
int i;
@ -332,6 +431,12 @@ void DThinker::DestroyAllThinkers ()
GC::FullGC();
}
//==========================================================================
//
//
//
//==========================================================================
void DThinker::DestroyThinkersInList (FThinkerList &list)
{
if (list.Sentinel != NULL)
@ -346,6 +451,12 @@ void DThinker::DestroyThinkersInList (FThinkerList &list)
}
}
//==========================================================================
//
//
//
//==========================================================================
void DThinker::RunThinkers ()
{
int i, count;
@ -376,6 +487,12 @@ void DThinker::RunThinkers ()
ThinkCycles.Unclock();
}
//==========================================================================
//
//
//
//==========================================================================
int DThinker::TickThinkers (FThinkerList *list, FThinkerList *dest)
{
int count = 0;
@ -398,7 +515,7 @@ int DThinker::TickThinkers (FThinkerList *list, FThinkerList *dest)
node->Remove();
dest->AddTail(node);
}
node->PostBeginPlay();
node->CallPostBeginPlay();
}
else if (dest != NULL)
{
@ -407,7 +524,7 @@ int DThinker::TickThinkers (FThinkerList *list, FThinkerList *dest)
if (!(node->ObjectFlags & OF_EuthanizeMe))
{ // Only tick thinkers not scheduled for destruction
node->Tick();
node->CallTick();
node->ObjectFlags &= ~OF_JustSpawned;
GC::CheckGC();
}
@ -416,10 +533,40 @@ int DThinker::TickThinkers (FThinkerList *list, FThinkerList *dest)
return count;
}
//==========================================================================
//
//
//
//==========================================================================
void DThinker::Tick ()
{
}
DEFINE_ACTION_FUNCTION(DThinker, Tick)
{
PARAM_SELF_PROLOGUE(DThinker);
self->Tick();
return 0;
}
void DThinker::CallTick()
{
IFVIRTUAL(DThinker, Tick)
{
// Without the type cast this picks the 'void *' assignment...
VMValue params[1] = { (DObject*)this };
GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr);
}
else Tick();
}
//==========================================================================
//
//
//
//==========================================================================
size_t DThinker::PropagateMark()
{
// Do not choke on partially initialized objects (as happens when loading a savegame fails)
@ -433,6 +580,12 @@ size_t DThinker::PropagateMark()
return Super::PropagateMark();
}
//==========================================================================
//
//
//
//==========================================================================
FThinkerIterator::FThinkerIterator (const PClass *type, int statnum)
{
if ((unsigned)statnum > MAX_STATNUM)
@ -450,6 +603,12 @@ FThinkerIterator::FThinkerIterator (const PClass *type, int statnum)
m_SearchingFresh = false;
}
//==========================================================================
//
//
//
//==========================================================================
FThinkerIterator::FThinkerIterator (const PClass *type, int statnum, DThinker *prev)
{
if ((unsigned)statnum > MAX_STATNUM)
@ -474,13 +633,25 @@ FThinkerIterator::FThinkerIterator (const PClass *type, int statnum, DThinker *p
}
}
//==========================================================================
//
//
//
//==========================================================================
void FThinkerIterator::Reinit ()
{
m_CurrThinker = DThinker::Thinkers[m_Stat].GetHead();
m_SearchingFresh = false;
}
DThinker *FThinkerIterator::Next ()
//==========================================================================
//
//
//
//==========================================================================
DThinker *FThinkerIterator::Next (bool exact)
{
if (m_ParentType == NULL)
{
@ -496,7 +667,11 @@ DThinker *FThinkerIterator::Next ()
{
DThinker *thinker = m_CurrThinker;
m_CurrThinker = thinker->NextThinker;
if (thinker->IsKindOf(m_ParentType))
if (exact)
{
if (thinker->IsA(m_ParentType)) return thinker;
}
else if (thinker->IsKindOf(m_ParentType))
{
return thinker;
}
@ -521,6 +696,52 @@ DThinker *FThinkerIterator::Next ()
return NULL;
}
//==========================================================================
//
// This is for scripting, which needs the iterator wrapped into an object with the needed functions exported.
// Unfortunately we cannot have templated type conversions in scripts.
//
//==========================================================================
class DThinkerIterator : public DObject, public FThinkerIterator
{
DECLARE_CLASS(DThinkerIterator, DObject)
public:
DThinkerIterator(PClass *cls = nullptr, int statnum = MAX_STATNUM + 1)
: FThinkerIterator(cls, statnum)
{
}
};
IMPLEMENT_CLASS(DThinkerIterator, false, false);
DEFINE_ACTION_FUNCTION(DThinkerIterator, Create)
{
PARAM_PROLOGUE;
PARAM_CLASS_DEF(type, DThinker);
PARAM_INT_DEF(statnum);
ACTION_RETURN_OBJECT(new DThinkerIterator(type, statnum));
}
DEFINE_ACTION_FUNCTION(DThinkerIterator, Next)
{
PARAM_SELF_PROLOGUE(DThinkerIterator);
ACTION_RETURN_OBJECT(self->Next());
}
DEFINE_ACTION_FUNCTION(DThinkerIterator, Reinit)
{
PARAM_SELF_PROLOGUE(DThinkerIterator);
self->Reinit();
return 0;
}
//==========================================================================
//
//
//
//==========================================================================
ADD_STAT (think)
{
FString out;

View file

@ -66,10 +66,12 @@ class DThinker : public DObject
DECLARE_CLASS (DThinker, DObject)
public:
DThinker (int statnum = STAT_DEFAULT) throw();
void Destroy ();
void Destroy () override;
virtual ~DThinker ();
virtual void Tick ();
void CallTick();
virtual void PostBeginPlay (); // Called just before the first tick
void CallPostBeginPlay();
virtual void PostSerialize();
size_t PropagateMark();
@ -121,7 +123,7 @@ private:
public:
FThinkerIterator (const PClass *type, int statnum=MAX_STATNUM+1);
FThinkerIterator (const PClass *type, int statnum, DThinker *prev);
DThinker *Next ();
DThinker *Next (bool exact = false);
void Reinit ();
};
@ -146,9 +148,9 @@ public:
TThinkerIterator (const char *subclass, int statnum=MAX_STATNUM+1) : FThinkerIterator(PClass::FindClass(subclass), statnum)
{
}
T *Next ()
T *Next (bool exact = false)
{
return static_cast<T *>(FThinkerIterator::Next ());
return static_cast<T *>(FThinkerIterator::Next (exact));
}
};

View file

@ -69,6 +69,7 @@
#include "p_setup.h"
#include "p_spec.h"
#include "r_utility.h"
#include "a_ammo.h"
#include "math/cmath.h"
static FRandom pr_script("FScript");
@ -1785,9 +1786,7 @@ public:
void Destroy() { Super::Destroy(); m_Sector->lightingdata=NULL; }
};
IMPLEMENT_CLASS (DLightLevel)
IMPLEMENT_CLASS(DLightLevel, false, false)
void DLightLevel::Serialize(FSerializer &arc)
{
@ -2015,13 +2014,13 @@ void FParser::SF_CeilingTexture(void)
void FParser::SF_ChangeHubLevel(void)
{
I_Error("FS hub system permanently disabled\n");
script_error("FS hub system permanently disabled\n");
}
// for start map: start new game on a particular skill
void FParser::SF_StartSkill(void)
{
I_Error("startskill is not supported by this implementation!\n");
script_error("startskill is not supported by this implementation!\n");
}
//==========================================================================
@ -2977,7 +2976,7 @@ void FParser::SF_ObjAwaken(void)
if(mo)
{
mo->Activate(Script->trigger);
mo->CallActivate(Script->trigger);
}
}
@ -3636,7 +3635,7 @@ void FParser::SF_Pow()
{
if (CheckArgs(2))
{
t_return.setDouble(pow(floatvalue(t_argv[0]), floatvalue(t_argv[1])));
t_return.setDouble(g_pow(floatvalue(t_argv[0]), floatvalue(t_argv[1])));
}
}

View file

@ -113,7 +113,7 @@ void FParser::NextToken()
}
if(!Section)
{
I_Error("section not found!\n");
script_error("section not found!\n");
return;
}
}
@ -708,6 +708,18 @@ void FParser::EvaluateExpression(svalue_t &result, int start, int stop)
//
//==========================================================================
void FS_Error(const char *error, ...)
{
va_list argptr;
char errortext[MAX_ERRORTEXT];
va_start(argptr, error);
myvsnprintf(errortext, MAX_ERRORTEXT, error, argptr);
va_end(argptr);
throw CFraggleScriptError(errortext);
}
void FParser::ErrorMessage(FString msg)
{
int linenum = 0;
@ -721,7 +733,7 @@ void FParser::ErrorMessage(FString msg)
}
//lineinfo.Format("Script %d, line %d: ", Script->scriptnum, linenum);
I_Error("Script %d, line %d: %s", Script->scriptnum, linenum, msg.GetChars());
FS_Error("Script %d, line %d: %s", Script->scriptnum, linenum, msg.GetChars());
}
//==========================================================================

View file

@ -71,9 +71,11 @@
//
//==========================================================================
IMPLEMENT_POINTY_CLASS(DFsSection)
DECLARE_POINTER(next)
END_POINTERS
IMPLEMENT_CLASS(DFsSection, false, true)
IMPLEMENT_POINTERS_START(DFsSection)
IMPLEMENT_POINTER(next)
IMPLEMENT_POINTERS_END
//==========================================================================
//

View file

@ -75,23 +75,23 @@ AActor *trigger_obj;
//
//==========================================================================
#define DECLARE_16_POINTERS(v, i) \
DECLARE_POINTER(v[i]) \
DECLARE_POINTER(v[i+1]) \
DECLARE_POINTER(v[i+2]) \
DECLARE_POINTER(v[i+3]) \
DECLARE_POINTER(v[i+4]) \
DECLARE_POINTER(v[i+5]) \
DECLARE_POINTER(v[i+6]) \
DECLARE_POINTER(v[i+7]) \
DECLARE_POINTER(v[i+8]) \
DECLARE_POINTER(v[i+9]) \
DECLARE_POINTER(v[i+10]) \
DECLARE_POINTER(v[i+11]) \
DECLARE_POINTER(v[i+12]) \
DECLARE_POINTER(v[i+13]) \
DECLARE_POINTER(v[i+14]) \
DECLARE_POINTER(v[i+15]) \
#define IMPLEMENT_16_POINTERS(v, i) \
IMPLEMENT_POINTER(v[i]) \
IMPLEMENT_POINTER(v[i+1]) \
IMPLEMENT_POINTER(v[i+2]) \
IMPLEMENT_POINTER(v[i+3]) \
IMPLEMENT_POINTER(v[i+4]) \
IMPLEMENT_POINTER(v[i+5]) \
IMPLEMENT_POINTER(v[i+6]) \
IMPLEMENT_POINTER(v[i+7]) \
IMPLEMENT_POINTER(v[i+8]) \
IMPLEMENT_POINTER(v[i+9]) \
IMPLEMENT_POINTER(v[i+10]) \
IMPLEMENT_POINTER(v[i+11]) \
IMPLEMENT_POINTER(v[i+12]) \
IMPLEMENT_POINTER(v[i+13]) \
IMPLEMENT_POINTER(v[i+14]) \
IMPLEMENT_POINTER(v[i+15]) \
//==========================================================================
//
@ -99,30 +99,32 @@ AActor *trigger_obj;
//
//==========================================================================
IMPLEMENT_POINTY_CLASS(DFsScript)
DECLARE_POINTER(parent)
DECLARE_POINTER(trigger)
DECLARE_16_POINTERS(sections, 0)
DECLARE_POINTER(sections[16])
DECLARE_16_POINTERS(variables, 0)
DECLARE_16_POINTERS(children, 0)
DECLARE_16_POINTERS(children, 16)
DECLARE_16_POINTERS(children, 32)
DECLARE_16_POINTERS(children, 48)
DECLARE_16_POINTERS(children, 64)
DECLARE_16_POINTERS(children, 80)
DECLARE_16_POINTERS(children, 96)
DECLARE_16_POINTERS(children, 112)
DECLARE_16_POINTERS(children, 128)
DECLARE_16_POINTERS(children, 144)
DECLARE_16_POINTERS(children, 160)
DECLARE_16_POINTERS(children, 176)
DECLARE_16_POINTERS(children, 192)
DECLARE_16_POINTERS(children, 208)
DECLARE_16_POINTERS(children, 224)
DECLARE_16_POINTERS(children, 240)
DECLARE_POINTER(children[256])
END_POINTERS
IMPLEMENT_CLASS(DFsScript, false, true)
IMPLEMENT_POINTERS_START(DFsScript)
IMPLEMENT_POINTER(parent)
IMPLEMENT_POINTER(trigger)
IMPLEMENT_16_POINTERS(sections, 0)
IMPLEMENT_POINTER(sections[16])
IMPLEMENT_16_POINTERS(variables, 0)
IMPLEMENT_16_POINTERS(children, 0)
IMPLEMENT_16_POINTERS(children, 16)
IMPLEMENT_16_POINTERS(children, 32)
IMPLEMENT_16_POINTERS(children, 48)
IMPLEMENT_16_POINTERS(children, 64)
IMPLEMENT_16_POINTERS(children, 80)
IMPLEMENT_16_POINTERS(children, 96)
IMPLEMENT_16_POINTERS(children, 112)
IMPLEMENT_16_POINTERS(children, 128)
IMPLEMENT_16_POINTERS(children, 144)
IMPLEMENT_16_POINTERS(children, 160)
IMPLEMENT_16_POINTERS(children, 176)
IMPLEMENT_16_POINTERS(children, 192)
IMPLEMENT_16_POINTERS(children, 208)
IMPLEMENT_16_POINTERS(children, 224)
IMPLEMENT_16_POINTERS(children, 240)
IMPLEMENT_POINTER(children[256])
IMPLEMENT_POINTERS_END
//==========================================================================
//
@ -249,7 +251,7 @@ void DFsScript::ParseScript(char *position)
FParser parse(this);
parse.Run(position, data, data + len);
}
catch (CRecoverableError &err)
catch (CFraggleScriptError &err)
{
Printf ("%s\n", err.GetMessage());
}
@ -267,12 +269,14 @@ void DFsScript::ParseScript(char *position)
//
//==========================================================================
IMPLEMENT_POINTY_CLASS(DRunningScript)
DECLARE_POINTER(prev)
DECLARE_POINTER(next)
DECLARE_POINTER(trigger)
DECLARE_16_POINTERS(variables, 0)
END_POINTERS
IMPLEMENT_CLASS(DRunningScript, false, true)
IMPLEMENT_POINTERS_START(DRunningScript)
IMPLEMENT_POINTER(prev)
IMPLEMENT_POINTER(next)
IMPLEMENT_POINTER(trigger)
IMPLEMENT_16_POINTERS(variables, 0)
IMPLEMENT_POINTERS_END
//==========================================================================
//
@ -375,10 +379,13 @@ void DRunningScript::Serialize(FSerializer &arc)
// The main thinker
//
//==========================================================================
IMPLEMENT_POINTY_CLASS(DFraggleThinker)
DECLARE_POINTER(RunningScripts)
DECLARE_POINTER(LevelScript)
END_POINTERS
IMPLEMENT_CLASS(DFraggleThinker, false, true)
IMPLEMENT_POINTERS_START(DFraggleThinker)
IMPLEMENT_POINTER(RunningScripts)
IMPLEMENT_POINTER(LevelScript)
IMPLEMENT_POINTERS_END
TObjPtr<DFraggleThinker> DFraggleThinker::ActiveThinker;

View file

@ -41,12 +41,22 @@
#include "p_lnspec.h"
#include "m_fixed.h"
#include "actor.h"
#include "doomerrors.h"
#ifdef _MSC_VER
// This pragma saves 8kb of wasted code.
#pragma pointers_to_members( full_generality, single_inheritance )
#endif
class CFraggleScriptError : public CDoomError
{
public:
CFraggleScriptError() : CDoomError() {}
CFraggleScriptError(const char *message) : CDoomError(message) {}
};
class DRunningScript;
@ -337,7 +347,7 @@ public:
DFsScript();
~DFsScript();
void Destroy();
void Destroy() override;
void Serialize(FSerializer &ar);
DFsVariable *NewVariable(const char *name, int vtype);
@ -652,7 +662,7 @@ class DRunningScript : public DObject
public:
DRunningScript(AActor *trigger=NULL, DFsScript *owner = NULL, int index = 0) ;
void Destroy();
void Destroy() override;
void Serialize(FSerializer &arc);
TObjPtr<DFsScript> script;
@ -687,7 +697,7 @@ public:
bool nocheckposition;
DFraggleThinker();
void Destroy();
void Destroy() override;
void Serialize(FSerializer & arc);

View file

@ -179,10 +179,12 @@ AActor* actorvalue(const svalue_t &svalue)
//
//==========================================================================
IMPLEMENT_POINTY_CLASS(DFsVariable)
DECLARE_POINTER (next)
DECLARE_POINTER (actor)
END_POINTERS
IMPLEMENT_CLASS(DFsVariable, false, true)
IMPLEMENT_POINTERS_START(DFsVariable)
IMPLEMENT_POINTER(next)
IMPLEMENT_POINTER(actor)
IMPLEMENT_POINTERS_END
//==========================================================================
//

View file

@ -1,30 +0,0 @@
/*
#include "actor.h"
#include "s_sound.h"
#include "p_local.h"
#include "p_enemy.h"
#include "a_action.h"
#include "thingdef/thingdef.h"
*/
DEFINE_ACTION_FUNCTION(AActor, A_BspiAttack)
{
PARAM_ACTION_PROLOGUE;
if (!self->target)
return 0;
A_FaceTarget (self);
// launch a missile
P_SpawnMissile (self, self->target, PClass::FindActor("ArachnotronPlasma"));
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_BabyMetal)
{
PARAM_ACTION_PROLOGUE;
S_Sound (self, CHAN_BODY, "baby/walk", 1, ATTN_IDLE);
A_Chase (stack, self);
return 0;
}

View file

@ -1,160 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "p_local.h"
#include "s_sound.h"
#include "p_enemy.h"
#include "gstrings.h"
#include "a_action.h"
#include "thingdef/thingdef.h"
*/
//
// PIT_VileCheck
// Detect a corpse that could be raised.
//
void A_Fire(AActor *self, double height);
//
// A_VileStart
//
DEFINE_ACTION_FUNCTION(AActor, A_VileStart)
{
PARAM_ACTION_PROLOGUE;
S_Sound (self, CHAN_VOICE, "vile/start", 1, ATTN_NORM);
return 0;
}
//
// A_Fire
// Keep fire in front of player unless out of sight
//
DEFINE_ACTION_FUNCTION(AActor, A_StartFire)
{
PARAM_ACTION_PROLOGUE;
S_Sound (self, CHAN_BODY, "vile/firestrt", 1, ATTN_NORM);
A_Fire (self, 0);
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_FireCrackle)
{
PARAM_ACTION_PROLOGUE;
S_Sound (self, CHAN_BODY, "vile/firecrkl", 1, ATTN_NORM);
A_Fire (self, 0);
return 0;
}
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Fire)
{
PARAM_ACTION_PROLOGUE;
PARAM_FLOAT_OPT(height) { height = 0; }
A_Fire(self, height);
return 0;
}
void A_Fire(AActor *self, double height)
{
AActor *dest;
dest = self->tracer;
if (dest == NULL || self->target == NULL)
return;
// don't move it if the vile lost sight
if (!P_CheckSight (self->target, dest, 0) )
return;
DVector3 newpos = dest->Vec3Angle(24., dest->Angles.Yaw, height);
self->SetOrigin(newpos, true);
}
//
// A_VileTarget
// Spawn the hellfire
//
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileTarget)
{
PARAM_ACTION_PROLOGUE;
PARAM_CLASS_OPT(fire, AActor) { fire = PClass::FindActor("ArchvileFire"); }
AActor *fog;
if (!self->target)
return 0;
A_FaceTarget (self);
fog = Spawn (fire, self->target->Pos(), ALLOW_REPLACE);
self->tracer = fog;
fog->target = self;
fog->tracer = self->target;
A_Fire(fog, 0);
return 0;
}
//
// A_VileAttack
//
// A_VileAttack flags
#define VAF_DMGTYPEAPPLYTODIRECT 1
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileAttack)
{
PARAM_ACTION_PROLOGUE;
PARAM_SOUND_OPT (snd) { snd = "vile/stop"; }
PARAM_INT_OPT (dmg) { dmg = 20; }
PARAM_INT_OPT (blastdmg) { blastdmg = 70; }
PARAM_INT_OPT (blastrad) { blastrad = 70; }
PARAM_FLOAT_OPT (thrust) { thrust = 1; }
PARAM_NAME_OPT (dmgtype) { dmgtype = NAME_Fire; }
PARAM_INT_OPT (flags) { flags = 0; }
AActor *fire, *target;
if (NULL == (target = self->target))
return 0;
A_FaceTarget (self);
if (!P_CheckSight (self, target, 0) )
return 0;
S_Sound (self, CHAN_WEAPON, snd, 1, ATTN_NORM);
int newdam;
if (flags & VAF_DMGTYPEAPPLYTODIRECT)
newdam = P_DamageMobj (target, self, self, dmg, dmgtype);
else
newdam = P_DamageMobj (target, self, self, dmg, NAME_None);
P_TraceBleed (newdam > 0 ? newdam : dmg, target);
fire = self->tracer;
if (fire != NULL)
{
// move the fire between the vile and the player
DVector3 pos = target->Vec3Angle(-24., self->Angles.Yaw, 0);
fire->SetOrigin (pos, true);
P_RadiusAttack (fire, self, blastdmg, blastrad, dmgtype, 0);
}
if (!(target->flags7 & MF7_DONTTHRUST))
{
target->Vel.Z = thrust * 1000 / MAX(1, target->Mass);
}
return 0;
}

View file

@ -1,325 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "m_random.h"
#include "p_local.h"
#include "p_enemy.h"
#include "s_sound.h"
#include "statnums.h"
#include "a_specialspot.h"
#include "thingdef/thingdef.h"
#include "doomstat.h"
#include "g_level.h"
*/
static FRandom pr_brainscream ("BrainScream");
static FRandom pr_brainexplode ("BrainExplode");
static FRandom pr_spawnfly ("SpawnFly");
DEFINE_ACTION_FUNCTION(AActor, A_BrainAwake)
{
PARAM_ACTION_PROLOGUE;
// killough 3/26/98: only generates sound now
S_Sound (self, CHAN_VOICE, "brain/sight", 1, ATTN_NONE);
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_BrainPain)
{
PARAM_ACTION_PROLOGUE;
S_Sound (self, CHAN_VOICE, "brain/pain", 1, ATTN_NONE);
return 0;
}
static void BrainishExplosion (const DVector3 &pos)
{
AActor *boom = Spawn("Rocket", pos, NO_REPLACE);
if (boom != NULL)
{
boom->DeathSound = "misc/brainexplode";
boom->Vel.Z = pr_brainscream() /128.;
PClassActor *cls = PClass::FindActor("BossBrain");
if (cls != NULL)
{
FState *state = cls->FindState(NAME_Brainexplode);
if (state != NULL)
boom->SetState (state);
}
boom->effects = 0;
boom->SetDamage(0); // disables collision detection which is not wanted here
boom->tics -= pr_brainscream() & 7;
if (boom->tics < 1)
boom->tics = 1;
}
}
DEFINE_ACTION_FUNCTION(AActor, A_BrainScream)
{
PARAM_ACTION_PROLOGUE;
for (double x = -196; x < +320; x += 8)
{
// (1 / 512.) is actually what the original value of 128 did, even though it probably meant 128 map units.
BrainishExplosion(self->Vec2OffsetZ(x, -320, (1 / 512.) + pr_brainexplode() * 2));
}
S_Sound (self, CHAN_VOICE, "brain/death", 1, ATTN_NONE);
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_BrainExplode)
{
PARAM_ACTION_PROLOGUE;
double x = pr_brainexplode.Random2() / 32.;
DVector3 pos = self->Vec2OffsetZ(x, 0, 1 / 512. + pr_brainexplode() * 2);
BrainishExplosion(pos);
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_BrainDie)
{
PARAM_ACTION_PROLOGUE;
// [RH] If noexit, then don't end the level.
if ((deathmatch || alwaysapplydmflags) && (dmflags & DF_NO_EXIT))
return 0;
// New dmflag: Kill all boss spawned monsters before ending the level.
if (dmflags2 & DF2_KILLBOSSMONST)
{
int count; // Repeat until we have no more boss-spawned monsters.
do // (e.g. Pain Elementals can spawn more to kill upon death.)
{
TThinkerIterator<AActor> it;
AActor *mo;
count = 0;
while ((mo = it.Next()))
{
if (mo->health > 0 && mo->flags4 & MF4_BOSSSPAWNED)
{
P_DamageMobj(mo, self, self, mo->health, NAME_None,
DMG_NO_ARMOR|DMG_FORCED|DMG_THRUSTLESS|DMG_NO_FACTOR);
count++;
}
}
} while (count != 0);
}
G_ExitLevel (0, false);
return 0;
}
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BrainSpit)
{
PARAM_ACTION_PROLOGUE;
PARAM_CLASS_OPT(spawntype, AActor) { spawntype = NULL; }
DSpotState *state = DSpotState::GetSpotState();
AActor *targ;
AActor *spit;
bool isdefault = false;
// shoot a cube at current target
targ = state->GetNextInList(PClass::FindActor("BossTarget"), G_SkillProperty(SKILLP_EasyBossBrain));
if (targ != NULL)
{
if (spawntype == NULL)
{
spawntype = PClass::FindActor("SpawnShot");
isdefault = true;
}
// spawn brain missile
spit = P_SpawnMissile (self, targ, spawntype);
if (spit != NULL)
{
// Boss cubes should move freely to their destination so it's
// probably best to disable all collision detection for them.
if (spit->flags & MF_NOCLIP) spit->flags5 |= MF5_NOINTERACTION;
spit->target = targ;
spit->master = self;
// [RH] Do this correctly for any trajectory. Doom would divide by 0
// if the target had the same y coordinate as the spitter.
if (spit->Vel.X == 0 && spit->Vel.Y == 0)
{
spit->special2 = 0;
}
else if (fabs(spit->Vel.Y) > fabs(spit->Vel.X))
{
spit->special2 = int((targ->Y() - self->Y()) / spit->Vel.Y);
}
else
{
spit->special2 = int((targ->X() - self->X()) / spit->Vel.X);
}
// [GZ] Calculates when the projectile will have reached destination
spit->special2 += level.maptime;
spit->flags6 |= MF6_BOSSCUBE;
}
if (!isdefault)
{
S_Sound(self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NONE);
}
else
{
// compatibility fallback
S_Sound (self, CHAN_WEAPON, "brain/spit", 1, ATTN_NONE);
}
}
return 0;
}
static void SpawnFly(AActor *self, PClassActor *spawntype, FSoundID sound)
{
AActor *newmobj;
AActor *fog;
AActor *eye = self->master; // The eye is the spawnshot's master, not the target!
AActor *targ = self->target; // Unlike other projectiles, the target is the intended destination.
int r;
// [GZ] Should be more viable than a countdown...
if (self->special2 != 0)
{
if (self->special2 > level.maptime)
return; // still flying
}
else
{
if (self->reactiontime == 0 || --self->reactiontime != 0)
return; // still flying
}
if (spawntype != NULL)
{
fog = Spawn (spawntype, targ->Pos(), ALLOW_REPLACE);
if (fog != NULL) S_Sound (fog, CHAN_BODY, sound, 1, ATTN_NORM);
}
FName SpawnName;
DDropItem *di; // di will be our drop item list iterator
DDropItem *drop; // while drop stays as the reference point.
int n = 0;
// First see if this cube has its own actor list
drop = self->GetDropItems();
// If not, then default back to its master's list
if (drop == NULL && eye != NULL)
drop = eye->GetDropItems();
if (drop != NULL)
{
for (di = drop; di != NULL; di = di->Next)
{
if (di->Name != NAME_None)
{
if (di->Amount < 0)
{
di->Amount = 1; // default value is -1, we need a positive value.
}
n += di->Amount; // this is how we can weight the list.
}
}
di = drop;
n = pr_spawnfly(n);
while (n >= 0)
{
if (di->Name != NAME_None)
{
n -= di->Amount; // logically, none of the -1 values have survived by now.
}
if ((di->Next != NULL) && (n >= 0))
{
di = di->Next;
}
else
{
n = -1;
}
}
SpawnName = di->Name;
}
if (SpawnName == NAME_None)
{
// Randomly select monster to spawn.
r = pr_spawnfly ();
// Probability distribution (kind of :),
// decreasing likelihood.
if (r < 50) SpawnName = "DoomImp";
else if (r < 90) SpawnName = "Demon";
else if (r < 120) SpawnName = "Spectre";
else if (r < 130) SpawnName = "PainElemental";
else if (r < 160) SpawnName = "Cacodemon";
else if (r < 162) SpawnName = "Archvile";
else if (r < 172) SpawnName = "Revenant";
else if (r < 192) SpawnName = "Arachnotron";
else if (r < 222) SpawnName = "Fatso";
else if (r < 246) SpawnName = "HellKnight";
else SpawnName = "BaronOfHell";
}
spawntype = PClass::FindActor(SpawnName);
if (spawntype != NULL)
{
newmobj = Spawn (spawntype, targ->Pos(), ALLOW_REPLACE);
if (newmobj != NULL)
{
// Make the new monster hate what the boss eye hates
if (eye != NULL)
{
newmobj->CopyFriendliness (eye, false);
}
// Make it act as if it was around when the player first made noise
// (if the player has made noise).
newmobj->LastHeard = newmobj->Sector->SoundTarget;
if (newmobj->SeeState != NULL && P_LookForPlayers (newmobj, true, NULL))
{
newmobj->SetState (newmobj->SeeState);
}
if (!(newmobj->ObjectFlags & OF_EuthanizeMe))
{
// telefrag anything in this spot
P_TeleportMove (newmobj, newmobj->Pos(), true);
}
newmobj->flags4 |= MF4_BOSSSPAWNED;
}
}
// remove self (i.e., cube).
self->Destroy ();
}
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnFly)
{
PARAM_ACTION_PROLOGUE;
PARAM_CLASS_OPT (spawntype, AActor) { spawntype = NULL; }
FSoundID sound;
if (spawntype != NULL)
{
sound = GetDefaultByType(spawntype)->SeeSound;
}
else
{
spawntype = PClass::FindActor("SpawnFire");
sound = "brain/spawn";
}
SpawnFly(self, spawntype, sound);
return 0;
}
// travelling cube sound
DEFINE_ACTION_FUNCTION(AActor, A_SpawnSound)
{
PARAM_ACTION_PROLOGUE;
S_Sound (self, CHAN_BODY, "brain/cube", 1, ATTN_IDLE);
SpawnFly(self, PClass::FindActor("SpawnFire"), "brain/spawn");
return 0;
}

View file

@ -1,23 +0,0 @@
static FRandom pr_bruisattack ("BruisAttack");
DEFINE_ACTION_FUNCTION(AActor, A_BruisAttack)
{
PARAM_ACTION_PROLOGUE;
if (!self->target)
return 0;
if (self->CheckMeleeRange ())
{
int damage = (pr_bruisattack()%8+1)*10;
S_Sound (self, CHAN_WEAPON, "baron/melee", 1, ATTN_NORM);
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
return 0;
}
// launch a missile
P_SpawnMissile (self, self->target, PClass::FindActor("BaronBall"));
return 0;
}

View file

@ -1,35 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "m_random.h"
#include "p_local.h"
#include "p_enemy.h"
#include "gstrings.h"
#include "a_action.h"
#include "s_sound.h"
#include "thingdef/thingdef.h"
*/
static FRandom pr_headattack ("HeadAttack");
DEFINE_ACTION_FUNCTION(AActor, A_HeadAttack)
{
PARAM_ACTION_PROLOGUE;
if (!self->target)
return 0;
A_FaceTarget (self);
if (self->CheckMeleeRange ())
{
int damage = (pr_headattack()%6+1)*10;
S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM);
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
return 0;
}
// launch a missile
P_SpawnMissile (self, self->target, PClass::FindActor("CacodemonBall"));
return 0;
}

View file

@ -1,29 +0,0 @@
/*
#include "actor.h"
#include "p_local.h"
#include "s_sound.h"
#include "p_enemy.h"
#include "a_action.h"
#include "thingdef/thingdef.h"
*/
DEFINE_ACTION_FUNCTION(AActor, A_CyberAttack)
{
PARAM_ACTION_PROLOGUE;
if (!self->target)
return 0;
A_FaceTarget (self);
P_SpawnMissile (self, self->target, PClass::FindActor("Rocket"));
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_Hoof)
{
PARAM_ACTION_PROLOGUE;
S_Sound (self, CHAN_BODY, "cyber/hoof", 1, ATTN_IDLE);
A_Chase (stack, self);
return 0;
}

View file

@ -1,29 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "m_random.h"
#include "p_local.h"
#include "p_enemy.h"
#include "gstrings.h"
#include "a_action.h"
#include "thingdef/thingdef.h"
*/
static FRandom pr_sargattack ("SargAttack");
DEFINE_ACTION_FUNCTION(AActor, A_SargAttack)
{
PARAM_ACTION_PROLOGUE;
if (!self->target)
return 0;
A_FaceTarget (self);
if (self->CheckMeleeRange ())
{
int damage = ((pr_sargattack()%10)+1)*4;
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
}
return 0;
}

View file

@ -1,43 +0,0 @@
#ifndef __A_DOOMGLOBAL_H__
#define __A_DOOMGLOBAL_H__
#include "info.h"
class AScriptedMarine : public AActor
{
DECLARE_CLASS (AScriptedMarine, AActor)
public:
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
};
void Activate (AActor *activator);
void Deactivate (AActor *activator);
void BeginPlay ();
void Tick ();
void SetWeapon (EMarineWeapon);
void SetSprite (PClassActor *source);
void Serialize(FSerializer &arc);
int CurrentWeapon;
protected:
bool GetWeaponStates(int weap, FState *&melee, FState *&missile);
int SpriteOverride;
};
#endif //__A_DOOMGLOBAL_H__

View file

@ -1,38 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "m_random.h"
#include "s_sound.h"
#include "p_local.h"
#include "p_enemy.h"
#include "gstrings.h"
#include "a_action.h"
#include "thingdef/thingdef.h"
*/
static FRandom pr_troopattack ("TroopAttack");
//
// A_TroopAttack
//
DEFINE_ACTION_FUNCTION(AActor, A_TroopAttack)
{
PARAM_ACTION_PROLOGUE;
if (!self->target)
return 0;
A_FaceTarget (self);
if (self->CheckMeleeRange ())
{
int damage = (pr_troopattack()%8+1)*3;
S_Sound (self, CHAN_WEAPON, "imp/melee", 1, ATTN_NORM);
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
return 0;
}
// launch a missile
P_SpawnMissile (self, self->target, PClass::FindActor("DoomImpBall"));
return 0;
}

View file

@ -1,59 +0,0 @@
#include "actor.h"
#include "info.h"
#include "p_local.h"
#include "p_spec.h"
#include "a_sharedglobal.h"
#include "m_random.h"
#include "gi.h"
#include "doomstat.h"
#include "gstrings.h"
#include "thingdef/thingdef.h"
#include "g_level.h"
#include "p_enemy.h"
#include "a_doomglobal.h"
#include "a_specialspot.h"
#include "templates.h"
#include "m_bbox.h"
#include "portal.h"
#include "d_player.h"
#include "p_maputl.h"
#include "serializer.h"
#include "g_shared/a_pickups.h"
// Include all the other Doom stuff here to reduce compile time
#include "a_arachnotron.cpp"
#include "a_archvile.cpp"
#include "a_bossbrain.cpp"
#include "a_bruiser.cpp"
#include "a_cacodemon.cpp"
#include "a_cyberdemon.cpp"
#include "a_demon.cpp"
#include "a_doomimp.cpp"
#include "a_doomweaps.cpp"
#include "a_fatso.cpp"
#include "a_keen.cpp"
#include "a_lostsoul.cpp"
#include "a_painelemental.cpp"
#include "a_possessed.cpp"
#include "a_revenant.cpp"
#include "a_spidermaster.cpp"
#include "a_scriptedmarine.cpp"
// The barrel of green goop ------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_BarrelDestroy)
{
PARAM_ACTION_PROLOGUE;
if (dmflags2 & DF2_BARRELS_RESPAWN)
{
self->Height = self->GetDefault()->Height;
self->renderflags |= RF_INVISIBLE;
self->flags &= ~MF_SOLID;
}
else
{
self->Destroy ();
}
return 0;
}

View file

@ -1,782 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "s_sound.h"
#include "m_random.h"
#include "a_pickups.h"
#include "d_player.h"
#include "p_pspr.h"
#include "p_local.h"
#include "gstrings.h"
#include "p_effect.h"
#include "gi.h"
#include "templates.h"
#include "thingdef/thingdef.h"
#include "doomstat.h"
*/
static FRandom pr_punch ("Punch");
static FRandom pr_saw ("Saw");
static FRandom pr_fireshotgun2 ("FireSG2");
static FRandom pr_fireplasma ("FirePlasma");
static FRandom pr_firerail ("FireRail");
static FRandom pr_bfgspray ("BFGSpray");
static FRandom pr_oldbfg ("OldBFG");
//
// A_Punch
//
DEFINE_ACTION_FUNCTION(AActor, A_Punch)
{
PARAM_ACTION_PROLOGUE;
DAngle angle;
int damage;
DAngle pitch;
FTranslatedLineTarget t;
if (self->player != NULL)
{
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL && !(weapon->WeaponFlags & WIF_DEHAMMO) && ACTION_CALL_FROM_PSPRITE())
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
return 0;
}
}
damage = (pr_punch()%10+1)<<1;
if (self->FindInventory<APowerStrength>())
damage *= 10;
angle = self->Angles.Yaw + pr_punch.Random2() * (5.625 / 256);
pitch = P_AimLineAttack (self, angle, MELEERANGE);
P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, LAF_ISMELEEATTACK, &t);
// turn to face target
if (t.linetarget)
{
S_Sound (self, CHAN_WEAPON, "*fist", 1, ATTN_NORM);
self->Angles.Yaw = t.angleFromSource;
}
return 0;
}
//
// A_FirePistol
//
DEFINE_ACTION_FUNCTION(AActor, A_FirePistol)
{
PARAM_ACTION_PROLOGUE;
bool accurate;
if (self->player != nullptr)
{
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != nullptr && ACTION_CALL_FROM_PSPRITE())
{
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
return 0;
P_SetPsprite(self->player, PSP_FLASH, weapon->FindState(NAME_Flash), true);
}
self->player->mo->PlayAttacking2 ();
accurate = !self->player->refire;
}
else
{
accurate = true;
}
S_Sound (self, CHAN_WEAPON, "weapons/pistol", 1, ATTN_NORM);
P_GunShot (self, accurate, PClass::FindActor(NAME_BulletPuff), P_BulletSlope (self));
return 0;
}
//
// A_Saw
//
enum SAW_Flags
{
SF_NORANDOM = 1,
SF_RANDOMLIGHTMISS = 2,
SF_RANDOMLIGHTHIT = 4,
SF_NOUSEAMMOMISS = 8,
SF_NOUSEAMMO = 16,
SF_NOPULLIN = 32,
SF_NOTURN = 64,
SF_STEALARMOR = 128,
};
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw)
{
PARAM_ACTION_PROLOGUE;
PARAM_SOUND_OPT (fullsound) { fullsound = "weapons/sawfull"; }
PARAM_SOUND_OPT (hitsound) { hitsound = "weapons/sawhit"; }
PARAM_INT_OPT (damage) { damage = 2; }
PARAM_CLASS_OPT (pufftype, AActor) { pufftype = NULL; }
PARAM_INT_OPT (flags) { flags = 0; }
PARAM_FLOAT_OPT (range) { range = 0; }
PARAM_ANGLE_OPT (spread_xy) { spread_xy = 2.8125; }
PARAM_ANGLE_OPT (spread_z) { spread_z = 0.; }
PARAM_FLOAT_OPT (lifesteal) { lifesteal = 0; }
PARAM_INT_OPT (lifestealmax) { lifestealmax = 0; }
PARAM_CLASS_OPT (armorbonustype, ABasicArmorBonus) { armorbonustype = NULL; }
DAngle angle;
DAngle slope;
player_t *player;
FTranslatedLineTarget t;
int actualdamage;
if (NULL == (player = self->player))
{
return 0;
}
if (pufftype == NULL)
{
pufftype = PClass::FindActor(NAME_BulletPuff);
}
if (damage == 0)
{
damage = 2;
}
if (!(flags & SF_NORANDOM))
{
damage *= (pr_saw()%10+1);
}
if (range == 0)
{
range = SAWRANGE;
}
angle = self->Angles.Yaw + spread_xy * (pr_saw.Random2() / 255.);
slope = P_AimLineAttack (self, angle, range, &t) + spread_z * (pr_saw.Random2() / 255.);
AWeapon *weapon = self->player->ReadyWeapon;
if ((weapon != NULL) && !(flags & SF_NOUSEAMMO) && !(!t.linetarget && (flags & SF_NOUSEAMMOMISS)) && !(weapon->WeaponFlags & WIF_DEHAMMO) && ACTION_CALL_FROM_PSPRITE())
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
return 0;
}
P_LineAttack (self, angle, range, slope, damage, NAME_Melee, pufftype, false, &t, &actualdamage);
if (!t.linetarget)
{
if ((flags & SF_RANDOMLIGHTMISS) && (pr_saw() > 64))
{
player->extralight = !player->extralight;
}
S_Sound (self, CHAN_WEAPON, fullsound, 1, ATTN_NORM);
return 0;
}
if (flags & SF_RANDOMLIGHTHIT)
{
int randVal = pr_saw();
if (randVal < 64)
{
player->extralight = 0;
}
else if (randVal < 160)
{
player->extralight = 1;
}
else
{
player->extralight = 2;
}
}
if (lifesteal && !(t.linetarget->flags5 & MF5_DONTDRAIN))
{
if (flags & SF_STEALARMOR)
{
if (armorbonustype == NULL)
{
armorbonustype = dyn_cast<ABasicArmorBonus::MetaClass>(PClass::FindClass("ArmorBonus"));
}
if (armorbonustype != NULL)
{
assert(armorbonustype->IsDescendantOf (RUNTIME_CLASS(ABasicArmorBonus)));
ABasicArmorBonus *armorbonus = static_cast<ABasicArmorBonus *>(Spawn(armorbonustype));
armorbonus->SaveAmount = int(armorbonus->SaveAmount * actualdamage * lifesteal);
armorbonus->MaxSaveAmount = lifestealmax <= 0 ? armorbonus->MaxSaveAmount : lifestealmax;
armorbonus->flags |= MF_DROPPED;
armorbonus->ClearCounters();
if (!armorbonus->CallTryPickup (self))
{
armorbonus->Destroy ();
}
}
}
else
{
P_GiveBody (self, int(actualdamage * lifesteal), lifestealmax);
}
}
S_Sound (self, CHAN_WEAPON, hitsound, 1, ATTN_NORM);
// turn to face target
if (!(flags & SF_NOTURN))
{
DAngle anglediff = deltaangle(self->Angles.Yaw, t.angleFromSource);
if (anglediff < 0.0)
{
if (anglediff < -4.5)
self->Angles.Yaw = angle + 90.0 / 21;
else
self->Angles.Yaw -= 4.5;
}
else
{
if (anglediff > 4.5)
self->Angles.Yaw = angle - 90.0 / 21;
else
self->Angles.Yaw += 4.5;
}
}
if (!(flags & SF_NOPULLIN))
self->flags |= MF_JUSTATTACKED;
return 0;
}
//
// A_FireShotgun
//
DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun)
{
PARAM_ACTION_PROLOGUE;
int i;
player_t *player;
if (nullptr == (player = self->player))
{
return 0;
}
S_Sound (self, CHAN_WEAPON, "weapons/shotgf", 1, ATTN_NORM);
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != nullptr && ACTION_CALL_FROM_PSPRITE())
{
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
return 0;
P_SetPsprite(player, PSP_FLASH, weapon->FindState(NAME_Flash), true);
}
player->mo->PlayAttacking2 ();
DAngle pitch = P_BulletSlope (self);
for (i = 0; i < 7; i++)
{
P_GunShot (self, false, PClass::FindActor(NAME_BulletPuff), pitch);
}
return 0;
}
//
// A_FireShotgun2
//
DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun2)
{
PARAM_ACTION_PROLOGUE;
int i;
DAngle angle;
int damage;
player_t *player;
if (nullptr == (player = self->player))
{
return 0;
}
S_Sound (self, CHAN_WEAPON, "weapons/sshotf", 1, ATTN_NORM);
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != nullptr && ACTION_CALL_FROM_PSPRITE())
{
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 2))
return 0;
P_SetPsprite(player, PSP_FLASH, weapon->FindState(NAME_Flash), true);
}
player->mo->PlayAttacking2 ();
DAngle pitch = P_BulletSlope (self);
for (i=0 ; i<20 ; i++)
{
damage = 5*(pr_fireshotgun2()%3+1);
angle = self->Angles.Yaw + pr_fireshotgun2.Random2() * (11.25 / 256);
// Doom adjusts the bullet slope by shifting a random number [-255,255]
// left 5 places. At 2048 units away, this means the vertical position
// of the shot can deviate as much as 255 units from nominal. So using
// some simple trigonometry, that means the vertical angle of the shot
// can deviate by as many as ~7.097 degrees or ~84676099 BAMs.
P_LineAttack (self,
angle,
PLAYERMISSILERANGE,
pitch + pr_fireshotgun2.Random2() * (7.097 / 256), damage,
NAME_Hitscan, NAME_BulletPuff);
}
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_OpenShotgun2)
{
PARAM_ACTION_PROLOGUE;
S_Sound (self, CHAN_WEAPON, "weapons/sshoto", 1, ATTN_NORM);
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_LoadShotgun2)
{
PARAM_ACTION_PROLOGUE;
S_Sound (self, CHAN_WEAPON, "weapons/sshotl", 1, ATTN_NORM);
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_CloseShotgun2)
{
PARAM_ACTION_PROLOGUE;
S_Sound (self, CHAN_WEAPON, "weapons/sshotc", 1, ATTN_NORM);
A_ReFire (self);
return 0;
}
//------------------------------------------------------------------------------------
//
// Setting a random flash like some of Doom's weapons can easily crash when the
// definition is overridden incorrectly so let's check that the state actually exists.
// Be aware though that this will not catch all DEHACKED related problems. But it will
// find all DECORATE related ones.
//
//------------------------------------------------------------------------------------
void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int index)
{
PClassActor *cls = weapon->GetClass();
while (cls != RUNTIME_CLASS(AWeapon))
{
if (flashstate >= cls->OwnedStates && flashstate < cls->OwnedStates + cls->NumOwnedStates)
{
// The flash state belongs to this class.
// Now let's check if the actually wanted state does also
if (flashstate + index < cls->OwnedStates + cls->NumOwnedStates)
{
// we're ok so set the state
P_SetPsprite(player, PSP_FLASH, flashstate + index, true);
return;
}
else
{
// oh, no! The state is beyond the end of the state table so use the original flash state.
P_SetPsprite(player, PSP_FLASH, flashstate, true);
return;
}
}
// try again with parent class
cls = static_cast<PClassActor *>(cls->ParentClass);
}
// if we get here the state doesn't seem to belong to any class in the inheritance chain
// This can happen with Dehacked if the flash states are remapped.
// The only way to check this would be to go through all Dehacked modifiable actors, convert
// their states into a single flat array and find the correct one.
// Rather than that, just check to make sure it belongs to something.
if (FState::StaticFindStateOwner(flashstate + index) == NULL)
{ // Invalid state. With no index offset, it should at least be valid.
index = 0;
}
P_SetPsprite(player, PSP_FLASH, flashstate + index, true);
}
//
// A_FireCGun
//
DEFINE_ACTION_FUNCTION(AActor, A_FireCGun)
{
PARAM_ACTION_PROLOGUE;
player_t *player;
if (self == nullptr || nullptr == (player = self->player))
{
return 0;
}
AWeapon *weapon = player->ReadyWeapon;
if (weapon != nullptr && ACTION_CALL_FROM_PSPRITE())
{
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
return 0;
S_Sound (self, CHAN_WEAPON, "weapons/chngun", 1, ATTN_NORM);
FState *flash = weapon->FindState(NAME_Flash);
if (flash != nullptr)
{
// [RH] Fix for Sparky's messed-up Dehacked patch! Blargh!
FState * atk = weapon->FindState(NAME_Fire);
int theflash = clamp (int(player->GetPSprite(PSP_WEAPON)->GetState() - atk), 0, 1);
if (flash[theflash].sprite != flash->sprite)
{
theflash = 0;
}
P_SetSafeFlash (weapon, player, flash, theflash);
}
}
player->mo->PlayAttacking2 ();
P_GunShot (self, !player->refire, PClass::FindActor(NAME_BulletPuff), P_BulletSlope (self));
return 0;
}
//
// A_FireMissile
//
DEFINE_ACTION_FUNCTION(AActor, A_FireMissile)
{
PARAM_ACTION_PROLOGUE;
player_t *player;
if (NULL == (player = self->player))
{
return 0;
}
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL && ACTION_CALL_FROM_PSPRITE())
{
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
return 0;
}
P_SpawnPlayerMissile (self, PClass::FindActor("Rocket"));
return 0;
}
//
// A_FireSTGrenade: not exactly backported from ST, but should work the same
//
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireSTGrenade)
{
PARAM_ACTION_PROLOGUE;
PARAM_CLASS_OPT(grenade, AActor) { grenade = PClass::FindActor("Grenade"); }
player_t *player;
if (grenade == NULL)
return 0;
if (NULL == (player = self->player))
{
return 0;
}
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL && ACTION_CALL_FROM_PSPRITE())
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
return 0;
}
// Temporarily raise the pitch to send the grenade slightly upwards
DAngle SavedPlayerPitch = self->Angles.Pitch;
self->Angles.Pitch -= 6.328125; //(1152 << F RACBITS);
P_SpawnPlayerMissile(self, grenade);
self->Angles.Pitch = SavedPlayerPitch;
return 0;
}
//
// A_FirePlasma
//
DEFINE_ACTION_FUNCTION(AActor, A_FirePlasma)
{
PARAM_ACTION_PROLOGUE;
player_t *player;
if (NULL == (player = self->player))
{
return 0;
}
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL && ACTION_CALL_FROM_PSPRITE())
{
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
return 0;
FState *flash = weapon->FindState(NAME_Flash);
if (flash != NULL)
{
P_SetSafeFlash(weapon, player, flash, (pr_fireplasma()&1));
}
}
P_SpawnPlayerMissile (self, PClass::FindActor("PlasmaBall"));
return 0;
}
//
// [RH] A_FireRailgun
//
static void FireRailgun(AActor *self, int offset_xy, bool fromweapon)
{
int damage;
player_t *player;
if (NULL == (player = self->player))
{
return;
}
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL && fromweapon)
{
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
return;
FState *flash = weapon->FindState(NAME_Flash);
if (flash != NULL)
{
P_SetSafeFlash(weapon, player, flash, (pr_firerail()&1));
}
}
damage = deathmatch ? 100 : 150;
FRailParams p;
p.source = self;
p.damage = damage;
p.offset_xy = offset_xy;
P_RailAttack (&p);
}
DEFINE_ACTION_FUNCTION(AActor, A_FireRailgun)
{
PARAM_ACTION_PROLOGUE;
FireRailgun(self, 0, ACTION_CALL_FROM_PSPRITE());
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_FireRailgunRight)
{
PARAM_ACTION_PROLOGUE;
FireRailgun(self, 10, ACTION_CALL_FROM_PSPRITE());
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_FireRailgunLeft)
{
PARAM_ACTION_PROLOGUE;
FireRailgun(self, -10, ACTION_CALL_FROM_PSPRITE());
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_RailWait)
{
// Okay, this was stupid. Just use a NULL function instead of this.
return 0;
}
//
// A_FireBFG
//
DEFINE_ACTION_FUNCTION(AActor, A_FireBFG)
{
PARAM_ACTION_PROLOGUE;
player_t *player;
if (NULL == (player = self->player))
{
return 0;
}
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL && ACTION_CALL_FROM_PSPRITE())
{
if (!weapon->DepleteAmmo (weapon->bAltFire, true, deh.BFGCells))
return 0;
}
P_SpawnPlayerMissile (self, 0, 0, 0, PClass::FindActor("BFGBall"), self->Angles.Yaw, NULL, NULL, !!(dmflags2 & DF2_NO_FREEAIMBFG));
return 0;
}
//
// A_BFGSpray
// Spawn a BFG explosion on every monster in view
//
enum BFG_Flags
{
BFGF_HURTSOURCE = 1,
BFGF_MISSILEORIGIN = 2,
};
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray)
{
PARAM_ACTION_PROLOGUE;
PARAM_CLASS_OPT (spraytype, AActor) { spraytype = NULL; }
PARAM_INT_OPT (numrays) { numrays = 0; }
PARAM_INT_OPT (damagecnt) { damagecnt = 0; }
PARAM_ANGLE_OPT (angle) { angle = 0.; }
PARAM_FLOAT_OPT (distance) { distance = 0; }
PARAM_ANGLE_OPT (vrange) { vrange = 0.; }
PARAM_INT_OPT (defdamage) { defdamage = 0; }
PARAM_INT_OPT (flags) { flags = 0; }
int i;
int j;
int damage;
DAngle an;
FTranslatedLineTarget t;
AActor *originator;
if (spraytype == NULL) spraytype = PClass::FindActor("BFGExtra");
if (numrays <= 0) numrays = 40;
if (damagecnt <= 0) damagecnt = 15;
if (angle == 0) angle = 90.;
if (distance <= 0) distance = 16 * 64;
if (vrange == 0) vrange = 32.;
// [RH] Don't crash if no target
if (!self->target)
return 0;
// [XA] Set the originator of the rays to the projectile (self) if
// the new flag is set, else set it to the player (self->target)
originator = (flags & BFGF_MISSILEORIGIN) ? self : (AActor *)(self->target);
// offset angles from its attack angle
for (i = 0; i < numrays; i++)
{
an = self->Angles.Yaw - angle / 2 + angle / numrays*i;
P_AimLineAttack(originator, an, distance, &t, vrange);
if (t.linetarget != NULL)
{
AActor *spray = Spawn(spraytype, t.linetarget->PosPlusZ(t.linetarget->Height / 4), ALLOW_REPLACE);
int dmgFlags = 0;
FName dmgType = NAME_BFGSplash;
if (spray != NULL)
{
if ((spray->flags6 & MF6_MTHRUSPECIES && self->target->GetSpecies() == t.linetarget->GetSpecies()) ||
(!(flags & BFGF_HURTSOURCE) && self->target == t.linetarget)) // [XA] Don't hit oneself unless we say so.
{
spray->Destroy(); // [MC] Remove it because technically, the spray isn't trying to "hit" them.
continue;
}
if (spray->flags5 & MF5_PUFFGETSOWNER) spray->target = self->target;
if (spray->flags3 & MF3_FOILINVUL) dmgFlags |= DMG_FOILINVUL;
if (spray->flags7 & MF7_FOILBUDDHA) dmgFlags |= DMG_FOILBUDDHA;
dmgType = spray->DamageType;
}
if (defdamage == 0)
{
damage = 0;
for (j = 0; j < damagecnt; ++j)
damage += (pr_bfgspray() & 7) + 1;
}
else
{
// if this is used, damagecnt will be ignored
damage = defdamage;
}
int newdam = P_DamageMobj(t.linetarget, originator, self->target, damage, dmgType, dmgFlags|DMG_USEANGLE, t.angleFromSource.Degrees);
P_TraceBleed(newdam > 0 ? newdam : damage, &t, self);
}
}
return 0;
}
//
// A_BFGsound
//
DEFINE_ACTION_FUNCTION(AActor, A_BFGsound)
{
PARAM_ACTION_PROLOGUE;
S_Sound (self, CHAN_WEAPON, "weapons/bfgf", 1, ATTN_NORM);
return 0;
}
//
// A_FireOldBFG
//
// This function emulates Doom's Pre-Beta BFG
// By Lee Killough 6/6/98, 7/11/98, 7/19/98, 8/20/98
//
// This code may not be used in other mods without appropriate credit given.
// Code leeches will be telefragged.
DEFINE_ACTION_FUNCTION(AActor, A_FireOldBFG)
{
PARAM_ACTION_PROLOGUE;
PClassActor *plasma[] = { PClass::FindActor("PlasmaBall1"), PClass::FindActor("PlasmaBall2") };
AActor * mo = NULL;
player_t *player;
bool doesautoaim = false;
if (NULL == (player = self->player))
{
return 0;
}
AWeapon *weapon = self->player->ReadyWeapon;
if (!ACTION_CALL_FROM_PSPRITE()) weapon = NULL;
if (weapon != NULL)
{
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
return 0;
doesautoaim = !(weapon->WeaponFlags & WIF_NOAUTOAIM);
weapon->WeaponFlags |= WIF_NOAUTOAIM; // No autoaiming that gun
}
self->player->extralight = 2;
// Save values temporarily
DAngle SavedPlayerAngle = self->Angles.Yaw;
DAngle SavedPlayerPitch = self->Angles.Pitch;
for (int i = 0; i < 2; i++) // Spawn two plasma balls in sequence
{
self->Angles.Yaw += ((pr_oldbfg()&127) - 64) * (90./768);
self->Angles.Pitch += ((pr_oldbfg()&127) - 64) * (90./640);
mo = P_SpawnPlayerMissile (self, plasma[i]);
// Restore saved values
self->Angles.Yaw = SavedPlayerAngle;
self->Angles.Pitch = SavedPlayerPitch;
}
if (doesautoaim && weapon != NULL)
{ // Restore autoaim setting
weapon->WeaponFlags &= ~WIF_NOAUTOAIM;
}
return 0;
}

View file

@ -1,177 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "m_random.h"
#include "s_sound.h"
#include "p_local.h"
#include "p_enemy.h"
#include "gstrings.h"
#include "a_action.h"
#include "thingdef/thingdef.h"
*/
//
// Mancubus attack,
// firing three missiles in three different directions?
// Doesn't look like it.
//
#define FATSPREAD (90./8)
DEFINE_ACTION_FUNCTION(AActor, A_FatRaise)
{
PARAM_ACTION_PROLOGUE;
A_FaceTarget (self);
S_Sound (self, CHAN_WEAPON, "fatso/raiseguns", 1, ATTN_NORM);
return 0;
}
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FatAttack1)
{
PARAM_ACTION_PROLOGUE;
PARAM_CLASS_OPT(spawntype, AActor) { spawntype = NULL; }
AActor *missile;
if (!self->target)
return 0;
if (spawntype == NULL) spawntype = PClass::FindActor("FatShot");
A_FaceTarget (self);
// Change direction to ...
self->Angles.Yaw += FATSPREAD;
P_SpawnMissile (self, self->target, spawntype);
missile = P_SpawnMissile (self, self->target, spawntype);
if (missile != NULL)
{
missile->Angles.Yaw += FATSPREAD;
missile->VelFromAngle();
}
return 0;
}
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FatAttack2)
{
PARAM_ACTION_PROLOGUE;
PARAM_CLASS_OPT(spawntype, AActor) { spawntype = NULL; }
AActor *missile;
if (!self->target)
return 0;
if (spawntype == NULL) spawntype = PClass::FindActor("FatShot");
A_FaceTarget (self);
// Now here choose opposite deviation.
self->Angles.Yaw -= FATSPREAD;
P_SpawnMissile (self, self->target, spawntype);
missile = P_SpawnMissile (self, self->target, spawntype);
if (missile != NULL)
{
missile->Angles.Yaw -= FATSPREAD*2;
missile->VelFromAngle();
}
return 0;
}
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FatAttack3)
{
PARAM_ACTION_PROLOGUE;
PARAM_CLASS_OPT(spawntype, AActor) { spawntype = NULL; }
AActor *missile;
if (!self->target)
return 0;
if (spawntype == NULL) spawntype = PClass::FindActor("FatShot");
A_FaceTarget (self);
missile = P_SpawnMissile (self, self->target, spawntype);
if (missile != NULL)
{
missile->Angles.Yaw -= FATSPREAD/2;
missile->VelFromAngle();
}
missile = P_SpawnMissile (self, self->target, spawntype);
if (missile != NULL)
{
missile->Angles.Yaw += FATSPREAD/2;
missile->VelFromAngle();
}
return 0;
}
//
// killough 9/98: a mushroom explosion effect, sorta :)
// Original idea: Linguica
//
enum
{
MSF_Standard = 0,
MSF_Classic = 1,
MSF_DontHurt = 2,
};
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Mushroom)
{
PARAM_ACTION_PROLOGUE;
PARAM_CLASS_OPT (spawntype, AActor) { spawntype = NULL; }
PARAM_INT_OPT (n) { n = 0; }
PARAM_INT_OPT (flags) { flags = 0; }
PARAM_FLOAT_OPT (vrange) { vrange = 4; }
PARAM_FLOAT_OPT (hrange) { hrange = 0.5; }
int i, j;
if (n == 0)
{
n = self->GetMissileDamage(0, 1);
}
if (spawntype == NULL)
{
spawntype = PClass::FindActor("FatShot");
}
P_RadiusAttack (self, self->target, 128, 128, self->DamageType, (flags & MSF_DontHurt) ? 0 : RADF_HURTSOURCE);
P_CheckSplash(self, 128.);
// Now launch mushroom cloud
AActor *target = Spawn("Mapspot", self->Pos(), NO_REPLACE); // We need something to aim at.
AActor *master = (flags & MSF_DontHurt) ? (AActor*)(self->target) : self;
target->Height = self->Height;
for (i = -n; i <= n; i += 8)
{
for (j = -n; j <= n; j += 8)
{
AActor *mo;
target->SetXYZ(
self->X() + i, // Aim in many directions from source
self->Y() + j,
self->Z() + (P_AproxDistance(i,j) * vrange)); // Aim up fairly high
if ((flags & MSF_Classic) || // Flag explicitely set, or no flags and compat options
(flags == 0 && (self->state->DefineFlags & SDF_DEHACKED) && (i_compatflags & COMPATF_MUSHROOM)))
{ // Use old function for MBF compatibility
mo = P_OldSpawnMissile (self, master, target, spawntype);
}
else // Use normal function
{
mo = P_SpawnMissile(self, target, spawntype, master);
}
if (mo != NULL)
{ // Slow it down a bit
mo->Vel *= hrange;
mo->flags &= ~MF_NOGRAVITY; // Make debris fall under gravity
}
}
}
target->Destroy();
return 0;
}

View file

@ -1,42 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "p_local.h"
#include "p_spec.h"
#include "p_enemy.h"
#include "a_action.h"
#include "thingdef/thingdef.h"
*/
//
// A_KeenDie
// DOOM II special, map 32.
// Uses special tag 666 by default.
//
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KeenDie)
{
PARAM_ACTION_PROLOGUE;
PARAM_INT_OPT(doortag) { doortag = 666; }
A_Unblock(self, false);
// scan the remaining thinkers to see if all Keens are dead
AActor *other;
TThinkerIterator<AActor> iterator;
const PClass *matchClass = self->GetClass ();
while ( (other = iterator.Next ()) )
{
if (other != self && other->health > 0 && other->IsA (matchClass))
{
// other Keen not dead
return 0;
}
}
EV_DoDoor (DDoor::doorOpen, NULL, NULL, doortag, 2., 0, 0, 0);
return 0;
}

View file

@ -1,86 +0,0 @@
/*
#include "templates.h"
#include "actor.h"
#include "info.h"
#include "m_random.h"
#include "s_sound.h"
#include "p_local.h"
#include "p_enemy.h"
#include "gi.h"
#include "gstrings.h"
#include "a_action.h"
#include "thingdef/thingdef.h"
*/
FRandom pr_oldsoul ("BetaLostSoul");
//
// SkullAttack
// Fly at the player like a missile.
//
void A_SkullAttack(AActor *self, double speed)
{
AActor *dest;
if (!self->target)
return;
dest = self->target;
self->flags |= MF_SKULLFLY;
S_Sound (self, CHAN_VOICE, self->AttackSound, 1, ATTN_NORM);
A_FaceTarget (self);
self->VelFromAngle(speed);
self->Vel.Z = (dest->Center() - self->Z()) / self->DistanceBySpeed(dest, speed);
}
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SkullAttack)
{
PARAM_ACTION_PROLOGUE;
PARAM_FLOAT_OPT(speed) { speed = SKULLSPEED; }
if (speed <= 0)
speed = SKULLSPEED;
A_SkullAttack(self, speed);
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_BetaSkullAttack)
{
PARAM_ACTION_PROLOGUE;
int damage;
if (!self || !self->target || self->target->GetSpecies() == self->GetSpecies())
return 0;
S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM);
A_FaceTarget(self);
damage = (pr_oldsoul()%8+1)*self->GetMissileDamage(0,1);
P_DamageMobj(self->target, self, self, damage, NAME_None);
return 0;
}
//==========================================================================
//
// CVAR transsouls
//
// How translucent things drawn with STYLE_SoulTrans are. Normally, only
// Lost Souls have this render style, but a dehacked patch could give other
// things this style. Values less than 0.25 will automatically be set to
// 0.25 to ensure some degree of visibility. Likewise, values above 1.0 will
// be set to 1.0, because anything higher doesn't make sense.
//
//==========================================================================
CUSTOM_CVAR (Float, transsouls, 0.75f, CVAR_ARCHIVE)
{
if (self < 0.25f)
{
self = 0.25f;
}
else if (self > 1.f)
{
self = 1.f;
}
}

View file

@ -1,194 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "p_enemy.h"
#include "p_local.h"
#include "a_action.h"
#include "templates.h"
#include "m_bbox.h"
#include "thingdef/thingdef.h"
#include "doomstat.h"
*/
enum PA_Flags
{
PAF_NOSKULLATTACK = 1,
PAF_AIMFACING = 2,
PAF_NOTARGET = 4,
};
//
// A_PainShootSkull
// Spawn a lost soul and launch it at the target
//
void A_PainShootSkull (AActor *self, DAngle Angle, PClassActor *spawntype, int flags = 0, int limit = -1)
{
AActor *other;
double prestep;
if (spawntype == NULL) spawntype = PClass::FindActor("LostSoul");
assert(spawntype != NULL);
if (self->DamageType == NAME_Massacre) return;
// [RH] check to make sure it's not too close to the ceiling
if (self->Top() + 8 > self->ceilingz)
{
if (self->flags & MF_FLOAT)
{
self->Vel.Z -= 2;
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 + (self->radius + GetDefaultByType(spawntype)->radius) * 1.5;
// NOTE: The following code contains some advance work for line-to-line portals which is currenty inactive.
DVector2 dist = Angle.ToVector(prestep);
DVector3 pos = self->Vec3Offset(dist.X, dist.Y, 8., true);
DVector3 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, ld) == 0 &&
P_PointOnLineSidePrecise(pos, 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.inRange(ld))
{
if (P_PointOnLineSidePrecise(src, ld) != P_PointOnLineSidePrecise(pos, 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.);
src.X = pos.X - dist.X;
src.Y = pos.Y - dist.Y;
}
other = Spawn (spawntype, pos, 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->Top() > other->Sector->HighestCeilingAt(other) ||
other->Z() < other->Sector->LowestFloorAt(other))
{
// kill it immediately
P_DamageMobj (other, self, self, TELEFRAG_DAMAGE, NAME_None);// ^
return; // |
} // phares
// Check for movements.
if (!P_CheckPosition (other, other->Pos()))
{
// kill it immediately
P_DamageMobj (other, self, self, TELEFRAG_DAMAGE, NAME_None);
return;
}
// [RH] Lost souls hate the same things as their pain elementals
other->CopyFriendliness (self, !(flags & PAF_NOTARGET));
if (!(flags & PAF_NOSKULLATTACK))
A_SkullAttack(other, SKULLSPEED);
}
//
// A_PainAttack
// Spawn a lost soul and launch it at the target
//
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PainAttack)
{
PARAM_ACTION_PROLOGUE;
if (!self->target)
return 0;
PARAM_CLASS_OPT (spawntype, AActor) { spawntype = NULL; }
PARAM_ANGLE_OPT (angle) { angle = 0.; }
PARAM_INT_OPT (flags) { flags = 0; }
PARAM_INT_OPT (limit) { limit = -1; }
if (!(flags & PAF_AIMFACING))
A_FaceTarget (self);
A_PainShootSkull (self, self->Angles.Yaw + angle, spawntype, flags, limit);
return 0;
}
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DualPainAttack)
{
PARAM_ACTION_PROLOGUE;
PARAM_CLASS_OPT(spawntype, AActor) { spawntype = NULL; }
if (!self->target)
return 0;
A_FaceTarget (self);
A_PainShootSkull (self, self->Angles.Yaw + 45., spawntype);
A_PainShootSkull (self, self->Angles.Yaw - 45., spawntype);
return 0;
}
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PainDie)
{
PARAM_ACTION_PROLOGUE;
PARAM_CLASS_OPT(spawntype, AActor) { spawntype = NULL; }
if (self->target != NULL && self->IsFriend(self->target))
{ // And I thought you were my friend!
self->flags &= ~MF_FRIENDLY;
}
A_Unblock(self, true);
A_PainShootSkull (self, self->Angles.Yaw + 90, spawntype);
A_PainShootSkull (self, self->Angles.Yaw + 180, spawntype);
A_PainShootSkull (self, self->Angles.Yaw + 270, spawntype);
return 0;
}

View file

@ -1,134 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "m_random.h"
#include "s_sound.h"
#include "p_local.h"
#include "p_enemy.h"
#include "gstrings.h"
#include "a_action.h"
#include "thingdef/thingdef.h"
*/
static FRandom pr_posattack ("PosAttack");
static FRandom pr_sposattack ("SPosAttack");
static FRandom pr_cposattack ("CPosAttack");
static FRandom pr_cposrefire ("CPosRefire");
//
// A_PosAttack
//
DEFINE_ACTION_FUNCTION(AActor, A_PosAttack)
{
PARAM_ACTION_PROLOGUE;
int damage;
DAngle angle;
DAngle slope;
if (!self->target)
return 0;
A_FaceTarget (self);
angle = self->Angles.Yaw;
slope = P_AimLineAttack (self, angle, MISSILERANGE);
S_Sound (self, CHAN_WEAPON, "grunt/attack", 1, ATTN_NORM);
angle += pr_posattack.Random2() * (22.5 / 256);
damage = ((pr_posattack()%5)+1)*3;
P_LineAttack (self, angle, MISSILERANGE, slope, damage, NAME_Hitscan, NAME_BulletPuff);
return 0;
}
static void A_SPosAttack2 (AActor *self)
{
int i;
DAngle bangle;
DAngle slope;
A_FaceTarget (self);
bangle = self->Angles.Yaw;
slope = P_AimLineAttack (self, bangle, MISSILERANGE);
for (i=0 ; i<3 ; i++)
{
DAngle angle = bangle + pr_sposattack.Random2() * (22.5 / 256);
int damage = ((pr_sposattack()%5)+1)*3;
P_LineAttack(self, angle, MISSILERANGE, slope, damage, NAME_Hitscan, NAME_BulletPuff);
}
}
DEFINE_ACTION_FUNCTION(AActor, A_SPosAttackUseAtkSound)
{
PARAM_ACTION_PROLOGUE;
if (!self->target)
return 0;
S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM);
A_SPosAttack2 (self);
return 0;
}
// This version of the function, which uses a hard-coded sound, is
// meant for Dehacked only.
DEFINE_ACTION_FUNCTION(AActor, A_SPosAttack)
{
PARAM_ACTION_PROLOGUE;
if (!self->target)
return 0;
S_Sound (self, CHAN_WEAPON, "shotguy/attack", 1, ATTN_NORM);
A_SPosAttack2 (self);
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_CPosAttack)
{
PARAM_ACTION_PROLOGUE;
DAngle angle;
DAngle bangle;
int damage;
DAngle slope;
if (!self->target)
return 0;
// [RH] Andy Baker's stealth monsters
if (self->flags & MF_STEALTH)
{
self->visdir = 1;
}
S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM);
A_FaceTarget (self);
bangle = self->Angles.Yaw;
slope = P_AimLineAttack (self, bangle, MISSILERANGE);
angle = bangle + pr_cposattack.Random2() * (22.5 / 256);
damage = ((pr_cposattack()%5)+1)*3;
P_LineAttack (self, angle, MISSILERANGE, slope, damage, NAME_Hitscan, NAME_BulletPuff);
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_CPosRefire)
{
PARAM_ACTION_PROLOGUE;
// keep firing unless target got out of sight
A_FaceTarget (self);
if (pr_cposrefire() < 40)
return 0;
if (!self->target
|| P_HitFriend (self)
|| self->target->health <= 0
|| !P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES))
{
self->SetState (self->SeeState);
}
return 0;
}

View file

@ -1,152 +0,0 @@
/*
#include "templates.h"
#include "actor.h"
#include "info.h"
#include "m_random.h"
#include "s_sound.h"
#include "p_local.h"
#include "p_enemy.h"
#include "gstrings.h"
#include "a_action.h"
#include "thingdef/thingdef.h"
#include "g_level.h"
*/
static FRandom pr_tracer ("Tracer");
static FRandom pr_skelfist ("SkelFist");
//
// A_SkelMissile
//
DEFINE_ACTION_FUNCTION(AActor, A_SkelMissile)
{
PARAM_ACTION_PROLOGUE;
AActor *missile;
if (!self->target)
return 0;
A_FaceTarget (self);
self->AddZ(16.);
missile = P_SpawnMissile(self, self->target, PClass::FindActor("RevenantTracer"));
self->AddZ(-16.);
if (missile != NULL)
{
missile->SetOrigin(missile->Vec3Offset(missile->Vel.X, missile->Vel.Y, 0.), false);
missile->tracer = self->target;
}
return 0;
}
#define TRACEANGLE (16.875)
DEFINE_ACTION_FUNCTION(AActor, A_Tracer)
{
PARAM_ACTION_PROLOGUE;
double dist;
double slope;
AActor *dest;
AActor *smoke;
// killough 1/18/98: this is why some missiles do not have smoke
// and some do. Also, internal demos start at random gametics, thus
// the bug in which revenants cause internal demos to go out of sync.
//
// killough 3/6/98: fix revenant internal demo bug by subtracting
// levelstarttic from gametic:
//
// [RH] level.time is always 0-based, so nothing special to do here.
if (level.time & 3)
return 0;
// spawn a puff of smoke behind the rocket
P_SpawnPuff (self, PClass::FindActor(NAME_BulletPuff), self->Pos(), self->Angles.Yaw, self->Angles.Yaw, 3);
smoke = Spawn ("RevenantTracerSmoke", self->Vec3Offset(-self->Vel.X, -self->Vel.Y, 0.), ALLOW_REPLACE);
smoke->Vel.Z = 1.;
smoke->tics -= pr_tracer()&3;
if (smoke->tics < 1)
smoke->tics = 1;
// adjust direction
dest = self->tracer;
if (!dest || dest->health <= 0 || self->Speed == 0 || !self->CanSeek(dest))
return 0;
// change angle
DAngle exact = self->AngleTo(dest);
DAngle diff = deltaangle(self->Angles.Yaw, exact);
if (diff < 0)
{
self->Angles.Yaw -= TRACEANGLE;
if (deltaangle(self->Angles.Yaw, exact) > 0)
self->Angles.Yaw = exact;
}
else if (diff > 0)
{
self->Angles.Yaw += TRACEANGLE;
if (deltaangle(self->Angles.Yaw, exact) < 0.)
self->Angles.Yaw = exact;
}
self->VelFromAngle();
if (!(self->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER)))
{
// change slope
dist = self->DistanceBySpeed(dest, self->Speed);
if (dest->Height >= 56.)
{
slope = (dest->Z() + 40. - self->Z()) / dist;
}
else
{
slope = (dest->Z() + self->Height*(2./3) - self->Z()) / dist;
}
if (slope < self->Vel.Z)
self->Vel.Z -= 1. / 8;
else
self->Vel.Z += 1. / 8;
}
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_SkelWhoosh)
{
PARAM_ACTION_PROLOGUE;
if (!self->target)
return 0;
A_FaceTarget (self);
S_Sound (self, CHAN_WEAPON, "skeleton/swing", 1, ATTN_NORM);
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_SkelFist)
{
PARAM_ACTION_PROLOGUE;
if (!self->target)
return 0;
A_FaceTarget (self);
if (self->CheckMeleeRange ())
{
int damage = ((pr_skelfist()%10)+1)*6;
S_Sound (self, CHAN_WEAPON, "skeleton/melee", 1, ATTN_NORM);
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
}
return 0;
}

View file

@ -1,654 +0,0 @@
/*
#include "actor.h"
#include "p_enemy.h"
#include "a_action.h"
#include "m_random.h"
#include "p_local.h"
#include "a_doomglobal.h"
#include "s_sound.h"
#include "r_data/r_translate.h"
#include "thingdef/thingdef.h"
#include "g_level.h"
*/
#define MARINE_PAIN_CHANCE 160
static FRandom pr_m_refire ("SMarineRefire");
static FRandom pr_m_punch ("SMarinePunch");
static FRandom pr_m_gunshot ("SMarineGunshot");
static FRandom pr_m_saw ("SMarineSaw");
static FRandom pr_m_fireshotgun2 ("SMarineFireSSG");
IMPLEMENT_CLASS (AScriptedMarine)
void AScriptedMarine::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
auto def = (AScriptedMarine*)GetDefault();
arc.Sprite("spriteoverride", SpriteOverride, &def->SpriteOverride)
("currentweapon", CurrentWeapon, def->CurrentWeapon);
}
void AScriptedMarine::Activate (AActor *activator)
{
if (flags2 & MF2_DORMANT)
{
flags2 &= ~MF2_DORMANT;
tics = 1;
}
}
void AScriptedMarine::Deactivate (AActor *activator)
{
if (!(flags2 & MF2_DORMANT))
{
flags2 |= MF2_DORMANT;
tics = -1;
}
}
bool AScriptedMarine::GetWeaponStates(int weap, FState *&melee, FState *&missile)
{
static ENamedName WeaponNames[] =
{
NAME_None,
NAME_Fist,
NAME_Berserk,
NAME_Chainsaw,
NAME_Pistol,
NAME_Shotgun,
NAME_SSG,
NAME_Chaingun,
NAME_Rocket,
NAME_Plasma,
NAME_Railgun,
NAME_BFG
};
if (weap < WEAPON_Dummy || weap > WEAPON_BFG) weap = WEAPON_Dummy;
melee = FindState(NAME_Melee, WeaponNames[weap], true);
missile = FindState(NAME_Missile, WeaponNames[weap], true);
return melee != NULL || missile != NULL;
}
void AScriptedMarine::BeginPlay ()
{
Super::BeginPlay ();
// Set the current weapon
for(int i=WEAPON_Dummy; i<=WEAPON_BFG; i++)
{
FState *melee, *missile;
if (GetWeaponStates(i, melee, missile))
{
if (melee == MeleeState && missile == MissileState)
{
CurrentWeapon = i;
}
}
}
}
void AScriptedMarine::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:
S_Sound (this, CHAN_WEAPON, "weapons/sshoto", 1, ATTN_NORM);
break;
case 28:
S_Sound (this, CHAN_WEAPON, "weapons/sshotl", 1, ATTN_NORM);
break;
case 41:
S_Sound (this, CHAN_WEAPON, "weapons/sshotc", 1, ATTN_NORM);
break;
}
}
else
{
special1 = 0;
}
}
else
{ // Wait for a long refire time
if (level.maptime >= special1)
{
special1 = 0;
}
else
{
flags |= MF_JUSTATTACKED;
}
}
}
}
//============================================================================
//
// A_M_Refire
//
//============================================================================
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Refire)
{
PARAM_ACTION_PROLOGUE;
PARAM_BOOL_OPT(ignoremissile) { ignoremissile = false; }
if (self->target == NULL || self->target->health <= 0)
{
if (self->MissileState && pr_m_refire() < 160)
{ // Look for a new target most of the time
if (P_LookForPlayers (self, true, NULL) && P_CheckMissileRange (self))
{ // Found somebody new and in range, so don't stop shooting
return 0;
}
}
self->SetState (self->state + 1);
return 0;
}
if (((ignoremissile || self->MissileState == NULL) && !self->CheckMeleeRange ()) ||
!P_CheckSight (self, self->target) ||
pr_m_refire() < 4) // Small chance of stopping even when target not dead
{
self->SetState (self->state + 1);
}
return 0;
}
//============================================================================
//
// A_M_SawRefire
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_M_SawRefire)
{
PARAM_ACTION_PROLOGUE;
if (self->target == NULL || self->target->health <= 0)
{
self->SetState (self->state + 1);
return 0;
}
if (!self->CheckMeleeRange ())
{
self->SetState (self->state + 1);
}
return 0;
}
//============================================================================
//
// A_MarineNoise
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_MarineNoise)
{
PARAM_ACTION_PROLOGUE;
if (static_cast<AScriptedMarine *>(self)->CurrentWeapon == AScriptedMarine::WEAPON_Chainsaw)
{
S_Sound (self, CHAN_WEAPON, "weapons/sawidle", 1, ATTN_NORM);
}
return 0;
}
//============================================================================
//
// A_MarineChase
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_MarineChase)
{
PARAM_ACTION_PROLOGUE;
CALL_ACTION(A_MarineNoise, self);
A_Chase (stack, self);
return 0;
}
//============================================================================
//
// A_MarineLook
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_MarineLook)
{
PARAM_ACTION_PROLOGUE;
CALL_ACTION(A_MarineNoise, self);
CALL_ACTION(A_Look, self);
return 0;
}
//============================================================================
//
// A_M_Saw
//
//============================================================================
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Saw)
{
PARAM_ACTION_PROLOGUE;
PARAM_SOUND_OPT (fullsound) { fullsound = "weapons/sawfull"; }
PARAM_SOUND_OPT (hitsound) { hitsound = "weapons/sawhit"; }
PARAM_INT_OPT (damage) { damage = 2; }
PARAM_CLASS_OPT (pufftype, AActor) { pufftype = NULL; }
if (self->target == NULL)
return 0;
if (pufftype == NULL)
{
pufftype = PClass::FindActor(NAME_BulletPuff);
}
if (damage == 0)
{
damage = 2;
}
A_FaceTarget (self);
if (self->CheckMeleeRange ())
{
DAngle angle;
FTranslatedLineTarget t;
damage *= (pr_m_saw()%10+1);
angle = self->Angles.Yaw + pr_m_saw.Random2() * (5.625 / 256);
P_LineAttack (self, angle, SAWRANGE,
P_AimLineAttack (self, angle, SAWRANGE), damage,
NAME_Melee, pufftype, false, &t);
if (!t.linetarget)
{
S_Sound (self, CHAN_WEAPON, fullsound, 1, ATTN_NORM);
return 0;
}
S_Sound (self, CHAN_WEAPON, hitsound, 1, ATTN_NORM);
// turn to face target
angle = t.angleFromSource;
DAngle anglediff = deltaangle(self->Angles.Yaw, angle);
if (anglediff < 0.0)
{
if (anglediff < -4.5)
self->Angles.Yaw = angle + 90.0 / 21;
else
self->Angles.Yaw -= 4.5;
}
else
{
if (anglediff > 4.5)
self->Angles.Yaw = angle - 90.0 / 21;
else
self->Angles.Yaw += 4.5;
}
}
else
{
S_Sound (self, CHAN_WEAPON, fullsound, 1, ATTN_NORM);
}
//A_Chase (self);
return 0;
}
//============================================================================
//
// A_M_Punch
//
//============================================================================
static void MarinePunch(AActor *self, int damagemul)
{
DAngle angle;
int damage;
DAngle pitch;
FTranslatedLineTarget t;
if (self->target == NULL)
return;
damage = ((pr_m_punch()%10+1) << 1) * damagemul;
A_FaceTarget (self);
angle = self->Angles.Yaw + pr_m_punch.Random2() * (5.625 / 256);
pitch = P_AimLineAttack (self, angle, MELEERANGE);
P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, true, &t);
// turn to face target
if (t.linetarget)
{
S_Sound (self, CHAN_WEAPON, "*fist", 1, ATTN_NORM);
self->Angles.Yaw = t.angleFromSource;
}
}
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Punch)
{
PARAM_ACTION_PROLOGUE;
PARAM_INT(mult);
MarinePunch(self, mult);
return 0;
}
//============================================================================
//
// P_GunShot2
//
//============================================================================
void P_GunShot2 (AActor *mo, bool accurate, DAngle pitch, PClassActor *pufftype)
{
DAngle angle;
int damage;
damage = 5*(pr_m_gunshot()%3+1);
angle = mo->Angles.Yaw;
if (!accurate)
{
angle += pr_m_gunshot.Random2() * (5.625 / 256);
}
P_LineAttack (mo, angle, MISSILERANGE, pitch, damage, NAME_Hitscan, pufftype);
}
//============================================================================
//
// A_M_FirePistol
//
//============================================================================
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_FirePistol)
{
PARAM_ACTION_PROLOGUE;
PARAM_BOOL(accurate);
if (self->target == NULL)
return 0;
S_Sound (self, CHAN_WEAPON, "weapons/pistol", 1, ATTN_NORM);
A_FaceTarget (self);
P_GunShot2 (self, accurate, P_AimLineAttack (self, self->Angles.Yaw, MISSILERANGE),
PClass::FindActor(NAME_BulletPuff));
return 0;
}
//============================================================================
//
// A_M_FireShotgun
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_M_FireShotgun)
{
PARAM_ACTION_PROLOGUE;
DAngle pitch;
if (self->target == NULL)
return 0;
S_Sound (self, CHAN_WEAPON, "weapons/shotgf", 1, ATTN_NORM);
A_FaceTarget (self);
pitch = P_AimLineAttack (self, self->Angles.Yaw, MISSILERANGE);
for (int i = 0; i < 7; ++i)
{
P_GunShot2 (self, false, pitch, PClass::FindActor(NAME_BulletPuff));
}
self->special1 = level.maptime + 27;
return 0;
}
//============================================================================
//
// A_M_CheckAttack
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_M_CheckAttack)
{
PARAM_ACTION_PROLOGUE;
if (self->special1 != 0 || self->target == NULL)
{
self->SetState (self->FindState("SkipAttack"));
}
else
{
A_FaceTarget (self);
}
return 0;
}
//============================================================================
//
// A_M_FireShotgun2
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_M_FireShotgun2)
{
PARAM_ACTION_PROLOGUE;
DAngle pitch;
if (self->target == NULL)
return 0;
S_Sound (self, CHAN_WEAPON, "weapons/sshotf", 1, ATTN_NORM);
A_FaceTarget (self);
pitch = P_AimLineAttack (self, self->Angles.Yaw, MISSILERANGE);
for (int i = 0; i < 20; ++i)
{
int damage = 5*(pr_m_fireshotgun2()%3+1);
DAngle angle = self->Angles.Yaw + pr_m_fireshotgun2.Random2() * (11.25 / 256);
P_LineAttack (self, angle, MISSILERANGE,
pitch + pr_m_fireshotgun2.Random2() * (7.097 / 256), damage,
NAME_Hitscan, NAME_BulletPuff);
}
self->special1 = level.maptime;
return 0;
}
//============================================================================
//
// A_M_FireCGun
//
//============================================================================
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_FireCGun)
{
PARAM_ACTION_PROLOGUE;
PARAM_BOOL(accurate);
if (self->target == NULL)
return 0;
S_Sound (self, CHAN_WEAPON, "weapons/chngun", 1, ATTN_NORM);
A_FaceTarget (self);
P_GunShot2 (self, accurate, P_AimLineAttack (self, self->Angles.Yaw, MISSILERANGE),
PClass::FindActor(NAME_BulletPuff));
return 0;
}
//============================================================================
//
// 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.
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_M_FireMissile)
{
PARAM_ACTION_PROLOGUE;
if (self->target == NULL)
return 0;
if (self->CheckMeleeRange ())
{ // If too close, punch it
MarinePunch(self, 1);
}
else
{
A_FaceTarget (self);
P_SpawnMissile (self, self->target, PClass::FindActor("Rocket"));
}
return 0;
}
//============================================================================
//
// A_M_FireRailgun
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_M_FireRailgun)
{
PARAM_ACTION_PROLOGUE;
if (self->target == NULL)
return 0;
CALL_ACTION(A_MonsterRail, self);
self->special1 = level.maptime + 50;
return 0;
}
//============================================================================
//
// A_M_FirePlasma
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_M_FirePlasma)
{
PARAM_ACTION_PROLOGUE;
if (self->target == NULL)
return 0;
A_FaceTarget (self);
P_SpawnMissile (self, self->target, PClass::FindActor("PlasmaBall"));
self->special1 = level.maptime + 20;
return 0;
}
//============================================================================
//
// A_M_BFGsound
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_M_BFGsound)
{
PARAM_ACTION_PROLOGUE;
if (self->target == NULL)
return 0;
if (self->special1 != 0)
{
self->SetState (self->SeeState);
}
else
{
A_FaceTarget (self);
S_Sound (self, CHAN_WEAPON, "weapons/bfgf", 1, ATTN_NORM);
// Don't interrupt the firing sequence
self->PainChance = 0;
}
return 0;
}
//============================================================================
//
// A_M_FireBFG
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_M_FireBFG)
{
PARAM_ACTION_PROLOGUE;
if (self->target == NULL)
return 0;
A_FaceTarget (self);
P_SpawnMissile (self, self->target, PClass::FindActor("BFGBall"));
self->special1 = level.maptime + 30;
self->PainChance = MARINE_PAIN_CHANCE;
return 0;
}
//---------------------------------------------------------------------------
void AScriptedMarine::SetWeapon (EMarineWeapon type)
{
if (GetWeaponStates(type, MeleeState, MissileState))
{
static const char *classes[] = {
"ScriptedMarine",
"MarineFist",
"MarineBerserk",
"MarineChainsaw",
"MarinePistol",
"MarineShotgun",
"MarineSSG",
"MarineChaingun",
"MarineRocket",
"MarinePlasma",
"MarineRailgun",
"MarineBFG"
};
const PClass *cls = PClass::FindClass(classes[type]);
if (cls != NULL)
DecalGenerator = GetDefaultByType(cls)->DecalGenerator;
else
DecalGenerator = NULL;
}
}
void AScriptedMarine::SetSprite (PClassActor *source)
{
if (source == NULL)
{ // A valid actor class wasn't passed, so use the standard sprite
SpriteOverride = sprite = GetClass()->OwnedStates[0].sprite;
// Copy the standard scaling
Scale = GetDefault()->Scale;
}
else
{ // Use the same sprite and scaling the passed class spawns with
SpriteOverride = sprite = GetDefaultByType (source)->SpawnState->sprite;
Scale = GetDefaultByType(source)->Scale;
}
}

View file

@ -1,41 +0,0 @@
/*
#include "templates.h"
#include "actor.h"
#include "m_random.h"
#include "s_sound.h"
#include "p_local.h"
#include "p_enemy.h"
#include "a_action.h"
#include "thingdef/thingdef.h"
*/
static FRandom pr_spidrefire ("SpidRefire");
DEFINE_ACTION_FUNCTION(AActor, A_SpidRefire)
{
PARAM_ACTION_PROLOGUE;
// keep firing unless target got out of sight
A_FaceTarget (self);
if (pr_spidrefire() < 10)
return 0;
if (!self->target
|| P_HitFriend (self)
|| self->target->health <= 0
|| !P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES))
{
self->SetState (self->SeeState);
}
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_Metal)
{
PARAM_ACTION_PROLOGUE;
S_Sound (self, CHAN_BODY, "spider/walk", 1, ATTN_IDLE);
A_Chase (stack, self);
return 0;
}

View file

@ -478,15 +478,15 @@ CCMD (useflechette)
{ // Select from one of arti_poisonbag1-3, whichever the player has
static const ENamedName bagnames[3] =
{
NAME_ArtiPoisonBag3, // use type 3 first because that's the default when the player has none specified.
NAME_ArtiPoisonBag1,
NAME_ArtiPoisonBag2,
NAME_ArtiPoisonBag3
NAME_ArtiPoisonBag2
};
if (who == NULL)
return;
PClassActor *type = GetFlechetteType(who);
PClassActor *type = who->FlechetteType;
if (type != NULL)
{
AInventory *item;
@ -497,7 +497,7 @@ CCMD (useflechette)
}
}
// The default flechette could not be found. Try all 3 types then.
// The default flechette could not be found, or the player had no default. Try all 3 types then.
for (int j = 0; j < 3; ++j)
{
AInventory *item;
@ -1536,6 +1536,36 @@ static FPlayerStart *SelectRandomDeathmatchSpot (int playernum, unsigned int sel
return &deathmatchstarts[i];
}
DEFINE_ACTION_FUNCTION(DObject, G_PickDeathmatchStart)
{
PARAM_PROLOGUE;
unsigned int selections = deathmatchstarts.Size();
DVector3 pos;
int angle;
if (selections == 0)
{
angle = INT_MAX;
pos = DVector3(0, 0, 0);
}
else
{
unsigned int i = pr_dmspawn() % selections;
angle = deathmatchstarts[i].angle;
pos = deathmatchstarts[i].pos;
}
if (numret > 1)
{
ret[1].SetInt(angle);
numret = 2;
}
if (numret > 0)
{
ret[0].SetVector(pos);
}
return numret;
}
void G_DeathMatchSpawnPlayer (int playernum)
{
unsigned int selections;
@ -1577,6 +1607,7 @@ void G_DeathMatchSpawnPlayer (int playernum)
if (mo != NULL) P_PlayerStartStomp(mo);
}
//
// G_PickPlayerStart
//
@ -1614,6 +1645,24 @@ FPlayerStart *G_PickPlayerStart(int playernum, int flags)
return &playerstarts[playernum];
}
DEFINE_ACTION_FUNCTION(DObject, G_PickPlayerStart)
{
PARAM_PROLOGUE;
PARAM_INT(playernum);
PARAM_INT_DEF(flags);
auto ps = G_PickPlayerStart(playernum, flags);
if (numret > 1)
{
ret[1].SetInt(ps? ps->angle : 0);
numret = 2;
}
if (numret > 0)
{
ret[0].SetVector(ps ? ps->pos : DVector3(0, 0, 0));
}
return numret;
}
//
// G_QueueBody
//

View file

@ -1,233 +0,0 @@
/*
#include "actor.h"
#include "gi.h"
#include "m_random.h"
#include "s_sound.h"
#include "d_player.h"
#include "a_action.h"
#include "a_pickups.h"
#include "p_local.h"
#include "a_sharedglobal.h"
#include "p_enemy.h"
#include "d_event.h"
#include "gstrings.h"
#include "thingdef/thingdef.h"
*/
void P_UpdateBeak (AActor *actor);
static FRandom pr_chickenplayerthink ("ChickenPlayerThink");
static FRandom pr_chicattack ("ChicAttack");
static FRandom pr_feathers ("Feathers");
static FRandom pr_beakatkpl1 ("BeakAtkPL1");
static FRandom pr_beakatkpl2 ("BeakAtkPL2");
class AChickenPlayer : public APlayerPawn
{
DECLARE_CLASS (AChickenPlayer, APlayerPawn)
public:
void MorphPlayerThink ();
};
IMPLEMENT_CLASS(AChickenPlayer)
void AChickenPlayer::MorphPlayerThink ()
{
if (health > 0)
{ // Handle beak movement
P_UpdateBeak (this);
}
if (player->morphTics & 15)
{
return;
}
if (Vel.X == 0 && Vel.Y == 0 && pr_chickenplayerthink () < 160)
{ // Twitch view angle
Angles.Yaw += pr_chickenplayerthink.Random2() * (360. / 256. / 32.);
}
if ((Z() <= floorz) && (pr_chickenplayerthink() < 32))
{ // Jump and noise
Vel.Z += JumpZ;
FState * painstate = FindState(NAME_Pain);
if (painstate != NULL) SetState (painstate);
}
if (pr_chickenplayerthink () < 48)
{ // Just noise
S_Sound (this, CHAN_VOICE, "chicken/active", 1, ATTN_NORM);
}
}
//----------------------------------------------------------------------------
//
// PROC A_ChicAttack
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_ChicAttack)
{
PARAM_ACTION_PROLOGUE;
if (!self->target)
{
return 0;
}
if (self->CheckMeleeRange())
{
int damage = 1 + (pr_chicattack() & 1);
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
}
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_Feathers
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_Feathers)
{
PARAM_ACTION_PROLOGUE;
int i;
int count;
AActor *mo;
if (self->health > 0)
{ // Pain
count = pr_feathers() < 32 ? 2 : 1;
}
else
{ // Death
count = 5 + (pr_feathers()&3);
}
for (i = 0; i < count; i++)
{
mo = Spawn("Feather", self->PosPlusZ(20.), NO_REPLACE);
mo->target = self;
mo->Vel.X = pr_feathers.Random2() / 256.;
mo->Vel.Y = pr_feathers.Random2() / 256.;
mo->Vel.Z = 1. + pr_feathers() / 128.;
mo->SetState (mo->SpawnState + (pr_feathers()&7));
}
return 0;
}
//---------------------------------------------------------------------------
//
// PROC P_UpdateBeak
//
//---------------------------------------------------------------------------
void P_UpdateBeak (AActor *self)
{
DPSprite *pspr;
if (self->player != nullptr && (pspr = self->player->FindPSprite(PSP_WEAPON)) != nullptr)
{
pspr->y = WEAPONTOP + self->player->chickenPeck / 2;
}
}
//---------------------------------------------------------------------------
//
// PROC A_BeakRaise
//
//---------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_BeakRaise)
{
PARAM_ACTION_PROLOGUE;
player_t *player;
if (nullptr == (player = self->player))
{
return 0;
}
player->GetPSprite(PSP_WEAPON)->y = WEAPONTOP;
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->GetReadyState());
return 0;
}
//----------------------------------------------------------------------------
//
// PROC P_PlayPeck
//
//----------------------------------------------------------------------------
void P_PlayPeck (AActor *chicken)
{
S_Sound (chicken, CHAN_VOICE, "chicken/peck", 1, ATTN_NORM);
}
//----------------------------------------------------------------------------
//
// PROC A_BeakAttackPL1
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL1)
{
PARAM_ACTION_PROLOGUE;
DAngle angle;
int damage;
DAngle slope;
player_t *player;
FTranslatedLineTarget t;
if (NULL == (player = self->player))
{
return 0;
}
damage = 1 + (pr_beakatkpl1()&3);
angle = player->mo->Angles.Yaw;
slope = P_AimLineAttack (player->mo, angle, MELEERANGE);
P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &t);
if (t.linetarget)
{
player->mo->Angles.Yaw = t.angleFromSource;
}
P_PlayPeck (player->mo);
player->chickenPeck = 12;
player->GetPSprite(PSP_WEAPON)->Tics -= pr_beakatkpl1() & 7;
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_BeakAttackPL2
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL2)
{
PARAM_ACTION_PROLOGUE;
DAngle angle;
int damage;
DAngle slope;
player_t *player;
FTranslatedLineTarget t;
if (NULL == (player = self->player))
{
return 0;
}
damage = pr_beakatkpl2.HitDice (4);
angle = player->mo->Angles.Yaw;
slope = P_AimLineAttack (player->mo, angle, MELEERANGE);
P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &t);
if (t.linetarget)
{
player->mo->Angles.Yaw = t.angleFromSource;
}
P_PlayPeck (player->mo);
player->chickenPeck = 12;
player->GetPSprite(PSP_WEAPON)->Tics -= pr_beakatkpl2()&3;
return 0;
}

View file

@ -1,327 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "p_local.h"
#include "p_enemy.h"
#include "a_action.h"
#include "s_sound.h"
#include "m_random.h"
#include "a_sharedglobal.h"
#include "gstrings.h"
#include "a_specialspot.h"
#include "thingdef/thingdef.h"
#include "g_level.h"
*/
static FRandom pr_s2fx1 ("S2FX1");
static FRandom pr_scrc1atk ("Srcr1Attack");
static FRandom pr_dst ("D'SparilTele");
static FRandom pr_s2d ("Srcr2Decide");
static FRandom pr_s2a ("Srcr2Attack");
static FRandom pr_bluespark ("BlueSpark");
//----------------------------------------------------------------------------
//
// PROC A_Sor1Pain
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_Sor1Pain)
{
PARAM_ACTION_PROLOGUE;
self->special1 = 20; // Number of steps to walk fast
CALL_ACTION(A_Pain, self);
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_Sor1Chase
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_Sor1Chase)
{
PARAM_ACTION_PROLOGUE;
if (self->special1)
{
self->special1--;
self->tics -= 3;
}
A_Chase(stack, self);
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_Srcr1Attack
//
// Sorcerer demon attack.
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_Srcr1Attack)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
DAngle angle;
if (!self->target)
{
return 0;
}
S_Sound (self, CHAN_BODY, self->AttackSound, 1, ATTN_NORM);
if (self->CheckMeleeRange ())
{
int damage = pr_scrc1atk.HitDice (8);
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
return 0;
}
PClassActor *fx = PClass::FindActor("SorcererFX1");
if (self->health > (self->SpawnHealth()/3)*2)
{ // Spit one fireball
P_SpawnMissileZ (self, self->Z() + 48, self->target, fx );
}
else
{ // Spit three fireballs
mo = P_SpawnMissileZ (self, self->Z() + 48, self->target, fx);
if (mo != NULL)
{
angle = mo->Angles.Yaw;
P_SpawnMissileAngleZ(self, self->Z() + 48, fx, angle - 3, mo->Vel.Z);
P_SpawnMissileAngleZ(self, self->Z() + 48, fx, angle + 3, mo->Vel.Z);
}
if (self->health < self->SpawnHealth()/3)
{ // Maybe attack again
if (self->special1)
{ // Just attacked, so don't attack again
self->special1 = 0;
}
else
{ // Set state to attack again
self->special1 = 1;
self->SetState (self->FindState("Missile2"));
}
}
}
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_SorcererRise
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_SorcererRise)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
self->flags &= ~MF_SOLID;
mo = Spawn("Sorcerer2", self->Pos(), ALLOW_REPLACE);
mo->Translation = self->Translation;
mo->SetState (mo->FindState("Rise"));
mo->Angles.Yaw = self->Angles.Yaw;
mo->CopyFriendliness (self, true);
return 0;
}
//----------------------------------------------------------------------------
//
// PROC P_DSparilTeleport
//
//----------------------------------------------------------------------------
void P_DSparilTeleport (AActor *actor)
{
DVector3 prev;
AActor *mo;
AActor *spot;
DSpotState *state = DSpotState::GetSpotState();
if (state == NULL) return;
spot = state->GetSpotWithMinMaxDistance(PClass::FindActor("BossSpot"), actor->X(), actor->Y(), 128, 0);
if (spot == NULL) return;
prev = actor->Pos();
if (P_TeleportMove (actor, spot->Pos(), false))
{
mo = Spawn("Sorcerer2Telefade", prev, ALLOW_REPLACE);
if (mo) mo->Translation = actor->Translation;
S_Sound (mo, CHAN_BODY, "misc/teleport", 1, ATTN_NORM);
actor->SetState (actor->FindState("Teleport"));
S_Sound (actor, CHAN_BODY, "misc/teleport", 1, ATTN_NORM);
actor->SetZ(actor->floorz);
actor->Angles.Yaw = spot->Angles.Yaw;
actor->Vel.Zero();
}
}
//----------------------------------------------------------------------------
//
// PROC A_Srcr2Decide
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_Srcr2Decide)
{
PARAM_ACTION_PROLOGUE;
static const int chance[] =
{
192, 120, 120, 120, 64, 64, 32, 16, 0
};
unsigned int chanceindex = self->health / ((self->SpawnHealth()/8 == 0) ? 1 : self->SpawnHealth()/8);
if (chanceindex >= countof(chance))
{
chanceindex = countof(chance) - 1;
}
if (pr_s2d() < chance[chanceindex])
{
P_DSparilTeleport (self);
}
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_Srcr2Attack
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_Srcr2Attack)
{
PARAM_ACTION_PROLOGUE;
int chance;
if (!self->target)
{
return 0;
}
S_Sound (self, CHAN_BODY, self->AttackSound, 1, ATTN_NONE);
if (self->CheckMeleeRange())
{
int damage = pr_s2a.HitDice (20);
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
return 0;
}
chance = self->health < self->SpawnHealth()/2 ? 96 : 48;
if (pr_s2a() < chance)
{ // Wizard spawners
PClassActor *fx = PClass::FindActor("Sorcerer2FX2");
if (fx)
{
P_SpawnMissileAngle(self, fx, self->Angles.Yaw - 45, 0.5);
P_SpawnMissileAngle(self, fx, self->Angles.Yaw + 45, 0.5);
}
}
else
{ // Blue bolt
P_SpawnMissile (self, self->target, PClass::FindActor("Sorcerer2FX1"));
}
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_BlueSpark
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_BlueSpark)
{
PARAM_ACTION_PROLOGUE;
int i;
AActor *mo;
for (i = 0; i < 2; i++)
{
mo = Spawn("Sorcerer2FXSpark", self->Pos(), ALLOW_REPLACE);
mo->Vel.X = pr_bluespark.Random2() / 128.;
mo->Vel.Y = pr_bluespark.Random2() / 128.;
mo->Vel.Z = 1. + pr_bluespark() / 256.;
}
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_GenWizard
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_GenWizard)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
mo = Spawn("Wizard", self->Pos(), ALLOW_REPLACE);
if (mo != NULL)
{
mo->AddZ(-mo->GetDefault()->Height / 2, false);
if (!P_TestMobjLocation (mo))
{ // Didn't fit
mo->ClearCounters();
mo->Destroy ();
}
else
{ // [RH] Make the new wizards inherit D'Sparil's target
mo->CopyFriendliness (self->target, true);
self->Vel.Zero();
self->SetState (self->FindState(NAME_Death));
self->flags &= ~MF_MISSILE;
mo->master = self->target;
P_SpawnTeleportFog(self, self->Pos(), false, true);
}
}
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_Sor2DthInit
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_Sor2DthInit)
{
PARAM_ACTION_PROLOGUE;
self->special1 = 7; // Animation loop counter
P_Massacre (); // Kill monsters early
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_Sor2DthLoop
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_Sor2DthLoop)
{
PARAM_ACTION_PROLOGUE;
if (--self->special1)
{ // Need to loop
self->SetState (self->FindState("DeathLoop"));
}
return 0;
}

View file

@ -1,77 +0,0 @@
/*
#include "info.h"
#include "a_pickups.h"
#include "a_artifacts.h"
#include "gstrings.h"
#include "p_local.h"
#include "s_sound.h"
#include "thingdef/thingdef.h"
*/
// Tome of power ------------------------------------------------------------
class AArtiTomeOfPower : public APowerupGiver
{
DECLARE_CLASS (AArtiTomeOfPower, APowerupGiver)
public:
bool Use (bool pickup);
};
IMPLEMENT_CLASS (AArtiTomeOfPower)
bool AArtiTomeOfPower::Use (bool pickup)
{
if (Owner->player->morphTics && (Owner->player->MorphStyle & MORPH_UNDOBYTOMEOFPOWER))
{ // Attempt to undo chicken
if (!P_UndoPlayerMorph (Owner->player, Owner->player, MORPH_UNDOBYTOMEOFPOWER))
{ // Failed
if (!(Owner->player->MorphStyle & MORPH_FAILNOTELEFRAG))
{
P_DamageMobj (Owner, NULL, NULL, TELEFRAG_DAMAGE, NAME_Telefrag);
}
}
else
{ // Succeeded
S_Sound (Owner, CHAN_VOICE, "*evillaugh", 1, ATTN_IDLE);
}
return true;
}
else
{
return Super::Use (pickup);
}
}
// Time bomb ----------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_TimeBomb)
{
PARAM_ACTION_PROLOGUE;
self->AddZ(32, false);
self->RenderStyle = STYLE_Add;
self->Alpha = 1.;
P_RadiusAttack (self, self->target, 128, 128, self->DamageType, RADF_HURTSOURCE);
P_CheckSplash(self, 128);
return 0;
}
class AArtiTimeBomb : public AInventory
{
DECLARE_CLASS (AArtiTimeBomb, AInventory)
public:
bool Use (bool pickup);
};
IMPLEMENT_CLASS (AArtiTimeBomb)
bool AArtiTimeBomb::Use (bool pickup)
{
AActor *mo = Spawn("ActivatedTimeBomb",
Owner->Vec3Angle(24., Owner->Angles.Yaw, - Owner->Floorclip), ALLOW_REPLACE);
mo->target = Owner;
return true;
}

View file

@ -1,96 +0,0 @@
/*
#include "templates.h"
#include "actor.h"
#include "info.h"
#include "m_random.h"
#include "s_sound.h"
#include "p_local.h"
#include "gstrings.h"
#include "thingdef/thingdef.h"
*/
static FRandom pr_impmsatk ("ImpMsAttack");
static FRandom pr_imp ("ImpExplode");
//----------------------------------------------------------------------------
//
// PROC A_ImpMsAttack
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_ImpMsAttack)
{
PARAM_ACTION_PROLOGUE;
if (!self->target || pr_impmsatk() > 64)
{
self->SetState (self->SeeState);
return 0;
}
A_SkullAttack(self, 12.);
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_ImpExplode
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_ImpExplode)
{
PARAM_ACTION_PROLOGUE;
AActor *chunk;
self->flags &= ~MF_NOGRAVITY;
chunk = Spawn("HereticImpChunk1", self->Pos(), ALLOW_REPLACE);
chunk->Vel.X = pr_imp.Random2() / 64.;
chunk->Vel.Y = pr_imp.Random2() / 64.;
chunk->Vel.Z = 9;
chunk = Spawn("HereticImpChunk2", self->Pos(), ALLOW_REPLACE);
chunk->Vel.X = pr_imp.Random2() / 64.;
chunk->Vel.Y = pr_imp.Random2() / 64.;
chunk->Vel.Z = 9;
if (self->special1 == 666)
{ // Extreme death crash
self->SetState (self->FindState("XCrash"));
}
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_ImpDeath
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_ImpDeath)
{
PARAM_ACTION_PROLOGUE;
self->flags &= ~MF_SOLID;
self->flags2 |= MF2_FLOORCLIP;
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_ImpXDeath1
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_ImpXDeath1)
{
PARAM_ACTION_PROLOGUE;
self->flags &= ~MF_SOLID;
self->flags |= MF_NOGRAVITY;
self->flags2 |= MF2_FLOORCLIP;
self->special1 = 666; // Flag the crash routine
return 0;
}

View file

@ -1,219 +0,0 @@
#include "actor.h"
#include "info.h"
#include "a_pickups.h"
#include "a_action.h"
#include "m_random.h"
#include "p_local.h"
#include "s_sound.h"
#include "gstrings.h"
#include "thingdef/thingdef.h"
#include "p_enemy.h"
#include "a_specialspot.h"
#include "g_level.h"
#include "a_sharedglobal.h"
#include "templates.h"
#include "r_data/r_translate.h"
#include "doomstat.h"
#include "d_player.h"
#include "a_morph.h"
#include "p_spec.h"
#include "serializer.h"
// Include all the other Heretic stuff here to reduce compile time
#include "a_chicken.cpp"
#include "a_dsparil.cpp"
#include "a_hereticartifacts.cpp"
#include "a_hereticimp.cpp"
#include "a_hereticweaps.cpp"
#include "a_ironlich.cpp"
#include "a_knight.cpp"
#include "a_wizard.cpp"
static FRandom pr_podpain ("PodPain");
static FRandom pr_makepod ("MakePod");
static FRandom pr_teleg ("TeleGlitter");
static FRandom pr_teleg2 ("TeleGlitter2");
static FRandom pr_volcano ("VolcanoSet");
static FRandom pr_blast ("VolcanoBlast");
static FRandom pr_volcimpact ("VolcBallImpact");
//----------------------------------------------------------------------------
//
// PROC A_PodPain
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PodPain)
{
PARAM_ACTION_PROLOGUE;
PARAM_CLASS_OPT (gootype, AActor) { gootype = PClass::FindActor("PodGoo"); }
int count;
int chance;
AActor *goo;
chance = pr_podpain ();
if (chance < 128)
{
return 0;
}
for (count = chance > 240 ? 2 : 1; count; count--)
{
goo = Spawn(gootype, self->PosPlusZ(48.), ALLOW_REPLACE);
goo->target = self;
goo->Vel.X = pr_podpain.Random2() / 128.;
goo->Vel.Y = pr_podpain.Random2() / 128.;
goo->Vel.Z = 0.5 + pr_podpain() / 128.;
}
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_RemovePod
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_RemovePod)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
if ( (mo = self->master) )
{
if (mo->special1 > 0)
{
mo->special1--;
}
}
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_MakePod
//
//----------------------------------------------------------------------------
#define MAX_GEN_PODS 16
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MakePod)
{
PARAM_ACTION_PROLOGUE;
PARAM_CLASS_OPT(podtype, AActor) { podtype = PClass::FindActor("Pod"); }
AActor *mo;
if (self->special1 == MAX_GEN_PODS)
{ // Too many generated pods
return 0;
}
mo = Spawn(podtype, self->PosAtZ(ONFLOORZ), ALLOW_REPLACE);
if (!P_CheckPosition (mo, mo->Pos()))
{ // Didn't fit
mo->Destroy ();
return 0;
}
mo->SetState (mo->FindState("Grow"));
mo->Thrust(pr_makepod() * (360. / 256), 4.5);
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 0;
}
//----------------------------------------------------------------------------
//
// PROC A_AccTeleGlitter
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_AccTeleGlitter)
{
PARAM_ACTION_PROLOGUE;
if (++self->health > 35)
{
self->Vel.Z *= 1.5;
}
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_VolcanoSet
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_VolcanoSet)
{
PARAM_ACTION_PROLOGUE;
self->tics = 105 + (pr_volcano() & 127);
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_VolcanoBlast
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_VolcanoBlast)
{
PARAM_ACTION_PROLOGUE;
int i;
int count;
AActor *blast;
count = 1 + (pr_blast() % 3);
for (i = 0; i < count; i++)
{
blast = Spawn("VolcanoBlast", self->PosPlusZ(44.), ALLOW_REPLACE);
blast->target = self;
blast->Angles.Yaw = pr_blast() * (360 / 256.);
blast->VelFromAngle(1.);
blast->Vel.Z = 2.5 + pr_blast() / 64.;
S_Sound (blast, CHAN_BODY, "world/volcano/shoot", 1, ATTN_NORM);
P_CheckMissileSpawn (blast, self->radius);
}
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_VolcBallImpact
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_VolcBallImpact)
{
PARAM_ACTION_PROLOGUE;
unsigned int i;
AActor *tiny;
if (self->Z() <= self->floorz)
{
self->flags |= MF_NOGRAVITY;
self->Gravity = 1;
self->AddZ(28);
//self->Vel.Z = 3;
}
P_RadiusAttack (self, self->target, 25, 25, NAME_Fire, RADF_HURTSOURCE);
for (i = 0; i < 4; i++)
{
tiny = Spawn("VolcanoTBlast", self->Pos(), ALLOW_REPLACE);
tiny->target = self;
tiny->Angles.Yaw = 90.*i;
tiny->VelFromAngle(0.7);
tiny->Vel.Z = 1. + pr_volcimpact() / 128.;
P_CheckMissileSpawn (tiny, self->radius);
}
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -1,213 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "m_random.h"
#include "s_sound.h"
#include "p_local.h"
#include "p_enemy.h"
#include "a_action.h"
#include "gstrings.h"
#include "thingdef/thingdef.h"
#include "g_level.h"
*/
static FRandom pr_foo ("WhirlwindDamage");
static FRandom pr_atk ("LichAttack");
static FRandom pr_seek ("WhirlwindSeek");
class AWhirlwind : public AActor
{
DECLARE_CLASS (AWhirlwind, AActor)
public:
int DoSpecialDamage (AActor *target, int damage, FName damagetype);
};
IMPLEMENT_CLASS(AWhirlwind)
int AWhirlwind::DoSpecialDamage (AActor *target, int damage, FName damagetype)
{
int randVal;
if (!(target->flags7 & MF7_DONTTHRUST))
{
target->Angles.Yaw += pr_foo.Random2() * (360 / 4096.);
target->Vel.X += pr_foo.Random2() / 64.;
target->Vel.Y += pr_foo.Random2() / 64.;
}
if ((level.time & 16) && !(target->flags2 & MF2_BOSS) && !(target->flags7 & MF7_DONTTHRUST))
{
randVal = pr_foo();
if (randVal > 160)
{
randVal = 160;
}
target->Vel.Z += randVal / 32.;
if (target->Vel.Z > 12)
{
target->Vel.Z = 12;
}
}
if (!(level.time & 7))
{
P_DamageMobj (target, NULL, this->target, 3, NAME_Melee);
}
return -1;
}
//----------------------------------------------------------------------------
//
// PROC A_LichAttack
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_LichAttack)
{
PARAM_ACTION_PROLOGUE;
int i;
AActor *fire;
AActor *baseFire;
AActor *mo;
AActor *target;
int randAttack;
static const int atkResolve1[] = { 50, 150 };
static const int atkResolve2[] = { 150, 200 };
// 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 0;
}
A_FaceTarget (self);
if (self->CheckMeleeRange ())
{
int damage = pr_atk.HitDice (6);
int newdam = P_DamageMobj (target, self, self, damage, NAME_Melee);
P_TraceBleed (newdam > 0 ? newdam : damage, target, self);
return 0;
}
int dist = self->Distance2D(target) > 8 * 64;
randAttack = pr_atk ();
if (randAttack < atkResolve1[dist])
{ // Ice ball
P_SpawnMissile (self, target, PClass::FindActor("HeadFX1"));
S_Sound (self, CHAN_BODY, "ironlich/attack2", 1, ATTN_NORM);
}
else if (randAttack < atkResolve2[dist])
{ // Fire column
baseFire = P_SpawnMissile (self, target, PClass::FindActor("HeadFX3"));
if (baseFire != NULL)
{
baseFire->SetState (baseFire->FindState("NoGrow"));
for (i = 0; i < 5; i++)
{
fire = Spawn("HeadFX3", baseFire->Pos(), ALLOW_REPLACE);
if (i == 0)
{
S_Sound (self, CHAN_BODY, "ironlich/attack1", 1, ATTN_NORM);
}
fire->target = baseFire->target;
fire->Angles.Yaw = baseFire->Angles.Yaw;
fire->Vel = baseFire->Vel;
fire->SetDamage(0);
fire->health = (i+1) * 2;
P_CheckMissileSpawn (fire, self->radius);
}
}
}
else
{ // Whirlwind
mo = P_SpawnMissile (self, target, RUNTIME_CLASS(AWhirlwind));
if (mo != NULL)
{
mo->AddZ(-32);
mo->tracer = target;
mo->health = 20*TICRATE; // Duration
S_Sound (self, CHAN_BODY, "ironlich/attack3", 1, ATTN_NORM);
}
}
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_WhirlwindSeek
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_WhirlwindSeek)
{
PARAM_ACTION_PROLOGUE;
self->health -= 3;
if (self->health < 0)
{
self->Vel.Zero();
self->SetState(self->FindState(NAME_Death));
self->flags &= ~MF_MISSILE;
return 0;
}
if ((self->threshold -= 3) < 0)
{
self->threshold = 58 + (pr_seek() & 31);
S_Sound(self, CHAN_BODY, "ironlich/attack3", 1, ATTN_NORM);
}
if (self->tracer && self->tracer->flags&MF_SHADOW)
{
return 0;
}
P_SeekerMissile(self, 10, 30);
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_LichIceImpact
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_LichIceImpact)
{
PARAM_ACTION_PROLOGUE;
unsigned int i;
AActor *shard;
for (i = 0; i < 8; i++)
{
shard = Spawn("HeadFX2", self->Pos(), ALLOW_REPLACE);
shard->target = self->target;
shard->Angles.Yaw = i*45.;
shard->VelFromAngle();
shard->Vel.Z = -.6;
P_CheckMissileSpawn (shard, self->radius);
}
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_LichFireGrow
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_LichFireGrow)
{
PARAM_ACTION_PROLOGUE;
self->health--;
self->AddZ(9.);
if (self->health == 0)
{
self->RestoreDamage();
self->SetState (self->FindState("NoGrow"));
}
return 0;
}

View file

@ -1,70 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "m_random.h"
#include "s_sound.h"
#include "p_local.h"
#include "a_action.h"
#include "a_sharedglobal.h"
#include "gstrings.h"
#include "thingdef/thingdef.h"
*/
static FRandom pr_dripblood ("DripBlood");
static FRandom pr_knightatk ("KnightAttack");
//----------------------------------------------------------------------------
//
// PROC A_DripBlood
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_DripBlood)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
double xo = pr_dripblood.Random2() / 32.;
double yo = pr_dripblood.Random2() / 32.;
mo = Spawn ("Blood", self->Vec3Offset(xo, yo, 0.), ALLOW_REPLACE);
mo->Vel.X = pr_dripblood.Random2 () / 64.;
mo->Vel.Y = pr_dripblood.Random2() / 64.;
mo->Gravity = 1./8;
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_KnightAttack
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_KnightAttack)
{
PARAM_ACTION_PROLOGUE;
if (!self->target)
{
return 0;
}
if (self->CheckMeleeRange ())
{
int damage = pr_knightatk.HitDice (3);
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
S_Sound (self, CHAN_BODY, "hknight/melee", 1, ATTN_NORM);
return 0;
}
// Throw axe
S_Sound (self, CHAN_BODY, self->AttackSound, 1, ATTN_NORM);
if (self->flags & MF_SHADOW || pr_knightatk () < 40)
{ // Red axe
P_SpawnMissileZ (self, self->Z() + 36, self->target, PClass::FindActor("RedAxe"));
return 0;
}
// Green axe
P_SpawnMissileZ (self, self->Z() + 36, self->target, PClass::FindActor("KnightAxe"));
return 0;
}

View file

@ -1,95 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "m_random.h"
#include "s_sound.h"
#include "p_local.h"
#include "p_enemy.h"
#include "a_action.h"
#include "gstrings.h"
#include "thingdef/thingdef.h"
*/
static FRandom pr_wizatk3 ("WizAtk3");
//----------------------------------------------------------------------------
//
// PROC A_GhostOff
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_GhostOff)
{
PARAM_ACTION_PROLOGUE;
self->RenderStyle = STYLE_Normal;
self->flags3 &= ~MF3_GHOST;
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_WizAtk1
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_WizAtk1)
{
PARAM_ACTION_PROLOGUE;
A_FaceTarget (self);
CALL_ACTION(A_GhostOff, self);
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_WizAtk2
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_WizAtk2)
{
PARAM_ACTION_PROLOGUE;
A_FaceTarget (self);
self->Alpha = HR_SHADOW;
self->RenderStyle = STYLE_Translucent;
self->flags3 |= MF3_GHOST;
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_WizAtk3
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_WizAtk3)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
CALL_ACTION(A_GhostOff, self);
if (!self->target)
{
return 0;
}
S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM);
if (self->CheckMeleeRange())
{
int damage = pr_wizatk3.HitDice (4);
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
return 0;
}
PClassActor *fx = PClass::FindActor("WizardFX1");
mo = P_SpawnMissile (self, self->target, fx);
if (mo != NULL)
{
P_SpawnMissileAngle(self, fx, mo->Angles.Yaw - 45. / 8, mo->Vel.Z);
P_SpawnMissileAngle(self, fx, mo->Angles.Yaw + 45. / 8, mo->Vel.Z);
}
return 0;
}

View file

@ -1,98 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "m_random.h"
#include "p_local.h"
#include "s_sound.h"
#include "thingdef/thingdef.h"
*/
static FRandom pr_batspawn ("BatSpawn");
static FRandom pr_batmove ("BatMove");
//===========================================================================
// Bat Spawner Variables
// special1 frequency counter
// special2
// args[0] frequency of spawn (1=fastest, 10=slowest)
// args[1] spread angle (0..255)
// args[2]
// args[3] duration of bats (in octics)
// args[4] turn amount per move (in degrees)
//
// Bat Variables
// special2 lifetime counter
// args[4] turn amount per move (in degrees)
//===========================================================================
DEFINE_ACTION_FUNCTION(AActor, A_BatSpawnInit)
{
PARAM_ACTION_PROLOGUE;
self->special1 = 0; // Frequency count
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_BatSpawn)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
int delta;
DAngle angle;
// Countdown until next spawn
if (self->special1-- > 0) return 0;
self->special1 = self->args[0]; // Reset frequency count
delta = self->args[1];
if (delta==0) delta=1;
angle = self->Angles.Yaw + (((pr_batspawn() % delta) - (delta >> 1)) * (360 / 256.));
mo = P_SpawnMissileAngle (self, PClass::FindActor("Bat"), angle, 0);
if (mo)
{
mo->args[0] = pr_batspawn()&63; // floatbob index
mo->args[4] = self->args[4]; // turn degrees
mo->special2 = self->args[3]<<3; // Set lifetime
mo->target = self;
}
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_BatMove)
{
PARAM_ACTION_PROLOGUE;
DAngle newangle;
if (self->special2 < 0)
{
self->SetState (self->FindState(NAME_Death));
}
self->special2 -= 2; // Called every 2 tics
if (pr_batmove()<128)
{
newangle = self->Angles.Yaw + self->args[4];
}
else
{
newangle = self->Angles.Yaw - self->args[4];
}
// Adjust velocity vector to new direction
self->VelFromAngle(newangle, self->Speed);
if (pr_batmove()<15)
{
S_Sound (self, CHAN_VOICE, "BatScream", 1, ATTN_IDLE);
}
// Handle Z movement
self->SetZ(self->target->Z() + 2 * BobSin(self->args[0]));
self->args[0] = (self->args[0]+3)&63;
return 0;
}

View file

@ -1,230 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "p_local.h"
#include "s_sound.h"
#include "a_action.h"
#include "m_random.h"
#include "a_hexenglobal.h"
#include "thingdef/thingdef.h"
*/
static FRandom pr_boom ("BishopBoom");
static FRandom pr_atk ("BishopAttack");
static FRandom pr_decide ("BishopDecide");
static FRandom pr_doblur ("BishopDoBlur");
static FRandom pr_sblur ("BishopSpawnBlur");
static FRandom pr_pain ("BishopPainBlur");
//============================================================================
//
// A_BishopAttack
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_BishopAttack)
{
PARAM_ACTION_PROLOGUE;
if (!self->target)
{
return 0;
}
S_Sound (self, CHAN_BODY, self->AttackSound, 1, ATTN_NORM);
if (self->CheckMeleeRange())
{
int damage = pr_atk.HitDice (4);
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
return 0;
}
self->special1 = (pr_atk() & 3) + 5;
return 0;
}
//============================================================================
//
// A_BishopAttack2
//
// Spawns one of a string of bishop missiles
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_BishopAttack2)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
if (!self->target || !self->special1)
{
self->special1 = 0;
self->SetState (self->SeeState);
return 0;
}
mo = P_SpawnMissile (self, self->target, PClass::FindActor("BishopFX"));
if (mo != NULL)
{
mo->tracer = self->target;
}
self->special1--;
return 0;
}
//============================================================================
//
// A_BishopMissileWeave
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_BishopMissileWeave)
{
PARAM_ACTION_PROLOGUE;
A_Weave(self, 2, 2, 2., 1.);
return 0;
}
//============================================================================
//
// A_BishopDecide
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_BishopDecide)
{
PARAM_ACTION_PROLOGUE;
if (pr_decide() < 220)
{
return 0;
}
else
{
self->SetState (self->FindState ("Blur"));
}
return 0;
}
//============================================================================
//
// A_BishopDoBlur
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_BishopDoBlur)
{
PARAM_ACTION_PROLOGUE;
self->special1 = (pr_doblur() & 3) + 3; // Random number of blurs
if (pr_doblur() < 120)
{
self->Thrust(self->Angles.Yaw + 90, 11);
}
else if (pr_doblur() > 125)
{
self->Thrust(self->Angles.Yaw - 90, 11);
}
else
{ // Thrust forward
self->Thrust(11);
}
S_Sound (self, CHAN_BODY, "BishopBlur", 1, ATTN_NORM);
return 0;
}
//============================================================================
//
// A_BishopSpawnBlur
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_BishopSpawnBlur)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
if (!--self->special1)
{
self->Vel.X = self->Vel.Y = 0;
if (pr_sblur() > 96)
{
self->SetState (self->SeeState);
}
else
{
self->SetState (self->MissileState);
}
}
mo = Spawn ("BishopBlur", self->Pos(), ALLOW_REPLACE);
if (mo)
{
mo->Angles.Yaw = self->Angles.Yaw;
}
return 0;
}
//============================================================================
//
// A_BishopChase
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_BishopChase)
{
PARAM_ACTION_PROLOGUE;
double newz = self->Z() - BobSin(self->special2) / 2.;
self->special2 = (self->special2 + 4) & 63;
newz += BobSin(self->special2) / 2.;
self->SetZ(newz);
return 0;
}
//============================================================================
//
// A_BishopPuff
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_BishopPuff)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
mo = Spawn ("BishopPuff", self->PosPlusZ(40.), ALLOW_REPLACE);
if (mo)
{
mo->Vel.Z = -.5;
}
return 0;
}
//============================================================================
//
// A_BishopPainBlur
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_BishopPainBlur)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
if (pr_pain() < 64)
{
self->SetState (self->FindState ("Blur"));
return 0;
}
double xo = pr_pain.Random2() / 16.;
double yo = pr_pain.Random2() / 16.;
double zo = pr_pain.Random2() / 32.;
mo = Spawn ("BishopPainBlur", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE);
if (mo)
{
mo->Angles.Yaw = self->Angles.Yaw;
}
return 0;
}

View file

@ -1,158 +0,0 @@
/*
#include "info.h"
#include "a_pickups.h"
#include "a_artifacts.h"
#include "gstrings.h"
#include "p_local.h"
#include "p_enemy.h"
#include "s_sound.h"
*/
/* For reference, the default values:
#define BLAST_RADIUS_DIST 255*F.RACUNIT
#define BLAST_SPEED 20*F.RACUNIT
#define BLAST_FULLSTRENGTH 255
*/
// Disc of Repulsion --------------------------------------------------------
//==========================================================================
//
// AArtiBlastRadius :: BlastActor
//
//==========================================================================
void BlastActor (AActor *victim, double strength, double speed, AActor *Owner, PClassActor *blasteffect, bool dontdamage)
{
DAngle angle;
AActor *mo;
DVector3 pos;
if (!victim->SpecialBlastHandling (Owner, strength))
{
return;
}
angle = Owner->AngleTo(victim);
DVector2 move = angle.ToVector(speed);
victim->Vel.X = move.X;
victim->Vel.Y = move.Y;
// Spawn blast puff
angle -= 180.;
pos = victim->Vec3Offset(
(victim->radius + 1) * angle.Cos(),
(victim->radius + 1) * angle.Sin(),
(victim->Height / 2) - victim->Floorclip);
mo = Spawn (blasteffect, pos, ALLOW_REPLACE);
if (mo)
{
mo->Vel.X = victim->Vel.X;
mo->Vel.Y = victim->Vel.Y;
}
if (victim->flags & MF_MISSILE)
{
// [RH] Floor and ceiling huggers should not be blasted vertically.
if (!(victim->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER)))
{
mo->Vel.Z = victim->Vel.Z = 8;
}
}
else
{
victim->Vel.Z = 1000. / victim->Mass;
}
if (victim->player)
{
// Players handled automatically
}
else if (!dontdamage)
{
victim->flags2 |= MF2_BLASTED;
}
if (victim->flags6 & MF6_TOUCHY)
{ // Touchy objects die when blasted
victim->flags6 &= ~MF6_ARMED; // Disarm
P_DamageMobj(victim, Owner, Owner, victim->health, NAME_Melee, DMG_FORCED);
}
}
enum
{
BF_USEAMMO = 1,
BF_DONTWARN = 2,
BF_AFFECTBOSSES = 4,
BF_NOIMPACTDAMAGE = 8,
};
//==========================================================================
//
// AArtiBlastRadius :: Activate
//
// Blast all actors away
//
//==========================================================================
DEFINE_ACTION_FUNCTION_PARAMS (AActor, A_Blast)
{
PARAM_ACTION_PROLOGUE;
PARAM_INT_OPT (blastflags) { blastflags = 0; }
PARAM_FLOAT_OPT (strength) { strength = 255; }
PARAM_FLOAT_OPT (radius) { radius = 255; }
PARAM_FLOAT_OPT (speed) { speed = 20; }
PARAM_CLASS_OPT (blasteffect, AActor) { blasteffect = PClass::FindActor("BlastEffect"); }
PARAM_SOUND_OPT (blastsound) { blastsound = "BlastRadius"; }
AActor *mo;
TThinkerIterator<AActor> iterator;
if (self->player && (blastflags & BF_USEAMMO) && ACTION_CALL_FROM_PSPRITE())
{
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL && !weapon->DepleteAmmo(weapon->bAltFire))
{
return 0;
}
}
S_Sound (self, CHAN_AUTO, blastsound, 1, ATTN_NORM);
if (!(blastflags & BF_DONTWARN))
{
P_NoiseAlert (self, self);
}
while ( (mo = iterator.Next ()) )
{
if ((mo == self) || ((mo->flags2 & MF2_BOSS) && !(blastflags & BF_AFFECTBOSSES))
|| (mo->flags2 & MF2_DORMANT) || (mo->flags3 & MF3_DONTBLAST))
{ // Not a valid monster: originator, boss, dormant, or otherwise protected
continue;
}
if ((mo->flags & MF_ICECORPSE) || (mo->flags3 & MF3_CANBLAST))
{
// Let these special cases go
}
else if ((mo->flags3 & MF3_ISMONSTER) && (mo->health <= 0))
{
continue;
}
else if (!(mo->player) &&
!(mo->flags & MF_MISSILE) &&
!(mo->flags3 & (MF3_ISMONSTER|MF3_CANBLAST)) &&
!(mo->flags6 & (MF6_TOUCHY|MF6_VULNERABLE)))
{ // Must be monster, player, missile, touchy or vulnerable
continue;
}
if (self->Distance2D(mo) > radius)
{ // Out of range
continue;
}
if (mo->Sector->PortalGroup != self->Sector->PortalGroup && !P_CheckSight(self, mo))
{
// in another region and cannot be seen.
continue;
}
BlastActor (mo, strength, speed, self, blasteffect, !!(blastflags & BF_NOIMPACTDAMAGE));
}
return 0;
}

View file

@ -1,64 +0,0 @@
/*
#include "info.h"
#include "a_pickups.h"
#include "a_artifacts.h"
#include "gstrings.h"
#include "p_local.h"
#include "gi.h"
#include "s_sound.h"
*/
// Boost Armor Artifact (Dragonskin Bracers) --------------------------------
class AArtiBoostArmor : public AInventory
{
DECLARE_CLASS (AArtiBoostArmor, AInventory)
public:
bool Use (bool pickup);
};
IMPLEMENT_CLASS (AArtiBoostArmor)
bool AArtiBoostArmor::Use (bool pickup)
{
int count = 0;
if (gameinfo.gametype == GAME_Hexen)
{
AHexenArmor *armor;
for (int i = 0; i < 4; ++i)
{
armor = Spawn<AHexenArmor>();
armor->flags |= MF_DROPPED;
armor->health = i;
armor->Amount = 1;
if (!armor->CallTryPickup (Owner))
{
armor->Destroy ();
}
else
{
count++;
}
}
return count != 0;
}
else
{
ABasicArmorBonus *armor = Spawn<ABasicArmorBonus>();
armor->flags |= MF_DROPPED;
armor->SaveAmount = 50;
armor->MaxSaveAmount = 300;
if (!armor->CallTryPickup (Owner))
{
armor->Destroy ();
return false;
}
else
{
return true;
}
}
}

View file

@ -1,30 +0,0 @@
/*
#include "actor.h"
#include "p_enemy.h"
#include "a_action.h"
#include "m_random.h"
#include "thingdef/thingdef.h"
*/
static FRandom pr_centaurdefend ("CentaurDefend");
//============================================================================
//
// A_CentaurDefend
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_CentaurDefend)
{
PARAM_ACTION_PROLOGUE;
A_FaceTarget (self);
if (self->CheckMeleeRange() && pr_centaurdefend() < 32)
{
// This should unset REFLECTIVE as well
// (unless you want the Centaur to reflect projectiles forever!)
self->flags2&=~(MF2_REFLECTIVE|MF2_INVULNERABLE);
self->SetState (self->MeleeState);
}
return 0;
}

View file

@ -1,170 +0,0 @@
/*
#include "actor.h"
#include "gi.h"
#include "m_random.h"
#include "s_sound.h"
#include "d_player.h"
#include "a_action.h"
#include "p_local.h"
#include "a_action.h"
#include "p_pspr.h"
#include "gstrings.h"
#include "a_hexenglobal.h"
#include "thingdef/thingdef.h"
*/
const double FLAMESPEED = 0.45;
const double FLAMEROTSPEED = 2.;
static FRandom pr_missile ("CFlameMissile");
void A_CFlameAttack (AActor *);
void A_CFlameRotate (AActor *);
void A_CFlamePuff (AActor *);
void A_CFlameMissile (AActor *);
// Flame Missile ------------------------------------------------------------
class ACFlameMissile : public AFastProjectile
{
DECLARE_CLASS (ACFlameMissile, AFastProjectile)
public:
void BeginPlay ();
void Effect ();
};
IMPLEMENT_CLASS (ACFlameMissile)
void ACFlameMissile::BeginPlay ()
{
special1 = 2;
}
void ACFlameMissile::Effect ()
{
if (!--special1)
{
special1 = 4;
double newz = Z() - 12;
if (newz < floorz)
{
newz = floorz;
}
AActor *mo = Spawn ("CFlameFloor", PosAtZ(newz), ALLOW_REPLACE);
if (mo)
{
mo->Angles.Yaw = Angles.Yaw;
}
}
}
//============================================================================
//
// A_CFlameAttack
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_CFlameAttack)
{
PARAM_ACTION_PROLOGUE;
player_t *player;
if (NULL == (player = self->player))
{
return 0;
}
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL)
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
return 0;
}
P_SpawnPlayerMissile (self, RUNTIME_CLASS(ACFlameMissile));
S_Sound (self, CHAN_WEAPON, "ClericFlameFire", 1, ATTN_NORM);
return 0;
}
//============================================================================
//
// A_CFlamePuff
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_CFlamePuff)
{
PARAM_ACTION_PROLOGUE;
self->renderflags &= ~RF_INVISIBLE;
self->Vel.Zero();
S_Sound (self, CHAN_BODY, "ClericFlameExplode", 1, ATTN_NORM);
return 0;
}
//============================================================================
//
// A_CFlameMissile
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_CFlameMissile)
{
PARAM_ACTION_PROLOGUE;
int i;
DAngle an;
double dist;
AActor *mo;
self->renderflags &= ~RF_INVISIBLE;
S_Sound (self, CHAN_BODY, "ClericFlameExplode", 1, ATTN_NORM);
AActor *BlockingMobj = self->BlockingMobj;
if (BlockingMobj && BlockingMobj->flags&MF_SHOOTABLE)
{ // Hit something, so spawn the flame circle around the thing
dist = BlockingMobj->radius + 18;
for (i = 0; i < 4; i++)
{
an = i*45.;
mo = Spawn ("CircleFlame", BlockingMobj->Vec3Angle(dist, an, 5), ALLOW_REPLACE);
if (mo)
{
mo->Angles.Yaw = an;
mo->target = self->target;
mo->VelFromAngle(FLAMESPEED);
mo->specialf1 = mo->Vel.X;
mo->specialf2 = mo->Vel.Y;
mo->tics -= pr_missile()&3;
}
mo = Spawn("CircleFlame", BlockingMobj->Vec3Angle(dist, an, 5), ALLOW_REPLACE);
if(mo)
{
mo->Angles.Yaw = an + 180.;
mo->target = self->target;
mo->VelFromAngle(-FLAMESPEED);
mo->specialf1 = mo->Vel.X;
mo->specialf2 = mo->Vel.Y;
mo->tics -= pr_missile()&3;
}
}
self->SetState (self->SpawnState);
}
return 0;
}
//============================================================================
//
// A_CFlameRotate
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_CFlameRotate)
{
PARAM_ACTION_PROLOGUE;
DAngle an = self->Angles.Yaw + 90.;
self->VelFromAngle(an, FLAMEROTSPEED);
self->Vel += DVector2(self->specialf1, self->specialf2);
self->Angles.Yaw += 6.;
return 0;
}

View file

@ -1,516 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "p_local.h"
#include "m_random.h"
#include "s_sound.h"
#include "a_hexenglobal.h"
#include "gstrings.h"
#include "a_weaponpiece.h"
#include "thingdef/thingdef.h"
#include "g_level.h"
#include "doomstat.h"
*/
#define BLAST_FULLSTRENGTH 255
static FRandom pr_holyatk2 ("CHolyAtk2");
static FRandom pr_holyseeker ("CHolySeeker");
static FRandom pr_holyweave ("CHolyWeave");
static FRandom pr_holyseek ("CHolySeek");
static FRandom pr_checkscream ("CCheckScream");
static FRandom pr_spiritslam ("CHolySlam");
static FRandom pr_wraithvergedrop ("WraithvergeDrop");
void SpawnSpiritTail (AActor *spirit);
//==========================================================================
// Cleric's Wraithverge (Holy Symbol?) --------------------------------------
class ACWeapWraithverge : public AClericWeapon
{
DECLARE_CLASS (ACWeapWraithverge, AClericWeapon)
public:
void Serialize(FSerializer &arc)
{
Super::Serialize (arc);
arc("cholycount", CHolyCount);
}
PalEntry GetBlend ()
{
if (paletteflash & PF_HEXENWEAPONS)
{
if (CHolyCount == 3)
return PalEntry(128, 70, 70, 70);
else if (CHolyCount == 2)
return PalEntry(128, 100, 100, 100);
else if (CHolyCount == 1)
return PalEntry(128, 130, 130, 130);
else
return PalEntry(0, 0, 0, 0);
}
else
{
return PalEntry (CHolyCount * 128 / 3, 131, 131, 131);
}
}
BYTE CHolyCount;
};
IMPLEMENT_CLASS (ACWeapWraithverge)
// Holy Spirit --------------------------------------------------------------
IMPLEMENT_CLASS (AHolySpirit)
bool AHolySpirit::Slam(AActor *thing)
{
if (thing->flags&MF_SHOOTABLE && thing != target)
{
if (multiplayer && !deathmatch && thing->player && target->player)
{ // don't attack other co-op players
return true;
}
if (thing->flags2&MF2_REFLECTIVE
&& (thing->player || thing->flags2&MF2_BOSS))
{
tracer = target;
target = thing;
return true;
}
if (thing->flags3&MF3_ISMONSTER || thing->player)
{
tracer = thing;
}
if (pr_spiritslam() < 96)
{
int dam = 12;
if (thing->player || thing->flags2&MF2_BOSS)
{
dam = 3;
// ghost burns out faster when attacking players/bosses
health -= 6;
}
P_DamageMobj(thing, this, target, dam, NAME_Melee);
if (pr_spiritslam() < 128)
{
Spawn("HolyPuff", Pos(), ALLOW_REPLACE);
S_Sound(this, CHAN_WEAPON, "SpiritAttack", 1, ATTN_NORM);
if (thing->flags3&MF3_ISMONSTER && pr_spiritslam() < 128)
{
thing->Howl();
}
}
}
if (thing->health <= 0)
{
tracer = NULL;
}
}
return true;
}
bool AHolySpirit::SpecialBlastHandling (AActor *source, double strength)
{
if (tracer == source)
{
tracer = target;
target = source;
GC::WriteBarrier(this, source);
}
return true;
}
//============================================================================
//
// A_CHolyAttack2
//
// Spawns the spirits
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_CHolyAttack2)
{
PARAM_ACTION_PROLOGUE;
int j;
AActor *mo;
for (j = 0; j < 4; j++)
{
mo = Spawn<AHolySpirit> (self->Pos(), ALLOW_REPLACE);
if (!mo)
{
continue;
}
switch (j)
{ // float bob index
case 0:
mo->WeaveIndexZ = pr_holyatk2() & 7; // upper-left
break;
case 1:
mo->WeaveIndexZ = 32 + (pr_holyatk2() & 7); // upper-right
break;
case 2:
mo->WeaveIndexXY = 32 + (pr_holyatk2() & 7); // lower-left
break;
case 3:
mo->WeaveIndexXY = 32 + (pr_holyatk2() & 7);
mo->WeaveIndexZ = 32 + (pr_holyatk2() & 7);
break;
}
mo->SetZ(self->Z());
mo->Angles.Yaw = self->Angles.Yaw + 67.5 - 45.*j;
mo->Thrust();
mo->target = self->target;
mo->args[0] = 10; // initial turn value
mo->args[1] = 0; // initial look angle
if (deathmatch)
{ // Ghosts last slightly less longer in DeathMatch
mo->health = 85;
}
if (self->tracer)
{
mo->tracer = self->tracer;
mo->flags |= MF_NOCLIP|MF_SKULLFLY;
mo->flags &= ~MF_MISSILE;
}
SpawnSpiritTail (mo);
}
return 0;
}
//============================================================================
//
// SpawnSpiritTail
//
//============================================================================
void SpawnSpiritTail (AActor *spirit)
{
AActor *tail, *next;
int i;
tail = Spawn ("HolyTail", spirit->Pos(), ALLOW_REPLACE);
tail->target = spirit; // parent
for (i = 1; i < 3; i++)
{
next = Spawn ("HolyTailTrail", spirit->Pos(), ALLOW_REPLACE);
tail->tracer = next;
tail = next;
}
tail->tracer = NULL; // last tail bit
}
//============================================================================
//
// A_CHolyAttack
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_CHolyAttack)
{
PARAM_ACTION_PROLOGUE;
player_t *player;
FTranslatedLineTarget t;
if (NULL == (player = self->player))
{
return 0;
}
ACWeapWraithverge *weapon = static_cast<ACWeapWraithverge *> (self->player->ReadyWeapon);
if (weapon != NULL)
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
return 0;
}
AActor *missile = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindActor("HolyMissile"), self->Angles.Yaw, &t);
if (missile != NULL && !t.unlinked)
{
missile->tracer = t.linetarget;
}
weapon->CHolyCount = 3;
S_Sound (self, CHAN_WEAPON, "HolySymbolFire", 1, ATTN_NORM);
return 0;
}
//============================================================================
//
// A_CHolyPalette
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_CHolyPalette)
{
PARAM_ACTION_PROLOGUE;
if (self->player != NULL)
{
ACWeapWraithverge *weapon = static_cast<ACWeapWraithverge *> (self->player->ReadyWeapon);
if (weapon != NULL && weapon->CHolyCount != 0)
{
weapon->CHolyCount--;
}
}
return 0;
}
//============================================================================
//
// CHolyTailFollow
//
//============================================================================
static void CHolyTailFollow(AActor *actor, double dist)
{
AActor *child;
DAngle an;
double oldDistance, newDistance;
while (actor)
{
child = actor->tracer;
if (child)
{
an = actor->AngleTo(child);
oldDistance = child->Distance2D(actor);
if (P_TryMove(child, actor->Pos().XY() + an.ToVector(dist), true))
{
newDistance = child->Distance2D(actor) - 1;
if (oldDistance < 1)
{
if (child->Z() < actor->Z())
{
child->SetZ(actor->Z() - dist);
}
else
{
child->SetZ(actor->Z() + dist);
}
}
else
{
child->SetZ(actor->Z() + (newDistance * (child->Z() - actor->Z()) / oldDistance));
}
}
}
actor = child;
dist -= 1;
}
}
//============================================================================
//
// CHolyTailRemove
//
//============================================================================
static void CHolyTailRemove (AActor *actor)
{
AActor *next;
while (actor)
{
next = actor->tracer;
actor->Destroy ();
actor = next;
}
}
//============================================================================
//
// A_CHolyTail
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_CHolyTail)
{
PARAM_ACTION_PROLOGUE;
AActor *parent;
parent = self->target;
if (parent == NULL || parent->health <= 0) // better check for health than current state - it's safer!
{ // Ghost removed, so remove all tail parts
CHolyTailRemove (self);
return 0;
}
else
{
if (P_TryMove(self, parent->Vec2Angle(14., parent->Angles.Yaw, true), true))
{
self->SetZ(parent->Z() - 5.);
}
CHolyTailFollow(self, 10);
}
return 0;
}
//============================================================================
//
// CHolyFindTarget
//
//============================================================================
static void CHolyFindTarget (AActor *actor)
{
AActor *target;
if ( (target = P_RoughMonsterSearch (actor, 6, true)) )
{
actor->tracer = target;
actor->flags |= MF_NOCLIP|MF_SKULLFLY;
actor->flags &= ~MF_MISSILE;
}
}
//============================================================================
//
// CHolySeekerMissile
//
// Similar to P_SeekerMissile, but seeks to a random Z on the target
//============================================================================
static void CHolySeekerMissile (AActor *actor, DAngle thresh, DAngle turnMax)
{
int dir;
DAngle delta;
AActor *target;
double newZ;
double deltaZ;
target = actor->tracer;
if (target == NULL)
{
return;
}
if (!(target->flags&MF_SHOOTABLE)
|| (!(target->flags3&MF3_ISMONSTER) && !target->player))
{ // Target died/target isn't a player or creature
actor->tracer = NULL;
actor->flags &= ~(MF_NOCLIP | MF_SKULLFLY);
actor->flags |= MF_MISSILE;
CHolyFindTarget(actor);
return;
}
dir = P_FaceMobj (actor, target, &delta);
if (delta > thresh)
{
delta /= 2;
if (delta > turnMax)
{
delta = turnMax;
}
}
if (dir)
{ // Turn clockwise
actor->Angles.Yaw += delta;
}
else
{ // Turn counter clockwise
actor->Angles.Yaw -= delta;
}
actor->VelFromAngle();
if (!(level.time&15)
|| actor->Z() > target->Top()
|| actor->Top() < target->Z())
{
newZ = target->Z() + ((pr_holyseeker()*target->Height) / 256.);
deltaZ = newZ - actor->Z();
if (fabs(deltaZ) > 15)
{
if (deltaZ > 0)
{
deltaZ = 15;
}
else
{
deltaZ = -15;
}
}
actor->Vel.Z = deltaZ / actor->DistanceBySpeed(target, actor->Speed);
}
return;
}
//============================================================================
//
// A_CHolySeek
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_CHolySeek)
{
PARAM_ACTION_PROLOGUE;
self->health--;
if (self->health <= 0)
{
self->Vel.X /= 4;
self->Vel.Y /= 4;
self->Vel.Z = 0;
self->SetState (self->FindState(NAME_Death));
self->tics -= pr_holyseek()&3;
return 0;
}
if (self->tracer)
{
CHolySeekerMissile (self, (double)self->args[0], self->args[0]*2.);
if (!((level.time+7)&15))
{
self->args[0] = 5+(pr_holyseek()/20);
}
}
int xyspeed = (pr_holyweave() % 5);
int zspeed = (pr_holyweave() % 5);
A_Weave(self, xyspeed, zspeed, 4., 2.);
return 0;
}
//============================================================================
//
// A_CHolyCheckScream
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_CHolyCheckScream)
{
PARAM_ACTION_PROLOGUE;
CALL_ACTION(A_CHolySeek, self);
if (pr_checkscream() < 20)
{
S_Sound (self, CHAN_VOICE, "SpiritActive", 1, ATTN_NORM);
}
if (!self->tracer)
{
CHolyFindTarget(self);
}
return 0;
}
//============================================================================
//
// A_ClericAttack
// (for the ClericBoss)
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_ClericAttack)
{
PARAM_ACTION_PROLOGUE;
if (!self->target) return 0;
AActor * missile = P_SpawnMissileZ (self, self->Z() + 40., self->target, PClass::FindActor ("HolyMissile"));
if (missile != NULL) missile->tracer = NULL; // No initial target
S_Sound (self, CHAN_WEAPON, "HolySymbolFire", 1, ATTN_NORM);
return 0;
}

View file

@ -1,59 +0,0 @@
/*
#include "m_random.h"
#include "p_local.h"
#include "a_hexenglobal.h"
#include "thingdef/thingdef.h"
*/
static FRandom pr_maceatk ("CMaceAttack");
//===========================================================================
//
// A_CMaceAttack
//
//===========================================================================
DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack)
{
PARAM_ACTION_PROLOGUE;
DAngle angle;
int damage;
DAngle slope;
int i;
player_t *player;
FTranslatedLineTarget t;
if (NULL == (player = self->player))
{
return 0;
}
PClassActor *hammertime = PClass::FindActor("HammerPuff");
damage = 25+(pr_maceatk()&15);
for (i = 0; i < 16; i++)
{
for (int j = 1; j >= -1; j -= 2)
{
angle = player->mo->Angles.Yaw + j*i*(45. / 16);
slope = P_AimLineAttack(player->mo, angle, 2 * MELEERANGE, &t);
if (t.linetarget)
{
P_LineAttack(player->mo, angle, 2 * MELEERANGE, slope, damage, NAME_Melee, hammertime, true, &t);
if (t.linetarget != NULL)
{
AdjustPlayerAngle(player->mo, &t);
return 0;
}
}
}
}
// didn't find any creatures, so try to strike any walls
player->mo->weaponspecial = 0;
angle = player->mo->Angles.Yaw;
slope = P_AimLineAttack (player->mo, angle, MELEERANGE);
P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, hammertime);
return 0;
}

View file

@ -1,199 +0,0 @@
/*
#include "actor.h"
#include "gi.h"
#include "m_random.h"
#include "s_sound.h"
#include "d_player.h"
#include "a_action.h"
#include "p_local.h"
#include "a_action.h"
#include "p_pspr.h"
#include "gstrings.h"
#include "a_hexenglobal.h"
#include "thingdef/thingdef.h"
*/
static FRandom pr_staffcheck ("CStaffCheck");
static FRandom pr_blink ("CStaffBlink");
// Serpent Staff Missile ----------------------------------------------------
class ACStaffMissile : public AActor
{
DECLARE_CLASS (ACStaffMissile, AActor)
public:
int DoSpecialDamage (AActor *target, int damage, FName damagetype);
};
IMPLEMENT_CLASS (ACStaffMissile)
int ACStaffMissile::DoSpecialDamage (AActor *target, int damage, FName damagetype)
{
// Cleric Serpent Staff does poison damage
if (target->player)
{
P_PoisonPlayer (target->player, this, this->target, 20);
damage >>= 1;
}
return damage;
}
//============================================================================
//
// A_CStaffCheck
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck)
{
PARAM_ACTION_PROLOGUE;
APlayerPawn *pmo;
int damage;
int newLife, max;
DAngle angle;
DAngle slope;
int i;
player_t *player;
FTranslatedLineTarget t;
PClassActor *puff;
if (nullptr == (player = self->player))
{
return 0;
}
AWeapon *weapon = self->player->ReadyWeapon;
pmo = player->mo;
damage = 20 + (pr_staffcheck() & 15);
max = pmo->GetMaxHealth();
puff = PClass::FindActor("CStaffPuff");
for (i = 0; i < 3; i++)
{
for (int j = 1; j >= -1; j -= 2)
{
angle = pmo->Angles.Yaw + j*i*(45. / 16);
slope = P_AimLineAttack(pmo, angle, 1.5 * MELEERANGE, &t, 0., ALF_CHECK3D);
if (t.linetarget)
{
P_LineAttack(pmo, angle, 1.5 * MELEERANGE, slope, damage, NAME_Melee, puff, false, &t);
if (t.linetarget != nullptr)
{
pmo->Angles.Yaw = t.angleFromSource;
if (((t.linetarget->player && (!t.linetarget->IsTeammate(pmo) || level.teamdamage != 0)) || t.linetarget->flags3&MF3_ISMONSTER)
&& (!(t.linetarget->flags2&(MF2_DORMANT | MF2_INVULNERABLE))))
{
newLife = player->health + (damage >> 3);
newLife = newLife > max ? max : newLife;
if (newLife > player->health)
{
pmo->health = player->health = newLife;
}
if (weapon != nullptr)
{
FState * newstate = weapon->FindState("Drain");
if (newstate != nullptr) P_SetPsprite(player, PSP_WEAPON, newstate);
}
}
if (weapon != nullptr)
{
weapon->DepleteAmmo(weapon->bAltFire, false);
}
}
return 0;
}
}
}
return 0;
}
//============================================================================
//
// A_CStaffAttack
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_CStaffAttack)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
player_t *player;
if (NULL == (player = self->player))
{
return 0;
}
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL)
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
return 0;
}
mo = P_SpawnPlayerMissile (self, RUNTIME_CLASS(ACStaffMissile), self->Angles.Yaw - 3.0);
if (mo)
{
mo->WeaveIndexXY = 32;
}
mo = P_SpawnPlayerMissile (self, RUNTIME_CLASS(ACStaffMissile), self->Angles.Yaw + 3.0);
if (mo)
{
mo->WeaveIndexXY = 0;
}
S_Sound (self, CHAN_WEAPON, "ClericCStaffFire", 1, ATTN_NORM);
return 0;
}
//============================================================================
//
// A_CStaffMissileSlither
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_CStaffMissileSlither)
{
PARAM_ACTION_PROLOGUE;
A_Weave(self, 3, 0, 1., 0.);
return 0;
}
//============================================================================
//
// A_CStaffInitBlink
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_CStaffInitBlink)
{
PARAM_ACTION_PROLOGUE;
self->weaponspecial = (pr_blink()>>1)+20;
return 0;
}
//============================================================================
//
// A_CStaffCheckBlink
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheckBlink)
{
PARAM_ACTION_PROLOGUE;
if (self->player && self->player->ReadyWeapon)
{
if (!--self->weaponspecial)
{
P_SetPsprite(self->player, PSP_WEAPON, self->player->ReadyWeapon->FindState ("Blink"));
self->weaponspecial = (pr_blink()+50)>>2;
}
else
{
DoReadyWeapon(self);
}
}
return 0;
}

View file

@ -1,311 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "p_enemy.h"
#include "p_local.h"
#include "a_action.h"
#include "m_random.h"
#include "s_sound.h"
#include "thingdef/thingdef.h"
*/
static FRandom pr_dragonseek ("DragonSeek");
static FRandom pr_dragonflight ("DragonFlight");
static FRandom pr_dragonflap ("DragonFlap");
static FRandom pr_dragonfx2 ("DragonFX2");
DECLARE_ACTION(A_DragonFlight)
//============================================================================
//
// DragonSeek
//
//============================================================================
static void DragonSeek (AActor *actor, DAngle thresh, DAngle turnMax)
{
int dir;
double dist;
DAngle delta;
AActor *target;
int i;
DAngle bestAngle;
DAngle angleToSpot, angleToTarget;
AActor *mo;
target = actor->tracer;
if(target == NULL)
{
return;
}
dir = P_FaceMobj (actor, target, &delta);
if (delta > thresh)
{
delta /= 2;
if (delta > turnMax)
{
delta = turnMax;
}
}
if (dir)
{ // Turn clockwise
actor->Angles.Yaw += delta;
}
else
{ // Turn counter clockwise
actor->Angles.Yaw -= delta;
}
actor->VelFromAngle();
dist = actor->DistanceBySpeed(target, actor->Speed);
if (actor->Top() < target->Z() ||
target->Top() < actor->Z())
{
actor->Vel.Z = (target->Z() - actor->Z()) / dist;
}
if (target->flags&MF_SHOOTABLE && pr_dragonseek() < 64)
{ // attack the destination mobj if it's attackable
AActor *oldTarget;
if (absangle(actor->Angles.Yaw, actor->AngleTo(target)) < 22.5)
{
oldTarget = actor->target;
actor->target = target;
if (actor->CheckMeleeRange ())
{
int damage = pr_dragonseek.HitDice (10);
int newdam = P_DamageMobj (actor->target, actor, actor, damage, NAME_Melee);
P_TraceBleed (newdam > 0 ? newdam : damage, actor->target, actor);
S_Sound (actor, CHAN_WEAPON, actor->AttackSound, 1, ATTN_NORM);
}
else if (pr_dragonseek() < 128 && P_CheckMissileRange(actor))
{
P_SpawnMissile(actor, target, PClass::FindActor("DragonFireball"));
S_Sound (actor, CHAN_WEAPON, actor->AttackSound, 1, ATTN_NORM);
}
actor->target = oldTarget;
}
}
if (dist < 4)
{ // Hit the target thing
if (actor->target && pr_dragonseek() < 200)
{
AActor *bestActor = NULL;
bestAngle = 360.;
angleToTarget = actor->AngleTo(actor->target);
for (i = 0; i < 5; i++)
{
if (!target->args[i])
{
continue;
}
FActorIterator iterator (target->args[i]);
mo = iterator.Next ();
if (mo == NULL)
{
continue;
}
angleToSpot = actor->AngleTo(mo);
DAngle diff = absangle(angleToSpot, angleToTarget);
if (diff < bestAngle)
{
bestAngle = diff;
bestActor = mo;
}
}
if (bestActor != NULL)
{
actor->tracer = bestActor;
}
}
else
{
// [RH] Don't lock up if the dragon doesn't have any
// targets defined
for (i = 0; i < 5; ++i)
{
if (target->args[i] != 0)
{
break;
}
}
if (i < 5)
{
do
{
i = (pr_dragonseek()>>2)%5;
} while(!target->args[i]);
FActorIterator iterator (target->args[i]);
actor->tracer = iterator.Next ();
}
}
}
}
//============================================================================
//
// A_DragonInitFlight
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_DragonInitFlight)
{
PARAM_ACTION_PROLOGUE;
FActorIterator iterator (self->tid);
do
{ // find the first tid identical to the dragon's tid
self->tracer = iterator.Next ();
if (self->tracer == NULL)
{
self->SetState (self->SpawnState);
return 0;
}
} while (self->tracer == self);
self->RemoveFromHash ();
return 0;
}
//============================================================================
//
// A_DragonFlight
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_DragonFlight)
{
PARAM_ACTION_PROLOGUE;
DAngle angle;
DragonSeek (self, 4., 8.);
if (self->target)
{
if(!(self->target->flags&MF_SHOOTABLE))
{ // target died
self->target = NULL;
return 0;
}
angle = absangle(self->Angles.Yaw, self->AngleTo(self->target));
if (angle <22.5 && self->CheckMeleeRange())
{
int damage = pr_dragonflight.HitDice (8);
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM);
}
else if (angle <= 20)
{
self->SetState (self->MissileState);
S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM);
}
}
else
{
P_LookForPlayers (self, true, NULL);
}
return 0;
}
//============================================================================
//
// A_DragonFlap
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_DragonFlap)
{
PARAM_ACTION_PROLOGUE;
CALL_ACTION(A_DragonFlight, self);
if (pr_dragonflap() < 240)
{
S_Sound (self, CHAN_BODY, "DragonWingflap", 1, ATTN_NORM);
}
else
{
self->PlayActiveSound ();
}
return 0;
}
//============================================================================
//
// A_DragonAttack
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_DragonAttack)
{
PARAM_ACTION_PROLOGUE;
P_SpawnMissile (self, self->target, PClass::FindActor("DragonFireball"));
return 0;
}
//============================================================================
//
// A_DragonFX2
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_DragonFX2)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
int i;
int delay;
delay = 16+(pr_dragonfx2()>>3);
for (i = 1+(pr_dragonfx2()&3); i; i--)
{
double xo = (pr_dragonfx2() - 128) / 4.;
double yo = (pr_dragonfx2() - 128) / 4.;
double zo = (pr_dragonfx2() - 128) / 16.;
mo = Spawn ("DragonExplosion", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE);
if (mo)
{
mo->tics = delay+(pr_dragonfx2()&3)*i*2;
mo->target = self->target;
}
}
return 0;
}
//============================================================================
//
// A_DragonPain
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_DragonPain)
{
PARAM_ACTION_PROLOGUE;
CALL_ACTION(A_Pain, self);
if (!self->tracer)
{ // no destination spot yet
self->SetState (self->SeeState);
}
return 0;
}
//============================================================================
//
// A_DragonCheckCrash
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_DragonCheckCrash)
{
PARAM_ACTION_PROLOGUE;
if (self->Z() <= self->floorz)
{
self->SetState (self->FindState ("Crash"));
}
return 0;
}

View file

@ -1,282 +0,0 @@
/*
#include "actor.h"
#include "gi.h"
#include "m_random.h"
#include "s_sound.h"
#include "d_player.h"
#include "a_action.h"
#include "p_local.h"
#include "a_action.h"
#include "p_pspr.h"
#include "gstrings.h"
#include "a_hexenglobal.h"
#include "thingdef/thingdef.h"
*/
#define AXERANGE (2.25 * MELEERANGE)
static FRandom pr_axeatk ("FAxeAtk");
void A_FAxeCheckReady (AActor *actor);
void A_FAxeCheckUp (AActor *actor);
void A_FAxeCheckAtk (AActor *actor);
void A_FAxeCheckReadyG (AActor *actor);
void A_FAxeCheckUpG (AActor *actor);
void A_FAxeAttack (AActor *actor);
// The Fighter's Axe --------------------------------------------------------
class AFWeapAxe : public AFighterWeapon
{
DECLARE_CLASS (AFWeapAxe, AFighterWeapon)
public:
FState *GetUpState ();
FState *GetDownState ();
FState *GetReadyState ();
FState *GetAtkState (bool hold);
};
IMPLEMENT_CLASS (AFWeapAxe)
FState *AFWeapAxe::GetUpState ()
{
return Ammo1->Amount ? FindState ("SelectGlow") : Super::GetUpState();
}
FState *AFWeapAxe::GetDownState ()
{
return Ammo1->Amount ? FindState ("DeselectGlow") : Super::GetDownState();
}
FState *AFWeapAxe::GetReadyState ()
{
return Ammo1->Amount ? FindState ("ReadyGlow") : Super::GetReadyState();
}
FState *AFWeapAxe::GetAtkState (bool hold)
{
return Ammo1->Amount ? FindState ("FireGlow") : Super::GetAtkState(hold);
}
//============================================================================
//
// A_FAxeCheckReady
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckReady)
{
PARAM_ACTION_PROLOGUE;
player_t *player;
if (nullptr == (player = self->player))
{
return 0;
}
if (player->ReadyWeapon->Ammo1->Amount)
{
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState ("ReadyGlow"));
}
else
{
DoReadyWeapon(self);
}
return 0;
}
//============================================================================
//
// A_FAxeCheckReadyG
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckReadyG)
{
PARAM_ACTION_PROLOGUE;
player_t *player;
if (nullptr == (player = self->player))
{
return 0;
}
if (player->ReadyWeapon->Ammo1->Amount <= 0)
{
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState ("Ready"));
}
else
{
DoReadyWeapon(self);
}
return 0;
}
//============================================================================
//
// A_FAxeCheckUp
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckUp)
{
PARAM_ACTION_PROLOGUE;
player_t *player;
if (nullptr == (player = self->player))
{
return 0;
}
if (player->ReadyWeapon->Ammo1->Amount)
{
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState ("SelectGlow"));
}
else
{
CALL_ACTION(A_Raise, self);
}
return 0;
}
//============================================================================
//
// A_FAxeCheckUpG
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckUpG)
{
PARAM_ACTION_PROLOGUE;
player_t *player;
if (nullptr == (player = self->player))
{
return 0;
}
if (player->ReadyWeapon->Ammo1->Amount <= 0)
{
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState ("Select"));
}
else
{
CALL_ACTION(A_Raise, self);
}
return 0;
}
//============================================================================
//
// A_FAxeCheckAtk
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckAtk)
{
PARAM_ACTION_PROLOGUE;
player_t *player;
if (nullptr == (player = self->player))
{
return 0;
}
if (player->ReadyWeapon->Ammo1->Amount)
{
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState ("FireGlow"));
}
return 0;
}
//============================================================================
//
// A_FAxeAttack
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FAxeAttack)
{
PARAM_ACTION_PROLOGUE;
DAngle angle;
int power;
int damage;
DAngle slope;
int i;
int useMana;
player_t *player;
AWeapon *weapon;
PClassActor *pufftype;
FTranslatedLineTarget t;
if (nullptr == (player = self->player))
{
return 0;
}
AActor *pmo=player->mo;
damage = 40+(pr_axeatk()&15);
damage += pr_axeatk()&7;
power = 0;
weapon = player->ReadyWeapon;
if (player->ReadyWeapon->Ammo1->Amount > 0)
{
damage <<= 1;
power = 6;
pufftype = PClass::FindActor ("AxePuffGlow");
useMana = 1;
}
else
{
pufftype = PClass::FindActor ("AxePuff");
useMana = 0;
}
for (i = 0; i < 16; i++)
{
for (int j = 1; j >= -1; j -= 2)
{
angle = pmo->Angles.Yaw + j*i*(45. / 16);
slope = P_AimLineAttack(pmo, angle, AXERANGE, &t);
if (t.linetarget)
{
P_LineAttack(pmo, angle, AXERANGE, slope, damage, NAME_Melee, pufftype, true, &t);
if (t.linetarget != nullptr)
{
if (t.linetarget->flags3&MF3_ISMONSTER || t.linetarget->player)
{
t.linetarget->Thrust(t.angleFromSource, power);
}
AdjustPlayerAngle(pmo, &t);
useMana++;
goto axedone;
}
}
}
}
// didn't find any creatures, so try to strike any walls
pmo->weaponspecial = 0;
angle = pmo->Angles.Yaw;
slope = P_AimLineAttack (pmo, angle, MELEERANGE);
P_LineAttack (pmo, angle, MELEERANGE, slope, damage, NAME_Melee, pufftype, true);
axedone:
if (useMana == 2)
{
AWeapon *weapon = player->ReadyWeapon;
if (weapon != nullptr)
{
weapon->DepleteAmmo (weapon->bAltFire, false);
if ((weapon->Ammo1 == nullptr || weapon->Ammo1->Amount == 0) &&
(!(weapon->WeaponFlags & WIF_PRIMARY_USES_BOTH) ||
weapon->Ammo2 == nullptr || weapon->Ammo2->Amount == 0))
{
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState ("Fire") + 5);
}
}
}
return 0;
}

View file

@ -1,124 +0,0 @@
/*
#include "actor.h"
#include "gi.h"
#include "m_random.h"
#include "s_sound.h"
#include "d_player.h"
#include "a_action.h"
#include "p_local.h"
#include "a_action.h"
#include "p_pspr.h"
#include "gstrings.h"
#include "a_hexenglobal.h"
#include "thingdef/thingdef.h"
*/
const double HAMMER_RANGE = 1.5 * MELEERANGE;
static FRandom pr_hammeratk ("FHammerAtk");
//============================================================================
//
// A_FHammerAttack
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack)
{
PARAM_ACTION_PROLOGUE;
DAngle angle;
int damage;
DAngle slope;
int i;
player_t *player;
FTranslatedLineTarget t;
PClassActor *hammertime;
if (NULL == (player = self->player))
{
return 0;
}
AActor *pmo=player->mo;
damage = 60+(pr_hammeratk()&63);
hammertime = PClass::FindActor("HammerPuff");
for (i = 0; i < 16; i++)
{
for (int j = 1; j >= -1; j -= 2)
{
angle = pmo->Angles.Yaw + j*i*(45. / 32);
slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE, &t, 0., ALF_CHECK3D);
if (t.linetarget != NULL)
{
P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true, &t);
if (t.linetarget != NULL)
{
AdjustPlayerAngle(pmo, &t);
if (t.linetarget->flags3 & MF3_ISMONSTER || t.linetarget->player)
{
t.linetarget->Thrust(t.angleFromSource, 10);
}
pmo->weaponspecial = false; // Don't throw a hammer
goto hammerdone;
}
}
}
}
// didn't find any targets in meleerange, so set to throw out a hammer
angle = pmo->Angles.Yaw;
slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, NULL, 0., ALF_CHECK3D);
if (P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true) != NULL)
{
pmo->weaponspecial = false;
}
else
{
pmo->weaponspecial = true;
}
hammerdone:
// Don't spawn a hammer if the player doesn't have enough mana
if (player->ReadyWeapon == NULL ||
!player->ReadyWeapon->CheckAmmo (player->ReadyWeapon->bAltFire ?
AWeapon::AltFire : AWeapon::PrimaryFire, false, true))
{
pmo->weaponspecial = false;
}
return 0;
}
//============================================================================
//
// A_FHammerThrow
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FHammerThrow)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
player_t *player;
if (NULL == (player = self->player))
{
return 0;
}
if (!player->mo->weaponspecial)
{
return 0;
}
AWeapon *weapon = player->ReadyWeapon;
if (weapon != NULL)
{
if (!weapon->DepleteAmmo (weapon->bAltFire, false))
return 0;
}
mo = P_SpawnPlayerMissile (player->mo, PClass::FindActor("HammerMissile"));
if (mo)
{
mo->special1 = 0;
}
return 0;
}

View file

@ -1,135 +0,0 @@
/*
#include "actor.h"
#include "gi.h"
#include "m_random.h"
#include "s_sound.h"
#include "d_player.h"
#include "a_action.h"
#include "p_local.h"
#include "a_action.h"
#include "a_hexenglobal.h"
#include "thingdef/thingdef.h"
*/
IMPLEMENT_CLASS (AFighterWeapon)
IMPLEMENT_CLASS (AClericWeapon)
IMPLEMENT_CLASS (AMageWeapon)
static FRandom pr_fpatk ("FPunchAttack");
//============================================================================
//
// AdjustPlayerAngle
//
//============================================================================
#define MAX_ANGLE_ADJUST (5.)
void AdjustPlayerAngle (AActor *pmo, FTranslatedLineTarget *t)
{
// normally this will adjust relative to the actual direction to the target,
// but with arbitrary portals that cannot be calculated so using the actual
// attack angle is the only option.
DAngle atkangle = t->unlinked ? t->angleFromSource : pmo->AngleTo(t->linetarget);
DAngle difference = deltaangle(pmo->Angles.Yaw, atkangle);
if (fabs(difference) > MAX_ANGLE_ADJUST)
{
if (difference > 0)
{
pmo->Angles.Yaw += MAX_ANGLE_ADJUST;
}
else
{
pmo->Angles.Yaw -= MAX_ANGLE_ADJUST;
}
}
else
{
pmo->Angles.Yaw = t->angleFromSource;
}
}
//============================================================================
//
// TryPunch
//
// Returns true if an actor was punched, false if not.
//
//============================================================================
static bool TryPunch(APlayerPawn *pmo, DAngle angle, int damage, int power)
{
PClassActor *pufftype;
FTranslatedLineTarget t;
DAngle slope;
slope = P_AimLineAttack (pmo, angle, 2*MELEERANGE, &t);
if (t.linetarget != NULL)
{
if (++pmo->weaponspecial >= 3)
{
damage <<= 1;
power *= 3;
pufftype = PClass::FindActor("HammerPuff");
}
else
{
pufftype = PClass::FindActor("PunchPuff");
}
P_LineAttack (pmo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, pufftype, true, &t);
if (t.linetarget != NULL)
{
if (t.linetarget->player != NULL ||
(t.linetarget->Mass != INT_MAX && (t.linetarget->flags3 & MF3_ISMONSTER)))
{
t.linetarget->Thrust(t.angleFromSource, power);
}
AdjustPlayerAngle (pmo, &t);
return true;
}
}
return false;
}
//============================================================================
//
// A_FPunchAttack
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack)
{
PARAM_ACTION_PROLOGUE;
int damage;
int i;
player_t *player;
if (nullptr == (player = self->player))
{
return 0;
}
APlayerPawn *pmo = player->mo;
damage = 40+(pr_fpatk()&15);
for (i = 0; i < 16; i++)
{
if (TryPunch(pmo, pmo->Angles.Yaw + i*(45./16), damage, 2) ||
TryPunch(pmo, pmo->Angles.Yaw - i*(45./16), damage, 2))
{ // hit something
if (pmo->weaponspecial >= 3)
{
pmo->weaponspecial = 0;
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState("Fire2"));
S_Sound (pmo, CHAN_VOICE, "*fistgrunt", 1, ATTN_NORM);
}
return 0;
}
}
// didn't find any creatures, so try to strike any walls
pmo->weaponspecial = 0;
DAngle slope = P_AimLineAttack (pmo, pmo->Angles.Yaw, MELEERANGE);
P_LineAttack (pmo, pmo->Angles.Yaw, MELEERANGE, slope, damage, NAME_Melee, PClass::FindActor("PunchPuff"), true);
return 0;
}

View file

@ -1,146 +0,0 @@
/*
#include "actor.h"
#include "gi.h"
#include "m_random.h"
#include "s_sound.h"
#include "d_player.h"
#include "a_action.h"
#include "p_local.h"
#include "p_pspr.h"
#include "gstrings.h"
#include "a_hexenglobal.h"
#include "a_weaponpiece.h"
#include "thingdef/thingdef.h"
*/
static FRandom pr_quietusdrop ("QuietusDrop");
static FRandom pr_fswordflame ("FSwordFlame");
//==========================================================================
//============================================================================
//
// A_DropQuietusPieces
//
//============================================================================
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DropWeaponPieces)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_CLASS(p1, AActor);
PARAM_CLASS(p2, AActor);
PARAM_CLASS(p3, AActor);
for (int i = 0, j = 0; i < 3; ++i)
{
PClassActor *cls = j == 0 ? p1 : j == 1 ? p2 : p3;
if (cls)
{
AActor *piece = Spawn (cls, self->Pos(), ALLOW_REPLACE);
if (piece != NULL)
{
piece->Vel = self->Vel + DAngle(i*120.).ToVector(1);
piece->flags |= MF_DROPPED;
j = (j == 0) ? (pr_quietusdrop() & 1) + 1 : 3-j;
}
}
}
return 0;
}
// Fighter Sword Missile ----------------------------------------------------
class AFSwordMissile : public AActor
{
DECLARE_CLASS (AFSwordMissile, AActor)
public:
int DoSpecialDamage(AActor *victim, int damage, FName damagetype);
};
IMPLEMENT_CLASS (AFSwordMissile)
int AFSwordMissile::DoSpecialDamage(AActor *victim, int damage, FName damagetype)
{
if (victim->player)
{
damage -= damage >> 2;
}
return damage;
}
//============================================================================
//
// A_FSwordAttack
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FSwordAttack)
{
PARAM_ACTION_PROLOGUE;
player_t *player;
if (NULL == (player = self->player))
{
return 0;
}
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL)
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
return 0;
}
P_SpawnPlayerMissile (self, 0, 0, -10, RUNTIME_CLASS(AFSwordMissile), self->Angles.Yaw + (45./4));
P_SpawnPlayerMissile (self, 0, 0, -5, RUNTIME_CLASS(AFSwordMissile), self->Angles.Yaw + (45./8));
P_SpawnPlayerMissile (self, 0, 0, 0, RUNTIME_CLASS(AFSwordMissile), self->Angles.Yaw);
P_SpawnPlayerMissile (self, 0, 0, 5, RUNTIME_CLASS(AFSwordMissile), self->Angles.Yaw - (45./8));
P_SpawnPlayerMissile (self, 0, 0, 10, RUNTIME_CLASS(AFSwordMissile), self->Angles.Yaw - (45./4));
S_Sound (self, CHAN_WEAPON, "FighterSwordFire", 1, ATTN_NORM);
return 0;
}
//============================================================================
//
// A_FSwordFlames
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FSwordFlames)
{
PARAM_ACTION_PROLOGUE;
int i;
for (i = 1+(pr_fswordflame()&3); i; i--)
{
double xo = (pr_fswordflame() - 128) / 16.;
double yo = (pr_fswordflame() - 128) / 16.;
double zo = (pr_fswordflame() - 128) / 8.;
Spawn ("FSwordFlame", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE);
}
return 0;
}
//============================================================================
//
// A_FighterAttack
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FighterAttack)
{
PARAM_ACTION_PROLOGUE;
if (!self->target) return 0;
P_SpawnMissileAngle(self, RUNTIME_CLASS(AFSwordMissile), self->Angles.Yaw + (45. / 4), 0);
P_SpawnMissileAngle(self, RUNTIME_CLASS(AFSwordMissile), self->Angles.Yaw + (45. / 8), 0);
P_SpawnMissileAngle(self, RUNTIME_CLASS(AFSwordMissile), self->Angles.Yaw, 0);
P_SpawnMissileAngle(self, RUNTIME_CLASS(AFSwordMissile), self->Angles.Yaw - (45. / 8), 0);
P_SpawnMissileAngle(self, RUNTIME_CLASS(AFSwordMissile), self->Angles.Yaw - (45. / 4), 0);
S_Sound (self, CHAN_WEAPON, "FighterSwordFire", 1, ATTN_NORM);
return 0;
}

View file

@ -1,248 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "p_local.h"
#include "s_sound.h"
#include "p_enemy.h"
#include "a_action.h"
#include "m_random.h"
#include "thingdef/thingdef.h"
*/
#define FIREDEMON_ATTACK_RANGE (64*8.)
static FRandom pr_firedemonrock ("FireDemonRock");
static FRandom pr_smbounce ("SMBounce");
static FRandom pr_firedemonchase ("FiredChase");
static FRandom pr_firedemonsplotch ("FiredSplotch");
//============================================================================
// Fire Demon AI
//
// special1 index into floatbob
// special2 whether strafing or not
//============================================================================
//============================================================================
//
// A_FiredSpawnRock
//
//============================================================================
void A_FiredSpawnRock (AActor *actor)
{
AActor *mo;
PClassActor *rtype;
switch (pr_firedemonrock() % 5)
{
case 0:
rtype = PClass::FindActor("FireDemonRock1");
break;
case 1:
rtype = PClass::FindActor("FireDemonRock2");
break;
case 2:
rtype = PClass::FindActor("FireDemonRock3");
break;
case 3:
rtype = PClass::FindActor("FireDemonRock4");
break;
case 4:
default:
rtype = PClass::FindActor("FireDemonRock5");
break;
}
double xo = (pr_firedemonrock() - 128) / 16.;
double yo = (pr_firedemonrock() - 128) / 16.;
double zo = pr_firedemonrock() / 32.;
mo = Spawn (rtype, actor->Vec3Offset(xo, yo, zo), ALLOW_REPLACE);
if (mo)
{
mo->target = actor;
mo->Vel.X = (pr_firedemonrock() - 128) / 64.;
mo->Vel.Y = (pr_firedemonrock() - 128) / 64.;
mo->Vel.Z = (pr_firedemonrock() / 64.);
mo->special1 = 2; // Number bounces
}
// Initialize fire demon
actor->special2 = 0;
actor->flags &= ~MF_JUSTATTACKED;
}
//============================================================================
//
// A_FiredRocks
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FiredRocks)
{
PARAM_ACTION_PROLOGUE;
A_FiredSpawnRock (self);
A_FiredSpawnRock (self);
A_FiredSpawnRock (self);
A_FiredSpawnRock (self);
A_FiredSpawnRock (self);
return 0;
}
//============================================================================
//
// A_SmBounce
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SmBounce)
{
PARAM_ACTION_PROLOGUE;
// give some more velocity (x,y,&z)
self->SetZ(self->floorz + 1);
self->Vel.Z = 2. + pr_smbounce() / 64.;
self->Vel.X = pr_smbounce() % 3;
self->Vel.Y = pr_smbounce() % 3;
return 0;
}
//============================================================================
//
// A_FiredAttack
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FiredAttack)
{
PARAM_ACTION_PROLOGUE;
if (self->target == NULL)
return 0;
AActor *mo = P_SpawnMissile (self, self->target, PClass::FindActor("FireDemonMissile"));
if (mo) S_Sound (self, CHAN_BODY, "FireDemonAttack", 1, ATTN_NORM);
return 0;
}
//============================================================================
//
// A_FiredChase
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FiredChase)
{
PARAM_ACTION_PROLOGUE;
int weaveindex = self->special1;
AActor *target = self->target;
DAngle ang;
double dist;
if (self->reactiontime) self->reactiontime--;
if (self->threshold) self->threshold--;
// Float up and down
self->AddZ(BobSin(weaveindex));
self->special1 = (weaveindex + 2) & 63;
// Ensure it stays above certain height
if (self->Z() < self->floorz + 64)
{
self->AddZ(2);
}
if(!self->target || !(self->target->flags&MF_SHOOTABLE))
{ // Invalid target
P_LookForPlayers (self,true, NULL);
return 0;
}
// Strafe
if (self->special2 > 0)
{
self->special2--;
}
else
{
self->special2 = 0;
self->Vel.X = self->Vel.Y = 0;
dist = self->Distance2D(target);
if (dist < FIREDEMON_ATTACK_RANGE)
{
if (pr_firedemonchase() < 30)
{
ang = self->AngleTo(target);
if (pr_firedemonchase() < 128)
ang += 90;
else
ang -= 90;
self->Thrust(ang, 8);
self->special2 = 3; // strafe time
}
}
}
FaceMovementDirection (self);
// Normal movement
if (!self->special2)
{
if (--self->movecount<0 || !P_Move (self))
{
P_NewChaseDir (self);
}
}
// Do missile attack
if (!(self->flags & MF_JUSTATTACKED))
{
if (P_CheckMissileRange (self) && (pr_firedemonchase() < 20))
{
self->SetState (self->MissileState);
self->flags |= MF_JUSTATTACKED;
return 0;
}
}
else
{
self->flags &= ~MF_JUSTATTACKED;
}
// make active sound
if (pr_firedemonchase() < 3)
{
self->PlayActiveSound ();
}
return 0;
}
//============================================================================
//
// A_FiredSplotch
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FiredSplotch)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
mo = Spawn ("FireDemonSplotch1", self->Pos(), ALLOW_REPLACE);
if (mo)
{
mo->Vel.X = (pr_firedemonsplotch() - 128) / 32.;
mo->Vel.Y = (pr_firedemonsplotch() - 128) / 32.;
mo->Vel.Z = (pr_firedemonsplotch() / 64.) + 3;
}
mo = Spawn ("FireDemonSplotch2", self->Pos(), ALLOW_REPLACE);
if (mo)
{
mo->Vel.X = (pr_firedemonsplotch() - 128) / 32.;
mo->Vel.Y = (pr_firedemonsplotch() - 128) / 32.;
mo->Vel.Z = (pr_firedemonsplotch() / 64.) + 3;
}
return 0;
}

View file

@ -1,455 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "a_pickups.h"
#include "a_artifacts.h"
#include "gstrings.h"
#include "p_local.h"
#include "s_sound.h"
#include "m_random.h"
#include "a_action.h"
#include "a_hexenglobal.h"
#include "w_wad.h"
#include "thingdef/thingdef.h"
#include "g_level.h"
*/
EXTERN_CVAR(Bool, sv_unlimited_pickup)
static FRandom pr_poisonbag ("PoisonBag");
static FRandom pr_poisoncloud ("PoisonCloud");
static FRandom pr_poisoncloudd ("PoisonCloudDamage");
DECLARE_ACTION(A_CheckThrowBomb)
// Poison Bag Artifact (Flechette) ------------------------------------------
IMPLEMENT_CLASS (AArtiPoisonBag)
// Poison Bag 1 (The Cleric's) ----------------------------------------------
class AArtiPoisonBag1 : public AArtiPoisonBag
{
DECLARE_CLASS (AArtiPoisonBag1, AArtiPoisonBag)
public:
bool Use (bool pickup);
};
IMPLEMENT_CLASS (AArtiPoisonBag1)
bool AArtiPoisonBag1::Use (bool pickup)
{
AActor *mo = Spawn("PoisonBag", Owner->Vec3Offset(
16 * Owner->Angles.Yaw.Cos(),
24 * Owner->Angles.Yaw.Sin(),
-Owner->Floorclip + 8), ALLOW_REPLACE);
if (mo)
{
mo->target = Owner;
return true;
}
return false;
}
// Poison Bag 2 (The Mage's) ------------------------------------------------
class AArtiPoisonBag2 : public AArtiPoisonBag
{
DECLARE_CLASS (AArtiPoisonBag2, AArtiPoisonBag)
public:
bool Use (bool pickup);
};
IMPLEMENT_CLASS (AArtiPoisonBag2)
bool AArtiPoisonBag2::Use (bool pickup)
{
AActor *mo = Spawn("FireBomb", Owner->Vec3Offset(
16 * Owner->Angles.Yaw.Cos(),
24 * Owner->Angles.Yaw.Sin(),
-Owner->Floorclip + 8), ALLOW_REPLACE);
if (mo)
{
mo->target = Owner;
return true;
}
return false;
}
// Poison Bag 3 (The Fighter's) ---------------------------------------------
class AArtiPoisonBag3 : public AArtiPoisonBag
{
DECLARE_CLASS (AArtiPoisonBag3, AArtiPoisonBag)
public:
bool Use (bool pickup);
};
IMPLEMENT_CLASS (AArtiPoisonBag3)
bool AArtiPoisonBag3::Use (bool pickup)
{
AActor *mo;
mo = Spawn("ThrowingBomb", Owner->PosPlusZ(35. - Owner->Floorclip + (Owner->player? Owner->player->crouchoffset : 0)), ALLOW_REPLACE);
if (mo)
{
mo->Angles.Yaw = Owner->Angles.Yaw + (((pr_poisonbag() & 7) - 4) * (360./256.));
/* Original flight code from Hexen
* mo->momz = 4*F.RACUNIT+((player->lookdir)<<(F.RACBITS-4));
* mo->z += player->lookdir<<(F.RACBITS-4);
* P_ThrustMobj(mo, mo->angle, mo->info->speed);
* mo->momx += player->mo->momx>>1;
* mo->momy += player->mo->momy>>1;
*/
// When looking straight ahead, it uses a z velocity of 4 while the xy velocity
// is as set by the projectile. To accommodate this with a proper trajectory, we
// aim the projectile ~20 degrees higher than we're looking at and increase the
// speed we fire at accordingly.
DAngle orgpitch = -Owner->Angles.Pitch;
DAngle modpitch = clamp<DAngle>(-Owner->Angles.Pitch + 20, -89., 89.);
DAngle angle = mo->Angles.Yaw;
double speed = DVector2(mo->Speed, 4.).Length();
double xyscale = speed * modpitch.Cos();
mo->Vel.Z = speed * modpitch.Sin();
mo->Vel.X = xyscale * angle.Cos() + Owner->Vel.X / 2;
mo->Vel.Y = xyscale * angle.Sin() + Owner->Vel.Y / 2;
mo->AddZ(mo->Speed * orgpitch.Sin());
mo->target = Owner;
mo->tics -= pr_poisonbag()&3;
P_CheckMissileSpawn(mo, Owner->radius);
return true;
}
return false;
}
// Poison Bag 4 (Generic Giver) ----------------------------------------------
class AArtiPoisonBagGiver : public AArtiPoisonBag
{
DECLARE_CLASS (AArtiPoisonBagGiver, AArtiPoisonBag)
public:
bool Use (bool pickup);
};
IMPLEMENT_CLASS (AArtiPoisonBagGiver)
bool AArtiPoisonBagGiver::Use (bool pickup)
{
PClassActor *missiletype = PClass::FindActor(this->GetClass()->MissileName);
if (missiletype != NULL)
{
AActor *mo = Spawn (missiletype, Owner->Pos(), ALLOW_REPLACE);
if (mo != NULL)
{
if (mo->IsKindOf(RUNTIME_CLASS(AInventory)))
{
AInventory *inv = static_cast<AInventory *>(mo);
if (inv->CallTryPickup(Owner))
return true;
}
mo->Destroy(); // Destroy if not inventory or couldn't be picked up
}
}
return false;
}
// Poison Bag 5 (Generic Thrower) ----------------------------------------------
class AArtiPoisonBagShooter : public AArtiPoisonBag
{
DECLARE_CLASS (AArtiPoisonBagShooter, AArtiPoisonBag)
public:
bool Use (bool pickup);
};
IMPLEMENT_CLASS (AArtiPoisonBagShooter)
bool AArtiPoisonBagShooter::Use (bool pickup)
{
PClassActor *missiletype = PClass::FindActor(this->GetClass()->MissileName);
if (missiletype != NULL)
{
AActor *mo = P_SpawnPlayerMissile(Owner, missiletype);
if (mo != NULL)
{
// automatic handling of seeker missiles
if (mo->flags2 & MF2_SEEKERMISSILE)
{
mo->tracer = Owner->target;
}
return true;
}
}
return false;
}
//============================================================================
//
// GetFlechetteType
//
//============================================================================
PClassActor *GetFlechetteType(AActor *other)
{
PClassActor *spawntype = NULL;
if (other->IsKindOf(RUNTIME_CLASS(APlayerPawn)))
{
spawntype = static_cast<APlayerPawn*>(other)->FlechetteType;
}
if (spawntype == NULL)
{
// default fallback if nothing valid defined.
spawntype = RUNTIME_CLASS(AArtiPoisonBag3);
}
return spawntype;
}
//============================================================================
//
// AArtiPoisonBag :: HandlePickup
//
//============================================================================
bool AArtiPoisonBag::HandlePickup (AInventory *item)
{
// Only do special handling when picking up the base class
if (item->GetClass() != RUNTIME_CLASS(AArtiPoisonBag))
{
return Super::HandlePickup (item);
}
if (GetClass() == GetFlechetteType(Owner))
{
if (Amount < MaxAmount || sv_unlimited_pickup)
{
Amount += item->Amount;
if (Amount > MaxAmount && !sv_unlimited_pickup)
{
Amount = MaxAmount;
}
item->ItemFlags |= IF_PICKUPGOOD;
}
return true;
}
if (Inventory != NULL)
{
return Inventory->HandlePickup (item);
}
return false;
}
//============================================================================
//
// AArtiPoisonBag :: CreateCopy
//
//============================================================================
AInventory *AArtiPoisonBag::CreateCopy (AActor *other)
{
// Only the base class gets special handling
if (GetClass() != RUNTIME_CLASS(AArtiPoisonBag))
{
return Super::CreateCopy (other);
}
AInventory *copy;
PClassActor *spawntype = GetFlechetteType(other);
copy = static_cast<AInventory *>(Spawn (spawntype));
copy->Amount = Amount;
copy->MaxAmount = MaxAmount;
GoAwayAndDie ();
return copy;
}
//============================================================================
//
// AArtiPoisonBag :: BeginPlay
//
//============================================================================
void AArtiPoisonBag::BeginPlay ()
{
Super::BeginPlay ();
// If a subclass's specific icon is not defined, let it use the base class's.
if (!Icon.isValid())
{
AInventory *defbag;
// Why doesn't this work?
//defbag = GetDefault<AArtiPoisonBag>();
defbag = (AInventory *)GetDefaultByType (RUNTIME_CLASS(AArtiPoisonBag));
Icon = defbag->Icon;
}
}
// Poison Cloud -------------------------------------------------------------
class APoisonCloud : public AActor
{
DECLARE_CLASS (APoisonCloud, AActor)
public:
int DoSpecialDamage (AActor *target, int damage, FName damagetype);
void BeginPlay ();
};
IMPLEMENT_CLASS (APoisonCloud)
void APoisonCloud::BeginPlay ()
{
Vel.X = MinVel; // missile objects must move to impact other objects
special1 = 24+(pr_poisoncloud()&7);
special2 = 0;
}
int APoisonCloud::DoSpecialDamage (AActor *victim, int damage, FName damagetype)
{
if (victim->player)
{
bool mate = (target != NULL && victim->player != target->player && victim->IsTeammate (target));
bool dopoison;
if (!mate)
{
dopoison = victim->player->poisoncount < 4;
}
else
{
dopoison = victim->player->poisoncount < (int)(4. * level.teamdamage);
}
if (dopoison)
{
int damage = 15 + (pr_poisoncloudd()&15);
if (mate)
{
damage = (int)(damage * level.teamdamage);
}
// Handle passive damage modifiers (e.g. PowerProtection)
if (victim->Inventory != NULL)
{
victim->Inventory->ModifyDamage(damage, damagetype, damage, true);
}
// Modify with damage factors
damage = victim->ApplyDamageFactor(damagetype, damage);
if (damage > 0)
{
P_PoisonDamage (victim->player, this,
15+(pr_poisoncloudd()&15), false); // Don't play painsound
// If successful, play the poison sound.
if (P_PoisonPlayer (victim->player, this, this->target, 50))
S_Sound (victim, CHAN_VOICE, "*poison", 1, ATTN_NORM);
}
}
return -1;
}
else if (!(victim->flags3 & MF3_ISMONSTER))
{ // only damage monsters/players with the poison cloud
return -1;
}
return damage;
}
//===========================================================================
//
// A_PoisonBagInit
//
//===========================================================================
DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagInit)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
mo = Spawn<APoisonCloud> (self->PosPlusZ(28.), ALLOW_REPLACE);
if (mo)
{
mo->target = self->target;
}
return 0;
}
//===========================================================================
//
// A_PoisonBagCheck
//
//===========================================================================
DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagCheck)
{
PARAM_ACTION_PROLOGUE;
if (--self->special1 <= 0)
{
self->SetState (self->FindState ("Death"));
}
else
{
return 0;
}
return 0;
}
//===========================================================================
//
// A_PoisonBagDamage
//
//===========================================================================
DEFINE_ACTION_FUNCTION(AActor, A_PoisonBagDamage)
{
PARAM_ACTION_PROLOGUE;
int bobIndex;
P_RadiusAttack (self, self->target, 4, 40, self->DamageType, RADF_HURTSOURCE);
bobIndex = self->special2;
self->AddZ(BobSin(bobIndex) / 16);
self->special2 = (bobIndex + 1) & 63;
return 0;
}
//===========================================================================
//
// A_CheckThrowBomb
//
//===========================================================================
DEFINE_ACTION_FUNCTION(AActor, A_CheckThrowBomb)
{
PARAM_ACTION_PROLOGUE;
if (--self->health <= 0)
{
self->SetState (self->FindState(NAME_Death));
}
return 0;
}
//===========================================================================
//
// A_CheckThrowBomb2
//
//===========================================================================
DEFINE_ACTION_FUNCTION(AActor, A_CheckThrowBomb2)
{
PARAM_ACTION_PROLOGUE;
// [RH] Check using actual velocity, although the vel.z < 2 check still stands
if (self->Vel.Z < 2 && self->Vel.LengthSquared() < (9./4.))
{
self->SetState (self->SpawnState + 6);
self->SetZ(self->floorz);
self->Vel.Z = 0;
self->BounceFlags = BOUNCE_None;
self->flags &= ~MF_MISSILE;
}
CALL_ACTION(A_CheckThrowBomb, self);
return 0;
}

View file

@ -1,110 +0,0 @@
static FRandom pr_fly("GetOffMeFly");
//===========================================================================
//
// FindCorpse
//
// Finds a corpse to buzz around. We can't use a blockmap check because
// corpses generally aren't linked into the blockmap.
//
//===========================================================================
static AActor *FindCorpse(AActor *fly, sector_t *sec, int recurselimit)
{
AActor *fallback = NULL;
sec->validcount = validcount;
// Search the current sector
for (AActor *check = sec->thinglist; check != NULL; check = check->snext)
{
if (check == fly)
continue;
if (!(check->flags & MF_CORPSE))
continue;
if (!P_CheckSight(fly, check))
continue;
fallback = check;
if (pr_fly(2)) // 50% chance to try to pick a different corpse
continue;
return check;
}
if (--recurselimit <= 0 || (fallback != NULL && pr_fly(2)))
{
return fallback;
}
// Try neighboring sectors
for (int i = 0; i < sec->linecount; ++i)
{
line_t *line = sec->lines[i];
sector_t *sec2 = (line->frontsector == sec) ? line->backsector : line->frontsector;
if (sec2 != NULL && sec2->validcount != validcount)
{
AActor *neighbor = FindCorpse(fly, sec2, recurselimit);
if (neighbor != NULL)
{
return neighbor;
}
}
}
return fallback;
}
DEFINE_ACTION_FUNCTION(AActor, A_FlySearch)
{
// The version from the retail beta is not so great for general use:
// 1. Pick one of the first fifty thinkers at random.
// 2. Starting from that thinker, find one that is an actor, not itself,
// and within sight. Give up after 100 sequential thinkers.
// It's effectively useless if there are more than 150 thinkers on a map.
//
// So search the sectors instead. We can't potentially find something all
// the way on the other side of the map and we can't find invisible corpses,
// but at least we aren't crippled on maps with lots of stuff going on.
PARAM_ACTION_PROLOGUE;
validcount++;
AActor *other = FindCorpse(self, self->Sector, 5);
if (other != NULL)
{
self->target = other;
self->SetState(self->FindState("Buzz"));
}
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_FlyBuzz)
{
PARAM_ACTION_PROLOGUE;
AActor *targ = self->target;
if (targ == NULL || !(targ->flags & MF_CORPSE) || pr_fly() < 5)
{
self->SetIdle();
return 0;
}
self->Angles.Yaw = self->AngleTo(targ);
self->args[0]++;
if (!P_TryMove(self, self->Pos().XY() + self->Angles.Yaw.ToVector(6), true))
{
self->SetIdle(true);
return 0;
}
if (self->args[0] & 2)
{
self->Vel.X += (pr_fly() - 128) / 512.;
self->Vel.Y += (pr_fly() - 128) / 512.;
}
int zrand = pr_fly();
if (targ->Z() + 5. < self->Z() && zrand > 150)
{
zrand = -zrand;
}
self->Vel.Z = zrand / 512.;
if (pr_fly() < 40)
{
S_Sound(self, CHAN_VOICE, self->ActiveSound, 0.5f, ATTN_STATIC);
}
return 0;
}

View file

@ -1,99 +0,0 @@
/*
#include "m_random.h"
#include "p_local.h"
#include "thingdef/thingdef.h"
*/
static FRandom pr_fogspawn ("FogSpawn");
//==========================================================================
// Fog Variables:
//
// args[0] Speed (0..10) of fog
// args[1] Angle of spread (0..128)
// args[2] Frequency of spawn (1..10)
// args[3] Lifetime countdown
// args[4] Boolean: fog moving?
// special1 Internal: Counter for spawn frequency
// WeaveIndexZ Internal: Index into floatbob table
//
//==========================================================================
//==========================================================================
//
// A_FogSpawn
//
//==========================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FogSpawn)
{
PARAM_ACTION_PROLOGUE;
static const char *fogs[3] =
{
"FogPatchSmall",
"FogPatchMedium",
"FogPatchLarge"
};
AActor *mo = NULL;
int delta;
if (self->special1-- > 0)
{
return 0;
}
self->special1 = self->args[2]; // Reset frequency count
mo = Spawn (fogs[pr_fogspawn()%3], self->Pos(), ALLOW_REPLACE);
if (mo)
{
delta = self->args[1];
if (delta==0) delta=1;
mo->Angles.Yaw = self->Angles.Yaw + (((pr_fogspawn() % delta) - (delta >> 1)) * (360 / 256.));
mo->target = self;
if (self->args[0] < 1) self->args[0] = 1;
mo->args[0] = (pr_fogspawn() % (self->args[0]))+1; // Random speed
mo->args[3] = self->args[3]; // Set lifetime
mo->args[4] = 1; // Set to moving
mo->WeaveIndexZ = pr_fogspawn()&63;
}
return 0;
}
//==========================================================================
//
// A_FogMove
//
//==========================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FogMove)
{
PARAM_ACTION_PROLOGUE;
double speed = self->args[0];
int weaveindex;
if (!self->args[4])
{
return 0;
}
if (self->args[3]-- <= 0)
{
self->SetState (self->FindState(NAME_Death), true);
return 0;
}
if ((self->args[3] % 4) == 0)
{
weaveindex = self->WeaveIndexZ;
self->AddZ(BobSin(weaveindex) / 2);
self->WeaveIndexZ = (weaveindex + 1) & 63;
}
self->VelFromAngle(speed);
return 0;
}

View file

@ -1,95 +0,0 @@
/*
#include "info.h"
#include "a_pickups.h"
#include "a_artifacts.h"
#include "gstrings.h"
#include "p_local.h"
#include "s_sound.h"
#include "m_random.h"
#include "a_action.h"
#include "a_hexenglobal.h"
#include "gi.h"
#include "doomstat.h"
*/
#define HEAL_RADIUS_DIST 255.
static FRandom pr_healradius ("HealRadius");
// Healing Radius Artifact --------------------------------------------------
class AArtiHealingRadius : public AInventory
{
DECLARE_CLASS (AArtiHealingRadius, AInventory)
public:
bool Use (bool pickup);
};
IMPLEMENT_CLASS (AArtiHealingRadius)
bool AArtiHealingRadius::Use (bool pickup)
{
bool effective = false;
FName mode;
if (Owner->IsKindOf(RUNTIME_CLASS(APlayerPawn)))
{
mode = static_cast<PClassPlayerPawn *>(Owner->GetClass())->HealingRadiusType;
}
for (int i = 0; i < MAXPLAYERS; ++i)
{
if (playeringame[i] &&
players[i].mo != NULL &&
players[i].mo->health > 0 &&
players[i].mo->Distance2D (Owner) <= HEAL_RADIUS_DIST)
{
// Q: Is it worth it to make this selectable as a player property?
// A: Probably not - but it sure doesn't hurt.
bool gotsome=false;
switch (mode)
{
case NAME_Armor:
for (int j = 0; j < 4; ++j)
{
AHexenArmor *armor = Spawn<AHexenArmor> ();
armor->health = j;
armor->Amount = 1;
if (!armor->CallTryPickup (players[i].mo))
{
armor->Destroy ();
}
else
{
gotsome = true;
}
}
break;
case NAME_Mana:
{
int amount = 50 + (pr_healradius() % 50);
if (players[i].mo->GiveAmmo (dyn_cast<PClassAmmo>(PClass::FindClass(NAME_Mana1)), amount) ||
players[i].mo->GiveAmmo (dyn_cast<PClassAmmo>(PClass::FindClass(NAME_Mana2)), amount))
{
gotsome = true;
}
break;
}
default:
//case NAME_Health:
gotsome = P_GiveBody (players[i].mo, 50 + (pr_healradius()%50));
break;
}
if (gotsome)
{
S_Sound (players[i].mo, CHAN_AUTO, "MysticIncant", 1, ATTN_NORM);
effective=true;
}
}
}
return effective;
}

View file

@ -1,968 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "p_local.h"
#include "s_sound.h"
#include "a_action.h"
#include "m_random.h"
#include "a_hexenglobal.h"
#include "i_system.h"
#include "thingdef/thingdef.h"
#include "g_level.h"
*/
//============================================================================
//
// Sorcerer stuff
//
// Sorcerer Variables
// specialf1 Angle of ball 1 (all others relative to that)
// StopBall which ball to stop at in stop mode (MT_???)
// args[0] Defense time
// args[1] Number of full rotations since stopping mode
// args[2] Target orbit speed for acceleration/deceleration
// args[3] Movement mode (see SORC_ macros)
// args[4] Current ball orbit speed
// Sorcerer Ball Variables
// specialf1 Previous angle of ball (for woosh)
// special2 Countdown of rapid fire (FX4)
//============================================================================
#define SORCBALL_INITIAL_SPEED 7
#define SORCBALL_TERMINAL_SPEED 25
#define SORCBALL_SPEED_ROTATIONS 5
#define SORC_DEFENSE_TIME 255
#define SORC_DEFENSE_HEIGHT 45
#define BOUNCE_TIME_UNIT (35/2)
#define SORCFX4_RAPIDFIRE_TIME (6*3) // 3 seconds
#define SORCFX4_SPREAD_ANGLE 20
#define SORC_DECELERATE 0
#define SORC_ACCELERATE 1
#define SORC_STOPPING 2
#define SORC_FIRESPELL 3
#define SORC_STOPPED 4
#define SORC_NORMAL 5
#define SORC_FIRING_SPELL 6
#define BALL1_ANGLEOFFSET 0.
#define BALL2_ANGLEOFFSET 120.
#define BALL3_ANGLEOFFSET 240.
void A_SlowBalls (AActor *actor);
void A_StopBalls (AActor *actor);
void A_AccelBalls (AActor *actor);
void A_DecelBalls (AActor *actor);
void A_SorcOffense2 (AActor *actor);
void A_DoBounceCheck (AActor *actor, const char *sound);
static FRandom pr_heresiarch ("Heresiarch");
// The Heresiarch him/itself ------------------------------------------------
class AHeresiarch : public AActor
{
DECLARE_CLASS (AHeresiarch, AActor)
public:
PClassActor *StopBall;
DAngle BallAngle;
void Serialize(FSerializer &arc);
void Die (AActor *source, AActor *inflictor, int dmgflags);
};
IMPLEMENT_CLASS (AHeresiarch)
void AHeresiarch::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
arc("stopball", StopBall)
("ballangle", BallAngle);
}
void AHeresiarch::Die (AActor *source, AActor *inflictor, int dmgflags)
{
// The heresiarch just executes a script instead of a special upon death
int script = special;
special = 0;
Super::Die (source, inflictor, dmgflags);
if (script != 0)
{
P_StartScript (this, NULL, script, level.MapName, NULL, 0, 0);
}
}
// Base class for the balls flying around the Heresiarch's head -------------
class ASorcBall : public AActor
{
DECLARE_CLASS (ASorcBall, AActor)
public:
virtual void DoFireSpell ();
virtual void SorcUpdateBallAngle ();
virtual void CastSorcererSpell ();
DAngle AngleOffset;
DAngle OldAngle;
void Serialize(FSerializer &arc)
{
Super::Serialize (arc);
arc("angleoffset", AngleOffset)
("oldangle", OldAngle);
}
bool SpecialBlastHandling (AActor *source, double strength)
{ // don't blast sorcerer balls
return false;
}
};
IMPLEMENT_CLASS (ASorcBall)
// First ball (purple) - fires projectiles ----------------------------------
class ASorcBall1 : public ASorcBall
{
DECLARE_CLASS (ASorcBall1, ASorcBall)
public:
void BeginPlay ()
{
Super::BeginPlay ();
AngleOffset = BALL1_ANGLEOFFSET;
}
virtual void DoFireSpell ();
virtual void SorcUpdateBallAngle ();
virtual void CastSorcererSpell ();
};
IMPLEMENT_CLASS (ASorcBall1)
// Second ball (blue) - generates the shield --------------------------------
class ASorcBall2 : public ASorcBall
{
DECLARE_CLASS (ASorcBall2, ASorcBall)
public:
void BeginPlay ()
{
Super::BeginPlay ();
AngleOffset = BALL2_ANGLEOFFSET;
}
virtual void CastSorcererSpell ();
};
IMPLEMENT_CLASS (ASorcBall2)
// Third ball (green) - summons Bishops -------------------------------------
class ASorcBall3 : public ASorcBall
{
DECLARE_CLASS (ASorcBall3, ASorcBall)
public:
void BeginPlay ()
{
Super::BeginPlay ();
AngleOffset = BALL3_ANGLEOFFSET;
}
virtual void CastSorcererSpell ();
};
IMPLEMENT_CLASS (ASorcBall3)
// Sorcerer spell 1 (The burning, bouncing head thing) ----------------------
//============================================================================
//
// SorcBall::DoFireSpell
//
//============================================================================
void ASorcBall::DoFireSpell ()
{
CastSorcererSpell ();
target->args[3] = SORC_STOPPED;
}
//============================================================================
//
// SorcBall1::DoFireSpell
//
//============================================================================
void ASorcBall1::DoFireSpell ()
{
if (pr_heresiarch() < 200)
{
S_Sound (target, CHAN_VOICE, "SorcererSpellCast", 1, ATTN_NONE);
special2 = SORCFX4_RAPIDFIRE_TIME;
args[4] = 128;
target->args[3] = SORC_FIRING_SPELL;
}
else
{
Super::DoFireSpell ();
}
}
//============================================================================
//
// A_SorcSpinBalls
//
// Spawn spinning balls above head - actor is sorcerer
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SorcSpinBalls)
{
PARAM_ACTION_PROLOGUE_TYPE(AHeresiarch);
AActor *mo;
self->SpawnState += 2; // [RH] Don't spawn balls again
A_SlowBalls(self);
self->args[0] = 0; // Currently no defense
self->args[3] = SORC_NORMAL;
self->args[4] = SORCBALL_INITIAL_SPEED; // Initial orbit speed
self->BallAngle = 1.;
DVector3 pos = self->PosPlusZ(-self->Floorclip + self->Height);
mo = Spawn("SorcBall1", pos, NO_REPLACE);
if (mo)
{
mo->target = self;
mo->special2 = SORCFX4_RAPIDFIRE_TIME;
}
mo = Spawn("SorcBall2", pos, NO_REPLACE);
if (mo) mo->target = self;
mo = Spawn("SorcBall3", pos, NO_REPLACE);
if (mo) mo->target = self;
return 0;
}
//============================================================================
//
// A_SorcBallOrbit
//
// - actor is ball
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SorcBallOrbit)
{
PARAM_ACTION_PROLOGUE_TYPE(ASorcBall);
// [RH] If no parent, then die instead of crashing
if (self->target == NULL)
{
self->SetState (self->FindState(NAME_Pain));
return 0;
}
int mode = self->target->args[3];
AHeresiarch *parent = barrier_cast<AHeresiarch *>(self->target);
double dist = parent->radius - (self->radius*2);
#if 0
// This cannot happen anymore because this is defined locally in SorcBall
if (!self->IsKindOf (RUNTIME_CLASS(ASorcBall)))
{
I_Error ("Corrupted sorcerer:\nTried to use a %s", self->GetClass()->TypeName.GetChars());
}
#endif
if (self->target->health <= 0)
{
self->SetState (self->FindState(NAME_Pain));
return 0;
}
DAngle prevangle = self->OldAngle;
DAngle baseangle = parent->BallAngle;
DAngle angle = baseangle + self->AngleOffset;
self->Angles.Yaw = angle;
switch (mode)
{
case SORC_NORMAL: // Balls rotating normally
self->SorcUpdateBallAngle ();
break;
case SORC_DECELERATE: // Balls decelerating
A_DecelBalls(self);
self->SorcUpdateBallAngle ();
break;
case SORC_ACCELERATE: // Balls accelerating
A_AccelBalls(self);
self->SorcUpdateBallAngle ();
break;
case SORC_STOPPING: // Balls stopping
if ((parent->StopBall == self->GetClass()) &&
(parent->args[1] > SORCBALL_SPEED_ROTATIONS) &&
absangle(angle, parent->Angles.Yaw) < 42.1875)
{
// Can stop now
self->target->args[3] = SORC_FIRESPELL;
self->target->args[4] = 0;
// Set angle so self angle == sorcerer angle
parent->BallAngle = parent->Angles.Yaw - self->AngleOffset;
}
else
{
self->SorcUpdateBallAngle ();
}
break;
case SORC_FIRESPELL: // Casting spell
if (parent->StopBall == self->GetClass())
{
// Put sorcerer into special throw spell anim
if (parent->health > 0)
parent->SetState (parent->FindState("Attack1"));
self->DoFireSpell ();
}
break;
case SORC_FIRING_SPELL:
if (parent->StopBall == self->GetClass())
{
if (self->special2-- <= 0)
{
// Done rapid firing
parent->args[3] = SORC_STOPPED;
// Back to orbit balls
if (parent->health > 0)
parent->SetState (parent->FindState("Attack2"));
}
else
{
// Do rapid fire spell
A_SorcOffense2(self);
}
}
break;
case SORC_STOPPED: // Balls stopped
default:
break;
}
if ( angle.BAMs() < prevangle.BAMs() && (parent->args[4]==SORCBALL_TERMINAL_SPEED))
{
parent->args[1]++; // Bump rotation counter
// Completed full rotation - make woosh sound
S_Sound (self, CHAN_BODY, "SorcererBallWoosh", 1, ATTN_NORM);
}
self->OldAngle = angle; // Set previous angle
DVector3 pos = parent->Vec3Angle(dist, angle, -parent->Floorclip + parent->Height);
self->SetOrigin (pos, true);
self->floorz = parent->floorz;
self->ceilingz = parent->ceilingz;
return 0;
}
//============================================================================
//
// A_SpeedBalls
//
// Set balls to speed mode - self is sorcerer
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SpeedBalls)
{
PARAM_ACTION_PROLOGUE;
self->args[3] = SORC_ACCELERATE; // speed mode
self->args[2] = SORCBALL_TERMINAL_SPEED; // target speed
return 0;
}
//============================================================================
//
// A_SlowBalls
//
// Set balls to slow mode - actor is sorcerer
//
//============================================================================
void A_SlowBalls(AActor *self)
{
self->args[3] = SORC_DECELERATE; // slow mode
self->args[2] = SORCBALL_INITIAL_SPEED; // target speed
}
//============================================================================
//
// A_StopBalls
//
// Instant stop when rotation gets to ball in special2
// self is sorcerer
//
//============================================================================
void A_StopBalls(AActor *scary)
{
AHeresiarch *self = static_cast<AHeresiarch *> (scary);
int chance = pr_heresiarch();
self->args[3] = SORC_STOPPING; // stopping mode
self->args[1] = 0; // Reset rotation counter
if ((self->args[0] <= 0) && (chance < 200))
{
self->StopBall = RUNTIME_CLASS(ASorcBall2); // Blue
}
else if((self->health < (self->SpawnHealth() >> 1)) &&
(chance < 200))
{
self->StopBall = RUNTIME_CLASS(ASorcBall3); // Green
}
else
{
self->StopBall = RUNTIME_CLASS(ASorcBall1); // Yellow
}
}
//============================================================================
//
// A_AccelBalls
//
// Increase ball orbit speed - actor is ball
//
//============================================================================
void A_AccelBalls(AActor *self)
{
AActor *sorc = self->target;
if (sorc->args[4] < sorc->args[2])
{
sorc->args[4]++;
}
else
{
sorc->args[3] = SORC_NORMAL;
if (sorc->args[4] >= SORCBALL_TERMINAL_SPEED)
{
// Reached terminal velocity - stop balls
A_StopBalls(sorc);
}
}
}
//============================================================================
//
// A_DecelBalls
//
// Decrease ball orbit speed - actor is ball
//
//============================================================================
void A_DecelBalls(AActor *self)
{
AActor *sorc = self->target;
if (sorc->args[4] > sorc->args[2])
{
sorc->args[4]--;
}
else
{
sorc->args[3] = SORC_NORMAL;
}
}
//============================================================================
//
// ASorcBall1::SorcUpdateBallAngle
//
// Update angle if first ball
//============================================================================
void ASorcBall1::SorcUpdateBallAngle ()
{
barrier_cast<AHeresiarch*>(target)->BallAngle += target->args[4];
}
//============================================================================
//
// ASorcBall::SorcUpdateBallAngle
//
//============================================================================
void ASorcBall::SorcUpdateBallAngle ()
{
}
//============================================================================
//
// ASorcBall::CastSorcererSpell
//
// Make noise and change the parent sorcerer's animation
//
//============================================================================
void ASorcBall::CastSorcererSpell ()
{
S_Sound (target, CHAN_VOICE, "SorcererSpellCast", 1, ATTN_NONE);
// Put sorcerer into throw spell animation
if (target->health > 0)
target->SetState (target->FindState("Attack2"));
}
//============================================================================
//
// ASorcBall2::CastSorcererSpell
//
// Defensive
//
//============================================================================
void ASorcBall2::CastSorcererSpell ()
{
Super::CastSorcererSpell ();
AActor *parent = target;
AActor *mo;
mo = Spawn("SorcFX2", PosPlusZ(parent->Floorclip + SORC_DEFENSE_HEIGHT), ALLOW_REPLACE);
parent->flags2 |= MF2_REFLECTIVE|MF2_INVULNERABLE;
parent->args[0] = SORC_DEFENSE_TIME;
if (mo) mo->target = parent;
}
//============================================================================
//
// ASorcBall3::CastSorcererSpell
//
// Reinforcements
//
//============================================================================
void ASorcBall3::CastSorcererSpell ()
{
Super::CastSorcererSpell ();
AActor *mo;
DAngle ang1, ang2;
AActor *parent = target;
ang1 = Angles.Yaw.Degrees - 45;
ang2 = Angles.Yaw.Degrees + 45;
PClassActor *cls = PClass::FindActor("SorcFX3");
if (health < (SpawnHealth()/3))
{ // Spawn 2 at a time
mo = P_SpawnMissileAngle(parent, cls, ang1, 4.);
if (mo) mo->target = parent;
mo = P_SpawnMissileAngle(parent, cls, ang2, 4.);
if (mo) mo->target = parent;
}
else
{
if (pr_heresiarch() < 128)
ang1 = ang2;
mo = P_SpawnMissileAngle(parent, cls, ang1, 4.);
if (mo) mo->target = parent;
}
}
/*
void A_SpawnReinforcements(AActor *actor)
{
AActor *parent = self->target;
AActor *mo;
DAngle ang;
ang = P_Random();
mo = P_SpawnMissileAngle(actor, MT_SORCFX3, ang, 5.);
if (mo) mo->target = parent;
}
*/
//============================================================================
//
// SorcBall1::CastSorcererSpell
//
// Offensive
//
//============================================================================
void ASorcBall1::CastSorcererSpell ()
{
Super::CastSorcererSpell ();
AActor *mo;
DAngle ang1, ang2;
AActor *parent = target;
ang1 = Angles.Yaw.Degrees + 70;
ang2 = Angles.Yaw.Degrees - 70;
PClassActor *cls = PClass::FindActor("SorcFX1");
mo = P_SpawnMissileAngle (parent, cls, ang1, 0);
if (mo)
{
mo->target = parent;
mo->tracer = parent->target;
mo->args[4] = BOUNCE_TIME_UNIT;
mo->args[3] = 15; // Bounce time in seconds
}
mo = P_SpawnMissileAngle (parent, cls, ang2, 0);
if (mo)
{
mo->target = parent;
mo->tracer = parent->target;
mo->args[4] = BOUNCE_TIME_UNIT;
mo->args[3] = 15; // Bounce time in seconds
}
}
//============================================================================
//
// A_SorcOffense2
//
// Actor is ball
//
//============================================================================
void A_SorcOffense2(AActor *self)
{
DAngle ang1;
AActor *mo;
double delta;
int index;
AActor *parent = self->target;
AActor *dest = parent->target;
double dist;
// [RH] If no enemy, then don't try to shoot.
if (dest == NULL)
{
return;
}
index = self->args[4];
self->args[4] = (self->args[4] + 15) & 255;
delta = DAngle(index * (360 / 256.f)).Sin() * SORCFX4_SPREAD_ANGLE;
ang1 = self->Angles.Yaw + delta;
mo = P_SpawnMissileAngle(parent, PClass::FindActor("SorcFX4"), ang1, 0);
if (mo)
{
mo->special2 = 35*5/2; // 5 seconds
dist = mo->DistanceBySpeed(dest, mo->Speed);
mo->Vel.Z = (dest->Z() - mo->Z()) / dist;
}
}
//============================================================================
//
// A_SorcBossAttack
//
// Resume ball spinning
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SorcBossAttack)
{
PARAM_ACTION_PROLOGUE;
self->args[3] = SORC_ACCELERATE;
self->args[2] = SORCBALL_INITIAL_SPEED;
return 0;
}
//============================================================================
//
// A_SpawnFizzle
//
// spell cast magic fizzle
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SpawnFizzle)
{
PARAM_ACTION_PROLOGUE;
int speed = (int)self->Speed;
DAngle rangle;
AActor *mo;
int ix;
DVector3 pos = self->Vec3Angle(5., self->Angles.Yaw, -self->Floorclip + self->Height / 2. );
for (ix=0; ix<5; ix++)
{
mo = Spawn("SorcSpark1", pos, ALLOW_REPLACE);
if (mo)
{
rangle = self->Angles.Yaw + (pr_heresiarch() % 5) * (4096 / 360.);
mo->Vel.X = (pr_heresiarch() % speed) * rangle.Cos();
mo->Vel.Y = (pr_heresiarch() % speed) * rangle.Sin();
mo->Vel.Z = 2;
}
}
return 0;
}
//============================================================================
//
// A_SorcFX1Seek
//
// Yellow spell - offense
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SorcFX1Seek)
{
PARAM_ACTION_PROLOGUE;
A_DoBounceCheck (self, "SorcererHeadScream");
P_SeekerMissile(self, 2, 6);
return 0;
}
//============================================================================
//
// A_SorcFX2Split
//
// Blue spell - defense
//
//============================================================================
//
// FX2 Variables
// specialf1 current angle
// special2
// args[0] 0 = CW, 1 = CCW
// args[1]
//============================================================================
// Split ball in two
DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Split)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
mo = Spawn(self->GetClass(), self->Pos(), NO_REPLACE);
if (mo)
{
mo->target = self->target;
mo->args[0] = 0; // CW
mo->specialf1 = self->Angles.Yaw.Degrees; // Set angle
mo->SetState (mo->FindState("Orbit"));
}
mo = Spawn(self->GetClass(), self->Pos(), NO_REPLACE);
if (mo)
{
mo->target = self->target;
mo->args[0] = 1; // CCW
mo->specialf1 = self->Angles.Yaw.Degrees; // Set angle
mo->SetState (mo->FindState("Orbit"));
}
self->Destroy ();
return 0;
}
//============================================================================
//
// A_SorcFX2Orbit
//
// Orbit FX2 about sorcerer
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SorcFX2Orbit)
{
PARAM_ACTION_PROLOGUE;
DAngle angle;
DVector3 pos;
AActor *parent = self->target;
// [RH] If no parent, then disappear
if (parent == NULL)
{
self->Destroy();
return 0;
}
double dist = parent->radius;
if ((parent->health <= 0) || // Sorcerer is dead
(!parent->args[0])) // Time expired
{
self->SetState (self->FindState(NAME_Death));
parent->args[0] = 0;
parent->flags2 &= ~MF2_REFLECTIVE;
parent->flags2 &= ~MF2_INVULNERABLE;
}
if (self->args[0] && (parent->args[0]-- <= 0)) // Time expired
{
self->SetState (self->FindState(NAME_Death));
parent->args[0] = 0;
parent->flags2 &= ~MF2_REFLECTIVE;
}
// Move to new position based on angle
if (self->args[0]) // Counter clock-wise
{
self->specialf1 += 10;
angle = self->specialf1;
pos = parent->Vec3Angle(dist, angle, parent->Floorclip + SORC_DEFENSE_HEIGHT);
pos.Z += 15 * angle.Cos();
// Spawn trailer
Spawn("SorcFX2T1", pos, ALLOW_REPLACE);
}
else // Clock wise
{
self->specialf1 -= 10;
angle = self->specialf1;
pos = parent->Vec3Angle(dist, angle, parent->Floorclip + SORC_DEFENSE_HEIGHT);
pos.Z += 20 * angle.Sin();
// Spawn trailer
Spawn("SorcFX2T1", pos, ALLOW_REPLACE);
}
self->SetOrigin (pos, true);
self->floorz = parent->floorz;
self->ceilingz = parent->ceilingz;
return 0;
}
//============================================================================
//
// A_SpawnBishop
//
// Green spell - spawn bishops
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SpawnBishop)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
mo = Spawn("Bishop", self->Pos(), ALLOW_REPLACE);
if (mo)
{
if (!P_TestMobjLocation(mo))
{
mo->ClearCounters();
mo->Destroy ();
}
else if (self->target != NULL)
{ // [RH] Make the new bishops inherit the Heriarch's target
mo->CopyFriendliness (self->target, true);
mo->master = self->target;
}
}
self->Destroy ();
return 0;
}
//============================================================================
//
// A_SorcererBishopEntry
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SorcererBishopEntry)
{
PARAM_ACTION_PROLOGUE;
Spawn("SorcFX3Explosion", self->Pos(), ALLOW_REPLACE);
S_Sound (self, CHAN_VOICE, self->SeeSound, 1, ATTN_NORM);
return 0;
}
//============================================================================
//
// A_SorcFX4Check
//
// FX4 - rapid fire balls
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SorcFX4Check)
{
PARAM_ACTION_PROLOGUE;
if (self->special2-- <= 0)
{
self->SetState (self->FindState(NAME_Death));
}
return 0;
}
//============================================================================
//
// A_SorcBallPop
//
// Ball death - bounce away in a random direction
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SorcBallPop)
{
PARAM_ACTION_PROLOGUE;
S_Sound (self, CHAN_BODY, "SorcererBallPop", 1, ATTN_NONE);
self->flags &= ~MF_NOGRAVITY;
self->Gravity = 1. / 8;;
self->Vel.X = ((pr_heresiarch()%10)-5);
self->Vel.Y = ((pr_heresiarch()%10)-5);
self->Vel.Z = (2+(pr_heresiarch()%3));
self->args[4] = BOUNCE_TIME_UNIT; // Bounce time unit
self->args[3] = 5; // Bounce time in seconds
return 0;
}
//============================================================================
//
// A_DoBounceCheck
//
//============================================================================
void A_DoBounceCheck (AActor *self, const char *sound)
{
if (self->args[4]-- <= 0)
{
if (self->args[3]-- <= 0)
{
self->SetState (self->FindState(NAME_Death));
S_Sound (self, CHAN_BODY, sound, 1, ATTN_NONE);
}
else
{
self->args[4] = BOUNCE_TIME_UNIT;
}
}
}
//============================================================================
//
// A_BounceCheck
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_BounceCheck)
{
PARAM_ACTION_PROLOGUE;
A_DoBounceCheck (self, "SorcererBigBallExplode");
return 0;
}

View file

@ -1,43 +0,0 @@
#ifndef __A_HEXENGLOBAL_H__
#define __A_HEXENGLOBAL_H__
#include "d_player.h"
void AdjustPlayerAngle(AActor *pmo, FTranslatedLineTarget *t);
class AHolySpirit : public AActor
{
DECLARE_CLASS (AHolySpirit, AActor)
public:
bool Slam (AActor *thing);
bool SpecialBlastHandling (AActor *source, double strength);
};
class AFighterWeapon : public AWeapon
{
DECLARE_CLASS (AFighterWeapon, AWeapon);
public:
};
class AClericWeapon : public AWeapon
{
DECLARE_CLASS (AClericWeapon, AWeapon);
public:
};
class AMageWeapon : public AWeapon
{
DECLARE_CLASS (AMageWeapon, AWeapon);
public:
};
class AArtiPoisonBag : public AInventory
{
DECLARE_CLASS (AArtiPoisonBag, AInventory)
public:
bool HandlePickup (AInventory *item);
AInventory *CreateCopy (AActor *other);
void BeginPlay ();
};
#endif //__A_HEXENGLOBAL_H__

View file

@ -1,60 +0,0 @@
#include "actor.h"
#include "info.h"
#include "p_local.h"
#include "s_sound.h"
#include "a_action.h"
#include "m_random.h"
#include "a_sharedglobal.h"
#include "a_hexenglobal.h"
#include "i_system.h"
#include "thingdef/thingdef.h"
#include "gi.h"
#include "g_level.h"
#include "p_enemy.h"
#include "a_weaponpiece.h"
#include "doomstat.h"
#include "p_lnspec.h"
#include "p_terrain.h"
#include "m_bbox.h"
#include "ravenshared.h"
#include "v_palette.h"
#include "g_game.h"
#include "p_blockmap.h"
#include "r_utility.h"
#include "p_maputl.h"
#include "p_spec.h"
#include "serializer.h"
// Include all the Hexen stuff here to reduce compile time
#include "a_bats.cpp"
#include "a_bishop.cpp"
#include "a_blastradius.cpp"
#include "a_boostarmor.cpp"
#include "a_centaur.cpp"
#include "a_clericflame.cpp"
#include "a_clericholy.cpp"
#include "a_clericmace.cpp"
#include "a_clericstaff.cpp"
#include "a_dragon.cpp"
#include "a_fighteraxe.cpp"
#include "a_fighterhammer.cpp"
#include "a_fighterplayer.cpp"
#include "a_fighterquietus.cpp"
#include "a_firedemon.cpp"
#include "a_flechette.cpp"
#include "a_flies.cpp"
#include "a_fog.cpp"
#include "a_healingradius.cpp"
#include "a_heresiarch.cpp"
#include "a_hexenspecialdecs.cpp"
#include "a_iceguy.cpp"
#include "a_korax.cpp"
#include "a_magecone.cpp"
#include "a_magelightning.cpp"
#include "a_magestaff.cpp"
#include "a_pig.cpp"
#include "a_serpent.cpp"
#include "a_spike.cpp"
#include "a_summon.cpp"
#include "a_teleportother.cpp"
#include "a_wraith.cpp"

View file

@ -1,394 +0,0 @@
/*
** Decorations that do special things
*/
/*
#include "actor.h"
#include "info.h"
#include "a_action.h"
#include "m_random.h"
#include "s_sound.h"
#include "p_local.h"
#include "p_lnspec.h"
#include "a_hexenglobal.h"
#include "thingdef/thingdef.h"
#include "g_level.h"
#include "doomstat.h"
*/
static FRandom pr_pottery ("PotteryExplode");
static FRandom pr_bit ("PotteryChooseBit");
static FRandom pr_drip ("CorpseBloodDrip");
static FRandom pr_foo ("CorpseExplode");
static FRandom pr_leaf ("LeafSpawn");
static FRandom pr_leafthrust ("LeafThrust");
static FRandom pr_leafcheck ("LeafCheck");
static FRandom pr_shroom ("PoisonShroom");
static FRandom pr_soaexplode ("SoAExplode");
// Pottery1 ------------------------------------------------------------------
void A_PotteryExplode (AActor *);
void A_PotteryChooseBit (AActor *);
void A_PotteryCheck (AActor *);
class APottery1 : public AActor
{
DECLARE_CLASS (APottery1, AActor)
public:
void HitFloor ();
};
IMPLEMENT_CLASS (APottery1)
void APottery1::HitFloor ()
{
Super::HitFloor ();
P_DamageMobj (this, NULL, NULL, 25, NAME_None);
}
//============================================================================
//
// A_PotteryExplode
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_PotteryExplode)
{
PARAM_ACTION_PROLOGUE;
AActor *mo = NULL;
int i;
for(i = (pr_pottery()&3)+3; i; i--)
{
mo = Spawn ("PotteryBit", self->Pos(), ALLOW_REPLACE);
if (mo)
{
mo->SetState (mo->SpawnState + (pr_pottery()%5));
mo->Vel.X = pr_pottery.Random2() / 64.;
mo->Vel.Y = pr_pottery.Random2() / 64.;
mo->Vel.Z = ((pr_pottery() & 7) + 5) * 0.75;
}
}
S_Sound (mo, CHAN_BODY, "PotteryExplode", 1, ATTN_NORM);
// Spawn an item?
PClassActor *type = P_GetSpawnableType(self->args[0]);
if (type != NULL)
{
if (!((level.flags2 & LEVEL2_NOMONSTERS) || (dmflags & DF_NO_MONSTERS))
|| !(GetDefaultByType (type)->flags3 & MF3_ISMONSTER))
{ // Only spawn monsters if not -nomonsters
Spawn (type, self->Pos(), ALLOW_REPLACE);
}
}
return 0;
}
//============================================================================
//
// A_PotteryChooseBit
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_PotteryChooseBit)
{
PARAM_ACTION_PROLOGUE;
self->SetState (self->FindState(NAME_Death) + 1 + 2*(pr_bit()%5));
self->tics = 256+(pr_bit()<<1);
return 0;
}
//============================================================================
//
// A_PotteryCheck
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_PotteryCheck)
{
PARAM_ACTION_PROLOGUE;
int i;
for(i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i])
{
AActor *pmo = players[i].mo;
if (P_CheckSight (self, pmo) && (absangle(pmo->AngleTo(self), pmo->Angles.Yaw) <= 45))
{ // Previous state (pottery bit waiting state)
self->SetState (self->state - 1);
return 0;
}
}
}
return 0;
}
// Lynched corpse (no heart) ------------------------------------------------
class AZCorpseLynchedNoHeart : public AActor
{
DECLARE_CLASS (AZCorpseLynchedNoHeart, AActor)
public:
void PostBeginPlay ();
};
IMPLEMENT_CLASS (AZCorpseLynchedNoHeart)
void AZCorpseLynchedNoHeart::PostBeginPlay ()
{
Super::PostBeginPlay ();
Spawn ("BloodPool", PosAtZ(floorz), ALLOW_REPLACE);
}
//============================================================================
//
// A_CorpseBloodDrip
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_CorpseBloodDrip)
{
PARAM_ACTION_PROLOGUE;
if (pr_drip() <= 128)
{
Spawn ("CorpseBloodDrip", self->PosPlusZ(self->Height / 2), ALLOW_REPLACE);
}
return 0;
}
//============================================================================
//
// A_CorpseExplode
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_CorpseExplode)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
int i;
for (i = (pr_foo()&3)+3; i; i--)
{
mo = Spawn ("CorpseBit", self->Pos(), ALLOW_REPLACE);
if (mo)
{
mo->SetState (mo->SpawnState + (pr_foo()%3));
mo->Vel.X = pr_foo.Random2() / 64.;
mo->Vel.Y = pr_foo.Random2() / 64.;
mo->Vel.Z = ((pr_foo() & 7) + 5) * 0.75;
}
}
// Spawn a skull
mo = Spawn ("CorpseBit", self->Pos(), ALLOW_REPLACE);
if (mo)
{
mo->SetState (mo->SpawnState + 3);
mo->Vel.X = pr_foo.Random2() / 64.;
mo->Vel.Y = pr_foo.Random2() / 64.;
mo->Vel.Z = ((pr_foo() & 7) + 5) * 0.75;
}
S_Sound (self, CHAN_BODY, self->DeathSound, 1, ATTN_IDLE);
self->Destroy ();
return 0;
}
//============================================================================
//
// A_LeafSpawn
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_LeafSpawn)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
int i;
for (i = (pr_leaf()&3)+1; i; i--)
{
double xo = pr_leaf.Random2() / 4.;
double yo = pr_leaf.Random2() / 4.;
double zo = pr_leaf() / 4.;
mo = Spawn (pr_leaf()&1 ? PClass::FindActor ("Leaf1") : PClass::FindActor ("Leaf2"),
self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE);
if (mo)
{
mo->Thrust(pr_leaf() / 128. + 3);
mo->target = self;
mo->special1 = 0;
}
}
return 0;
}
//============================================================================
//
// A_LeafThrust
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_LeafThrust)
{
PARAM_ACTION_PROLOGUE;
if (pr_leafthrust() <= 96)
{
self->Vel.Z += pr_leafthrust() / 128. + 1;
}
return 0;
}
//============================================================================
//
// A_LeafCheck
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_LeafCheck)
{
PARAM_ACTION_PROLOGUE;
self->special1++;
if (self->special1 >= 20)
{
self->SetState (NULL);
return 0;
}
DAngle ang = self->target ? self->target->Angles.Yaw : self->Angles.Yaw;
if (pr_leafcheck() > 64)
{
if (self->Vel.X == 0 && self->Vel.Y == 0)
{
self->Thrust(ang, pr_leafcheck() / 128. + 1);
}
return 0;
}
self->SetState (self->SpawnState + 7);
self->Vel.Z = pr_leafcheck() / 128. + 1;
self->Thrust(ang, pr_leafcheck() / 128. + 2);
self->flags |= MF_MISSILE;
return 0;
}
//===========================================================================
//
// A_PoisonShroom
//
//===========================================================================
DEFINE_ACTION_FUNCTION(AActor, A_PoisonShroom)
{
PARAM_ACTION_PROLOGUE;
self->tics = 128 + (pr_shroom() << 1);
return 0;
}
//===========================================================================
//
// A_SoAExplode - Suit of Armor Explode
//
//===========================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SoAExplode)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
int i;
for (i = 0; i < 10; i++)
{
double xo = (pr_soaexplode() - 128) / 16.;
double yo = (pr_soaexplode() - 128) / 16.;
double zo = pr_soaexplode()*self->Height / 256.;
mo = Spawn ("ZArmorChunk", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE);
if (mo)
{
mo->SetState (mo->SpawnState + i);
mo->Vel.X = pr_soaexplode.Random2() / 64.;
mo->Vel.Y = pr_soaexplode.Random2() / 64.;
mo->Vel.Z = (pr_soaexplode() & 7) + 5;
}
}
// Spawn an item?
PClassActor *type = P_GetSpawnableType(self->args[0]);
if (type != NULL)
{
if (!((level.flags2 & LEVEL2_NOMONSTERS) || (dmflags & DF_NO_MONSTERS))
|| !(GetDefaultByType (type)->flags3 & MF3_ISMONSTER))
{ // Only spawn monsters if not -nomonsters
Spawn (type, self->Pos(), ALLOW_REPLACE);
}
}
S_Sound (self, CHAN_BODY, self->DeathSound, 1, ATTN_NORM);
self->Destroy ();
return 0;
}
// Bell ---------------------------------------------------------------------
class AZBell : public AActor
{
DECLARE_CLASS (AZBell, AActor)
public:
void Activate (AActor *activator);
};
IMPLEMENT_CLASS (AZBell)
void AZBell::Activate (AActor *activator)
{
if (health > 0)
{
P_DamageMobj (this, activator, activator, 10, NAME_Melee, DMG_THRUSTLESS); // 'ring' the bell
}
}
//===========================================================================
//
// A_BellReset1
//
//===========================================================================
DEFINE_ACTION_FUNCTION(AActor, A_BellReset1)
{
PARAM_ACTION_PROLOGUE;
self->flags |= MF_NOGRAVITY;
self->Height *= 4;
if (self->special)
{ // Initiate death action
P_ExecuteSpecial(self->special, NULL, NULL, false, self->args[0],
self->args[1], self->args[2], self->args[3], self->args[4]);
self->special = 0;
}
return 0;
}
//===========================================================================
//
// A_BellReset2
//
//===========================================================================
DEFINE_ACTION_FUNCTION(AActor, A_BellReset2)
{
PARAM_ACTION_PROLOGUE;
self->flags |= MF_SHOOTABLE;
self->flags &= ~MF_CORPSE;
self->flags6 &= ~MF6_KILLED;
self->health = 5;
return 0;
}

View file

@ -1,132 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "p_local.h"
#include "s_sound.h"
#include "p_enemy.h"
#include "a_action.h"
#include "m_random.h"
#include "thingdef/thingdef.h"
*/
static FRandom pr_iceguylook ("IceGuyLook");
static FRandom pr_iceguychase ("IceGuyChase");
static const char *WispTypes[2] =
{
"IceGuyWisp1",
"IceGuyWisp2",
};
//============================================================================
//
// A_IceGuyLook
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_IceGuyLook)
{
PARAM_ACTION_PROLOGUE;
double dist;
DAngle an;
CALL_ACTION(A_Look, self);
if (pr_iceguylook() < 64)
{
dist = (pr_iceguylook() - 128) * self->radius / 128.;
an = self->Angles.Yaw + 90;
Spawn(WispTypes[pr_iceguylook() & 1], self->Vec3Angle(dist, an, 60.), ALLOW_REPLACE);
}
return 0;
}
//============================================================================
//
// A_IceGuyChase
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_IceGuyChase)
{
PARAM_ACTION_PROLOGUE;
double dist;
DAngle an;
AActor *mo;
A_Chase(stack, self);
if (pr_iceguychase() < 128)
{
dist = (pr_iceguychase() - 128) * self->radius / 128.;
an = self->Angles.Yaw + 90;
mo = Spawn(WispTypes[pr_iceguylook() & 1], self->Vec3Angle(dist, an, 60.), ALLOW_REPLACE);
if (mo)
{
mo->Vel = self->Vel;
mo->target = self;
}
}
return 0;
}
//============================================================================
//
// A_IceGuyAttack
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_IceGuyAttack)
{
PARAM_ACTION_PROLOGUE;
if(!self->target)
{
return 0;
}
P_SpawnMissileXYZ(self->Vec3Angle(self->radius / 2, self->Angles.Yaw + 90, 40.), self, self->target, PClass::FindActor("IceGuyFX"));
P_SpawnMissileXYZ(self->Vec3Angle(self->radius / 2, self->Angles.Yaw - 90, 40.), self, self->target, PClass::FindActor("IceGuyFX"));
S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM);
return 0;
}
//============================================================================
//
// A_IceGuyDie
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_IceGuyDie)
{
PARAM_ACTION_PROLOGUE;
self->Vel.Zero();
self->Height = self->GetDefault()->Height;
CALL_ACTION(A_FreezeDeathChunks, self);
return 0;
}
//============================================================================
//
// A_IceGuyMissileExplode
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_IceGuyMissileExplode)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
unsigned int i;
for (i = 0; i < 8; i++)
{
mo = P_SpawnMissileAngleZ (self, self->Z()+3, PClass::FindActor("IceGuyFX2"), DAngle(i*45.), -0.3);
if (mo)
{
mo->target = self->target;
}
}
return 0;
}

View file

@ -1,499 +0,0 @@
//===========================================================================
// Korax Variables
// tracer last teleport destination
// special2 set if "below half" script not yet run
//
// Korax Scripts (reserved)
// 249 Tell scripts that we are below half health
// 250-254 Control scripts (254 is only used when less than half health)
// 255 Death script
//
// Korax TIDs (reserved)
// 245 Reserved for Korax himself
// 248 Initial teleport destination
// 249 Teleport destination
// 250-254 For use in respective control scripts
// 255 For use in death script (spawn spots)
//===========================================================================
/*
#include "actor.h"
#include "info.h"
#include "p_local.h"
#include "p_spec.h"
#include "s_sound.h"
#include "a_action.h"
#include "m_random.h"
#include "i_system.h"
#include "thingdef/thingdef.h"
#include "g_level.h"
*/
const int KORAX_SPIRIT_LIFETIME = 5*TICRATE/5; // 5 seconds
const int KORAX_COMMAND_HEIGHT = 120;
const int KORAX_COMMAND_OFFSET = 27;
const int KORAX_TID = 245;
const int KORAX_FIRST_TELEPORT_TID = 248;
const int KORAX_TELEPORT_TID = 249;
const int KORAX_DELTAANGLE = 85;
const int KORAX_ARM_EXTENSION_SHORT = 40;
const int KORAX_ARM_EXTENSION_LONG = 55;
const int KORAX_ARM1_HEIGHT = 108;
const int KORAX_ARM2_HEIGHT = 82;
const int KORAX_ARM3_HEIGHT = 54;
const int KORAX_ARM4_HEIGHT = 104;
const int KORAX_ARM5_HEIGHT = 86;
const int KORAX_ARM6_HEIGHT = 53;
const double KORAX_BOLT_HEIGHT = 48.;
const int KORAX_BOLT_LIFETIME = 3;
static FRandom pr_koraxchase ("KoraxChase");
static FRandom pr_kspiritinit ("KSpiritInit");
static FRandom pr_koraxdecide ("KoraxDecide");
static FRandom pr_koraxmissile ("KoraxMissile");
static FRandom pr_koraxcommand ("KoraxCommand");
static FRandom pr_kspiritweave ("KSpiritWeave");
static FRandom pr_kspiritseek ("KSpiritSeek");
static FRandom pr_kspiritroam ("KSpiritRoam");
static FRandom pr_kmissile ("SKoraxMissile");
void A_KoraxChase (AActor *);
void A_KoraxStep (AActor *);
void A_KoraxStep2 (AActor *);
void A_KoraxDecide (AActor *);
void A_KoraxBonePop (AActor *);
void A_KoraxMissile (AActor *);
void A_KoraxCommand (AActor *);
void A_KSpiritRoam (AActor *);
void A_KBolt (AActor *);
void A_KBoltRaise (AActor *);
void KoraxFire (AActor *actor, PClassActor *type, int arm);
void KSpiritInit (AActor *spirit, AActor *korax);
AActor *P_SpawnKoraxMissile (const DVector3 &pos, AActor *source, AActor *dest, PClassActor *type);
extern void SpawnSpiritTail (AActor *spirit);
//============================================================================
//
// A_KoraxChase
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_KoraxChase)
{
PARAM_ACTION_PROLOGUE;
AActor *spot;
if ((!self->special2) && (self->health <= (self->SpawnHealth()/2)))
{
FActorIterator iterator (KORAX_FIRST_TELEPORT_TID);
spot = iterator.Next ();
if (spot != NULL)
{
P_Teleport (self, spot->PosAtZ(ONFLOORZ), spot->Angles.Yaw, TELF_SOURCEFOG | TELF_DESTFOG);
}
P_StartScript (self, NULL, 249, NULL, NULL, 0, 0);
self->special2 = 1; // Don't run again
return 0;
}
if (self->target == NULL)
{
return 0;
}
if (pr_koraxchase()<30)
{
self->SetState (self->MissileState);
}
else if (pr_koraxchase()<30)
{
S_Sound (self, CHAN_VOICE, "KoraxActive", 1, ATTN_NONE);
}
// Teleport away
if (self->health < (self->SpawnHealth()>>1))
{
if (pr_koraxchase()<10)
{
FActorIterator iterator (KORAX_TELEPORT_TID);
if (self->tracer != NULL)
{ // Find the previous teleport destination
do
{
spot = iterator.Next ();
} while (spot != NULL && spot != self->tracer);
}
// Go to the next teleport destination
spot = iterator.Next ();
self->tracer = spot;
if (spot)
{
P_Teleport (self, spot->PosAtZ(ONFLOORZ), spot->Angles.Yaw, TELF_SOURCEFOG | TELF_DESTFOG);
}
}
}
return 0;
}
//============================================================================
//
// A_KoraxBonePop
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_KoraxBonePop)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
int i;
// Spawn 6 spirits equalangularly
for (i = 0; i < 6; ++i)
{
mo = P_SpawnMissileAngle (self, PClass::FindActor("KoraxSpirit"), DAngle(60.*i), 5.);
if (mo)
{
KSpiritInit (mo, self);
}
}
P_StartScript (self, NULL, 255, NULL, NULL, 0, 0); // Death script
return 0;
}
//============================================================================
//
// KSpiritInit
//
//============================================================================
void KSpiritInit (AActor *spirit, AActor *korax)
{
spirit->health = KORAX_SPIRIT_LIFETIME;
spirit->tracer = korax; // Swarm around korax
spirit->WeaveIndexZ = 32 + (pr_kspiritinit() & 7); // Float bob index
spirit->args[0] = 10; // initial turn value
spirit->args[1] = 0; // initial look angle
// Spawn a tail for spirit
SpawnSpiritTail (spirit);
}
//============================================================================
//
// A_KoraxDecide
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_KoraxDecide)
{
PARAM_ACTION_PROLOGUE;
if (pr_koraxdecide()<220)
{
self->SetState (self->FindState("Attack"));
}
else
{
self->SetState (self->FindState("Command"));
}
return 0;
}
//============================================================================
//
// A_KoraxMissile
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_KoraxMissile)
{
PARAM_ACTION_PROLOGUE;
static const struct { const char *type, *sound; } choices[6] =
{
{ "WraithFX1", "WraithMissileFire" },
{ "Demon1FX1", "DemonMissileFire" },
{ "Demon2FX1", "DemonMissileFire" },
{ "FireDemonMissile", "FireDemonAttack" },
{ "CentaurFX", "CentaurLeaderAttack" },
{ "SerpentFX", "CentaurLeaderAttack" }
};
int type = pr_koraxmissile() % 6;
int i;
PClassActor *info;
S_Sound(self, CHAN_VOICE, "KoraxAttack", 1, ATTN_NORM);
info = PClass::FindActor(choices[type].type);
if (info == NULL)
{
I_Error("Unknown Korax missile: %s\n", choices[type].type);
}
// Fire all 6 missiles at once
S_Sound(self, CHAN_WEAPON, choices[type].sound, 1, ATTN_NONE);
for (i = 0; i < 6; ++i)
{
KoraxFire(self, info, i);
}
return 0;
}
//============================================================================
//
// A_KoraxCommand
//
// Call action code scripts (250-254)
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_KoraxCommand)
{
PARAM_ACTION_PROLOGUE;
DAngle ang;
int numcommands;
S_Sound (self, CHAN_VOICE, "KoraxCommand", 1, ATTN_NORM);
// Shoot stream of lightning to ceiling
ang = self->Angles.Yaw - 90;
DVector3 pos = self->Vec3Angle(KORAX_COMMAND_OFFSET, ang, KORAX_COMMAND_HEIGHT);
Spawn("KoraxBolt", pos, ALLOW_REPLACE);
if (self->health <= (self->SpawnHealth() >> 1))
{
numcommands = 5;
}
else
{
numcommands = 4;
}
P_StartScript (self, NULL, 250+(pr_koraxcommand()%numcommands), NULL, NULL, 0, 0);
return 0;
}
//============================================================================
//
// KoraxFire
//
// Arm projectiles
// arm positions numbered:
// 1 top left
// 2 middle left
// 3 lower left
// 4 top right
// 5 middle right
// 6 lower right
//
//============================================================================
void KoraxFire (AActor *actor, PClassActor *type, int arm)
{
static const int extension[6] =
{
KORAX_ARM_EXTENSION_SHORT,
KORAX_ARM_EXTENSION_LONG,
KORAX_ARM_EXTENSION_LONG,
KORAX_ARM_EXTENSION_SHORT,
KORAX_ARM_EXTENSION_LONG,
KORAX_ARM_EXTENSION_LONG
};
static const int armheight[6] =
{
KORAX_ARM1_HEIGHT,
KORAX_ARM2_HEIGHT,
KORAX_ARM3_HEIGHT,
KORAX_ARM4_HEIGHT,
KORAX_ARM5_HEIGHT,
KORAX_ARM6_HEIGHT
};
DAngle ang = actor->Angles.Yaw + (arm < 3 ? -KORAX_DELTAANGLE : KORAX_DELTAANGLE);
DVector3 pos = actor->Vec3Angle(extension[arm], ang, armheight[arm] - actor->Floorclip);
P_SpawnKoraxMissile (pos, actor, actor->target, type);
}
//============================================================================
//
// A_KSpiritSeeker
//
//============================================================================
static void A_KSpiritSeeker (AActor *actor, DAngle thresh, DAngle turnMax)
{
int dir;
DAngle delta;
AActor *target;
double newZ;
double deltaZ;
target = actor->tracer;
if (target == NULL)
{
return;
}
dir = P_FaceMobj (actor, target, &delta);
if (delta > thresh)
{
delta /= 2;
if(delta > turnMax)
{
delta = turnMax;
}
}
if(dir)
{ // Turn clockwise
actor->Angles.Yaw += delta;
}
else
{ // Turn counter clockwise
actor->Angles.Yaw -= delta;
}
actor->VelFromAngle();
if (!(level.time&15)
|| actor->Z() > target->Z() + target->GetDefault()->Height
|| actor->Top() < target->Z())
{
newZ = target->Z() + pr_kspiritseek() * target->GetDefault()->Height / 256;
deltaZ = newZ-actor->Z();
if (fabs(deltaZ) > 15)
{
if(deltaZ > 0)
{
deltaZ = 15;
}
else
{
deltaZ = -15;
}
}
actor->Vel.Z = deltaZ + actor->DistanceBySpeed(target, actor->Speed);
}
return;
}
//============================================================================
//
// A_KSpiritRoam
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_KSpiritRoam)
{
PARAM_ACTION_PROLOGUE;
if (self->health-- <= 0)
{
S_Sound (self, CHAN_VOICE, "SpiritDie", 1, ATTN_NORM);
self->SetState (self->FindState("Death"));
}
else
{
if (self->tracer)
{
A_KSpiritSeeker(self, (double)self->args[0], self->args[0] * 2.);
}
int xyspeed = (pr_kspiritweave() % 5);
int zspeed = (pr_kspiritweave() % 5);
A_Weave(self, xyspeed, zspeed, 4., 2.);
if (pr_kspiritroam()<50)
{
S_Sound (self, CHAN_VOICE, "SpiritActive", 1, ATTN_NONE);
}
}
return 0;
}
//============================================================================
//
// A_KBolt
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_KBolt)
{
PARAM_ACTION_PROLOGUE;
// Countdown lifetime
if (self->special1-- <= 0)
{
self->Destroy ();
}
return 0;
}
//============================================================================
//
// A_KBoltRaise
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_KBoltRaise)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
// Spawn a child upward
double z = self->Z() + KORAX_BOLT_HEIGHT;
if ((z + KORAX_BOLT_HEIGHT) < self->ceilingz)
{
mo = Spawn("KoraxBolt", self->PosAtZ(z), ALLOW_REPLACE);
if (mo)
{
mo->special1 = KORAX_BOLT_LIFETIME;
}
}
else
{
// Maybe cap it off here
}
return 0;
}
//============================================================================
//
// P_SpawnKoraxMissile
//
//============================================================================
AActor *P_SpawnKoraxMissile (const DVector3 &pos, AActor *source, AActor *dest, PClassActor *type)
{
AActor *th;
DAngle an;
double dist;
th = Spawn (type, pos, ALLOW_REPLACE);
th->target = source; // Originator
an = th->AngleTo(dest);
if (dest->flags & MF_SHADOW)
{ // Invisible target
an += pr_kmissile.Random2() * (45/256.);
}
th->Angles.Yaw = an;
th->VelFromAngle();
dist = dest->DistanceBySpeed(th, th->Speed);
th->Vel.Z = (dest->Z() - pos.Z + 30) / dist;
return (P_CheckMissileSpawn(th, source->radius) ? th : NULL);
}

View file

@ -1,185 +0,0 @@
/*
#include "actor.h"
#include "gi.h"
#include "m_random.h"
#include "s_sound.h"
#include "d_player.h"
#include "a_action.h"
#include "p_local.h"
#include "a_action.h"
#include "p_pspr.h"
#include "gstrings.h"
#include "a_hexenglobal.h"
#include "thingdef/thingdef.h"
*/
const int SHARDSPAWN_LEFT = 1;
const int SHARDSPAWN_RIGHT = 2;
const int SHARDSPAWN_UP = 4;
const int SHARDSPAWN_DOWN = 8;
static FRandom pr_cone ("FireConePL1");
void A_FireConePL1 (AActor *actor);
void A_ShedShard (AActor *);
// Frost Missile ------------------------------------------------------------
class AFrostMissile : public AActor
{
DECLARE_CLASS (AFrostMissile, AActor)
public:
int DoSpecialDamage (AActor *victim, int damage, FName damagetype);
};
IMPLEMENT_CLASS (AFrostMissile)
int AFrostMissile::DoSpecialDamage (AActor *victim, int damage, FName damagetype)
{
if (special2 > 0)
{
damage <<= special2;
}
return damage;
}
//============================================================================
//
// A_FireConePL1
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FireConePL1)
{
PARAM_ACTION_PROLOGUE;
DAngle angle;
int damage;
DAngle slope;
int i;
AActor *mo;
bool conedone=false;
player_t *player;
FTranslatedLineTarget t;
if (NULL == (player = self->player))
{
return 0;
}
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL)
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
return 0;
}
S_Sound (self, CHAN_WEAPON, "MageShardsFire", 1, ATTN_NORM);
damage = 90+(pr_cone()&15);
for (i = 0; i < 16; i++)
{
angle = self->Angles.Yaw + i*(45./16);
slope = P_AimLineAttack (self, angle, MELEERANGE, &t, 0., ALF_CHECK3D);
if (t.linetarget)
{
P_DamageMobj (t.linetarget, self, self, damage, NAME_Ice, DMG_USEANGLE, t.angleFromSource.Degrees);
conedone = true;
break;
}
}
// didn't find any creatures, so fire projectiles
if (!conedone)
{
mo = P_SpawnPlayerMissile (self, RUNTIME_CLASS(AFrostMissile));
if (mo)
{
mo->special1 = SHARDSPAWN_LEFT|SHARDSPAWN_DOWN|SHARDSPAWN_UP
|SHARDSPAWN_RIGHT;
mo->special2 = 3; // Set sperm count (levels of reproductivity)
mo->target = self;
mo->args[0] = 3; // Mark Initial shard as super damage
}
}
return 0;
}
//============================================================================
//
// A_ShedShard
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_ShedShard)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
int spawndir = self->special1;
int spermcount = self->special2;
if (spermcount <= 0)
{
return 0; // No sperm left
}
self->special2 = 0;
spermcount--;
// every so many calls, spawn a new missile in its set directions
if (spawndir & SHARDSPAWN_LEFT)
{
mo = P_SpawnMissileAngleZSpeed(self, self->Z(), RUNTIME_CLASS(AFrostMissile),
self->Angles.Yaw + 5, 0, (20. + 2 * spermcount), self->target);
if (mo)
{
mo->special1 = SHARDSPAWN_LEFT;
mo->special2 = spermcount;
mo->Vel.Z = self->Vel.Z;
mo->args[0] = (spermcount==3)?2:0;
}
}
if (spawndir & SHARDSPAWN_RIGHT)
{
mo = P_SpawnMissileAngleZSpeed(self, self->Z(), RUNTIME_CLASS(AFrostMissile),
self->Angles.Yaw - 5, 0, (20. + 2 * spermcount), self->target);
if (mo)
{
mo->special1 = SHARDSPAWN_RIGHT;
mo->special2 = spermcount;
mo->Vel.Z = self->Vel.Z;
mo->args[0] = (spermcount==3)?2:0;
}
}
if (spawndir & SHARDSPAWN_UP)
{
mo = P_SpawnMissileAngleZSpeed(self, self->Z() + 8., RUNTIME_CLASS(AFrostMissile),
self->Angles.Yaw, 0, (15. + 2 * spermcount), self->target);
if (mo)
{
mo->Vel.Z = self->Vel.Z;
if (spermcount & 1) // Every other reproduction
mo->special1 = SHARDSPAWN_UP | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT;
else
mo->special1 = SHARDSPAWN_UP;
mo->special2 = spermcount;
mo->args[0] = (spermcount==3)?2:0;
}
}
if (spawndir & SHARDSPAWN_DOWN)
{
mo = P_SpawnMissileAngleZSpeed(self, self->Z() - 4., RUNTIME_CLASS(AFrostMissile),
self->Angles.Yaw, 0, (15. + 2 * spermcount), self->target);
if (mo)
{
mo->Vel.Z = self->Vel.Z;
if (spermcount & 1) // Every other reproduction
mo->special1 = SHARDSPAWN_DOWN | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT;
else
mo->special1 = SHARDSPAWN_DOWN;
mo->special2 = spermcount;
mo->target = self->target;
mo->args[0] = (spermcount==3)?2:0;
}
}
return 0;
}

View file

@ -1,367 +0,0 @@
/*
#include "actor.h"
#include "gi.h"
#include "m_random.h"
#include "s_sound.h"
#include "d_player.h"
#include "a_action.h"
#include "p_local.h"
#include "a_action.h"
#include "p_pspr.h"
#include "gstrings.h"
#include "a_hexenglobal.h"
#include "thingdef/thingdef.h"
#include "g_level.h"
*/
#define ZAGSPEED 1.
static FRandom pr_lightningready ("LightningReady");
static FRandom pr_lightningclip ("LightningClip");
static FRandom pr_zap ("LightningZap");
static FRandom pr_zapf ("LightningZapF");
static FRandom pr_hit ("LightningHit");
DECLARE_ACTION(A_LightningClip)
DECLARE_ACTION(A_LightningZap)
// Lightning ----------------------------------------------------------------
class ALightning : public AActor
{
DECLARE_CLASS (ALightning, AActor)
public:
int SpecialMissileHit (AActor *victim);
};
IMPLEMENT_CLASS(ALightning)
int ALightning::SpecialMissileHit (AActor *thing)
{
if (thing->flags&MF_SHOOTABLE && thing != target)
{
if (thing->Mass != INT_MAX)
{
thing->Vel.X += Vel.X / 16;
thing->Vel.Y += Vel.Y / 16;
}
if ((!thing->player && !(thing->flags2&MF2_BOSS))
|| !(level.time&1))
{
P_DamageMobj(thing, this, target, 3, NAME_Electric);
if (!(S_IsActorPlayingSomething (this, CHAN_WEAPON, -1)))
{
S_Sound (this, CHAN_WEAPON, this->AttackSound, 1, ATTN_NORM);
}
if (thing->flags3&MF3_ISMONSTER && pr_hit() < 64)
{
thing->Howl ();
}
}
health--;
if (health <= 0 || thing->health <= 0)
{
return 0;
}
if (flags3 & MF3_FLOORHUGGER)
{
if (lastenemy && ! lastenemy->tracer)
{
lastenemy->tracer = thing;
}
}
else if (!tracer)
{
tracer = thing;
}
}
return 1; // lightning zaps through all sprites
}
// Lightning Zap ------------------------------------------------------------
class ALightningZap : public AActor
{
DECLARE_CLASS (ALightningZap, AActor)
public:
int SpecialMissileHit (AActor *thing);
};
IMPLEMENT_CLASS (ALightningZap)
int ALightningZap::SpecialMissileHit (AActor *thing)
{
AActor *lmo;
if (thing->flags&MF_SHOOTABLE && thing != target)
{
lmo = lastenemy;
if (lmo)
{
if (lmo->flags3 & MF3_FLOORHUGGER)
{
if (lmo->lastenemy && !lmo->lastenemy->tracer)
{
lmo->lastenemy->tracer = thing;
}
}
else if (!lmo->tracer)
{
lmo->tracer = thing;
}
if (!(level.time&3))
{
lmo->health--;
}
}
}
return -1;
}
//============================================================================
//
// A_LightningReady
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_LightningReady)
{
PARAM_ACTION_PROLOGUE;
DoReadyWeapon(self);
if (pr_lightningready() < 160)
{
S_Sound (self, CHAN_WEAPON, "MageLightningReady", 1, ATTN_NORM);
}
return 0;
}
//============================================================================
//
// A_LightningClip
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_LightningClip)
{
PARAM_ACTION_PROLOGUE;
AActor *cMo;
AActor *target = NULL;
int zigZag;
if (self->flags3 & MF3_FLOORHUGGER)
{
if (self->lastenemy == NULL)
{
return 0;
}
self->SetZ(self->floorz);
target = self->lastenemy->tracer;
}
else if (self->flags3 & MF3_CEILINGHUGGER)
{
self->SetZ(self->ceilingz - self->Height);
target = self->tracer;
}
if (self->flags3 & MF3_FLOORHUGGER)
{ // floor lightning zig-zags, and forces the ceiling lightning to mimic
cMo = self->lastenemy;
zigZag = pr_lightningclip();
if((zigZag > 128 && self->special1 < 2) || self->special1 < -2)
{
self->Thrust(self->Angles.Yaw + 90, ZAGSPEED);
if(cMo)
{
cMo->Thrust(self->Angles.Yaw + 90, ZAGSPEED);
}
self->special1++;
}
else
{
self->Thrust(self->Angles.Yaw - 90, ZAGSPEED);
if(cMo)
{
cMo->Thrust(self->Angles.Yaw - 90, ZAGSPEED);
}
self->special1--;
}
}
if(target)
{
if(target->health <= 0)
{
P_ExplodeMissile(self, NULL, NULL);
}
else
{
self->Angles.Yaw = self->AngleTo(target);
self->VelFromAngle(self->Speed / 2);
}
}
return 0;
}
//============================================================================
//
// A_LightningZap
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_LightningZap)
{
PARAM_ACTION_PROLOGUE;
PClassActor *lightning = PClass::FindActor(self->GetClass()->MissileName);
AActor *mo;
if (lightning == NULL)
{
lightning = PClass::FindActor(NAME_LightningZap);
}
CALL_ACTION(A_LightningClip, self);
self->health -= 8;
if (self->health <= 0)
{
self->SetState (self->FindState(NAME_Death));
return 0;
}
double deltaX = (pr_zap() - 128) * self->radius / 256;
double deltaY = (pr_zap() - 128) * self->radius / 256;
double deltaZ = (self->flags3 & MF3_FLOORHUGGER) ? 10 : -10;
mo = Spawn(lightning, self->Vec3Offset(deltaX, deltaY, deltaZ), ALLOW_REPLACE);
if (mo)
{
mo->lastenemy = self;
mo->Vel.X = self->Vel.X;
mo->Vel.Y = self->Vel.Y;
mo->Vel.Z = (self->flags3 & MF3_FLOORHUGGER) ? 20 : -20;
mo->target = self->target;
}
if ((self->flags3 & MF3_FLOORHUGGER) && pr_zapf() < 160)
{
S_Sound (self, CHAN_BODY, self->ActiveSound, 1, ATTN_NORM);
}
return 0;
}
//============================================================================
//
// A_MLightningAttack
//
//============================================================================
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MLightningAttack)
{
PARAM_ACTION_PROLOGUE;
PARAM_CLASS_OPT(floor, AActor) { floor = PClass::FindActor("LightningFloor"); }
PARAM_CLASS_OPT(ceiling, AActor) { ceiling = PClass::FindActor("LightningCeiling"); }
AActor *fmo, *cmo;
fmo = P_SpawnPlayerMissile (self, floor);
cmo = P_SpawnPlayerMissile (self, ceiling);
if (fmo)
{
fmo->special1 = 0;
fmo->lastenemy = cmo;
CALL_ACTION(A_LightningZap, fmo);
}
if (cmo)
{
cmo->tracer = NULL;
cmo->lastenemy = fmo;
CALL_ACTION(A_LightningZap, cmo);
}
S_Sound (self, CHAN_BODY, "MageLightningFire", 1, ATTN_NORM);
if (self->player != NULL)
{
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL)
{
weapon->DepleteAmmo (weapon->bAltFire);
}
}
return 0;
}
//============================================================================
//
// A_ZapMimic
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_ZapMimic)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
mo = self->lastenemy;
if (mo)
{
if (mo->state >= mo->FindState(NAME_Death))
{
P_ExplodeMissile (self, NULL, NULL);
}
else
{
self->Vel.X = mo->Vel.X;
self->Vel.Y = mo->Vel.Y;
}
}
return 0;
}
//============================================================================
//
// A_LastZap
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_LastZap)
{
PARAM_ACTION_PROLOGUE;
PClassActor *lightning = PClass::FindActor(self->GetClass()->MissileName);
AActor *mo;
if (lightning == NULL)
{
lightning = PClass::FindActor(NAME_LightningZap);
}
mo = Spawn(lightning, self->Pos(), ALLOW_REPLACE);
if (mo)
{
mo->SetState (mo->FindState (NAME_Death));
mo->Vel.Z = 40;
mo->SetDamage(0);
}
return 0;
}
//============================================================================
//
// A_LightningRemove
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_LightningRemove)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
mo = self->lastenemy;
if (mo)
{
mo->lastenemy = NULL;
P_ExplodeMissile (mo, NULL, NULL);
}
return 0;
}

View file

@ -1,265 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "p_local.h"
#include "m_random.h"
#include "s_sound.h"
#include "a_hexenglobal.h"
#include "gstrings.h"
#include "a_weaponpiece.h"
#include "thingdef/thingdef.h"
#include "doomstat.h"
*/
static FRandom pr_mstafftrack ("MStaffTrack");
static FRandom pr_bloodscourgedrop ("BloodScourgeDrop");
void A_MStaffTrack (AActor *);
void A_DropBloodscourgePieces (AActor *);
void A_MStaffAttack (AActor *actor);
void A_MStaffPalette (AActor *actor);
static AActor *FrontBlockCheck (AActor *mo, int index, void *);
static divline_t BlockCheckLine;
//==========================================================================
// The Mages's Staff (Bloodscourge) -----------------------------------------
class AMWeapBloodscourge : public AMageWeapon
{
DECLARE_CLASS (AMWeapBloodscourge, AMageWeapon)
public:
void Serialize(FSerializer &arc)
{
Super::Serialize (arc);
arc("mstaffcount", MStaffCount);
}
PalEntry GetBlend ()
{
if (paletteflash & PF_HEXENWEAPONS)
{
if (MStaffCount == 3)
return PalEntry(128, 100, 73, 0);
else if (MStaffCount == 2)
return PalEntry(128, 125, 92, 0);
else if (MStaffCount == 1)
return PalEntry(128, 150, 110, 0);
else
return PalEntry(0, 0, 0, 0);
}
else
{
return PalEntry (MStaffCount * 128 / 3, 151, 110, 0);
}
}
BYTE MStaffCount;
};
IMPLEMENT_CLASS (AMWeapBloodscourge)
// Mage Staff FX2 (Bloodscourge) --------------------------------------------
class AMageStaffFX2 : public AActor
{
DECLARE_CLASS(AMageStaffFX2, AActor)
public:
int SpecialMissileHit (AActor *victim);
bool SpecialBlastHandling (AActor *source, double strength);
};
IMPLEMENT_CLASS (AMageStaffFX2)
int AMageStaffFX2::SpecialMissileHit (AActor *victim)
{
if (victim != target &&
!victim->player &&
!(victim->flags2 & MF2_BOSS))
{
P_DamageMobj (victim, this, target, 10, NAME_Fire);
return 1; // Keep going
}
return -1;
}
bool AMageStaffFX2::SpecialBlastHandling (AActor *source, double strength)
{
// Reflect to originator
tracer = target;
target = source;
return true;
}
//============================================================================
//============================================================================
//
// MStaffSpawn
//
//============================================================================
void MStaffSpawn (AActor *pmo, DAngle angle, AActor *alttarget)
{
AActor *mo;
FTranslatedLineTarget t;
mo = P_SpawnPlayerMissile (pmo, 0, 0, 8, RUNTIME_CLASS(AMageStaffFX2), angle, &t);
if (mo)
{
mo->target = pmo;
if (t.linetarget && !t.unlinked)
mo->tracer = t.linetarget;
else
mo->tracer = alttarget;
}
}
//============================================================================
//
// A_MStaffAttack
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_MStaffAttack)
{
PARAM_ACTION_PROLOGUE;
DAngle angle;
player_t *player;
FTranslatedLineTarget t;
if (NULL == (player = self->player))
{
return 0;
}
AMWeapBloodscourge *weapon = static_cast<AMWeapBloodscourge *> (self->player->ReadyWeapon);
if (weapon != NULL)
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
return 0;
}
angle = self->Angles.Yaw;
// [RH] Let's try and actually track what the player aimed at
P_AimLineAttack (self, angle, PLAYERMISSILERANGE, &t, 32.);
if (t.linetarget == NULL)
{
BlockCheckLine.x = self->X();
BlockCheckLine.y = self->Y();
BlockCheckLine.dx = -angle.Sin();
BlockCheckLine.dy = -angle.Cos();
t.linetarget = P_BlockmapSearch (self, 10, FrontBlockCheck);
}
MStaffSpawn (self, angle, t.linetarget);
MStaffSpawn (self, angle-5, t.linetarget);
MStaffSpawn (self, angle+5, t.linetarget);
S_Sound (self, CHAN_WEAPON, "MageStaffFire", 1, ATTN_NORM);
weapon->MStaffCount = 3;
return 0;
}
//============================================================================
//
// A_MStaffPalette
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_MStaffPalette)
{
PARAM_ACTION_PROLOGUE;
if (self->player != NULL)
{
AMWeapBloodscourge *weapon = static_cast<AMWeapBloodscourge *> (self->player->ReadyWeapon);
if (weapon != NULL && weapon->MStaffCount != 0)
{
weapon->MStaffCount--;
}
}
return 0;
}
//============================================================================
//
// A_MStaffTrack
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_MStaffTrack)
{
PARAM_ACTION_PROLOGUE;
if ((self->tracer == 0) && (pr_mstafftrack()<50))
{
self->tracer = P_RoughMonsterSearch (self, 10, true);
}
P_SeekerMissile(self, 2, 10);
return 0;
}
//============================================================================
//
// FrontBlockCheck
//
// [RH] Like RoughBlockCheck, but it won't return anything behind a line.
//
//============================================================================
static AActor *FrontBlockCheck (AActor *mo, int index, void *)
{
FBlockNode *link;
for (link = blocklinks[index]; link != NULL; link = link->NextActor)
{
if (link->Me != mo)
{
if (P_PointOnDivlineSide(link->Me->X(), link->Me->Y(), &BlockCheckLine) == 0 &&
mo->IsOkayToAttack (link->Me))
{
return link->Me;
}
}
}
return NULL;
}
//============================================================================
//
// MStaffSpawn2 - for use by mage class boss
//
//============================================================================
void MStaffSpawn2 (AActor *actor, DAngle angle)
{
AActor *mo;
mo = P_SpawnMissileAngleZ (actor, actor->Z()+40, RUNTIME_CLASS(AMageStaffFX2), angle, 0.);
if (mo)
{
mo->target = actor;
mo->tracer = P_BlockmapSearch (mo, 10, FrontBlockCheck);
}
}
//============================================================================
//
// A_MStaffAttack2 - for use by mage class boss
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_MageAttack)
{
PARAM_ACTION_PROLOGUE;
if (self->target == NULL)
{
return 0;
}
DAngle angle = self->Angles.Yaw;
MStaffSpawn2(self, angle);
MStaffSpawn2(self, angle - 5);
MStaffSpawn2(self, angle + 5);
S_Sound(self, CHAN_WEAPON, "MageStaffFire", 1, ATTN_NORM);
return 0;
}

View file

@ -1,107 +0,0 @@
/*
#include "actor.h"
#include "gi.h"
#include "m_random.h"
#include "s_sound.h"
#include "d_player.h"
#include "a_action.h"
#include "a_pickups.h"
#include "p_local.h"
#include "a_sharedglobal.h"
#include "p_enemy.h"
#include "d_event.h"
#include "gstrings.h"
#include "thingdef/thingdef.h"
*/
static FRandom pr_snoutattack ("SnoutAttack");
static FRandom pr_pigattack ("PigAttack");
static FRandom pr_pigplayerthink ("PigPlayerThink");
// Pig player ---------------------------------------------------------------
class APigPlayer : public APlayerPawn
{
DECLARE_CLASS (APigPlayer, APlayerPawn)
public:
void MorphPlayerThink ();
};
IMPLEMENT_CLASS (APigPlayer)
void APigPlayer::MorphPlayerThink ()
{
if (player->morphTics & 15)
{
return;
}
if(Vel.X == 0 && Vel.Y == 0 && pr_pigplayerthink() < 64)
{ // Snout sniff
if (player->ReadyWeapon != nullptr)
{
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState("Grunt"));
}
S_Sound (this, CHAN_VOICE, "PigActive1", 1, ATTN_NORM); // snort
return;
}
if (pr_pigplayerthink() < 48)
{
S_Sound (this, CHAN_VOICE, "PigActive", 1, ATTN_NORM);
}
}
//============================================================================
//
// A_SnoutAttack
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SnoutAttack)
{
PARAM_ACTION_PROLOGUE;
DAngle angle;
int damage;
DAngle slope;
player_t *player;
AActor *puff;
FTranslatedLineTarget t;
if (NULL == (player = self->player))
{
return 0;
}
damage = 3+(pr_snoutattack()&3);
angle = player->mo->Angles.Yaw;
slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
puff = P_LineAttack(player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "SnoutPuff", true, &t);
S_Sound(player->mo, CHAN_VOICE, "PigActive", 1, ATTN_NORM);
if(t.linetarget)
{
AdjustPlayerAngle(player->mo, &t);
if(puff != NULL)
{ // Bit something
S_Sound(player->mo, CHAN_VOICE, "PigAttack", 1, ATTN_NORM);
}
}
return 0;
}
//============================================================================
//
// A_PigPain
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_PigPain)
{
PARAM_ACTION_PROLOGUE;
CALL_ACTION(A_Pain, self);
if (self->Z() <= self->floorz)
{
self->Vel.Z = 3.5;
}
return 0;
}

View file

@ -1,311 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "p_local.h"
#include "s_sound.h"
#include "p_enemy.h"
#include "a_action.h"
#include "m_random.h"
#include "p_terrain.h"
#include "thingdef/thingdef.h"
*/
static FRandom pr_serpentchase ("SerpentChase");
static FRandom pr_serpenthump ("SerpentHump");
static FRandom pr_serpentattack ("SerpentAttack");
static FRandom pr_serpentmeattack ("SerpentMeAttack");
static FRandom pr_serpentgibs ("SerpentGibs");
static FRandom pr_delaygib ("DelayGib");
//============================================================================
//
// A_SerpentUnHide
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SerpentUnHide)
{
PARAM_ACTION_PROLOGUE;
self->renderflags &= ~RF_INVISIBLE;
self->Floorclip = 24;
return 0;
}
//============================================================================
//
// A_SerpentHide
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SerpentHide)
{
PARAM_ACTION_PROLOGUE;
self->renderflags |= RF_INVISIBLE;
self->Floorclip = 0;
return 0;
}
//============================================================================
//
// A_SerpentRaiseHump
//
// Raises the hump above the surface by raising the floorclip level
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SerpentRaiseHump)
{
PARAM_ACTION_PROLOGUE;
self->Floorclip -= 4;
return 0;
}
//============================================================================
//
// A_SerpentLowerHump
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SerpentLowerHump)
{
PARAM_ACTION_PROLOGUE;
self->Floorclip += 4;
return 0;
}
//============================================================================
//
// A_SerpentHumpDecide
//
// Decided whether to hump up, or if the mobj is a serpent leader,
// to missile attack
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SerpentHumpDecide)
{
PARAM_ACTION_PROLOGUE;
if (self->MissileState != NULL)
{
if (pr_serpenthump() > 30)
{
return 0;
}
else if (pr_serpenthump() < 40)
{ // Missile attack
self->SetState (self->MeleeState);
return 0;
}
}
else if (pr_serpenthump() > 3)
{
return 0;
}
if (!self->CheckMeleeRange ())
{ // The hump shouldn't occur when within melee range
if (self->MissileState != NULL && pr_serpenthump() < 128)
{
self->SetState (self->MeleeState);
}
else
{
self->SetState (self->FindState ("Hump"));
S_Sound (self, CHAN_BODY, "SerpentActive", 1, ATTN_NORM);
}
}
return 0;
}
//============================================================================
//
// A_SerpentCheckForAttack
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SerpentCheckForAttack)
{
PARAM_ACTION_PROLOGUE;
if (!self->target)
{
return 0;
}
if (self->MissileState != NULL)
{
if (!self->CheckMeleeRange ())
{
self->SetState (self->FindState ("Attack"));
return 0;
}
}
if (P_CheckMeleeRange2 (self))
{
self->SetState (self->FindState ("Walk"));
}
else if (self->CheckMeleeRange ())
{
if (pr_serpentattack() < 32)
{
self->SetState (self->FindState ("Walk"));
}
else
{
self->SetState (self->FindState ("Attack"));
}
}
return 0;
}
//============================================================================
//
// A_SerpentChooseAttack
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SerpentChooseAttack)
{
PARAM_ACTION_PROLOGUE;
if (!self->target || self->CheckMeleeRange())
{
return 0;
}
if (self->MissileState != NULL)
{
self->SetState (self->MissileState);
}
return 0;
}
//============================================================================
//
// A_SerpentMeleeAttack
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SerpentMeleeAttack)
{
PARAM_ACTION_PROLOGUE;
if (!self->target)
{
return 0;
}
if (self->CheckMeleeRange ())
{
int damage = pr_serpentmeattack.HitDice (5);
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
S_Sound (self, CHAN_BODY, "SerpentMeleeHit", 1, ATTN_NORM);
}
if (pr_serpentmeattack() < 96)
{
CALL_ACTION(A_SerpentCheckForAttack, self);
}
return 0;
}
//============================================================================
//
// A_SerpentSpawnGibs
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SerpentSpawnGibs)
{
PARAM_ACTION_PROLOGUE;
AActor *mo;
static const char *GibTypes[] =
{
"SerpentGib3",
"SerpentGib2",
"SerpentGib1"
};
for (int i = countof(GibTypes)-1; i >= 0; --i)
{
double x = (pr_serpentgibs() - 128) / 16.;
double y = (pr_serpentgibs() - 128) / 16.;
mo = Spawn (GibTypes[i], self->Vec2OffsetZ(x, y, self->floorz + 1), ALLOW_REPLACE);
if (mo)
{
mo->Vel.X = (pr_serpentgibs() - 128) / 1024.f;
mo->Vel.Y = (pr_serpentgibs() - 128) / 1024.f;
mo->Floorclip = 6;
}
}
return 0;
}
//============================================================================
//
// A_FloatGib
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FloatGib)
{
PARAM_ACTION_PROLOGUE;
self->Floorclip -= 1;
return 0;
}
//============================================================================
//
// A_SinkGib
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SinkGib)
{
PARAM_ACTION_PROLOGUE;
self->Floorclip += 1;;
return 0;
}
//============================================================================
//
// A_DelayGib
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_DelayGib)
{
PARAM_ACTION_PROLOGUE;
self->tics -= pr_delaygib()>>2;
return 0;
}
//============================================================================
//
// A_SerpentHeadCheck
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SerpentHeadCheck)
{
PARAM_ACTION_PROLOGUE;
if (self->Z() <= self->floorz)
{
if (Terrains[P_GetThingFloorType(self)].IsLiquid)
{
P_HitFloor (self);
self->SetState (NULL);
}
else
{
self->SetState (self->FindState(NAME_Death));
}
}
return 0;
}

View file

@ -1,187 +0,0 @@
/*
#include "actor.h"
#include "info.h"
#include "m_random.h"
#include "p_enemy.h"
#include "p_local.h"
#include "a_sharedglobal.h"
#include "s_sound.h"
#include "m_bbox.h"
#include "thingdef/thingdef.h"
*/
static FRandom pr_thrustraise ("ThrustRaise");
// Spike (thrust floor) -----------------------------------------------------
// AThrustFloor is just a container for all the spike states.
// All the real spikes subclass it.
class AThrustFloor : public AActor
{
DECLARE_CLASS (AThrustFloor, AActor)
HAS_OBJECT_POINTERS
public:
void Serialize(FSerializer &arc);
void Activate (AActor *activator);
void Deactivate (AActor *activator);
TObjPtr<AActor> DirtClump;
};
IMPLEMENT_POINTY_CLASS (AThrustFloor)
DECLARE_POINTER (DirtClump)
END_POINTERS
void AThrustFloor::Serialize(FSerializer &arc)
{
Super::Serialize (arc);
arc("dirtclump", DirtClump);
}
void AThrustFloor::Activate (AActor *activator)
{
if (args[0] == 0)
{
S_Sound (this, CHAN_BODY, "ThrustSpikeLower", 1, ATTN_NORM);
renderflags &= ~RF_INVISIBLE;
if (args[1])
SetState (FindState ("BloodThrustRaise"));
else
SetState (FindState ("ThrustRaise"));
}
}
void AThrustFloor::Deactivate (AActor *activator)
{
if (args[0] == 1)
{
S_Sound (this, CHAN_BODY, "ThrustSpikeRaise", 1, ATTN_NORM);
if (args[1])
SetState (FindState ("BloodThrustLower"));
else
SetState (FindState ("ThrustLower"));
}
}
//===========================================================================
//
// Thrust floor stuff
//
// Thrust Spike Variables
// DirtClump pointer to dirt clump actor
// special2 speed of raise
// args[0] 0 = lowered, 1 = raised
// args[1] 0 = normal, 1 = bloody
//===========================================================================
DEFINE_ACTION_FUNCTION(AActor, A_ThrustInitUp)
{
PARAM_ACTION_PROLOGUE;
self->special2 = 5; // Raise speed
self->args[0] = 1; // Mark as up
self->Floorclip = 0;
self->flags = MF_SOLID;
self->flags2 = MF2_NOTELEPORT|MF2_FLOORCLIP;
self->special1 = 0L;
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_ThrustInitDn)
{
PARAM_ACTION_PROLOGUE;
self->special2 = 5; // Raise speed
self->args[0] = 0; // Mark as down
self->Floorclip = self->GetDefault()->Height;
self->flags = 0;
self->flags2 = MF2_NOTELEPORT|MF2_FLOORCLIP;
self->renderflags = RF_INVISIBLE;
static_cast<AThrustFloor *>(self)->DirtClump =
Spawn("DirtClump", self->Pos(), ALLOW_REPLACE);
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_ThrustRaise)
{
PARAM_ACTION_PROLOGUE;
AThrustFloor *actor = static_cast<AThrustFloor *>(self);
if (A_RaiseMobj (actor, self->special2))
{ // Reached it's target height
actor->args[0] = 1;
if (actor->args[1])
actor->SetState (actor->FindState ("BloodThrustInit2"), true);
else
actor->SetState (actor->FindState ("ThrustInit2"), true);
}
// Lose the dirt clump
if ((actor->Floorclip < actor->Height) && actor->DirtClump)
{
actor->DirtClump->Destroy ();
actor->DirtClump = NULL;
}
// Spawn some dirt
if (pr_thrustraise()<40)
P_SpawnDirt (actor, actor->radius);
actor->special2++; // Increase raise speed
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_ThrustLower)
{
PARAM_ACTION_PROLOGUE;
if (A_SinkMobj (self, 6))
{
self->args[0] = 0;
if (self->args[1])
self->SetState (self->FindState ("BloodThrustInit1"), true);
else
self->SetState (self->FindState ("ThrustInit1"), true);
}
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_ThrustImpale)
{
PARAM_ACTION_PROLOGUE;
// This doesn't need to iterate through portals.
FPortalGroupArray check;
FMultiBlockThingsIterator it(check, self);
FMultiBlockThingsIterator::CheckResult cres;
while (it.Next(&cres))
{
double blockdist = self->radius + cres.thing->radius;
if (fabs(cres.thing->X() - cres.Position.X) >= blockdist || fabs(cres.thing->Y() - cres.Position.Y) >= blockdist)
continue;
// Q: Make this z-aware for everything? It never was before.
if (cres.thing->Top() < self->Z() || cres.thing->Z() > self->Top())
{
if (self->Sector->PortalGroup != cres.thing->Sector->PortalGroup)
continue;
}
if (!(cres.thing->flags & MF_SHOOTABLE) )
continue;
if (cres.thing == self)
continue; // don't clip against self
int newdam = P_DamageMobj (cres.thing, self, self, 10001, NAME_Crush);
P_TraceBleed (newdam > 0 ? newdam : 10001, cres.thing);
self->args[1] = 1; // Mark thrust thing as bloody
}
return 0;
}

View file

@ -1,85 +0,0 @@
/*
#include "info.h"
#include "a_pickups.h"
#include "a_artifacts.h"
#include "gstrings.h"
#include "p_local.h"
#include "s_sound.h"
#include "ravenshared.h"
#include "thingdef/thingdef.h"
#include "g_level.h"
*/
void A_Summon (AActor *);
// Dark Servant Artifact ----------------------------------------------------
class AArtiDarkServant : public AInventory
{
DECLARE_CLASS (AArtiDarkServant, AInventory)
public:
bool Use (bool pickup);
};
IMPLEMENT_CLASS (AArtiDarkServant)
//============================================================================
//
// Activate the summoning artifact
//
//============================================================================
bool AArtiDarkServant::Use (bool pickup)
{
AActor *mo = P_SpawnPlayerMissile (Owner, PClass::FindActor("SummoningDoll"));
if (mo)
{
mo->target = Owner;
mo->tracer = Owner;
mo->Vel.Z = 5;
}
return true;
}
//============================================================================
//
// A_Summon
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_Summon)
{
PARAM_ACTION_PROLOGUE;
AMinotaurFriend *mo;
mo = Spawn<AMinotaurFriend>(self->Pos(), ALLOW_REPLACE);
if (mo)
{
if (P_TestMobjLocation(mo) == false || !self->tracer)
{ // Didn't fit - change back to artifact
mo->Destroy();
AActor *arti = Spawn<AArtiDarkServant>(self->Pos(), ALLOW_REPLACE);
if (arti) arti->flags |= MF_DROPPED;
return 0;
}
mo->StartTime = level.maptime;
if (self->tracer->flags & MF_CORPSE)
{ // Master dead
mo->tracer = NULL; // No master
}
else
{
mo->tracer = self->tracer; // Pointer to master
AInventory *power = Spawn<APowerMinotaur>();
power->CallTryPickup(self->tracer);
mo->SetFriendPlayer(self->tracer->player);
}
// Make smoke puff
Spawn("MinotaurSmoke", self->Pos(), ALLOW_REPLACE);
S_Sound(self, CHAN_VOICE, mo->ActiveSound, 1, ATTN_NORM);
}
return 0;
}

View file

@ -1,198 +0,0 @@
/*
#include "info.h"
#include "a_pickups.h"
#include "a_artifacts.h"
#include "gstrings.h"
#include "p_local.h"
#include "s_sound.h"
#include "p_lnspec.h"
#include "m_random.h"
#include "thingdef/thingdef.h"
#include "g_level.h"
#include "doomstat.h"
*/
#define TELEPORT_LIFE 1
static FRandom pr_telestarts ("TeleStarts");
static FRandom pr_teledm ("TeleDM");
void A_TeloSpawnA (AActor *);
void A_TeloSpawnB (AActor *);
void A_TeloSpawnC (AActor *);
void A_TeloSpawnD (AActor *);
void A_CheckTeleRing (AActor *);
void P_TeleportToPlayerStarts (AActor *victim);
void P_TeleportToDeathmatchStarts (AActor *victim);
// Teleport Other Artifact --------------------------------------------------
class AArtiTeleportOther : public AInventory
{
DECLARE_CLASS (AArtiTeleportOther, AInventory)
public:
bool Use (bool pickup);
};
IMPLEMENT_CLASS (AArtiTeleportOther)
// Teleport Other FX --------------------------------------------------------
class ATelOtherFX1 : public AActor
{
DECLARE_CLASS (ATelOtherFX1, AActor)
public:
int DoSpecialDamage (AActor *target, int damage, FName damagetype);
};
IMPLEMENT_CLASS (ATelOtherFX1)
static void TeloSpawn (AActor *source, const char *type)
{
AActor *fx;
fx = Spawn (type, source->Pos(), ALLOW_REPLACE);
if (fx)
{
fx->special1 = TELEPORT_LIFE; // Lifetime countdown
fx->Angles.Yaw = source->Angles.Yaw;
fx->target = source->target;
fx->Vel = source->Vel / 2;
}
}
DEFINE_ACTION_FUNCTION(AActor, A_TeloSpawnA)
{
PARAM_ACTION_PROLOGUE;
TeloSpawn (self, "TelOtherFX2");
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_TeloSpawnB)
{
PARAM_ACTION_PROLOGUE;
TeloSpawn (self, "TelOtherFX3");
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_TeloSpawnC)
{
PARAM_ACTION_PROLOGUE;
TeloSpawn (self, "TelOtherFX4");
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_TeloSpawnD)
{
PARAM_ACTION_PROLOGUE;
TeloSpawn (self, "TelOtherFX5");
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_CheckTeleRing)
{
PARAM_ACTION_PROLOGUE;
if (self->special1-- <= 0)
{
self->SetState (self->FindState(NAME_Death));
}
return 0;
}
//===========================================================================
//
// Activate Teleport Other
//
//===========================================================================
bool AArtiTeleportOther::Use (bool pickup)
{
AActor *mo;
mo = P_SpawnPlayerMissile (Owner, RUNTIME_CLASS(ATelOtherFX1));
if (mo)
{
mo->target = Owner;
}
return true;
}
//===========================================================================
//
// Perform Teleport Other
//
//===========================================================================
int ATelOtherFX1::DoSpecialDamage (AActor *target, int damage, FName damagetype)
{
if ((target->flags3 & MF3_ISMONSTER || target->player != NULL) &&
!(target->flags2 & MF2_BOSS) &&
!(target->flags3 & MF3_NOTELEOTHER))
{
if (target->player)
{
if (deathmatch)
P_TeleportToDeathmatchStarts (target);
else
P_TeleportToPlayerStarts (target);
}
else
{
// If death action, run it upon teleport
if (target->flags3 & MF3_ISMONSTER && target->special)
{
target->RemoveFromHash ();
P_ExecuteSpecial(target->special, NULL, level.flags & LEVEL_ACTOWNSPECIAL
? target : (AActor *)(this->target), false, target->args[0], target->args[1],
target->args[2], target->args[3], target->args[4]);
target->special = 0;
}
// Send all monsters to deathmatch spots
P_TeleportToDeathmatchStarts (target);
}
}
return -1;
}
//===========================================================================
//
// P_TeleportToPlayerStarts
//
//===========================================================================
void P_TeleportToPlayerStarts (AActor *victim)
{
DVector3 dest;
FPlayerStart *start = G_PickPlayerStart(0, PPS_FORCERANDOM | PPS_NOBLOCKINGCHECK);
dest = start->pos;
dest.Z = ONFLOORZ;
P_Teleport (victim, dest, (double)start->angle, TELF_SOURCEFOG | TELF_DESTFOG);
}
//===========================================================================
//
// P_TeleportToDeathmatchStarts
//
//===========================================================================
void P_TeleportToDeathmatchStarts (AActor *victim)
{
unsigned int i, selections;
DVector3 dest;
selections = deathmatchstarts.Size ();
if (selections > 0)
{
i = pr_teledm() % selections;
dest = deathmatchstarts[i].pos;
dest.Z = ONFLOORZ;
P_Teleport (victim, dest, (double)deathmatchstarts[i].angle, TELF_SOURCEFOG | TELF_DESTFOG);
}
else
{
P_TeleportToPlayerStarts (victim);
}
}

Some files were not shown because too many files have changed in this diff Show more