mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-25 21:51:09 +00:00
Merge branch 'gz-zscript'
This commit is contained in:
commit
c3fb43db3a
701 changed files with 75689 additions and 59344 deletions
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
78
src/actor.h
78
src/actor.h
|
@ -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.
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 ()
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"))
|
||||
{
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -124,7 +124,8 @@ public:
|
|||
int PolyNum;
|
||||
int SideNum;
|
||||
};
|
||||
IMPLEMENT_CLASS(DSectorMarker)
|
||||
|
||||
IMPLEMENT_CLASS(DSectorMarker, false, false)
|
||||
|
||||
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
||||
|
||||
|
|
1241
src/dobjtype.cpp
1241
src/dobjtype.cpp
File diff suppressed because it is too large
Load diff
285
src/dobjtype.h
285
src/dobjtype.h
|
@ -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 ---------------------------------------------------------
|
||||
|
||||
|
|
|
@ -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];
|
||||
};
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 ()
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
231
src/dthinker.cpp
231
src/dthinker.cpp
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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])));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -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
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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__
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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__
|
|
@ -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"
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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
Loading…
Reference in a new issue