diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 617b4c2401..ec8c1c09d4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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) diff --git a/src/__autostart.cpp b/src/__autostart.cpp index 280c3b13d3..13e104d753 100644 --- a/src/__autostart.cpp +++ b/src/__autostart.cpp @@ -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; diff --git a/src/actor.h b/src/actor.h index 800548d2c1..03891c8ba5 100644 --- a/src/actor.h +++ b/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. }; diff --git a/src/am_map.cpp b/src/am_map.cpp index 70153404a7..8fb46ed6b9 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -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 it (STAT_MAPMARKER); - AMapMarker *mark; + TThinkerIterator it ("MapMarker", STAT_MAPMARKER); + AActor *mark; while ((mark = it.Next()) != NULL) { diff --git a/src/autosegs.h b/src/autosegs.h index 08abe7cd31..f38e3628e9 100644 --- a/src/autosegs.h +++ b/src/autosegs.h @@ -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; diff --git a/src/b_bot.cpp b/src/b_bot.cpp index c4d702c8ec..3f4d0c592b 100644 --- a/src/b_bot.cpp +++ b/src/b_bot.cpp @@ -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) diff --git a/src/b_think.cpp b/src/b_think.cpp index d097db8640..e41433fa30 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -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"); diff --git a/src/c_console.cpp b/src/c_console.cpp index 3064abb0d2..691c4a3ca7 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -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 diff --git a/src/c_cvars.cpp b/src/c_cvars.cpp index c8f1ee4c62..fe859cb49c 100644 --- a/src/c_cvars.cpp +++ b/src/c_cvars.cpp @@ -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 diff --git a/src/c_cvars.h b/src/c_cvars.h index be7676e895..cf6975b866 100644 --- a/src/c_cvars.h +++ b/src/c_cvars.h @@ -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); diff --git a/src/c_dispatch.cpp b/src/c_dispatch.cpp index c3fc9bae11..d112634d6a 100644 --- a/src/c_dispatch.cpp +++ b/src/c_dispatch.cpp @@ -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 () { diff --git a/src/cmdlib.cpp b/src/cmdlib.cpp index 3a3d2876de..266ef47beb 100644 --- a/src/cmdlib.cpp +++ b/src/cmdlib.cpp @@ -15,6 +15,7 @@ #include "cmdlib.h" #include "i_system.h" #include "v_text.h" +#include "sc_man.h" #include #include @@ -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; diff --git a/src/cmdlib.h b/src/cmdlib.h index b035842cdf..6e9fcd622f 100644 --- a/src/cmdlib.h +++ b/src/cmdlib.h @@ -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); diff --git a/src/ct_chat.cpp b/src/ct_chat.cpp index 3c0994a3b4..0a92a58b9c 100644 --- a/src/ct_chat.cpp +++ b/src/ct_chat.cpp @@ -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 diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index dd71fdf756..ed2310d459 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -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 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 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(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(FName(MBFCodePointers[codepointer].name), true)); + sym = dyn_cast(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(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(symname, true)); + PFunction *sym = dyn_cast(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 &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(RUNTIME_CLASS(AInventory)->Symbols.FindSymbol(name, true)); + PFunction *sym = dyn_cast(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 &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(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; } diff --git a/src/d_dehacked.h b/src/d_dehacked.h index 564a6d499b..434853bf22 100644 --- a/src/d_dehacked.h +++ b/src/d_dehacked.h @@ -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); diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index 1fc63e03d3..b80cbaf988 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -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")) { diff --git a/src/d_main.cpp b/src/d_main.cpp index 1f9fcdbcab..0f2d5af92b 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -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 &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 // diff --git a/src/d_net.cpp b/src/d_net.cpp index 2611338679..4bda255103 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -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) diff --git a/src/d_player.h b/src/d_player.h index 7f57837c70..81a1c43a69 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -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 diff --git a/src/decallib.cpp b/src/decallib.cpp index fc7e465dc6..5d24e44d51 100644 --- a/src/decallib.cpp +++ b/src/decallib.cpp @@ -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) { diff --git a/src/dobject.cpp b/src/dobject.cpp index 4acb86ce40..6b973de336 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -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) { diff --git a/src/dobject.h b/src/dobject.h index 91a80f9d07..ed9c0fffa9 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -36,6 +36,7 @@ #include #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 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. diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index afdc755083..827516172e 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -124,7 +124,8 @@ public: int PolyNum; int SideNum; }; -IMPLEMENT_CLASS(DSectorMarker) + +IMPLEMENT_CLASS(DSectorMarker, false, false) // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 37ff26fe30..ae26bc37dc 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -45,10 +45,13 @@ #include "autosegs.h" #include "v_text.h" #include "a_pickups.h" +#include "a_artifacts.h" #include "a_weaponpiece.h" #include "d_player.h" #include "doomerrors.h" #include "fragglescript/t_fs.h" +#include "a_keys.h" +#include "a_health.h" // MACROS ------------------------------------------------------------------ @@ -71,6 +74,7 @@ TArray PClass::AllClasses; bool PClass::bShutdown; PErrorType *TypeError; +PErrorType *TypeAuto; PVoidType *TypeVoid; PInt *TypeSInt8, *TypeUInt8; PInt *TypeSInt16, *TypeUInt16; @@ -81,7 +85,15 @@ PString *TypeString; PName *TypeName; PSound *TypeSound; PColor *TypeColor; +PTextureID *TypeTextureID; +PSpriteID *TypeSpriteID; PStatePointer *TypeState; +PStateLabel *TypeStateLabel; +PStruct *TypeVector2; +PStruct *TypeVector3; +PStruct *TypeColorStruct; +PStruct *TypeStringStruct; +PPointer *TypeNullPtr; // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -90,8 +102,8 @@ static const size_t TheEnd = ~(size_t)0; // CODE -------------------------------------------------------------------- -IMPLEMENT_CLASS(PErrorType) -IMPLEMENT_CLASS(PVoidType) +IMPLEMENT_CLASS(PErrorType, false, false) +IMPLEMENT_CLASS(PVoidType, false, false) void DumpTypeTable() { @@ -138,7 +150,7 @@ void DumpTypeTable() /* PClassType *************************************************************/ -IMPLEMENT_CLASS(PClassType) +IMPLEMENT_CLASS(PClassType, false, false) //========================================================================== // @@ -153,20 +165,20 @@ PClassType::PClassType() //========================================================================== // -// PClassType :: Derive +// PClassType :: DeriveData // //========================================================================== -void PClassType::Derive(PClass *newclass) +void PClassType::DeriveData(PClass *newclass) { assert(newclass->IsKindOf(RUNTIME_CLASS(PClassType))); - Super::Derive(newclass); + Super::DeriveData(newclass); static_cast(newclass)->TypeTableType = TypeTableType; } /* PClassClass ************************************************************/ -IMPLEMENT_CLASS(PClassClass) +IMPLEMENT_CLASS(PClassClass, false, false) //========================================================================== // @@ -184,20 +196,11 @@ PClassClass::PClassClass() /* PType ******************************************************************/ -IMPLEMENT_ABSTRACT_POINTY_CLASS(PType) - DECLARE_POINTER(HashNext) -END_POINTERS +IMPLEMENT_CLASS(PType, true, true) -//========================================================================== -// -// PType Default Constructor -// -//========================================================================== - -PType::PType() -: Size(0), Align(1), HashNext(NULL) -{ -} +IMPLEMENT_POINTERS_START(PType) + IMPLEMENT_POINTER(HashNext) +IMPLEMENT_POINTERS_END //========================================================================== // @@ -208,6 +211,12 @@ PType::PType() PType::PType(unsigned int size, unsigned int align) : Size(size), Align(align), HashNext(NULL) { + mDescriptiveName = "Type"; + loadOp = OP_NOP; + storeOp = OP_NOP; + moveOp = OP_NOP; + RegType = REGT_NIL; + RegCount = 1; } //========================================================================== @@ -418,6 +427,16 @@ void PType::SetDefaultValue(void *base, unsigned offset, TArray { } +//========================================================================== +// +// PType :: SetDefaultValue +// +//========================================================================== + +void PType::SetPointer(void *base, unsigned offset, TArray *stroffs) const +{ +} + //========================================================================== // // PType :: InitializeValue @@ -472,42 +491,6 @@ double PType::GetValueFloat(void *addr) const return 0; } -//========================================================================== -// -// PType :: GetStoreOp -// -//========================================================================== - -int PType::GetStoreOp() const -{ - assert(0 && "Cannot store this type"); - return OP_NOP; -} - -//========================================================================== -// -// PType :: GetLoadOp -// -//========================================================================== - -int PType::GetLoadOp() const -{ - assert(0 && "Cannot load this type"); - return OP_NOP; -} - -//========================================================================== -// -// PType :: GetRegType -// -//========================================================================== - -int PType::GetRegType() const -{ - assert(0 && "No register for this type"); - return REGT_NIL; -} - //========================================================================== // // PType :: IsMatch @@ -531,6 +514,17 @@ void PType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const id2 = 0; } +//========================================================================== +// +// PType :: GetTypeIDs +// +//========================================================================== + +const char *PType::DescriptiveName() const +{ + return mDescriptiveName.GetChars(); +} + //========================================================================== // // PType :: StaticInit STATIC @@ -559,21 +553,25 @@ void PType::StaticInit() RUNTIME_CLASS(PString)->TypeTableType = RUNTIME_CLASS(PString); RUNTIME_CLASS(PName)->TypeTableType = RUNTIME_CLASS(PName); RUNTIME_CLASS(PSound)->TypeTableType = RUNTIME_CLASS(PSound); + RUNTIME_CLASS(PSpriteID)->TypeTableType = RUNTIME_CLASS(PSpriteID); + RUNTIME_CLASS(PTextureID)->TypeTableType = RUNTIME_CLASS(PTextureID); RUNTIME_CLASS(PColor)->TypeTableType = RUNTIME_CLASS(PColor); RUNTIME_CLASS(PPointer)->TypeTableType = RUNTIME_CLASS(PPointer); RUNTIME_CLASS(PClassPointer)->TypeTableType = RUNTIME_CLASS(PClassPointer); RUNTIME_CLASS(PEnum)->TypeTableType = RUNTIME_CLASS(PEnum); RUNTIME_CLASS(PArray)->TypeTableType = RUNTIME_CLASS(PArray); RUNTIME_CLASS(PDynArray)->TypeTableType = RUNTIME_CLASS(PDynArray); - RUNTIME_CLASS(PVector)->TypeTableType = RUNTIME_CLASS(PVector); RUNTIME_CLASS(PMap)->TypeTableType = RUNTIME_CLASS(PMap); RUNTIME_CLASS(PStruct)->TypeTableType = RUNTIME_CLASS(PStruct); + RUNTIME_CLASS(PNativeStruct)->TypeTableType = RUNTIME_CLASS(PNativeStruct); RUNTIME_CLASS(PPrototype)->TypeTableType = RUNTIME_CLASS(PPrototype); RUNTIME_CLASS(PClass)->TypeTableType = RUNTIME_CLASS(PClass); RUNTIME_CLASS(PStatePointer)->TypeTableType = RUNTIME_CLASS(PStatePointer); - + RUNTIME_CLASS(PStateLabel)->TypeTableType = RUNTIME_CLASS(PStateLabel); + // Create types and add them type the type table. TypeTable.AddType(TypeError = new PErrorType); + TypeTable.AddType(TypeAuto = new PErrorType(2)); TypeTable.AddType(TypeVoid = new PVoidType); TypeTable.AddType(TypeSInt8 = new PInt(1, false)); TypeTable.AddType(TypeUInt8 = new PInt(1, true)); @@ -589,6 +587,49 @@ void PType::StaticInit() TypeTable.AddType(TypeSound = new PSound); TypeTable.AddType(TypeColor = new PColor); TypeTable.AddType(TypeState = new PStatePointer); + TypeTable.AddType(TypeStateLabel = new PStateLabel); + TypeTable.AddType(TypeNullPtr = new PPointer); + TypeTable.AddType(TypeSpriteID = new PSpriteID); + TypeTable.AddType(TypeTextureID = new PTextureID); + + TypeColorStruct = NewStruct("@ColorStruct", nullptr); //This name is intentionally obfuscated so that it cannot be used explicitly. The point of this type is to gain access to the single channels of a color value. + TypeStringStruct = NewNativeStruct(NAME_String, nullptr); +#ifdef __BIG_ENDIAN__ + TypeColorStruct->AddField(NAME_a, TypeUInt8); + TypeColorStruct->AddField(NAME_r, TypeUInt8); + TypeColorStruct->AddField(NAME_g, TypeUInt8); + TypeColorStruct->AddField(NAME_b, TypeUInt8); +#else + TypeColorStruct->AddField(NAME_b, TypeUInt8); + TypeColorStruct->AddField(NAME_g, TypeUInt8); + TypeColorStruct->AddField(NAME_r, TypeUInt8); + TypeColorStruct->AddField(NAME_a, TypeUInt8); +#endif + + TypeVector2 = new PStruct(NAME_Vector2, nullptr); + TypeVector2->AddField(NAME_X, TypeFloat64); + TypeVector2->AddField(NAME_Y, TypeFloat64); + TypeTable.AddType(TypeVector2); + TypeVector2->loadOp = OP_LV2; + TypeVector2->storeOp = OP_SV2; + TypeVector2->moveOp = OP_MOVEV2; + TypeVector2->RegType = REGT_FLOAT; + TypeVector2->RegCount = 2; + + TypeVector3 = new PStruct(NAME_Vector3, nullptr); + TypeVector3->AddField(NAME_X, TypeFloat64); + TypeVector3->AddField(NAME_Y, TypeFloat64); + TypeVector3->AddField(NAME_Z, TypeFloat64); + // allow accessing xy as a vector2. This is not supposed to be serialized so it's marked transient + TypeVector3->Symbols.AddSymbol(new PField(NAME_XY, TypeVector2, VARF_Transient, 0)); + TypeTable.AddType(TypeVector3); + TypeVector3->loadOp = OP_LV3; + TypeVector3->storeOp = OP_SV3; + TypeVector3->moveOp = OP_MOVEV3; + TypeVector3->RegType = REGT_FLOAT; + TypeVector3->RegCount = 3; + + GlobalSymbols.AddSymbol(new PSymbolType(NAME_sByte, TypeSInt8)); GlobalSymbols.AddSymbol(new PSymbolType(NAME_Byte, TypeUInt8)); @@ -606,12 +647,14 @@ void PType::StaticInit() GlobalSymbols.AddSymbol(new PSymbolType(NAME_Sound, TypeSound)); GlobalSymbols.AddSymbol(new PSymbolType(NAME_Color, TypeColor)); GlobalSymbols.AddSymbol(new PSymbolType(NAME_State, TypeState)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Vector2, TypeVector2)); + GlobalSymbols.AddSymbol(new PSymbolType(NAME_Vector3, TypeVector3)); } /* PBasicType *************************************************************/ -IMPLEMENT_ABSTRACT_CLASS(PBasicType) +IMPLEMENT_CLASS(PBasicType, true, false) //========================================================================== // @@ -632,17 +675,20 @@ PBasicType::PBasicType() PBasicType::PBasicType(unsigned int size, unsigned int align) : PType(size, align) { + mDescriptiveName = "BasicType"; } /* PCompoundType **********************************************************/ -IMPLEMENT_ABSTRACT_CLASS(PCompoundType) +IMPLEMENT_CLASS(PCompoundType, true, false) /* PNamedType *************************************************************/ -IMPLEMENT_ABSTRACT_POINTY_CLASS(PNamedType) - DECLARE_POINTER(Outer) -END_POINTERS +IMPLEMENT_CLASS(PNamedType, true, true) + +IMPLEMENT_POINTERS_START(PNamedType) + IMPLEMENT_POINTER(Outer) +IMPLEMENT_POINTERS_END //========================================================================== // @@ -686,7 +732,7 @@ FString PNamedType::QualifiedName() const /* PInt *******************************************************************/ -IMPLEMENT_CLASS(PInt) +IMPLEMENT_CLASS(PInt, false, false) //========================================================================== // @@ -695,10 +741,12 @@ IMPLEMENT_CLASS(PInt) //========================================================================== PInt::PInt() -: PBasicType(4, 4), Unsigned(false) +: PBasicType(4, 4), Unsigned(false), IntCompatible(true) { + mDescriptiveName = "SInt32"; Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Min, this, -0x7FFFFFFF - 1)); Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Max, this, 0x7FFFFFFF)); + SetOps(); } //========================================================================== @@ -707,9 +755,12 @@ PInt::PInt() // //========================================================================== -PInt::PInt(unsigned int size, bool unsign) -: PBasicType(size, size), Unsigned(unsign) +PInt::PInt(unsigned int size, bool unsign, bool compatible) +: PBasicType(size, size), Unsigned(unsign), IntCompatible(compatible) { + mDescriptiveName.Format("%cInt%d", unsign? 'U':'S', size); + + MemberOnly = (size < 4); if (!unsign) { int maxval = (1 << ((8 * size) - 1)) - 1; @@ -722,6 +773,33 @@ PInt::PInt(unsigned int size, bool unsign) Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Min, this, 0u)); Symbols.AddSymbol(new PSymbolConstNumeric(NAME_Max, this, (1u << (8 * size)) - 1)); } + SetOps(); +} + +void PInt::SetOps() +{ + moveOp = OP_MOVE; + RegType = REGT_INT; + if (Size == 4) + { + storeOp = OP_SW; + loadOp = OP_LW; + } + else if (Size == 1) + { + storeOp = OP_SB; + loadOp = Unsigned ? OP_LBU : OP_LB; + } + else if (Size == 2) + { + storeOp = OP_SH; + loadOp = Unsigned ? OP_LHU : OP_LH; + } + else + { + assert(0 && "Unhandled integer size"); + storeOp = OP_NOP; + } } //========================================================================== @@ -891,68 +969,9 @@ double PInt::GetValueFloat(void *addr) const // //========================================================================== -int PInt::GetStoreOp() const -{ - if (Size == 4) - { - return OP_SW; - } - else if (Size == 1) - { - return OP_SB; - } - else if (Size == 2) - { - return OP_SH; - } - else - { - assert(0 && "Unhandled integer size"); - return OP_NOP; - } -} - -//========================================================================== -// -// PInt :: GetLoadOp -// -//========================================================================== - -int PInt::GetLoadOp() const -{ - if (Size == 4) - { - return OP_LW; - } - else if (Size == 1) - { - return Unsigned ? OP_LBU : OP_LB; - } - else if (Size == 2) - { - return Unsigned ? OP_LHU : OP_LH; - } - else - { - assert(0 && "Unhandled integer size"); - return OP_NOP; - } -} - -//========================================================================== -// -// PInt :: GetRegType -// -//========================================================================== - -int PInt::GetRegType() const -{ - return REGT_INT; -} - /* PBool ******************************************************************/ -IMPLEMENT_CLASS(PBool) +IMPLEMENT_CLASS(PBool, false, false) //========================================================================== // @@ -963,6 +982,8 @@ IMPLEMENT_CLASS(PBool) PBool::PBool() : PInt(sizeof(bool), true) { + mDescriptiveName = "Bool"; + MemberOnly = false; // Override the default max set by PInt's constructor PSymbolConstNumeric *maxsym = static_cast(Symbols.FindSymbol(NAME_Max, false)); assert(maxsym != NULL && maxsym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric))); @@ -971,7 +992,7 @@ PBool::PBool() /* PFloat *****************************************************************/ -IMPLEMENT_CLASS(PFloat) +IMPLEMENT_CLASS(PFloat, false, false) //========================================================================== // @@ -982,7 +1003,9 @@ IMPLEMENT_CLASS(PFloat) PFloat::PFloat() : PBasicType(8, 8) { + mDescriptiveName = "Float"; SetDoubleSymbols(); + SetOps(); } //========================================================================== @@ -994,6 +1017,7 @@ PFloat::PFloat() PFloat::PFloat(unsigned int size) : PBasicType(size, size) { + mDescriptiveName.Format("Float%d", size); if (size == 8) { SetDoubleSymbols(); @@ -1001,8 +1025,10 @@ PFloat::PFloat(unsigned int size) else { assert(size == 4); + MemberOnly = true; SetSingleSymbols(); } + SetOps(); } //========================================================================== @@ -1197,54 +1223,26 @@ double PFloat::GetValueFloat(void *addr) const // //========================================================================== -int PFloat::GetStoreOp() const +void PFloat::SetOps() { if (Size == 4) { - return OP_SSP; + storeOp = OP_SSP; + loadOp = OP_LSP; } else { assert(Size == 8); - return OP_SDP; + storeOp = OP_SDP; + loadOp = OP_LDP; } -} - -//========================================================================== -// -// PFloat :: GetLoadOp -// -//========================================================================== - -int PFloat::GetLoadOp() const -{ - if (Size == 4) - { - return OP_LSP; - } - else - { - assert(Size == 8); - return OP_LDP; - } - assert(0 && "Cannot load this type"); - return OP_NOP; -} - -//========================================================================== -// -// PFloat :: GetRegType -// -//========================================================================== - -int PFloat::GetRegType() const -{ - return REGT_FLOAT; + moveOp = OP_MOVEF; + RegType = REGT_FLOAT; } /* PString ****************************************************************/ -IMPLEMENT_CLASS(PString) +IMPLEMENT_CLASS(PString, false, false) //========================================================================== // @@ -1253,19 +1251,14 @@ IMPLEMENT_CLASS(PString) //========================================================================== PString::PString() -: PBasicType(sizeof(FString), __alignof(FString)) +: PBasicType(sizeof(FString), alignof(FString)) { -} + mDescriptiveName = "String"; + storeOp = OP_SS; + loadOp = OP_LS; + moveOp = OP_MOVES; + RegType = REGT_STRING; -//========================================================================== -// -// PString :: GetRegType -// -//========================================================================== - -int PString::GetRegType() const -{ - return REGT_STRING; } //========================================================================== @@ -1308,7 +1301,7 @@ bool PString::ReadValue(FSerializer &ar, const char *key, void *addr) const void PString::SetDefaultValue(void *base, unsigned offset, TArray *special) const { - new((BYTE *)base + offset) FString; + if (base != nullptr) new((BYTE *)base + offset) FString; if (special != NULL) { special->Push(std::make_pair(this, offset)); @@ -1323,7 +1316,14 @@ void PString::SetDefaultValue(void *base, unsigned offset, TArray", pointsat->DescriptiveName(), isconst? "readonly " : ""); + SetOps(); } //========================================================================== @@ -1557,31 +1595,12 @@ PPointer::PPointer(PType *pointsat) // //========================================================================== -int PPointer::GetStoreOp() const +void PPointer::SetOps() { - return OP_SP; -} - -//========================================================================== -// -// PPointer :: GetLoadOp -// -//========================================================================== - -int PPointer::GetLoadOp() const -{ - return PointedType->IsKindOf(RUNTIME_CLASS(PClass)) ? OP_LO : OP_LP; -} - -//========================================================================== -// -// PPointer :: GetRegType -// -//========================================================================== - -int PPointer::GetRegType() const -{ - return REGT_POINTER; + storeOp = OP_SP; + loadOp = (PointedType && PointedType->IsKindOf(RUNTIME_CLASS(PClass))) ? OP_LO : OP_LP; + moveOp = OP_MOVEA; + RegType = REGT_POINTER; } //========================================================================== @@ -1592,10 +1611,10 @@ int PPointer::GetRegType() const bool PPointer::IsMatch(intptr_t id1, intptr_t id2) const { - assert(id2 == 0); + assert(id2 == 0 || id2 == 1); PType *pointat = (PType *)id1; - return pointat == PointedType; + return pointat == PointedType && (!!id2) == IsConst; } //========================================================================== @@ -1610,6 +1629,21 @@ void PPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const id2 = 0; } +//========================================================================== +// +// PPointer :: SetDefaultValue +// +//========================================================================== + +void PPointer::SetPointer(void *base, unsigned offset, TArray *special) const +{ + if (PointedType != nullptr && PointedType->IsKindOf(RUNTIME_CLASS(PClass))) + { + // Add to the list of pointers for this class. + special->Push(offset); + } +} + //========================================================================== // // PPointer :: WriteValue @@ -1654,24 +1688,68 @@ bool PPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const // //========================================================================== -PPointer *NewPointer(PType *type) +PPointer *NewPointer(PType *type, bool isconst) { size_t bucket; - PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PPointer), (intptr_t)type, 0, &bucket); + PType *ptype = TypeTable.FindType(RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, &bucket); if (ptype == NULL) { - ptype = new PPointer(type); - TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (intptr_t)type, 0, bucket); + ptype = new PPointer(type, isconst); + TypeTable.AddType(ptype, RUNTIME_CLASS(PPointer), (intptr_t)type, isconst ? 1 : 0, bucket); } return static_cast(ptype); } +/* PStatePointer **********************************************************/ + +IMPLEMENT_CLASS(PStatePointer, false, false) + +//========================================================================== +// +// PStatePointer Default Constructor +// +//========================================================================== + +PStatePointer::PStatePointer() +{ + mDescriptiveName = "Pointer"; + PointedType = NewNativeStruct(NAME_State, nullptr); + IsConst = true; +} + +//========================================================================== +// +// PStatePointer :: WriteValue +// +//========================================================================== + +void PStatePointer::WriteValue(FSerializer &ar, const char *key, const void *addr) const +{ + ar(key, *(FState **)addr); +} + +//========================================================================== +// +// PStatePointer :: ReadValue +// +//========================================================================== + +bool PStatePointer::ReadValue(FSerializer &ar, const char *key, void *addr) const +{ + bool res = false; + ::Serialize(ar, key, *(FState **)addr, nullptr, &res); + return res; +} + + /* PClassPointer **********************************************************/ -IMPLEMENT_POINTY_CLASS(PClassPointer) - DECLARE_POINTER(ClassRestriction) -END_POINTERS +IMPLEMENT_CLASS(PClassPointer,false, true) + +IMPLEMENT_POINTERS_START(PClassPointer) + IMPLEMENT_POINTER(ClassRestriction) +IMPLEMENT_POINTERS_END //========================================================================== // @@ -1682,6 +1760,7 @@ END_POINTERS PClassPointer::PClassPointer() : PPointer(RUNTIME_CLASS(PClass)), ClassRestriction(NULL) { + mDescriptiveName = "ClassPointer"; } //========================================================================== @@ -1693,6 +1772,8 @@ PClassPointer::PClassPointer() PClassPointer::PClassPointer(PClass *restrict) : PPointer(RUNTIME_CLASS(PClass)), ClassRestriction(restrict) { + if (restrict) mDescriptiveName.Format("ClassPointer<%s>", restrict->TypeName.GetChars()); + else mDescriptiveName = "ClassPointer"; } //========================================================================== @@ -1745,9 +1826,11 @@ PClassPointer *NewClassPointer(PClass *restrict) /* PEnum ******************************************************************/ -IMPLEMENT_POINTY_CLASS(PEnum) - DECLARE_POINTER(ValueType) -END_POINTERS +IMPLEMENT_CLASS(PEnum, false, true) + +IMPLEMENT_POINTERS_START(PEnum) + IMPLEMENT_POINTER(ValueType) +IMPLEMENT_POINTERS_END //========================================================================== // @@ -1758,6 +1841,7 @@ END_POINTERS PEnum::PEnum() : ValueType(NULL) { + mDescriptiveName = "Enum"; } //========================================================================== @@ -1769,6 +1853,7 @@ PEnum::PEnum() PEnum::PEnum(FName name, PTypeBase *outer) : PNamedType(name, outer), ValueType(NULL) { + mDescriptiveName.Format("Enum<%s>", name.GetChars()); } //========================================================================== @@ -1794,9 +1879,11 @@ PEnum *NewEnum(FName name, PTypeBase *outer) /* PArray *****************************************************************/ -IMPLEMENT_POINTY_CLASS(PArray) - DECLARE_POINTER(ElementType) -END_POINTERS +IMPLEMENT_CLASS(PArray, false, true) + +IMPLEMENT_POINTERS_START(PArray) + IMPLEMENT_POINTER(ElementType) +IMPLEMENT_POINTERS_END //========================================================================== // @@ -1807,6 +1894,7 @@ END_POINTERS PArray::PArray() : ElementType(NULL), ElementCount(0) { + mDescriptiveName = "Array"; } //========================================================================== @@ -1818,6 +1906,8 @@ PArray::PArray() PArray::PArray(PType *etype, unsigned int ecount) : ElementType(etype), ElementCount(ecount) { + mDescriptiveName.Format("Array<%s>[%d]", etype->DescriptiveName(), ecount); + Align = etype->Align; // Since we are concatenating elements together, the element size should // also be padded to the nearest alignment. @@ -1915,6 +2005,20 @@ void PArray::SetDefaultValue(void *base, unsigned offset, TArray } } +//========================================================================== +// +// PArray :: SetDefaultValue +// +//========================================================================== + +void PArray::SetPointer(void *base, unsigned offset, TArray *special) const +{ + for (unsigned i = 0; i < ElementCount; ++i) + { + ElementType->SetPointer(base, offset + i*ElementSize, special); + } +} + //========================================================================== // // NewArray @@ -1936,59 +2040,13 @@ PArray *NewArray(PType *type, unsigned int count) return (PArray *)atype; } -/* PVector ****************************************************************/ - -IMPLEMENT_CLASS(PVector) - -//========================================================================== -// -// PVector - Default Constructor -// -//========================================================================== - -PVector::PVector() -: PArray(TypeFloat32, 3) -{ -} - -//========================================================================== -// -// PVector - Parameterized Constructor -// -//========================================================================== - -PVector::PVector(unsigned int size) -: PArray(TypeFloat32, size) -{ - assert(size >= 2 && size <= 4); -} - -//========================================================================== -// -// NewVector -// -// Returns a PVector with the given dimension, making sure not to create -// duplicates. -// -//========================================================================== - -PVector *NewVector(unsigned int size) -{ - size_t bucket; - PType *type = TypeTable.FindType(RUNTIME_CLASS(PVector), (intptr_t)TypeFloat32, size, &bucket); - if (type == NULL) - { - type = new PVector(size); - TypeTable.AddType(type, RUNTIME_CLASS(PVector), (intptr_t)TypeFloat32, size, bucket); - } - return (PVector *)type; -} - /* PDynArray **************************************************************/ -IMPLEMENT_POINTY_CLASS(PDynArray) - DECLARE_POINTER(ElementType) -END_POINTERS +IMPLEMENT_CLASS(PDynArray, false, true) + +IMPLEMENT_POINTERS_START(PDynArray) + IMPLEMENT_POINTER(ElementType) +IMPLEMENT_POINTERS_END //========================================================================== // @@ -1999,8 +2057,9 @@ END_POINTERS PDynArray::PDynArray() : ElementType(NULL) { + mDescriptiveName = "DynArray"; Size = sizeof(FArray); - Align = __alignof(FArray); + Align = alignof(FArray); } //========================================================================== @@ -2012,8 +2071,9 @@ PDynArray::PDynArray() PDynArray::PDynArray(PType *etype) : ElementType(etype) { + mDescriptiveName.Format("DynArray<%s>", etype->DescriptiveName()); Size = sizeof(FArray); - Align = __alignof(FArray); + Align = alignof(FArray); } //========================================================================== @@ -2065,10 +2125,12 @@ PDynArray *NewDynArray(PType *type) /* PMap *******************************************************************/ -IMPLEMENT_POINTY_CLASS(PMap) - DECLARE_POINTER(KeyType) - DECLARE_POINTER(ValueType) -END_POINTERS +IMPLEMENT_CLASS(PMap, false, true) + +IMPLEMENT_POINTERS_START(PMap) + IMPLEMENT_POINTER(KeyType) + IMPLEMENT_POINTER(ValueType) +IMPLEMENT_POINTERS_END //========================================================================== // @@ -2079,8 +2141,9 @@ END_POINTERS PMap::PMap() : KeyType(NULL), ValueType(NULL) { + mDescriptiveName = "Map"; Size = sizeof(FMap); - Align = __alignof(FMap); + Align = alignof(FMap); } //========================================================================== @@ -2092,8 +2155,9 @@ PMap::PMap() PMap::PMap(PType *keytype, PType *valtype) : KeyType(keytype), ValueType(valtype) { + mDescriptiveName.Format("Map<%s, %s>", keytype->DescriptiveName(), valtype->DescriptiveName()); Size = sizeof(FMap); - Align = __alignof(FMap); + Align = alignof(FMap); } //========================================================================== @@ -2145,7 +2209,7 @@ PMap *NewMap(PType *keytype, PType *valuetype) /* PStruct ****************************************************************/ -IMPLEMENT_CLASS(PStruct) +IMPLEMENT_CLASS(PStruct, false, false) //========================================================================== // @@ -2155,6 +2219,8 @@ IMPLEMENT_CLASS(PStruct) PStruct::PStruct() { + mDescriptiveName = "Struct"; + Size = 0; } //========================================================================== @@ -2166,6 +2232,9 @@ PStruct::PStruct() PStruct::PStruct(FName name, PTypeBase *outer) : PNamedType(name, outer) { + mDescriptiveName.Format("Struct<%s>", name.GetChars()); + Size = 0; + HasNativeFields = false; } //========================================================================== @@ -2178,9 +2247,26 @@ void PStruct::SetDefaultValue(void *base, unsigned offset, TArrayFlags & VARF_Native)) + if (!(field->Flags & VARF_Transient)) { - field->Type->SetDefaultValue(base, offset + field->Offset, special); + field->Type->SetDefaultValue(base, unsigned(offset + field->Offset), special); + } + } +} + +//========================================================================== +// +// PStruct :: SetPointer +// +//========================================================================== + +void PStruct::SetPointer(void *base, unsigned offset, TArray *special) const +{ + for (const PField *field : Fields) + { + if (!(field->Flags & VARF_Transient)) + { + field->Type->SetPointer(base, unsigned(offset + field->Offset), special); } } } @@ -2228,8 +2314,8 @@ void PStruct::WriteFields(FSerializer &ar, const void *addr, const TArrayFlags & VARF_Native)) + // Skip fields without or with native serialization + if (!(field->Flags & VARF_Transient)) { field->Type->WriteValue(ar, field->SymbolName.GetChars(), (const BYTE *)addr + field->Offset); } @@ -2282,13 +2368,13 @@ bool PStruct::ReadFields(FSerializer &ar, void *addr) const PField *PStruct::AddField(FName name, PType *type, DWORD flags) { - PField *field = new PField(name, type); + PField *field = new PField(name, type, flags); // The new field is added to the end of this struct, alignment permitting. field->Offset = (Size + (type->Align - 1)) & ~(type->Align - 1); // Enlarge this struct to enclose the new field. - Size = field->Offset + type->Size; + Size = unsigned(field->Offset + type->Size); // This struct's alignment is the same as the largest alignment of any of // its fields. @@ -2304,6 +2390,29 @@ PField *PStruct::AddField(FName name, PType *type, DWORD flags) return field; } +//========================================================================== +// +// PStruct :: AddField +// +// Appends a new native field to the struct. Returns either the new field +// or NULL if a symbol by that name already exists. +// +//========================================================================== + +PField *PStruct::AddNativeField(FName name, PType *type, size_t address, DWORD flags, int bitvalue) +{ + PField *field = new PField(name, type, flags|VARF_Native|VARF_Transient, address, bitvalue); + + if (Symbols.AddSymbol(field) == nullptr) + { // name is already in use + field->Destroy(); + return nullptr; + } + Fields.Push(field); + HasNativeFields = true; + return field; +} + //========================================================================== // // PStruct :: PropagateMark @@ -2336,9 +2445,47 @@ PStruct *NewStruct(FName name, PTypeBase *outer) return static_cast(stype); } +/* PNativeStruct ****************************************************************/ + +IMPLEMENT_CLASS(PNativeStruct, false, false) + +//========================================================================== +// +// PNativeStruct - Parameterized Constructor +// +//========================================================================== + +PNativeStruct::PNativeStruct(FName name) + : PStruct(name, nullptr) +{ + mDescriptiveName.Format("NativeStruct<%s>", name.GetChars()); + Size = 0; + HasNativeFields = true; +} + +//========================================================================== +// +// NewNativeStruct +// Returns a PNativeStruct for the given name and container, making sure not to +// create duplicates. +// +//========================================================================== + +PNativeStruct *NewNativeStruct(FName name, PTypeBase *outer) +{ + size_t bucket; + PType *stype = TypeTable.FindType(RUNTIME_CLASS(PNativeStruct), (intptr_t)outer, (intptr_t)name, &bucket); + if (stype == NULL) + { + stype = new PNativeStruct(name); + TypeTable.AddType(stype, RUNTIME_CLASS(PNativeStruct), (intptr_t)outer, (intptr_t)name, bucket); + } + return static_cast(stype); +} + /* PField *****************************************************************/ -IMPLEMENT_CLASS(PField) +IMPLEMENT_CLASS(PField, false, false) //========================================================================== // @@ -2351,9 +2498,39 @@ PField::PField() { } + +PField::PField(FName name, PType *type, DWORD flags, size_t offset, int bitvalue) + : PSymbol(name), Offset(offset), Type(type), Flags(flags) +{ + if (bitvalue != 0) + { + BitValue = 0; + unsigned val = bitvalue; + while ((val >>= 1)) BitValue++; + + if (type->IsA(RUNTIME_CLASS(PInt)) && unsigned(BitValue) < 8u * type->Size) + { + // map to the single bytes in the actual variable. The internal bit instructions operate on 8 bit values. +#ifndef __BIG_ENDIAN__ + Offset += BitValue / 8; +#else + Offset += type->Size - 1 - BitValue / 8; +#endif + BitValue &= 7; + Type = TypeBool; + } + else + { + // Just abort. Bit fields should only be defined internally. + I_Error("Trying to create an invalid bit field element: %s", name.GetChars()); + } + } + else BitValue = -1; +} + /* PPrototype *************************************************************/ -IMPLEMENT_CLASS(PPrototype) +IMPLEMENT_CLASS(PPrototype, false, false) //========================================================================== // @@ -2439,7 +2616,7 @@ PPrototype *NewPrototype(const TArray &rettypes, const TArray /* PFunction **************************************************************/ -IMPLEMENT_CLASS(PFunction) +IMPLEMENT_CLASS(PFunction, false, false) //========================================================================== // @@ -2451,7 +2628,7 @@ size_t PFunction::PropagateMark() { for (unsigned i = 0; i < Variants.Size(); ++i) { - //GC::Mark(Variants[i].Proto); + GC::Mark(Variants[i].Proto); GC::Mark(Variants[i].Implementation); } return Variants.Size() * sizeof(Variants[0]) + Super::PropagateMark(); @@ -2466,22 +2643,47 @@ size_t PFunction::PropagateMark() // //========================================================================== -unsigned PFunction::AddVariant(PPrototype *proto, TArray &argflags, VMFunction *impl) +unsigned PFunction::AddVariant(PPrototype *proto, TArray &argflags, TArray &argnames, VMFunction *impl, int flags, int useflags) { Variant variant; - //variant.Proto = proto; - variant.ArgFlags = argflags; + // I do not think we really want to deal with overloading here... + assert(Variants.Size() == 0); + + variant.Flags = flags; + variant.UseFlags = useflags; + variant.Proto = proto; + variant.ArgFlags = std::move(argflags); + variant.ArgNames = std::move(argnames); variant.Implementation = impl; - impl->Proto = proto; + if (impl != nullptr) impl->Proto = proto; + + // SelfClass can differ from OwningClass, but this is variant-dependent. + // Unlike the owner there can be cases where different variants can have different SelfClasses. + // (Of course only if this ever gets enabled...) + if (flags & VARF_Method) + { + assert(proto->ArgumentTypes.Size() > 0); + auto selftypeptr = dyn_cast(proto->ArgumentTypes[0]); + assert(selftypeptr != nullptr); + variant.SelfClass = dyn_cast(selftypeptr->PointedType); + assert(variant.SelfClass != nullptr); + } + else + { + variant.SelfClass = nullptr; + } + return Variants.Push(variant); } /* PClass *****************************************************************/ -IMPLEMENT_POINTY_CLASS(PClass) - DECLARE_POINTER(ParentClass) -END_POINTERS +IMPLEMENT_CLASS(PClass, false, true) + +IMPLEMENT_POINTERS_START(PClass) + IMPLEMENT_POINTER(ParentClass) +IMPLEMENT_POINTERS_END //========================================================================== // @@ -2497,10 +2699,10 @@ static void RecurseWriteFields(const PClass *type, FSerializer &ar, const void * if (type != NULL) { RecurseWriteFields(type->ParentClass, ar, addr); - // Don't write this part if it has no non-native variables + // Don't write this part if it has no non-transient variables for (unsigned i = 0; i < type->Fields.Size(); ++i) { - if (!(type->Fields[i]->Flags & VARF_Native)) + if (!(type->Fields[i]->Flags & VARF_Transient)) { // Tag this section with the class it came from in case // a more-derived class has variables that shadow a less- @@ -2647,6 +2849,16 @@ void PClass::StaticInit () // Keep built-in classes in consistant order. I did this before, though // I'm not sure if this is really necessary to maintain any sort of sync. qsort(&AllClasses[0], AllClasses.Size(), sizeof(AllClasses[0]), cregcmp); + + // Set all symbol table relations here so that they are valid right from the start. + for (auto c : AllClasses) + { + if (c->ParentClass != nullptr) + { + c->Symbols.SetParentTable(&c->ParentClass->Symbols); + } + } + } //========================================================================== @@ -2684,6 +2896,7 @@ void PClass::StaticShutdown () uniqueFPs.Push(const_cast(type->FlatPointers)); } } + type->Destroy(); } for (i = 0; i < uniqueFPs.Size(); ++i) { @@ -2697,9 +2910,10 @@ void PClass::StaticShutdown () FAutoSegIterator probe(CRegHead, CRegTail); - while (*++probe != NULL) + while (*++probe != nullptr) { - ((ClassReg *)*probe)->MyClass = NULL; + auto cr = ((ClassReg *)*probe); + cr->MyClass = nullptr; } } @@ -2744,13 +2958,16 @@ void PClass::StaticBootstrap() PClass::PClass() { Size = sizeof(DObject); - ParentClass = NULL; - Pointers = NULL; - FlatPointers = NULL; - HashNext = NULL; - Defaults = NULL; + ParentClass = nullptr; + Pointers = nullptr; + FlatPointers = nullptr; + HashNext = nullptr; + Defaults = nullptr; bRuntimeClass = false; - ConstructNative = NULL; + bExported = false; + bDecorateClass = false; + ConstructNative = nullptr; + mDescriptiveName = "Class"; PClass::AllClasses.Push(this); } @@ -2793,8 +3010,6 @@ PClass *ClassReg::RegisterClass() &PClassPlayerPawn::RegistrationInfo, &PClassType::RegistrationInfo, &PClassClass::RegistrationInfo, - &PClassWeaponPiece::RegistrationInfo, - &PClassPowerupGiver::RegistrationInfo, }; // Skip classes that have already been registered @@ -2811,7 +3026,7 @@ PClass *ClassReg::RegisterClass() assert(0 && "Class registry has an invalid meta class identifier"); } - if (metaclasses[MetaClassNum]->MyClass == NULL) + if (metaclasses[MetaClassNum]->MyClass == nullptr) { // Make sure the meta class is already registered before registering this one metaclasses[MetaClassNum]->RegisterClass(); } @@ -2819,7 +3034,7 @@ PClass *ClassReg::RegisterClass() SetupClass(cls); cls->InsertIntoHash(); - if (ParentType != NULL) + if (ParentType != nullptr) { cls->ParentClass = ParentType->RegisterClass(); } @@ -2843,6 +3058,7 @@ void ClassReg::SetupClass(PClass *cls) cls->Size = SizeOf; cls->Pointers = Pointers; cls->ConstructNative = ConstructNative; + cls->mDescriptiveName.Format("Class<%s>", cls->TypeName.GetChars()); } //========================================================================== @@ -2928,10 +3144,7 @@ DObject *PClass::CreateNew() const ConstructNative (mem); ((DObject *)mem)->SetClass (const_cast(this)); - if (Defaults != NULL) - { - InitializeSpecials(mem); - } + InitializeSpecials(mem); return (DObject *)mem; } @@ -2955,7 +3168,7 @@ void PClass::InitializeSpecials(void *addr) const ParentClass->InitializeSpecials(addr); for (auto tao : SpecialInits) { - tao.first->InitializeValue((BYTE*)addr + tao.second, Defaults + tao.second); + tao.first->InitializeValue((BYTE*)addr + tao.second, Defaults == nullptr? nullptr : Defaults + tao.second); } } @@ -2992,20 +3205,65 @@ void PClass::DestroySpecials(void *addr) const // //========================================================================== -void PClass::Derive(PClass *newclass) +void PClass::Derive(PClass *newclass, FName name) { + newclass->bRuntimeClass = true; newclass->ParentClass = this; newclass->ConstructNative = ConstructNative; + newclass->Symbols.SetParentTable(&this->Symbols); + newclass->TypeName = name; + newclass->mDescriptiveName.Format("Class<%s>", name.GetChars()); +} - // Set up default instance of the new class. - newclass->Defaults = (BYTE *)M_Malloc(newclass->Size); - if (Defaults) memcpy(newclass->Defaults, Defaults, Size); - if (newclass->Size > Size) +//========================================================================== +// +// PClassActor :: InitializeNativeDefaults +// +//========================================================================== + +void PClass::InitializeDefaults() +{ + assert(Defaults == NULL); + Defaults = (BYTE *)M_Malloc(Size); + if (ParentClass->Defaults != NULL) { - memset(newclass->Defaults + Size, 0, newclass->Size - Size); + memcpy(Defaults, ParentClass->Defaults, ParentClass->Size); + if (Size > ParentClass->Size) + { + memset(Defaults + ParentClass->Size, 0, Size - ParentClass->Size); + } + } + else + { + memset(Defaults, 0, Size); } - newclass->Symbols.SetParentTable(&this->Symbols); + if (bRuntimeClass) + { + // Copy parent values from the parent defaults. + assert(ParentClass != NULL); + ParentClass->InitializeSpecials(Defaults); + + for (const PField *field : Fields) + { + if (!(field->Flags & VARF_Native)) + { + field->Type->SetDefaultValue(Defaults, unsigned(field->Offset), &SpecialInits); + } + } + } +} + +//========================================================================== +// +// PClass :: DeriveData +// +// Copies inheritable data to the child class. +// +//========================================================================== + +void PClass::DeriveData(PClass *newclass) +{ } //========================================================================== @@ -3030,12 +3288,20 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) { if (existclass->Size == TentativeClass) { - type = const_cast(existclass); - if (!IsDescendantOf(type->ParentClass)) + if (!IsDescendantOf(existclass->ParentClass)) { - I_Error("%s must inherit from %s but doesn't.", name.GetChars(), type->ParentClass->TypeName.GetChars()); + I_Error("%s must inherit from %s but doesn't.", name.GetChars(), existclass->ParentClass->TypeName.GetChars()); + } + + if (size == TentativeClass) + { + // see if we can reuse the existing class. This is only possible if the inheritance is identical. Otherwise it needs to be replaced. + if (this == existclass->ParentClass) + { + existclass->ObjectFlags &= OF_Transient; + return existclass; + } } - DPrintf(DMSG_SPAMMY, "Defining placeholder class %s\n", name.GetChars()); notnew = true; } else @@ -3052,26 +3318,29 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) // Create a new type object of the same type as us. (We may be a derived class of PClass.) type = static_cast(GetClass()->CreateNew()); - type->TypeName = name; + Derive(type, name); type->Size = size; - type->bRuntimeClass = true; - Derive(type); - DeriveData(type); + if (size != TentativeClass) + { + type->InitializeDefaults(); + type->Virtuals = Virtuals; + DeriveData(type); + } if (!notnew) { type->InsertIntoHash(); } else { - PClassActor::AllActorClasses.Pop(); // remove the newly added class from the list - // todo: replace all affected fields - for (unsigned i = 0; i < PClassActor::AllActorClasses.Size(); i++) - { - PClassActor::AllActorClasses[i]->ReplaceClassRef(existclass, type); - if (PClassActor::AllActorClasses[i] == existclass) - PClassActor::AllActorClasses[i] = static_cast(type); - } TypeTable.ReplaceType(type, existclass, bucket); + StaticPointerSubstitution(existclass, type, true); // replace the old one, also in the actor defaults. + // Delete the old class from the class lists, both the full one and the actor list. + auto index = PClassActor::AllActorClasses.Find(static_cast(existclass)); + if (index < PClassActor::AllActorClasses.Size()) PClassActor::AllActorClasses.Delete(index); + index = PClass::AllClasses.Find(existclass); + if (index < PClass::AllClasses.Size()) PClass::AllClasses.Delete(index); + // Now we can destroy the old class as nothing should reference it anymore + existclass->Destroy(); } return type; } @@ -3086,15 +3355,14 @@ PField *PClass::AddField(FName name, PType *type, DWORD flags) { unsigned oldsize = Size; PField *field = Super::AddField(name, type, flags); - if (field != NULL) + + // Only initialize the defaults if they have already been created. + // For ZScript this is not the case, it will first define all fields before + // setting up any defaults for any class. + if (field != nullptr && !(flags & VARF_Native) && Defaults != nullptr) { - Defaults = (BYTE *)M_Realloc(Defaults, Size); - memset(Defaults + oldsize, 0, Size - oldsize); - // If this is a native class, then we must not initialize and - // destroy any of its members. We do, however, initialize the - // default instance since it's not a normal instance of the class. - type->SetDefaultValue(Defaults, field->Offset, - bRuntimeClass ? &SpecialInits : NULL); + Defaults = (BYTE *)M_Realloc(Defaults, Size); + memset(Defaults + oldsize, 0, Size - oldsize); } return field; } @@ -3104,12 +3372,11 @@ PField *PClass::AddField(FName name, PType *type, DWORD flags) // PClass :: FindClassTentative // // Like FindClass but creates a placeholder if no class is found. -// CreateDerivedClass will automatically fill in the placeholder when the -// actual class is defined. +// This will be filled in when the actual class is constructed. // //========================================================================== -PClass *PClass::FindClassTentative(FName name, bool fatal) +PClass *PClass::FindClassTentative(FName name) { if (name == NAME_None) { @@ -3127,14 +3394,59 @@ PClass *PClass::FindClassTentative(FName name, bool fatal) PClass *type = static_cast(GetClass()->CreateNew()); DPrintf(DMSG_SPAMMY, "Creating placeholder class %s : %s\n", name.GetChars(), TypeName.GetChars()); - type->TypeName = name; - type->ParentClass = this; + Derive(type, name); type->Size = TentativeClass; - type->bRuntimeClass = true; TypeTable.AddType(type, RUNTIME_CLASS(PClass), (intptr_t)type->Outer, name, bucket); return type; } +//========================================================================== +// +// PClass :: FindVirtualIndex +// +// Compares a prototype with the existing list of virtual functions +// and returns an index if something matching is found. +// +//========================================================================== + +int PClass::FindVirtualIndex(FName name, PPrototype *proto) +{ + for (unsigned i = 0; i < Virtuals.Size(); i++) + { + if (Virtuals[i]->Name == name) + { + auto vproto = Virtuals[i]->Proto; + if (vproto->ReturnTypes.Size() != proto->ReturnTypes.Size() || + vproto->ArgumentTypes.Size() != proto->ArgumentTypes.Size()) + { + continue; // number of parameters does not match, so it's incompatible + } + bool fail = false; + // The first argument is self and will mismatch so just skip it. + for (unsigned a = 1; a < proto->ArgumentTypes.Size(); a++) + { + if (proto->ArgumentTypes[a] != vproto->ArgumentTypes[a]) + { + fail = true; + break; + } + } + if (fail) continue; + + for (unsigned a = 0; a < proto->ReturnTypes.Size(); a++) + { + if (proto->ReturnTypes[a] != vproto->ReturnTypes[a]) + { + fail = true; + break; + } + } + if (!fail) return i; + } + } + return -1; +} + //========================================================================== // // PClass :: BuildFlatPointers @@ -3153,7 +3465,7 @@ void PClass::BuildFlatPointers () return; } else if (ParentClass == NULL) - { // No parent: FlatPointers is the same as Pointers. + { // No parent (i.e. DObject: FlatPointers is the same as Pointers. if (Pointers == NULL) { // No pointers: Make FlatPointers a harmless non-NULL. FlatPointers = &TheEnd; @@ -3166,7 +3478,19 @@ void PClass::BuildFlatPointers () else { ParentClass->BuildFlatPointers (); - if (Pointers == NULL) + + TArray ScriptPointers; + + // Collect all pointers in scripted fields. These are not part of the Pointers list. + for (auto field : Fields) + { + if (!(field->Flags & VARF_Native)) + { + field->Type->SetPointer(Defaults, unsigned(field->Offset), &ScriptPointers); + } + } + + if (Pointers == nullptr && ScriptPointers.Size() == 0) { // No new pointers: Just use the same FlatPointers as the parent. FlatPointers = ParentClass->FlatPointers; } @@ -3174,20 +3498,34 @@ void PClass::BuildFlatPointers () { // New pointers: Create a new FlatPointers array and add them. int numPointers, numSuperPointers; - // Count pointers defined by this class. - for (numPointers = 0; Pointers[numPointers] != ~(size_t)0; numPointers++) - { } + if (Pointers != nullptr) + { + // Count pointers defined by this class. + for (numPointers = 0; Pointers[numPointers] != ~(size_t)0; numPointers++) + { + } + } + else numPointers = 0; + // Count pointers defined by superclasses. for (numSuperPointers = 0; ParentClass->FlatPointers[numSuperPointers] != ~(size_t)0; numSuperPointers++) { } // Concatenate them into a new array - size_t *flat = new size_t[numPointers + numSuperPointers + 1]; + size_t *flat = new size_t[numPointers + numSuperPointers + ScriptPointers.Size() + 1]; if (numSuperPointers > 0) { memcpy (flat, ParentClass->FlatPointers, sizeof(size_t)*numSuperPointers); } - memcpy (flat + numSuperPointers, Pointers, sizeof(size_t)*(numPointers+1)); + if (numPointers > 0) + { + memcpy(flat + numSuperPointers, Pointers, sizeof(size_t)*numPointers); + } + if (ScriptPointers.Size() > 0) + { + memcpy(flat + numSuperPointers + numPointers, &ScriptPointers[0], sizeof(size_t) * ScriptPointers.Size()); + } + flat[numSuperPointers + numPointers + ScriptPointers.Size()] = ~(size_t)0; FlatPointers = flat; } } @@ -3197,7 +3535,7 @@ void PClass::BuildFlatPointers () // // PClass :: NativeClass // -// Finds the underlying native type underlying this class. +// Finds the native type underlying this class. // //========================================================================== @@ -3211,6 +3549,16 @@ const PClass *PClass::NativeClass() const return cls; } +VMFunction *PClass::FindFunction(FName clsname, FName funcname) +{ + auto cls = PClass::FindActor(clsname); + if (!cls) return nullptr; + auto func = dyn_cast(cls->Symbols.FindSymbol(funcname, true)); + if (!func) return nullptr; + return func->Variants[0].Implementation; +} + + /* FTypeTable **************************************************************/ //========================================================================== @@ -3379,18 +3727,23 @@ CCMD(typetable) // Symbol tables ------------------------------------------------------------ -IMPLEMENT_ABSTRACT_CLASS(PTypeBase); -IMPLEMENT_ABSTRACT_CLASS(PSymbol); -IMPLEMENT_CLASS(PSymbolConst); -IMPLEMENT_CLASS(PSymbolConstNumeric); -IMPLEMENT_CLASS(PSymbolConstString); -IMPLEMENT_POINTY_CLASS(PSymbolType) - DECLARE_POINTER(Type) -END_POINTERS -IMPLEMENT_POINTY_CLASS(PSymbolVMFunction) - DECLARE_POINTER(Function) -END_POINTERS -IMPLEMENT_CLASS(PSymbolTreeNode) +IMPLEMENT_CLASS(PTypeBase, true, false); +IMPLEMENT_CLASS(PSymbol, true, false); +IMPLEMENT_CLASS(PSymbolConst, false, false); +IMPLEMENT_CLASS(PSymbolConstNumeric, false, false); +IMPLEMENT_CLASS(PSymbolConstString, false, false); +IMPLEMENT_CLASS(PSymbolTreeNode, false, false) +IMPLEMENT_CLASS(PSymbolType, false, true) + +IMPLEMENT_POINTERS_START(PSymbolType) + IMPLEMENT_POINTER(Type) +IMPLEMENT_POINTERS_END + +IMPLEMENT_CLASS(PSymbolVMFunction, false, true) + +IMPLEMENT_POINTERS_START(PSymbolVMFunction) + IMPLEMENT_POINTER(Function) +IMPLEMENT_POINTERS_END //========================================================================== // diff --git a/src/dobjtype.h b/src/dobjtype.h index 338c51f982..c310f9863b 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -5,20 +5,36 @@ #error You must #include "dobject.h" to get dobjtype.h #endif -#include "vm.h" - typedef std::pair 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 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 *special=NULL) const; + virtual void SetPointer(void *base, unsigned offset, TArray *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 *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 *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 *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 *special) const override; + void SetPointer(void *base, unsigned offset, TArray *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 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 *specials) const override; + void SetPointer(void *base, unsigned offset, TArray *specials) const override; static void WriteFields(FSerializer &ar, const void *addr, const TArray &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 ArgFlags; // Should be the same length as Proto->ArgumentTypes + TArray ArgNames; // we need the names to access them later when the function gets compiled. + uint32_t Flags; + int UseFlags; + PStruct *SelfClass; }; TArray Variants; - DWORD Flags; + PStruct *OwningClass = nullptr; - unsigned AddVariant(PPrototype *proto, TArray &argflags, VMFunction *impl); + unsigned AddVariant(PPrototype *proto, TArray &argflags, TArray &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 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 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 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(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 &rettypes, const TArray &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 --------------------------------------------------------- diff --git a/src/doomerrors.h b/src/doomerrors.h index f4b0c9566e..c389c6b052 100644 --- a/src/doomerrors.h +++ b/src/doomerrors.h @@ -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]; }; diff --git a/src/doomtype.h b/src/doomtype.h index 129c5f1221..a9818df78c 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -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" diff --git a/src/dsectoreffect.cpp b/src/dsectoreffect.cpp index 815b49dc47..3c33d1634c 100644 --- a/src/dsectoreffect.cpp +++ b/src/dsectoreffect.cpp @@ -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 () { diff --git a/src/dsectoreffect.h b/src/dsectoreffect.h index 0a5e9bd568..e9327ce702 100644 --- a/src/dsectoreffect.h +++ b/src/dsectoreffect.h @@ -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 diff --git a/src/dthinker.cpp b/src/dthinker.cpp index 114d260df7..fd20a4e79a 100644 --- a/src/dthinker.cpp +++ b/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; diff --git a/src/dthinker.h b/src/dthinker.h index 3f96472977..3d580c3c20 100644 --- a/src/dthinker.h +++ b/src/dthinker.h @@ -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(FThinkerIterator::Next ()); + return static_cast(FThinkerIterator::Next (exact)); } }; diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index cc096ed601..7cd599b11d 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -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]))); } } diff --git a/src/fragglescript/t_parse.cpp b/src/fragglescript/t_parse.cpp index 0b2f27680e..28330e9e98 100644 --- a/src/fragglescript/t_parse.cpp +++ b/src/fragglescript/t_parse.cpp @@ -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()); } //========================================================================== diff --git a/src/fragglescript/t_prepro.cpp b/src/fragglescript/t_prepro.cpp index 619b6d570e..4128e6661d 100644 --- a/src/fragglescript/t_prepro.cpp +++ b/src/fragglescript/t_prepro.cpp @@ -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 //========================================================================== // diff --git a/src/fragglescript/t_script.cpp b/src/fragglescript/t_script.cpp index f1376b7eb3..81b2ce21ec 100644 --- a/src/fragglescript/t_script.cpp +++ b/src/fragglescript/t_script.cpp @@ -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::ActiveThinker; diff --git a/src/fragglescript/t_script.h b/src/fragglescript/t_script.h index 3734e16b8a..f0409a3f0b 100644 --- a/src/fragglescript/t_script.h +++ b/src/fragglescript/t_script.h @@ -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 script; @@ -687,7 +697,7 @@ public: bool nocheckposition; DFraggleThinker(); - void Destroy(); + void Destroy() override; void Serialize(FSerializer & arc); diff --git a/src/fragglescript/t_variable.cpp b/src/fragglescript/t_variable.cpp index 125f32367d..9bdddda34d 100644 --- a/src/fragglescript/t_variable.cpp +++ b/src/fragglescript/t_variable.cpp @@ -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 //========================================================================== // diff --git a/src/g_doom/a_arachnotron.cpp b/src/g_doom/a_arachnotron.cpp deleted file mode 100644 index 62660c7f50..0000000000 --- a/src/g_doom/a_arachnotron.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_doom/a_archvile.cpp b/src/g_doom/a_archvile.cpp deleted file mode 100644 index 84481e5f62..0000000000 --- a/src/g_doom/a_archvile.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_doom/a_bossbrain.cpp b/src/g_doom/a_bossbrain.cpp deleted file mode 100644 index b0e7259105..0000000000 --- a/src/g_doom/a_bossbrain.cpp +++ /dev/null @@ -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 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; -} diff --git a/src/g_doom/a_bruiser.cpp b/src/g_doom/a_bruiser.cpp deleted file mode 100644 index 0d2f83aee0..0000000000 --- a/src/g_doom/a_bruiser.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_doom/a_cacodemon.cpp b/src/g_doom/a_cacodemon.cpp deleted file mode 100644 index 3532374cf1..0000000000 --- a/src/g_doom/a_cacodemon.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_doom/a_cyberdemon.cpp b/src/g_doom/a_cyberdemon.cpp deleted file mode 100644 index 9e0ddd1ddb..0000000000 --- a/src/g_doom/a_cyberdemon.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_doom/a_demon.cpp b/src/g_doom/a_demon.cpp deleted file mode 100644 index 3f8e2f6265..0000000000 --- a/src/g_doom/a_demon.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_doom/a_doomglobal.h b/src/g_doom/a_doomglobal.h deleted file mode 100644 index 31d41f6c0a..0000000000 --- a/src/g_doom/a_doomglobal.h +++ /dev/null @@ -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__ diff --git a/src/g_doom/a_doomimp.cpp b/src/g_doom/a_doomimp.cpp deleted file mode 100644 index f00b53a420..0000000000 --- a/src/g_doom/a_doomimp.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_doom/a_doommisc.cpp b/src/g_doom/a_doommisc.cpp deleted file mode 100644 index 129c32f1ed..0000000000 --- a/src/g_doom/a_doommisc.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp deleted file mode 100644 index a35a31b61f..0000000000 --- a/src/g_doom/a_doomweaps.cpp +++ /dev/null @@ -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()) - 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(PClass::FindClass("ArmorBonus")); - } - if (armorbonustype != NULL) - { - assert(armorbonustype->IsDescendantOf (RUNTIME_CLASS(ABasicArmorBonus))); - ABasicArmorBonus *armorbonus = static_cast(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(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; -} diff --git a/src/g_doom/a_fatso.cpp b/src/g_doom/a_fatso.cpp deleted file mode 100644 index 872e1982d3..0000000000 --- a/src/g_doom/a_fatso.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_doom/a_keen.cpp b/src/g_doom/a_keen.cpp deleted file mode 100644 index d0a10da58a..0000000000 --- a/src/g_doom/a_keen.cpp +++ /dev/null @@ -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 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; -} - - diff --git a/src/g_doom/a_lostsoul.cpp b/src/g_doom/a_lostsoul.cpp deleted file mode 100644 index 056802fe07..0000000000 --- a/src/g_doom/a_lostsoul.cpp +++ /dev/null @@ -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; - } -} diff --git a/src/g_doom/a_painelemental.cpp b/src/g_doom/a_painelemental.cpp deleted file mode 100644 index 3620b88dba..0000000000 --- a/src/g_doom/a_painelemental.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_doom/a_possessed.cpp b/src/g_doom/a_possessed.cpp deleted file mode 100644 index f6b559c4bb..0000000000 --- a/src/g_doom/a_possessed.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_doom/a_revenant.cpp b/src/g_doom/a_revenant.cpp deleted file mode 100644 index 9c8a38602e..0000000000 --- a/src/g_doom/a_revenant.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_doom/a_scriptedmarine.cpp b/src/g_doom/a_scriptedmarine.cpp deleted file mode 100644 index 2c293a2deb..0000000000 --- a/src/g_doom/a_scriptedmarine.cpp +++ /dev/null @@ -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(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; - } -} diff --git a/src/g_doom/a_spidermaster.cpp b/src/g_doom/a_spidermaster.cpp deleted file mode 100644 index aaafc4d99f..0000000000 --- a/src/g_doom/a_spidermaster.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_game.cpp b/src/g_game.cpp index 810a29da10..b5729283e9 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -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 // diff --git a/src/g_heretic/a_chicken.cpp b/src/g_heretic/a_chicken.cpp deleted file mode 100644 index 7f62d5f0e1..0000000000 --- a/src/g_heretic/a_chicken.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_heretic/a_dsparil.cpp b/src/g_heretic/a_dsparil.cpp deleted file mode 100644 index f5870f09ec..0000000000 --- a/src/g_heretic/a_dsparil.cpp +++ /dev/null @@ -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; -} - diff --git a/src/g_heretic/a_hereticartifacts.cpp b/src/g_heretic/a_hereticartifacts.cpp deleted file mode 100644 index 518abb44a8..0000000000 --- a/src/g_heretic/a_hereticartifacts.cpp +++ /dev/null @@ -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; -} - diff --git a/src/g_heretic/a_hereticimp.cpp b/src/g_heretic/a_hereticimp.cpp deleted file mode 100644 index 81185c0c14..0000000000 --- a/src/g_heretic/a_hereticimp.cpp +++ /dev/null @@ -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; -} - diff --git a/src/g_heretic/a_hereticmisc.cpp b/src/g_heretic/a_hereticmisc.cpp deleted file mode 100644 index 36969f6e7d..0000000000 --- a/src/g_heretic/a_hereticmisc.cpp +++ /dev/null @@ -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; -} - diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp deleted file mode 100644 index eb7d49983f..0000000000 --- a/src/g_heretic/a_hereticweaps.cpp +++ /dev/null @@ -1,1395 +0,0 @@ -/* -#include "templates.h" -#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 "gi.h" -#include "r_data/r_translate.h" -#include "thingdef/thingdef.h" -#include "doomstat.h" -*/ - -static FRandom pr_sap ("StaffAtkPL1"); -static FRandom pr_sap2 ("StaffAtkPL2"); -static FRandom pr_fgw ("FireWandPL1"); -static FRandom pr_fgw2 ("FireWandPL2"); -static FRandom pr_boltspark ("BoltSpark"); -static FRandom pr_macerespawn ("MaceRespawn"); -static FRandom pr_maceatk ("FireMacePL1"); -static FRandom pr_gatk ("GauntletAttack"); -static FRandom pr_bfx1 ("BlasterFX1"); -static FRandom pr_ripd ("RipperD"); -static FRandom pr_fb1 ("FireBlasterPL1"); -static FRandom pr_bfx1t ("BlasterFX1Tick"); -static FRandom pr_hrfx2 ("HornRodFX2"); -static FRandom pr_rp ("RainPillar"); -static FRandom pr_fsr1 ("FireSkullRodPL1"); -static FRandom pr_storm ("SkullRodStorm"); -static FRandom pr_impact ("RainImpact"); -static FRandom pr_pfx1 ("PhoenixFX1"); -static FRandom pr_pfx2 ("PhoenixFX2"); -static FRandom pr_fp2 ("FirePhoenixPL2"); - -#define FLAME_THROWER_TICS (10*TICRATE) - -void P_DSparilTeleport (AActor *actor); - -#define USE_BLSR_AMMO_1 1 -#define USE_BLSR_AMMO_2 5 -#define USE_SKRD_AMMO_1 1 -#define USE_SKRD_AMMO_2 5 -#define USE_PHRD_AMMO_1 1 -#define USE_PHRD_AMMO_2 1 -#define USE_MACE_AMMO_1 1 -#define USE_MACE_AMMO_2 5 - -extern bool P_AutoUseChaosDevice (player_t *player); - -// --- Staff ---------------------------------------------------------------- - -//---------------------------------------------------------------------------- -// -// PROC A_StaffAttackPL1 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StaffAttack) -{ - PARAM_ACTION_PROLOGUE; - - DAngle angle; - DAngle slope; - player_t *player; - FTranslatedLineTarget t; - - if (NULL == (player = self->player)) - { - return 0; - } - - PARAM_INT (damage); - PARAM_CLASS (puff, AActor); - - AWeapon *weapon = player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - if (puff == NULL) - { - puff = PClass::FindActor(NAME_BulletPuff); // just to be sure - } - angle = self->Angles.Yaw + pr_sap.Random2() * (5.625 / 256); - slope = P_AimLineAttack (self, angle, MELEERANGE); - P_LineAttack (self, angle, MELEERANGE, slope, damage, NAME_Melee, puff, true, &t); - if (t.linetarget) - { - //S_StartSound(player->mo, sfx_stfhit); - // turn to face target - self->Angles.Yaw = t.angleFromSource; - } - return 0; -} - - -//---------------------------------------------------------------------------- -// -// PROC A_FireGoldWandPL1 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FireGoldWandPL1) -{ - PARAM_ACTION_PROLOGUE; - - DAngle angle; - int damage; - player_t *player; - - if (NULL == (player = self->player)) - { - return 0; - } - - AWeapon *weapon = player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo(weapon->bAltFire)) - return 0; - } - DAngle pitch = P_BulletSlope(self); - damage = 7 + (pr_fgw() & 7); - angle = self->Angles.Yaw; - if (player->refire) - { - angle += pr_fgw.Random2() * (5.625 / 256); - } - P_LineAttack(self, angle, PLAYERMISSILERANGE, pitch, damage, NAME_Hitscan, "GoldWandPuff1"); - S_Sound(self, CHAN_WEAPON, "weapons/wandhit", 1, ATTN_NORM); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_FireGoldWandPL2 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FireGoldWandPL2) -{ - PARAM_ACTION_PROLOGUE; - - int i; - DAngle angle; - int damage; - double vz; - player_t *player; - - if (NULL == (player = self->player)) - { - return 0; - } - - AWeapon *weapon = player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - DAngle pitch = P_BulletSlope(self); - - vz = -GetDefaultByName("GoldWandFX2")->Speed * pitch.TanClamped(); - P_SpawnMissileAngle(self, PClass::FindActor("GoldWandFX2"), self->Angles.Yaw - (45. / 8), vz); - P_SpawnMissileAngle(self, PClass::FindActor("GoldWandFX2"), self->Angles.Yaw + (45. / 8), vz); - angle = self->Angles.Yaw - (45. / 8); - for(i = 0; i < 5; i++) - { - damage = 1+(pr_fgw2()&7); - P_LineAttack (self, angle, PLAYERMISSILERANGE, pitch, damage, NAME_Hitscan, "GoldWandPuff2"); - angle += ((45. / 8) * 2) / 4; - } - S_Sound (self, CHAN_WEAPON, "weapons/wandhit", 1, ATTN_NORM); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_FireCrossbowPL1 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FireCrossbowPL1) -{ - PARAM_ACTION_PROLOGUE; - - player_t *player; - - if (NULL == (player = self->player)) - { - return 0; - } - - AWeapon *weapon = player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX1")); - P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX3"), self->Angles.Yaw - 4.5); - P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX3"), self->Angles.Yaw + 4.5); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_FireCrossbowPL2 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FireCrossbowPL2) -{ - 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, PClass::FindActor("CrossbowFX2")); - P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX2"), self->Angles.Yaw - 4.5); - P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX2"), self->Angles.Yaw + 4.5); - P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX3"), self->Angles.Yaw - 9.); - P_SpawnPlayerMissile (self, PClass::FindActor("CrossbowFX3"), self->Angles.Yaw + 9.); - return 0; -} - -//--------------------------------------------------------------------------- -// -// PROC A_GauntletAttack -// -//--------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack) -{ - PARAM_ACTION_PROLOGUE; - - DAngle Angle; - int damage; - DAngle slope; - int randVal; - double dist; - player_t *player; - PClassActor *pufftype; - FTranslatedLineTarget t; - int actualdamage = 0; - - if (nullptr == (player = self->player)) - { - return 0; - } - - PARAM_INT(power); - - AWeapon *weapon = player->ReadyWeapon; - if (weapon != nullptr) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - - player->GetPSprite(PSP_WEAPON)->x = ((pr_gatk() & 3) - 2); - player->GetPSprite(PSP_WEAPON)->y = WEAPONTOP + (pr_gatk() & 3); - } - Angle = self->Angles.Yaw; - if (power) - { - damage = pr_gatk.HitDice (2); - dist = 4*MELEERANGE; - Angle += pr_gatk.Random2() * (2.8125 / 256); - pufftype = PClass::FindActor("GauntletPuff2"); - } - else - { - damage = pr_gatk.HitDice (2); - dist = SAWRANGE; - Angle += pr_gatk.Random2() * (5.625 / 256); - pufftype = PClass::FindActor("GauntletPuff1"); - } - slope = P_AimLineAttack (self, Angle, dist); - P_LineAttack (self, Angle, dist, slope, damage, NAME_Melee, pufftype, false, &t, &actualdamage); - if (!t.linetarget) - { - if (pr_gatk() > 64) - { - player->extralight = !player->extralight; - } - S_Sound (self, CHAN_AUTO, "weapons/gauntletson", 1, ATTN_NORM); - return 0; - } - randVal = pr_gatk(); - if (randVal < 64) - { - player->extralight = 0; - } - else if (randVal < 160) - { - player->extralight = 1; - } - else - { - player->extralight = 2; - } - if (power) - { - if (!(t.linetarget->flags5 & MF5_DONTDRAIN)) P_GiveBody (self, actualdamage>>1); - S_Sound (self, CHAN_AUTO, "weapons/gauntletspowhit", 1, ATTN_NORM); - } - else - { - S_Sound (self, CHAN_AUTO, "weapons/gauntletshit", 1, ATTN_NORM); - } - // turn to face target - DAngle 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; - } - self->flags |= MF_JUSTATTACKED; - return 0; -} - -// --- Mace ----------------------------------------------------------------- - -#define MAGIC_JUNK 1234 - -// Mace FX4 ----------------------------------------------------------------- - -class AMaceFX4 : public AActor -{ - DECLARE_CLASS (AMaceFX4, AActor) -public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS (AMaceFX4) - -int AMaceFX4::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - if ((target->flags2 & MF2_BOSS) || (target->flags3 & MF3_DONTSQUASH) || target->IsTeammate (this->target)) - { // Don't allow cheap boss kills and don't instagib teammates - return damage; - } - else if (target->player) - { // Player specific checks - if (target->player->mo->flags2 & MF2_INVULNERABLE) - { // Can't hurt invulnerable players - return -1; - } - if (P_AutoUseChaosDevice (target->player)) - { // Player was saved using chaos device - return -1; - } - } - return TELEFRAG_DAMAGE; // Something's gonna die -} - -//---------------------------------------------------------------------------- -// -// PROC A_FireMacePL1B -// -//---------------------------------------------------------------------------- - -void FireMacePL1B (AActor *actor) -{ - AActor *ball; - player_t *player; - - if (NULL == (player = actor->player)) - { - return; - } - - AWeapon *weapon = player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return; - } - ball = Spawn("MaceFX2", actor->PosPlusZ(28 - actor->Floorclip), ALLOW_REPLACE); - ball->Vel.Z = 2 - player->mo->Angles.Pitch.TanClamped(); - ball->target = actor; - ball->Angles.Yaw = actor->Angles.Yaw; - ball->AddZ(ball->Vel.Z); - ball->VelFromAngle(); - ball->Vel += actor->Vel.XY()/2; - S_Sound (ball, CHAN_BODY, "weapons/maceshoot", 1, ATTN_NORM); - P_CheckMissileSpawn (ball, actor->radius); -} - -//---------------------------------------------------------------------------- -// -// PROC A_FireMacePL1 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL1) -{ - PARAM_ACTION_PROLOGUE; - - AActor *ball; - player_t *player; - - if (nullptr == (player = self->player)) - { - return 0; - } - - if (pr_maceatk() < 28) - { - FireMacePL1B(self); - return 0; - } - AWeapon *weapon = player->ReadyWeapon; - if (weapon != nullptr) - { - if (!weapon->DepleteAmmo(weapon->bAltFire)) - return 0; - - player->GetPSprite(PSP_WEAPON)->x = ((pr_maceatk() & 3) - 2); - player->GetPSprite(PSP_WEAPON)->y = WEAPONTOP + (pr_maceatk() & 3); - } - ball = P_SpawnPlayerMissile(self, PClass::FindActor("MaceFX1"), self->Angles.Yaw + (((pr_maceatk() & 7) - 4) * (360. / 256))); - if (ball) - { - ball->special1 = 16; // tics till dropoff - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_MacePL1Check -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_MacePL1Check) -{ - PARAM_ACTION_PROLOGUE; - - if (self->special1 == 0) - { - return 0; - } - self->special1 -= 4; - if (self->special1 > 0) - { - return 0; - } - self->special1 = 0; - self->flags &= ~MF_NOGRAVITY; - self->Gravity = 1. / 8;; - // [RH] Avoid some precision loss by scaling the velocity directly -#if 0 - // This is the original code, for reference. - a.ngle_t angle = self->angle>>ANGLETOF.INESHIFT; - self->velx = F.ixedMul(7*F.RACUNIT, f.inecosine[angle]); - self->vely = F.ixedMul(7*F.RACUNIT, f.inesine[angle]); -#else - double velscale = 7 / self->Vel.XY().Length(); - self->Vel.X *= velscale; - self->Vel.Y *= velscale; -#endif - self->Vel.Z *= 0.5; - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_MaceBallImpact -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_MaceBallImpact) -{ - PARAM_ACTION_PROLOGUE; - - if ((self->health != MAGIC_JUNK) && (self->flags & MF_INBOUNCE)) - { // Bounce - self->health = MAGIC_JUNK; - self->Vel.Z *= 0.75; - self->BounceFlags = BOUNCE_None; - self->SetState (self->SpawnState); - S_Sound (self, CHAN_BODY, "weapons/macebounce", 1, ATTN_NORM); - } - else - { // Explode - self->Vel.Zero(); - self->flags |= MF_NOGRAVITY; - self->Gravity = 1; - S_Sound (self, CHAN_BODY, "weapons/macehit", 1, ATTN_NORM); - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_MaceBallImpact2 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_MaceBallImpact2) -{ - PARAM_ACTION_PROLOGUE; - - AActor *tiny; - - if ((self->Z() <= self->floorz) && P_HitFloor (self)) - { // Landed in some sort of liquid - self->Destroy (); - return 0; - } - if (self->flags & MF_INBOUNCE) - { - if (self->Vel.Z < 2) - { - goto boom; - } - - // Bounce - self->Vel.Z *= 0.75; - self->SetState (self->SpawnState); - - tiny = Spawn("MaceFX3", self->Pos(), ALLOW_REPLACE); - tiny->target = self->target; - tiny->Angles.Yaw = self->Angles.Yaw + 90.; - tiny->VelFromAngle(self->Vel.Z - 1.); - tiny->Vel += { self->Vel.X * .5, self->Vel.Y * .5, self->Vel.Z }; - P_CheckMissileSpawn (tiny, self->radius); - - tiny = Spawn("MaceFX3", self->Pos(), ALLOW_REPLACE); - tiny->target = self->target; - tiny->Angles.Yaw = self->Angles.Yaw - 90.; - tiny->VelFromAngle(self->Vel.Z - 1.); - tiny->Vel += { self->Vel.X * .5, self->Vel.Y * .5, self->Vel.Z }; - P_CheckMissileSpawn (tiny, self->radius); - } - else - { // Explode -boom: - self->Vel.Zero(); - self->flags |= MF_NOGRAVITY; - self->BounceFlags = BOUNCE_None; - self->Gravity = 1; - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_FireMacePL2 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL2) -{ - PARAM_ACTION_PROLOGUE; - - AActor *mo; - player_t *player; - FTranslatedLineTarget t; - - if (NULL == (player = self->player)) - { - return 0; - } - - AWeapon *weapon = player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - mo = P_SpawnPlayerMissile (self, 0,0,0, RUNTIME_CLASS(AMaceFX4), self->Angles.Yaw, &t); - if (mo) - { - mo->Vel += self->Vel.XY(); - mo->Vel.Z = 2 - player->mo->Angles.Pitch.TanClamped(); - if (t.linetarget && !t.unlinked) - { - mo->tracer = t.linetarget; - } - } - S_Sound (self, CHAN_WEAPON, "weapons/maceshoot", 1, ATTN_NORM); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_DeathBallImpact -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_DeathBallImpact) -{ - PARAM_ACTION_PROLOGUE; - - int i; - AActor *target; - DAngle angle = 0.; - bool newAngle; - FTranslatedLineTarget t; - - if ((self->Z() <= self->floorz) && P_HitFloor (self)) - { // Landed in some sort of liquid - self->Destroy (); - return 0; - } - if (self->flags & MF_INBOUNCE) - { - if (self->Vel.Z < 2) - { - goto boom; - } - - // Bounce - newAngle = false; - target = self->tracer; - if (target) - { - if (!(target->flags&MF_SHOOTABLE)) - { // Target died - self->tracer = NULL; - } - else - { // Seek - angle = self->AngleTo(target); - newAngle = true; - } - } - else - { // Find new target - angle = 0.; - for (i = 0; i < 16; i++) - { - P_AimLineAttack (self, angle, 640., &t, 0., ALF_NOFRIENDS|ALF_PORTALRESTRICT, NULL, self->target); - if (t.linetarget && self->target != t.linetarget) - { - self->tracer = t.linetarget; - angle = t.angleFromSource; - newAngle = true; - break; - } - angle += 22.5; - } - } - if (newAngle) - { - self->Angles.Yaw = angle; - self->VelFromAngle(); - } - self->SetState (self->SpawnState); - S_Sound (self, CHAN_BODY, "weapons/macestop", 1, ATTN_NORM); - } - else - { // Explode -boom: - self->Vel.Zero(); - self->flags |= MF_NOGRAVITY; - self->Gravity = 1; - S_Sound (self, CHAN_BODY, "weapons/maceexplode", 1, ATTN_NORM); - } - return 0; -} - - -// Blaster FX 1 ------------------------------------------------------------- - -//---------------------------------------------------------------------------- -// -// Thinker for the ultra-fast blaster PL2 ripper-spawning missile. -// -//---------------------------------------------------------------------------- - -class ABlasterFX1 : public AFastProjectile -{ - DECLARE_CLASS(ABlasterFX1, AFastProjectile) -public: - void Effect (); - int DoSpecialDamage (AActor *target, int damage, FName damagetype); -}; - -int ABlasterFX1::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - if (target->IsKindOf (PClass::FindClass ("Ironlich"))) - { // Less damage to Ironlich bosses - damage = pr_bfx1() & 1; - if (!damage) - { - return -1; - } - } - return damage; -} - -void ABlasterFX1::Effect () -{ - if (pr_bfx1t() < 64) - { - Spawn("BlasterSmoke", PosAtZ(MAX(Z() - 8., floorz)), ALLOW_REPLACE); - } -} - -IMPLEMENT_CLASS(ABlasterFX1) - -// Ripper ------------------------------------------------------------------- - - -class ARipper : public AActor -{ - DECLARE_CLASS (ARipper, AActor) -public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS(ARipper) - -int ARipper::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - if (target->IsKindOf (PClass::FindClass ("Ironlich"))) - { // Less damage to Ironlich bosses - damage = pr_ripd() & 1; - if (!damage) - { - return -1; - } - } - return damage; -} - -//---------------------------------------------------------------------------- -// -// PROC A_FireBlasterPL1 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FireBlasterPL1) -{ - PARAM_ACTION_PROLOGUE; - - DAngle angle; - int damage; - 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; - } - DAngle pitch = P_BulletSlope(self); - damage = pr_fb1.HitDice (4); - angle = self->Angles.Yaw; - if (player->refire) - { - angle += pr_fb1.Random2() * (5.625 / 256); - } - P_LineAttack (self, angle, PLAYERMISSILERANGE, pitch, damage, NAME_Hitscan, "BlasterPuff"); - S_Sound (self, CHAN_WEAPON, "weapons/blastershoot", 1, ATTN_NORM); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_SpawnRippers -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_SpawnRippers) -{ - PARAM_ACTION_PROLOGUE; - - unsigned int i; - DAngle angle; - AActor *ripper; - - for(i = 0; i < 8; i++) - { - ripper = Spawn (self->Pos(), ALLOW_REPLACE); - angle = i*45.; - ripper->target = self->target; - ripper->Angles.Yaw = angle; - ripper->VelFromAngle(); - P_CheckMissileSpawn (ripper, self->radius); - } - return 0; -} - -// --- Skull rod ------------------------------------------------------------ - - -// Horn Rod FX 2 ------------------------------------------------------------ - -class AHornRodFX2 : public AActor -{ - DECLARE_CLASS (AHornRodFX2, AActor) -public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS (AHornRodFX2) - -int AHornRodFX2::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - if (target->IsKindOf (PClass::FindClass("Sorcerer2")) && pr_hrfx2() < 96) - { // D'Sparil teleports away - P_DSparilTeleport (target); - return -1; - } - return damage; -} - -// Rain pillar 1 ------------------------------------------------------------ - -class ARainPillar : public AActor -{ - DECLARE_CLASS (ARainPillar, AActor) -public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS (ARainPillar) - -int ARainPillar::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - if (target->flags2 & MF2_BOSS) - { // Decrease damage for bosses - damage = (pr_rp() & 7) + 1; - } - return damage; -} - -// Rain tracker "inventory" item -------------------------------------------- - -class ARainTracker : public AInventory -{ - DECLARE_CLASS (ARainTracker, AInventory) -public: - - void Serialize(FSerializer &arc); - TObjPtr Rain1, Rain2; -}; - -IMPLEMENT_CLASS (ARainTracker) - -void ARainTracker::Serialize(FSerializer &arc) -{ - Super::Serialize (arc); - arc("rain1", Rain1) - ("rain2", Rain2); -} - -//---------------------------------------------------------------------------- -// -// PROC A_FireSkullRodPL1 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL1) -{ - PARAM_ACTION_PROLOGUE; - - AActor *mo; - player_t *player; - - if (NULL == (player = self->player)) - { - return 0; - } - - AWeapon *weapon = player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - mo = P_SpawnPlayerMissile (self, PClass::FindActor("HornRodFX1")); - // Randomize the first frame - if (mo && pr_fsr1() > 128) - { - mo->SetState (mo->state->GetNextState()); - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_FireSkullRodPL2 -// -// The special2 field holds the player number that shot the rain missile. -// The special1 field holds the id of the rain sound. -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL2) -{ - PARAM_ACTION_PROLOGUE; - - player_t *player; - AActor *MissileActor; - FTranslatedLineTarget t; - - if (NULL == (player = self->player)) - { - return 0; - } - AWeapon *weapon = player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - P_SpawnPlayerMissile (self, 0,0,0, RUNTIME_CLASS(AHornRodFX2), self->Angles.Yaw, &t, &MissileActor); - // Use MissileActor instead of the return value from - // P_SpawnPlayerMissile because we need to give info to the mobj - // even if it exploded immediately. - if (MissileActor != NULL) - { - MissileActor->special2 = (int)(player - players); - if (t.linetarget && !t.unlinked) - { - MissileActor->tracer = t.linetarget; - } - S_Sound (MissileActor, CHAN_WEAPON, "weapons/hornrodpowshoot", 1, ATTN_NORM); - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_AddPlayerRain -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_AddPlayerRain) -{ - PARAM_ACTION_PROLOGUE; - - ARainTracker *tracker; - - if (self->target == NULL || self->target->health <= 0) - { // Shooter is dead or nonexistant - return 0; - } - - tracker = self->target->FindInventory (); - - // They player is only allowed two rainstorms at a time. Shooting more - // than that will cause the oldest one to terminate. - if (tracker != NULL) - { - if (tracker->Rain1 && tracker->Rain2) - { // Terminate an active rain - if (tracker->Rain1->health < tracker->Rain2->health) - { - if (tracker->Rain1->health > 16) - { - tracker->Rain1->health = 16; - } - tracker->Rain1 = NULL; - } - else - { - if (tracker->Rain2->health > 16) - { - tracker->Rain2->health = 16; - } - tracker->Rain2 = NULL; - } - } - } - else - { - tracker = static_cast (self->target->GiveInventoryType (RUNTIME_CLASS(ARainTracker))); - } - // Add rain mobj to list - if (tracker->Rain1) - { - tracker->Rain2 = self; - } - else - { - tracker->Rain1 = self; - } - self->special1 = S_FindSound ("misc/rain"); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_SkullRodStorm -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm) -{ - PARAM_ACTION_PROLOGUE; - - AActor *mo; - ARainTracker *tracker; - - if (self->health-- == 0) - { - S_StopSound (self, CHAN_BODY); - if (self->target == NULL) - { // Player left the game - self->Destroy (); - return 0; - } - tracker = self->target->FindInventory (); - if (tracker != NULL) - { - if (tracker->Rain1 == self) - { - tracker->Rain1 = NULL; - } - else if (tracker->Rain2 == self) - { - tracker->Rain2 = NULL; - } - } - self->Destroy (); - return 0; - } - if (pr_storm() < 25) - { // Fudge rain frequency - return 0; - } - double xo = ((pr_storm() & 127) - 64); - double yo = ((pr_storm() & 127) - 64); - DVector3 pos = self->Vec2OffsetZ(xo, yo, ONCEILINGZ); - mo = Spawn (pos, ALLOW_REPLACE); - // We used bouncecount to store the 3D floor index in A_HideInCeiling - if (!mo) return 0; - if (mo->Sector->PortalGroup != self->Sector->PortalGroup) - { - // spawning this through a portal will never work right so abort right away. - mo->Destroy(); - return 0; - } - if (self->bouncecount >= 0 && (unsigned)self->bouncecount < self->Sector->e->XFloor.ffloors.Size()) - pos.Z = self->Sector->e->XFloor.ffloors[self->bouncecount]->bottom.plane->ZatPoint(mo); - else - pos.Z = self->Sector->ceilingplane.ZatPoint(mo); - int moceiling = P_Find3DFloor(NULL, pos, false, false, pos.Z); - if (moceiling >= 0) mo->SetZ(pos.Z - mo->Height); - mo->Translation = multiplayer ? TRANSLATION(TRANSLATION_RainPillar,self->special2) : 0; - mo->target = self->target; - mo->Vel.X = MinVel; // Force collision detection - mo->Vel.Z = -mo->Speed; - mo->special2 = self->special2; // Transfer player number - P_CheckMissileSpawn (mo, self->radius); - if (self->special1 != -1 && !S_IsActorPlayingSomething (self, CHAN_BODY, -1)) - { - S_Sound (self, CHAN_BODY|CHAN_LOOP, self->special1, 1, ATTN_NORM); - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_RainImpact -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_RainImpact) -{ - PARAM_ACTION_PROLOGUE; - if (self->Z() > self->floorz) - { - self->SetState (self->FindState("NotFloor")); - } - else if (pr_impact() < 40) - { - P_HitFloor (self); - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_HideInCeiling -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_HideInCeiling) -{ - PARAM_ACTION_PROLOGUE; - - // We use bouncecount to store the 3D floor index - double foo; - for (int i = self->Sector->e->XFloor.ffloors.Size() - 1; i >= 0; i--) - { - F3DFloor * rover = self->Sector->e->XFloor.ffloors[i]; - if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue; - - if ((foo = rover->bottom.plane->ZatPoint(self)) >= self->Top()) - { - self->SetZ(foo + 4, false); - self->bouncecount = i; - return 0; - } - } - self->bouncecount = -1; - self->SetZ(self->ceilingz + 4, false); - return 0; -} - -// --- Phoenix Rod ---------------------------------------------------------- - -class APhoenixRod : public AWeapon -{ - DECLARE_CLASS (APhoenixRod, AWeapon) -public: - - void Serialize(FSerializer &arc) - { - Super::Serialize (arc); - arc("flamecount", FlameCount); - } - int FlameCount; // for flamethrower duration -}; - -class APhoenixRodPowered : public APhoenixRod -{ - DECLARE_CLASS (APhoenixRodPowered, APhoenixRod) -public: - void EndPowerup (); -}; - -IMPLEMENT_CLASS (APhoenixRod) -IMPLEMENT_CLASS (APhoenixRodPowered) - -void APhoenixRodPowered::EndPowerup () -{ - DepleteAmmo (bAltFire); - Owner->player->refire = 0; - S_StopSound (Owner, CHAN_WEAPON); - Owner->player->ReadyWeapon = SisterWeapon; - P_SetPsprite(Owner->player, PSP_WEAPON, SisterWeapon->GetReadyState()); -} - -class APhoenixFX1 : public AActor -{ - DECLARE_CLASS (APhoenixFX1, AActor) -public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); -}; - - -IMPLEMENT_CLASS (APhoenixFX1) - -int APhoenixFX1::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - if (target->IsKindOf (PClass::FindClass("Sorcerer2")) && pr_hrfx2() < 96) - { // D'Sparil teleports away - P_DSparilTeleport (target); - return -1; - } - return damage; -} - -// Phoenix FX 2 ------------------------------------------------------------- - -class APhoenixFX2 : public AActor -{ - DECLARE_CLASS (APhoenixFX2, AActor) -public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS (APhoenixFX2) - -int APhoenixFX2::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - if (target->player && pr_pfx2 () < 128) - { // Freeze player for a bit - target->reactiontime += 4; - } - return damage; -} - -//---------------------------------------------------------------------------- -// -// PROC A_FirePhoenixPL1 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL1) -{ - 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(APhoenixFX1)); - self->Thrust(self->Angles.Yaw + 180, 4); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_PhoenixPuff -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_PhoenixPuff) -{ - PARAM_ACTION_PROLOGUE; - - AActor *puff; - DAngle angle; - - //[RH] Heretic never sets the target for seeking - //P_SeekerMissile (self, 5, 10); - puff = Spawn("PhoenixPuff", self->Pos(), ALLOW_REPLACE); - angle = self->Angles.Yaw + 90; - puff->Vel = DVector3(angle.ToVector(1.3), 0); - - puff = Spawn("PhoenixPuff", self->Pos(), ALLOW_REPLACE); - angle = self->Angles.Yaw - 90; - puff->Vel = DVector3(angle.ToVector(1.3), 0); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_InitPhoenixPL2 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_InitPhoenixPL2) -{ - PARAM_ACTION_PROLOGUE; - - if (self->player != NULL) - { - APhoenixRod *flamethrower = static_cast (self->player->ReadyWeapon); - if (flamethrower != NULL) - { - flamethrower->FlameCount = FLAME_THROWER_TICS; - } - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_FirePhoenixPL2 -// -// Flame thrower effect. -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL2) -{ - PARAM_ACTION_PROLOGUE; - - AActor *mo; - - double slope; - FSoundID soundid; - player_t *player; - APhoenixRod *flamethrower; - - if (nullptr == (player = self->player)) - { - return 0; - } - - soundid = "weapons/phoenixpowshoot"; - - flamethrower = static_cast (player->ReadyWeapon); - if (flamethrower == nullptr || --flamethrower->FlameCount == 0) - { // Out of flame - P_SetPsprite(player, PSP_WEAPON, flamethrower->FindState("Powerdown")); - player->refire = 0; - S_StopSound (self, CHAN_WEAPON); - return 0; - } - - slope = -self->Angles.Pitch.TanClamped(); - double xo = pr_fp2.Random2() / 128.; - double yo = pr_fp2.Random2() / 128.; - DVector3 pos = self->Vec3Offset(xo, yo, 26 + slope - self->Floorclip); - - slope += 0.1; - mo = Spawn("PhoenixFX2", pos, ALLOW_REPLACE); - mo->target = self; - mo->Angles.Yaw = self->Angles.Yaw; - mo->VelFromAngle(); - mo->Vel += self->Vel.XY(); - mo->Vel.Z = mo->Speed * slope; - if (!player->refire || !S_IsActorPlayingSomething (self, CHAN_WEAPON, -1)) - { - S_Sound (self, CHAN_WEAPON|CHAN_LOOP, soundid, 1, ATTN_NORM); - } - P_CheckMissileSpawn (mo, self->radius); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_ShutdownPhoenixPL2 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_ShutdownPhoenixPL2) -{ - PARAM_ACTION_PROLOGUE; - - player_t *player; - - if (NULL == (player = self->player)) - { - return 0; - } - S_StopSound (self, CHAN_WEAPON); - AWeapon *weapon = player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_FlameEnd -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FlameEnd) -{ - PARAM_ACTION_PROLOGUE; - - self->Vel.Z += 1.5; - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_FloatPuff -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_FloatPuff) -{ - PARAM_ACTION_PROLOGUE; - - self->Vel.Z += 1.8; - return 0; -} - diff --git a/src/g_heretic/a_ironlich.cpp b/src/g_heretic/a_ironlich.cpp deleted file mode 100644 index a887484070..0000000000 --- a/src/g_heretic/a_ironlich.cpp +++ /dev/null @@ -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; -} - diff --git a/src/g_heretic/a_knight.cpp b/src/g_heretic/a_knight.cpp deleted file mode 100644 index 9f42a328ae..0000000000 --- a/src/g_heretic/a_knight.cpp +++ /dev/null @@ -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; -} - diff --git a/src/g_heretic/a_wizard.cpp b/src/g_heretic/a_wizard.cpp deleted file mode 100644 index 704488f16b..0000000000 --- a/src/g_heretic/a_wizard.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_hexen/a_bats.cpp b/src/g_hexen/a_bats.cpp deleted file mode 100644 index 56c7ac0247..0000000000 --- a/src/g_hexen/a_bats.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_hexen/a_bishop.cpp b/src/g_hexen/a_bishop.cpp deleted file mode 100644 index 5fb95d8bee..0000000000 --- a/src/g_hexen/a_bishop.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_hexen/a_blastradius.cpp b/src/g_hexen/a_blastradius.cpp deleted file mode 100644 index f906d247c1..0000000000 --- a/src/g_hexen/a_blastradius.cpp +++ /dev/null @@ -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 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; -} diff --git a/src/g_hexen/a_boostarmor.cpp b/src/g_hexen/a_boostarmor.cpp deleted file mode 100644 index 3234174f36..0000000000 --- a/src/g_hexen/a_boostarmor.cpp +++ /dev/null @@ -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(); - 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(); - armor->flags |= MF_DROPPED; - armor->SaveAmount = 50; - armor->MaxSaveAmount = 300; - if (!armor->CallTryPickup (Owner)) - { - armor->Destroy (); - return false; - } - else - { - return true; - } - } -} - diff --git a/src/g_hexen/a_centaur.cpp b/src/g_hexen/a_centaur.cpp deleted file mode 100644 index 692688b63c..0000000000 --- a/src/g_hexen/a_centaur.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_hexen/a_clericflame.cpp b/src/g_hexen/a_clericflame.cpp deleted file mode 100644 index 5b4eba2e85..0000000000 --- a/src/g_hexen/a_clericflame.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_hexen/a_clericholy.cpp b/src/g_hexen/a_clericholy.cpp deleted file mode 100644 index b08ab3e74a..0000000000 --- a/src/g_hexen/a_clericholy.cpp +++ /dev/null @@ -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 (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 (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 (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; -} - diff --git a/src/g_hexen/a_clericmace.cpp b/src/g_hexen/a_clericmace.cpp deleted file mode 100644 index 69f1f729cb..0000000000 --- a/src/g_hexen/a_clericmace.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_hexen/a_clericstaff.cpp b/src/g_hexen/a_clericstaff.cpp deleted file mode 100644 index de4e1d75f2..0000000000 --- a/src/g_hexen/a_clericstaff.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_hexen/a_dragon.cpp b/src/g_hexen/a_dragon.cpp deleted file mode 100644 index c94be3988f..0000000000 --- a/src/g_hexen/a_dragon.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_hexen/a_fighteraxe.cpp b/src/g_hexen/a_fighteraxe.cpp deleted file mode 100644 index f47ad6a9d7..0000000000 --- a/src/g_hexen/a_fighteraxe.cpp +++ /dev/null @@ -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; -} - diff --git a/src/g_hexen/a_fighterhammer.cpp b/src/g_hexen/a_fighterhammer.cpp deleted file mode 100644 index c33737bfdd..0000000000 --- a/src/g_hexen/a_fighterhammer.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_hexen/a_fighterplayer.cpp b/src/g_hexen/a_fighterplayer.cpp deleted file mode 100644 index 3624ed6250..0000000000 --- a/src/g_hexen/a_fighterplayer.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_hexen/a_fighterquietus.cpp b/src/g_hexen/a_fighterquietus.cpp deleted file mode 100644 index 3d04e984af..0000000000 --- a/src/g_hexen/a_fighterquietus.cpp +++ /dev/null @@ -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; -} - diff --git a/src/g_hexen/a_firedemon.cpp b/src/g_hexen/a_firedemon.cpp deleted file mode 100644 index 712363167b..0000000000 --- a/src/g_hexen/a_firedemon.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_hexen/a_flechette.cpp b/src/g_hexen/a_flechette.cpp deleted file mode 100644 index ccc2bf1126..0000000000 --- a/src/g_hexen/a_flechette.cpp +++ /dev/null @@ -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(-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(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(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(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(); - 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 (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; -} diff --git a/src/g_hexen/a_flies.cpp b/src/g_hexen/a_flies.cpp deleted file mode 100644 index 1023c12aec..0000000000 --- a/src/g_hexen/a_flies.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_hexen/a_fog.cpp b/src/g_hexen/a_fog.cpp deleted file mode 100644 index b89f8d38cc..0000000000 --- a/src/g_hexen/a_fog.cpp +++ /dev/null @@ -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; -} - diff --git a/src/g_hexen/a_healingradius.cpp b/src/g_hexen/a_healingradius.cpp deleted file mode 100644 index c381f39643..0000000000 --- a/src/g_hexen/a_healingradius.cpp +++ /dev/null @@ -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(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 (); - 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(PClass::FindClass(NAME_Mana1)), amount) || - players[i].mo->GiveAmmo (dyn_cast(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; - -} diff --git a/src/g_hexen/a_heresiarch.cpp b/src/g_hexen/a_heresiarch.cpp deleted file mode 100644 index c96c4cc1f2..0000000000 --- a/src/g_hexen/a_heresiarch.cpp +++ /dev/null @@ -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(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 (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(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; -} diff --git a/src/g_hexen/a_hexenglobal.h b/src/g_hexen/a_hexenglobal.h deleted file mode 100644 index 3455b684df..0000000000 --- a/src/g_hexen/a_hexenglobal.h +++ /dev/null @@ -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__ diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp deleted file mode 100644 index 31a17c3a37..0000000000 --- a/src/g_hexen/a_hexenmisc.cpp +++ /dev/null @@ -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" diff --git a/src/g_hexen/a_hexenspecialdecs.cpp b/src/g_hexen/a_hexenspecialdecs.cpp deleted file mode 100644 index 28de8d46a2..0000000000 --- a/src/g_hexen/a_hexenspecialdecs.cpp +++ /dev/null @@ -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; -} - diff --git a/src/g_hexen/a_iceguy.cpp b/src/g_hexen/a_iceguy.cpp deleted file mode 100644 index d00e860415..0000000000 --- a/src/g_hexen/a_iceguy.cpp +++ /dev/null @@ -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; -} - diff --git a/src/g_hexen/a_korax.cpp b/src/g_hexen/a_korax.cpp deleted file mode 100644 index 7f0d3a43cf..0000000000 --- a/src/g_hexen/a_korax.cpp +++ /dev/null @@ -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); -} diff --git a/src/g_hexen/a_magecone.cpp b/src/g_hexen/a_magecone.cpp deleted file mode 100644 index f31e57e581..0000000000 --- a/src/g_hexen/a_magecone.cpp +++ /dev/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; -} diff --git a/src/g_hexen/a_magelightning.cpp b/src/g_hexen/a_magelightning.cpp deleted file mode 100644 index 896384f4e4..0000000000 --- a/src/g_hexen/a_magelightning.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_hexen/a_magestaff.cpp b/src/g_hexen/a_magestaff.cpp deleted file mode 100644 index d7b06d009e..0000000000 --- a/src/g_hexen/a_magestaff.cpp +++ /dev/null @@ -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 (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 (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; -} diff --git a/src/g_hexen/a_pig.cpp b/src/g_hexen/a_pig.cpp deleted file mode 100644 index ea767dccd0..0000000000 --- a/src/g_hexen/a_pig.cpp +++ /dev/null @@ -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; -} diff --git a/src/g_hexen/a_serpent.cpp b/src/g_hexen/a_serpent.cpp deleted file mode 100644 index 9984660536..0000000000 --- a/src/g_hexen/a_serpent.cpp +++ /dev/null @@ -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; -} - diff --git a/src/g_hexen/a_spike.cpp b/src/g_hexen/a_spike.cpp deleted file mode 100644 index 9f73963996..0000000000 --- a/src/g_hexen/a_spike.cpp +++ /dev/null @@ -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 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(self)->DirtClump = - Spawn("DirtClump", self->Pos(), ALLOW_REPLACE); - return 0; -} - - -DEFINE_ACTION_FUNCTION(AActor, A_ThrustRaise) -{ - PARAM_ACTION_PROLOGUE; - - AThrustFloor *actor = static_cast(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; -} - diff --git a/src/g_hexen/a_summon.cpp b/src/g_hexen/a_summon.cpp deleted file mode 100644 index eb5d825bf2..0000000000 --- a/src/g_hexen/a_summon.cpp +++ /dev/null @@ -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(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(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(); - 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; -} diff --git a/src/g_hexen/a_teleportother.cpp b/src/g_hexen/a_teleportother.cpp deleted file mode 100644 index 7333d9d917..0000000000 --- a/src/g_hexen/a_teleportother.cpp +++ /dev/null @@ -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); - } -} diff --git a/src/g_hexen/a_wraith.cpp b/src/g_hexen/a_wraith.cpp deleted file mode 100644 index 460fa65032..0000000000 --- a/src/g_hexen/a_wraith.cpp +++ /dev/null @@ -1,258 +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 "a_sharedglobal.h" -#include "thingdef/thingdef.h" -*/ - -static FRandom pr_stealhealth ("StealHealth"); -static FRandom pr_wraithfx2 ("WraithFX2"); -static FRandom pr_wraithfx3 ("WraithFX3"); -static FRandom pr_wraithfx4 ("WraithFX4"); - -//============================================================================ -// -// A_WraithInit -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_WraithInit) -{ - PARAM_ACTION_PROLOGUE; - - self->AddZ(48); - - // [RH] Make sure the wraith didn't go into the ceiling - if (self->Top() > self->ceilingz) - { - self->SetZ(self->ceilingz - self->Height); - } - - self->WeaveIndexZ = 0; // index into floatbob - return 0; -} - -//============================================================================ -// -// A_WraithRaiseInit -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_WraithRaiseInit) -{ - PARAM_ACTION_PROLOGUE; - - self->renderflags &= ~RF_INVISIBLE; - self->flags2 &= ~MF2_NONSHOOTABLE; - self->flags3 &= ~MF3_DONTBLAST; - self->flags |= MF_SHOOTABLE|MF_SOLID; - self->Floorclip = self->Height; - return 0; -} - -//============================================================================ -// -// A_WraithRaise -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_WraithRaise) -{ - PARAM_ACTION_PROLOGUE; - - if (A_RaiseMobj (self, 2)) - { - // Reached it's target height - // [RH] Once a buried wraith is fully raised, it should be - // morphable, right? - self->flags3 &= ~(MF3_DONTMORPH|MF3_SPECIALFLOORCLIP); - self->SetState (self->FindState("Chase")); - // [RH] Reset PainChance to a normal wraith's. - self->PainChance = GetDefaultByName ("Wraith")->PainChance; - } - - P_SpawnDirt (self, self->radius); - return 0; -} - -//============================================================================ -// -// A_WraithMelee -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_WraithMelee) -{ - PARAM_ACTION_PROLOGUE; - - int amount; - - // Steal health from target and give to self - if (self->CheckMeleeRange() && (pr_stealhealth()<220)) - { - amount = pr_stealhealth.HitDice (2); - P_DamageMobj (self->target, self, self, amount, NAME_Melee); - self->health += amount; - } - return 0; -} - -//============================================================================ -// -// A_WraithFX2 - spawns sparkle tail of missile -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_WraithFX2) -{ - PARAM_ACTION_PROLOGUE; - - AActor *mo; - DAngle angle; - int i; - - for (i = 2; i; --i) - { - mo = Spawn ("WraithFX2", self->Pos(), ALLOW_REPLACE); - if(mo) - { - angle = pr_wraithfx2() * (360 / 1024.f); - if (pr_wraithfx2() >= 128) - { - angle = -angle; - } - angle += self->Angles.Yaw; - mo->Vel.X = ((pr_wraithfx2() / 512.) + 1) * angle.Cos(); - mo->Vel.Y = ((pr_wraithfx2() / 512.) + 1) * angle.Sin(); - mo->Vel.Z = 0; - mo->target = self; - mo->Floorclip = 10; - } - } - return 0; -} - -//============================================================================ -// -// A_WraithFX3 -// -// Spawn an FX3 around the self during attacks -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_WraithFX3) -{ - PARAM_ACTION_PROLOGUE; - - AActor *mo; - int numdropped = pr_wraithfx3() % 15; - - while (numdropped-- > 0) - { - double xo = (pr_wraithfx3() - 128) / 32.; - double yo = (pr_wraithfx3() - 128) / 32.; - double zo = pr_wraithfx3() / 64.; - - mo = Spawn("WraithFX3", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); - if (mo) - { - mo->floorz = self->floorz; - mo->ceilingz = self->ceilingz; - mo->target = self; - } - } - return 0; -} - -//============================================================================ -// -// A_WraithFX4 -// -// Spawn an FX4 during movement -// -//============================================================================ - -void A_WraithFX4 (AActor *self) -{ - AActor *mo; - int chance = pr_wraithfx4(); - bool spawn4, spawn5; - - if (chance < 10) - { - spawn4 = true; - spawn5 = false; - } - else if (chance < 20) - { - spawn4 = false; - spawn5 = true; - } - else if (chance < 25) - { - spawn4 = true; - spawn5 = true; - } - else - { - spawn4 = false; - spawn5 = false; - } - - if (spawn4) - { - double xo = (pr_wraithfx4() - 128) / 16.; - double yo = (pr_wraithfx4() - 128) / 16.; - double zo = (pr_wraithfx4() / 64.); - - mo = Spawn ("WraithFX4", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); - if (mo) - { - mo->floorz = self->floorz; - mo->ceilingz = self->ceilingz; - mo->target = self; - } - } - if (spawn5) - { - double xo = (pr_wraithfx4() - 128) / 32.; - double yo = (pr_wraithfx4() - 128) / 32.; - double zo = (pr_wraithfx4() / 64.); - - mo = Spawn ("WraithFX5", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); - if (mo) - { - mo->floorz = self->floorz; - mo->ceilingz = self->ceilingz; - mo->target = self; - } - } -} - -//============================================================================ -// -// A_WraithChase -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_WraithChase) -{ - PARAM_ACTION_PROLOGUE; - - int weaveindex = self->WeaveIndexZ; - self->AddZ(BobSin(weaveindex)); - self->WeaveIndexZ = (weaveindex + 2) & 63; -// if (self->Floorclip > 0) -// { -// P_SetMobjState(self, S_WRAITH_RAISE2); -// return; -// } - A_Chase (stack, self); - A_WraithFX4 (self); - return 0; -} diff --git a/src/g_inventory/a_ammo.cpp b/src/g_inventory/a_ammo.cpp new file mode 100644 index 0000000000..23a9221874 --- /dev/null +++ b/src/g_inventory/a_ammo.cpp @@ -0,0 +1,381 @@ +/* +** a_ammo.cpp +** Implements ammo and backpack items. +** +**--------------------------------------------------------------------------- +** Copyright 2000-2016 Randy Heit +** Copyright 2006-2016 Cheistoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include "c_dispatch.h" +#include "d_player.h" +#include "serializer.h" + +IMPLEMENT_CLASS(PClassAmmo, false, false) + +PClassAmmo::PClassAmmo() +{ + DropAmount = 0; +} + +void PClassAmmo::DeriveData(PClass *newclass) +{ + assert(newclass->IsKindOf(RUNTIME_CLASS(PClassAmmo))); + Super::DeriveData(newclass); + PClassAmmo *newc = static_cast(newclass); + + newc->DropAmount = DropAmount; +} + +IMPLEMENT_CLASS(AAmmo, false, false) + +DEFINE_FIELD(AAmmo, BackpackAmount) +DEFINE_FIELD(AAmmo, BackpackMaxAmount) + +//=========================================================================== +// +// AAmmo :: Serialize +// +//=========================================================================== + +void AAmmo::Serialize(FSerializer &arc) +{ + Super::Serialize (arc); + auto def = (AAmmo*)GetDefault(); + arc("backpackamount", BackpackAmount, def->BackpackAmount) + ("backpackmaxamount", BackpackMaxAmount, def->BackpackMaxAmount); +} + +//=========================================================================== +// +// AAmmo :: GetParentAmmo +// +// Returns the least-derived ammo type that this ammo is a descendant of. +// That is, if this ammo is an immediate subclass of Ammo, then this ammo's +// type is returned. If this ammo's superclass is not Ammo, then this +// function travels up the inheritance chain until it finds a type that is +// an immediate subclass of Ammo and returns that. +// +// The intent of this is that all unique ammo types will be immediate +// subclasses of Ammo. To make different pickups with different ammo amounts, +// you subclass the type of ammo you want a different amount for and edit +// that. +// +//=========================================================================== + +PClassActor *AAmmo::GetParentAmmo () const +{ + PClass *type = GetClass(); + + while (type->ParentClass != RUNTIME_CLASS(AAmmo) && type->ParentClass != NULL) + { + type = type->ParentClass; + } + return static_cast(type); +} + +//=========================================================================== +// +// AAmmo :: HandlePickup +// +//=========================================================================== +EXTERN_CVAR(Bool, sv_unlimited_pickup) + +bool AAmmo::HandlePickup (AInventory *item) +{ + if (GetClass() == item->GetClass() || + (item->IsKindOf (RUNTIME_CLASS(AAmmo)) && static_cast(item)->GetParentAmmo() == GetClass())) + { + if (Amount < MaxAmount || sv_unlimited_pickup) + { + int receiving = item->Amount; + + if (!(item->ItemFlags & IF_IGNORESKILL)) + { // extra ammo in baby mode and nightmare mode + receiving = int(receiving * G_SkillProperty(SKILLP_AmmoFactor)); + } + int oldamount = Amount; + + if (Amount > 0 && Amount + receiving < 0) + { + Amount = 0x7fffffff; + } + else + { + Amount += receiving; + } + if (Amount > MaxAmount && !sv_unlimited_pickup) + { + Amount = MaxAmount; + } + item->ItemFlags |= IF_PICKUPGOOD; + + // If the player previously had this ammo but ran out, possibly switch + // to a weapon that uses it, but only if the player doesn't already + // have a weapon pending. + + assert (Owner != NULL); + + if (oldamount == 0 && Owner != NULL && Owner->player != NULL) + { + barrier_cast(Owner)->CheckWeaponSwitch(GetClass()); + } + } + return true; + } + return false; +} + +//=========================================================================== +// +// AAmmo :: CreateCopy +// +//=========================================================================== + +AInventory *AAmmo::CreateCopy (AActor *other) +{ + AInventory *copy; + int amount = Amount; + + // extra ammo in baby mode and nightmare mode + if (!(ItemFlags&IF_IGNORESKILL)) + { + amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor)); + } + + if (GetClass()->ParentClass != RUNTIME_CLASS(AAmmo) && GetClass() != RUNTIME_CLASS(AAmmo)) + { + PClassActor *type = GetParentAmmo(); + if (!GoAway ()) + { + Destroy (); + } + + copy = static_cast(Spawn (type)); + copy->Amount = amount; + copy->BecomeItem (); + } + else + { + copy = Super::CreateCopy (other); + copy->Amount = amount; + } + if (copy->Amount > copy->MaxAmount) + { // Don't pick up more ammo than you're supposed to be able to carry. + copy->Amount = copy->MaxAmount; + } + return copy; +} + +//=========================================================================== +// +// AAmmo :: CreateTossable +// +//=========================================================================== + +AInventory *AAmmo::CreateTossable() +{ + AInventory *copy = Super::CreateTossable(); + if (copy != NULL) + { // Do not increase ammo by dropping it and picking it back up at + // certain skill levels. + copy->ItemFlags |= IF_IGNORESKILL; + } + return copy; +} + + +// Backpack ----------------------------------------------------------------- + +IMPLEMENT_CLASS(ABackpackItem, false, false) + +DEFINE_FIELD(ABackpackItem, bDepleted) + +//=========================================================================== +// +// ABackpackItem :: Serialize +// +//=========================================================================== + +void ABackpackItem::Serialize(FSerializer &arc) +{ + Super::Serialize (arc); + auto def = (ABackpackItem*)GetDefault(); + arc("bdepleted", bDepleted, def->bDepleted); +} + +//=========================================================================== +// +// ABackpackItem :: CreateCopy +// +// A backpack is being added to a player who doesn't yet have one. Give them +// every kind of ammo, and increase their max amounts. +// +//=========================================================================== + +AInventory *ABackpackItem::CreateCopy (AActor *other) +{ + // Find every unique type of ammo. Give it to the player if + // he doesn't have it already, and double its maximum capacity. + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) + { + PClass *type = PClassActor::AllActorClasses[i]; + + if (type->ParentClass == RUNTIME_CLASS(AAmmo)) + { + PClassActor *atype = static_cast(type); + AAmmo *ammo = static_cast(other->FindInventory(atype)); + int amount = static_cast(GetDefaultByType(type))->BackpackAmount; + // extra ammo in baby mode and nightmare mode + if (!(ItemFlags&IF_IGNORESKILL)) + { + amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor)); + } + if (amount < 0) amount = 0; + if (ammo == NULL) + { // The player did not have the ammo. Add it. + ammo = static_cast(Spawn(atype)); + ammo->Amount = bDepleted ? 0 : amount; + if (ammo->BackpackMaxAmount > ammo->MaxAmount) + { + ammo->MaxAmount = ammo->BackpackMaxAmount; + } + if (ammo->Amount > ammo->MaxAmount) + { + ammo->Amount = ammo->MaxAmount; + } + ammo->AttachToOwner (other); + } + else + { // The player had the ammo. Give some more. + if (ammo->MaxAmount < ammo->BackpackMaxAmount) + { + ammo->MaxAmount = ammo->BackpackMaxAmount; + } + if (!bDepleted && ammo->Amount < ammo->MaxAmount) + { + ammo->Amount += amount; + if (ammo->Amount > ammo->MaxAmount) + { + ammo->Amount = ammo->MaxAmount; + } + } + } + } + } + return Super::CreateCopy (other); +} + +//=========================================================================== +// +// ABackpackItem :: HandlePickup +// +// When the player picks up another backpack, just give them more ammo. +// +//=========================================================================== + +bool ABackpackItem::HandlePickup (AInventory *item) +{ + // Since you already have a backpack, that means you already have every + // kind of ammo in your inventory, so we don't need to look at the + // entire PClass list to discover what kinds of ammo exist, and we don't + // have to alter the MaxAmount either. + if (item->IsKindOf (RUNTIME_CLASS(ABackpackItem))) + { + for (AInventory *probe = Owner->Inventory; probe != NULL; probe = probe->Inventory) + { + if (probe->GetClass()->ParentClass == RUNTIME_CLASS(AAmmo)) + { + if (probe->Amount < probe->MaxAmount || sv_unlimited_pickup) + { + int amount = static_cast(probe->GetDefault())->BackpackAmount; + // extra ammo in baby mode and nightmare mode + if (!(item->ItemFlags&IF_IGNORESKILL)) + { + amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor)); + } + probe->Amount += amount; + if (probe->Amount > probe->MaxAmount && !sv_unlimited_pickup) + { + probe->Amount = probe->MaxAmount; + } + } + } + } + // The pickup always succeeds, even if you didn't get anything + item->ItemFlags |= IF_PICKUPGOOD; + return true; + } + return false; +} + +//=========================================================================== +// +// ABackpackItem :: CreateTossable +// +// The tossed backpack must not give out any more ammo, otherwise a player +// could cheat by dropping their backpack and picking it up for more ammo. +// +//=========================================================================== + +AInventory *ABackpackItem::CreateTossable () +{ + ABackpackItem *pack = static_cast(Super::CreateTossable()); + if (pack != NULL) + { + pack->bDepleted = true; + } + return pack; +} + +//=========================================================================== +// +// ABackpackItem :: DetachFromOwner +// +//=========================================================================== + +void ABackpackItem::DetachFromOwner () +{ + // When removing a backpack, drop the player's ammo maximums to normal + AInventory *item; + + for (item = Owner->Inventory; item != NULL; item = item->Inventory) + { + if (item->GetClass()->ParentClass == RUNTIME_CLASS(AAmmo) && + item->MaxAmount == static_cast(item)->BackpackMaxAmount) + { + item->MaxAmount = static_cast(item->GetDefault())->MaxAmount; + if (item->Amount > item->MaxAmount) + { + item->Amount = item->MaxAmount; + } + } + } +} + diff --git a/src/g_inventory/a_ammo.h b/src/g_inventory/a_ammo.h new file mode 100644 index 0000000000..643d4b9248 --- /dev/null +++ b/src/g_inventory/a_ammo.h @@ -0,0 +1,47 @@ +#pragma once +#include "a_pickups.h" + +// Ammo: Something a weapon needs to operate +class PClassAmmo : public PClassInventory +{ + DECLARE_CLASS(PClassAmmo, PClassInventory) +protected: + virtual void DeriveData(PClass *newclass); +public: + PClassAmmo(); + + int DropAmount; // Specifies the amount for a dropped ammo item. +}; + +class AAmmo : public AInventory +{ + DECLARE_CLASS_WITH_META(AAmmo, AInventory, PClassAmmo) +public: + + virtual void Serialize(FSerializer &arc) override; + virtual AInventory *CreateCopy (AActor *other) override; + virtual bool HandlePickup (AInventory *item) override; + virtual AInventory *CreateTossable () override; + PClassActor *GetParentAmmo () const; + + int BackpackAmount, BackpackMaxAmount; +}; + + +// A backpack gives you one clip of each ammo and doubles your +// normal maximum ammo amounts. +class ABackpackItem : public AInventory +{ + DECLARE_CLASS (ABackpackItem, AInventory) +public: + + virtual void Serialize(FSerializer &arc) override; + virtual bool HandlePickup (AInventory *item) override; + virtual AInventory *CreateCopy (AActor *other) override; + virtual AInventory *CreateTossable () override; + virtual void DetachFromOwner () override; + + bool bDepleted; +}; + + diff --git a/src/g_shared/a_armor.cpp b/src/g_inventory/a_armor.cpp similarity index 79% rename from src/g_shared/a_armor.cpp rename to src/g_inventory/a_armor.cpp index 50472e51d0..ebe8f49f6b 100644 --- a/src/g_shared/a_armor.cpp +++ b/src/g_inventory/a_armor.cpp @@ -1,19 +1,71 @@ +/* +** a_armor.cpp +** Implements all variations of armor objects +** +**--------------------------------------------------------------------------- +** Copyright 2002-2016 Randy Heit +** Copyright 2006-2016 Cheistoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + #include #include "info.h" #include "gi.h" #include "a_pickups.h" +#include "a_armor.h" #include "templates.h" #include "g_level.h" #include "d_player.h" #include "serializer.h" +#include "cmdlib.h" +IMPLEMENT_CLASS(AArmor, false, false) +IMPLEMENT_CLASS(ABasicArmor, false, false) +IMPLEMENT_CLASS(ABasicArmorPickup, false, false) +IMPLEMENT_CLASS(ABasicArmorBonus, false, false) +IMPLEMENT_CLASS(AHexenArmor, false, false) -IMPLEMENT_CLASS (AArmor) -IMPLEMENT_CLASS (ABasicArmor) -IMPLEMENT_CLASS (ABasicArmorPickup) -IMPLEMENT_CLASS (ABasicArmorBonus) -IMPLEMENT_CLASS (AHexenArmor) +//=========================================================================== +// +// +// BasicArmor +// +// +//=========================================================================== + +DEFINE_FIELD(ABasicArmor, AbsorbCount) +DEFINE_FIELD(ABasicArmor, SavePercent) +DEFINE_FIELD(ABasicArmor, MaxAbsorb) +DEFINE_FIELD(ABasicArmor, MaxFullAbsorb) +DEFINE_FIELD(ABasicArmor, BonusCount) +DEFINE_FIELD(ABasicArmor, ArmorType) +DEFINE_FIELD(ABasicArmor, ActualSaveAmount) //=========================================================================== // @@ -106,10 +158,6 @@ bool ABasicArmor::HandlePickup (AInventory *item) armor->SaveAmount = int(armor->SaveAmount * G_SkillProperty(SKILLP_ArmorFactor)); } - if (Inventory != NULL) - { - return Inventory->HandlePickup (item); - } return false; } @@ -193,6 +241,20 @@ void ABasicArmor::AbsorbDamage (int damage, FName damageType, int &newdamage) } } +//=========================================================================== +// +// +// BasicArmorPickup +// +// +//=========================================================================== + + +DEFINE_FIELD(ABasicArmorPickup, SavePercent) +DEFINE_FIELD(ABasicArmorPickup, MaxAbsorb) +DEFINE_FIELD(ABasicArmorPickup, MaxFullAbsorb) +DEFINE_FIELD(ABasicArmorPickup, SaveAmount) + //=========================================================================== // // ABasicArmorPickup :: Serialize @@ -279,6 +341,23 @@ bool ABasicArmorPickup::Use (bool pickup) return true; } +//=========================================================================== +// +// +// BasicArmorBonus +// +// +//=========================================================================== + + +DEFINE_FIELD(ABasicArmorBonus, SavePercent) +DEFINE_FIELD(ABasicArmorBonus, MaxSaveAmount) +DEFINE_FIELD(ABasicArmorBonus, MaxAbsorb) +DEFINE_FIELD(ABasicArmorBonus, MaxFullAbsorb) +DEFINE_FIELD(ABasicArmorBonus, SaveAmount) +DEFINE_FIELD(ABasicArmorBonus, BonusCount) +DEFINE_FIELD(ABasicArmorBonus, BonusMax) + //=========================================================================== // // ABasicArmorBonus :: Serialize @@ -382,6 +461,17 @@ bool ABasicArmorBonus::Use (bool pickup) return true; } +//=========================================================================== +// +// +// HexenArmor +// +// +//=========================================================================== + +DEFINE_FIELD(AHexenArmor, Slots) +DEFINE_FIELD(AHexenArmor, SlotsIncrement) + //=========================================================================== // // AHexenArmor :: Serialize @@ -442,10 +532,6 @@ bool AHexenArmor::HandlePickup (AInventory *item) } return true; } - else if (Inventory != NULL) - { - return Inventory->HandlePickup (item); - } return false; } @@ -549,6 +635,11 @@ void AHexenArmor::AbsorbDamage (int damage, FName damageType, int &newdamage) } } +//=========================================================================== +// +// AHexenArmor :: DepleteOrDestroy +// +//=========================================================================== void AHexenArmor::DepleteOrDestroy() { diff --git a/src/g_inventory/a_armor.h b/src/g_inventory/a_armor.h new file mode 100644 index 0000000000..63febda912 --- /dev/null +++ b/src/g_inventory/a_armor.h @@ -0,0 +1,89 @@ +#pragma once + +#include "a_pickups.h" + +// Armor absorbs some damage for the player. +class AArmor : public AInventory +{ + DECLARE_CLASS (AArmor, AInventory) +}; + +// Basic armor absorbs a specific percent of the damage. You should +// never pickup a BasicArmor. Instead, you pickup a BasicArmorPickup +// or BasicArmorBonus and those gives you BasicArmor when it activates. +class ABasicArmor : public AArmor +{ + DECLARE_CLASS (ABasicArmor, AArmor) +public: + + virtual void Serialize(FSerializer &arc) override; + virtual void Tick () override; + virtual AInventory *CreateCopy (AActor *other) override; + virtual bool HandlePickup (AInventory *item) override; + virtual void AbsorbDamage (int damage, FName damageType, int &newdamage) override; + + int AbsorbCount; + double SavePercent; + int MaxAbsorb; + int MaxFullAbsorb; + int BonusCount; + FNameNoInit ArmorType; + int ActualSaveAmount; +}; + +// BasicArmorPickup replaces the armor you have. +class ABasicArmorPickup : public AArmor +{ + DECLARE_CLASS (ABasicArmorPickup, AArmor) +public: + + virtual void Serialize(FSerializer &arc) override; + virtual AInventory *CreateCopy (AActor *other) override; + virtual bool Use (bool pickup) override; + + double SavePercent; + int MaxAbsorb; + int MaxFullAbsorb; + int SaveAmount; +}; + +// BasicArmorBonus adds to the armor you have. +class ABasicArmorBonus : public AArmor +{ + DECLARE_CLASS (ABasicArmorBonus, AArmor) +public: + + virtual void Serialize(FSerializer &arc) override; + virtual AInventory *CreateCopy (AActor *other) override; + virtual bool Use (bool pickup) override; + + double SavePercent; // The default, for when you don't already have armor + int MaxSaveAmount; + int MaxAbsorb; + int MaxFullAbsorb; + int SaveAmount; + int BonusCount; + int BonusMax; +}; + +// Hexen armor consists of four separate armor types plus a conceptual armor +// type (the player himself) that work together as a single armor. +class AHexenArmor : public AArmor +{ + DECLARE_CLASS (AHexenArmor, AArmor) +public: + + virtual void Serialize(FSerializer &arc) override; + virtual AInventory *CreateCopy (AActor *other) override; + virtual AInventory *CreateTossable () override; + virtual bool HandlePickup (AInventory *item) override; + virtual void AbsorbDamage (int damage, FName damageType, int &newdamage) override; + virtual void DepleteOrDestroy() override; + + double Slots[5]; + double SlotsIncrement[4]; + +protected: + bool AddArmorToSlot (AActor *actor, int slot, int amount); +}; + diff --git a/src/g_shared/a_artifacts.cpp b/src/g_inventory/a_artifacts.cpp similarity index 93% rename from src/g_shared/a_artifacts.cpp rename to src/g_inventory/a_artifacts.cpp index 7e4970e040..4afe74f1f0 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_inventory/a_artifacts.cpp @@ -40,21 +40,23 @@ static FRandom pr_torch ("Torch"); #define TIMEFREEZE_TICS ( 12 * TICRATE ) */ -IMPLEMENT_CLASS (APowerup) + +IMPLEMENT_CLASS(APowerup, false, false) // Powerup-Giver ------------------------------------------------------------- -IMPLEMENT_CLASS(PClassPowerupGiver) -void PClassPowerupGiver::ReplaceClassRef(PClass *oldclass, PClass *newclass) -{ - Super::ReplaceClassRef(oldclass, newclass); - APowerupGiver *def = (APowerupGiver*)Defaults; - if (def != NULL) - { - if (def->PowerupType == oldclass) def->PowerupType = static_cast(newclass); - } -} +IMPLEMENT_CLASS(APowerupGiver, false, true) + +IMPLEMENT_POINTERS_START(APowerupGiver) +IMPLEMENT_POINTER(PowerupType) +IMPLEMENT_POINTERS_END + +DEFINE_FIELD(APowerupGiver, PowerupType) +DEFINE_FIELD(APowerupGiver, EffectTics) +DEFINE_FIELD(APowerupGiver, BlendColor) +DEFINE_FIELD(APowerupGiver, Mode) +DEFINE_FIELD(APowerupGiver, Strength) //=========================================================================== // @@ -65,6 +67,7 @@ void PClassPowerupGiver::ReplaceClassRef(PClass *oldclass, PClass *newclass) bool APowerupGiver::Use (bool pickup) { if (PowerupType == NULL) return true; // item is useless + if (Owner == nullptr) return true; APowerup *power = static_cast (Spawn (PowerupType)); @@ -114,6 +117,11 @@ void APowerupGiver::Serialize(FSerializer &arc) // Powerup ------------------------------------------------------------------- +DEFINE_FIELD(APowerup, EffectTics) +DEFINE_FIELD(APowerup, BlendColor) +DEFINE_FIELD(APowerup, Mode) +DEFINE_FIELD(APowerup, Strength) + //=========================================================================== // // APowerup :: Tick @@ -297,10 +305,6 @@ bool APowerup::HandlePickup (AInventory *item) power->ItemFlags |= IF_PICKUPGOOD; return true; } - if (Inventory != NULL) - { - return Inventory->HandlePickup (item); - } return false; } @@ -362,21 +366,9 @@ void APowerup::OwnerDied () Destroy (); } -//=========================================================================== -// -// AInventory :: GetNoTeleportFreeze -// -//=========================================================================== - -bool APowerup::GetNoTeleportFreeze () -{ - if (ItemFlags & IF_NOTELEPORTFREEZE) return true; - return Super::GetNoTeleportFreeze(); -} - // Invulnerability Powerup --------------------------------------------------- -IMPLEMENT_CLASS (APowerInvulnerable) +IMPLEMENT_CLASS(APowerInvulnerable, false, false) //=========================================================================== // @@ -513,7 +505,7 @@ int APowerInvulnerable::AlterWeaponSprite (visstyle_t *vis) // Strength (aka Berserk) Powerup -------------------------------------------- -IMPLEMENT_CLASS (APowerStrength) +IMPLEMENT_CLASS(APowerStrength, false, false) //=========================================================================== // @@ -578,7 +570,7 @@ PalEntry APowerStrength::GetBlend () // Invisibility Powerup ------------------------------------------------------ -IMPLEMENT_CLASS (APowerInvisibility) +IMPLEMENT_CLASS(APowerInvisibility, false, false) // Invisibility flag combos #define INVISIBILITY_FLAGS1 (MF_SHADOW) @@ -783,7 +775,7 @@ bool APowerInvisibility::HandlePickup (AInventory *item) // Ironfeet Powerup ---------------------------------------------------------- -IMPLEMENT_CLASS (APowerIronFeet) +IMPLEMENT_CLASS(APowerIronFeet, false, false) //=========================================================================== // @@ -820,7 +812,7 @@ void APowerIronFeet::DoEffect () // Strife Environment Suit Powerup ------------------------------------------- -IMPLEMENT_CLASS (APowerMask) +IMPLEMENT_CLASS(APowerMask, false, false) //=========================================================================== // @@ -857,7 +849,7 @@ void APowerMask::DoEffect () // Light-Amp Powerup --------------------------------------------------------- -IMPLEMENT_CLASS (APowerLightAmp) +IMPLEMENT_CLASS(APowerLightAmp, false, false) //=========================================================================== // @@ -899,7 +891,7 @@ void APowerLightAmp::EndEffect () // Torch Powerup ------------------------------------------------------------- -IMPLEMENT_CLASS (APowerTorch) +IMPLEMENT_CLASS(APowerTorch, false, false) //=========================================================================== // @@ -962,7 +954,7 @@ void APowerTorch::DoEffect () // Flight (aka Wings of Wrath) powerup --------------------------------------- -IMPLEMENT_CLASS (APowerFlight) +IMPLEMENT_CLASS(APowerFlight, false, false) //=========================================================================== // @@ -1102,7 +1094,7 @@ bool APowerFlight::DrawPowerup (int x, int y) // Weapon Level 2 (aka Tome of Power) Powerup -------------------------------- -IMPLEMENT_CLASS (APowerWeaponLevel2) +IMPLEMENT_CLASS(APowerWeaponLevel2, false, false) //=========================================================================== // @@ -1173,7 +1165,7 @@ void APowerWeaponLevel2::EndEffect () if (player->ReadyWeapon != NULL && player->ReadyWeapon->WeaponFlags & WIF_POWERED_UP) { - player->ReadyWeapon->EndPowerup (); + player->ReadyWeapon->CallEndPowerup (); } if (player->PendingWeapon != NULL && player->PendingWeapon != WP_NOCHANGE && player->PendingWeapon->WeaponFlags & WIF_POWERED_UP && @@ -1184,39 +1176,11 @@ void APowerWeaponLevel2::EndEffect () } } -// Player Speed Trail (used by the Speed Powerup) ---------------------------- - -class APlayerSpeedTrail : public AActor -{ - DECLARE_CLASS (APlayerSpeedTrail, AActor) -public: - void Tick (); -}; - -IMPLEMENT_CLASS (APlayerSpeedTrail) - -//=========================================================================== -// -// APlayerSpeedTrail :: Tick -// -//=========================================================================== - -void APlayerSpeedTrail::Tick () -{ - const double fade = .6 / 8; - if (Alpha <= fade) - { - Destroy (); - } - else - { - Alpha -= fade; - } -} - // Speed Powerup ------------------------------------------------------------- -IMPLEMENT_CLASS (APowerSpeed) +IMPLEMENT_CLASS(APowerSpeed, false, false) + +DEFINE_FIELD(APowerSpeed, SpeedFlags) //=========================================================================== // @@ -1230,20 +1194,6 @@ void APowerSpeed::Serialize(FSerializer &arc) arc("speedflags", SpeedFlags); } -//=========================================================================== -// -// APowerSpeed :: GetSpeedFactor -// -//=========================================================================== - -double APowerSpeed ::GetSpeedFactor () -{ - if (Inventory != NULL) - return Speed * Inventory->GetSpeedFactor(); - else - return Speed; -} - //=========================================================================== // // APowerSpeed :: DoEffect @@ -1280,7 +1230,7 @@ void APowerSpeed::DoEffect () if (Owner->Vel.LengthSquared() <= 12*12) return; - AActor *speedMo = Spawn (Owner->Pos(), NO_REPLACE); + AActor *speedMo = Spawn("PlayerSpeedTrail", Owner->Pos(), NO_REPLACE); if (speedMo) { speedMo->Angles.Yaw = Owner->Angles.Yaw; @@ -1303,11 +1253,11 @@ void APowerSpeed::DoEffect () // Minotaur (aka Dark Servant) powerup --------------------------------------- -IMPLEMENT_CLASS (APowerMinotaur) +IMPLEMENT_CLASS(APowerMinotaur, false, false) // Targeter powerup --------------------------------------------------------- -IMPLEMENT_CLASS (APowerTargeter) +IMPLEMENT_CLASS(APowerTargeter, false, false) void APowerTargeter::Travelled () { @@ -1422,7 +1372,7 @@ void APowerTargeter::PositionAccuracy () // Frightener Powerup -------------------------------- -IMPLEMENT_CLASS (APowerFrightener) +IMPLEMENT_CLASS(APowerFrightener, false, false) //=========================================================================== // @@ -1458,7 +1408,7 @@ void APowerFrightener::EndEffect () // Buddha Powerup -------------------------------- -IMPLEMENT_CLASS (APowerBuddha) +IMPLEMENT_CLASS(APowerBuddha, false, false) //=========================================================================== // @@ -1494,11 +1444,11 @@ void APowerBuddha::EndEffect () // Scanner powerup ---------------------------------------------------------- -IMPLEMENT_CLASS (APowerScanner) +IMPLEMENT_CLASS(APowerScanner, false, false) // Time freezer powerup ----------------------------------------------------- -IMPLEMENT_CLASS( APowerTimeFreezer) +IMPLEMENT_CLASS( APowerTimeFreezer, false, false) //=========================================================================== // @@ -1625,7 +1575,7 @@ void APowerTimeFreezer::EndEffect() // Damage powerup ------------------------------------------------------ -IMPLEMENT_CLASS(APowerDamage) +IMPLEMENT_CLASS(APowerDamage, false, false) //=========================================================================== // @@ -1682,7 +1632,7 @@ void APowerDamage::ModifyDamage(int damage, FName damageType, int &newdamage, bo // Quarter damage powerup ------------------------------------------------------ -IMPLEMENT_CLASS(APowerProtection) +IMPLEMENT_CLASS(APowerProtection, false, false) #define PROTECTION_FLAGS3 (MF3_NORADIUSDMG | MF3_DONTMORPH | MF3_DONTSQUASH | MF3_DONTBLAST | MF3_NOTELEOTHER) #define PROTECTION_FLAGS5 (MF5_NOPAIN | MF5_DONTRIP) @@ -1760,7 +1710,7 @@ void APowerProtection::ModifyDamage(int damage, FName damageType, int &newdamage // Drain rune ------------------------------------------------------- -IMPLEMENT_CLASS(APowerDrain) +IMPLEMENT_CLASS(APowerDrain, false, false) //=========================================================================== // @@ -1800,7 +1750,7 @@ void APowerDrain::EndEffect( ) // Regeneration rune ------------------------------------------------------- -IMPLEMENT_CLASS(APowerRegeneration) +IMPLEMENT_CLASS(APowerRegeneration, false, false) //=========================================================================== // @@ -1822,7 +1772,7 @@ void APowerRegeneration::DoEffect() // High jump rune ------------------------------------------------------- -IMPLEMENT_CLASS(APowerHighJump) +IMPLEMENT_CLASS(APowerHighJump, false, false) //=========================================================================== // @@ -1860,7 +1810,7 @@ void APowerHighJump::EndEffect( ) // Double firing speed rune --------------------------------------------- -IMPLEMENT_CLASS(APowerDoubleFiringSpeed) +IMPLEMENT_CLASS(APowerDoubleFiringSpeed, false, false) //=========================================================================== // @@ -1898,7 +1848,21 @@ void APowerDoubleFiringSpeed::EndEffect( ) // Morph powerup ------------------------------------------------------ -IMPLEMENT_CLASS(APowerMorph) +IMPLEMENT_CLASS(APowerMorph, false, true) + +IMPLEMENT_POINTERS_START(APowerMorph) + IMPLEMENT_POINTER(PlayerClass) + IMPLEMENT_POINTER(MorphFlash) + IMPLEMENT_POINTER(UnMorphFlash) +IMPLEMENT_POINTERS_END + + +DEFINE_FIELD(APowerMorph, PlayerClass) +DEFINE_FIELD(APowerMorph, MorphFlash) +DEFINE_FIELD(APowerMorph, UnMorphFlash) +DEFINE_FIELD(APowerMorph, MorphStyle) +DEFINE_FIELD(APowerMorph, MorphedPlayer) +DEFINE_FIELD(APowerMorph, bInUndoMorph) //=========================================================================== // @@ -1913,7 +1877,7 @@ void APowerMorph::Serialize(FSerializer &arc) ("morphstyle", MorphStyle) ("morphflash", MorphFlash) ("unmorphflash", UnMorphFlash) - ("player", Player); + ("morphedplayer", MorphedPlayer); } //=========================================================================== @@ -1926,17 +1890,14 @@ void APowerMorph::InitEffect( ) { Super::InitEffect(); - if (Owner != NULL && Owner->player != NULL && PlayerClass != NAME_None) + if (Owner != nullptr && Owner->player != nullptr && PlayerClass != nullptr) { player_t *realplayer = Owner->player; // Remember the identity of the player - PClassActor *morph_flash = PClass::FindActor(MorphFlash); - PClassActor *unmorph_flash = PClass::FindActor(UnMorphFlash); - PClassPlayerPawn *player_class = dyn_cast(PClass::FindClass (PlayerClass)); - if (P_MorphPlayer(realplayer, realplayer, player_class, -1/*INDEFINITELY*/, MorphStyle, morph_flash, unmorph_flash)) + if (P_MorphPlayer(realplayer, realplayer, PlayerClass, -1/*INDEFINITELY*/, MorphStyle, MorphFlash, UnMorphFlash)) { Owner = realplayer->mo; // Replace the new owner in our owner; safe because we are not attached to anything yet ItemFlags |= IF_CREATECOPYMOVED; // Let the caller know the "real" owner has changed (to the morphed actor) - Player = realplayer; // Store the player identity (morphing clears the unmorphed actor's "player" field) + MorphedPlayer = realplayer; // Store the player identity (morphing clears the unmorphed actor's "player" field) } else // morph failed - give the caller an opportunity to fail the pickup completely { @@ -1955,54 +1916,47 @@ void APowerMorph::EndEffect( ) { Super::EndEffect(); - // Abort if owner already destroyed - if (Owner == NULL) + // Abort if owner already destroyed or unmorphed + if (Owner == nullptr || MorphedPlayer == nullptr) { - assert(Player == NULL); return; } - // Abort if owner already unmorphed - if (Player == NULL) - { - return; - } - // Abort if owner is dead; their Die() method will // take care of any required unmorphing on death. - if (Player->health <= 0) + if (MorphedPlayer->health <= 0) { return; } // Unmorph if possible - if (!bNoCallUndoMorph) + if (!bInUndoMorph) { - int savedMorphTics = Player->morphTics; - P_UndoPlayerMorph (Player, Player, 0, !!(Player->MorphStyle & MORPH_UNDOALWAYS)); + int savedMorphTics = MorphedPlayer->morphTics; + P_UndoPlayerMorph (MorphedPlayer, MorphedPlayer, 0, !!(MorphedPlayer->MorphStyle & MORPH_UNDOALWAYS)); // Abort if unmorph failed; in that case, // set the usual retry timer and return. - if (Player != NULL && Player->morphTics) + if (MorphedPlayer != NULL && MorphedPlayer->morphTics) { // Transfer retry timeout // to the powerup's timer. - EffectTics = Player->morphTics; + EffectTics = MorphedPlayer->morphTics; // Reload negative morph tics; // use actual value; it may // be in use for animation. - Player->morphTics = savedMorphTics; + MorphedPlayer->morphTics = savedMorphTics; // Try again some time later return; } } // Unmorph suceeded - Player = NULL; + MorphedPlayer = NULL; } // Infinite Ammo Powerup ----------------------------------------------------- -IMPLEMENT_CLASS(APowerInfiniteAmmo) +IMPLEMENT_CLASS(APowerInfiniteAmmo, false, false) //=========================================================================== // diff --git a/src/g_shared/a_artifacts.h b/src/g_inventory/a_artifacts.h similarity index 52% rename from src/g_shared/a_artifacts.h rename to src/g_inventory/a_artifacts.h index 85ebc2e81b..bb821b5d63 100644 --- a/src/g_shared/a_artifacts.h +++ b/src/g_inventory/a_artifacts.h @@ -11,17 +11,15 @@ class APowerup : public AInventory { DECLARE_CLASS (APowerup, AInventory) public: - virtual void Tick (); - virtual void Destroy (); - virtual bool HandlePickup (AInventory *item); - virtual AInventory *CreateCopy (AActor *other); - virtual AInventory *CreateTossable (); - - virtual void Serialize(FSerializer &arc); - virtual void OwnerDied (); - virtual bool GetNoTeleportFreeze(); - virtual PalEntry GetBlend (); - virtual bool DrawPowerup (int x, int y); + virtual void Tick () override; + virtual void Destroy () override; + virtual bool HandlePickup (AInventory *item) override; + virtual AInventory *CreateCopy (AActor *other) override; + virtual AInventory *CreateTossable () override; + virtual void Serialize(FSerializer &arc) override; + virtual void OwnerDied () override; + virtual PalEntry GetBlend () override; + virtual bool DrawPowerup (int x, int y) override; int EffectTics; PalEntry BlendColor; @@ -30,30 +28,21 @@ public: protected: virtual void InitEffect (); - virtual void DoEffect (); + virtual void DoEffect () override; virtual void EndEffect (); friend void EndAllPowerupEffects(AInventory *item); friend void InitAllPowerupEffects(AInventory *item); }; -class PClassPowerupGiver: public PClassInventory -{ - DECLARE_CLASS(PClassPowerupGiver, PClassInventory) -protected: -public: - virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); -}; - - // An artifact is an item that gives the player a powerup when activated. class APowerupGiver : public AInventory { - DECLARE_CLASS_WITH_META (APowerupGiver, AInventory, PClassPowerupGiver) + DECLARE_CLASS (APowerupGiver, AInventory) + HAS_OBJECT_POINTERS public: - virtual bool Use (bool pickup); - - virtual void Serialize(FSerializer &arc); + virtual bool Use (bool pickup) override; + virtual void Serialize(FSerializer &arc) override; PClassActor *PowerupType; @@ -67,10 +56,10 @@ class APowerInvulnerable : public APowerup { DECLARE_CLASS (APowerInvulnerable, APowerup) protected: - void InitEffect (); - void DoEffect (); - void EndEffect (); - int AlterWeaponSprite (visstyle_t *vis); + virtual void InitEffect () override; + virtual void DoEffect () override; + virtual void EndEffect () override; + virtual int AlterWeaponSprite (visstyle_t *vis) override; }; class APowerStrength : public APowerup @@ -79,44 +68,44 @@ class APowerStrength : public APowerup public: PalEntry GetBlend (); protected: - void InitEffect (); - void Tick (); - bool HandlePickup (AInventory *item); + virtual void InitEffect () override; + virtual void Tick () override; + virtual bool HandlePickup (AInventory *item) override; }; class APowerInvisibility : public APowerup { DECLARE_CLASS (APowerInvisibility, APowerup) protected: - bool HandlePickup (AInventory *item); - void InitEffect (); - void DoEffect (); - void EndEffect (); - int AlterWeaponSprite (visstyle_t *vis); + virtual bool HandlePickup (AInventory *item) override; + virtual void InitEffect () override; + virtual void DoEffect () override; + virtual void EndEffect () override; + virtual int AlterWeaponSprite (visstyle_t *vis) override; }; class APowerIronFeet : public APowerup { DECLARE_CLASS (APowerIronFeet, APowerup) public: - void AbsorbDamage (int damage, FName damageType, int &newdamage); - void DoEffect (); + virtual void AbsorbDamage (int damage, FName damageType, int &newdamage) override; + virtual void DoEffect () override; }; class APowerMask : public APowerIronFeet { DECLARE_CLASS (APowerMask, APowerIronFeet) public: - void AbsorbDamage (int damage, FName damageType, int &newdamage); - void DoEffect (); + virtual void AbsorbDamage (int damage, FName damageType, int &newdamage) override; + virtual void DoEffect () override; }; class APowerLightAmp : public APowerup { DECLARE_CLASS (APowerLightAmp, APowerup) protected: - void DoEffect (); - void EndEffect (); + virtual void DoEffect () override; + virtual void EndEffect () override; }; class APowerTorch : public APowerLightAmp @@ -124,9 +113,9 @@ class APowerTorch : public APowerLightAmp DECLARE_CLASS (APowerTorch, APowerLightAmp) public: - virtual void Serialize(FSerializer &arc); + virtual void Serialize(FSerializer &arc) override; protected: - void DoEffect (); + virtual void DoEffect () override; int NewTorch, NewTorchDelta; }; @@ -134,15 +123,15 @@ class APowerFlight : public APowerup { DECLARE_CLASS (APowerFlight, APowerup) public: - bool DrawPowerup (int x, int y); - - virtual void Serialize(FSerializer &arc); + virtual bool DrawPowerup (int x, int y) override; + virtual void Serialize(FSerializer &arc) override; protected: - void InitEffect (); - void Tick (); - void EndEffect (); + virtual void InitEffect () override; + virtual void Tick () override; + virtual void EndEffect () override; +private: bool HitCenterFrame; }; @@ -150,18 +139,17 @@ class APowerWeaponLevel2 : public APowerup { DECLARE_CLASS (APowerWeaponLevel2, APowerup) protected: - void InitEffect (); - void EndEffect (); + virtual void InitEffect () override; + virtual void EndEffect () override; }; class APowerSpeed : public APowerup { DECLARE_CLASS (APowerSpeed, APowerup) protected: - void DoEffect (); + virtual void DoEffect () override; - virtual void Serialize(FSerializer &arc); - double GetSpeedFactor(); + virtual void Serialize(FSerializer &arc) override; public: int SpeedFlags; }; @@ -182,114 +170,116 @@ class APowerTargeter : public APowerup { DECLARE_CLASS (APowerTargeter, APowerup) protected: - void InitEffect (); - void DoEffect (); - void EndEffect (); + virtual void InitEffect () override; + virtual void DoEffect () override; + virtual void EndEffect () override; void PositionAccuracy (); - void Travelled (); - void AttachToOwner(AActor *other); - bool HandlePickup(AInventory *item); + virtual void Travelled () override; + virtual void AttachToOwner(AActor *other) override; + virtual bool HandlePickup(AInventory *item) override; }; class APowerFrightener : public APowerup { DECLARE_CLASS (APowerFrightener, APowerup) protected: - void InitEffect (); - void EndEffect (); + virtual void InitEffect () override; + virtual void EndEffect () override; }; class APowerBuddha : public APowerup { DECLARE_CLASS (APowerBuddha, APowerup) protected: - void InitEffect (); - void EndEffect (); + virtual void InitEffect () override; + virtual void EndEffect () override; }; class APowerTimeFreezer : public APowerup { DECLARE_CLASS( APowerTimeFreezer, APowerup ) protected: - void InitEffect( ); - void DoEffect( ); - void EndEffect( ); + virtual void InitEffect() override; + virtual void DoEffect() override; + virtual void EndEffect() override; }; class APowerDamage : public APowerup { DECLARE_CLASS( APowerDamage, APowerup ) protected: - void InitEffect (); - void EndEffect (); - virtual void ModifyDamage (int damage, FName damageType, int &newdamage, bool passive); + virtual void InitEffect () override; + virtual void EndEffect () override; + virtual void ModifyDamage (int damage, FName damageType, int &newdamage, bool passive) override; }; class APowerProtection : public APowerup { DECLARE_CLASS( APowerProtection, APowerup ) protected: - void InitEffect (); - void EndEffect (); - virtual void ModifyDamage (int damage, FName damageType, int &newdamage, bool passive); + virtual void InitEffect () override; + virtual void EndEffect () override; + virtual void ModifyDamage (int damage, FName damageType, int &newdamage, bool passive) override; }; class APowerDrain : public APowerup { DECLARE_CLASS( APowerDrain, APowerup ) protected: - void InitEffect( ); - void EndEffect( ); + virtual void InitEffect() override; + virtual void EndEffect() override; }; class APowerRegeneration : public APowerup { DECLARE_CLASS( APowerRegeneration, APowerup ) protected: - void DoEffect(); + virtual void DoEffect() override; }; class APowerHighJump : public APowerup { DECLARE_CLASS( APowerHighJump, APowerup ) protected: - void InitEffect( ); - void EndEffect( ); + virtual void InitEffect() override; + virtual void EndEffect() override; }; class APowerDoubleFiringSpeed : public APowerup { DECLARE_CLASS( APowerDoubleFiringSpeed, APowerup ) protected: - void InitEffect( ); - void EndEffect( ); + virtual void InitEffect() override; + virtual void EndEffect() override; }; class APowerInfiniteAmmo : public APowerup { DECLARE_CLASS( APowerInfiniteAmmo, APowerup ) protected: - void InitEffect( ); - void EndEffect( ); + virtual void InitEffect() override; + virtual void EndEffect() override; }; class APowerMorph : public APowerup { DECLARE_CLASS( APowerMorph, APowerup ) + HAS_OBJECT_POINTERS public: - virtual void Serialize(FSerializer &arc); - void SetNoCallUndoMorph() { bNoCallUndoMorph = true; } + virtual void Serialize(FSerializer &arc) override; + void SetNoCallUndoMorph() { bInUndoMorph = true; } - FNameNoInit PlayerClass, MorphFlash, UnMorphFlash; + // Variables + PClassPlayerPawn *PlayerClass; + PClassActor *MorphFlash, *UnMorphFlash; int MorphStyle; + player_t *MorphedPlayer; + bool bInUndoMorph; // Because P_UndoPlayerMorph() can call EndEffect recursively protected: - void InitEffect (); - void EndEffect (); - // Variables - player_t *Player; - bool bNoCallUndoMorph; // Because P_UndoPlayerMorph() can call EndEffect recursively + virtual void InitEffect () override; + virtual void EndEffect () override; }; #endif //__A_ARTIFACTS_H__ diff --git a/src/g_inventory/a_health.cpp b/src/g_inventory/a_health.cpp new file mode 100644 index 0000000000..58cd86e2a5 --- /dev/null +++ b/src/g_inventory/a_health.cpp @@ -0,0 +1,301 @@ +/* +** a_health.cpp +** All health items +** +**--------------------------------------------------------------------------- +** Copyright 2000-2016 Randy Heit +** Copyright 2006-2016 Cheistoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include "d_player.h" +#include "a_morph.h" +#include "a_health.h" +#include "serializer.h" + +//--------------------------------------------------------------------------- +// +// FUNC P_GiveBody +// +// Returns false if the body isn't needed at all. +// +//--------------------------------------------------------------------------- + +bool P_GiveBody (AActor *actor, int num, int max) +{ + if (actor->health <= 0 || (actor->player != NULL && actor->player->playerstate == PST_DEAD)) + { // Do not heal dead things. + return false; + } + + player_t *player = actor->player; + + num = clamp(num, -65536, 65536); // prevent overflows for bad values + if (player != NULL) + { + // Max is 0 by default, preserving default behavior for P_GiveBody() + // calls while supporting AHealth. + if (max <= 0) + { + max = static_cast(actor)->GetMaxHealth() + player->mo->stamina; + // [MH] First step in predictable generic morph effects + if (player->morphTics) + { + if (player->MorphStyle & MORPH_FULLHEALTH) + { + if (!(player->MorphStyle & MORPH_ADDSTAMINA)) + { + max -= player->mo->stamina; + } + } + else // old health behaviour + { + max = MAXMORPHHEALTH; + if (player->MorphStyle & MORPH_ADDSTAMINA) + { + max += player->mo->stamina; + } + } + } + } + // [RH] For Strife: A negative body sets you up with a percentage + // of your full health. + if (num < 0) + { + num = max * -num / 100; + if (player->health < num) + { + player->health = num; + actor->health = num; + return true; + } + } + else if (num > 0) + { + if (player->health < max) + { + num = int(num * G_SkillProperty(SKILLP_HealthFactor)); + if (num < 1) num = 1; + player->health += num; + if (player->health > max) + { + player->health = max; + } + actor->health = player->health; + return true; + } + } + } + else + { + // Parameter value for max is ignored on monsters, preserving original + // behaviour on AHealth as well as on existing calls to P_GiveBody(). + max = actor->SpawnHealth(); + if (num < 0) + { + num = max * -num / 100; + if (actor->health < num) + { + actor->health = num; + return true; + } + } + else if (actor->health < max) + { + actor->health += num; + if (actor->health > max) + { + actor->health = max; + } + return true; + } + } + return false; +} + +DEFINE_ACTION_FUNCTION(AActor, GiveBody) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(num); + PARAM_INT_DEF(max); + ACTION_RETURN_BOOL(P_GiveBody(self, num, max)); +} + +//=========================================================================== +// +// Classes +// +//=========================================================================== + +IMPLEMENT_CLASS(PClassHealth, false, false) +IMPLEMENT_CLASS(AHealth, false, false) +DEFINE_FIELD(AHealth, PrevHealth) + +//=========================================================================== +// +// PClassHealth Constructor +// +//=========================================================================== + +PClassHealth::PClassHealth() +{ + LowHealth = 0; +} + +//=========================================================================== +// +// PClassHealth :: DeriveData +// +//=========================================================================== + +void PClassHealth::DeriveData(PClass *newclass) +{ + assert(newclass->IsKindOf(RUNTIME_CLASS(PClassHealth))); + Super::DeriveData(newclass); + PClassHealth *newc = static_cast(newclass); + + newc->LowHealth = LowHealth; + newc->LowHealthMessage = LowHealthMessage; +} + + +//=========================================================================== +// +// AHealth :: PickupMessage +// +//=========================================================================== +FString AHealth::PickupMessage () +{ + int threshold = GetClass()->LowHealth; + + if (PrevHealth < threshold) + { + FString message = GetClass()->LowHealthMessage; + + if (message.IsNotEmpty()) + { + return message; + } + } + return Super::PickupMessage(); +} + +//=========================================================================== +// +// AHealth :: TryPickup +// +//=========================================================================== + +bool AHealth::TryPickup (AActor *&other) +{ + PrevHealth = other->player != NULL ? other->player->health : other->health; + + // P_GiveBody adds one new feature, applied only if it is possible to pick up negative health: + // Negative values are treated as positive percentages, ie Amount -100 means 100% health, ignoring max amount. + if (P_GiveBody(other, Amount, MaxAmount)) + { + GoAwayAndDie(); + return true; + } + return false; +} + +IMPLEMENT_CLASS(AHealthPickup, false, false) + +DEFINE_FIELD(AHealthPickup, autousemode) + +//=========================================================================== +// +// AHealthPickup :: CreateCopy +// +//=========================================================================== + +AInventory *AHealthPickup::CreateCopy (AActor *other) +{ + AInventory *copy = Super::CreateCopy (other); + copy->health = health; + return copy; +} + +//=========================================================================== +// +// AHealthPickup :: CreateTossable +// +//=========================================================================== + +AInventory *AHealthPickup::CreateTossable () +{ + AInventory *copy = Super::CreateTossable (); + if (copy != NULL) + { + copy->health = health; + } + return copy; +} + +//=========================================================================== +// +// AHealthPickup :: HandlePickup +// +//=========================================================================== + +bool AHealthPickup::HandlePickup (AInventory *item) +{ + // HealthPickups that are the same type but have different health amounts + // do not count as the same item. + if (item->health == health) + { + return Super::HandlePickup (item); + } + return false; +} + +//=========================================================================== +// +// AHealthPickup :: Use +// +//=========================================================================== + +bool AHealthPickup::Use (bool pickup) +{ + return P_GiveBody (Owner, health, 0); +} + +//=========================================================================== +// +// AHealthPickup :: Serialize +// +//=========================================================================== + +void AHealthPickup::Serialize(FSerializer &arc) +{ + Super::Serialize(arc); + auto def = (AHealthPickup*)GetDefault(); + arc("autousemode", autousemode, def->autousemode); +} + diff --git a/src/g_inventory/a_health.h b/src/g_inventory/a_health.h new file mode 100644 index 0000000000..af282031c3 --- /dev/null +++ b/src/g_inventory/a_health.h @@ -0,0 +1,42 @@ +#pragma once + +#include "a_pickups.h" + +// Health is some item that gives the player health when picked up. +class PClassHealth : public PClassInventory +{ + DECLARE_CLASS(PClassHealth, PClassInventory) +protected: +public: + PClassHealth(); + virtual void DeriveData(PClass *newclass); + + FString LowHealthMessage; + int LowHealth; +}; + +class AHealth : public AInventory +{ + DECLARE_CLASS_WITH_META(AHealth, AInventory, PClassHealth) + +public: + int PrevHealth; + virtual bool TryPickup (AActor *&other) override; + virtual FString PickupMessage () override; +}; + +// HealthPickup is some item that gives the player health when used. +class AHealthPickup : public AInventory +{ + DECLARE_CLASS (AHealthPickup, AInventory) +public: + int autousemode; + + + virtual void Serialize(FSerializer &arc) override; + virtual AInventory *CreateCopy (AActor *other) override; + virtual AInventory *CreateTossable () override; + virtual bool HandlePickup (AInventory *item) override; + virtual bool Use (bool pickup) override; +}; + diff --git a/src/g_shared/a_keys.cpp b/src/g_inventory/a_keys.cpp similarity index 79% rename from src/g_shared/a_keys.cpp rename to src/g_inventory/a_keys.cpp index 2d2b5be87f..a2b5b308a5 100644 --- a/src/g_shared/a_keys.cpp +++ b/src/g_inventory/a_keys.cpp @@ -1,3 +1,36 @@ +/* +** a_keys.cpp +** Implements all keys and associated data +** +**--------------------------------------------------------------------------- +** Copyright 2005-2016 Cheistoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ #include "a_keys.h" #include "tarray.h" #include "gi.h" @@ -12,6 +45,18 @@ #include "v_font.h" +//=========================================================================== +// +// Data for the LOCKDEFS +// +//=========================================================================== + + +//=========================================================================== +// +// +//=========================================================================== + struct OneKey { PClassActor *key; @@ -45,6 +90,11 @@ struct OneKey } }; +//=========================================================================== +// +// +//=========================================================================== + struct Keygroup { TArray anykeylist; @@ -59,6 +109,11 @@ struct Keygroup } }; +//=========================================================================== +// +// +//=========================================================================== + struct Lock { TArray keylist; @@ -100,6 +155,10 @@ struct Lock } }; +//=========================================================================== +// +// +//=========================================================================== static Lock *locks[256]; // all valid locks static bool keysdone=false; // have the locks been initialized? @@ -470,7 +529,9 @@ bool P_CheckKeys (AActor *owner, int keynum, bool remote) // //========================================================================== -IMPLEMENT_CLASS (AKey) +IMPLEMENT_CLASS(AKey, false, false) + +DEFINE_FIELD(AKey, KeyNumber) bool AKey::HandlePickup (AInventory *item) { @@ -485,13 +546,14 @@ bool AKey::HandlePickup (AInventory *item) item->ItemFlags |= IF_PICKUPGOOD; return true; } - if (Inventory != NULL) - { - return Inventory->HandlePickup (item); - } return false; } +//=========================================================================== +// +// +//=========================================================================== + bool AKey::ShouldStay () { return !!multiplayer; diff --git a/src/g_inventory/a_keys.h b/src/g_inventory/a_keys.h new file mode 100644 index 0000000000..eda0473a30 --- /dev/null +++ b/src/g_inventory/a_keys.h @@ -0,0 +1,48 @@ +#ifndef A_KEYS_H +#define A_KEYS_H + +#include "a_pickups.h" + +class AKey : public AInventory +{ + DECLARE_CLASS (AKey, AInventory) +public: + virtual bool HandlePickup (AInventory *item) override; + + BYTE KeyNumber; + +protected: + virtual bool ShouldStay () override; +}; + +bool P_CheckKeys (AActor *owner, int keynum, bool remote); +void P_InitKeyMessages (); +void P_DeinitKeyMessages (); +int P_GetMapColorForLock (int lock); +int P_GetMapColorForKey (AInventory *key); + + +// PuzzleItems work in conjunction with the UsePuzzleItem special +class PClassPuzzleItem : public PClassInventory +{ + DECLARE_CLASS(PClassPuzzleItem, PClassInventory); +protected: +public: + virtual void DeriveData(PClass *newclass); + FString PuzzFailMessage; +}; + +class APuzzleItem : public AInventory +{ + DECLARE_CLASS_WITH_META(APuzzleItem, AInventory, PClassPuzzleItem) +public: + + virtual bool ShouldStay () override; + virtual bool Use (bool pickup) override; + virtual bool HandlePickup (AInventory *item) override; + + int PuzzleItemNumber; +}; + + +#endif diff --git a/src/g_shared/a_pickups.cpp b/src/g_inventory/a_pickups.cpp similarity index 61% rename from src/g_shared/a_pickups.cpp rename to src/g_inventory/a_pickups.cpp index e80e548183..bdd1b6dc66 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -11,20 +11,20 @@ #include "c_dispatch.h" #include "gstrings.h" #include "templates.h" -#include "a_strifeglobal.h" #include "a_morph.h" #include "a_specialspot.h" -#include "thingdef/thingdef.h" #include "g_level.h" #include "g_game.h" #include "doomstat.h" #include "d_player.h" #include "p_spec.h" #include "serializer.h" +#include "virtual.h" +#include "a_ammo.h" -static FRandom pr_restore ("RestorePos"); +EXTERN_CVAR(Bool, sv_unlimited_pickup) -IMPLEMENT_CLASS(PClassInventory) +IMPLEMENT_CLASS(PClassInventory, false, false) PClassInventory::PClassInventory() { @@ -45,9 +45,9 @@ void PClassInventory::DeriveData(PClass *newclass) newc->RestrictedToPlayerClass = RestrictedToPlayerClass; } -void PClassInventory::ReplaceClassRef(PClass *oldclass, PClass *newclass) +size_t PClassInventory::PointerSubstitution(DObject *oldclass, DObject *newclass) { - Super::ReplaceClassRef(oldclass, newclass); + size_t changed = Super::PointerSubstitution(oldclass, newclass); AInventory *def = (AInventory*)Defaults; if (def != NULL) { @@ -55,288 +55,27 @@ void PClassInventory::ReplaceClassRef(PClass *oldclass, PClass *newclass) for (unsigned i = 0; i < ForbiddenToPlayerClass.Size(); i++) { if (ForbiddenToPlayerClass[i] == oldclass) + { ForbiddenToPlayerClass[i] = static_cast(newclass); + changed++; + } } for (unsigned i = 0; i < RestrictedToPlayerClass.Size(); i++) { if (RestrictedToPlayerClass[i] == oldclass) + { RestrictedToPlayerClass[i] = static_cast(newclass); - } - } -} - -IMPLEMENT_CLASS(PClassAmmo) - -PClassAmmo::PClassAmmo() -{ - DropAmount = 0; -} - -void PClassAmmo::DeriveData(PClass *newclass) -{ - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassAmmo))); - Super::DeriveData(newclass); - PClassAmmo *newc = static_cast(newclass); - - newc->DropAmount = DropAmount; -} - -IMPLEMENT_CLASS (AAmmo) - -//=========================================================================== -// -// AAmmo :: Serialize -// -//=========================================================================== - -void AAmmo::Serialize(FSerializer &arc) -{ - Super::Serialize (arc); - auto def = (AAmmo*)GetDefault(); - arc("backpackamount", BackpackAmount, def->BackpackAmount) - ("backpackmaxamount", BackpackMaxAmount, def->BackpackMaxAmount); -} - -//=========================================================================== -// -// AAmmo :: GetParentAmmo -// -// Returns the least-derived ammo type that this ammo is a descendant of. -// That is, if this ammo is an immediate subclass of Ammo, then this ammo's -// type is returned. If this ammo's superclass is not Ammo, then this -// function travels up the inheritance chain until it finds a type that is -// an immediate subclass of Ammo and returns that. -// -// The intent of this is that all unique ammo types will be immediate -// subclasses of Ammo. To make different pickups with different ammo amounts, -// you subclass the type of ammo you want a different amount for and edit -// that. -// -//=========================================================================== - -PClassActor *AAmmo::GetParentAmmo () const -{ - PClass *type = GetClass(); - - while (type->ParentClass != RUNTIME_CLASS(AAmmo) && type->ParentClass != NULL) - { - type = type->ParentClass; - } - return static_cast(type); -} - -//=========================================================================== -// -// AAmmo :: HandlePickup -// -//=========================================================================== -EXTERN_CVAR(Bool, sv_unlimited_pickup) - -bool AAmmo::HandlePickup (AInventory *item) -{ - if (GetClass() == item->GetClass() || - (item->IsKindOf (RUNTIME_CLASS(AAmmo)) && static_cast(item)->GetParentAmmo() == GetClass())) - { - if (Amount < MaxAmount || sv_unlimited_pickup) - { - int receiving = item->Amount; - - if (!(item->ItemFlags & IF_IGNORESKILL)) - { // extra ammo in baby mode and nightmare mode - receiving = int(receiving * G_SkillProperty(SKILLP_AmmoFactor)); - } - int oldamount = Amount; - - if (Amount > 0 && Amount + receiving < 0) - { - Amount = 0x7fffffff; - } - else - { - Amount += receiving; - } - if (Amount > MaxAmount && !sv_unlimited_pickup) - { - Amount = MaxAmount; - } - item->ItemFlags |= IF_PICKUPGOOD; - - // If the player previously had this ammo but ran out, possibly switch - // to a weapon that uses it, but only if the player doesn't already - // have a weapon pending. - - assert (Owner != NULL); - - if (oldamount == 0 && Owner != NULL && Owner->player != NULL) - { - barrier_cast(Owner)->CheckWeaponSwitch(GetClass()); - } - } - return true; - } - if (Inventory != NULL) - { - return Inventory->HandlePickup (item); - } - return false; -} - -//=========================================================================== -// -// AAmmo :: CreateCopy -// -//=========================================================================== - -AInventory *AAmmo::CreateCopy (AActor *other) -{ - AInventory *copy; - int amount = Amount; - - // extra ammo in baby mode and nightmare mode - if (!(ItemFlags&IF_IGNORESKILL)) - { - amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor)); - } - - if (GetClass()->ParentClass != RUNTIME_CLASS(AAmmo) && GetClass() != RUNTIME_CLASS(AAmmo)) - { - PClassActor *type = GetParentAmmo(); - if (!GoAway ()) - { - Destroy (); - } - - copy = static_cast(Spawn (type)); - copy->Amount = amount; - copy->BecomeItem (); - } - else - { - copy = Super::CreateCopy (other); - copy->Amount = amount; - } - if (copy->Amount > copy->MaxAmount) - { // Don't pick up more ammo than you're supposed to be able to carry. - copy->Amount = copy->MaxAmount; - } - return copy; -} - -//=========================================================================== -// -// AAmmo :: CreateTossable -// -//=========================================================================== - -AInventory *AAmmo::CreateTossable() -{ - AInventory *copy = Super::CreateTossable(); - if (copy != NULL) - { // Do not increase ammo by dropping it and picking it back up at - // certain skill levels. - copy->ItemFlags |= IF_IGNORESKILL; - } - return copy; -} - -//--------------------------------------------------------------------------- -// -// FUNC P_GiveBody -// -// Returns false if the body isn't needed at all. -// -//--------------------------------------------------------------------------- - -bool P_GiveBody (AActor *actor, int num, int max) -{ - if (actor->health <= 0 || (actor->player != NULL && actor->player->playerstate == PST_DEAD)) - { // Do not heal dead things. - return false; - } - - player_t *player = actor->player; - - num = clamp(num, -65536, 65536); // prevent overflows for bad values - if (player != NULL) - { - // Max is 0 by default, preserving default behavior for P_GiveBody() - // calls while supporting AHealth. - if (max <= 0) - { - max = static_cast(actor)->GetMaxHealth() + player->mo->stamina; - // [MH] First step in predictable generic morph effects - if (player->morphTics) - { - if (player->MorphStyle & MORPH_FULLHEALTH) - { - if (!(player->MorphStyle & MORPH_ADDSTAMINA)) - { - max -= player->mo->stamina; - } - } - else // old health behaviour - { - max = MAXMORPHHEALTH; - if (player->MorphStyle & MORPH_ADDSTAMINA) - { - max += player->mo->stamina; - } - } - } - } - // [RH] For Strife: A negative body sets you up with a percentage - // of your full health. - if (num < 0) - { - num = max * -num / 100; - if (player->health < num) - { - player->health = num; - actor->health = num; - return true; - } - } - else if (num > 0) - { - if (player->health < max) - { - num = int(num * G_SkillProperty(SKILLP_HealthFactor)); - if (num < 1) num = 1; - player->health += num; - if (player->health > max) - { - player->health = max; - } - actor->health = player->health; - return true; + changed++; } } } - else - { - // Parameter value for max is ignored on monsters, preserving original - // behaviour on AHealth as well as on existing calls to P_GiveBody(). - max = actor->SpawnHealth(); - if (num < 0) - { - num = max * -num / 100; - if (actor->health < num) - { - actor->health = num; - return true; - } - } - else if (actor->health < max) - { - actor->health += num; - if (actor->health > max) - { - actor->health = max; - } - return true; - } - } - return false; + return changed; +} + +void PClassInventory::Finalize(FStateDefinitions &statedef) +{ + Super::Finalize(statedef); + ((AActor*)Defaults)->flags |= MF_SPECIAL; } //--------------------------------------------------------------------------- @@ -347,12 +86,12 @@ bool P_GiveBody (AActor *actor, int num, int max) // //--------------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialThing1) +DEFINE_ACTION_FUNCTION(AInventory, A_RestoreSpecialThing1) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AInventory); self->renderflags &= ~RF_INVISIBLE; - if (static_cast(self)->DoRespawn ()) + if (self->DoRespawn ()) { S_Sound (self, CHAN_VOICE, "misc/spawn", 1, ATTN_IDLE); } @@ -365,9 +104,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialThing1) // //--------------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialThing2) +DEFINE_ACTION_FUNCTION(AInventory, A_RestoreSpecialThing2) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AInventory); self->flags |= MF_SPECIAL; if (!(self->GetDefault()->flags & MF_NOGRAVITY)) @@ -385,9 +124,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialThing2) // //--------------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialDoomThing) +DEFINE_ACTION_FUNCTION(AInventory, A_RestoreSpecialDoomThing) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AInventory); self->renderflags &= ~RF_INVISIBLE; self->flags |= MF_SPECIAL; @@ -395,7 +134,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialDoomThing) { self->flags &= ~MF_NOGRAVITY; } - if (static_cast(self)->DoRespawn ()) + if (self->DoRespawn ()) { self->SetState (self->SpawnState); S_Sound (self, CHAN_VOICE, "misc/spawn", 1, ATTN_IDLE); @@ -404,69 +143,28 @@ DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialDoomThing) return 0; } -//--------------------------------------------------------------------------- -// -// PROP A_RestoreSpecialPosition -// -//--------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition) -{ - PARAM_ACTION_PROLOGUE; - - // Move item back to its original location - DVector2 sp = self->SpawnPoint; - - self->UnlinkFromWorld(); - self->SetXY(sp); - self->LinkToWorld(true); - self->SetZ(self->Sector->floorplane.ZatPoint(sp)); - P_FindFloorCeiling(self, FFCF_ONLYSPAWNPOS | FFCF_NOPORTALS); // no portal checks here so that things get spawned in this sector. - - if (self->flags & MF_SPAWNCEILING) - { - self->SetZ(self->ceilingz - self->Height - self->SpawnPoint.Z); - } - else if (self->flags2 & MF2_SPAWNFLOAT) - { - double space = self->ceilingz - self->Height - self->floorz; - if (space > 48) - { - space -= 40; - self->SetZ((space * pr_restore()) / 256. + self->floorz + 40); - } - else - { - self->SetZ(self->floorz); - } - } - else - { - self->SetZ(self->SpawnPoint.Z + self->floorz); - } - // Redo floor/ceiling check, in case of 3D floors and portals - P_FindFloorCeiling(self, FFCF_SAMESECTOR | FFCF_ONLY3DFLOORS | FFCF_3DRESTRICT); - if (self->Z() < self->floorz) - { // Do not reappear under the floor, even if that's where we were for the - // initial spawn. - self->SetZ(self->floorz); - } - if ((self->flags & MF_SOLID) && (self->Top() > self->ceilingz)) - { // Do the same for the ceiling. - self->SetZ(self->ceilingz - self->Height); - } - // Do not interpolate from the position the actor was at when it was - // picked up, in case that is different from where it is now. - self->ClearInterpolation(); - return 0; -} - int AInventory::StaticLastMessageTic; -const char *AInventory::StaticLastMessage; +FString AInventory::StaticLastMessage; -IMPLEMENT_POINTY_CLASS (AInventory) - DECLARE_POINTER (Owner) -END_POINTERS +IMPLEMENT_CLASS(AInventory, false, true) + +IMPLEMENT_POINTERS_START(AInventory) + IMPLEMENT_POINTER(Owner) +IMPLEMENT_POINTERS_END + +DEFINE_FIELD_BIT(AInventory, ItemFlags, bPickupGood, IF_PICKUPGOOD) +DEFINE_FIELD_BIT(AInventory, ItemFlags, bCreateCopyMoved, IF_CREATECOPYMOVED) +DEFINE_FIELD_BIT(AInventory, ItemFlags, bInitEffectFailed, IF_INITEFFECTFAILED) +DEFINE_FIELD(AInventory, Owner) +DEFINE_FIELD(AInventory, Amount) +DEFINE_FIELD(AInventory, MaxAmount) +DEFINE_FIELD(AInventory, InterHubAmount) +DEFINE_FIELD(AInventory, RespawnTics) +DEFINE_FIELD(AInventory, Icon) +DEFINE_FIELD(AInventory, DropTime) +DEFINE_FIELD(AInventory, SpawnPointClass) +DEFINE_FIELD(AInventory, PickupFlash) +DEFINE_FIELD(AInventory, PickupSound) //=========================================================================== // @@ -560,6 +258,27 @@ bool AInventory::SpecialDropAction (AActor *dropper) return false; } +DEFINE_ACTION_FUNCTION(AInventory, SpecialDropAction) +{ + PARAM_SELF_PROLOGUE(AInventory); + PARAM_OBJECT_NOT_NULL(dropper, AActor); + ACTION_RETURN_BOOL(self->SpecialDropAction(dropper)); +} + +bool AInventory::CallSpecialDropAction(AActor *dropper) +{ + IFVIRTUAL(AInventory, SpecialDropAction) + { + VMValue params[2] = { (DObject*)this, (DObject*)dropper }; + VMReturn ret; + int retval; + ret.IntAt(&retval); + GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); + return !!retval; + } + return SpecialDropAction(dropper); +} + //=========================================================================== // // AInventory :: ShouldRespawn @@ -628,6 +347,25 @@ void AInventory::DoEffect () { } +DEFINE_ACTION_FUNCTION(AInventory, DoEffect) +{ + PARAM_SELF_PROLOGUE(AInventory); + self->DoEffect(); + return 0; +} + +void AInventory::CallDoEffect() +{ + IFVIRTUAL(AInventory, DoEffect) + { + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } + else DoEffect(); +} + + //=========================================================================== // // AInventory :: Travelled @@ -666,7 +404,7 @@ bool AInventory::HandlePickup (AInventory *item) { if (item->GetClass() == GetClass()) { - if (Amount < MaxAmount || (sv_unlimited_pickup && !item->ShouldStay())) + if (Amount < MaxAmount || (sv_unlimited_pickup && !item->CallShouldStay())) { if (Amount > 0 && Amount + item->Amount < 0) { @@ -685,13 +423,38 @@ bool AInventory::HandlePickup (AInventory *item) } return true; } - if (Inventory != NULL) + return false; +} + +DEFINE_ACTION_FUNCTION(AInventory, HandlePickup) +{ + PARAM_SELF_PROLOGUE(AInventory); + PARAM_OBJECT_NOT_NULL(item, AInventory); + ACTION_RETURN_BOOL(self->HandlePickup(item)); +} + +bool AInventory::CallHandlePickup(AInventory *item) +{ + auto self = this; + while (self != nullptr) { - return Inventory->HandlePickup (item); + IFVIRTUALPTR(self, AInventory, HandlePickup) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[2] = { (DObject*)self, (DObject*)item }; + VMReturn ret; + int retval; + ret.IntAt(&retval); + GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); + if (retval) return true; + } + else if (self->HandlePickup(item)) return true; + self = self->Inventory; } return false; } + //=========================================================================== // // AInventory :: GoAway @@ -709,7 +472,7 @@ bool AInventory::GoAway () return false; } - if (!ShouldStay ()) + if (!CallShouldStay ()) { Hide (); if (ShouldRespawn ()) @@ -739,6 +502,14 @@ void AInventory::GoAwayAndDie () } } +DEFINE_ACTION_FUNCTION(AInventory, GoAwayAndDie) +{ + PARAM_SELF_PROLOGUE(AInventory); + self->GoAwayAndDie(); + return 0; +} + + //=========================================================================== // // AInventory :: CreateCopy @@ -767,6 +538,28 @@ AInventory *AInventory::CreateCopy (AActor *other) return copy; } +DEFINE_ACTION_FUNCTION(AInventory, CreateCopy) +{ + PARAM_SELF_PROLOGUE(AInventory); + PARAM_OBJECT(other, AActor); + ACTION_RETURN_OBJECT(self->CreateCopy(other)); +} + +AInventory *AInventory::CallCreateCopy(AActor *other) +{ + IFVIRTUAL(AInventory, CreateCopy) + { + VMValue params[2] = { (DObject*)this, (DObject*)other }; + VMReturn ret; + AInventory *retval; + ret.PointerAt((void**)&retval); + GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); + return retval; + } + else return CreateCopy(other); +} + + //=========================================================================== // // AInventory::CreateTossable @@ -811,6 +604,26 @@ AInventory *AInventory::CreateTossable () return copy; } +DEFINE_ACTION_FUNCTION(AInventory, CreateTossable) +{ + PARAM_SELF_PROLOGUE(AInventory); + ACTION_RETURN_OBJECT(self->CreateTossable()); +} + +AInventory *AInventory::CallCreateTossable() +{ + IFVIRTUAL(AInventory, CreateTossable) + { + VMValue params[1] = { (DObject*)this }; + VMReturn ret; + AInventory *retval; + ret.PointerAt((void**)&retval); + GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); + return retval; + } + else return CreateTossable(); +} + //=========================================================================== // // AInventory :: BecomeItem @@ -838,6 +651,13 @@ void AInventory::BecomeItem () SetState (FindState("Held")); } +DEFINE_ACTION_FUNCTION(AInventory, BecomeItem) +{ + PARAM_SELF_PROLOGUE(AInventory); + self->BecomeItem(); + return 0; +} + //=========================================================================== // // AInventory :: BecomePickup @@ -865,6 +685,13 @@ void AInventory::BecomePickup () SetState (SpawnState); } +DEFINE_ACTION_FUNCTION(AInventory, BecomePickup) +{ + PARAM_SELF_PROLOGUE(AInventory); + self->BecomePickup(); + return 0; +} + //=========================================================================== // // AInventory :: AbsorbDamage @@ -913,16 +740,24 @@ void AInventory::ModifyDamage (int damage, FName damageType, int &newdamage, boo // //=========================================================================== -double AInventory::GetSpeedFactor () +double AInventory::GetSpeedFactor() { - if (Inventory != NULL) + double factor = 1.; + auto self = this; + while (self != nullptr) { - return Inventory->GetSpeedFactor(); - } - else - { - return 1.; + IFVIRTUALPTR(self, AInventory, GetSpeedFactor) + { + VMValue params[2] = { (DObject*)self }; + VMReturn ret; + double retval; + ret.FloatAt(&retval); + GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); + factor *= retval; + } + self = self->Inventory; } + return factor; } //=========================================================================== @@ -933,15 +768,21 @@ double AInventory::GetSpeedFactor () bool AInventory::GetNoTeleportFreeze () { - // do not check the flag here because it's only active when used on PowerUps, not on PowerupGivers. - if (Inventory != NULL) + auto self = this; + while (self != nullptr) { - return Inventory->GetNoTeleportFreeze(); - } - else - { - return false; + IFVIRTUALPTR(self, AInventory, GetNoTeleportFreeze) + { + VMValue params[2] = { (DObject*)self }; + VMReturn ret; + int retval; + ret.IntAt(&retval); + GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); + if (retval) return true; + } + self = self->Inventory; } + return false; } //=========================================================================== @@ -973,6 +814,29 @@ bool AInventory::Use (bool pickup) return false; } +DEFINE_ACTION_FUNCTION(AInventory, Use) +{ + PARAM_SELF_PROLOGUE(AInventory); + PARAM_BOOL(pickup); + ACTION_RETURN_BOOL(self->Use(pickup)); +} + +bool AInventory::CallUse(bool pickup) +{ + IFVIRTUAL(AInventory, Use) + { + VMValue params[2] = { (DObject*)this, pickup }; + VMReturn ret; + int retval; + ret.IntAt(&retval); + GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); + return !!retval; + + } + else return Use(pickup); +} + + //=========================================================================== // // AInventory :: Hide @@ -1066,17 +930,17 @@ void AInventory::Touch (AActor *toucher) if (!CallTryPickup (toucher, &toucher)) return; // This is the only situation when a pickup flash should ever play. - if (PickupFlash != NULL && !ShouldStay()) + if (PickupFlash != NULL && !CallShouldStay()) { Spawn(PickupFlash, Pos(), ALLOW_REPLACE); } if (!(ItemFlags & IF_QUIET)) { - const char * message = PickupMessage (); + FString message = GetPickupMessage (); - if (message != NULL && *message != 0 && localview - && (StaticLastMessageTic != gametic || StaticLastMessage != message)) + if (message.IsNotEmpty() && localview + && (StaticLastMessageTic != gametic || StaticLastMessage.Compare(message))) { StaticLastMessageTic = gametic; StaticLastMessage = message; @@ -1151,11 +1015,31 @@ void AInventory::DoPickupSpecial (AActor *toucher) // //=========================================================================== -const char *AInventory::PickupMessage () +FString AInventory::PickupMessage () { return GetClass()->PickupMessage; } +DEFINE_ACTION_FUNCTION(AInventory, PickupMessage) +{ + PARAM_SELF_PROLOGUE(AInventory); + ACTION_RETURN_STRING(self->PickupMessage()); +} + +FString AInventory::GetPickupMessage() +{ + IFVIRTUAL(AInventory, PickupMessage) + { + VMValue params[1] = { (DObject*)this }; + VMReturn ret; + FString retval; + ret.StringAt(&retval); + GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); + return retval; + } + else return PickupMessage(); +} + //=========================================================================== // // AInventory :: PlayPickupSound @@ -1194,6 +1078,25 @@ void AInventory::PlayPickupSound (AActor *toucher) S_Sound (toucher, chan, PickupSound, 1, atten); } +DEFINE_ACTION_FUNCTION(AInventory, PlayPickupSound) +{ + PARAM_SELF_PROLOGUE(AInventory); + PARAM_OBJECT(other, AActor); + self->PlayPickupSound(other); + return 0; +} + +void AInventory::CallPlayPickupSound(AActor *other) +{ + IFVIRTUAL(AInventory, PlayPickupSound) + { + VMValue params[2] = { (DObject*)this, (DObject*)other }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } + else PlayPickupSound(other); +} + + //=========================================================================== // // AInventory :: ShouldStay @@ -1207,6 +1110,27 @@ bool AInventory::ShouldStay () return false; } +DEFINE_ACTION_FUNCTION(AInventory, ShouldStay) +{ + PARAM_SELF_PROLOGUE(AInventory); + ACTION_RETURN_BOOL(self->ShouldStay()); +} + +bool AInventory::CallShouldStay() +{ + IFVIRTUAL(AInventory, ShouldStay) + { + VMValue params[1] = { (DObject*)this }; + VMReturn ret; + int retval; + ret.IntAt(&retval); + GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); + return !!retval; + } + else return ShouldStay(); +} + + //=========================================================================== // // AInventory :: Destroy @@ -1267,6 +1191,26 @@ PalEntry AInventory::GetBlend () return 0; } +DEFINE_ACTION_FUNCTION(AInventory, GetBlend) +{ + PARAM_SELF_PROLOGUE(AInventory); + ACTION_RETURN_INT(self->GetBlend()); +} + +PalEntry AInventory::CallGetBlend() +{ + IFVIRTUAL(AInventory, GetBlend) + { + VMValue params[1] = { (DObject*)this }; + VMReturn ret; + int retval; + ret.IntAt(&retval); + GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); + return retval; + } + else return GetBlend(); +} + //=========================================================================== // // AInventory :: PrevItem @@ -1342,12 +1286,6 @@ bool AInventory::DrawPowerup (int x, int y) return false; } -/***************************************************************************/ -/* AArtifact implementation */ -/***************************************************************************/ - -IMPLEMENT_CLASS (APowerupGiver) - //=========================================================================== // // AInventory :: DoRespawn @@ -1402,7 +1340,7 @@ bool AInventory::TryPickup (AActor *&toucher) // picked up, then it leaves the flag cleared. ItemFlags &= ~IF_PICKUPGOOD; - if (toucher->Inventory != NULL && toucher->Inventory->HandlePickup (this)) + if (toucher->Inventory != NULL && toucher->Inventory->CallHandlePickup (this)) { // Let something else the player is holding intercept the pickup. if (!(ItemFlags & IF_PICKUPGOOD)) @@ -1438,7 +1376,7 @@ bool AInventory::TryPickup (AActor *&toucher) { // Add the item to the inventory. It is not already there, or HandlePickup // would have already taken care of it. - AInventory *copy = CreateCopy (toucher); + AInventory *copy = CallCreateCopy (toucher); if (copy == NULL) { return false; @@ -1462,7 +1400,7 @@ bool AInventory::TryPickup (AActor *&toucher) copy->AttachToOwner (newtoucher); if (ItemFlags & IF_AUTOACTIVATE) { - if (copy->Use (true)) + if (copy->CallUse (true)) { if (--copy->Amount <= 0) { @@ -1475,6 +1413,13 @@ bool AInventory::TryPickup (AActor *&toucher) return true; } +DEFINE_ACTION_FUNCTION(AInventory, TryPickup) +{ + PARAM_SELF_PROLOGUE(AInventory); + PARAM_POINTER_NOT_NULL(toucher, AActor*); + ACTION_RETURN_BOOL(self->TryPickup(*toucher)); +} + //=========================================================================== // // AInventory :: TryPickupRestricted @@ -1486,6 +1431,14 @@ bool AInventory::TryPickupRestricted (AActor *&toucher) return false; } +DEFINE_ACTION_FUNCTION(AInventory, TryPickupRestricted) +{ + PARAM_SELF_PROLOGUE(AInventory); + PARAM_POINTER_NOT_NULL(toucher, AActor*); + ACTION_RETURN_BOOL(self->TryPickupRestricted(*toucher)); +} + + //=========================================================================== // // AInventory :: CallTryPickup @@ -1501,16 +1454,39 @@ bool AInventory::CallTryPickup (AActor *toucher, AActor **toucher_return) bool res; if (CanPickup(toucher)) - res = TryPickup(toucher); + { + IFVIRTUAL(AInventory, TryPickup) + { + VMValue params[2] = { (DObject*)this, (void*)&toucher }; + VMReturn ret; + int retval; + ret.IntAt(&retval); + GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); + res = !!retval; + } + else res = TryPickup(toucher); + } else if (!(ItemFlags & IF_RESTRICTABSOLUTELY)) - res = TryPickupRestricted(toucher); // let an item decide for itself how it will handle this + { + // let an item decide for itself how it will handle this + IFVIRTUAL(AInventory, TryPickupRestricted) + { + VMValue params[2] = { (DObject*)this, (void*)&toucher }; + VMReturn ret; + int retval; + ret.IntAt(&retval); + GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); + res = !!retval; + } + else res = TryPickupRestricted(toucher); + } else return false; // Morph items can change the toucher so we need an option to return this info. if (toucher_return != NULL) *toucher_return = toucher; - if (!res && (ItemFlags & IF_ALWAYSPICKUP) && !ShouldStay()) + if (!res && (ItemFlags & IF_ALWAYSPICKUP) && !CallShouldStay()) { res = true; GoAwayAndDie(); @@ -1540,6 +1516,17 @@ bool AInventory::CallTryPickup (AActor *toucher, AActor **toucher_return) return res; } +DEFINE_ACTION_FUNCTION(AInventory, CallTryPickup) +{ + PARAM_SELF_PROLOGUE(AInventory); + PARAM_OBJECT(toucher, AActor); + AActor *t_ret; + bool res = self->CallTryPickup(toucher, &t_ret); + if (numret > 0) ret[0].SetInt(res); + if (numret > 1) ret[1].SetPointer(t_ret, ATAG_OBJECT), numret = 2; + return numret; +} + //=========================================================================== // @@ -1623,6 +1610,25 @@ void AInventory::AttachToOwner (AActor *other) other->AddInventory (this); } +DEFINE_ACTION_FUNCTION(AInventory, AttachToOwner) +{ + PARAM_SELF_PROLOGUE(AInventory); + PARAM_OBJECT_NOT_NULL(other, AActor); + self->AttachToOwner(other); + return 0; +} + +void AInventory::CallAttachToOwner(AActor *other) +{ + IFVIRTUAL(AInventory, AttachToOwner) + { + VMValue params[2] = { (DObject*)this, (DObject*)other }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } + else AttachToOwner(other); +} + + //=========================================================================== // // AInventory :: DetachFromOwner @@ -1636,7 +1642,30 @@ void AInventory::DetachFromOwner () { } -IMPLEMENT_CLASS (ACustomInventory) +DEFINE_ACTION_FUNCTION(AInventory, DetachFromOwner) +{ + PARAM_SELF_PROLOGUE(AInventory); + self->DetachFromOwner(); + return 0; +} + +void AInventory::CallDetachFromOwner() +{ + IFVIRTUAL(AInventory, DetachFromOwner) + { + VMValue params[1] = { (DObject*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } + else DetachFromOwner(); +} + +//=========================================================================== +//=========================================================================== + + + +IMPLEMENT_CLASS(AStateProvider, false, false) +IMPLEMENT_CLASS(ACustomInventory, false, false) //=========================================================================== // @@ -1680,373 +1709,3 @@ bool ACustomInventory::TryPickup (AActor *&toucher) } return useok; } - -IMPLEMENT_CLASS(PClassHealth) - -//=========================================================================== -// -// PClassHealth Constructor -// -//=========================================================================== - -PClassHealth::PClassHealth() -{ - LowHealth = 0; -} - -//=========================================================================== -// -// PClassHealth :: Derive -// -//=========================================================================== - -void PClassHealth::DeriveData(PClass *newclass) -{ - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassHealth))); - Super::DeriveData(newclass); - PClassHealth *newc = static_cast(newclass); - - newc->LowHealth = LowHealth; - newc->LowHealthMessage = LowHealthMessage; -} - -IMPLEMENT_CLASS (AHealth) - -//=========================================================================== -// -// AHealth :: PickupMessage -// -//=========================================================================== -const char *AHealth::PickupMessage () -{ - int threshold = GetClass()->LowHealth; - - if (PrevHealth < threshold) - { - FString message = GetClass()->LowHealthMessage; - - if (message.IsNotEmpty()) - { - return message; - } - } - return Super::PickupMessage(); -} - -//=========================================================================== -// -// AHealth :: TryPickup -// -//=========================================================================== - -bool AHealth::TryPickup (AActor *&other) -{ - PrevHealth = other->player != NULL ? other->player->health : other->health; - - // P_GiveBody adds one new feature, applied only if it is possible to pick up negative health: - // Negative values are treated as positive percentages, ie Amount -100 means 100% health, ignoring max amount. - if (P_GiveBody(other, Amount, MaxAmount)) - { - GoAwayAndDie(); - return true; - } - return false; -} - -IMPLEMENT_CLASS (AHealthPickup) - -//=========================================================================== -// -// AHealthPickup :: CreateCopy -// -//=========================================================================== - -AInventory *AHealthPickup::CreateCopy (AActor *other) -{ - AInventory *copy = Super::CreateCopy (other); - copy->health = health; - return copy; -} - -//=========================================================================== -// -// AHealthPickup :: CreateTossable -// -//=========================================================================== - -AInventory *AHealthPickup::CreateTossable () -{ - AInventory *copy = Super::CreateTossable (); - if (copy != NULL) - { - copy->health = health; - } - return copy; -} - -//=========================================================================== -// -// AHealthPickup :: HandlePickup -// -//=========================================================================== - -bool AHealthPickup::HandlePickup (AInventory *item) -{ - // HealthPickups that are the same type but have different health amounts - // do not count as the same item. - if (item->health == health) - { - return Super::HandlePickup (item); - } - if (Inventory != NULL) - { - return Inventory->HandlePickup (item); - } - return false; -} - -//=========================================================================== -// -// AHealthPickup :: Use -// -//=========================================================================== - -bool AHealthPickup::Use (bool pickup) -{ - return P_GiveBody (Owner, health); -} - -//=========================================================================== -// -// AHealthPickup :: Serialize -// -//=========================================================================== - -void AHealthPickup::Serialize(FSerializer &arc) -{ - Super::Serialize(arc); - auto def = (AHealthPickup*)GetDefault(); - arc("autousemode", autousemode, def->autousemode); -} - -// Backpack ----------------------------------------------------------------- - -//=========================================================================== -// -// ABackpackItem :: Serialize -// -//=========================================================================== - -void ABackpackItem::Serialize(FSerializer &arc) -{ - Super::Serialize (arc); - auto def = (ABackpackItem*)GetDefault(); - arc("bdepleted", bDepleted, def->bDepleted); -} - -//=========================================================================== -// -// ABackpackItem :: CreateCopy -// -// A backpack is being added to a player who doesn't yet have one. Give them -// every kind of ammo, and increase their max amounts. -// -//=========================================================================== - -AInventory *ABackpackItem::CreateCopy (AActor *other) -{ - // Find every unique type of ammo. Give it to the player if - // he doesn't have it already, and double its maximum capacity. - for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) - { - PClass *type = PClassActor::AllActorClasses[i]; - - if (type->ParentClass == RUNTIME_CLASS(AAmmo)) - { - PClassActor *atype = static_cast(type); - AAmmo *ammo = static_cast(other->FindInventory(atype)); - int amount = static_cast(GetDefaultByType(type))->BackpackAmount; - // extra ammo in baby mode and nightmare mode - if (!(ItemFlags&IF_IGNORESKILL)) - { - amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor)); - } - if (amount < 0) amount = 0; - if (ammo == NULL) - { // The player did not have the ammo. Add it. - ammo = static_cast(Spawn(atype)); - ammo->Amount = bDepleted ? 0 : amount; - if (ammo->BackpackMaxAmount > ammo->MaxAmount) - { - ammo->MaxAmount = ammo->BackpackMaxAmount; - } - if (ammo->Amount > ammo->MaxAmount) - { - ammo->Amount = ammo->MaxAmount; - } - ammo->AttachToOwner (other); - } - else - { // The player had the ammo. Give some more. - if (ammo->MaxAmount < ammo->BackpackMaxAmount) - { - ammo->MaxAmount = ammo->BackpackMaxAmount; - } - if (!bDepleted && ammo->Amount < ammo->MaxAmount) - { - ammo->Amount += amount; - if (ammo->Amount > ammo->MaxAmount) - { - ammo->Amount = ammo->MaxAmount; - } - } - } - } - } - return Super::CreateCopy (other); -} - -//=========================================================================== -// -// ABackpackItem :: HandlePickup -// -// When the player picks up another backpack, just give them more ammo. -// -//=========================================================================== - -bool ABackpackItem::HandlePickup (AInventory *item) -{ - // Since you already have a backpack, that means you already have every - // kind of ammo in your inventory, so we don't need to look at the - // entire PClass list to discover what kinds of ammo exist, and we don't - // have to alter the MaxAmount either. - if (item->IsKindOf (RUNTIME_CLASS(ABackpackItem))) - { - for (AInventory *probe = Owner->Inventory; probe != NULL; probe = probe->Inventory) - { - if (probe->GetClass()->ParentClass == RUNTIME_CLASS(AAmmo)) - { - if (probe->Amount < probe->MaxAmount || sv_unlimited_pickup) - { - int amount = static_cast(probe->GetDefault())->BackpackAmount; - // extra ammo in baby mode and nightmare mode - if (!(item->ItemFlags&IF_IGNORESKILL)) - { - amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor)); - } - probe->Amount += amount; - if (probe->Amount > probe->MaxAmount && !sv_unlimited_pickup) - { - probe->Amount = probe->MaxAmount; - } - } - } - } - // The pickup always succeeds, even if you didn't get anything - item->ItemFlags |= IF_PICKUPGOOD; - return true; - } - else if (Inventory != NULL) - { - return Inventory->HandlePickup (item); - } - else - { - return false; - } -} - -//=========================================================================== -// -// ABackpackItem :: CreateTossable -// -// The tossed backpack must not give out any more ammo, otherwise a player -// could cheat by dropping their backpack and picking it up for more ammo. -// -//=========================================================================== - -AInventory *ABackpackItem::CreateTossable () -{ - ABackpackItem *pack = static_cast(Super::CreateTossable()); - if (pack != NULL) - { - pack->bDepleted = true; - } - return pack; -} - -//=========================================================================== -// -// ABackpackItem :: DetachFromOwner -// -//=========================================================================== - -void ABackpackItem::DetachFromOwner () -{ - // When removing a backpack, drop the player's ammo maximums to normal - AInventory *item; - - for (item = Owner->Inventory; item != NULL; item = item->Inventory) - { - if (item->GetClass()->ParentClass == RUNTIME_CLASS(AAmmo) && - item->MaxAmount == static_cast(item)->BackpackMaxAmount) - { - item->MaxAmount = static_cast(item->GetDefault())->MaxAmount; - if (item->Amount > item->MaxAmount) - { - item->Amount = item->MaxAmount; - } - } - } -} - -//=========================================================================== -// -// ABackpack -// -//=========================================================================== - -IMPLEMENT_CLASS(ABackpackItem) - -IMPLEMENT_CLASS (AMapRevealer) - -//=========================================================================== -// -// AMapRevealer :: TryPickup -// -// The MapRevealer doesn't actually go in your inventory. Instead, it sets -// a flag on the level. -// -//=========================================================================== - -bool AMapRevealer::TryPickup (AActor *&toucher) -{ - level.flags2 |= LEVEL2_ALLMAP; - GoAwayAndDie (); - return true; -} - - -//=========================================================================== -// -// AScoreItem -// -//=========================================================================== - -IMPLEMENT_CLASS(AScoreItem) - -//=========================================================================== -// -// AScoreItem :: TryPickup -// -// Adds the value (Amount) of the item to the toucher's Score property. -// -//=========================================================================== - -bool AScoreItem::TryPickup (AActor *&toucher) -{ - toucher->Score += Amount; - GoAwayAndDie(); - return true; -} - diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h new file mode 100644 index 0000000000..32914e3e52 --- /dev/null +++ b/src/g_inventory/a_pickups.h @@ -0,0 +1,204 @@ +#ifndef __A_PICKUPS_H__ +#define __A_PICKUPS_H__ + +#include "actor.h" +#include "info.h" +#include "s_sound.h" + +#define NUM_WEAPON_SLOTS 10 + +class player_t; +class FConfigFile; +class PClassPlayerPawn; +struct visstyle_t; + +/************************************************************************/ +/* Class definitions */ +/************************************************************************/ + +// A pickup is anything the player can pickup (i.e. weapons, ammo, powerups, etc) + +enum +{ + IF_ACTIVATABLE = 1<<0, // can be activated + IF_ACTIVATED = 1<<1, // is currently activated + IF_PICKUPGOOD = 1<<2, // HandlePickup wants normal pickup FX to happen + IF_QUIET = 1<<3, // Don't give feedback when picking up + IF_AUTOACTIVATE = 1<<4, // Automatically activate item on pickup + IF_UNDROPPABLE = 1<<5, // Item cannot be removed unless done explicitly with RemoveInventory + IF_INVBAR = 1<<6, // Item appears in the inventory bar + IF_HUBPOWER = 1<<7, // Powerup is kept when moving in a hub + IF_UNTOSSABLE = 1<<8, // The player cannot manually drop the item + IF_ADDITIVETIME = 1<<9, // when picked up while another item is active, time is added instead of replaced. + IF_ALWAYSPICKUP = 1<<10, // For IF_AUTOACTIVATE, MaxAmount=0 items: Always "pick up", even if it doesn't do anything + IF_FANCYPICKUPSOUND = 1<<11, // Play pickup sound in "surround" mode + IF_BIGPOWERUP = 1<<12, // Affected by RESPAWN_SUPER dmflag + IF_KEEPDEPLETED = 1<<13, // Items with this flag are retained even when they run out. + IF_IGNORESKILL = 1<<14, // Ignores any skill related multiplicators when giving this item. + IF_CREATECOPYMOVED = 1<<15, // CreateCopy changed the owner (copy's Owner field holds new owner). + IF_INITEFFECTFAILED = 1<<16, // CreateCopy tried to activate a powerup and activation failed (can happen with PowerMorph) + IF_NOATTENPICKUPSOUND = 1<<17, // Play pickup sound with ATTN_NONE + IF_PERSISTENTPOWER = 1<<18, // Powerup is kept when travelling between levels + IF_RESTRICTABSOLUTELY = 1<<19, // RestrictedTo and ForbiddenTo do not allow pickup in any form by other classes + IF_NEVERRESPAWN = 1<<20, // Never, ever respawns + IF_NOSCREENFLASH = 1<<21, // No pickup flash on the player's screen + IF_TOSSED = 1<<22, // Was spawned by P_DropItem (i.e. as a monster drop) + IF_ALWAYSRESPAWN = 1<<23, // Always respawn, regardless of dmflag + IF_TRANSFER = 1<<24, // All inventory items that the inventory item contains is also transfered to the pickuper + IF_NOTELEPORTFREEZE = 1<<25, // does not 'freeze' the player right after teleporting. +}; + + +class PClassInventory : public PClassActor +{ + DECLARE_CLASS(PClassInventory, PClassActor) +public: + PClassInventory(); + virtual void DeriveData(PClass *newclass); + virtual size_t PointerSubstitution(DObject *oldclass, DObject *newclass); + void Finalize(FStateDefinitions &statedef); + + FString PickupMessage; + int GiveQuest; // Optionally give one of the quest items. + FTextureID AltHUDIcon; + TArray RestrictedToPlayerClass; + TArray ForbiddenToPlayerClass; +}; + +class AInventory : public AActor +{ + DECLARE_CLASS_WITH_META(AInventory, AActor, PClassInventory) + HAS_OBJECT_POINTERS +public: + + virtual void Touch (AActor *toucher) override; + virtual void Serialize(FSerializer &arc) override; + virtual void MarkPrecacheSounds() const override; + virtual void BeginPlay () override; + virtual void Destroy () override; + virtual void Tick() override; + virtual bool Grind(bool items) override; + + // virtual methods that only get overridden by special internal classes, like DehackedPickup. + // There is no need to expose these to scripts. + virtual void DepleteOrDestroy (); + virtual bool ShouldRespawn (); + virtual void DoPickupSpecial (AActor *toucher); + + // methods that can be overridden by scripts, plus their callers. + virtual bool SpecialDropAction (AActor *dropper); + bool CallSpecialDropAction(AActor *dropper); + + virtual bool TryPickup(AActor *&toucher); + virtual bool TryPickupRestricted(AActor *&toucher); + bool CallTryPickup(AActor *toucher, AActor **toucher_return = NULL); // This wraps both virtual methods plus a few more checks. + + virtual AInventory *CreateCopy(AActor *other); + AInventory *CallCreateCopy(AActor *other); + + virtual AInventory *CreateTossable(); + AInventory *CallCreateTossable(); + + virtual FString PickupMessage(); + FString GetPickupMessage(); + + virtual bool HandlePickup(AInventory *item); + bool CallHandlePickup(AInventory *item); + + virtual bool Use(bool pickup); + bool CallUse(bool pickup); + + virtual PalEntry GetBlend(); + PalEntry CallGetBlend(); + + virtual bool ShouldStay(); + bool CallShouldStay(); + + virtual void DoEffect(); + void CallDoEffect(); + + virtual void PlayPickupSound(AActor *toucher); + void CallPlayPickupSound(AActor *toucher); + + virtual void AttachToOwner(AActor *other); + void CallAttachToOwner(AActor *other); + + virtual void DetachFromOwner(); + void CallDetachFromOwner(); + + // still need to be done. + virtual void AbsorbDamage(int damage, FName damageType, int &newdamage); + virtual void ModifyDamage(int damage, FName damageType, int &newdamage, bool passive); + + // visual stuff is for later. Right now the VM has not yet access to the needed functionality. + virtual bool DrawPowerup(int x, int y); + virtual int AlterWeaponSprite(visstyle_t *vis); + + + // virtual on the script side only. + double GetSpeedFactor(); + bool GetNoTeleportFreeze(); + // Stuff for later when more features are exported. + virtual void Travelled(); + virtual void OwnerDied(); + + + bool GoAway(); + void GoAwayAndDie(); + + void Hide(); + void BecomeItem (); + void BecomePickup (); + + bool DoRespawn(); + AInventory *PrevItem(); // Returns the item preceding this one in the list. + AInventory *PrevInv(); // Returns the previous item with IF_INVBAR set. + AInventory *NextInv(); // Returns the next item with IF_INVBAR set. + + TObjPtr Owner; // Who owns this item? NULL if it's still a pickup. + int Amount; // Amount of item this instance has + int MaxAmount; // Max amount of item this instance can have + int InterHubAmount; // Amount of item that can be kept between hubs or levels + int RespawnTics; // Tics from pickup time to respawn time + FTextureID Icon; // Icon to show on status bar or HUD + int DropTime; // Countdown after dropping + PClassActor *SpawnPointClass; // For respawning like Heretic's mace + + DWORD ItemFlags; + PClassActor *PickupFlash; // actor to spawn as pickup flash + + FSoundIDNoInit PickupSound; + + +protected: + bool CanPickup(AActor * toucher); + void GiveQuest(AActor * toucher); + +private: + static int StaticLastMessageTic; + static FString StaticLastMessage; +}; + +class AStateProvider : public AInventory +{ + DECLARE_CLASS(AStateProvider, AInventory) +}; + +// CustomInventory: Supports the Use, Pickup, and Drop states from 96x +class ACustomInventory : public AStateProvider +{ + DECLARE_CLASS (ACustomInventory, AStateProvider) +public: + + // This is used when an inventory item's use state sequence is executed. + bool CallStateChain (AActor *actor, FState *state); + + virtual bool TryPickup (AActor *&toucher) override; + virtual bool Use (bool pickup) override; + virtual bool SpecialDropAction (AActor *dropper) override; +}; + +extern PClassActor *QuestItemClasses[31]; + + +#endif //__A_PICKUPS_H__ diff --git a/src/g_inventory/a_puzzleitems.cpp b/src/g_inventory/a_puzzleitems.cpp new file mode 100644 index 0000000000..7617f63833 --- /dev/null +++ b/src/g_inventory/a_puzzleitems.cpp @@ -0,0 +1,117 @@ +/* +** a_puzzleitems.cpp +** Implements Hexen's puzzle items. +** +**--------------------------------------------------------------------------- +** Copyright 2002-2016 Randy Heit +** Copyright 2006-2016 Cheistoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include "info.h" +#include "a_pickups.h" +#include "a_artifacts.h" +#include "gstrings.h" +#include "p_local.h" +#include "s_sound.h" +#include "c_console.h" +#include "doomstat.h" +#include "v_font.h" +#include "a_keys.h" + + +IMPLEMENT_CLASS(PClassPuzzleItem, false, false) +IMPLEMENT_CLASS(APuzzleItem, false, false) + +DEFINE_FIELD(APuzzleItem, PuzzleItemNumber) + +//=========================================================================== +// +// +// +//=========================================================================== + +void PClassPuzzleItem::DeriveData(PClass *newclass) +{ + Super::DeriveData(newclass); + assert(newclass->IsKindOf(RUNTIME_CLASS(PClassPuzzleItem))); + static_cast(newclass)->PuzzFailMessage = PuzzFailMessage; +} + + +//=========================================================================== +// +// +// +//=========================================================================== + +bool APuzzleItem::HandlePickup (AInventory *item) +{ + // Can't carry more than 1 of each puzzle item in coop netplay + if (multiplayer && !deathmatch && item->GetClass() == GetClass()) + { + return true; + } + return Super::HandlePickup (item); +} + +//=========================================================================== +// +// +// +//=========================================================================== + +bool APuzzleItem::Use (bool pickup) +{ + if (P_UsePuzzleItem (Owner, PuzzleItemNumber)) + { + return true; + } + // [RH] Always play the sound if the use fails. + S_Sound (Owner, CHAN_VOICE, "*puzzfail", 1, ATTN_IDLE); + if (Owner != NULL && Owner->CheckLocalView (consoleplayer)) + { + FString message = GetClass()->PuzzFailMessage; + if (message.IsNotEmpty() && message[0] == '$') message = GStrings[&message[1]]; + if (message.IsEmpty()) message = GStrings("TXT_USEPUZZLEFAILED"); + C_MidPrintBold (SmallFont, message); + } + return false; +} + +//=========================================================================== +// +// +// +//=========================================================================== + +bool APuzzleItem::ShouldStay () +{ + return !!multiplayer; +} + diff --git a/src/g_shared/a_weaponpiece.cpp b/src/g_inventory/a_weaponpiece.cpp similarity index 60% rename from src/g_shared/a_weaponpiece.cpp rename to src/g_inventory/a_weaponpiece.cpp index aefce18c1c..2fe14ae91d 100644 --- a/src/g_shared/a_weaponpiece.cpp +++ b/src/g_inventory/a_weaponpiece.cpp @@ -1,21 +1,53 @@ +/* +** a_weaponpieces.cpp +** Implements generic weapon pieces +** +**--------------------------------------------------------------------------- +** Copyright 2006-2016 Cheistoph Oelckers +** Copyright 2006-2016 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + #include "a_pickups.h" #include "a_weaponpiece.h" #include "doomstat.h" #include "serializer.h" -IMPLEMENT_CLASS(PClassWeaponPiece) -IMPLEMENT_CLASS (AWeaponHolder) +IMPLEMENT_CLASS(AWeaponHolder, false, false) -void PClassWeaponPiece::ReplaceClassRef(PClass *oldclass, PClass *newclass) -{ - Super::ReplaceClassRef(oldclass, newclass); - AWeaponPiece *def = (AWeaponPiece*)Defaults; - if (def != NULL) - { - if (def->WeaponClass == oldclass) def->WeaponClass = static_cast(newclass); - } -} +DEFINE_FIELD(AWeaponHolder, PieceMask); +DEFINE_FIELD(AWeaponHolder, PieceWeapon); +//=========================================================================== +// +// +// +//=========================================================================== void AWeaponHolder::Serialize(FSerializer &arc) { @@ -24,11 +56,18 @@ void AWeaponHolder::Serialize(FSerializer &arc) ("pieceweapon", PieceWeapon); } +IMPLEMENT_CLASS(AWeaponPiece, false, true) -IMPLEMENT_POINTY_CLASS (AWeaponPiece) - DECLARE_POINTER (FullWeapon) -END_POINTERS +IMPLEMENT_POINTERS_START(AWeaponPiece) + IMPLEMENT_POINTER(FullWeapon) + IMPLEMENT_POINTER(WeaponClass) +IMPLEMENT_POINTERS_END +//=========================================================================== +// +// +// +//=========================================================================== void AWeaponPiece::Serialize(FSerializer &arc) { @@ -48,7 +87,7 @@ void AWeaponPiece::Serialize(FSerializer &arc) bool AWeaponPiece::TryPickupRestricted (AActor *&toucher) { // Wrong class, but try to pick up for ammo - if (ShouldStay()) + if (CallShouldStay()) { // Can't pick up weapons for other classes in coop netplay return false; } @@ -147,11 +186,23 @@ bool AWeaponPiece::TryPickup (AActor *&toucher) return true; } +//=========================================================================== +// +// +// +//=========================================================================== + bool AWeaponPiece::ShouldStay () { return PrivateShouldStay (); } +//=========================================================================== +// +// +// +//=========================================================================== + bool AWeaponPiece::PrivateShouldStay () { // We want a weapon piece to behave like a weapon, so follow the exact @@ -173,7 +224,7 @@ bool AWeaponPiece::PrivateShouldStay () // //=========================================================================== -const char *AWeaponPiece::PickupMessage () +FString AWeaponPiece::PickupMessage () { if (FullWeapon) { diff --git a/src/g_inventory/a_weaponpiece.h b/src/g_inventory/a_weaponpiece.h new file mode 100644 index 0000000000..a8c6a2e76d --- /dev/null +++ b/src/g_inventory/a_weaponpiece.h @@ -0,0 +1,37 @@ +#pragma once +#include "a_pickups.h" +#include "a_weapons.h" + +class AWeaponPiece : public AInventory +{ + DECLARE_CLASS(AWeaponPiece, AInventory) + HAS_OBJECT_POINTERS +protected: + bool PrivateShouldStay (); +public: + + virtual void Serialize(FSerializer &arc) override; + virtual bool TryPickup (AActor *&toucher) override; + virtual bool TryPickupRestricted (AActor *&toucher) override; + virtual bool ShouldStay () override; + virtual FString PickupMessage () override; + virtual void PlayPickupSound (AActor *toucher) override; + + int PieceValue; + PClassActor *WeaponClass; + TObjPtr FullWeapon; +}; + +// an internal class to hold the information for player class independent weapon piece handling +// [BL] Needs to be available for SBarInfo to check weaponpieces +class AWeaponHolder : public AInventory +{ + DECLARE_CLASS(AWeaponHolder, AInventory) + +public: + int PieceMask; + PClassActor * PieceWeapon; + + + virtual void Serialize(FSerializer &arc) override; +}; diff --git a/src/g_shared/a_weapons.cpp b/src/g_inventory/a_weapons.cpp similarity index 86% rename from src/g_shared/a_weapons.cpp rename to src/g_inventory/a_weapons.cpp index b1ede01874..3b3b765d6d 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -1,3 +1,38 @@ +/* +** a_weapons.cpp +** Implements weapon handling +** +**--------------------------------------------------------------------------- +** Copyright 2000-2016 Randy Heit +** Copyright 2006-2016 Cheistoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + #include #include "a_pickups.h" @@ -13,19 +48,68 @@ #include "cmdlib.h" #include "templates.h" #include "sbar.h" -#include "thingdef/thingdef.h" #include "doomstat.h" #include "g_level.h" #include "d_net.h" #include "serializer.h" +#include "thingdef.h" +#include "virtual.h" +#include "a_ammo.h" #define BONUSADD 6 -IMPLEMENT_POINTY_CLASS (AWeapon) - DECLARE_POINTER (Ammo1) - DECLARE_POINTER (Ammo2) - DECLARE_POINTER (SisterWeapon) -END_POINTERS +extern FFlagDef WeaponFlagDefs[]; + +IMPLEMENT_CLASS(AWeapon, false, true) + +IMPLEMENT_POINTERS_START(AWeapon) + IMPLEMENT_POINTER(Ammo1) + IMPLEMENT_POINTER(Ammo2) + IMPLEMENT_POINTER(SisterWeapon) + IMPLEMENT_POINTER(AmmoType1) + IMPLEMENT_POINTER(AmmoType2) + IMPLEMENT_POINTER(SisterWeaponType) +IMPLEMENT_POINTERS_END + +DEFINE_FIELD(AWeapon, WeaponFlags) +DEFINE_FIELD(AWeapon, AmmoType1) +DEFINE_FIELD(AWeapon, AmmoType2) +DEFINE_FIELD(AWeapon, AmmoGive1) +DEFINE_FIELD(AWeapon, AmmoGive2) +DEFINE_FIELD(AWeapon, MinAmmo1) +DEFINE_FIELD(AWeapon, MinAmmo2) +DEFINE_FIELD(AWeapon, AmmoUse1) +DEFINE_FIELD(AWeapon, AmmoUse2) +DEFINE_FIELD(AWeapon, Kickback) +DEFINE_FIELD(AWeapon, YAdjust) +DEFINE_FIELD(AWeapon, UpSound) +DEFINE_FIELD(AWeapon, ReadySound) +DEFINE_FIELD(AWeapon, SisterWeaponType) +DEFINE_FIELD(AWeapon, ProjectileType) +DEFINE_FIELD(AWeapon, AltProjectileType) +DEFINE_FIELD(AWeapon, SelectionOrder) +DEFINE_FIELD(AWeapon, MinSelAmmo1) +DEFINE_FIELD(AWeapon, MinSelAmmo2) +DEFINE_FIELD(AWeapon, MoveCombatDist) +DEFINE_FIELD(AWeapon, ReloadCounter) +DEFINE_FIELD(AWeapon, BobStyle) +DEFINE_FIELD(AWeapon, BobSpeed) +DEFINE_FIELD(AWeapon, BobRangeX) +DEFINE_FIELD(AWeapon, BobRangeY) +DEFINE_FIELD(AWeapon, Ammo1) +DEFINE_FIELD(AWeapon, Ammo2) +DEFINE_FIELD(AWeapon, SisterWeapon) +DEFINE_FIELD(AWeapon, FOVScale) +DEFINE_FIELD(AWeapon, Crosshair) +DEFINE_FIELD(AWeapon, GivenAsMorphWeapon) +DEFINE_FIELD(AWeapon, bAltFire) +DEFINE_FIELD_BIT(AWeapon, WeaponFlags, bDehAmmo, WIF_DEHAMMO) + +//=========================================================================== +// +// +// +//=========================================================================== FString WeaponSection; TArray KeyConfWeapons; @@ -36,7 +120,13 @@ TMap Weapons_hton; static int ntoh_cmp(const void *a, const void *b); -IMPLEMENT_CLASS(PClassWeapon) +IMPLEMENT_CLASS(PClassWeapon, false, false) + +//=========================================================================== +// +// +// +//=========================================================================== PClassWeapon::PClassWeapon() { @@ -44,6 +134,12 @@ PClassWeapon::PClassWeapon() SlotPriority = INT_MAX; } +//=========================================================================== +// +// +// +//=========================================================================== + void PClassWeapon::DeriveData(PClass *newclass) { assert(newclass->IsKindOf(RUNTIME_CLASS(PClassWeapon))); @@ -55,18 +151,44 @@ void PClassWeapon::DeriveData(PClass *newclass) } -void PClassWeapon::ReplaceClassRef(PClass *oldclass, PClass *newclass) +//=========================================================================== +// +// +// +//=========================================================================== + +void PClassWeapon::Finalize(FStateDefinitions &statedef) { - Super::ReplaceClassRef(oldclass, newclass); - AWeapon *def = (AWeapon*)Defaults; - if (def != NULL) + Super::Finalize(statedef); + FState *ready = FindState(NAME_Ready); + FState *select = FindState(NAME_Select); + FState *deselect = FindState(NAME_Deselect); + FState *fire = FindState(NAME_Fire); + + // Consider any weapon without any valid state abstract and don't output a warning + // This is for creating base classes for weapon groups that only set up some properties. + if (ready || select || deselect || fire) { - if (def->AmmoType1 == oldclass) def->AmmoType1 = static_cast(newclass); - if (def->AmmoType2 == oldclass) def->AmmoType2 = static_cast(newclass); - if (def->SisterWeaponType == oldclass) def->SisterWeaponType = static_cast(newclass); + if (!ready) + { + I_Error("Weapon %s doesn't define a ready state.", TypeName.GetChars()); + } + if (!select) + { + I_Error("Weapon %s doesn't define a select state.", TypeName.GetChars()); + } + if (!deselect) + { + I_Error("Weapon %s doesn't define a deselect state.", TypeName.GetChars()); + } + if (!fire) + { + I_Error("Weapon %s doesn't define a fire state.", TypeName.GetChars()); + } } } + //=========================================================================== // // AWeapon :: Serialize @@ -138,7 +260,7 @@ void AWeapon::MarkPrecacheSounds() const bool AWeapon::TryPickupRestricted (AActor *&toucher) { // Wrong class, but try to pick up for ammo - if (ShouldStay()) + if (CallShouldStay()) { // Can't pick up weapons for other classes in coop netplay return false; } @@ -245,10 +367,6 @@ bool AWeapon::HandlePickup (AInventory *item) } return true; } - if (Inventory != NULL) - { - return Inventory->HandlePickup (item); - } return false; } @@ -265,7 +383,7 @@ bool AWeapon::PickupForAmmo (AWeapon *ownedWeapon) bool gotstuff = false; // Don't take ammo if the weapon sticks around. - if (!ShouldStay ()) + if (!CallShouldStay ()) { int oldamount1 = 0; int oldamount2 = 0; @@ -327,7 +445,7 @@ AInventory *AWeapon::CreateTossable () (((AWeapon*)SisterWeapon->GetDefault())->AmmoGive1 > 0 || ((AWeapon*)SisterWeapon->GetDefault())->AmmoGive2 > 0)) { - return SisterWeapon->CreateTossable (); + return SisterWeapon->CallCreateTossable (); } AWeapon *copy = static_cast (Super::CreateTossable ()); @@ -563,6 +681,16 @@ bool AWeapon::CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo, int am return false; } +DEFINE_ACTION_FUNCTION(AWeapon, CheckAmmo) +{ + PARAM_SELF_PROLOGUE(AWeapon); + PARAM_INT(mode); + PARAM_BOOL(autoswitch); + PARAM_BOOL_DEF(require); + PARAM_INT_DEF(ammocnt); + ACTION_RETURN_BOOL(self->CheckAmmo(mode, autoswitch, require, ammocnt)); +} + //=========================================================================== // // AWeapon :: DepleteAmmo @@ -618,6 +746,15 @@ bool AWeapon::DepleteAmmo (bool altFire, bool checkEnough, int ammouse) return true; } +DEFINE_ACTION_FUNCTION(AWeapon, DepleteAmmo) +{ + PARAM_SELF_PROLOGUE(AWeapon); + PARAM_BOOL(altfire); + PARAM_BOOL_DEF(checkenough); + PARAM_INT_DEF(ammouse); + ACTION_RETURN_BOOL(self->DepleteAmmo(altfire, checkenough, ammouse)); +} + //=========================================================================== // @@ -680,6 +817,25 @@ void AWeapon::EndPowerup () } } +DEFINE_ACTION_FUNCTION(AWeapon, EndPowerup) +{ + PARAM_SELF_PROLOGUE(AWeapon); + self->EndPowerup(); + return 0; +} + +void AWeapon::CallEndPowerup() +{ + IFVIRTUAL(AWeapon, EndPowerup) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DObject*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } + else EndPowerup(); +} + + //=========================================================================== // // AWeapon :: GetUpState @@ -688,7 +844,16 @@ void AWeapon::EndPowerup () FState *AWeapon::GetUpState () { - return FindState(NAME_Select); + IFVIRTUAL(AWeapon, GetUpState) + { + VMValue params[1] = { (DObject*)this }; + VMReturn ret; + FState *retval; + ret.PointerAt((void**)&retval); + GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); + return retval; + } + return nullptr; } //=========================================================================== @@ -699,7 +864,16 @@ FState *AWeapon::GetUpState () FState *AWeapon::GetDownState () { - return FindState(NAME_Deselect); + IFVIRTUAL(AWeapon, GetDownState) + { + VMValue params[1] = { (DObject*)this }; + VMReturn ret; + FState *retval; + ret.PointerAt((void**)&retval); + GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); + return retval; + } + return nullptr; } //=========================================================================== @@ -710,7 +884,16 @@ FState *AWeapon::GetDownState () FState *AWeapon::GetReadyState () { - return FindState(NAME_Ready); + IFVIRTUAL(AWeapon, GetReadyState) + { + VMValue params[1] = { (DObject*)this }; + VMReturn ret; + FState *retval; + ret.PointerAt((void**)&retval); + GlobalVMStack.Call(func, params, 1, &ret, 1, nullptr); + return retval; + } + return nullptr; } //=========================================================================== @@ -721,11 +904,16 @@ FState *AWeapon::GetReadyState () FState *AWeapon::GetAtkState (bool hold) { - FState * state=NULL; - - if (hold) state = FindState(NAME_Hold); - if (state == NULL) state = FindState(NAME_Fire); - return state; + IFVIRTUAL(AWeapon, GetAtkState) + { + VMValue params[2] = { (DObject*)this, hold }; + VMReturn ret; + FState *retval; + ret.PointerAt((void**)&retval); + GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); + return retval; + } + return nullptr; } //=========================================================================== @@ -736,11 +924,16 @@ FState *AWeapon::GetAtkState (bool hold) FState *AWeapon::GetAltAtkState (bool hold) { - FState * state=NULL; - - if (hold) state = FindState(NAME_AltHold); - if (state == NULL) state = FindState(NAME_AltFire); - return state; + IFVIRTUAL(AWeapon, GetAltAtkState) + { + VMValue params[2] = { (DObject*)this, hold }; + VMReturn ret; + FState *retval; + ret.PointerAt((void**)&retval); + GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); + return retval; + } + return nullptr; } //=========================================================================== @@ -757,7 +950,9 @@ FState *AWeapon::GetStateForButtonName (FName button) /* Weapon giver ***********************************************************/ -IMPLEMENT_CLASS(AWeaponGiver) +IMPLEMENT_CLASS(AWeaponGiver, false, false) + +DEFINE_FIELD(AWeaponGiver, DropAmmoFactor); void AWeaponGiver::Serialize(FSerializer &arc) { @@ -1889,11 +2084,11 @@ PClassWeapon *Net_ReadWeapon(BYTE **stream) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AWeapon, A_ZoomFactor) +DEFINE_ACTION_FUNCTION(AWeapon, A_ZoomFactor) { - PARAM_ACTION_PROLOGUE; - PARAM_FLOAT_OPT (zoom) { zoom = 1; } - PARAM_INT_OPT (flags) { flags = 0; } + PARAM_ACTION_PROLOGUE(AActor); + PARAM_FLOAT_DEF(zoom); + PARAM_INT_DEF(flags); if (self->player != NULL && self->player->ReadyWeapon != NULL) { @@ -1917,9 +2112,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AWeapon, A_ZoomFactor) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AWeapon, A_SetCrosshair) +DEFINE_ACTION_FUNCTION(AWeapon, A_SetCrosshair) { - PARAM_ACTION_PROLOGUE; + PARAM_ACTION_PROLOGUE(AActor); PARAM_INT(xhair); if (self->player != NULL && self->player->ReadyWeapon != NULL) diff --git a/src/g_inventory/a_weapons.h b/src/g_inventory/a_weapons.h new file mode 100644 index 0000000000..1b12584012 --- /dev/null +++ b/src/g_inventory/a_weapons.h @@ -0,0 +1,232 @@ +#pragma once + +#include "a_ammo.h" + +class PClassWeapon; +class AWeapon; + +class FWeaponSlot +{ +public: + FWeaponSlot() { Clear(); } + FWeaponSlot(const FWeaponSlot &other) { Weapons = other.Weapons; } + FWeaponSlot &operator= (const FWeaponSlot &other) { Weapons = other.Weapons; return *this; } + void Clear() { Weapons.Clear(); } + bool AddWeapon (const char *type); + bool AddWeapon (PClassWeapon *type); + void AddWeaponList (const char *list, bool clear); + AWeapon *PickWeapon (player_t *player, bool checkammo = false); + int Size () const { return (int)Weapons.Size(); } + int LocateWeapon (PClassWeapon *type); + + inline PClassWeapon *GetWeapon (int index) const + { + if ((unsigned)index < Weapons.Size()) + { + return Weapons[index].Type; + } + else + { + return NULL; + } + } + + friend struct FWeaponSlots; + +private: + struct WeaponInfo + { + PClassWeapon *Type; + int Position; + }; + void SetInitialPositions(); + void Sort(); + TArray Weapons; +}; +// FWeaponSlots::AddDefaultWeapon return codes +enum ESlotDef +{ + SLOTDEF_Exists, // Weapon was already assigned a slot + SLOTDEF_Added, // Weapon was successfully added + SLOTDEF_Full // The specifed slot was full +}; + +struct FWeaponSlots +{ + FWeaponSlots() { Clear(); } + FWeaponSlots(const FWeaponSlots &other); + + FWeaponSlot Slots[NUM_WEAPON_SLOTS]; + + AWeapon *PickNextWeapon (player_t *player); + AWeapon *PickPrevWeapon (player_t *player); + + void Clear (); + bool LocateWeapon (PClassWeapon *type, int *const slot, int *const index); + ESlotDef AddDefaultWeapon (int slot, PClassWeapon *type); + void AddExtraWeapons(); + void SetFromGameInfo(); + void SetFromPlayer(PClassPlayerPawn *type); + void StandardSetup(PClassPlayerPawn *type); + void LocalSetup(PClassActor *type); + void SendDifferences(int playernum, const FWeaponSlots &other); + int RestoreSlots (FConfigFile *config, const char *section); + void PrintSettings(); + + void AddSlot(int slot, PClassWeapon *type, bool feedback); + void AddSlotDefault(int slot, PClassWeapon *type, bool feedback); + +}; + +void P_PlaybackKeyConfWeapons(FWeaponSlots *slots); +void Net_WriteWeapon(PClassWeapon *type); +PClassWeapon *Net_ReadWeapon(BYTE **stream); + +void P_SetupWeapons_ntohton(); +void P_WriteDemoWeaponsChunk(BYTE **demo); +void P_ReadDemoWeaponsChunk(BYTE **demo); + + +// A weapon is just that. +class PClassWeapon : public PClassInventory +{ + DECLARE_CLASS(PClassWeapon, PClassInventory); +protected: + virtual void DeriveData(PClass *newclass); +public: + PClassWeapon(); + void Finalize(FStateDefinitions &statedef); + + int SlotNumber; + int SlotPriority; +}; + +class AWeapon : public AStateProvider +{ + DECLARE_CLASS_WITH_META(AWeapon, AStateProvider, PClassWeapon) + HAS_OBJECT_POINTERS +public: + DWORD WeaponFlags; + PClassAmmo *AmmoType1, *AmmoType2; // Types of ammo used by this weapon + int AmmoGive1, AmmoGive2; // Amount of each ammo to get when picking up weapon + int MinAmmo1, MinAmmo2; // Minimum ammo needed to switch to this weapon + int AmmoUse1, AmmoUse2; // How much ammo to use with each shot + int Kickback; + float YAdjust; // For viewing the weapon fullscreen (visual only so no need to be a double) + FSoundIDNoInit UpSound, ReadySound; // Sounds when coming up and idle + PClassWeapon *SisterWeaponType; // Another weapon to pick up with this one + PClassActor *ProjectileType; // Projectile used by primary attack + PClassActor *AltProjectileType; // Projectile used by alternate attack + int SelectionOrder; // Lower-numbered weapons get picked first + int MinSelAmmo1, MinSelAmmo2; // Ignore in BestWeapon() if inadequate ammo + double MoveCombatDist; // Used by bots, but do they *really* need it? + int ReloadCounter; // For A_CheckForReload + int BobStyle; // [XA] Bobbing style. Defines type of bobbing (e.g. Normal, Alpha) (visual only so no need to be a double) + float BobSpeed; // [XA] Bobbing speed. Defines how quickly a weapon bobs. + float BobRangeX, BobRangeY; // [XA] Bobbing range. Defines how far a weapon bobs in either direction. + + // In-inventory instance variables + TObjPtr Ammo1, Ammo2; + TObjPtr SisterWeapon; + float FOVScale; + int Crosshair; // 0 to use player's crosshair + bool GivenAsMorphWeapon; + + bool bAltFire; // Set when this weapon's alternate fire is used. + + virtual void MarkPrecacheSounds() const; + + virtual void Serialize(FSerializer &arc) override; + virtual bool ShouldStay () override; + virtual void AttachToOwner (AActor *other) override; + virtual bool HandlePickup (AInventory *item) override; + virtual AInventory *CreateCopy (AActor *other) override; + virtual AInventory *CreateTossable () override; + virtual bool TryPickup (AActor *&toucher) override; + virtual bool TryPickupRestricted (AActor *&toucher) override; + virtual bool Use (bool pickup) override; + virtual void Destroy() override; + + bool PickupForAmmo(AWeapon *ownedWeapon); + void PostMorphWeapon(); + + // scripted virtuals. + FState *GetUpState (); + FState *GetDownState (); + FState *GetReadyState (); + FState *GetAtkState (bool hold); + FState *GetAltAtkState (bool hold); + + FState *GetStateForButtonName (FName button); + + + virtual void EndPowerup (); + void CallEndPowerup(); + + enum + { + PrimaryFire, + AltFire, + EitherFire + }; + bool CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo=false, int ammocount = -1); + bool DepleteAmmo (bool altFire, bool checkEnough=true, int ammouse = -1); + + enum + { + BobNormal, + BobInverse, + BobAlpha, + BobInverseAlpha, + BobSmooth, + BobInverseSmooth + }; + +protected: + AAmmo *AddAmmo (AActor *other, PClassActor *ammotype, int amount); + bool AddExistingAmmo (AAmmo *ammo, int amount); + AWeapon *AddWeapon (PClassWeapon *weapon); +}; + +enum +{ + WIF_NOAUTOFIRE = 0x00000001, // weapon does not autofire + WIF_READYSNDHALF = 0x00000002, // ready sound is played ~1/2 the time + WIF_DONTBOB = 0x00000004, // don't bob the weapon + WIF_AXEBLOOD = 0x00000008, // weapon makes axe blood on impact (Hexen only) + WIF_NOALERT = 0x00000010, // weapon does not alert monsters + WIF_AMMO_OPTIONAL = 0x00000020, // weapon can use ammo but does not require it + WIF_ALT_AMMO_OPTIONAL = 0x00000040, // alternate fire can use ammo but does not require it + WIF_PRIMARY_USES_BOTH = 0x00000080, // primary fire uses both ammo + WIF_ALT_USES_BOTH = 0x00000100, // alternate fire uses both ammo + WIF_WIMPY_WEAPON = 0x00000200, // change away when ammo for another weapon is replenished + WIF_POWERED_UP = 0x00000400, // this is a tome-of-power'ed version of its sister + WIF_AMMO_CHECKBOTH = 0x00000800, // check for both primary and secondary fire before switching it off + WIF_NO_AUTO_SWITCH = 0x00001000, // never switch to this weapon when it's picked up + WIF_STAFF2_KICKBACK = 0x00002000, // the powered-up Heretic staff has special kickback + WIF_NOAUTOAIM = 0x00004000, // this weapon never uses autoaim (useful for ballistic projectiles) + WIF_MELEEWEAPON = 0x00008000, // melee weapon. Used by bots and monster AI. + WIF_DEHAMMO = 0x00010000, // Uses Doom's original amount of ammo for the respective attack functions so that old DEHACKED patches work as intended. + // AmmoUse1 will be set to the first attack's ammo use so that checking for empty weapons still works + WIF_NODEATHDESELECT = 0x00020000, // Don't jump to the Deselect state when the player dies + WIF_NODEATHINPUT = 0x00040000, // The weapon cannot be fired/reloaded/whatever when the player is dead + WIF_CHEATNOTWEAPON = 0x08000000, // Give cheat considers this not a weapon (used by Sigil) + + // Flags used only by bot AI: + + WIF_BOT_REACTION_SKILL_THING = 1<<31, // I don't understand this + WIF_BOT_EXPLOSIVE = 1<<30, // weapon fires an explosive + WIF_BOT_BFG = 1<<28, // this is a BFG +}; + +class AWeaponGiver : public AWeapon +{ + DECLARE_CLASS(AWeaponGiver, AWeapon) + +public: + virtual bool TryPickup(AActor *&toucher) override; + virtual void Serialize(FSerializer &arc) override; + + double DropAmmoFactor; +}; + diff --git a/src/g_level.cpp b/src/g_level.cpp index 9e8448879f..4bb78461af 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -79,7 +79,6 @@ #include "v_palette.h" #include "menu/menu.h" #include "a_sharedglobal.h" -#include "a_strifeglobal.h" #include "r_data/colormaps.h" #include "r_renderer.h" #include "r_utility.h" @@ -478,7 +477,8 @@ void G_InitNew (const char *mapname, bool bTitleLevel) // Set the initial quest log text for Strife. for (i = 0; i < MAXPLAYERS; ++i) { - players[i].SetLogText ("Find help"); + if (playeringame[i]) + players[i].SetLogText ("Find help"); } } @@ -903,7 +903,7 @@ public: void Tick (); }; -IMPLEMENT_CLASS (DAutosaver) +IMPLEMENT_CLASS(DAutosaver, false, false) void DAutosaver::Tick () { @@ -1092,7 +1092,7 @@ void G_WorldDone (void) if (strncmp (nextlevel, "enDSeQ", 6) == 0) { FName endsequence = ENamedName(strtol(nextlevel.GetChars()+6, NULL, 16)); - // Strife needs a special case here to choose between good and sad ending. Bad is handled elsewherw. + // Strife needs a special case here to choose between good and sad ending. Bad is handled elsewhere. if (endsequence == NAME_Inter_Strife) { if (players[0].mo->FindInventory (QuestItemClasses[24]) || @@ -1848,6 +1848,49 @@ void FLevelLocals::AddScroller (int secnum) } } +//========================================================================== +// +// +// +//========================================================================== + +DEFINE_FIELD(FLevelLocals, time) +DEFINE_FIELD(FLevelLocals, maptime) +DEFINE_FIELD(FLevelLocals, totaltime) +DEFINE_FIELD(FLevelLocals, starttime) +DEFINE_FIELD(FLevelLocals, partime) +DEFINE_FIELD(FLevelLocals, sucktime) +DEFINE_FIELD(FLevelLocals, cluster) +DEFINE_FIELD(FLevelLocals, clusterflags) +DEFINE_FIELD(FLevelLocals, levelnum) +DEFINE_FIELD(FLevelLocals, LevelName) +DEFINE_FIELD(FLevelLocals, MapName) +DEFINE_FIELD(FLevelLocals, NextMap) +DEFINE_FIELD(FLevelLocals, NextSecretMap) +DEFINE_FIELD(FLevelLocals, maptype) +DEFINE_FIELD(FLevelLocals, Music) +DEFINE_FIELD(FLevelLocals, musicorder) +DEFINE_FIELD(FLevelLocals, total_secrets) +DEFINE_FIELD(FLevelLocals, found_secrets) +DEFINE_FIELD(FLevelLocals, total_items) +DEFINE_FIELD(FLevelLocals, found_items) +DEFINE_FIELD(FLevelLocals, total_monsters) +DEFINE_FIELD(FLevelLocals, killed_monsters) +DEFINE_FIELD(FLevelLocals, gravity) +DEFINE_FIELD(FLevelLocals, aircontrol) +DEFINE_FIELD(FLevelLocals, airfriction) +DEFINE_FIELD(FLevelLocals, airsupply) +DEFINE_FIELD(FLevelLocals, teamdamage) +DEFINE_FIELD_BIT(FLevelLocals, flags, monsterstelefrag, LEVEL_MONSTERSTELEFRAG) +DEFINE_FIELD_BIT(FLevelLocals, flags, actownspecial, LEVEL_ACTOWNSPECIAL) +DEFINE_FIELD_BIT(FLevelLocals, flags, sndseqtotalctrl, LEVEL_SNDSEQTOTALCTRL) +DEFINE_FIELD_BIT(FLevelLocals, flags2, allmap, LEVEL2_ALLMAP) +DEFINE_FIELD_BIT(FLevelLocals, flags2, missilesactivateimpact, LEVEL2_MISSILESACTIVATEIMPACT) +DEFINE_FIELD_BIT(FLevelLocals, flags2, monsterfallingdamage, LEVEL2_MONSTERFALLINGDAMAGE) +DEFINE_FIELD_BIT(FLevelLocals, flags2, checkswitchrange, LEVEL2_CHECKSWITCHRANGE) +DEFINE_FIELD_BIT(FLevelLocals, flags2, polygrind, LEVEL2_POLYGRIND) +DEFINE_FIELD_BIT(FLevelLocals, flags2, nomonsters, LEVEL2_NOMONSTERS) + //========================================================================== // // Lists all currently defined maps diff --git a/src/g_level.h b/src/g_level.h index 9f8c5efd52..790eba3444 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -110,6 +110,7 @@ struct FMapInfoParser void ParseAMColors(bool); FName CheckEndSequence(); FName ParseEndGame(); + void ParseDamageDefinition(); }; #define DEFINE_MAP_OPTION(name, old) \ @@ -259,7 +260,7 @@ struct FOptionalMapinfoDataPtr typedef TMap FOptData; typedef TMap FMusicMap; -enum EMapType +enum EMapType : int { MAPTYPE_UNKNOWN = 0, MAPTYPE_DOOM, diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index 7bfb690e79..5ffb04732b 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -860,14 +860,14 @@ DEFINE_MAP_OPTION(fade, true) { parse.ParseAssign(); parse.sc.MustGetString(); - info->fadeto = V_GetColor(NULL, parse.sc.String); + info->fadeto = V_GetColor(NULL, parse.sc); } DEFINE_MAP_OPTION(outsidefog, true) { parse.ParseAssign(); parse.sc.MustGetString(); - info->outsidefog = V_GetColor(NULL, parse.sc.String); + info->outsidefog = V_GetColor(NULL, parse.sc); } DEFINE_MAP_OPTION(titlepatch, true) @@ -1881,6 +1881,18 @@ void FMapInfoParser::ParseMapInfo (int lump, level_info_t &gamedefaults, level_i sc.ScriptError("doomednums definitions not supported with old MAPINFO syntax"); } } + else if (sc.Compare("damagetype")) + { + if (format_type != FMT_Old) + { + format_type = FMT_New; + ParseDamageDefinition(); + } + else + { + sc.ScriptError("damagetype definitions not supported with old MAPINFO syntax"); + } + } else if (sc.Compare("spawnnums")) { if (format_type != FMT_Old) diff --git a/src/g_pch.h b/src/g_pch.h index 3f44cf9b54..a22649815a 100644 --- a/src/g_pch.h +++ b/src/g_pch.h @@ -18,3 +18,4 @@ #include #include #include +#include diff --git a/src/g_raven/a_artitele.cpp b/src/g_raven/a_artitele.cpp deleted file mode 100644 index 9a43f8518d..0000000000 --- a/src/g_raven/a_artitele.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "info.h" -#include "a_pickups.h" -#include "a_artifacts.h" -#include "gstrings.h" -#include "p_local.h" -#include "p_spec.h" -#include "gi.h" -#include "s_sound.h" -#include "m_random.h" -#include "doomstat.h" -#include "g_game.h" -#include "d_player.h" -#include "a_morph.h" - -static FRandom pr_tele ("TeleportSelf"); - -// Teleport (self) ---------------------------------------------------------- - -class AArtiTeleport : public AInventory -{ - DECLARE_CLASS (AArtiTeleport, AInventory) -public: - bool Use (bool pickup); -}; - -IMPLEMENT_CLASS (AArtiTeleport) - -bool AArtiTeleport::Use (bool pickup) -{ - DVector3 dest; - int destAngle; - - if (deathmatch) - { - unsigned int selections = deathmatchstarts.Size (); - unsigned int i = pr_tele() % selections; - dest = deathmatchstarts[i].pos; - destAngle = deathmatchstarts[i].angle; - } - else - { - FPlayerStart *start = G_PickPlayerStart(int(Owner->player - players)); - dest = start->pos; - destAngle = start->angle; - } - dest.Z = ONFLOORZ; - P_Teleport (Owner, dest, (double)destAngle, TELF_SOURCEFOG | TELF_DESTFOG); - bool canlaugh = true; - if (Owner->player->morphTics && (Owner->player->MorphStyle & MORPH_UNDOBYCHAOSDEVICE)) - { // Teleporting away will undo any morph effects (pig) - if (!P_UndoPlayerMorph (Owner->player, Owner->player, MORPH_UNDOBYCHAOSDEVICE) - && (Owner->player->MorphStyle & MORPH_FAILNOLAUGH)) - { - canlaugh = false; - } - } - if (canlaugh) - { // Full volume laugh - S_Sound (Owner, CHAN_VOICE, "*evillaugh", 1, ATTN_NONE); - } - return true; -} - -//--------------------------------------------------------------------------- -// -// FUNC P_AutoUseChaosDevice -// -//--------------------------------------------------------------------------- - -bool P_AutoUseChaosDevice (player_t *player) -{ - AInventory *arti = player->mo->FindInventory(PClass::FindActor("ArtiTeleport")); - - if (arti != NULL) - { - player->mo->UseInventory (arti); - player->health = player->mo->health = (player->health+1)/2; - return true; - } - return false; -} diff --git a/src/g_raven/a_minotaur.cpp b/src/g_raven/a_minotaur.cpp deleted file mode 100644 index 9f58ce4c3f..0000000000 --- a/src/g_raven/a_minotaur.cpp +++ /dev/null @@ -1,628 +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 "ravenshared.h" -#include "a_action.h" -#include "gi.h" -#include "w_wad.h" -#include "thingdef/thingdef.h" -#include "g_level.h" -#include "doomstat.h" -#include "a_pickups.h" -#include "d_player.h" -#include "serializer.h" - -#define MAULATORTICS (25*35) - -static FRandom pr_minotauratk1 ("MinotaurAtk1"); -static FRandom pr_minotaurdecide ("MinotaurDecide"); -static FRandom pr_atk ("MinotaurAtk2"); -static FRandom pr_minotauratk3 ("MinotaurAtk3"); -static FRandom pr_fire ("MntrFloorFire"); -static FRandom pr_minotaurslam ("MinotaurSlam"); -static FRandom pr_minotaurroam ("MinotaurRoam"); -static FRandom pr_minotaurchase ("MinotaurChase"); - -void P_MinotaurSlam (AActor *source, AActor *target); - -DECLARE_ACTION(A_MinotaurLook) - -IMPLEMENT_CLASS(AMinotaur) - -void AMinotaur::Tick () -{ - Super::Tick (); - - // The unfriendly Minotaur (Heretic's) is invulnerable while charging - if (!(flags5 & MF5_SUMMONEDMONSTER)) - { - // Get MF_SKULLFLY bit and shift it so it matches MF2_INVULNERABLE - DWORD flying = (flags & MF_SKULLFLY) << 3; - if ((flags2 & MF2_INVULNERABLE) != flying) - { - flags2 ^= MF2_INVULNERABLE; - } - } -} - -bool AMinotaur::Slam (AActor *thing) -{ - // Slamming minotaurs shouldn't move non-creatures - if (!(thing->flags3&MF3_ISMONSTER) && !thing->player) - { - return false; - } - return Super::Slam (thing); -} - -int AMinotaur::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - damage = Super::DoSpecialDamage (target, damage, damagetype); - if ((damage != -1) && (flags & MF_SKULLFLY)) - { // Slam only when in charge mode - P_MinotaurSlam (this, target); - return -1; - } - return damage; -} - -// Minotaur Friend ---------------------------------------------------------- - -IMPLEMENT_CLASS(AMinotaurFriend) - -void AMinotaurFriend::BeginPlay () -{ - Super::BeginPlay (); - StartTime = -1; -} - -void AMinotaurFriend::Serialize(FSerializer &arc) -{ - Super::Serialize (arc); - arc("starttime", StartTime); -} - -void AMinotaurFriend::Die (AActor *source, AActor *inflictor, int dmgflags) -{ - Super::Die (source, inflictor, dmgflags); - - if (tracer && tracer->health > 0 && tracer->player) - { - // Search thinker list for minotaur - TThinkerIterator iterator; - AMinotaurFriend *mo; - - while ((mo = iterator.Next()) != NULL) - { - if (mo->health <= 0) continue; - // [RH] Minotaurs can't be morphed, so this isn't needed - //if (!(mo->flags&MF_COUNTKILL)) continue; // for morphed minotaurs - if (mo->flags&MF_CORPSE) continue; - if (mo->StartTime >= 0 && (level.maptime - StartTime) >= MAULATORTICS) continue; - if (mo->tracer != NULL && mo->tracer->player == tracer->player) break; - } - - if (mo == NULL) - { - AInventory *power = tracer->FindInventory(PClass::FindActor("PowerMinotaur")); - if (power != NULL) - { - power->Destroy (); - } - } - } -} - -bool AMinotaurFriend::OkayToSwitchTarget (AActor *other) -{ - if (other == tracer) return false; // Do not target the master - return Super::OkayToSwitchTarget (other); -} - -// Action functions for the minotaur ---------------------------------------- - -//---------------------------------------------------------------------------- -// -// PROC A_MinotaurAtk1 -// -// Melee attack. -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_MinotaurDeath) -{ - PARAM_ACTION_PROLOGUE; - - if (Wads.CheckNumForName ("MNTRF1", ns_sprites) < 0 && - Wads.CheckNumForName ("MNTRF0", ns_sprites) < 0) - self->SetState(self->FindState ("FadeOut")); - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk1) -{ - PARAM_ACTION_PROLOGUE; - - player_t *player; - - if (!self->target) - { - return 0; - } - S_Sound (self, CHAN_WEAPON, "minotaur/melee", 1, ATTN_NORM); - if (self->CheckMeleeRange()) - { - int damage = pr_minotauratk1.HitDice (4); - int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); - if ((player = self->target->player) != NULL && - player->mo == self->target) - { // Squish the player - player->deltaviewheight = -16; - } - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_MinotaurDecide -// -// Choose a missile attack. -// -//---------------------------------------------------------------------------- - -#define MNTR_CHARGE_SPEED (13.) - -DEFINE_ACTION_FUNCTION(AActor, A_MinotaurDecide) -{ - PARAM_ACTION_PROLOGUE; - - bool friendly = !!(self->flags5 & MF5_SUMMONEDMONSTER); - AActor *target; - double dist; - - target = self->target; - if (!target) - { - return 0; - } - if (!friendly) - { - S_Sound (self, CHAN_WEAPON, "minotaur/sight", 1, ATTN_NORM); - } - dist = self->Distance2D(target); - if (target->Top() > self->Z() - && target->Top() < self->Top() - && dist < (friendly ? 16*64. : 8*64.) - && dist > 1*64. - && pr_minotaurdecide() < 150) - { // Charge attack - // Don't call the state function right away - self->SetState (self->FindState ("Charge"), true); - self->flags |= MF_SKULLFLY; - if (!friendly) - { // Heretic's Minotaur is invulnerable during charge attack - self->flags2 |= MF2_INVULNERABLE; - } - A_FaceTarget (self); - self->VelFromAngle(MNTR_CHARGE_SPEED); - self->special1 = TICRATE/2; // Charge duration - } - else if (target->Z() == target->floorz - && dist < 9*64. - && pr_minotaurdecide() < (friendly ? 100 : 220)) - { // Floor fire attack - self->SetState (self->FindState ("Hammer")); - self->special2 = 0; - } - else - { // Swing attack - A_FaceTarget (self); - // Don't need to call P_SetMobjState because the current state - // falls through to the swing attack - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_MinotaurCharge -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_MinotaurCharge) -{ - PARAM_ACTION_PROLOGUE; - - AActor *puff; - - if (self->target == NULL) - { - return 0; - } - if (self->special1 > 0) - { - PClassActor *type; - - if (gameinfo.gametype == GAME_Heretic) - { - type = PClass::FindActor("PhoenixPuff"); - } - else - { - type = PClass::FindActor("PunchPuff"); - } - puff = Spawn (type, self->Pos(), ALLOW_REPLACE); - puff->Vel.Z = 2; - self->special1--; - } - else - { - self->flags &= ~MF_SKULLFLY; - self->flags2 &= ~MF2_INVULNERABLE; - self->SetState (self->SeeState); - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_MinotaurAtk2 -// -// Swing attack. -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk2) -{ - PARAM_ACTION_PROLOGUE; - - AActor *mo; - DAngle angle; - double vz; - double z; - bool friendly = !!(self->flags5 & MF5_SUMMONEDMONSTER); - - if (self->target == NULL) - { - return 0; - } - S_Sound (self, CHAN_WEAPON, "minotaur/attack2", 1, ATTN_NORM); - if (self->CheckMeleeRange()) - { - int damage; - damage = pr_atk.HitDice (friendly ? 3 : 5); - int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); - return 0; - } - z = self->Z() + 40; - PClassActor *fx = PClass::FindActor("MinotaurFX1"); - if (fx) - { - mo = P_SpawnMissileZ (self, z, self->target, fx); - if (mo != NULL) - { -// S_Sound (mo, CHAN_WEAPON, "minotaur/attack2", 1, ATTN_NORM); - vz = mo->Vel.Z; - angle = mo->Angles.Yaw; - P_SpawnMissileAngleZ (self, z, fx, angle-(45./8), vz); - P_SpawnMissileAngleZ (self, z, fx, angle+(45./8), vz); - P_SpawnMissileAngleZ (self, z, fx, angle-(45./16), vz); - P_SpawnMissileAngleZ (self, z, fx, angle+(45./16), vz); - } - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_MinotaurAtk3 -// -// Floor fire attack. -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_MinotaurAtk3) -{ - PARAM_ACTION_PROLOGUE; - - AActor *mo; - player_t *player; - bool friendly = !!(self->flags5 & MF5_SUMMONEDMONSTER); - - if (!self->target) - { - return 0; - } - S_Sound (self, CHAN_VOICE, "minotaur/attack3", 1, ATTN_NORM); - if (self->CheckMeleeRange()) - { - int damage; - - damage = pr_minotauratk3.HitDice (friendly ? 3 : 5); - int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); - if ((player = self->target->player) != NULL && - player->mo == self->target) - { // Squish the player - player->deltaviewheight = -16; - } - } - else - { - if (self->Floorclip > 0 && (i_compatflags & COMPATF_MINOTAUR)) - { - // only play the sound. - S_Sound (self, CHAN_WEAPON, "minotaur/fx2hit", 1, ATTN_NORM); - } - else - { - mo = P_SpawnMissile (self, self->target, PClass::FindActor("MinotaurFX2")); - if (mo != NULL) - { - S_Sound (mo, CHAN_WEAPON, "minotaur/attack1", 1, ATTN_NORM); - } - } - } - if (pr_minotauratk3() < 192 && self->special2 == 0) - { - self->SetState (self->FindState ("HammerLoop")); - self->special2 = 1; - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_MntrFloorFire -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_MntrFloorFire) -{ - PARAM_ACTION_PROLOGUE; - - AActor *mo; - - self->SetZ(self->floorz); - double x = pr_fire.Random2() / 64.; - double y = pr_fire.Random2() / 64.; - - mo = Spawn("MinotaurFX3", self->Vec2OffsetZ(x, y, self->floorz), ALLOW_REPLACE); - mo->target = self->target; - mo->Vel.X = MinVel; // Force block checking - P_CheckMissileSpawn (mo, self->radius); - return 0; -} - -//--------------------------------------------------------------------------- -// -// FUNC P_MinotaurSlam -// -//--------------------------------------------------------------------------- - -void P_MinotaurSlam (AActor *source, AActor *target) -{ - DAngle angle; - double thrust; - int damage; - - angle = source->AngleTo(target); - thrust = 16 + pr_minotaurslam() / 64.; - target->VelFromAngle(angle, thrust); - damage = pr_minotaurslam.HitDice (static_cast(source) ? 4 : 6); - int newdam = P_DamageMobj (target, NULL, NULL, damage, NAME_Melee); - P_TraceBleed (newdam > 0 ? newdam : damage, target, angle, 0.); - if (target->player) - { - target->reactiontime = 14+(pr_minotaurslam()&7); - } -} - -//---------------------------------------------------------------------------- -// -// Minotaur variables -// -// special1 charge duration countdown -// special2 internal to minotaur AI -// StartTime minotaur start time -// tracer pointer to player that spawned it -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -// -// A_MinotaurRoam -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_MinotaurRoam) -{ - PARAM_ACTION_PROLOGUE; - - // In case pain caused him to skip his fade in. - self->RenderStyle = STYLE_Normal; - - if (self->IsKindOf(RUNTIME_CLASS(AMinotaurFriend))) - { - AMinotaurFriend *self1 = static_cast (self); - - if (self1->StartTime >= 0 && (level.maptime - self1->StartTime) >= MAULATORTICS) - { - P_DamageMobj (self1, NULL, NULL, TELEFRAG_DAMAGE, NAME_None); - return 0; - } - } - - if (pr_minotaurroam() < 30) - CALL_ACTION(A_MinotaurLook, self); // adjust to closest target - - if (pr_minotaurroam() < 6) - { - //Choose new direction - self->movedir = pr_minotaurroam() % 8; - FaceMovementDirection (self); - } - if (!P_Move(self)) - { - // Turn - if (pr_minotaurroam() & 1) - self->movedir = (self->movedir + 1) % 8; - else - self->movedir = (self->movedir + 7) % 8; - FaceMovementDirection (self); - } - return 0; -} - - -//---------------------------------------------------------------------------- -// -// PROC A_MinotaurLook -// -// Look for enemy of player -//---------------------------------------------------------------------------- -#define MINOTAUR_LOOK_DIST (16*54.) - -DEFINE_ACTION_FUNCTION(AActor, A_MinotaurLook) -{ - PARAM_ACTION_PROLOGUE; - - if (!self->IsKindOf(RUNTIME_CLASS(AMinotaurFriend))) - { - CALL_ACTION(A_Look, self); - return 0; - } - - AActor *mo = NULL; - player_t *player; - double dist; - int i; - AActor *master = self->tracer; - - self->target = NULL; - if (deathmatch) // Quick search for players - { - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) continue; - player = &players[i]; - mo = player->mo; - if (mo == master) continue; - if (mo->health <= 0) continue; - dist = self->Distance2D(mo); - if (dist > MINOTAUR_LOOK_DIST) continue; - self->target = mo; - break; - } - } - - if (!self->target) // Near player monster search - { - if (master && (master->health>0) && (master->player)) - mo = P_RoughMonsterSearch(master, 20); - else - mo = P_RoughMonsterSearch(self, 20); - self->target = mo; - } - - if (!self->target) // Normal monster search - { - FActorIterator iterator (0); - - while ((mo = iterator.Next()) != NULL) - { - if (!(mo->flags3 & MF3_ISMONSTER)) continue; - if (mo->health <= 0) continue; - if (!(mo->flags & MF_SHOOTABLE)) continue; - dist = self->Distance2D(mo); - if (dist > MINOTAUR_LOOK_DIST) continue; - if ((mo == master) || (mo == self)) continue; - if ((mo->flags5 & MF5_SUMMONEDMONSTER) && (mo->tracer == master)) continue; - self->target = mo; - break; // Found actor to attack - } - } - - if (self->target) - { - self->SetState (self->SeeState, true); - } - else - { - self->SetState (self->FindState ("Roam"), true); - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_MinotaurChase) -{ - PARAM_ACTION_PROLOGUE; - - if (!self->IsKindOf(RUNTIME_CLASS(AMinotaurFriend))) - { - A_Chase (stack, self); - return 0; - } - - AMinotaurFriend *self1 = static_cast (self); - - // In case pain caused him to skip his fade in. - self1->RenderStyle = STYLE_Normal; - - if (self1->StartTime >= 0 && (level.maptime - self1->StartTime) >= MAULATORTICS) - { - P_DamageMobj (self1, NULL, NULL, TELEFRAG_DAMAGE, NAME_None); - return 0; - } - - if (pr_minotaurchase() < 30) - CALL_ACTION(A_MinotaurLook, self1); // adjust to closest target - - if (!self1->target || (self1->target->health <= 0) || - !(self1->target->flags&MF_SHOOTABLE)) - { // look for a new target - self1->SetIdle(); - return 0; - } - - FaceMovementDirection (self1); - self1->reactiontime = 0; - - // Melee attack - if (self1->MeleeState && self1->CheckMeleeRange ()) - { - if (self1->AttackSound) - { - S_Sound (self1, CHAN_WEAPON, self1->AttackSound, 1, ATTN_NORM); - } - self1->SetState (self1->MeleeState); - return 0; - } - - // Missile attack - if (self1->MissileState && P_CheckMissileRange(self1)) - { - self1->SetState (self1->MissileState); - return 0; - } - - // chase towards target - if (!P_Move (self1)) - { - P_NewChaseDir (self1); - FaceMovementDirection (self1); - } - - // Active sound - if (pr_minotaurchase() < 6) - { - self1->PlayActiveSound (); - } - return 0; -} - diff --git a/src/g_raven/ravenshared.h b/src/g_raven/ravenshared.h deleted file mode 100644 index 81824a9577..0000000000 --- a/src/g_raven/ravenshared.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef __RAVENSHARED_H__ -#define __RAVENSHARED_H__ - -class AActor; - -class AMinotaur : public AActor -{ - DECLARE_CLASS (AMinotaur, AActor) -public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); - -public: - bool Slam (AActor *); - void Tick (); -}; - -class AMinotaurFriend : public AMinotaur -{ - DECLARE_CLASS (AMinotaurFriend, AMinotaur) -public: - int StartTime; - - void Die (AActor *source, AActor *inflictor, int dmgflags); - bool OkayToSwitchTarget (AActor *other); - void BeginPlay (); - - void Serialize(FSerializer &arc); -}; - -#endif //__RAVENSHARED_H__ diff --git a/src/g_shared/a_action.cpp b/src/g_shared/a_action.cpp index c0ec37d09b..187b215b8f 100644 --- a/src/g_shared/a_action.cpp +++ b/src/g_shared/a_action.cpp @@ -1,8 +1,6 @@ #include "actor.h" -#include "thingdef/thingdef.h" #include "p_conversation.h" #include "p_lnspec.h" -#include "a_action.h" #include "m_random.h" #include "s_sound.h" #include "d_player.h" @@ -15,43 +13,9 @@ #include "r_data/r_translate.h" static FRandom pr_freezedeath ("FreezeDeath"); -static FRandom pr_icesettics ("IceSetTics"); static FRandom pr_freeze ("FreezeDeathChunks"); -// SwitchableDecoration: Activate and Deactivate change state --------------- - -class ASwitchableDecoration : public AActor -{ - DECLARE_CLASS (ASwitchableDecoration, AActor) -public: - void Activate (AActor *activator); - void Deactivate (AActor *activator); -}; - -IMPLEMENT_CLASS (ASwitchableDecoration) - -void ASwitchableDecoration::Activate (AActor *activator) -{ - SetState (FindState(NAME_Active)); -} - -void ASwitchableDecoration::Deactivate (AActor *activator) -{ - SetState (FindState(NAME_Inactive)); -} - -// SwitchingDecoration: Only Activate changes state ------------------------- - -class ASwitchingDecoration : public ASwitchableDecoration -{ - DECLARE_CLASS (ASwitchingDecoration, ASwitchableDecoration) -public: - void Deactivate (AActor *activator) {} -}; - -IMPLEMENT_CLASS (ASwitchingDecoration) - //---------------------------------------------------------------------------- // // PROC A_NoBlocking @@ -104,73 +68,9 @@ void A_Unblock(AActor *self, bool drop) DEFINE_ACTION_FUNCTION(AActor, A_NoBlocking) { - PARAM_ACTION_PROLOGUE; - A_Unblock(self, true); - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_Fall) -{ - PARAM_ACTION_PROLOGUE; - A_Unblock(self, true); - return 0; -} - -//========================================================================== -// -// A_SetFloorClip -// -//========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_SetFloorClip) -{ - PARAM_ACTION_PROLOGUE; - - self->flags2 |= MF2_FLOORCLIP; - self->AdjustFloorClip (); - return 0; -} - -//========================================================================== -// -// A_UnSetFloorClip -// -//========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_UnSetFloorClip) -{ - PARAM_ACTION_PROLOGUE; - - self->flags2 &= ~MF2_FLOORCLIP; - self->Floorclip = 0; - return 0; -} - -//========================================================================== -// -// A_HideThing -// -//========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_HideThing) -{ - PARAM_ACTION_PROLOGUE; - - self->renderflags |= RF_INVISIBLE; - return 0; -} - -//========================================================================== -// -// A_UnHideThing -// -//========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_UnHideThing) -{ - PARAM_ACTION_PROLOGUE; - - self->renderflags &= ~RF_INVISIBLE; + PARAM_SELF_PROLOGUE(AActor); + PARAM_BOOL_DEF(drop); + A_Unblock(self, drop); return 0; } @@ -182,7 +82,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_UnHideThing) DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeath) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); int t = pr_freezedeath(); self->tics = 75+t+pr_freezedeath(); @@ -220,46 +120,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeath) return 0; } -//========================================================================== -// -// A_GenericFreezeDeath -// -//========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_GenericFreezeDeath) -{ - PARAM_ACTION_PROLOGUE; - - self->Translation = TRANSLATION(TRANSLATION_Standard, 7); - CALL_ACTION(A_FreezeDeath, self); - return 0; -} - -//============================================================================ -// -// A_IceSetTics -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_IceSetTics) -{ - PARAM_ACTION_PROLOGUE; - - int floor; - - self->tics = 70+(pr_icesettics()&63); - floor = P_GetThingFloorType (self); - if (Terrains[floor].DamageMOD == NAME_Fire) - { - self->tics >>= 2; - } - else if (Terrains[floor].DamageMOD == NAME_Ice) - { - self->tics <<= 1; - } - return 0; -} - //============================================================================ // // A_FreezeDeathChunks @@ -268,7 +128,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_IceSetTics) DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeathChunks) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); int i; int numChunks; @@ -302,7 +162,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeathChunks) mo->Vel.X = pr_freeze.Random2() / 128.; mo->Vel.Y = pr_freeze.Random2() / 128.; mo->Vel.Z = (mo->Z() - self->Z()) / self->Height * 4; - CALL_ACTION(A_IceSetTics, mo); // set a random tic wait mo->RenderStyle = self->RenderStyle; mo->Alpha = self->Alpha; } @@ -360,7 +219,7 @@ class DCorpsePointer : public DThinker HAS_OBJECT_POINTERS public: DCorpsePointer (AActor *ptr); - void Destroy (); + void Destroy() override; void Serialize(FSerializer &arc); TObjPtr Corpse; DWORD Count; // Only the first corpse pointer's count is valid. @@ -368,9 +227,11 @@ private: DCorpsePointer () {} }; -IMPLEMENT_POINTY_CLASS(DCorpsePointer) - DECLARE_POINTER(Corpse) -END_POINTERS +IMPLEMENT_CLASS(DCorpsePointer, false, true) + +IMPLEMENT_POINTERS_START(DCorpsePointer) + IMPLEMENT_POINTER(Corpse) +IMPLEMENT_POINTERS_END CUSTOM_CVAR(Int, sv_corpsequeuesize, 64, CVAR_ARCHIVE|CVAR_SERVERINFO) { @@ -446,7 +307,7 @@ void DCorpsePointer::Serialize(FSerializer &arc) // throw another corpse on the queue DEFINE_ACTION_FUNCTION(AActor, A_QueueCorpse) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); if (sv_corpsequeuesize > 0) { @@ -458,7 +319,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_QueueCorpse) // Remove an self from the queue (for resurrection) DEFINE_ACTION_FUNCTION(AActor, A_DeQueueCorpse) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); TThinkerIterator iterator (STAT_CORPSEPOINTER); DCorpsePointer *corpsePtr; @@ -475,197 +336,3 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeQueueCorpse) return 0; } -//============================================================================ -// -// A_SetInvulnerable -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SetInvulnerable) -{ - PARAM_ACTION_PROLOGUE; - - self->flags2 |= MF2_INVULNERABLE; - return 0; -} - -//============================================================================ -// -// A_UnSetInvulnerable -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_UnSetInvulnerable) -{ - PARAM_ACTION_PROLOGUE; - - self->flags2 &= ~MF2_INVULNERABLE; - return 0; -} - -//============================================================================ -// -// A_SetReflective -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SetReflective) -{ - PARAM_ACTION_PROLOGUE; - - self->flags2 |= MF2_REFLECTIVE; - return 0; -} - -//============================================================================ -// -// A_UnSetReflective -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_UnSetReflective) -{ - PARAM_ACTION_PROLOGUE; - - self->flags2 &= ~MF2_REFLECTIVE; - return 0; -} - -//============================================================================ -// -// A_SetReflectiveInvulnerable -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SetReflectiveInvulnerable) -{ - PARAM_ACTION_PROLOGUE; - - self->flags2 |= MF2_REFLECTIVE|MF2_INVULNERABLE; - return 0; -} - -//============================================================================ -// -// A_UnSetReflectiveInvulnerable -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_UnSetReflectiveInvulnerable) -{ - PARAM_ACTION_PROLOGUE; - - self->flags2 &= ~(MF2_REFLECTIVE|MF2_INVULNERABLE); - return 0; -} - -//========================================================================== -// -// A_SetShootable -// -//========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_SetShootable) -{ - PARAM_ACTION_PROLOGUE; - - self->flags2 &= ~MF2_NONSHOOTABLE; - self->flags |= MF_SHOOTABLE; - return 0; -} - -//========================================================================== -// -// A_UnSetShootable -// -//========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_UnSetShootable) -{ - PARAM_ACTION_PROLOGUE; - - self->flags2 |= MF2_NONSHOOTABLE; - self->flags &= ~MF_SHOOTABLE; - return 0; -} - -//=========================================================================== -// -// A_NoGravity -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_NoGravity) -{ - PARAM_ACTION_PROLOGUE; - - self->flags |= MF_NOGRAVITY; - return 0; -} - -//=========================================================================== -// -// A_Gravity -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_Gravity) -{ - PARAM_ACTION_PROLOGUE; - - self->flags &= ~MF_NOGRAVITY; - self->Gravity = 1; - return 0; -} - -//=========================================================================== -// -// A_LowGravity -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_LowGravity) -{ - PARAM_ACTION_PROLOGUE; - - self->flags &= ~MF_NOGRAVITY; - self->Gravity = 1. / 8;; - return 0; -} - -//=========================================================================== -// -// FaceMovementDirection -// -//=========================================================================== - -void FaceMovementDirection(AActor *actor) -{ - switch (actor->movedir) - { - case DI_EAST: - actor->Angles.Yaw = 0.; - break; - case DI_NORTHEAST: - actor->Angles.Yaw = 45.; - break; - case DI_NORTH: - actor->Angles.Yaw = 90.; - break; - case DI_NORTHWEST: - actor->Angles.Yaw = 135.; - break; - case DI_WEST: - actor->Angles.Yaw = 180.; - break; - case DI_SOUTHWEST: - actor->Angles.Yaw = 225.; - break; - case DI_SOUTH: - actor->Angles.Yaw = 270.; - break; - case DI_SOUTHEAST: - actor->Angles.Yaw = 315.; - break; - } -} diff --git a/src/g_shared/a_action.h b/src/g_shared/a_action.h deleted file mode 100644 index 7c5e00a79e..0000000000 --- a/src/g_shared/a_action.h +++ /dev/null @@ -1,29 +0,0 @@ -class AActor; - -/* -void A_NoBlocking (AActor *); -void A_HideThing (AActor *); -void A_UnHideThing (AActor *); -void A_FreezeDeath (AActor *); -void A_FreezeDeathChunks (AActor *); -void A_GenericFreezeDeath (AActor *); -void A_IceSetTics (AActor *); -void A_IceCheckHeadDone (AActor *); -void A_QueueCorpse (AActor *); -void A_DeQueueCorpse (AActor *); -void A_SetInvulnerable (AActor *); -void A_UnSetInvulnerable (AActor *); -void A_SetReflective (AActor *); -void A_UnSetReflective (AActor *); -void A_SetReflectiveInvulnerable (AActor *); -void A_UnSetReflectiveInvulnerable (AActor *); -void A_SetShootable (AActor *); -void A_UnSetShootable (AActor *); -void A_SetFloorClip (AActor *); -void A_UnSetFloorClip (AActor *); -void A_NoGravity (AActor *); -void A_SkullPop (AActor *); -*/ - - -void FaceMovementDirection (AActor *); diff --git a/src/g_shared/a_bridge.cpp b/src/g_shared/a_bridge.cpp index 178f004caf..cb66577967 100644 --- a/src/g_shared/a_bridge.cpp +++ b/src/g_shared/a_bridge.cpp @@ -2,7 +2,6 @@ #include "info.h" #include "gi.h" #include "m_random.h" -#include "thingdef/thingdef.h" static FRandom pr_orbit ("Orbit"); @@ -38,10 +37,10 @@ class ACustomBridge : public AActor DECLARE_CLASS (ACustomBridge, AActor) public: void BeginPlay (); - void Destroy(); + void Destroy() override; }; -IMPLEMENT_CLASS(ACustomBridge) +IMPLEMENT_CLASS(ACustomBridge, false, false) void ACustomBridge::BeginPlay () { @@ -90,24 +89,22 @@ void ACustomBridge::Destroy() // target pointer to center mobj // angle angle of ball -DEFINE_ACTION_FUNCTION(AActor, A_BridgeOrbit) +static void BridgeOrbit(AActor *self) { - PARAM_ACTION_PROLOGUE; - if (self->target == NULL) { // Don't crash if somebody spawned this into the world // independantly of a Bridge actor. - return 0; + return; } // Set default values // Every five tics, Hexen moved the ball 3/256th of a revolution. - DAngle rotationspeed = 45./32*3/5; + DAngle rotationspeed = 45. / 32 * 3 / 5; double rotationradius = ORBIT_RADIUS; // If the bridge is custom, set non-default values if any. // Set angular speed; 1--128: counterclockwise rotation ~=1--180°; 129--255: clockwise rotation ~= 180--1° - if (self->target->args[3] > 128) rotationspeed = 45./32 * (self->target->args[3]-256) / TICRATE; - else if (self->target->args[3] > 0) rotationspeed = 45./32 * (self->target->args[3]) / TICRATE; + if (self->target->args[3] > 128) rotationspeed = 45. / 32 * (self->target->args[3] - 256) / TICRATE; + else if (self->target->args[3] > 0) rotationspeed = 45. / 32 * (self->target->args[3]) / TICRATE; // Set rotation radius if (self->target->args[4]) rotationradius = ((self->target->args[4] * self->target->radius) / 100); @@ -115,14 +112,20 @@ DEFINE_ACTION_FUNCTION(AActor, A_BridgeOrbit) self->SetOrigin(self->target->Vec3Angle(rotationradius, self->Angles.Yaw, 0), true); self->floorz = self->target->floorz; self->ceilingz = self->target->ceilingz; +} + +DEFINE_ACTION_FUNCTION(ABridgeBall, A_BridgeOrbit) +{ + PARAM_SELF_PROLOGUE(AActor); + BridgeOrbit(self); return 0; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BridgeInit) +DEFINE_ACTION_FUNCTION(ACustomBridge, A_BridgeInit) { - PARAM_ACTION_PROLOGUE; - PARAM_CLASS_OPT(balltype, AActor) { balltype = NULL; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_CLASS_DEF(balltype, AActor); AActor *ball; @@ -141,7 +144,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BridgeInit) ball = Spawn(balltype, self->Pos(), ALLOW_REPLACE); ball->Angles.Yaw = startangle + (45./32) * (256/ballcount) * i; ball->target = self; - CALL_ACTION(A_BridgeOrbit, ball); + BridgeOrbit(ball); } return 0; } @@ -156,7 +159,7 @@ public: void BeginPlay (); }; -IMPLEMENT_CLASS(AInvisibleBridge) +IMPLEMENT_CLASS(AInvisibleBridge, false, false) void AInvisibleBridge::BeginPlay () { diff --git a/src/g_shared/a_camera.cpp b/src/g_shared/a_camera.cpp deleted file mode 100644 index fb3d81533c..0000000000 --- a/src/g_shared/a_camera.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/* -** a_camera.cpp -** Implements the Duke Nukem 3D-ish security camera -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ - -#include "actor.h" -#include "info.h" -#include "a_sharedglobal.h" -#include "p_local.h" -#include "serializer.h" -#include "math/cmath.h" - -/* -== SecurityCamera -== -== args[0] = pitch -== args[1] = amount camera turns to either side of its initial position -== (in degrees) -== args[2] = octics to complete one cycle -*/ - -class ASecurityCamera : public AActor -{ - DECLARE_CLASS (ASecurityCamera, AActor) -public: - void PostBeginPlay (); - void Tick (); - - - void Serialize(FSerializer &arc); -protected: - DAngle Center; - DAngle Acc; - DAngle Delta; - DAngle Range; -}; - -IMPLEMENT_CLASS (ASecurityCamera) - -void ASecurityCamera::Serialize(FSerializer &arc) -{ - Super::Serialize (arc); - arc("center", Center) - ("acc", Acc) - ("delta", Delta) - ("range", Range); -} - -void ASecurityCamera::PostBeginPlay () -{ - Super::PostBeginPlay (); - Center = Angles.Yaw; - if (args[2]) - Delta = 360. / (args[2] * TICRATE / 8); - else - Delta = 0.; - if (args[1]) - Delta /= 2; - Acc = 0.; - Angles.Pitch = (double)clamp((signed char)args[0], -89, 89); - Range = (double)args[1]; -} - -void ASecurityCamera::Tick () -{ - Acc += Delta; - if (Range != 0) - Angles.Yaw = Center + Range * Acc.Sin(); - else if (Delta != 0) - Angles.Yaw = Acc; -} - -/* -== AimingCamera -== -== args[0] = pitch -== args[1] = max turn (in degrees) -== args[2] = max pitch turn (in degrees) -== args[3] = tid of thing to look at -== -== Also uses: -== tracer: thing to look at -*/ - -class AAimingCamera : public ASecurityCamera -{ - DECLARE_CLASS (AAimingCamera, ASecurityCamera) -public: - void PostBeginPlay (); - void Tick (); - - - void Serialize(FSerializer &arc); -protected: - DAngle MaxPitchChange; -}; - -IMPLEMENT_CLASS (AAimingCamera) - -void AAimingCamera::Serialize(FSerializer &arc) -{ - Super::Serialize (arc); - arc("maxpitchchange", MaxPitchChange); -} - -void AAimingCamera::PostBeginPlay () -{ - int changepitch = args[2]; - - args[2] = 0; - Super::PostBeginPlay (); - MaxPitchChange = double(changepitch / TICRATE); - Range /= TICRATE; - - TActorIterator iterator (args[3]); - tracer = iterator.Next (); - if (tracer == NULL) - { - //Printf ("AimingCamera %d: Can't find TID %d\n", tid, args[3]); - } - else - { // Don't try for a new target upon losing this one. - args[3] = 0; - } -} - -void AAimingCamera::Tick () -{ - if (tracer == NULL && args[3] != 0) - { // Recheck, in case something with this TID was created since the last time. - TActorIterator iterator (args[3]); - tracer = iterator.Next (); - } - if (tracer != NULL) - { - DAngle delta; - int dir = P_FaceMobj (this, tracer, &delta); - if (delta > Range) - { - delta = Range; - } - if (dir) - { - Angles.Yaw += delta; - } - else - { - Angles.Yaw -= delta; - } - if (MaxPitchChange != 0) - { // Aim camera's pitch; use floats for precision - DVector2 vect = tracer->Vec2To(this); - double dz = Z() - tracer->Z() - tracer->Height/2; - double dist = vect.Length(); - DAngle desiredPitch = dist != 0.f ? VecToAngle(dist, dz) : 0.; - DAngle diff = deltaangle(Angles.Pitch, desiredPitch); - if (fabs (diff) < MaxPitchChange) - { - Angles.Pitch = desiredPitch; - } - else if (diff < 0) - { - Angles.Pitch -= MaxPitchChange; - } - else - { - Angles.Pitch += MaxPitchChange; - } - } - } -} diff --git a/src/g_shared/a_debris.cpp b/src/g_shared/a_debris.cpp deleted file mode 100644 index 895c3b170a..0000000000 --- a/src/g_shared/a_debris.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "actor.h" -#include "info.h" -#include "m_random.h" -#include "m_fixed.h" - -static FRandom pr_dirt ("SpawnDirt"); - -// Stained glass ------------------------------------------------------------ - -class AGlassShard : public AActor -{ - DECLARE_CLASS (AGlassShard, AActor) -public: - bool FloorBounceMissile (secplane_t &plane) - { - if (!Super::FloorBounceMissile (plane)) - { - if (fabs (Vel.Z) < 0.5) - { - Destroy (); - } - return false; - } - return true; - } -}; - -IMPLEMENT_CLASS(AGlassShard) - -// Dirt stuff - -void P_SpawnDirt (AActor *actor, double radius) -{ - PClassActor *dtype = NULL; - AActor *mo; - - double zo = pr_dirt() / 128. + 1; - DVector3 pos = actor->Vec3Angle(radius, pr_dirt() * (360./256), zo); - - char fmt[8]; - mysnprintf(fmt, countof(fmt), "Dirt%d", 1 + pr_dirt()%6); - dtype = PClass::FindActor(fmt); - if (dtype) - { - mo = Spawn (dtype, pos, ALLOW_REPLACE); - if (mo) - { - mo->Vel.Z = pr_dirt() / 64.; - } - } -} diff --git a/src/g_shared/a_decals.cpp b/src/g_shared/a_decals.cpp index e02ab1a52d..bfbe6d13d2 100644 --- a/src/g_shared/a_decals.cpp +++ b/src/g_shared/a_decals.cpp @@ -58,12 +58,14 @@ static int ImpactCount; CVAR (Bool, cl_spreaddecals, true, CVAR_ARCHIVE) -IMPLEMENT_POINTY_CLASS (DBaseDecal) - DECLARE_POINTER(WallPrev) - DECLARE_POINTER(WallNext) -END_POINTERS +IMPLEMENT_CLASS(DBaseDecal, false, true) -IMPLEMENT_CLASS (DImpactDecal) +IMPLEMENT_POINTERS_START(DBaseDecal) + IMPLEMENT_POINTER(WallPrev) + IMPLEMENT_POINTER(WallNext) +IMPLEMENT_POINTERS_END + +IMPLEMENT_CLASS(DImpactDecal, false, false) DBaseDecal::DBaseDecal () : DThinker(STAT_DECAL), @@ -744,7 +746,7 @@ public: void BeginPlay (); }; -IMPLEMENT_CLASS (ADecal) +IMPLEMENT_CLASS(ADecal, false, false) void ADecal::BeginPlay () { diff --git a/src/g_shared/a_fastprojectile.cpp b/src/g_shared/a_fastprojectile.cpp index 82349c1a71..fb0faef0fc 100644 --- a/src/g_shared/a_fastprojectile.cpp +++ b/src/g_shared/a_fastprojectile.cpp @@ -6,9 +6,9 @@ #include "p_lnspec.h" #include "b_bot.h" #include "p_checkposition.h" +#include "virtual.h" - -IMPLEMENT_CLASS(AFastProjectile) +IMPLEMENT_CLASS(AFastProjectile, false, false) //---------------------------------------------------------------------------- @@ -133,7 +133,14 @@ void AFastProjectile::Tick () if (!frac.isZero() && ripcount <= 0) { ripcount = count >> 3; - Effect(); + + // call the scripted 'Effect' method. + IFVIRTUAL(AFastProjectile, Effect) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DObject*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } } } } @@ -154,35 +161,3 @@ void AFastProjectile::Tick () } -void AFastProjectile::Effect() -{ - FName name = GetClass()->MissileName; - if (name != NAME_None) - { - double hitz = Z()-8; - - if (hitz < floorz) - { - hitz = floorz; - } - // Do not clip this offset to the floor. - hitz += GetClass()->MissileHeight; - - PClassActor *trail = PClass::FindActor(name); - if (trail != NULL) - { - AActor *act = Spawn (trail, PosAtZ(hitz), ALLOW_REPLACE); - if (act != nullptr) - { - if ((flags5 & MF5_GETOWNER) && (target != nullptr)) - act->target = target; - else - act->target = this; - - act->Angles.Pitch = Angles.Pitch; - act->Angles.Yaw = Angles.Yaw; - } - } - } -} - diff --git a/src/g_shared/a_flashfader.cpp b/src/g_shared/a_flashfader.cpp index 71673e5c7d..3e0b939e0f 100644 --- a/src/g_shared/a_flashfader.cpp +++ b/src/g_shared/a_flashfader.cpp @@ -3,9 +3,11 @@ #include "d_player.h" #include "serializer.h" -IMPLEMENT_POINTY_CLASS (DFlashFader) - DECLARE_POINTER (ForWho) -END_POINTERS +IMPLEMENT_CLASS(DFlashFader, false, true) + +IMPLEMENT_POINTERS_START(DFlashFader) + IMPLEMENT_POINTER(ForWho) +IMPLEMENT_POINTERS_END DFlashFader::DFlashFader () { diff --git a/src/g_shared/a_fountain.cpp b/src/g_shared/a_fountain.cpp index 970bd8aaa8..7d7e2e412f 100644 --- a/src/g_shared/a_fountain.cpp +++ b/src/g_shared/a_fountain.cpp @@ -46,13 +46,13 @@ public: void Deactivate (AActor *activator); }; -IMPLEMENT_CLASS (AParticleFountain) +IMPLEMENT_CLASS(AParticleFountain, false, false) void AParticleFountain::PostBeginPlay () { Super::PostBeginPlay (); if (!(SpawnFlags & MTF_DORMANT)) - Activate (NULL); + CallActivate (NULL); } void AParticleFountain::Activate (AActor *activator) diff --git a/src/g_shared/a_hatetarget.cpp b/src/g_shared/a_hatetarget.cpp deleted file mode 100644 index 4d0d9a8e7c..0000000000 --- a/src/g_shared/a_hatetarget.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* -** a_hatetarget.cpp -** Something for monsters to hate and shoot at -** -**--------------------------------------------------------------------------- -** Copyright 2003-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ - -#include "actor.h" -#include "info.h" -#include "m_fixed.h" - -// Hate Target -------------------------------------------------------------- - -class AHateTarget : public AActor -{ - DECLARE_CLASS(AHateTarget, AActor) -public: - void BeginPlay(); - int TakeSpecialDamage(AActor *inflictor, AActor *source, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS(AHateTarget) - -void AHateTarget::BeginPlay() -{ - Super::BeginPlay(); - if (SpawnAngle != 0) - { // Each degree translates into 10 units of health - health = SpawnAngle * 10; - } - else - { - special2 = 1; - health = 1000001; - } -} - -int AHateTarget::TakeSpecialDamage(AActor *inflictor, AActor *source, int damage, FName damagetype) -{ - if (special2 != 0) - { - return 0; - } - else - { - return damage; - } -} - diff --git a/src/g_shared/a_keys.h b/src/g_shared/a_keys.h deleted file mode 100644 index 8222aa6942..0000000000 --- a/src/g_shared/a_keys.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef A_KEYS_H -#define A_KEYS_H - -#include "a_pickups.h" - -class AKey : public AInventory -{ - DECLARE_CLASS (AKey, AInventory) -public: - virtual bool HandlePickup (AInventory *item); - - BYTE KeyNumber; - -protected: - virtual bool ShouldStay (); -}; - -bool P_CheckKeys (AActor *owner, int keynum, bool remote); -void P_InitKeyMessages (); -void P_DeinitKeyMessages (); -int P_GetMapColorForLock (int lock); -int P_GetMapColorForKey (AInventory *key); - -#endif diff --git a/src/g_shared/a_lightning.cpp b/src/g_shared/a_lightning.cpp index 3eaedffc9c..3f44f2fddd 100644 --- a/src/g_shared/a_lightning.cpp +++ b/src/g_shared/a_lightning.cpp @@ -13,7 +13,7 @@ static FRandom pr_lightning ("Lightning"); -IMPLEMENT_CLASS (DLightningThinker) +IMPLEMENT_CLASS(DLightningThinker, false, false) DLightningThinker::DLightningThinker () : DThinker (STAT_LIGHTNING) diff --git a/src/g_shared/a_mapmarker.cpp b/src/g_shared/a_mapmarker.cpp deleted file mode 100644 index f8d7128c35..0000000000 --- a/src/g_shared/a_mapmarker.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* -** a_mapmarker.cpp -** An actor that appears on the automap instead of in the 3D view. -** -**--------------------------------------------------------------------------- -** Copyright 2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ - -#include "a_sharedglobal.h" -#include "statnums.h" - -// Map Marker -------------------------------------------------------------- -// -// This class uses the following argument: -// args[0] == 0, shows the sprite at this actor -// != 0, shows the sprite for all actors whose TIDs match instead -// -// args[1] == 0, show the sprite always -// == 1, show the sprite only after its sector has been drawn -// -// To enable display of the sprite, activate it. To turn off the sprite, -// deactivate it. -// -// All the code to display it is in am_map.cpp. -// -//-------------------------------------------------------------------------- - -IMPLEMENT_CLASS(AMapMarker) - -void AMapMarker::BeginPlay () -{ - ChangeStatNum (STAT_MAPMARKER); -} - -void AMapMarker::Activate (AActor *activator) -{ - flags2 |= MF2_DORMANT; -} - -void AMapMarker::Deactivate (AActor *activator) -{ - flags2 &= ~MF2_DORMANT; -} diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 46ae5cac7b..136c096a31 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -14,6 +14,7 @@ #include "serializer.h" #include "p_enemy.h" #include "d_player.h" +#include "a_armor.h" #include "r_data/sprites.h" static FRandom pr_morphmonst ("MorphMonster"); @@ -137,20 +138,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp AInventory *next = item->Inventory; if (item->IsKindOf (RUNTIME_CLASS(AArmor))) { - if (item->IsKindOf (RUNTIME_CLASS(AHexenArmor))) - { - // Set the HexenArmor slots to 0, except the class slot. - AHexenArmor *hxarmor = static_cast(item); - hxarmor->Slots[0] = 0; - hxarmor->Slots[1] = 0; - hxarmor->Slots[2] = 0; - hxarmor->Slots[3] = 0; - hxarmor->Slots[4] = spawntype->HexenArmor[0]; - } - else - { - item->DepleteOrDestroy(); - } + item->DepleteOrDestroy(); } item = next; } @@ -372,6 +360,15 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, return true; } +DEFINE_ACTION_FUNCTION(_PlayerInfo, UndoPlayerMorph) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_POINTER_NOT_NULL(player, player_t); + PARAM_INT_DEF(unmorphflag); + PARAM_BOOL_DEF(force); + ACTION_RETURN_BOOL(P_UndoPlayerMorph(self, player, unmorphflag, force)); +} + //--------------------------------------------------------------------------- // // FUNC P_MorphMonster @@ -616,21 +613,31 @@ void InitAllPowerupEffects(AInventory *item) // Base class for morphing projectiles -------------------------------------- -IMPLEMENT_CLASS(AMorphProjectile) +IMPLEMENT_CLASS(AMorphProjectile, false, true) + +IMPLEMENT_POINTERS_START(AMorphProjectile) + IMPLEMENT_POINTER(PlayerClass) + IMPLEMENT_POINTER(MonsterClass) + IMPLEMENT_POINTER(MorphFlash) + IMPLEMENT_POINTER(UnMorphFlash) +IMPLEMENT_POINTERS_END + +DEFINE_FIELD(AMorphProjectile, PlayerClass) +DEFINE_FIELD(AMorphProjectile, MonsterClass) +DEFINE_FIELD(AMorphProjectile, MorphFlash) +DEFINE_FIELD(AMorphProjectile, UnMorphFlash) +DEFINE_FIELD(AMorphProjectile, Duration) +DEFINE_FIELD(AMorphProjectile, MorphStyle) int AMorphProjectile::DoSpecialDamage (AActor *target, int damage, FName damagetype) { - PClassActor *morph_flash = PClass::FindActor(MorphFlash); - PClassActor *unmorph_flash = PClass::FindActor(UnMorphFlash); if (target->player) { - PClassPlayerPawn *player_class = dyn_cast(PClass::FindClass(PlayerClass)); - P_MorphPlayer (NULL, target->player, player_class, Duration, MorphStyle, morph_flash, unmorph_flash); + P_MorphPlayer (NULL, target->player, PlayerClass, Duration, MorphStyle, MorphFlash, UnMorphFlash); } else { - PClassActor *monster_class = PClass::FindActor(MonsterClass); - P_MorphMonster (target, monster_class, Duration, MorphStyle, morph_flash, unmorph_flash); + P_MorphMonster (target, MonsterClass, Duration, MorphStyle, MorphFlash, UnMorphFlash); } return -1; } @@ -650,9 +657,16 @@ void AMorphProjectile::Serialize(FSerializer &arc) // Morphed Monster (you must subclass this to do something useful) --------- -IMPLEMENT_POINTY_CLASS (AMorphedMonster) - DECLARE_POINTER (UnmorphedMe) -END_POINTERS +IMPLEMENT_CLASS(AMorphedMonster, false, true) + +IMPLEMENT_POINTERS_START(AMorphedMonster) + IMPLEMENT_POINTER(UnmorphedMe) +IMPLEMENT_POINTERS_END + +DEFINE_FIELD(AMorphedMonster, UnmorphedMe) +DEFINE_FIELD(AMorphedMonster, UnmorphTime) +DEFINE_FIELD(AMorphedMonster, MorphStyle) +DEFINE_FIELD(AMorphedMonster, MorphExitFlash) void AMorphedMonster::Serialize(FSerializer &arc) { @@ -685,7 +699,7 @@ void AMorphedMonster::Die (AActor *source, AActor *inflictor, int dmgflags) if (UnmorphedMe != NULL && (UnmorphedMe->flags & MF_UNMORPHED)) { UnmorphedMe->health = health; - UnmorphedMe->Die (source, inflictor, dmgflags); + UnmorphedMe->CallDie (source, inflictor, dmgflags); } } diff --git a/src/g_shared/a_movingcamera.cpp b/src/g_shared/a_movingcamera.cpp index 76f128b15a..a1ffe5dc60 100644 --- a/src/g_shared/a_movingcamera.cpp +++ b/src/g_shared/a_movingcamera.cpp @@ -66,9 +66,11 @@ public: TObjPtr Next; }; -IMPLEMENT_POINTY_CLASS (AInterpolationPoint) - DECLARE_POINTER (Next) -END_POINTERS +IMPLEMENT_CLASS(AInterpolationPoint, false, true) + +IMPLEMENT_POINTERS_START(AInterpolationPoint) + IMPLEMENT_POINTER(Next) +IMPLEMENT_POINTERS_END void AInterpolationPoint::Serialize(FSerializer &arc) { @@ -133,7 +135,7 @@ public: void Tick () {} // Does absolutely nothing itself }; -IMPLEMENT_CLASS (AInterpolationSpecial) +IMPLEMENT_CLASS(AInterpolationSpecial, false, false) /* == PathFollower: something that follows a camera path @@ -176,10 +178,12 @@ protected: int HoldTime; }; -IMPLEMENT_POINTY_CLASS (APathFollower) - DECLARE_POINTER (PrevNode) - DECLARE_POINTER (CurrNode) -END_POINTERS +IMPLEMENT_CLASS(APathFollower, false, true) + +IMPLEMENT_POINTERS_START(APathFollower) + IMPLEMENT_POINTER(PrevNode) + IMPLEMENT_POINTER(CurrNode) +IMPLEMENT_POINTERS_END void APathFollower::Serialize(FSerializer &arc) { @@ -338,9 +342,9 @@ void APathFollower::Tick () if (CurrNode != NULL) NewNode (); if (CurrNode == NULL || CurrNode->Next == NULL) - Deactivate (this); + CallDeactivate (this); if ((args[2] & 1) == 0 && CurrNode->Next->Next == NULL) - Deactivate (this); + CallDeactivate (this); } } } @@ -476,7 +480,7 @@ protected: bool Interpolate (); }; -IMPLEMENT_CLASS (AActorMover) +IMPLEMENT_CLASS(AActorMover, false, false) void AActorMover::BeginPlay() { @@ -592,9 +596,11 @@ protected: TObjPtr Activator; }; -IMPLEMENT_POINTY_CLASS (AMovingCamera) - DECLARE_POINTER (Activator) -END_POINTERS +IMPLEMENT_CLASS(AMovingCamera, false, true) + +IMPLEMENT_POINTERS_START(AMovingCamera) + IMPLEMENT_POINTER(Activator) +IMPLEMENT_POINTERS_END void AMovingCamera::Serialize(FSerializer &arc) { diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h deleted file mode 100644 index 9dba52639a..0000000000 --- a/src/g_shared/a_pickups.h +++ /dev/null @@ -1,589 +0,0 @@ -#ifndef __A_PICKUPS_H__ -#define __A_PICKUPS_H__ - -#include "actor.h" -#include "info.h" -#include "s_sound.h" - -#define NUM_WEAPON_SLOTS 10 - -class player_t; -class FConfigFile; -class AWeapon; -class PClassWeapon; -class PClassPlayerPawn; -struct visstyle_t; - -class FWeaponSlot -{ -public: - FWeaponSlot() { Clear(); } - FWeaponSlot(const FWeaponSlot &other) { Weapons = other.Weapons; } - FWeaponSlot &operator= (const FWeaponSlot &other) { Weapons = other.Weapons; return *this; } - void Clear() { Weapons.Clear(); } - bool AddWeapon (const char *type); - bool AddWeapon (PClassWeapon *type); - void AddWeaponList (const char *list, bool clear); - AWeapon *PickWeapon (player_t *player, bool checkammo = false); - int Size () const { return (int)Weapons.Size(); } - int LocateWeapon (PClassWeapon *type); - - inline PClassWeapon *GetWeapon (int index) const - { - if ((unsigned)index < Weapons.Size()) - { - return Weapons[index].Type; - } - else - { - return NULL; - } - } - - friend struct FWeaponSlots; - -private: - struct WeaponInfo - { - PClassWeapon *Type; - int Position; - }; - void SetInitialPositions(); - void Sort(); - TArray Weapons; -}; -// FWeaponSlots::AddDefaultWeapon return codes -enum ESlotDef -{ - SLOTDEF_Exists, // Weapon was already assigned a slot - SLOTDEF_Added, // Weapon was successfully added - SLOTDEF_Full // The specifed slot was full -}; - -struct FWeaponSlots -{ - FWeaponSlots() { Clear(); } - FWeaponSlots(const FWeaponSlots &other); - - FWeaponSlot Slots[NUM_WEAPON_SLOTS]; - - AWeapon *PickNextWeapon (player_t *player); - AWeapon *PickPrevWeapon (player_t *player); - - void Clear (); - bool LocateWeapon (PClassWeapon *type, int *const slot, int *const index); - ESlotDef AddDefaultWeapon (int slot, PClassWeapon *type); - void AddExtraWeapons(); - void SetFromGameInfo(); - void SetFromPlayer(PClassPlayerPawn *type); - void StandardSetup(PClassPlayerPawn *type); - void LocalSetup(PClassActor *type); - void SendDifferences(int playernum, const FWeaponSlots &other); - int RestoreSlots (FConfigFile *config, const char *section); - void PrintSettings(); - - void AddSlot(int slot, PClassWeapon *type, bool feedback); - void AddSlotDefault(int slot, PClassWeapon *type, bool feedback); - -}; - -void P_PlaybackKeyConfWeapons(FWeaponSlots *slots); -void Net_WriteWeapon(PClassWeapon *type); -PClassWeapon *Net_ReadWeapon(BYTE **stream); - -void P_SetupWeapons_ntohton(); -void P_WriteDemoWeaponsChunk(BYTE **demo); -void P_ReadDemoWeaponsChunk(BYTE **demo); - -/************************************************************************/ -/* Class definitions */ -/************************************************************************/ - -// A pickup is anything the player can pickup (i.e. weapons, ammo, powerups, etc) - -enum -{ - IF_ACTIVATABLE = 1<<0, // can be activated - IF_ACTIVATED = 1<<1, // is currently activated - IF_PICKUPGOOD = 1<<2, // HandlePickup wants normal pickup FX to happen - IF_QUIET = 1<<3, // Don't give feedback when picking up - IF_AUTOACTIVATE = 1<<4, // Automatically activate item on pickup - IF_UNDROPPABLE = 1<<5, // Item cannot be removed unless done explicitly with RemoveInventory - IF_INVBAR = 1<<6, // Item appears in the inventory bar - IF_HUBPOWER = 1<<7, // Powerup is kept when moving in a hub - IF_UNTOSSABLE = 1<<8, // The player cannot manually drop the item - IF_ADDITIVETIME = 1<<9, // when picked up while another item is active, time is added instead of replaced. - IF_ALWAYSPICKUP = 1<<10, // For IF_AUTOACTIVATE, MaxAmount=0 items: Always "pick up", even if it doesn't do anything - IF_FANCYPICKUPSOUND = 1<<11, // Play pickup sound in "surround" mode - IF_BIGPOWERUP = 1<<12, // Affected by RESPAWN_SUPER dmflag - IF_KEEPDEPLETED = 1<<13, // Items with this flag are retained even when they run out. - IF_IGNORESKILL = 1<<14, // Ignores any skill related multiplicators when giving this item. - IF_CREATECOPYMOVED = 1<<15, // CreateCopy changed the owner (copy's Owner field holds new owner). - IF_INITEFFECTFAILED = 1<<16, // CreateCopy tried to activate a powerup and activation failed (can happen with PowerMorph) - IF_NOATTENPICKUPSOUND = 1<<17, // Play pickup sound with ATTN_NONE - IF_PERSISTENTPOWER = 1<<18, // Powerup is kept when travelling between levels - IF_RESTRICTABSOLUTELY = 1<<19, // RestrictedTo and ForbiddenTo do not allow pickup in any form by other classes - IF_NEVERRESPAWN = 1<<20, // Never, ever respawns - IF_NOSCREENFLASH = 1<<21, // No pickup flash on the player's screen - IF_TOSSED = 1<<22, // Was spawned by P_DropItem (i.e. as a monster drop) - IF_ALWAYSRESPAWN = 1<<23, // Always respawn, regardless of dmflag - IF_TRANSFER = 1<<24, // All inventory items that the inventory item contains is also transfered to the pickuper - IF_NOTELEPORTFREEZE = 1<<25, // does not 'freeze' the player right after teleporting. -}; - - -class PClassInventory : public PClassActor -{ - DECLARE_CLASS(PClassInventory, PClassActor) -public: - PClassInventory(); - virtual void DeriveData(PClass *newclass); - virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); - - FString PickupMessage; - int GiveQuest; // Optionally give one of the quest items. - FTextureID AltHUDIcon; - TArray RestrictedToPlayerClass; - TArray ForbiddenToPlayerClass; -}; - -class AInventory : public AActor -{ - DECLARE_CLASS_WITH_META(AInventory, AActor, PClassInventory) - HAS_OBJECT_POINTERS -public: - virtual void Touch (AActor *toucher); - - virtual void Serialize(FSerializer &arc); - - virtual void MarkPrecacheSounds() const; - virtual void BeginPlay (); - virtual void Destroy (); - virtual void DepleteOrDestroy (); - virtual void Tick (); - virtual bool ShouldRespawn (); - virtual bool ShouldStay (); - virtual void Hide (); - bool CallTryPickup (AActor *toucher, AActor **toucher_return = NULL); - virtual void DoPickupSpecial (AActor *toucher); - virtual bool SpecialDropAction (AActor *dropper); - virtual bool DrawPowerup (int x, int y); - virtual void DoEffect (); - virtual bool Grind(bool items); - - virtual const char *PickupMessage (); - virtual void PlayPickupSound (AActor *toucher); - - bool DoRespawn (); - AInventory *PrevItem(); // Returns the item preceding this one in the list. - AInventory *PrevInv(); // Returns the previous item with IF_INVBAR set. - AInventory *NextInv(); // Returns the next item with IF_INVBAR set. - - TObjPtr Owner; // Who owns this item? NULL if it's still a pickup. - int Amount; // Amount of item this instance has - int MaxAmount; // Max amount of item this instance can have - int InterHubAmount; // Amount of item that can be kept between hubs or levels - int RespawnTics; // Tics from pickup time to respawn time - FTextureID Icon; // Icon to show on status bar or HUD - int DropTime; // Countdown after dropping - PClassActor *SpawnPointClass; // For respawning like Heretic's mace - - DWORD ItemFlags; - PClassActor *PickupFlash; // actor to spawn as pickup flash - - FSoundIDNoInit PickupSound; - - virtual void BecomeItem (); - virtual void BecomePickup (); - virtual void AttachToOwner (AActor *other); - virtual void DetachFromOwner (); - virtual AInventory *CreateCopy (AActor *other); - virtual AInventory *CreateTossable (); - virtual bool GoAway (); - virtual void GoAwayAndDie (); - virtual bool HandlePickup (AInventory *item); - virtual bool Use (bool pickup); - virtual void Travelled (); - virtual void OwnerDied (); - - virtual void AbsorbDamage (int damage, FName damageType, int &newdamage); - virtual void ModifyDamage (int damage, FName damageType, int &newdamage, bool passive); - virtual double GetSpeedFactor(); - virtual bool GetNoTeleportFreeze(); - virtual int AlterWeaponSprite (visstyle_t *vis); - - virtual PalEntry GetBlend (); - -protected: - virtual bool TryPickup (AActor *&toucher); - virtual bool TryPickupRestricted (AActor *&toucher); - bool CanPickup(AActor * toucher); - void GiveQuest(AActor * toucher); - -private: - static int StaticLastMessageTic; - static const char *StaticLastMessage; -}; - -// CustomInventory: Supports the Use, Pickup, and Drop states from 96x -class ACustomInventory : public AInventory -{ - DECLARE_CLASS (ACustomInventory, AInventory) -public: - - // This is used when an inventory item's use state sequence is executed. - bool CallStateChain (AActor *actor, FState *state); - - bool TryPickup (AActor *&toucher); - bool Use (bool pickup); - bool SpecialDropAction (AActor *dropper); -}; - -// Ammo: Something a weapon needs to operate -class PClassAmmo : public PClassInventory -{ - DECLARE_CLASS(PClassAmmo, PClassInventory) -protected: - virtual void DeriveData(PClass *newclass); -public: - PClassAmmo(); - - int DropAmount; // Specifies the amount for a dropped ammo item. -}; - -class AAmmo : public AInventory -{ - DECLARE_CLASS_WITH_META(AAmmo, AInventory, PClassAmmo) -public: - - void Serialize(FSerializer &arc); - AInventory *CreateCopy (AActor *other); - bool HandlePickup (AInventory *item); - PClassActor *GetParentAmmo () const; - AInventory *CreateTossable (); - - int BackpackAmount, BackpackMaxAmount; -}; - -// A weapon is just that. -class PClassWeapon : public PClassInventory -{ - DECLARE_CLASS(PClassWeapon, PClassInventory); -protected: - virtual void DeriveData(PClass *newclass); -public: - PClassWeapon(); - virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); - - int SlotNumber; - int SlotPriority; -}; - -class AWeapon : public AInventory -{ - DECLARE_CLASS_WITH_META(AWeapon, AInventory, PClassWeapon) - HAS_OBJECT_POINTERS -public: - DWORD WeaponFlags; - PClassAmmo *AmmoType1, *AmmoType2; // Types of ammo used by this weapon - int AmmoGive1, AmmoGive2; // Amount of each ammo to get when picking up weapon - int MinAmmo1, MinAmmo2; // Minimum ammo needed to switch to this weapon - int AmmoUse1, AmmoUse2; // How much ammo to use with each shot - int Kickback; - float YAdjust; // For viewing the weapon fullscreen (visual only so no need to be a double) - FSoundIDNoInit UpSound, ReadySound; // Sounds when coming up and idle - PClassWeapon *SisterWeaponType; // Another weapon to pick up with this one - PClassActor *ProjectileType; // Projectile used by primary attack - PClassActor *AltProjectileType; // Projectile used by alternate attack - int SelectionOrder; // Lower-numbered weapons get picked first - int MinSelAmmo1, MinSelAmmo2; // Ignore in BestWeapon() if inadequate ammo - double MoveCombatDist; // Used by bots, but do they *really* need it? - int ReloadCounter; // For A_CheckForReload - int BobStyle; // [XA] Bobbing style. Defines type of bobbing (e.g. Normal, Alpha) (visual only so no need to be a double) - float BobSpeed; // [XA] Bobbing speed. Defines how quickly a weapon bobs. - float BobRangeX, BobRangeY; // [XA] Bobbing range. Defines how far a weapon bobs in either direction. - - // In-inventory instance variables - TObjPtr Ammo1, Ammo2; - TObjPtr SisterWeapon; - float FOVScale; - int Crosshair; // 0 to use player's crosshair - bool GivenAsMorphWeapon; - - bool bAltFire; // Set when this weapon's alternate fire is used. - - virtual void MarkPrecacheSounds() const; - - virtual void Serialize(FSerializer &arc); - virtual bool ShouldStay (); - virtual void AttachToOwner (AActor *other); - virtual bool HandlePickup (AInventory *item); - virtual AInventory *CreateCopy (AActor *other); - virtual AInventory *CreateTossable (); - virtual bool TryPickup (AActor *&toucher); - virtual bool TryPickupRestricted (AActor *&toucher); - virtual bool PickupForAmmo (AWeapon *ownedWeapon); - virtual bool Use (bool pickup); - virtual void Destroy(); - - virtual FState *GetUpState (); - virtual FState *GetDownState (); - virtual FState *GetReadyState (); - virtual FState *GetAtkState (bool hold); - virtual FState *GetAltAtkState (bool hold); - virtual FState *GetStateForButtonName (FName button); - - virtual void PostMorphWeapon (); - virtual void EndPowerup (); - - enum - { - PrimaryFire, - AltFire, - EitherFire - }; - bool CheckAmmo (int fireMode, bool autoSwitch, bool requireAmmo=false, int ammocount = -1); - bool DepleteAmmo (bool altFire, bool checkEnough=true, int ammouse = -1); - - enum - { - BobNormal, - BobInverse, - BobAlpha, - BobInverseAlpha, - BobSmooth, - BobInverseSmooth - }; - -protected: - AAmmo *AddAmmo (AActor *other, PClassActor *ammotype, int amount); - bool AddExistingAmmo (AAmmo *ammo, int amount); - AWeapon *AddWeapon (PClassWeapon *weapon); -}; - -enum -{ - WIF_NOAUTOFIRE = 0x00000001, // weapon does not autofire - WIF_READYSNDHALF = 0x00000002, // ready sound is played ~1/2 the time - WIF_DONTBOB = 0x00000004, // don't bob the weapon - WIF_AXEBLOOD = 0x00000008, // weapon makes axe blood on impact (Hexen only) - WIF_NOALERT = 0x00000010, // weapon does not alert monsters - WIF_AMMO_OPTIONAL = 0x00000020, // weapon can use ammo but does not require it - WIF_ALT_AMMO_OPTIONAL = 0x00000040, // alternate fire can use ammo but does not require it - WIF_PRIMARY_USES_BOTH = 0x00000080, // primary fire uses both ammo - WIF_ALT_USES_BOTH = 0x00000100, // alternate fire uses both ammo - WIF_WIMPY_WEAPON = 0x00000200, // change away when ammo for another weapon is replenished - WIF_POWERED_UP = 0x00000400, // this is a tome-of-power'ed version of its sister - WIF_AMMO_CHECKBOTH = 0x00000800, // check for both primary and secondary fire before switching it off - WIF_NO_AUTO_SWITCH = 0x00001000, // never switch to this weapon when it's picked up - WIF_STAFF2_KICKBACK = 0x00002000, // the powered-up Heretic staff has special kickback - WIF_NOAUTOAIM = 0x00004000, // this weapon never uses autoaim (useful for ballistic projectiles) - WIF_MELEEWEAPON = 0x00008000, // melee weapon. Used by bots and monster AI. - WIF_DEHAMMO = 0x00010000, // Uses Doom's original amount of ammo for the respective attack functions so that old DEHACKED patches work as intended. - // AmmoUse1 will be set to the first attack's ammo use so that checking for empty weapons still works - WIF_NODEATHDESELECT = 0x00020000, // Don't jump to the Deselect state when the player dies - WIF_NODEATHINPUT = 0x00040000, // The weapon cannot be fired/reloaded/whatever when the player is dead - WIF_CHEATNOTWEAPON = 0x08000000, // Give cheat considers this not a weapon (used by Sigil) - - // Flags used only by bot AI: - - WIF_BOT_REACTION_SKILL_THING = 1<<31, // I don't understand this - WIF_BOT_EXPLOSIVE = 1<<30, // weapon fires an explosive - WIF_BOT_BFG = 1<<28, // this is a BFG -}; - -class AWeaponGiver : public AWeapon -{ - DECLARE_CLASS(AWeaponGiver, AWeapon) - -public: - bool TryPickup(AActor *&toucher); - - void Serialize(FSerializer &arc); - - double DropAmmoFactor; -}; - - -// Health is some item that gives the player health when picked up. -class PClassHealth : public PClassInventory -{ - DECLARE_CLASS(PClassHealth, PClassInventory) -protected: -public: - PClassHealth(); - virtual void DeriveData(PClass *newclass); - - FString LowHealthMessage; - int LowHealth; -}; - -class AHealth : public AInventory -{ - DECLARE_CLASS_WITH_META(AHealth, AInventory, PClassHealth) - - int PrevHealth; -public: - virtual bool TryPickup (AActor *&other); - virtual const char *PickupMessage (); -}; - -// HealthPickup is some item that gives the player health when used. -class AHealthPickup : public AInventory -{ - DECLARE_CLASS (AHealthPickup, AInventory) -public: - int autousemode; - - - virtual void Serialize(FSerializer &arc); - virtual AInventory *CreateCopy (AActor *other); - virtual AInventory *CreateTossable (); - virtual bool HandlePickup (AInventory *item); - virtual bool Use (bool pickup); -}; - -// Armor absorbs some damage for the player. -class AArmor : public AInventory -{ - DECLARE_CLASS (AArmor, AInventory) -}; - -// Basic armor absorbs a specific percent of the damage. You should -// never pickup a BasicArmor. Instead, you pickup a BasicArmorPickup -// or BasicArmorBonus and those gives you BasicArmor when it activates. -class ABasicArmor : public AArmor -{ - DECLARE_CLASS (ABasicArmor, AArmor) -public: - - virtual void Serialize(FSerializer &arc); - virtual void Tick (); - virtual AInventory *CreateCopy (AActor *other); - virtual bool HandlePickup (AInventory *item); - virtual void AbsorbDamage (int damage, FName damageType, int &newdamage); - - int AbsorbCount; - double SavePercent; - int MaxAbsorb; - int MaxFullAbsorb; - int BonusCount; - FNameNoInit ArmorType; - int ActualSaveAmount; -}; - -// BasicArmorPickup replaces the armor you have. -class ABasicArmorPickup : public AArmor -{ - DECLARE_CLASS (ABasicArmorPickup, AArmor) -public: - - virtual void Serialize(FSerializer &arc); - virtual AInventory *CreateCopy (AActor *other); - virtual bool Use (bool pickup); - - double SavePercent; - int MaxAbsorb; - int MaxFullAbsorb; - int SaveAmount; -}; - -// BasicArmorBonus adds to the armor you have. -class ABasicArmorBonus : public AArmor -{ - DECLARE_CLASS (ABasicArmorBonus, AArmor) -public: - - virtual void Serialize(FSerializer &arc); - virtual AInventory *CreateCopy (AActor *other); - virtual bool Use (bool pickup); - - double SavePercent; // The default, for when you don't already have armor - int MaxSaveAmount; - int MaxAbsorb; - int MaxFullAbsorb; - int SaveAmount; - int BonusCount; - int BonusMax; -}; - -// Hexen armor consists of four separate armor types plus a conceptual armor -// type (the player himself) that work together as a single armor. -class AHexenArmor : public AArmor -{ - DECLARE_CLASS (AHexenArmor, AArmor) -public: - - virtual void Serialize(FSerializer &arc); - virtual AInventory *CreateCopy (AActor *other); - virtual AInventory *CreateTossable (); - virtual bool HandlePickup (AInventory *item); - virtual void AbsorbDamage (int damage, FName damageType, int &newdamage); - void DepleteOrDestroy(); - - double Slots[5]; - double SlotsIncrement[4]; - -protected: - bool AddArmorToSlot (AActor *actor, int slot, int amount); -}; - -// PuzzleItems work in conjunction with the UsePuzzleItem special -class PClassPuzzleItem : public PClassInventory -{ - DECLARE_CLASS(PClassPuzzleItem, PClassInventory); -protected: -public: - virtual void DeriveData(PClass *newclass); - FString PuzzFailMessage; -}; - -class APuzzleItem : public AInventory -{ - DECLARE_CLASS_WITH_META(APuzzleItem, AInventory, PClassPuzzleItem) -public: - - bool ShouldStay (); - bool Use (bool pickup); - bool HandlePickup (AInventory *item); - - int PuzzleItemNumber; -}; - -// A MapRevealer reveals the whole map for the player who picks it up. -class AMapRevealer : public AInventory -{ - DECLARE_CLASS (AMapRevealer, AInventory) -public: - bool TryPickup (AActor *&toucher); -}; - -// A backpack gives you one clip of each ammo and doubles your -// normal maximum ammo amounts. -class ABackpackItem : public AInventory -{ - DECLARE_CLASS (ABackpackItem, AInventory) -public: - - void Serialize(FSerializer &arc); - bool HandlePickup (AInventory *item); - AInventory *CreateCopy (AActor *other); - AInventory *CreateTossable (); - void DetachFromOwner (); - - bool bDepleted; -}; - - -// A score item is picked up without being added to the inventory. -// It differs from FakeInventory by doing nothing more than increasing the player's score. -class AScoreItem : public AInventory -{ - DECLARE_CLASS (AScoreItem, AInventory) - -public: - bool TryPickup(AActor *&toucher); -}; - - -#endif //__A_PICKUPS_H__ diff --git a/src/g_shared/a_puzzleitems.cpp b/src/g_shared/a_puzzleitems.cpp deleted file mode 100644 index 233066edc7..0000000000 --- a/src/g_shared/a_puzzleitems.cpp +++ /dev/null @@ -1,54 +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 "c_console.h" -#include "doomstat.h" -#include "v_font.h" - -IMPLEMENT_CLASS(PClassPuzzleItem) - -void PClassPuzzleItem::DeriveData(PClass *newclass) -{ - Super::DeriveData(newclass); - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassPuzzleItem))); - static_cast(newclass)->PuzzFailMessage = PuzzFailMessage; -} - -IMPLEMENT_CLASS(APuzzleItem) - -bool APuzzleItem::HandlePickup (AInventory *item) -{ - // Can't carry more than 1 of each puzzle item in coop netplay - if (multiplayer && !deathmatch && item->GetClass() == GetClass()) - { - return true; - } - return Super::HandlePickup (item); -} - -bool APuzzleItem::Use (bool pickup) -{ - if (P_UsePuzzleItem (Owner, PuzzleItemNumber)) - { - return true; - } - // [RH] Always play the sound if the use fails. - S_Sound (Owner, CHAN_VOICE, "*puzzfail", 1, ATTN_IDLE); - if (Owner != NULL && Owner->CheckLocalView (consoleplayer)) - { - FString message = GetClass()->PuzzFailMessage; - if (message.IsNotEmpty() && message[0] == '$') message = GStrings[&message[1]]; - if (message.IsEmpty()) message = GStrings("TXT_USEPUZZLEFAILED"); - C_MidPrintBold (SmallFont, message); - } - return false; -} - -bool APuzzleItem::ShouldStay () -{ - return !!multiplayer; -} - diff --git a/src/g_shared/a_quake.cpp b/src/g_shared/a_quake.cpp index 98e505b2b9..96a932d4f4 100644 --- a/src/g_shared/a_quake.cpp +++ b/src/g_shared/a_quake.cpp @@ -14,9 +14,11 @@ static FRandom pr_quake ("Quake"); -IMPLEMENT_POINTY_CLASS (DEarthquake) - DECLARE_POINTER (m_Spot) -END_POINTERS +IMPLEMENT_CLASS(DEarthquake, false, true) + +IMPLEMENT_POINTERS_START(DEarthquake) + IMPLEMENT_POINTER(m_Spot) +IMPLEMENT_POINTERS_END //========================================================================== // diff --git a/src/g_shared/a_randomspawner.cpp b/src/g_shared/a_randomspawner.cpp index ac162a2417..d5a396d0d9 100644 --- a/src/g_shared/a_randomspawner.cpp +++ b/src/g_shared/a_randomspawner.cpp @@ -13,8 +13,6 @@ #include "s_sound.h" #include "statnums.h" #include "gstrings.h" -#include "a_action.h" -#include "thingdef/thingdef.h" #include "v_text.h" #include "doomstat.h" #include "doomdata.h" @@ -231,4 +229,4 @@ class ARandomSpawner : public AActor }; -IMPLEMENT_CLASS (ARandomSpawner) +IMPLEMENT_CLASS(ARandomSpawner, false, false) diff --git a/src/g_shared/a_secrettrigger.cpp b/src/g_shared/a_secrettrigger.cpp deleted file mode 100644 index 286ea50113..0000000000 --- a/src/g_shared/a_secrettrigger.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* -** a_secrettrigger.cpp -** A thing that counts toward the secret count when activated -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ - -#include "actor.h" -#include "g_level.h" -#include "c_console.h" -#include "info.h" -#include "s_sound.h" -#include "d_player.h" -#include "doomstat.h" -#include "v_font.h" -#include "p_spec.h" - -class ASecretTrigger : public AActor -{ - DECLARE_CLASS (ASecretTrigger, AActor) -public: - void PostBeginPlay (); - void Activate (AActor *activator); -}; - -IMPLEMENT_CLASS (ASecretTrigger) - -void ASecretTrigger::PostBeginPlay () -{ - Super::PostBeginPlay (); - level.total_secrets++; -} - -void ASecretTrigger::Activate (AActor *activator) -{ - P_GiveSecret(activator, args[0] <= 1, (args[0] == 0 || args[0] == 2), -1); - Destroy (); -} - diff --git a/src/g_shared/a_sectoraction.cpp b/src/g_shared/a_sectoraction.cpp index 38435e16be..2d70375510 100644 --- a/src/g_shared/a_sectoraction.cpp +++ b/src/g_shared/a_sectoraction.cpp @@ -37,7 +37,7 @@ // The base class for sector actions ---------------------------------------- -IMPLEMENT_CLASS (ASectorAction) +IMPLEMENT_CLASS(ASectorAction, false, false) ASectorAction::ASectorAction (bool activatedByUse) : ActivatedByUse (activatedByUse) {} @@ -142,7 +142,7 @@ public: bool DoTriggerAction (AActor *triggerer, int activationType); }; -IMPLEMENT_CLASS (ASecActEnter) +IMPLEMENT_CLASS(ASecActEnter, false, false) bool ASecActEnter::DoTriggerAction (AActor *triggerer, int activationType) @@ -160,7 +160,7 @@ public: bool DoTriggerAction (AActor *triggerer, int activationType); }; -IMPLEMENT_CLASS (ASecActExit) +IMPLEMENT_CLASS(ASecActExit, false, false) bool ASecActExit::DoTriggerAction (AActor *triggerer, int activationType) @@ -180,7 +180,8 @@ public: // Skull Tag uses 9999 for a special that is triggered whenever // the player is on the sector's floor. I think this is more useful. -IMPLEMENT_CLASS (ASecActHitFloor) + +IMPLEMENT_CLASS(ASecActHitFloor, false, false) bool ASecActHitFloor::DoTriggerAction (AActor *triggerer, int activationType) @@ -198,7 +199,7 @@ public: bool DoTriggerAction (AActor *triggerer, int activationType); }; -IMPLEMENT_CLASS (ASecActHitCeil) +IMPLEMENT_CLASS(ASecActHitCeil, false, false) bool ASecActHitCeil::DoTriggerAction (AActor *triggerer, int activationType) @@ -217,7 +218,7 @@ public: bool DoTriggerAction (AActor *triggerer, int activationType); }; -IMPLEMENT_CLASS (ASecActUse) +IMPLEMENT_CLASS(ASecActUse, false, false) bool ASecActUse::DoTriggerAction (AActor *triggerer, int activationType) @@ -236,7 +237,7 @@ public: bool DoTriggerAction (AActor *triggerer, int activationType); }; -IMPLEMENT_CLASS (ASecActUseWall) +IMPLEMENT_CLASS(ASecActUseWall, false, false) bool ASecActUseWall::DoTriggerAction (AActor *triggerer, int activationType) @@ -254,7 +255,7 @@ public: bool DoTriggerAction (AActor *triggerer, int activationType); }; -IMPLEMENT_CLASS (ASecActEyesDive) +IMPLEMENT_CLASS(ASecActEyesDive, false, false) bool ASecActEyesDive::DoTriggerAction (AActor *triggerer, int activationType) @@ -272,7 +273,7 @@ public: bool DoTriggerAction (AActor *triggerer, int activationType); }; -IMPLEMENT_CLASS (ASecActEyesSurface) +IMPLEMENT_CLASS(ASecActEyesSurface, false, false) bool ASecActEyesSurface::DoTriggerAction (AActor *triggerer, int activationType) @@ -290,7 +291,7 @@ public: bool DoTriggerAction (AActor *triggerer, int activationType); }; -IMPLEMENT_CLASS (ASecActEyesBelowC) +IMPLEMENT_CLASS(ASecActEyesBelowC, false, false) bool ASecActEyesBelowC::DoTriggerAction (AActor *triggerer, int activationType) @@ -308,7 +309,7 @@ public: bool DoTriggerAction (AActor *triggerer, int activationType); }; -IMPLEMENT_CLASS (ASecActEyesAboveC) +IMPLEMENT_CLASS(ASecActEyesAboveC, false, false) bool ASecActEyesAboveC::DoTriggerAction (AActor *triggerer, int activationType) @@ -326,7 +327,7 @@ public: bool DoTriggerAction (AActor *triggerer, int activationType); }; -IMPLEMENT_CLASS (ASecActHitFakeFloor) +IMPLEMENT_CLASS(ASecActHitFakeFloor, false, false) bool ASecActHitFakeFloor::DoTriggerAction (AActor *triggerer, int activationType) diff --git a/src/g_shared/a_setcolor.cpp b/src/g_shared/a_setcolor.cpp deleted file mode 100644 index 4e27257560..0000000000 --- a/src/g_shared/a_setcolor.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "r_defs.h" -#include "actor.h" -#include "info.h" - -class AColorSetter : public AActor -{ - DECLARE_CLASS(AColorSetter, AActor) - - void PostBeginPlay() - { - Super::PostBeginPlay(); - Sector->SetColor(args[0], args[1], args[2], args[3]); - Destroy(); - } - -}; - -IMPLEMENT_CLASS(AColorSetter) - -class AFadeSetter : public AActor -{ - DECLARE_CLASS(AFadeSetter, AActor) - - void PostBeginPlay() - { - Super::PostBeginPlay(); - Sector->SetFade(args[0], args[1], args[2]); - Destroy(); - } - -}; - -IMPLEMENT_CLASS(AFadeSetter) diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index c00cd8cf0c..001df5488e 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -10,7 +10,6 @@ struct side_t; struct F3DFloor; class DBaseDecal; -void P_SpawnDirt (AActor *actor, double radius); class DBaseDecal *ShootDecal(const FDecalTemplate *tpl, AActor *basisactor, sector_t *sec, double x, double y, double z, DAngle angle, double tracedist, bool permanent); class DBaseDecal : public DThinker @@ -25,7 +24,7 @@ public: DBaseDecal (const DBaseDecal *basis); void Serialize(FSerializer &arc); - void Destroy (); + void Destroy() override; FTextureID StickToWall(side_t *wall, double x, double y, F3DFloor * ffloor); double GetRealZ (const side_t *wall) const; void SetShade (DWORD rgb); @@ -67,7 +66,7 @@ public: static DImpactDecal *StaticCreate(const FDecalTemplate *tpl, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color = 0); void BeginPlay (); - void Destroy (); + void Destroy() override; protected: DBaseDecal *CloneSelf(const FDecalTemplate *tpl, double x, double y, double z, side_t *wall, F3DFloor * ffloor) const; @@ -89,7 +88,7 @@ class ASkyViewpoint : public AActor DECLARE_CLASS (ASkyViewpoint, AActor) public: void BeginPlay (); - void Destroy (); + void Destroy() override; }; // For an EE compatible linedef based definition. @@ -117,7 +116,7 @@ public: DFlashFader (float r1, float g1, float b1, float a1, float r2, float g2, float b2, float a2, float time, AActor *who); - void Destroy (); + void Destroy() override; void Serialize(FSerializer &arc); void Tick (); AActor *WhoFor() { return ForWho; } @@ -188,12 +187,14 @@ private: class AMorphProjectile : public AActor { DECLARE_CLASS (AMorphProjectile, AActor) + HAS_OBJECT_POINTERS; public: int DoSpecialDamage (AActor *target, int damage, FName damagetype); void Serialize(FSerializer &arc); - FNameNoInit PlayerClass, MonsterClass, MorphFlash, UnMorphFlash; + PClassPlayerPawn *PlayerClass; + PClassActor *MonsterClass, *MorphFlash, *UnMorphFlash; int Duration, MorphStyle; }; @@ -206,7 +207,7 @@ public: void Serialize(FSerializer &arc); void Die (AActor *source, AActor *inflictor, int dmgflags); - void Destroy (); + void Destroy() override; TObjPtr UnmorphedMe; int UnmorphTime, MorphStyle; @@ -214,21 +215,11 @@ public: ActorFlags FlagsSave; }; -class AMapMarker : public AActor -{ - DECLARE_CLASS(AMapMarker, AActor) -public: - void BeginPlay (); - void Activate (AActor *activator); - void Deactivate (AActor *activator); -}; - class AFastProjectile : public AActor { DECLARE_CLASS(AFastProjectile, AActor) public: void Tick (); - virtual void Effect(); }; diff --git a/src/g_shared/a_skies.cpp b/src/g_shared/a_skies.cpp index 89c785e3ef..9e99d9368e 100644 --- a/src/g_shared/a_skies.cpp +++ b/src/g_shared/a_skies.cpp @@ -42,7 +42,7 @@ // arg0 = Visibility*4 for this skybox -IMPLEMENT_CLASS (ASkyViewpoint) +IMPLEMENT_CLASS(ASkyViewpoint, false, false) // If this actor has no TID, make it the default sky box void ASkyViewpoint::BeginPlay () @@ -73,7 +73,7 @@ void ASkyViewpoint::Destroy () Super::Destroy(); } -IMPLEMENT_CLASS (ASkyCamCompat) +IMPLEMENT_CLASS(ASkyCamCompat, false, false) void ASkyCamCompat::BeginPlay() { @@ -98,7 +98,7 @@ public: void PostBeginPlay (); }; -IMPLEMENT_CLASS (ASkyPicker) +IMPLEMENT_CLASS(ASkyPicker, false, false) void ASkyPicker::PostBeginPlay () { @@ -142,7 +142,7 @@ void ASkyPicker::PostBeginPlay () // arg0 = opacity of plane; 0 = invisible, 255 = fully opaque -IMPLEMENT_CLASS (AStackPoint) +IMPLEMENT_CLASS(AStackPoint, false, false) void AStackPoint::BeginPlay () { @@ -157,10 +157,10 @@ class ASectorSilencer : public AActor DECLARE_CLASS (ASectorSilencer, AActor) public: void BeginPlay (); - void Destroy (); + void Destroy() override; }; -IMPLEMENT_CLASS (ASectorSilencer) +IMPLEMENT_CLASS(ASectorSilencer, false, false) void ASectorSilencer::BeginPlay () { @@ -177,18 +177,3 @@ void ASectorSilencer::Destroy () Super::Destroy (); } -class ASectorFlagSetter : public AActor -{ - DECLARE_CLASS (ASectorFlagSetter, AActor) -public: - void BeginPlay (); -}; - -IMPLEMENT_CLASS (ASectorFlagSetter) - -void ASectorFlagSetter::BeginPlay () -{ - Super::BeginPlay (); - Sector->Flags |= args[0]; -} - diff --git a/src/g_shared/a_soundenvironment.cpp b/src/g_shared/a_soundenvironment.cpp index ba01711573..25088ae448 100644 --- a/src/g_shared/a_soundenvironment.cpp +++ b/src/g_shared/a_soundenvironment.cpp @@ -46,14 +46,14 @@ public: void Activate (AActor *deactivator); }; -IMPLEMENT_CLASS (ASoundEnvironment) +IMPLEMENT_CLASS(ASoundEnvironment, false, false) void ASoundEnvironment::PostBeginPlay () { Super::PostBeginPlay (); if (!(flags2 & MF2_DORMANT)) { - Activate (this); + CallActivate (this); } } diff --git a/src/g_shared/a_soundsequence.cpp b/src/g_shared/a_soundsequence.cpp index f09b5b7adc..304017fbad 100644 --- a/src/g_shared/a_soundsequence.cpp +++ b/src/g_shared/a_soundsequence.cpp @@ -80,9 +80,11 @@ public: TObjPtr Sequence; }; -IMPLEMENT_POINTY_CLASS(ASoundSequenceSlot) - DECLARE_POINTER(Sequence) -END_POINTERS +IMPLEMENT_CLASS(ASoundSequenceSlot, false, true) + +IMPLEMENT_POINTERS_START(ASoundSequenceSlot) + IMPLEMENT_POINTER(Sequence) +IMPLEMENT_POINTERS_END //========================================================================== // @@ -102,14 +104,14 @@ class ASoundSequence : public AActor { DECLARE_CLASS (ASoundSequence, AActor) public: - void Destroy (); + void Destroy() override; void PostBeginPlay (); void Activate (AActor *activator); void Deactivate (AActor *activator); void MarkPrecacheSounds () const; }; -IMPLEMENT_CLASS (ASoundSequence) +IMPLEMENT_CLASS(ASoundSequence, false, false) //========================================================================== // diff --git a/src/g_shared/a_spark.cpp b/src/g_shared/a_spark.cpp deleted file mode 100644 index 4bc9dc4c48..0000000000 --- a/src/g_shared/a_spark.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* -** a_spark.cpp -** Actor that makes a particle spark when activated -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ - -#include "actor.h" -#include "info.h" -#include "m_random.h" -#include "p_effect.h" -#include "s_sound.h" - -class ASpark : public AActor -{ - DECLARE_CLASS (ASpark, AActor) -public: - void Activate (AActor *activator); -}; - -IMPLEMENT_CLASS (ASpark) - -void ASpark::Activate (AActor *activator) -{ - Super::Activate (activator); - P_DrawSplash (args[0] ? args[0] : 32, Pos(), Angles.Yaw, 1); - S_Sound (this, CHAN_AUTO, "world/spark", 1, ATTN_STATIC); -} diff --git a/src/g_shared/a_specialspot.cpp b/src/g_shared/a_specialspot.cpp index 1d8d1f72d5..335f10aced 100644 --- a/src/g_shared/a_specialspot.cpp +++ b/src/g_shared/a_specialspot.cpp @@ -37,7 +37,6 @@ #include "p_local.h" #include "statnums.h" #include "i_system.h" -#include "thingdef/thingdef.h" #include "doomstat.h" #include "serializer.h" #include "a_pickups.h" @@ -45,9 +44,8 @@ static FRandom pr_spot ("SpecialSpot"); static FRandom pr_spawnmace ("SpawnMace"); - -IMPLEMENT_CLASS(DSpotState) -IMPLEMENT_CLASS (ASpecialSpot) +IMPLEMENT_CLASS(DSpotState, false, false) +IMPLEMENT_CLASS(ASpecialSpot, false, false) TObjPtr DSpotState::SpotState; //---------------------------------------------------------------------------- @@ -253,6 +251,12 @@ DSpotState *DSpotState::GetSpotState(bool create) return SpotState; } +DEFINE_ACTION_FUNCTION(DSpotState, GetSpotState) +{ + PARAM_PROLOGUE; + ACTION_RETURN_OBJECT(DSpotState::GetSpotState()); +} + //---------------------------------------------------------------------------- // // @@ -261,6 +265,7 @@ DSpotState *DSpotState::GetSpotState(bool create) FSpotList *DSpotState::FindSpotList(PClassActor *type) { + if (type == nullptr) return nullptr; for(unsigned i = 0; i < SpotLists.Size(); i++) { if (SpotLists[i].Type == type) return &SpotLists[i]; @@ -319,6 +324,14 @@ ASpecialSpot *DSpotState::GetNextInList(PClassActor *type, int skipcounter) return NULL; } +DEFINE_ACTION_FUNCTION(DSpotState, GetNextInList) +{ + PARAM_SELF_PROLOGUE(DSpotState); + PARAM_CLASS(type, AActor); + PARAM_INT(skipcounter); + ACTION_RETURN_OBJECT(self->GetNextInList(type, skipcounter)); +} + //---------------------------------------------------------------------------- // // @@ -332,6 +345,18 @@ ASpecialSpot *DSpotState::GetSpotWithMinMaxDistance(PClassActor *type, double x, return NULL; } +DEFINE_ACTION_FUNCTION(DSpotState, GetSpotWithMinMaxDistance) +{ + PARAM_SELF_PROLOGUE(DSpotState); + PARAM_CLASS(type, AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(mindist); + PARAM_FLOAT(maxdist); + ACTION_RETURN_OBJECT(self->GetSpotWithMinMaxDistance(type, x, y, mindist, maxdist)); +} + + //---------------------------------------------------------------------------- // // @@ -373,18 +398,17 @@ void ASpecialSpot::Destroy() // Mace spawn spot ---------------------------------------------------------- - // Every mace spawn spot will execute this action. The first one // will build a list of all mace spots in the level and spawn a // mace. The rest of the spots will do nothing. -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnSingleItem) +DEFINE_ACTION_FUNCTION(ASpecialSpot, A_SpawnSingleItem) { - PARAM_ACTION_PROLOGUE; - PARAM_CLASS (cls, AActor); - PARAM_INT_OPT (fail_sp) { fail_sp = 0; } - PARAM_INT_OPT (fail_co) { fail_co = 0; } - PARAM_INT_OPT (fail_dm) { fail_dm = 0; } + PARAM_SELF_PROLOGUE(ASpecialSpot); + PARAM_CLASS_NOT_NULL(cls, AActor); + PARAM_INT_DEF (fail_sp) + PARAM_INT_DEF (fail_co) + PARAM_INT_DEF (fail_dm) AActor *spot = NULL; DSpotState *state = DSpotState::GetSpotState(); diff --git a/src/g_shared/a_specialspot.h b/src/g_shared/a_specialspot.h index 8fe38608aa..57a643bdd8 100644 --- a/src/g_shared/a_specialspot.h +++ b/src/g_shared/a_specialspot.h @@ -11,7 +11,7 @@ class ASpecialSpot : public AActor public: void BeginPlay(); - void Destroy(); + void Destroy() override; }; @@ -28,7 +28,7 @@ public: DSpotState (); - void Destroy (); + void Destroy() override; void Tick (); static DSpotState *GetSpotState(bool create = true); FSpotList *FindSpotList(PClassActor *type); diff --git a/src/g_shared/a_waterzone.cpp b/src/g_shared/a_waterzone.cpp deleted file mode 100644 index 50fc6825b1..0000000000 --- a/src/g_shared/a_waterzone.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* -** a_waterzone.cpp -** Actor that makes BOOM deep water swimmable -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ - -#include "info.h" -#include "r_defs.h" - -class AWaterZone : public AActor -{ - DECLARE_CLASS (AWaterZone, AActor) -public: - void PostBeginPlay (); -}; - -IMPLEMENT_CLASS (AWaterZone) - -void AWaterZone::PostBeginPlay () -{ - Super::PostBeginPlay (); - Sector->MoreFlags |= SECF_UNDERWATER; - Destroy (); -} - diff --git a/src/g_shared/a_weaponpiece.h b/src/g_shared/a_weaponpiece.h deleted file mode 100644 index 88f3da02c7..0000000000 --- a/src/g_shared/a_weaponpiece.h +++ /dev/null @@ -1,43 +0,0 @@ - -// -class PClassWeaponPiece : public PClassInventory -{ - DECLARE_CLASS(PClassWeaponPiece, PClassInventory) -protected: -public: - virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); -}; - -class AWeaponPiece : public AInventory -{ - DECLARE_CLASS_WITH_META(AWeaponPiece, AInventory, PClassWeaponPiece) - HAS_OBJECT_POINTERS -protected: - bool PrivateShouldStay (); -public: - - void Serialize(FSerializer &arc); - bool TryPickup (AActor *&toucher); - bool TryPickupRestricted (AActor *&toucher); - bool ShouldStay (); - virtual const char *PickupMessage (); - virtual void PlayPickupSound (AActor *toucher); - - int PieceValue; - PClassActor *WeaponClass; - TObjPtr FullWeapon; -}; - -// an internal class to hold the information for player class independent weapon piece handling -// [BL] Needs to be available for SBarInfo to check weaponpieces -class AWeaponHolder : public AInventory -{ - DECLARE_CLASS(AWeaponHolder, AInventory) - -public: - int PieceMask; - PClassActor * PieceWeapon; - - - void Serialize(FSerializer &arc); -}; diff --git a/src/g_shared/hudmessages.cpp b/src/g_shared/hudmessages.cpp index b86cf64175..0db6d4743a 100644 --- a/src/g_shared/hudmessages.cpp +++ b/src/g_shared/hudmessages.cpp @@ -44,13 +44,15 @@ EXTERN_CVAR(Int, con_scaletext) int active_con_scaletext(); -IMPLEMENT_POINTY_CLASS (DHUDMessage) - DECLARE_POINTER(Next) -END_POINTERS +IMPLEMENT_CLASS(DHUDMessage, false, true) -IMPLEMENT_CLASS (DHUDMessageFadeOut) -IMPLEMENT_CLASS (DHUDMessageFadeInOut) -IMPLEMENT_CLASS (DHUDMessageTypeOnFadeOut) +IMPLEMENT_POINTERS_START(DHUDMessage) + IMPLEMENT_POINTER(Next) +IMPLEMENT_POINTERS_END + +IMPLEMENT_CLASS(DHUDMessageFadeOut, false, false) +IMPLEMENT_CLASS(DHUDMessageFadeInOut, false, false) +IMPLEMENT_CLASS(DHUDMessageTypeOnFadeOut, false, false) /************************************************************************* * Basic HUD message. Appears and disappears without any special effects * diff --git a/src/g_shared/sbar.h b/src/g_shared/sbar.h index 6d5b107394..7b7a2849ae 100644 --- a/src/g_shared/sbar.h +++ b/src/g_shared/sbar.h @@ -341,7 +341,7 @@ public: }; DBaseStatusBar (int reltop, int hres=320, int vres=200); - void Destroy (); + void Destroy() override; void SetScaled (bool scale, bool force=false); diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index 42f28173c8..8ca8d68163 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -45,18 +45,21 @@ #include "st_stuff.h" #include "m_swap.h" #include "a_keys.h" +#include "a_armor.h" #include "templates.h" #include "i_system.h" #include "sbarinfo.h" #include "gi.h" #include "r_data/r_translate.h" +#include "a_artifacts.h" #include "a_weaponpiece.h" -#include "a_strifeglobal.h" #include "g_level.h" #include "v_palette.h" #include "p_acs.h" #include "gstrings.h" #include "version.h" +#include "cmdlib.h" +#include "a_ammo.h" #define ARTIFLASH_OFFSET (statusBar->invBarOffset+6) enum @@ -1530,11 +1533,13 @@ private: SBarInfoMainBlock *lastPopup; }; -IMPLEMENT_POINTY_CLASS(DSBarInfo) - DECLARE_POINTER(ammo1) - DECLARE_POINTER(ammo2) - DECLARE_POINTER(armor) -END_POINTERS +IMPLEMENT_CLASS(DSBarInfo, false, true) + +IMPLEMENT_POINTERS_START(DSBarInfo) + IMPLEMENT_POINTER(ammo1) + IMPLEMENT_POINTER(ammo2) + IMPLEMENT_POINTER(armor) +IMPLEMENT_POINTERS_END DBaseStatusBar *CreateCustomStatusBar (int script) { diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index b3aecb0b54..f78c610404 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -268,7 +268,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl } else if(type == SIGIL) { - AInventory *item = statusBar->CPlayer->mo->FindInventory(); + AInventory *item = statusBar->CPlayer->mo->FindInventory(PClass::FindActor(NAME_Sigil)); if (item != NULL) texture = TexMan(item->Icon); } diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index c4d8ec1ede..a061dbf59a 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -43,6 +43,8 @@ #include "c_cvars.h" #include "w_wad.h" #include "a_keys.h" +#include "a_armor.h" +#include "a_ammo.h" #include "sbar.h" #include "sc_man.h" #include "templates.h" @@ -52,6 +54,7 @@ #include "d_net.h" #include "d_player.h" #include "r_utility.h" +#include "cmdlib.h" #include diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index 5e76b422f2..c288a05c86 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -54,6 +54,7 @@ #include "serializer.h" #include "gstrings.h" #include "r_utility.h" +#include "cmdlib.h" #include "../version.h" @@ -61,11 +62,13 @@ #define XHAIRPICKUPSIZE (2+XHAIRSHRINKSIZE) #define POWERUPICONSIZE 32 -IMPLEMENT_POINTY_CLASS(DBaseStatusBar) - DECLARE_POINTER(Messages[0]) - DECLARE_POINTER(Messages[1]) - DECLARE_POINTER(Messages[2]) -END_POINTERS +IMPLEMENT_CLASS(DBaseStatusBar, false, true) + +IMPLEMENT_POINTERS_START(DBaseStatusBar) + IMPLEMENT_POINTER(Messages[0]) + IMPLEMENT_POINTER(Messages[1]) + IMPLEMENT_POINTER(Messages[2]) +IMPLEMENT_POINTERS_END EXTERN_CVAR (Bool, am_showmonsters) EXTERN_CVAR (Bool, am_showsecrets) diff --git a/src/g_skill.cpp b/src/g_skill.cpp index 44c2cef8c7..70daadc23f 100644 --- a/src/g_skill.cpp +++ b/src/g_skill.cpp @@ -388,6 +388,13 @@ int G_SkillProperty(ESkillProperty prop) return 0; } +DEFINE_ACTION_FUNCTION(DObject, G_SkillPropertyInt) +{ + PARAM_PROLOGUE; + PARAM_INT(which); + ACTION_RETURN_INT(G_SkillProperty((ESkillProperty)which)); +} + //========================================================================== // // @@ -433,6 +440,13 @@ double G_SkillProperty(EFSkillProperty prop) return 0; } +DEFINE_ACTION_FUNCTION(DObject, G_SkillPropertyFloat) +{ + PARAM_PROLOGUE; + PARAM_INT(which); + ACTION_RETURN_FLOAT(G_SkillProperty((EFSkillProperty)which)); +} + //========================================================================== diff --git a/src/g_strife/a_acolyte.cpp b/src/g_strife/a_acolyte.cpp deleted file mode 100644 index e8049da1b8..0000000000 --- a/src/g_strife/a_acolyte.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* -#include "actor.h" -#include "m_random.h" -#include "a_action.h" -#include "p_local.h" -#include "p_enemy.h" -#include "s_sound.h" -#include "a_strifeglobal.h" -#include "doomdata.h" -#include "thingdef/thingdef.h" -#include "doomstat.h" -*/ - -//============================================================================ -// -// A_HideDecepticon -// -// Hide the Acolyte-to-be -> -// Hide the guy transforming into an Acolyte -> -// Hide the transformer -> -// Transformers are Autobots and Decepticons, and -// Decepticons are the bad guys, so... -> -// -// Hide the Decepticon! -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_HideDecepticon) -{ - PARAM_ACTION_PROLOGUE; - - EV_DoDoor (DDoor::doorClose, NULL, self, 999, 8., 0, 0, 0); - if (self->target != NULL && self->target->player != NULL) - { - P_NoiseAlert (self->target, self); - } - return 0; -} - -//============================================================================ -// -// A_AcolyteDie -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_AcolyteDie) -{ - PARAM_ACTION_PROLOGUE; - - int i; - - // [RH] Disable translucency here. - self->RenderStyle = STYLE_Normal; - - // Only the Blue Acolyte does extra stuff on death. - if (self->GetClass()->TypeName != NAME_AcolyteBlue) - return 0; - - // Make sure somebody is still alive - for (i = 0; i < MAXPLAYERS; ++i) - { - if (playeringame[i] && players[i].health > 0) - break; - } - if (i == MAXPLAYERS) - return 0; - - // Make sure all the other blue acolytes are dead. - TThinkerIterator iterator(NAME_AcolyteBlue); - AActor *other; - - while ( (other = iterator.Next ()) ) - { - if (other != self && other->health > 0) - { // Found a living one - return 0; - } - } - - players[i].mo->GiveInventoryType (QuestItemClasses[6]); - players[i].SetLogNumber (14); - S_StopSound (CHAN_VOICE); - S_Sound (CHAN_VOICE, "svox/voc14", 1, ATTN_NORM); - return 0; -} - -//============================================================================ -// -// A_BeShadowyFoe -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_BeShadowyFoe) -{ - PARAM_ACTION_PROLOGUE; - - self->RenderStyle = STYLE_Translucent; - self->Alpha = HR_SHADOW; - self->flags &= ~MF_FRIENDLY; - return 0; -} - -//============================================================================ -// -// A_AcolyteBits -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_AcolyteBits) -{ - PARAM_ACTION_PROLOGUE; - - if (self->SpawnFlags & MTF_SHADOW) - { - CALL_ACTION(A_BeShadowyFoe, self); - } - if (self->SpawnFlags & MTF_ALTSHADOW) - { - //self->flags |= MF_STRIFEx8000000; - if (self->flags & MF_SHADOW) - { - // I dunno. - } - else - { - self->RenderStyle.BlendOp = STYLEOP_None; - } - } - return 0; -} diff --git a/src/g_strife/a_alienspectres.cpp b/src/g_strife/a_alienspectres.cpp deleted file mode 100644 index a7624785b0..0000000000 --- a/src/g_strife/a_alienspectres.cpp +++ /dev/null @@ -1,201 +0,0 @@ -/* -#include "actor.h" -#include "m_random.h" -#include "a_action.h" -#include "p_local.h" -#include "p_enemy.h" -#include "s_sound.h" -#include "m_random.h" -#include "a_strifeglobal.h" -#include "c_console.h" -#include "gstrings.h" -#include "thingdef/thingdef.h" -#include "doomstat.h" -*/ - -static FRandom pr_spectrespawn ("AlienSpectreSpawn"); -static FRandom pr_spectrechunk ("212e4"); - -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SpectreChunkSmall) -{ - PARAM_ACTION_PROLOGUE; - - AActor *foo = Spawn("AlienChunkSmall", self->PosPlusZ(10.), ALLOW_REPLACE); - - if (foo != NULL) - { - int t; - - t = pr_spectrechunk() & 15; - foo->Vel.X = (t - (pr_spectrechunk() & 7)); - - t = pr_spectrechunk() & 15; - foo->Vel.Y = (t - (pr_spectrechunk() & 7)); - - foo->Vel.Z = (pr_spectrechunk() & 15); - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_SpectreChunkLarge) -{ - PARAM_ACTION_PROLOGUE; - - AActor *foo = Spawn("AlienChunkLarge", self->PosPlusZ(10.), ALLOW_REPLACE); - - if (foo != NULL) - { - int t; - - t = pr_spectrechunk() & 7; - foo->Vel.X = (t - (pr_spectrechunk() & 15)); - - t = pr_spectrechunk() & 7; - foo->Vel.Y = (t - (pr_spectrechunk() & 15)); - - foo->Vel.Z = (pr_spectrechunk() & 7); - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_Spectre3Attack) -{ - PARAM_ACTION_PROLOGUE; - - if (self->target == NULL) - return 0; - - AActor *foo = Spawn("SpectralLightningV2", self->PosPlusZ(32.), ALLOW_REPLACE); - - foo->Vel.Z = -12; - foo->target = self; - foo->FriendPlayer = 0; - foo->tracer = self->target; - - self->Angles.Yaw -= 90.; - for (int i = 0; i < 20; ++i) - { - self->Angles.Yaw += 9.; - P_SpawnSubMissile (self, PClass::FindActor("SpectralLightningBall2"), self); - } - self->Angles.Yaw -= 90.; - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_AlienSpectreDeath) -{ - PARAM_ACTION_PROLOGUE; - - AActor *player; - char voc[32]; - int log; - int i; - - A_Unblock(self, true); // [RH] Need this for Sigil rewarding - if (!CheckBossDeath (self)) - { - return 0; - } - for (i = 0, player = NULL; i < MAXPLAYERS; ++i) - { - if (playeringame[i] && players[i].health > 0) - { - player = players[i].mo; - break; - } - } - if (player == NULL) - { - return 0; - } - - switch (self->GetClass()->TypeName) - { - case NAME_AlienSpectre1: - EV_DoFloor (DFloor::floorLowerToLowest, NULL, 999, 1., 0., -1, 0, false); - log = 95; - break; - - case NAME_AlienSpectre2: - C_MidPrint(SmallFont, GStrings("TXT_KILLED_BISHOP")); - log = 74; - player->GiveInventoryType (QuestItemClasses[20]); - break; - - case NAME_AlienSpectre3: - { - C_MidPrint(SmallFont, GStrings("TXT_KILLED_ORACLE")); - // If there are any Oracles still alive, kill them. - TThinkerIterator it(NAME_Oracle); - AActor *oracle; - - while ( (oracle = it.Next()) != NULL) - { - if (oracle->health > 0) - { - oracle->health = 0; - oracle->Die (self, self); - } - } - player->GiveInventoryType (QuestItemClasses[22]); - if (player->FindInventory (QuestItemClasses[20])) - { // If the Bishop is dead, set quest item 22 - player->GiveInventoryType (QuestItemClasses[21]); - } - if (player->FindInventory (QuestItemClasses[23]) == NULL) - { // Macil is calling us back... - log = 87; - } - else - { // You wield the power of the complete Sigil. - log = 85; - } - EV_DoDoor (DDoor::doorOpen, NULL, NULL, 222, 8., 0, 0, 0); - break; - } - - case NAME_AlienSpectre4: - C_MidPrint(SmallFont, GStrings("TXT_KILLED_MACIL")); - player->GiveInventoryType (QuestItemClasses[23]); - if (player->FindInventory (QuestItemClasses[24]) == NULL) - { // Richter has taken over. Macil is a snake. - log = 79; - } - else - { // Back to the factory for another Sigil! - log = 106; - } - break; - - case NAME_AlienSpectre5: - C_MidPrint(SmallFont, GStrings("TXT_KILLED_LOREMASTER")); - ASigil *sigil; - - player->GiveInventoryType (QuestItemClasses[25]); - if (!multiplayer) - { - player->GiveInventoryType (RUNTIME_CLASS(AUpgradeStamina)); - player->GiveInventoryType (RUNTIME_CLASS(AUpgradeAccuracy)); - } - sigil = player->FindInventory(); - if (sigil != NULL && sigil->NumPieces == 5) - { // You wield the power of the complete Sigil. - log = 85; - } - else - { // Another Sigil piece. Woohoo! - log = 83; - } - EV_DoFloor (DFloor::floorLowerToLowest, NULL, 666, 1., 0., -1, 0, false); - break; - - default: - return 0; - } - mysnprintf (voc, countof(voc), "svox/voc%d", log); - S_Sound (CHAN_VOICE, voc, 1, ATTN_NORM); - player->player->SetLogNumber (log); - return 0; -} diff --git a/src/g_strife/a_coin.cpp b/src/g_strife/a_coin.cpp deleted file mode 100644 index 5848164bde..0000000000 --- a/src/g_strife/a_coin.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* -#include "a_pickups.h" -#include "a_strifeglobal.h" -#include "gstrings.h" -*/ - -// Coin --------------------------------------------------------------------- - -IMPLEMENT_CLASS (ACoin) - -const char *ACoin::PickupMessage () -{ - if (Amount == 1) - { - return Super::PickupMessage(); - } - else - { - static char msg[64]; - - mysnprintf (msg, countof(msg), GStrings("TXT_XGOLD"), Amount); - return msg; - } -} - -bool ACoin::HandlePickup (AInventory *item) -{ - if (item->IsKindOf (RUNTIME_CLASS(ACoin))) - { - if (Amount < MaxAmount) - { - if (MaxAmount - Amount < item->Amount) - { - Amount = MaxAmount; - } - else - { - Amount += item->Amount; - } - item->ItemFlags |= IF_PICKUPGOOD; - } - return true; - } - if (Inventory != NULL) - { - return Inventory->HandlePickup (item); - } - return false; -} - -AInventory *ACoin::CreateCopy (AActor *other) -{ - if (GetClass() == RUNTIME_CLASS(ACoin)) - { - return Super::CreateCopy (other); - } - AInventory *copy = Spawn (); - copy->Amount = Amount; - copy->BecomeItem (); - GoAwayAndDie (); - return copy; -} - -//=========================================================================== -// -// ACoin :: CreateTossable -// -// Gold drops in increments of 50 if you have that much, less if you don't. -// -//=========================================================================== - -AInventory *ACoin::CreateTossable () -{ - ACoin *tossed; - - if ((ItemFlags & IF_UNDROPPABLE) || Owner == NULL || Amount <= 0) - { - return NULL; - } - if (Amount >= 50) - { - Amount -= 50; - tossed = static_cast(Spawn("Gold50", Owner->Pos(), NO_REPLACE)); - } - else if (Amount >= 25) - { - Amount -= 25; - tossed = static_cast(Spawn("Gold25", Owner->Pos(), NO_REPLACE)); - } - else if (Amount >= 10) - { - Amount -= 10; - tossed = static_cast(Spawn("Gold10", Owner->Pos(), NO_REPLACE)); - } - else if (Amount > 1 || (ItemFlags & IF_KEEPDEPLETED)) - { - Amount -= 1; - tossed = static_cast(Spawn("Coin", Owner->Pos(), NO_REPLACE)); - } - else // Amount == 1 && !(ItemFlags & IF_KEEPDEPLETED) - { - BecomePickup (); - tossed = this; - } - tossed->flags &= ~(MF_SPECIAL|MF_SOLID); - tossed->DropTime = 30; - if (tossed != this && Amount <= 0) - { - Destroy (); - } - return tossed; -} diff --git a/src/g_strife/a_crusader.cpp b/src/g_strife/a_crusader.cpp deleted file mode 100644 index b54fdd427a..0000000000 --- a/src/g_strife/a_crusader.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* -#include "actor.h" -#include "m_random.h" -#include "a_action.h" -#include "p_local.h" -#include "p_enemy.h" -#include "s_sound.h" -#include "a_strifeglobal.h" -#include "thingdef/thingdef.h" -*/ - -static bool CrusaderCheckRange (AActor *self) -{ - if (self->reactiontime == 0 && P_CheckSight (self, self->target)) - { - return self->Distance2D (self->target) < 264.; - } - return false; -} - -DEFINE_ACTION_FUNCTION(AActor, A_CrusaderChoose) -{ - PARAM_ACTION_PROLOGUE; - - if (self->target == NULL) - return 0; - - if (CrusaderCheckRange (self)) - { - A_FaceTarget (self); - self->Angles.Yaw -= 180./16; - P_SpawnMissileZAimed (self, self->Z() + 40, self->target, PClass::FindActor("FastFlameMissile")); - } - else - { - if (P_CheckMissileRange (self)) - { - A_FaceTarget (self); - P_SpawnMissileZAimed (self, self->Z() + 56, self->target, PClass::FindActor("CrusaderMissile")); - self->Angles.Yaw -= 45./32; - P_SpawnMissileZAimed (self, self->Z() + 40, self->target, PClass::FindActor("CrusaderMissile")); - self->Angles.Yaw += 45./16; - P_SpawnMissileZAimed (self, self->Z() + 40, self->target, PClass::FindActor("CrusaderMissile")); - self->Angles.Yaw -= 45./16; - self->reactiontime += 15; - } - self->SetState (self->SeeState); - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_CrusaderSweepLeft) -{ - PARAM_ACTION_PROLOGUE; - - self->Angles.Yaw += 90./16; - AActor *misl = P_SpawnMissileZAimed (self, self->Z() + 48, self->target, PClass::FindActor("FastFlameMissile")); - if (misl != NULL) - { - misl->Vel.Z += 1; - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_CrusaderSweepRight) -{ - PARAM_ACTION_PROLOGUE; - - self->Angles.Yaw -= 90./16; - AActor *misl = P_SpawnMissileZAimed (self, self->Z() + 48, self->target, PClass::FindActor("FastFlameMissile")); - if (misl != NULL) - { - misl->Vel.Z += 1; - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_CrusaderRefire) -{ - PARAM_ACTION_PROLOGUE; - - if (self->target == NULL || - self->target->health <= 0 || - !P_CheckSight (self, self->target)) - { - self->SetState (self->SeeState); - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_CrusaderDeath) -{ - PARAM_ACTION_PROLOGUE; - - if (CheckBossDeath (self)) - { - EV_DoFloor (DFloor::floorLowerToLowest, NULL, 667, 1., 0., -1, 0, false); - } - return 0; -} diff --git a/src/g_strife/a_entityboss.cpp b/src/g_strife/a_entityboss.cpp deleted file mode 100644 index 72eeaac3a0..0000000000 --- a/src/g_strife/a_entityboss.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* -#include "actor.h" -#include "m_random.h" -#include "a_action.h" -#include "p_local.h" -#include "p_enemy.h" -#include "s_sound.h" -#include "a_strifeglobal.h" -#include "thingdef/thingdef.h" -#include "g_level.h" -*/ - -static FRandom pr_entity ("Entity"); - -DEFINE_ACTION_FUNCTION(AActor, A_SubEntityDeath) -{ - PARAM_ACTION_PROLOGUE; - - if (CheckBossDeath (self)) - { - G_ExitLevel (0, false); - } - return 0; -} - -void A_SpectralMissile (AActor *self, const char *missilename) -{ - if (self->target != NULL) - { - AActor *missile = P_SpawnMissileXYZ (self->PosPlusZ(32.), self, self->target, PClass::FindActor(missilename), false); - if (missile != NULL) - { - missile->tracer = self->target; - P_CheckMissileSpawn(missile, self->radius); - } - } -} - -DECLARE_ACTION(A_SpotLightning) -DECLARE_ACTION(A_Spectre3Attack) - - -DEFINE_ACTION_FUNCTION(AActor, A_EntityAttack) -{ - PARAM_ACTION_PROLOGUE; - - // Apparent Strife bug: Case 5 was unreachable because they used % 5 instead of % 6. - // I've fixed that by making case 1 duplicate it, since case 1 did nothing. - switch (pr_entity() % 5) - { - case 0: - CALL_ACTION(A_SpotLightning, self); - break; - - case 2: - A_SpectralMissile (self, "SpectralLightningH3"); - break; - - case 3: - CALL_ACTION(A_Spectre3Attack, self); - break; - - case 4: - A_SpectralMissile (self, "SpectralLightningBigV2"); - break; - - case 1: - case 5: - A_SpectralMissile (self, "SpectralLightningBigBall2"); - break; - } - return 0; -} - - -DEFINE_ACTION_FUNCTION(AActor, A_SpawnEntity) -{ - PARAM_ACTION_PROLOGUE; - - AActor *entity = Spawn("EntityBoss", self->PosPlusZ(70.), ALLOW_REPLACE); - if (entity != NULL) - { - entity->Angles.Yaw = self->Angles.Yaw; - entity->CopyFriendliness(self, true); - entity->Vel.Z = 5; - entity->tracer = self; - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_EntityDeath) -{ - PARAM_ACTION_PROLOGUE; - - AActor *second; - double secondRadius = GetDefaultByName("EntitySecond")->radius * 2; - - static const double turns[3] = { 0, 90, -90 }; - const double velmul[3] = { 4.8828125f, secondRadius*4, secondRadius*4 }; - - AActor *spot = self->tracer; - if (spot == NULL) spot = self; - - for (int i = 0; i < 3; i++) - { - DAngle an = self->Angles.Yaw + turns[i]; - DVector3 pos = spot->Vec3Angle(secondRadius, an, self->tracer ? 70. : 0.); - - second = Spawn("EntitySecond", pos, ALLOW_REPLACE); - second->CopyFriendliness(self, true); - A_FaceTarget(second); - second->VelFromAngle(an, velmul[i]); - } - return 0; -} diff --git a/src/g_strife/a_inquisitor.cpp b/src/g_strife/a_inquisitor.cpp deleted file mode 100644 index e372d8de1a..0000000000 --- a/src/g_strife/a_inquisitor.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* -#include "actor.h" -#include "m_random.h" -#include "a_action.h" -#include "p_local.h" -#include "p_enemy.h" -#include "s_sound.h" -#include "thingdef/thingdef.h" -*/ - -static FRandom pr_inq ("Inquisitor"); - -DEFINE_ACTION_FUNCTION(AActor, A_InquisitorWalk) -{ - PARAM_ACTION_PROLOGUE; - - S_Sound (self, CHAN_BODY, "inquisitor/walk", 1, ATTN_NORM); - A_Chase (stack, self); - return 0; -} - -bool InquisitorCheckDistance (AActor *self) -{ - if (self->reactiontime == 0 && P_CheckSight (self, self->target)) - { - return self->Distance2D (self->target) < 264.; - } - return false; -} - -DEFINE_ACTION_FUNCTION(AActor, A_InquisitorDecide) -{ - PARAM_ACTION_PROLOGUE; - - if (self->target == NULL) - return 0; - - A_FaceTarget (self); - if (!InquisitorCheckDistance (self)) - { - self->SetState (self->FindState("Grenade")); - } - if (self->target->Z() != self->Z()) - { - if (self->Top() + 54 < self->ceilingz) - { - self->SetState (self->FindState("Jump")); - } - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_InquisitorAttack) -{ - PARAM_ACTION_PROLOGUE; - - AActor *proj; - - if (self->target == NULL) - return 0; - - A_FaceTarget (self); - - self->AddZ(32); - self->Angles.Yaw -= 45./32; - proj = P_SpawnMissileZAimed (self, self->Z(), self->target, PClass::FindActor("InquisitorShot")); - if (proj != NULL) - { - proj->Vel.Z += 9; - } - self->Angles.Yaw += 45./16; - proj = P_SpawnMissileZAimed (self, self->Z(), self->target, PClass::FindActor("InquisitorShot")); - if (proj != NULL) - { - proj->Vel.Z += 16; - } - self->AddZ(-32); - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_InquisitorJump) -{ - PARAM_ACTION_PROLOGUE; - - double dist; - double speed; - - if (self->target == NULL) - return 0; - - S_Sound (self, CHAN_ITEM|CHAN_LOOP, "inquisitor/jump", 1, ATTN_NORM); - self->AddZ(64); - A_FaceTarget (self); - speed = self->Speed * (2./3); - self->VelFromAngle(speed); - dist = self->DistanceBySpeed(self->target, speed); - self->Vel.Z = (self->target->Z() - self->Z()) / dist; - self->reactiontime = 60; - self->flags |= MF_NOGRAVITY; - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_InquisitorCheckLand) -{ - PARAM_ACTION_PROLOGUE; - - self->reactiontime--; - if (self->reactiontime < 0 || - self->Vel.X == 0 || - self->Vel.Y == 0 || - self->Z() <= self->floorz) - { - self->SetState (self->SeeState); - self->reactiontime = 0; - self->flags &= ~MF_NOGRAVITY; - S_StopSound (self, CHAN_ITEM); - return 0; - } - if (!S_IsActorPlayingSomething (self, CHAN_ITEM, -1)) - { - S_Sound (self, CHAN_ITEM|CHAN_LOOP, "inquisitor/jump", 1, ATTN_NORM); - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_TossArm) -{ - PARAM_ACTION_PROLOGUE; - - AActor *foo = Spawn("InquisitorArm", self->PosPlusZ(24.), ALLOW_REPLACE); - foo->Angles.Yaw = self->Angles.Yaw - 90. + pr_inq.Random2() * (360./1024.); - foo->VelFromAngle(foo->Speed / 8); - foo->Vel.Z = pr_inq() / 64.; - return 0; -} - diff --git a/src/g_strife/a_loremaster.cpp b/src/g_strife/a_loremaster.cpp deleted file mode 100644 index ead116c639..0000000000 --- a/src/g_strife/a_loremaster.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* -#include "actor.h" -#include "a_action.h" -#include "a_strifeglobal.h" -#include "m_random.h" -#include "p_local.h" -#include "s_sound.h" -#include "thingdef/thingdef.h" -*/ - -// Loremaster (aka Priest) -------------------------------------------------- - -class ALoreShot : public AActor -{ - DECLARE_CLASS (ALoreShot, AActor) -public: - int DoSpecialDamage (AActor *victim, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS (ALoreShot) - -int ALoreShot::DoSpecialDamage (AActor *victim, int damage, FName damagetype) -{ - - if (victim != NULL && target != NULL && !(victim->flags7 & MF7_DONTTHRUST)) - { - DVector3 thrust = victim->Vec3To(target); - thrust.MakeResize(255. * 50 / MAX(victim->Mass, 1)); - victim->Vel += thrust; - } - return damage; -} - -DEFINE_ACTION_FUNCTION(AActor, A_LoremasterChain) -{ - PARAM_ACTION_PROLOGUE; - - S_Sound (self, CHAN_BODY, "loremaster/active", 1, ATTN_NORM); - Spawn("LoreShot2", self->Pos(), ALLOW_REPLACE); - Spawn("LoreShot2", self->Vec3Offset(-self->Vel/2.), ALLOW_REPLACE); - Spawn("LoreShot2", self->Vec3Offset(-self->Vel), ALLOW_REPLACE); - return 0; -} diff --git a/src/g_strife/a_oracle.cpp b/src/g_strife/a_oracle.cpp deleted file mode 100644 index f1f0b0b2bc..0000000000 --- a/src/g_strife/a_oracle.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* -#include "actor.h" -#include "a_action.h" -#include "a_strifeglobal.h" -#include "p_enemy.h" -#include "r_defs.h" -#include "thingdef/thingdef.h" -*/ - - -DEFINE_ACTION_FUNCTION(AActor, A_WakeOracleSpectre) -{ - PARAM_ACTION_PROLOGUE; - - TThinkerIterator it(NAME_AlienSpectre3); - AActor *spectre = it.Next(); - - if (spectre != NULL && spectre->health > 0 && self->target != spectre) - { - spectre->Sector->SoundTarget = spectre->LastHeard = self->LastHeard; - spectre->target = self->target; - spectre->SetState (spectre->SeeState); - } - return 0; -} - diff --git a/src/g_strife/a_programmer.cpp b/src/g_strife/a_programmer.cpp deleted file mode 100644 index bed5f838ba..0000000000 --- a/src/g_strife/a_programmer.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/* -#include "actor.h" -#include "m_random.h" -#include "a_action.h" -#include "p_local.h" -#include "p_enemy.h" -#include "s_sound.h" -#include "a_strifeglobal.h" -#include "thingdef/thingdef.h" -#include "g_level.h" -#include "doomstat.h" -*/ -static FRandom pr_prog ("Programmer"); - -// The Programmer level ending thing ---------------------------------------- -// [RH] I took some liberties to make this "cooler" than it was in Strife. - -class AProgLevelEnder : public AInventory -{ - DECLARE_CLASS (AProgLevelEnder, AInventory) -public: - void Tick (); - PalEntry GetBlend (); -}; - -IMPLEMENT_CLASS (AProgLevelEnder) - -//============================================================================ -// -// AProgLevelEnder :: Tick -// -// Fade to black, end the level, then unfade. -// -//============================================================================ - -void AProgLevelEnder::Tick () -{ - if (special2 == 0) - { // fade out over .66 second - special1 += 255 / (TICRATE*2/3); - if (++special1 >= 255) - { - special1 = 255; - special2 = 1; - G_ExitLevel (0, false); - } - } - else - { // fade in over two seconds - special1 -= 255 / (TICRATE*2); - if (special1 <= 0) - { - Destroy (); - } - } -} - -//============================================================================ -// -// AProgLevelEnder :: GetBlend -// -//============================================================================ - -PalEntry AProgLevelEnder::GetBlend () -{ - return PalEntry ((BYTE)special1, 0, 0, 0); -} - -//============================================================================ -// -// A_ProgrammerMelee -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_ProgrammerMelee) -{ - PARAM_ACTION_PROLOGUE; - - int damage; - - if (self->target == NULL) - return 0; - - A_FaceTarget (self); - - if (!self->CheckMeleeRange ()) - return 0; - - S_Sound (self, CHAN_WEAPON, "programmer/clank", 1, ATTN_NORM); - - damage = ((pr_prog() % 10) + 1) * 6; - int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); - return 0; -} - -//============================================================================ -// -// A_SpotLightning -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SpotLightning) -{ - PARAM_ACTION_PROLOGUE; - - AActor *spot; - - if (self->target == NULL) - return 0; - - spot = Spawn("SpectralLightningSpot", self->target->PosAtZ(self->target->floorz), ALLOW_REPLACE); - if (spot != NULL) - { - spot->threshold = 25; - spot->target = self; - spot->FriendPlayer = 0; - spot->tracer = self->target; - } - return 0; -} - -//============================================================================ -// -// A_SpawnProgrammerBase -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SpawnProgrammerBase) -{ - PARAM_ACTION_PROLOGUE; - - AActor *foo = Spawn("ProgrammerBase", self->PosPlusZ(24.), ALLOW_REPLACE); - if (foo != NULL) - { - foo->Angles.Yaw = self->Angles.Yaw + 180. + pr_prog.Random2() * (360. / 1024.); - foo->VelFromAngle(); - foo->Vel.Z = pr_prog() / 128.; - } - return 0; -} - -//============================================================================ -// -// A_ProgrammerDeath -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_ProgrammerDeath) -{ - PARAM_ACTION_PROLOGUE; - - if (!CheckBossDeath (self)) - return 0; - - for (int i = 0; i < MAXPLAYERS; ++i) - { - if (playeringame[i] && players[i].health > 0) - { - players[i].mo->GiveInventoryType (RUNTIME_CLASS(AProgLevelEnder)); - break; - } - } - // the sky change scripts are now done as special actions in MAPINFO - A_BossDeath(self); - return 0; -} diff --git a/src/g_strife/a_reaver.cpp b/src/g_strife/a_reaver.cpp deleted file mode 100644 index 372aea794c..0000000000 --- a/src/g_strife/a_reaver.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* -#include "actor.h" -#include "p_enemy.h" -#include "a_action.h" -#include "s_sound.h" -#include "m_random.h" -#include "p_local.h" -#include "a_strifeglobal.h" -#include "thingdef/thingdef.h" -*/ - -static FRandom pr_reaverattack ("ReaverAttack"); - -DEFINE_ACTION_FUNCTION(AActor, A_ReaverRanged) -{ - PARAM_ACTION_PROLOGUE; - - if (self->target != NULL) - { - DAngle bangle; - DAngle pitch; - - A_FaceTarget (self); - S_Sound (self, CHAN_WEAPON, "reaver/attack", 1, ATTN_NORM); - bangle = self->Angles.Yaw; - pitch = P_AimLineAttack (self, bangle, MISSILERANGE); - - for (int i = 0; i < 3; ++i) - { - DAngle angle = bangle + pr_reaverattack.Random2() * (22.5 / 256); - int damage = ((pr_reaverattack() & 7) + 1) * 3; - P_LineAttack (self, angle, MISSILERANGE, pitch, damage, NAME_Hitscan, NAME_StrifePuff); - } - } - return 0; -} diff --git a/src/g_strife/a_rebels.cpp b/src/g_strife/a_rebels.cpp deleted file mode 100644 index f2031a7a37..0000000000 --- a/src/g_strife/a_rebels.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* -#include "actor.h" -#include "m_random.h" -#include "a_action.h" -#include "p_local.h" -#include "p_enemy.h" -#include "s_sound.h" -#include "gi.h" -#include "a_sharedglobal.h" -#include "a_strifeglobal.h" -#include "thingdef/thingdef.h" -#include "doomstat.h" -*/ - -static FRandom pr_shootgun ("ShootGun"); - -//============================================================================ -// -// A_ShootGun -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_ShootGun) -{ - PARAM_ACTION_PROLOGUE; - - DAngle pitch; - - if (self->target == NULL) - return 0; - - S_Sound (self, CHAN_WEAPON, "monsters/rifle", 1, ATTN_NORM); - A_FaceTarget (self); - pitch = P_AimLineAttack (self, self->Angles.Yaw, MISSILERANGE); - P_LineAttack (self, self->Angles.Yaw + pr_shootgun.Random2() * (11.25 / 256), - MISSILERANGE, pitch, - 3*(pr_shootgun() % 5 + 1), NAME_Hitscan, NAME_StrifePuff); - return 0; -} - -// Teleporter Beacon -------------------------------------------------------- - -class ATeleporterBeacon : public AInventory -{ - DECLARE_CLASS (ATeleporterBeacon, AInventory) -public: - bool Use (bool pickup); -}; - -IMPLEMENT_CLASS (ATeleporterBeacon) - -bool ATeleporterBeacon::Use (bool pickup) -{ - AInventory *drop; - - // Increase the amount by one so that when DropInventory decrements it, - // the actor will have the same number of beacons that he started with. - // When we return to UseInventory, it will take care of decrementing - // Amount again and disposing of this item if there are no more. - Amount++; - drop = Owner->DropInventory (this); - if (drop == NULL) - { - Amount--; - return false; - } - else - { - drop->SetState(drop->FindState(NAME_Drop)); - drop->target = Owner; - return true; - } -} - -DEFINE_ACTION_FUNCTION(AActor, A_Beacon) -{ - PARAM_ACTION_PROLOGUE; - - AActor *owner = self->target; - AActor *rebel; - - rebel = Spawn("Rebel1", self->PosAtZ(self->floorz), ALLOW_REPLACE); - if (!P_TryMove (rebel, rebel->Pos(), true)) - { - rebel->Destroy (); - return 0; - } - // Once the rebels start teleporting in, you can't pick up the beacon anymore. - self->flags &= ~MF_SPECIAL; - static_cast(self)->DropTime = 0; - // Set up the new rebel. - rebel->threshold = rebel->DefThreshold; - rebel->target = NULL; - rebel->flags4 |= MF4_INCOMBAT; - rebel->LastHeard = owner; // Make sure the rebels look for targets - if (deathmatch) - { - rebel->health *= 2; - } - if (owner != NULL) - { - // Rebels are the same color as their owner (but only in multiplayer) - if (multiplayer) - { - rebel->Translation = owner->Translation; - } - rebel->SetFriendPlayer(owner->player); - // Set the rebel's target to whatever last hurt the player, so long as it's not - // one of the player's other rebels. - if (owner->target != NULL && !rebel->IsFriend (owner->target)) - { - rebel->target = owner->target; - } - } - - rebel->SetState (rebel->SeeState); - rebel->Angles.Yaw = self->Angles.Yaw; - P_SpawnTeleportFog(rebel, rebel->Vec3Angle(20., self->Angles.Yaw, 0), false, true); - if (--self->health < 0) - { - self->SetState(self->FindState(NAME_Death)); - } - return 0; -} diff --git a/src/g_strife/a_sentinel.cpp b/src/g_strife/a_sentinel.cpp deleted file mode 100644 index 91adbb01ec..0000000000 --- a/src/g_strife/a_sentinel.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* -#include "actor.h" -#include "p_enemy.h" -#include "a_action.h" -#include "p_local.h" -#include "m_random.h" -#include "thingdef/thingdef.h" -*/ - -static FRandom pr_sentinelrefire ("SentinelRefire"); - -DEFINE_ACTION_FUNCTION(AActor, A_SentinelBob) -{ - PARAM_ACTION_PROLOGUE; - - double minz, maxz; - - if (self->flags & MF_INFLOAT) - { - self->Vel.Z = 0; - return 0; - } - if (self->threshold != 0) - return 0; - - maxz = self->ceilingz - self->Height - 16; - minz = self->floorz + 96; - if (minz > maxz) - { - minz = maxz; - } - if (minz < self->Z()) - { - self->Vel.Z -= 1; - } - else - { - self->Vel.Z += 1; - } - self->reactiontime = (minz >= self->Z()) ? 4 : 0; - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_SentinelAttack) -{ - PARAM_ACTION_PROLOGUE; - - AActor *missile, *trail; - - // [BB] Without a target the P_SpawnMissileZAimed call will crash. - if (!self->target) - { - return 0; - } - - missile = P_SpawnMissileZAimed (self, self->Z() + 32, self->target, PClass::FindActor("SentinelFX2")); - - if (missile != NULL && (missile->Vel.X != 0 || missile->Vel.Y != 0)) - { - for (int i = 8; i > 1; --i) - { - trail = Spawn("SentinelFX1", - self->Vec3Angle(missile->radius*i, missile->Angles.Yaw, 32 + missile->Vel.Z / 4 * i), ALLOW_REPLACE); - if (trail != NULL) - { - trail->target = self; - trail->Vel = missile->Vel; - P_CheckMissileSpawn (trail, self->radius); - } - } - missile->AddZ(missile->Vel.Z / 4); - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_SentinelRefire) -{ - PARAM_ACTION_PROLOGUE; - - A_FaceTarget (self); - - if (pr_sentinelrefire() >= 30) - { - if (self->target == NULL || - self->target->health <= 0 || - !P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES) || - P_HitFriend(self) || - (self->MissileState == NULL && !self->CheckMeleeRange()) || - pr_sentinelrefire() < 40) - { - self->SetState (self->SeeState); - } - } - return 0; -} diff --git a/src/g_strife/a_spectral.cpp b/src/g_strife/a_spectral.cpp deleted file mode 100644 index 00b19055c6..0000000000 --- a/src/g_strife/a_spectral.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* -#include "actor.h" -#include "m_random.h" -#include "a_action.h" -#include "p_local.h" -#include "s_sound.h" -#include "m_random.h" -#include "a_strifeglobal.h" -#include "thingdef/thingdef.h" -*/ - -class ASpectralMonster : public AActor -{ - DECLARE_CLASS (ASpectralMonster, AActor) -public: - void Touch (AActor *toucher); -}; - -IMPLEMENT_CLASS (ASpectralMonster) - -void ASpectralMonster::Touch (AActor *toucher) -{ - P_DamageMobj (toucher, this, this, 5, NAME_Melee); -} - - -DEFINE_ACTION_FUNCTION(AActor, A_SpectralLightningTail) -{ - PARAM_ACTION_PROLOGUE; - - AActor *foo = Spawn("SpectralLightningHTail", self->Vec3Offset(-self->Vel.X, -self->Vel.Y, 0.), ALLOW_REPLACE); - - foo->Angles.Yaw = self->Angles.Yaw; - foo->FriendPlayer = self->FriendPlayer; - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_SpectralBigBallLightning) -{ - PARAM_ACTION_PROLOGUE; - - PClassActor *cls = PClass::FindActor("SpectralLightningH3"); - if (cls) - { - self->Angles.Yaw += 90.; - P_SpawnSubMissile (self, cls, self->target); - self->Angles.Yaw += 180.; - P_SpawnSubMissile (self, cls, self->target); - self->Angles.Yaw -= 270.; - P_SpawnSubMissile (self, cls, self->target); - } - return 0; -} - -static FRandom pr_zap5 ("Zap5"); - -DEFINE_ACTION_FUNCTION(AActor, A_SpectralLightning) -{ - PARAM_ACTION_PROLOGUE; - - AActor *flash; - - if (self->threshold != 0) - --self->threshold; - - self->Vel.X += pr_zap5.Random2(3); - self->Vel.Y += pr_zap5.Random2(3); - - double xo = pr_zap5.Random2(3) * 50.; - double yo = pr_zap5.Random2(3) * 50.; - - flash = Spawn (self->threshold > 25 ? PClass::FindActor(NAME_SpectralLightningV2) : - PClass::FindActor(NAME_SpectralLightningV1), self->Vec2OffsetZ(xo, yo, ONCEILINGZ), ALLOW_REPLACE); - - flash->target = self->target; - flash->Vel.Z = -18; - flash->FriendPlayer = self->FriendPlayer; - - flash = Spawn(NAME_SpectralLightningV2, self->PosAtZ(ONCEILINGZ), ALLOW_REPLACE); - - flash->target = self->target; - flash->Vel.Z = -18; - flash->FriendPlayer = self->FriendPlayer; - return 0; -} - -// In Strife, this number is stored in the data segment, but it doesn't seem to be -// altered anywhere. -#define TRACEANGLE (19.6875) - -DEFINE_ACTION_FUNCTION(AActor, A_Tracer2) -{ - PARAM_ACTION_PROLOGUE; - - AActor *dest; - double dist; - double slope; - - dest = self->tracer; - - if (!dest || dest->health <= 0 || self->Speed == 0 || !self->CanSeek(dest)) - return 0; - - 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; -} diff --git a/src/g_strife/a_stalker.cpp b/src/g_strife/a_stalker.cpp deleted file mode 100644 index 8ee07de8ab..0000000000 --- a/src/g_strife/a_stalker.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* -#include "actor.h" -#include "m_random.h" -#include "a_action.h" -#include "p_local.h" -#include "p_enemy.h" -#include "s_sound.h" -#include "thingdef/thingdef.h" -*/ - -static FRandom pr_stalker ("Stalker"); - - -DEFINE_ACTION_FUNCTION(AActor, A_StalkerChaseDecide) -{ - PARAM_ACTION_PROLOGUE; - - if (!(self->flags & MF_NOGRAVITY)) - { - self->SetState (self->FindState("SeeFloor")); - } - else if (self->ceilingz > self->Top()) - { - self->SetState (self->FindState("Drop")); - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_StalkerLookInit) -{ - PARAM_ACTION_PROLOGUE; - - FState *state; - if (self->flags & MF_NOGRAVITY) - { - state = self->FindState("LookCeiling"); - } - else - { - state = self->FindState("LookFloor"); - } - if (self->state->NextState != state) - { - self->SetState (state); - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_StalkerDrop) -{ - PARAM_ACTION_PROLOGUE; - - self->flags5 &= ~MF5_NOVERTICALMELEERANGE; - self->flags &= ~MF_NOGRAVITY; - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_StalkerAttack) -{ - PARAM_ACTION_PROLOGUE; - - if (self->flags & MF_NOGRAVITY) - { - self->SetState (self->FindState("Drop")); - } - else if (self->target != NULL) - { - A_FaceTarget (self); - if (self->CheckMeleeRange ()) - { - int damage = (pr_stalker() & 7) * 2 + 2; - - int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); - } - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_StalkerWalk) -{ - PARAM_ACTION_PROLOGUE; - - S_Sound (self, CHAN_BODY, "stalker/walk", 1, ATTN_NORM); - A_Chase (stack, self); - return 0; -} - diff --git a/src/g_strife/a_strifeglobal.h b/src/g_strife/a_strifeglobal.h deleted file mode 100644 index 9e7f9148e0..0000000000 --- a/src/g_strife/a_strifeglobal.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef __A_STRIFEGLOBAL_H__ -#define __A_STRIFEGLOBAL_H__ - -#include "info.h" -#include "a_pickups.h" - -// Base class for every humanoid in Strife that can go into -// a fire or electric death. -class ADegninOre : public AInventory -{ - DECLARE_CLASS (ADegninOre, AInventory) -public: - bool Use (bool pickup); -}; - -class ACoin : public AInventory -{ - DECLARE_CLASS (ACoin, AInventory) -public: - const char *PickupMessage (); - bool HandlePickup (AInventory *item); - AInventory *CreateTossable (); - AInventory *CreateCopy (AActor *other); -}; - -class ADummyStrifeItem : public AInventory -{ - DECLARE_CLASS (ADummyStrifeItem, AInventory) -}; - -class AUpgradeStamina : public ADummyStrifeItem -{ - DECLARE_CLASS (AUpgradeStamina, ADummyStrifeItem) -public: - bool TryPickup (AActor *&toucher); -}; - -class AUpgradeAccuracy : public ADummyStrifeItem -{ - DECLARE_CLASS (AUpgradeAccuracy, ADummyStrifeItem) -public: - bool TryPickup (AActor *&toucher); -}; - -class ASlideshowStarter : public ADummyStrifeItem -{ - DECLARE_CLASS (ASlideshowStarter, ADummyStrifeItem) -public: - bool TryPickup (AActor *&toucher); -}; - -class ASigil : public AWeapon -{ - DECLARE_CLASS (ASigil, AWeapon) -public: - bool HandlePickup (AInventory *item); - AInventory *CreateCopy (AActor *other); - - void Serialize(FSerializer &arc); - bool SpecialDropAction (AActor *dropper); - static int GiveSigilPiece (AActor *daPlayer); - void BeginPlay(); - - int NumPieces, DownPieces; -}; - -extern PClassActor *QuestItemClasses[31]; - -#endif diff --git a/src/g_strife/a_strifeitems.cpp b/src/g_strife/a_strifeitems.cpp deleted file mode 100644 index 26ac88393b..0000000000 --- a/src/g_strife/a_strifeitems.cpp +++ /dev/null @@ -1,387 +0,0 @@ -/* -#include "info.h" -#include "a_pickups.h" -#include "d_player.h" -#include "gstrings.h" -#include "p_local.h" -#include "p_spec.h" -#include "a_strifeglobal.h" -#include "p_lnspec.h" -#include "p_enemy.h" -#include "s_sound.h" -#include "d_event.h" -#include "a_keys.h" -#include "c_console.h" -#include "templates.h" -#include "thingdef/thingdef.h" -#include "g_level.h" -#include "doomstat.h" -*/ -// Degnin Ore --------------------------------------------------------------- - -IMPLEMENT_CLASS(ADegninOre) - -DEFINE_ACTION_FUNCTION(AActor, A_RemoveForceField) -{ - PARAM_ACTION_PROLOGUE; - - self->flags &= ~MF_SPECIAL; - - for (int i = 0; i < self->Sector->linecount; ++i) - { - line_t *line = self->Sector->lines[i]; - if (line->backsector != NULL && line->special == ForceField) - { - line->flags &= ~(ML_BLOCKING|ML_BLOCKEVERYTHING); - line->special = 0; - line->sidedef[0]->SetTexture(side_t::mid, FNullTextureID()); - line->sidedef[1]->SetTexture(side_t::mid, FNullTextureID()); - } - } - return 0; -} - -bool ADegninOre::Use (bool pickup) -{ - if (pickup) - { - return false; - } - else - { - AInventory *drop; - - // Increase the amount by one so that when DropInventory decrements it, - // the actor will have the same number of beacons that he started with. - // When we return to UseInventory, it will take care of decrementing - // Amount again and disposing of this item if there are no more. - Amount++; - drop = Owner->DropInventory (this); - if (drop == NULL) - { - Amount--; - return false; - } - return true; - } -} - -// Health Training ---------------------------------------------------------- - -class AHealthTraining : public AInventory -{ - DECLARE_CLASS (AHealthTraining, AInventory) -public: - bool TryPickup (AActor *&toucher); -}; - -IMPLEMENT_CLASS (AHealthTraining) - -bool AHealthTraining::TryPickup (AActor *&toucher) -{ - if (Super::TryPickup (toucher)) - { - toucher->GiveInventoryType (PClass::FindActor("GunTraining")); - AInventory *coin = Spawn (); - if (coin != NULL) - { - coin->Amount = toucher->player->mo->accuracy*5 + 300; - if (!coin->CallTryPickup (toucher)) - { - coin->Destroy (); - } - } - return true; - } - return false; -} - -// Scanner ------------------------------------------------------------------ - -class AScanner : public APowerupGiver -{ - DECLARE_CLASS (AScanner, APowerupGiver) -public: - bool Use (bool pickup); -}; - -IMPLEMENT_CLASS (AScanner) - -bool AScanner::Use (bool pickup) -{ - if (!(level.flags2 & LEVEL2_ALLMAP)) - { - if (Owner->CheckLocalView (consoleplayer)) - { - C_MidPrint(SmallFont, GStrings("TXT_NEEDMAP")); - } - return false; - } - return Super::Use (pickup); -} - -// Prison Pass -------------------------------------------------------------- - -class APrisonPass : public AKey -{ - DECLARE_CLASS (APrisonPass, AKey) -public: - bool TryPickup (AActor *&toucher); - bool SpecialDropAction (AActor *dropper); -}; - -IMPLEMENT_CLASS (APrisonPass) - -bool APrisonPass::TryPickup (AActor *&toucher) -{ - Super::TryPickup (toucher); - EV_DoDoor (DDoor::doorOpen, NULL, toucher, 223, 2., 0, 0, 0); - toucher->GiveInventoryType (QuestItemClasses[9]); - return true; -} - -//============================================================================ -// -// APrisonPass :: SpecialDropAction -// -// Trying to make a monster that drops a prison pass turns it into an -// OpenDoor223 item instead. That means the only way to get it in Strife -// is through dialog, which is why it doesn't have its own sprite. -// -//============================================================================ - -bool APrisonPass::SpecialDropAction (AActor *dropper) -{ - EV_DoDoor (DDoor::doorOpen, NULL, dropper, 223, 2., 0, 0, 0); - Destroy (); - return true; -} - - -//--------------------------------------------------------------------------- -// Dummy items. They are just used by Strife to perform --------------------- -// actions and cannot be held. ---------------------------------------------- -//--------------------------------------------------------------------------- - -IMPLEMENT_CLASS (ADummyStrifeItem) - -// Sound the alarm! --------------------------------------------------------- - -class ARaiseAlarm : public ADummyStrifeItem -{ - DECLARE_CLASS (ARaiseAlarm, ADummyStrifeItem) -public: - bool TryPickup (AActor *&toucher); - bool SpecialDropAction (AActor *dropper); -}; - -IMPLEMENT_CLASS (ARaiseAlarm) - -bool ARaiseAlarm::TryPickup (AActor *&toucher) -{ - P_NoiseAlert (toucher, toucher); - VMFrameStack stack1, *stack = &stack1; - CALL_ACTION(A_WakeOracleSpectre, toucher); - GoAwayAndDie (); - return true; -} - -bool ARaiseAlarm::SpecialDropAction (AActor *dropper) -{ - if (dropper->target != nullptr) - { - P_NoiseAlert(dropper->target, dropper->target); - if (dropper->target->CheckLocalView(consoleplayer)) - { - Printf("You Fool! You've set off the alarm.\n"); - } - } - Destroy (); - return true; -} - -// Open door tag 222 -------------------------------------------------------- - -class AOpenDoor222 : public ADummyStrifeItem -{ - DECLARE_CLASS (AOpenDoor222, ADummyStrifeItem) -public: - bool TryPickup (AActor *&toucher); -}; - -IMPLEMENT_CLASS (AOpenDoor222) - -bool AOpenDoor222::TryPickup (AActor *&toucher) -{ - EV_DoDoor (DDoor::doorOpen, NULL, toucher, 222, 2., 0, 0, 0); - GoAwayAndDie (); - return true; -} - -// Close door tag 222 ------------------------------------------------------- - -class ACloseDoor222 : public ADummyStrifeItem -{ - DECLARE_CLASS (ACloseDoor222, ADummyStrifeItem) -public: - bool TryPickup (AActor *&toucher); - bool SpecialDropAction (AActor *dropper); -}; - -IMPLEMENT_CLASS (ACloseDoor222) - -bool ACloseDoor222::TryPickup (AActor *&toucher) -{ - EV_DoDoor (DDoor::doorClose, NULL, toucher, 222, 2., 0, 0, 0); - GoAwayAndDie (); - return true; -} - -bool ACloseDoor222::SpecialDropAction (AActor *dropper) -{ - EV_DoDoor (DDoor::doorClose, NULL, dropper, 222, 2., 0, 0, 0); - if (dropper->target != nullptr) - { - if (dropper->target->CheckLocalView(consoleplayer)) - { - Printf("You're dead! You set off the alarm.\n"); - } - P_NoiseAlert(dropper->target, dropper->target); - } - Destroy (); - return true; -} - -// Open door tag 224 -------------------------------------------------------- - -class AOpenDoor224 : public ADummyStrifeItem -{ - DECLARE_CLASS (AOpenDoor224, ADummyStrifeItem) -public: - bool TryPickup (AActor *&toucher); - bool SpecialDropAction (AActor *dropper); -}; - -IMPLEMENT_CLASS (AOpenDoor224) - -bool AOpenDoor224::TryPickup (AActor *&toucher) -{ - EV_DoDoor (DDoor::doorOpen, NULL, toucher, 224, 2., 0, 0, 0); - GoAwayAndDie (); - return true; -} - -bool AOpenDoor224::SpecialDropAction (AActor *dropper) -{ - EV_DoDoor (DDoor::doorOpen, NULL, dropper, 224, 2., 0, 0, 0); - Destroy (); - return true; -} - -// Ammo --------------------------------------------------------------------- - -class AAmmoFillup : public ADummyStrifeItem -{ - DECLARE_CLASS (AAmmoFillup, ADummyStrifeItem) -public: - bool TryPickup (AActor *&toucher); -}; - -IMPLEMENT_CLASS (AAmmoFillup) - -bool AAmmoFillup::TryPickup (AActor *&toucher) -{ - PClassActor *clip = PClass::FindActor(NAME_ClipOfBullets); - if (clip != NULL) - { - AInventory *item = toucher->FindInventory(clip); - if (item == NULL) - { - item = toucher->GiveInventoryType (clip); - if (item != NULL) - { - item->Amount = 50; - } - } - else if (item->Amount < 50) - { - item->Amount = 50; - } - else - { - return false; - } - GoAwayAndDie (); - } - return true; -} - -// Health ------------------------------------------------------------------- - -class AHealthFillup : public ADummyStrifeItem -{ - DECLARE_CLASS (AHealthFillup, ADummyStrifeItem) -public: - bool TryPickup (AActor *&toucher); -}; - -IMPLEMENT_CLASS (AHealthFillup) - -bool AHealthFillup::TryPickup (AActor *&toucher) -{ - static const int skillhealths[5] = { -100, -75, -50, -50, -100 }; - - int index = clamp(gameskill, 0,4); - if (!P_GiveBody (toucher, skillhealths[index])) - { - return false; - } - GoAwayAndDie (); - return true; -} - -// Upgrade Stamina ---------------------------------------------------------- - -IMPLEMENT_CLASS (AUpgradeStamina) - -bool AUpgradeStamina::TryPickup (AActor *&toucher) -{ - if (toucher->player == NULL) - return false; - - toucher->player->mo->stamina += Amount; - if (toucher->player->mo->stamina >= MaxAmount) - toucher->player->mo->stamina = MaxAmount; - - P_GiveBody (toucher, -100); - GoAwayAndDie (); - return true; -} - -// Upgrade Accuracy --------------------------------------------------------- - -IMPLEMENT_CLASS (AUpgradeAccuracy) - -bool AUpgradeAccuracy::TryPickup (AActor *&toucher) -{ - if (toucher->player == NULL || toucher->player->mo->accuracy >= 100) - return false; - toucher->player->mo->accuracy += 10; - GoAwayAndDie (); - return true; -} - -// Start a slideshow -------------------------------------------------------- - -IMPLEMENT_CLASS (ASlideshowStarter) - -bool ASlideshowStarter::TryPickup (AActor *&toucher) -{ - gameaction = ga_slideshow; - if (level.levelnum == 10) - { - toucher->GiveInventoryType (QuestItemClasses[16]); - } - GoAwayAndDie (); - return true; -} diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp deleted file mode 100644 index ad6bbe133d..0000000000 --- a/src/g_strife/a_strifestuff.cpp +++ /dev/null @@ -1,424 +0,0 @@ -#include "actor.h" -#include "g_level.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_strifeglobal.h" -#include "p_enemy.h" -#include "p_lnspec.h" -#include "c_console.h" -#include "thingdef/thingdef.h" -#include "doomstat.h" -#include "gstrings.h" -#include "a_keys.h" -#include "a_sharedglobal.h" -#include "templates.h" -#include "d_event.h" -#include "v_font.h" -#include "serializer.h" -#include "p_spec.h" -#include "portal.h" - -// Include all the other Strife stuff here to reduce compile time -#include "a_acolyte.cpp" -#include "a_spectral.cpp" -#include "a_alienspectres.cpp" -#include "a_coin.cpp" -#include "a_crusader.cpp" -#include "a_entityboss.cpp" -#include "a_inquisitor.cpp" -#include "a_loremaster.cpp" -//#include "a_macil.cpp" -#include "a_oracle.cpp" -#include "a_programmer.cpp" -#include "a_reaver.cpp" -#include "a_rebels.cpp" -#include "a_sentinel.cpp" -#include "a_stalker.cpp" -#include "a_strifeitems.cpp" -#include "a_strifeweapons.cpp" -#include "a_templar.cpp" -#include "a_thingstoblowup.cpp" - -// Notes so I don't forget them: -// Strife does some extra stuff in A_Explode if a player caused the explosion. (probably NoiseAlert) -// See the instructions @ 21249. -// -// Strife's FLOATSPEED is 5 and not 4. -// -// In P_CheckMissileRange, mobjtypes 53,54,55,56,57,58 shift the distance right 4 bits (some, but not all the acolytes) -// mobjtypes 61,63,91 shift it right 1 bit -// -// When shooting missiles at something, if MF_SHADOW is set, the angle is adjusted with the formula: -// angle += pr_spawnmissile.Random2() << 21 -// When MF_STRIFEx4000000 is set, the angle is adjusted similarly: -// angle += pr_spawnmissile.Random2() << 22 -// Note that these numbers are different from those used by all the other Doom engine games. - -static FRandom pr_gibtosser ("GibTosser"); - -// Force Field Guard -------------------------------------------------------- - -void A_RemoveForceField (AActor *); - -class AForceFieldGuard : public AActor -{ - DECLARE_CLASS (AForceFieldGuard, AActor) -public: - int TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS (AForceFieldGuard) - -int AForceFieldGuard::TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype) -{ - if (inflictor == NULL || !inflictor->IsKindOf (RUNTIME_CLASS(ADegninOre))) - { - return -1; - } - return health; -} - -// Kneeling Guy ------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_SetShadow) -{ - PARAM_ACTION_PROLOGUE; - - self->flags |= MF_STRIFEx8000000|MF_SHADOW; - self->RenderStyle = STYLE_Translucent; - self->Alpha = HR_SHADOW; - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_ClearShadow) -{ - PARAM_ACTION_PROLOGUE; - - self->flags &= ~(MF_STRIFEx8000000|MF_SHADOW); - self->RenderStyle = STYLE_Normal; - self->Alpha = 1.; - return 0; -} - -static FRandom pr_gethurt ("HurtMe!"); - -DEFINE_ACTION_FUNCTION(AActor, A_GetHurt) -{ - PARAM_ACTION_PROLOGUE; - - self->flags4 |= MF4_INCOMBAT; - if ((pr_gethurt() % 5) == 0) - { - S_Sound (self, CHAN_VOICE, self->PainSound, 1, ATTN_NORM); - self->health--; - } - if (self->health <= 0) - { - self->Die (self->target, self->target); - } - return 0; -} - -// Klaxon Warning Light ----------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_TurretLook) -{ - PARAM_ACTION_PROLOGUE; - - AActor *target; - - if (self->flags5 & MF5_INCONVERSATION) - return 0; - - self->threshold = 0; - target = self->LastHeard; - if (target != NULL && - target->health > 0 && - target->flags & MF_SHOOTABLE && - (self->flags & MF_FRIENDLY) != (target->flags & MF_FRIENDLY)) - { - self->target = target; - if ((self->flags & MF_AMBUSH) && !P_CheckSight (self, target)) - { - return 0; - } - if (self->SeeSound != 0) - { - S_Sound (self, CHAN_VOICE, self->SeeSound, 1, ATTN_NORM); - } - self->LastHeard = NULL; - self->threshold = 10; - self->SetState (self->SeeState); - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_KlaxonBlare) -{ - PARAM_ACTION_PROLOGUE; - - if (--self->reactiontime < 0) - { - self->target = NULL; - self->reactiontime = self->GetDefault()->reactiontime; - CALL_ACTION(A_TurretLook, self); - if (self->target == NULL) - { - self->SetIdle(); - } - else - { - self->reactiontime = 50; - } - } - if (self->reactiontime == 2) - { - // [RH] Unalert monsters near the alarm and not just those in the same sector as it. - P_NoiseAlert (NULL, self, false); - } - else if (self->reactiontime > 50) - { - S_Sound (self, CHAN_VOICE, "misc/alarm", 1, ATTN_NORM); - } - return 0; -} - -// Power Coupling ----------------------------------------------------------- - -class APowerCoupling : public AActor -{ - DECLARE_CLASS (APowerCoupling, AActor) -public: - void Die (AActor *source, AActor *inflictor, int dmgflags); -}; - -IMPLEMENT_CLASS (APowerCoupling) - -void APowerCoupling::Die (AActor *source, AActor *inflictor, int dmgflags) -{ - Super::Die (source, inflictor, dmgflags); - - int i; - - for (i = 0; i < MAXPLAYERS; ++i) - if (playeringame[i] && players[i].health > 0) - break; - - if (i == MAXPLAYERS) - return; - - // [RH] In case the player broke it with the dagger, alert the guards now. - if (LastHeard != source) - { - P_NoiseAlert (source, this); - } - EV_DoDoor (DDoor::doorClose, NULL, players[i].mo, 225, 2., 0, 0, 0); - EV_DoFloor (DFloor::floorLowerToHighest, NULL, 44, 1., 0., -1, 0, false); - players[i].mo->GiveInventoryType (QuestItemClasses[5]); - S_Sound (CHAN_VOICE, "svox/voc13", 1, ATTN_NORM); - players[i].SetLogNumber (13); - P_DropItem (this, PClass::FindActor("BrokenPowerCoupling"), -1, 256); - Destroy (); -} - -// Gibs for things that bleed ----------------------------------------------- - -class AMeat : public AActor -{ - DECLARE_CLASS (AMeat, AActor) -public: - void BeginPlay () - { - // Strife used mod 19, but there are 20 states. Hmm. - SetState (SpawnState + pr_gibtosser() % 20); - } -}; - -IMPLEMENT_CLASS (AMeat) - -//========================================================================== -// -// A_TossGib -// -//========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_TossGib) -{ - PARAM_ACTION_PROLOGUE; - - const char *gibtype = (self->flags & MF_NOBLOOD) ? "Junk" : "Meat"; - AActor *gib = Spawn (gibtype, self->PosPlusZ(24.), ALLOW_REPLACE); - - if (gib == NULL) - { - return 0; - } - - gib->Angles.Yaw = pr_gibtosser() * (360 / 256.f); - gib->VelFromAngle(pr_gibtosser() & 15); - gib->Vel.Z = pr_gibtosser() & 15; - return 0; -} - -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FLoopActiveSound) -{ - PARAM_ACTION_PROLOGUE; - - if (self->ActiveSound != 0 && !(level.time & 7)) - { - S_Sound (self, CHAN_VOICE, self->ActiveSound, 1, ATTN_NORM); - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_Countdown) -{ - PARAM_ACTION_PROLOGUE; - - if (--self->reactiontime <= 0) - { - P_ExplodeMissile (self, NULL, NULL); - self->flags &= ~MF_SKULLFLY; - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_LoopActiveSound) -{ - PARAM_ACTION_PROLOGUE; - - if (self->ActiveSound != 0 && !S_IsActorPlayingSomething (self, CHAN_VOICE, -1)) - { - S_Sound (self, CHAN_VOICE|CHAN_LOOP, self->ActiveSound, 1, ATTN_NORM); - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain) -{ - PARAM_ACTION_PROLOGUE; - - sector_t *sec = self->Sector; - - if (self->Z() == sec->floorplane.ZatPoint(self) && sec->PortalBlocksMovement(sector_t::floor)) - { - if (sec->special == Damage_InstantDeath) - { - P_DamageMobj (self, NULL, NULL, 999, NAME_InstantDeath); - } - else if (sec->special == Scroll_StrifeCurrent) - { - int anglespeed = tagManager.GetFirstSectorTag(sec) - 100; - double speed = (anglespeed % 10) / 16.; - DAngle an = (anglespeed / 10) * (360 / 8.); - self->Thrust(an, speed); - } - } - return 0; -} - -//============================================================================ -// -// A_ClearSoundTarget -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_ClearSoundTarget) -{ - PARAM_ACTION_PROLOGUE; - - AActor *actor; - - self->Sector->SoundTarget = NULL; - for (actor = self->Sector->thinglist; actor != NULL; actor = actor->snext) - { - actor->LastHeard = NULL; - } - return 0; -} - - -DEFINE_ACTION_FUNCTION(AActor, A_ItBurnsItBurns) -{ - PARAM_ACTION_PROLOGUE; - - S_Sound (self, CHAN_VOICE, "human/imonfire", 1, ATTN_NORM); - - if (self->player != nullptr && self->player->mo == self) - { - P_SetPsprite(self->player, PSP_STRIFEHANDS, self->FindState("FireHands")); - - self->player->ReadyWeapon = nullptr; - self->player->PendingWeapon = WP_NOCHANGE; - self->player->playerstate = PST_LIVE; - self->player->extralight = 3; - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_DropFire) -{ - PARAM_ACTION_PROLOGUE; - - AActor *drop = Spawn("FireDroplet", self->PosPlusZ(24.), ALLOW_REPLACE); - drop->Vel.Z = -1.; - P_RadiusAttack (self, self, 64, 64, NAME_Fire, 0); - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_CrispyPlayer) -{ - PARAM_ACTION_PROLOGUE; - - if (self->player != nullptr && self->player->mo == self) - { - DPSprite *psp; - psp = self->player->GetPSprite(PSP_STRIFEHANDS); - - FState *firehandslower = self->FindState("FireHandsLower"); - FState *firehands = self->FindState("FireHands"); - FState *state = psp->GetState(); - - if (state != nullptr && firehandslower != nullptr && firehands != nullptr && firehands < firehandslower) - { - self->player->playerstate = PST_DEAD; - psp->SetState(state + (firehandslower - firehands)); - } - else if (state == nullptr) - { - psp->SetState(nullptr); - } - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_HandLower) -{ - PARAM_ACTION_PROLOGUE; - - if (self->player != nullptr) - { - DPSprite *psp = self->player->GetPSprite(PSP_STRIFEHANDS); - - if (psp->GetState() == nullptr) - { - psp->SetState(nullptr); - return 0; - } - - psp->y += 9; - if (psp->y > WEAPONBOTTOM*2) - { - psp->SetState(nullptr); - } - - if (self->player->extralight > 0) self->player->extralight--; - } - return 0; -} diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp deleted file mode 100644 index be3c3bf2bf..0000000000 --- a/src/g_strife/a_strifeweapons.cpp +++ /dev/null @@ -1,1187 +0,0 @@ -/* -#include "a_pickups.h" -#include "p_local.h" -#include "m_random.h" -#include "a_strifeglobal.h" -#include "s_sound.h" -#include "p_enemy.h" -#include "templates.h" -#include "thingdef/thingdef.h" -#include "doomstat.h" -*/ - -// Note: Strife missiles do 1-4 times their damage amount. -// Doom missiles do 1-8 times their damage amount, so to -// make the strife missiles do proper damage without -// hacking more stuff in the executable, be sure to give -// all Strife missiles the MF4_STRIFEDAMAGE flag. - -static FRandom pr_jabdagger ("JabDagger"); -static FRandom pr_electric ("FireElectric"); -static FRandom pr_sgunshot ("StrifeGunShot"); -static FRandom pr_minimissile ("MiniMissile"); -static FRandom pr_flamethrower ("FlameThrower"); -static FRandom pr_flamedie ("FlameDie"); -static FRandom pr_mauler1 ("Mauler1"); -static FRandom pr_mauler2 ("Mauler2"); -static FRandom pr_phburn ("PhBurn"); - -void A_LoopActiveSound (AActor *); -void A_Countdown (AActor *); - -// Punch Dagger ------------------------------------------------------------- - -//============================================================================ -// -// P_DaggerAlert -// -//============================================================================ - -void P_DaggerAlert (AActor *target, AActor *emitter) -{ - AActor *looker; - sector_t *sec = emitter->Sector; - - if (emitter->LastHeard != NULL) - return; - if (emitter->health <= 0) - return; - if (!(emitter->flags3 & MF3_ISMONSTER)) - return; - if (emitter->flags4 & MF4_INCOMBAT) - return; - emitter->flags4 |= MF4_INCOMBAT; - - emitter->target = target; - FState *painstate = emitter->FindState(NAME_Pain, NAME_Dagger); - if (painstate != NULL) - { - emitter->SetState (painstate); - } - - for (looker = sec->thinglist; looker != NULL; looker = looker->snext) - { - if (looker == emitter || looker == target) - continue; - - if (looker->health <= 0) - continue; - - if (!(looker->flags4 & MF4_SEESDAGGERS)) - continue; - - if (!(looker->flags4 & MF4_INCOMBAT)) - { - if (!P_CheckSight (looker, target) && !P_CheckSight (looker, emitter)) - continue; - - looker->target = target; - if (looker->SeeSound) - { - S_Sound (looker, CHAN_VOICE, looker->SeeSound, 1, ATTN_NORM); - } - looker->SetState (looker->SeeState); - looker->flags4 |= MF4_INCOMBAT; - } - } -} - -//============================================================================ -// -// A_JabDagger -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_JabDagger) -{ - PARAM_ACTION_PROLOGUE; - - DAngle angle; - int damage; - DAngle pitch; - int power; - FTranslatedLineTarget t; - - power = MIN(10, self->player->mo->stamina / 10); - damage = (pr_jabdagger() % (power + 8)) * (power + 2); - - if (self->FindInventory()) - { - damage *= 10; - } - - angle = self->Angles.Yaw + pr_jabdagger.Random2() * (5.625 / 256); - pitch = P_AimLineAttack (self, angle, 80.); - P_LineAttack (self, angle, 80., pitch, damage, NAME_Melee, "StrifeSpark", true, &t); - - // turn to face target - if (t.linetarget) - { - S_Sound (self, CHAN_WEAPON, - t.linetarget->flags & MF_NOBLOOD ? "misc/metalhit" : "misc/meathit", - 1, ATTN_NORM); - self->Angles.Yaw = t.angleFromSource; - self->flags |= MF_JUSTATTACKED; - P_DaggerAlert (self, t.linetarget); - } - else - { - S_Sound (self, CHAN_WEAPON, "misc/swish", 1, ATTN_NORM); - } - return 0; -} - -//============================================================================ -// -// A_AlertMonsters -// -//============================================================================ - -enum -{ - AMF_TARGETEMITTER = 1, - AMF_TARGETNONPLAYER = 2, - AMF_EMITFROMTARGET = 4, -}; - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_AlertMonsters) -{ - PARAM_ACTION_PROLOGUE; - PARAM_FLOAT_OPT(maxdist) { maxdist = 0; } - PARAM_INT_OPT(Flags) { Flags = 0; } - - AActor * target = NULL; - AActor * emitter = self; - - if (self->player != NULL || (Flags & AMF_TARGETEMITTER)) - { - target = self; - } - else if (self->target != NULL && (Flags & AMF_TARGETNONPLAYER)) - { - target = self->target; - } - else if (self->target != NULL && self->target->player != NULL) - { - target = self->target; - } - - if (Flags & AMF_EMITFROMTARGET) emitter = target; - - if (target != NULL && emitter != NULL) - { - P_NoiseAlert(target, emitter, false, maxdist); - } - return 0; -} - -// Poison Bolt -------------------------------------------------------------- - -class APoisonBolt : public AActor -{ - DECLARE_CLASS (APoisonBolt, AActor) -public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS (APoisonBolt) - -int APoisonBolt::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - if (target->flags & MF_NOBLOOD) - { - return -1; - } - if (target->health < 1000000) - { - if (!(target->flags2 & MF2_BOSS)) - return target->health + 10; - else - return 50; - } - return 1; -} - -// Strife's Crossbow -------------------------------------------------------- - -//============================================================================ -// -// A_ClearFlash -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_ClearFlash) -{ - PARAM_ACTION_PROLOGUE; - - player_t *player = self->player; - - if (player == nullptr) - return 0; - - P_SetPsprite (player, PSP_FLASH, nullptr); - return 0; -} - -//============================================================================ -// -// A_ShowElectricFlash -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_ShowElectricFlash) -{ - PARAM_ACTION_PROLOGUE; - - if (self->player != nullptr) - { - P_SetPsprite (self->player, PSP_FLASH, self->player->ReadyWeapon->FindState(NAME_Flash)); - } - return 0; -} - -//============================================================================ -// -// A_FireElectric -// -//============================================================================ - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireArrow) -{ - PARAM_ACTION_PROLOGUE; - PARAM_CLASS(ti, AActor); - - DAngle savedangle; - - if (self->player == NULL) - return 0; - - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - - if (ti) - { - savedangle = self->Angles.Yaw; - self->Angles.Yaw += pr_electric.Random2() * (5.625/256) * self->player->mo->AccuracyFactor(); - self->player->mo->PlayAttacking2 (); - P_SpawnPlayerMissile (self, ti); - self->Angles.Yaw = savedangle; - S_Sound (self, CHAN_WEAPON, "weapons/xbowshoot", 1, ATTN_NORM); - } - return 0; -} - -// Assault Gun -------------------------------------------------------------- - -//============================================================================ -// -// P_StrifeGunShot -// -//============================================================================ - -void P_StrifeGunShot (AActor *mo, bool accurate, DAngle pitch) -{ - DAngle angle; - int damage; - - damage = 4*(pr_sgunshot()%3+1); - angle = mo->Angles.Yaw; - - if (mo->player != NULL && !accurate) - { - angle += pr_sgunshot.Random2() * (22.5 / 256) * mo->player->mo->AccuracyFactor(); - } - - P_LineAttack (mo, angle, PLAYERMISSILERANGE, pitch, damage, NAME_Hitscan, NAME_StrifePuff); -} - -//============================================================================ -// -// A_FireAssaultGun -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireAssaultGun) -{ - PARAM_ACTION_PROLOGUE; - - bool accurate; - - S_Sound (self, CHAN_WEAPON, "weapons/assaultgun", 1, ATTN_NORM); - - if (self->player != NULL) - { - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - self->player->mo->PlayAttacking2 (); - accurate = !self->player->refire; - } - else - { - accurate = true; - } - - P_StrifeGunShot (self, accurate, P_BulletSlope (self)); - return 0; -} - -// Mini-Missile Launcher ---------------------------------------------------- - -//============================================================================ -// -// A_FireMiniMissile -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireMiniMissile) -{ - PARAM_ACTION_PROLOGUE; - - player_t *player = self->player; - DAngle savedangle; - - if (self->player == NULL) - return 0; - - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - - savedangle = self->Angles.Yaw; - self->Angles.Yaw += pr_minimissile.Random2() * (11.25 / 256) * player->mo->AccuracyFactor(); - player->mo->PlayAttacking2 (); - P_SpawnPlayerMissile (self, PClass::FindActor("MiniMissile")); - self->Angles.Yaw = savedangle; - return 0; -} - -//============================================================================ -// -// A_RocketInFlight -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_RocketInFlight) -{ - PARAM_ACTION_PROLOGUE; - - AActor *trail; - - S_Sound (self, CHAN_VOICE, "misc/missileinflight", 1, ATTN_NORM); - P_SpawnPuff (self, PClass::FindActor("MiniMissilePuff"), self->Pos(), self->Angles.Yaw - 180, self->Angles.Yaw - 180, 2, PF_HITTHING); - trail = Spawn("RocketTrail", self->Vec3Offset(-self->Vel.X, -self->Vel.Y, 0.), ALLOW_REPLACE); - if (trail != NULL) - { - trail->Vel.Z = 1; - } - return 0; -} - -// Flame Thrower ------------------------------------------------------------ - -//============================================================================ -// -// A_FlameDie -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FlameDie) -{ - PARAM_ACTION_PROLOGUE; - - self->flags |= MF_NOGRAVITY; - self->Vel.Z = pr_flamedie() & 3; - return 0; -} - -//============================================================================ -// -// A_FireFlamer -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireFlamer) -{ - PARAM_ACTION_PROLOGUE; - - player_t *player = self->player; - - if (player != NULL) - { - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - player->mo->PlayAttacking2 (); - } - - self->Angles.Yaw += pr_flamethrower.Random2() * (5.625/256.); - self = P_SpawnPlayerMissile (self, PClass::FindActor("FlameMissile")); - if (self != NULL) - { - self->Vel.Z += 5; - } - return 0; -} - -// Mauler ------------------------------------------------------------------- - -//============================================================================ -// -// A_FireMauler1 -// -// Hey! This is exactly the same as a super shotgun except for the sound -// and the bullet puffs and the disintegration death. -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireMauler1) -{ - PARAM_ACTION_PROLOGUE; - - if (self->player != NULL) - { - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - // Strife apparently didn't show the player shooting. Let's fix that. - self->player->mo->PlayAttacking2 (); - } - - S_Sound (self, CHAN_WEAPON, "weapons/mauler1", 1, ATTN_NORM); - - - DAngle bpitch = P_BulletSlope (self); - - for (int i = 0; i < 20; ++i) - { - int damage = 5 * (pr_mauler1() % 3 + 1); - DAngle angle = self->Angles.Yaw + pr_mauler1.Random2() * (11.25 / 256); - DAngle pitch = bpitch + pr_mauler1.Random2() * (7.097 / 256); - - // Strife used a range of 2112 units for the mauler to signal that - // it should use a different puff. ZDoom's default range is longer - // than this, so let's not handicap it by being too faithful to the - // original. - P_LineAttack (self, angle, PLAYERMISSILERANGE, pitch, damage, NAME_Hitscan, NAME_MaulerPuff); - } - return 0; -} - -//============================================================================ -// -// A_FireMauler2Pre -// -// Makes some noise and moves the psprite. -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireMauler2Pre) -{ - PARAM_ACTION_PROLOGUE; - - S_Sound (self, CHAN_WEAPON, "weapons/mauler2charge", 1, ATTN_NORM); - - if (self->player != nullptr) - { - self->player->GetPSprite(PSP_WEAPON)->x += pr_mauler2.Random2() / 64.; - self->player->GetPSprite(PSP_WEAPON)->y += pr_mauler2.Random2() / 64.; - } - return 0; -} - -//============================================================================ -// -// A_FireMauler2Pre -// -// Fires the torpedo. -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireMauler2) -{ - PARAM_ACTION_PROLOGUE; - - if (self->player != NULL) - { - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != NULL) - { - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - } - self->player->mo->PlayAttacking2 (); - } - P_SpawnPlayerMissile (self, PClass::FindActor("MaulerTorpedo")); - P_DamageMobj (self, self, NULL, 20, self->DamageType); - self->Thrust(self->Angles.Yaw+180., 7.8125); - return 0; -} - -//============================================================================ -// -// A_MaulerTorpedoWave -// -// Launches lots of balls when the torpedo hits something. -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_MaulerTorpedoWave) -{ - PARAM_ACTION_PROLOGUE; - - AActor *wavedef = GetDefaultByName("MaulerTorpedoWave"); - double savedz; - self->Angles.Yaw += 180.; - - // If the torpedo hit the ceiling, it should still spawn the wave - savedz = self->Z(); - if (wavedef && self->ceilingz < self->Z() + wavedef->Height) - { - self->SetZ(self->ceilingz - wavedef->Height); - } - - for (int i = 0; i < 80; ++i) - { - self->Angles.Yaw += 4.5; - P_SpawnSubMissile (self, PClass::FindActor("MaulerTorpedoWave"), self->target); - } - self->SetZ(savedz); - return 0; -} - -AActor *P_SpawnSubMissile (AActor *source, PClassActor *type, AActor *target) -{ - AActor *other = Spawn (type, source->Pos(), ALLOW_REPLACE); - - if (other == NULL) - { - return NULL; - } - - other->target = target; - other->Angles.Yaw = source->Angles.Yaw; - other->VelFromAngle(); - - if (other->flags4 & MF4_SPECTRAL) - { - if (source->flags & MF_MISSILE && source->flags4 & MF4_SPECTRAL) - { - other->FriendPlayer = source->FriendPlayer; - } - else - { - other->SetFriendPlayer(target->player); - } - } - - if (P_CheckMissileSpawn (other, source->radius)) - { - DAngle pitch = P_AimLineAttack (source, source->Angles.Yaw, 1024.); - other->Vel.Z = -other->Speed * pitch.Sin(); - return other; - } - return NULL; -} - -class APhosphorousFire : public AActor -{ - DECLARE_CLASS (APhosphorousFire, AActor) -public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); -}; - -IMPLEMENT_CLASS (APhosphorousFire) - -int APhosphorousFire::DoSpecialDamage (AActor *target, int damage, FName damagetype) -{ - if (target->flags & MF_NOBLOOD) - { - return damage / 2; - } - return Super::DoSpecialDamage (target, damage, damagetype); -} - -DEFINE_ACTION_FUNCTION(AActor, A_BurnArea) -{ - PARAM_ACTION_PROLOGUE; - - P_RadiusAttack (self, self->target, 128, 128, self->DamageType, RADF_HURTSOURCE); - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_Burnination) -{ - PARAM_ACTION_PROLOGUE; - - self->Vel.Z -= 8; - self->Vel.X += (pr_phburn.Random2 (3)); - self->Vel.Y += (pr_phburn.Random2 (3)); - S_Sound (self, CHAN_VOICE, "world/largefire", 1, ATTN_NORM); - - // Only the main fire spawns more. - if (!(self->flags & MF_DROPPED)) - { - // Original x and y offsets seemed to be like this: - // x + (((pr_phburn() + 12) & 31) << F.RACBITS); - // - // But that creates a lop-sided burn because it won't use negative offsets. - int xofs, xrand = pr_phburn(); - int yofs, yrand = pr_phburn(); - - // Adding 12 is pointless if you're going to mask it afterward. - xofs = xrand & 31; - if (xrand & 128) - { - xofs = -xofs; - } - - yofs = yrand & 31; - if (yrand & 128) - { - yofs = -yofs; - } - - DVector2 pos = self->Vec2Offset((double)xofs, (double)yofs); - sector_t * sector = P_PointInSector(pos); - - // The sector's floor is too high so spawn the flame elsewhere. - if (sector->floorplane.ZatPoint(pos) > self->Z() + self->MaxStepHeight) - { - pos = self->Pos(); - } - - AActor *drop = Spawn (DVector3(pos, self->Z() + 4.), ALLOW_REPLACE); - if (drop != NULL) - { - drop->Vel.X = self->Vel.X + pr_phburn.Random2 (7); - drop->Vel.Y = self->Vel.Y + pr_phburn.Random2 (7); - drop->Vel.Z = self->Vel.Z - 1; - drop->reactiontime = (pr_phburn() & 3) + 2; - drop->flags |= MF_DROPPED; - } - } - return 0; -} - -//============================================================================ -// -// A_FireGrenade -// -//============================================================================ - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireGrenade) -{ - PARAM_ACTION_PROLOGUE; - PARAM_CLASS(grenadetype, AActor); - PARAM_ANGLE(angleofs); - PARAM_STATE(flash) - - player_t *player = self->player; - AActor *grenade; - DAngle an; - AWeapon *weapon; - - if (player == nullptr || grenadetype == nullptr) - return 0; - - if ((weapon = player->ReadyWeapon) == nullptr) - return 0; - - if (!weapon->DepleteAmmo (weapon->bAltFire)) - return 0; - - P_SetPsprite (player, PSP_FLASH, flash, true); - - if (grenadetype != nullptr) - { - self->AddZ(32); - grenade = P_SpawnSubMissile (self, grenadetype, self); - self->AddZ(-32); - if (grenade == nullptr) - return 0; - - if (grenade->SeeSound != 0) - { - S_Sound (grenade, CHAN_VOICE, grenade->SeeSound, 1, ATTN_NORM); - } - - grenade->Vel.Z = (-self->Angles.Pitch.TanClamped()) * grenade->Speed + 8; - - DVector2 offset = self->Angles.Yaw.ToVector(self->radius + grenade->radius); - DAngle an = self->Angles.Yaw + angleofs; - offset += an.ToVector(15); - grenade->SetOrigin(grenade->Vec3Offset(offset.X, offset.Y, 0.), false); - } - return 0; -} - -// The Almighty Sigil! ------------------------------------------------------ - -IMPLEMENT_CLASS(ASigil) - -//============================================================================ -// -// ASigil :: Serialize -// -//============================================================================ - -void ASigil::BeginPlay() -{ - NumPieces = health; -} - -//============================================================================ -// -// ASigil :: Serialize -// -//============================================================================ - -void ASigil::Serialize(FSerializer &arc) -{ - Super::Serialize (arc); - arc("numpieces", NumPieces) - ("downpieces", DownPieces); -} - -//============================================================================ -// -// ASigil :: HandlePickup -// -//============================================================================ - -bool ASigil::HandlePickup (AInventory *item) -{ - if (item->IsKindOf (RUNTIME_CLASS(ASigil))) - { - int otherPieces = static_cast(item)->NumPieces; - if (otherPieces > NumPieces) - { - item->ItemFlags |= IF_PICKUPGOOD; - Icon = item->Icon; - // If the player is holding the Sigil right now, drop it and bring - // it back with the new piece(s) in view. - if (Owner->player != NULL && Owner->player->ReadyWeapon == this) - { - DownPieces = NumPieces; - Owner->player->PendingWeapon = this; - } - NumPieces = otherPieces; - } - return true; - } - if (Inventory != NULL) - { - return Inventory->HandlePickup (item); - } - return false; -} - -//============================================================================ -// -// ASigil :: CreateCopy -// -//============================================================================ - -AInventory *ASigil::CreateCopy (AActor *other) -{ - ASigil *copy = Spawn (); - copy->Amount = Amount; - copy->MaxAmount = MaxAmount; - copy->NumPieces = NumPieces; - copy->Icon = Icon; - GoAwayAndDie (); - return copy; -} - -//============================================================================ -// -// A_SelectPiece -// -// Decide which sprite frame this Sigil should use as an item, based on how -// many pieces it represents. -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SelectPiece) -{ - PARAM_ACTION_PROLOGUE; - - int pieces = MIN (static_cast(self)->NumPieces, 5); - - if (pieces > 1) - { - self->SetState (self->FindState("Spawn")+pieces); - } - return 0; -} - -//============================================================================ -// -// A_SelectSigilView -// -// Decide which first-person frame this Sigil should show, based on how many -// pieces it represents. Strife did this by selecting a flash that looked like -// the Sigil whenever you switched to it and at the end of an attack. I have -// chosen to make the weapon sprite choose the correct frame and let the flash -// be a regular flash. It means I need to use more states, but I think it's -// worth it. -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilView) -{ - PARAM_ACTION_PROLOGUE; - - DPSprite *pspr; - int pieces; - - if (self->player == nullptr) - { - return 0; - } - pieces = static_cast(self->player->ReadyWeapon)->NumPieces; - pspr = self->player->GetPSprite(PSP_WEAPON); - pspr->SetState(pspr->GetState() + pieces); - return 0; -} - -//============================================================================ -// -// A_SelectSigilDown -// -// Same as A_SelectSigilView, except it uses DownPieces. This is so that when -// you pick up a Sigil, the old one will drop and *then* change to the new -// one. -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilDown) -{ - PARAM_ACTION_PROLOGUE; - - DPSprite *pspr; - int pieces; - - if (self->player == nullptr) - { - return 0; - } - pieces = static_cast(self->player->ReadyWeapon)->DownPieces; - static_cast(self->player->ReadyWeapon)->DownPieces = 0; - if (pieces == 0) - { - pieces = static_cast(self->player->ReadyWeapon)->NumPieces; - } - pspr = self->player->GetPSprite(PSP_WEAPON); - pspr->SetState(pspr->GetState() + pieces); - return 0; -} - -//============================================================================ -// -// A_SelectSigilAttack -// -// Same as A_SelectSigilView, but used just before attacking. -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilAttack) -{ - PARAM_ACTION_PROLOGUE; - - DPSprite *pspr; - int pieces; - - if (self->player == nullptr) - { - return 0; - } - pieces = static_cast(self->player->ReadyWeapon)->NumPieces; - pspr = self->player->GetPSprite(PSP_WEAPON); - pspr->SetState(pspr->GetState() + 4*pieces - 3); - return 0; -} - -//============================================================================ -// -// A_SigilCharge -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SigilCharge) -{ - PARAM_ACTION_PROLOGUE; - - S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); - if (self->player != NULL) - { - self->player->extralight = 2; - } - return 0; -} - -//============================================================================ -// -// A_LightInverse -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_LightInverse) -{ - PARAM_ACTION_PROLOGUE; - - if (self->player != NULL) - { - self->player->extralight = INT_MIN; - } - return 0; -} - -//============================================================================ -// -// A_FireSigil1 -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireSigil1) -{ - PARAM_ACTION_PROLOGUE; - - AActor *spot; - player_t *player = self->player; - FTranslatedLineTarget t; - - if (player == NULL || player->ReadyWeapon == NULL) - return 0; - - P_DamageMobj (self, self, NULL, 1*4, 0, DMG_NO_ARMOR); - S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); - - P_BulletSlope (self, &t, ALF_PORTALRESTRICT); - if (t.linetarget != NULL) - { - spot = Spawn("SpectralLightningSpot", t.linetarget->PosAtZ(t.linetarget->floorz), ALLOW_REPLACE); - if (spot != NULL) - { - spot->tracer = t.linetarget; - } - } - else - { - spot = Spawn("SpectralLightningSpot", self->Pos(), ALLOW_REPLACE); - if (spot != NULL) - { - spot->VelFromAngle(self->Angles.Yaw, 28.); - } - } - if (spot != NULL) - { - spot->SetFriendPlayer(player); - spot->target = self; - } - return 0; -} - -//============================================================================ -// -// A_FireSigil2 -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireSigil2) -{ - PARAM_ACTION_PROLOGUE; - - player_t *player = self->player; - - if (player == NULL || player->ReadyWeapon == NULL) - return 0; - - P_DamageMobj (self, self, NULL, 2*4, 0, DMG_NO_ARMOR); - S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); - - P_SpawnPlayerMissile (self, PClass::FindActor("SpectralLightningH1")); - return 0; -} - -//============================================================================ -// -// A_FireSigil3 -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireSigil3) -{ - PARAM_ACTION_PROLOGUE; - - AActor *spot; - player_t *player = self->player; - int i; - - if (player == NULL || player->ReadyWeapon == NULL) - return 0; - - P_DamageMobj (self, self, NULL, 3*4, 0, DMG_NO_ARMOR); - S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); - - self->Angles.Yaw -= 90.; - for (i = 0; i < 20; ++i) - { - self->Angles.Yaw += 9.; - spot = P_SpawnSubMissile (self, PClass::FindActor("SpectralLightningBall1"), self); - if (spot != NULL) - { - spot->SetZ(self->Z() + 32); - } - } - self->Angles.Yaw -= 90.; - return 0; -} - -//============================================================================ -// -// A_FireSigil4 -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireSigil4) -{ - PARAM_ACTION_PROLOGUE; - - AActor *spot; - player_t *player = self->player; - FTranslatedLineTarget t; - - if (player == NULL || player->ReadyWeapon == NULL) - return 0; - - P_DamageMobj (self, self, NULL, 4*4, 0, DMG_NO_ARMOR); - S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); - - P_BulletSlope (self, &t, ALF_PORTALRESTRICT); - if (t.linetarget != NULL) - { - spot = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindActor("SpectralLightningBigV1"), self->Angles.Yaw, &t, NULL, false, false, ALF_PORTALRESTRICT); - if (spot != NULL) - { - spot->tracer = t.linetarget; - } - } - else - { - spot = P_SpawnPlayerMissile (self, PClass::FindActor("SpectralLightningBigV1")); - if (spot != NULL) - { - spot->VelFromAngle(self->Angles.Yaw, spot->Speed); - } - } - return 0; -} - -//============================================================================ -// -// A_FireSigil5 -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FireSigil5) -{ - PARAM_ACTION_PROLOGUE; - - player_t *player = self->player; - - if (player == NULL || player->ReadyWeapon == NULL) - return 0; - - P_DamageMobj (self, self, NULL, 5*4, 0, DMG_NO_ARMOR); - S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM); - - P_SpawnPlayerMissile (self, PClass::FindActor("SpectralLightningBigBall1")); - return 0; -} - -//============================================================================ -// -// ASigil :: SpecialDropAction -// -// Monsters don't drop Sigil pieces. The Sigil pieces grab hold of the person -// who killed the dropper and automatically enter their inventory. That's the -// way it works if you believe Macil, anyway... -// -//============================================================================ - -bool ASigil::SpecialDropAction (AActor *dropper) -{ - // Give a Sigil piece to every player in the game - for (int i = 0; i < MAXPLAYERS; ++i) - { - if (playeringame[i] && players[i].mo != NULL) - { - GiveSigilPiece (players[i].mo); - Destroy (); - } - } - return true; -} - -//============================================================================ -// -// ASigil :: GiveSigilPiece -// -// Gives the actor another Sigil piece, up to 5. Returns the number of Sigil -// pieces the actor previously held. -// -//============================================================================ - -int ASigil::GiveSigilPiece (AActor *receiver) -{ - ASigil *sigil; - - sigil = receiver->FindInventory (); - if (sigil == NULL) - { - sigil = static_cast(Spawn("Sigil1")); - if (!sigil->CallTryPickup (receiver)) - { - sigil->Destroy (); - } - return 0; - } - else if (sigil->NumPieces < 5) - { - ++sigil->NumPieces; - static const char* sigils[5] = - { - "Sigil1", "Sigil2", "Sigil3", "Sigil4", "Sigil5" - }; - sigil->Icon = ((AInventory*)GetDefaultByName (sigils[MAX(0,sigil->NumPieces-1)]))->Icon; - // If the player has the Sigil out, drop it and bring it back up. - if (sigil->Owner->player != NULL && sigil->Owner->player->ReadyWeapon == sigil) - { - sigil->Owner->player->PendingWeapon = sigil; - sigil->DownPieces = sigil->NumPieces - 1; - } - return sigil->NumPieces - 1; - } - else - { - return 5; - } -} diff --git a/src/g_strife/a_templar.cpp b/src/g_strife/a_templar.cpp deleted file mode 100644 index 547d4d73e6..0000000000 --- a/src/g_strife/a_templar.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* -#include "actor.h" -#include "m_random.h" -#include "a_action.h" -#include "p_local.h" -#include "p_enemy.h" -#include "s_sound.h" -#include "a_strifeglobal.h" -#include "thingdef/thingdef.h" -*/ - -static FRandom pr_templar ("Templar"); - -DEFINE_ACTION_FUNCTION(AActor, A_TemplarAttack) -{ - PARAM_ACTION_PROLOGUE; - - int damage; - DAngle angle; - DAngle pitch; - - if (self->target == NULL) - return 0; - - S_Sound (self, CHAN_WEAPON, "templar/shoot", 1, ATTN_NORM); - A_FaceTarget (self); - pitch = P_AimLineAttack (self, self->Angles.Yaw, MISSILERANGE); - - for (int i = 0; i < 10; ++i) - { - damage = (pr_templar() & 4) * 2; - angle = self->Angles.Yaw + pr_templar.Random2() * (11.25 / 256); - P_LineAttack (self, angle, MISSILERANGE+64., pitch + pr_templar.Random2() * (7.097 / 256), damage, NAME_Hitscan, NAME_MaulerPuff); - } - return 0; -} diff --git a/src/g_strife/a_thingstoblowup.cpp b/src/g_strife/a_thingstoblowup.cpp deleted file mode 100644 index fed1c43371..0000000000 --- a/src/g_strife/a_thingstoblowup.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* -#include "actor.h" -#include "m_random.h" -#include "p_local.h" -#include "c_console.h" -#include "p_enemy.h" -#include "a_action.h" -#include "gstrings.h" -#include "thingdef/thingdef.h" -#include "thingdef/thingdef.h" -#include "doomstat.h" -*/ - -static FRandom pr_bang4cloud ("Bang4Cloud"); -static FRandom pr_lightout ("LightOut"); - -DEFINE_ACTION_FUNCTION(AActor, A_Bang4Cloud) -{ - PARAM_ACTION_PROLOGUE; - - double xo = (pr_bang4cloud.Random2() & 3) * (10. / 64); - double yo = (pr_bang4cloud.Random2() & 3) * (10. / 64); - Spawn("Bang4Cloud", self->Vec3Offset(xo, yo, 0.), ALLOW_REPLACE); - return 0; -} - -// ------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveQuestItem) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_INT(questitem); - - // Give one of these quest items to every player in the game - if (questitem >= 0 && questitem < (int)countof(QuestItemClasses)) - { - for (int i = 0; i < MAXPLAYERS; ++i) - { - if (playeringame[i]) - { - AInventory *item = static_cast(Spawn (QuestItemClasses[questitem - 1])); - if (!item->CallTryPickup (players[i].mo)) - { - item->Destroy (); - } - } - } - } - - char messageid[64]; - - mysnprintf(messageid, countof(messageid), "TXT_QUEST_%d", questitem); - const char * name = GStrings[messageid]; - - if (name != NULL) - { - C_MidPrint (SmallFont, name); - } - return 0; -} - -// PowerCrystal ------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_ExtraLightOff) -{ - PARAM_ACTION_PROLOGUE; - - if (self->target != NULL && self->target->player != NULL) - { - self->target->player->extralight = 0; - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_Explode512) -{ - PARAM_ACTION_PROLOGUE; - - P_RadiusAttack (self, self->target, 512, 512, NAME_None, RADF_HURTSOURCE); - if (self->target != NULL && self->target->player != NULL) - { - self->target->player->extralight = 5; - } - P_CheckSplash(self, 512); - - // Strife didn't do this next part, but it looks good - self->RenderStyle = STYLE_Add; - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_LightGoesOut) -{ - PARAM_ACTION_PROLOGUE; - - AActor *foo; - sector_t *sec = self->Sector; - vertex_t *spot; - double newheight; - - sec->SetLightLevel(0); - - double oldtheight = sec->floorplane.fD(); - newheight = sec->FindLowestFloorSurrounding(&spot); - sec->floorplane.setD(sec->floorplane.PointToDist (spot, newheight)); - double newtheight = sec->floorplane.fD(); - sec->ChangePlaneTexZ(sector_t::floor, newtheight - oldtheight); - sec->CheckPortalPlane(sector_t::floor); - - for (int i = 0; i < 8; ++i) - { - foo = Spawn("Rubble1", self->Pos(), ALLOW_REPLACE); - if (foo != NULL) - { - int t = pr_lightout() & 15; - foo->Vel.X = t - (pr_lightout() & 7); - foo->Vel.Y = pr_lightout.Random2() & 7; - foo->Vel.Z = 7 + (pr_lightout() & 3); - } - } - return 0; -} diff --git a/src/g_strife/strife_sbar.cpp b/src/g_strife/strife_sbar.cpp index bcdf624d7b..973364cf7d 100644 --- a/src/g_strife/strife_sbar.cpp +++ b/src/g_strife/strife_sbar.cpp @@ -12,11 +12,13 @@ #include "m_swap.h" #include "templates.h" #include "a_keys.h" -#include "a_strifeglobal.h" +#include "a_armor.h" +#include "a_ammo.h" #include "gi.h" #include "g_level.h" #include "colormatcher.h" #include "v_palette.h" +#include "cmdlib.h" // Number of tics to move the popscreen up and down. #define POP_TIME (TICRATE/8) @@ -438,7 +440,7 @@ private: } // Sigil - item = CPlayer->mo->FindInventory(); + item = CPlayer->mo->FindInventory(PClass::FindActor(NAME_Sigil)); if (item != NULL) { DrawImage (TexMan(item->Icon), 253, 7); @@ -850,7 +852,7 @@ private: double ItemFlash; }; -IMPLEMENT_CLASS(DStrifeStatusBar); +IMPLEMENT_CLASS(DStrifeStatusBar, false, false); DBaseStatusBar *CreateStrifeStatusBar () { diff --git a/src/gl/data/gl_data.cpp b/src/gl/data/gl_data.cpp index 67111ec924..606459c7e0 100644 --- a/src/gl/data/gl_data.cpp +++ b/src/gl/data/gl_data.cpp @@ -93,29 +93,30 @@ void gl_CreateSections(); void AdjustSpriteOffsets() { - static bool done=false; - char name[30]; - - if (done) return; - done=true; - - mysnprintf(name, countof(name), "sprofs/%s.sprofs", GameNames[gameinfo.gametype]); - int lump = Wads.CheckNumForFullName(name); - if (lump>=0) + int lump, lastlump = 0; + while ((lump = Wads.FindLump("SPROFS", &lastlump, false)) != -1) { FScanner sc; sc.OpenLumpNum(lump); + sc.SetCMode(true); GLRenderer->FlushTextures(); int ofslumpno = Wads.GetLumpFile(lump); while (sc.GetString()) { int x,y; + bool iwadonly = false; FTextureID texno = TexMan.CheckForTexture(sc.String, FTexture::TEX_Sprite); - sc.GetNumber(); + sc.MustGetStringName(","); + sc.MustGetNumber(); x=sc.Number; - sc.GetNumber(); + sc.MustGetStringName(","); + sc.MustGetNumber(); y=sc.Number; - + if (sc.CheckString(",")) + { + sc.MustGetString(); + if (sc.Compare("iwad")) iwadonly = true; + } if (texno.isValid()) { FTexture * tex = TexMan[texno]; @@ -125,7 +126,7 @@ void AdjustSpriteOffsets() if (lumpnum >= 0 && lumpnum < Wads.GetNumLumps()) { int wadno = Wads.GetLumpFile(lumpnum); - if (wadno==FWadCollection::IWAD_FILENUM || wadno == ofslumpno) + if ((iwadonly && wadno==FWadCollection::IWAD_FILENUM) || (!iwadonly && wadno == ofslumpno)) { tex->LeftOffset=x; tex->TopOffset=y; diff --git a/src/gl/dynlights/a_dynlight.cpp b/src/gl/dynlights/a_dynlight.cpp index 84e1d9ab1b..45e8bfb14f 100644 --- a/src/gl/dynlights/a_dynlight.cpp +++ b/src/gl/dynlights/a_dynlight.cpp @@ -62,7 +62,7 @@ #include "p_local.h" #include "c_dispatch.h" #include "g_level.h" -#include "thingdef/thingdef.h" +#include "scripting/thingdef.h" #include "i_system.h" #include "templates.h" #include "doomdata.h" @@ -107,10 +107,10 @@ DEFINE_CLASS_PROPERTY(type, S, DynamicLight) // which is controlled by flags // //========================================================================== -IMPLEMENT_CLASS (ADynamicLight) -IMPLEMENT_CLASS (AVavoomLight) -IMPLEMENT_CLASS (AVavoomLightWhite) -IMPLEMENT_CLASS (AVavoomLightColor) +IMPLEMENT_CLASS (ADynamicLight, false, false) +IMPLEMENT_CLASS (AVavoomLight, false, false) +IMPLEMENT_CLASS (AVavoomLightWhite, false, false) +IMPLEMENT_CLASS (AVavoomLightColor, false, false) void AVavoomLight::BeginPlay () { diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 52339e5870..6d080434dc 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -40,7 +40,6 @@ #include "sbar.h" #include "po_man.h" #include "r_utility.h" -#include "a_hexenglobal.h" #include "p_local.h" #include "colormatcher.h" #include "gl/gl_functions.h" diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 1437d3fd5d..0cf0fa0a1e 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -40,7 +40,6 @@ #include "sbar.h" #include "po_man.h" #include "r_utility.h" -#include "a_hexenglobal.h" #include "p_local.h" #include "gl/gl_functions.h" #include "serializer.h" diff --git a/src/gl/system/gl_framebuffer.cpp b/src/gl/system/gl_framebuffer.cpp index 4904cc1f6f..f20c9e5024 100644 --- a/src/gl/system/gl_framebuffer.cpp +++ b/src/gl/system/gl_framebuffer.cpp @@ -53,7 +53,7 @@ #include "gl/renderer/gl_2ddrawer.h" #include "gl_debug.h" -IMPLEMENT_CLASS(OpenGLFrameBuffer) +IMPLEMENT_CLASS(OpenGLFrameBuffer, false, false) EXTERN_CVAR (Float, vid_brightness) EXTERN_CVAR (Float, vid_contrast) EXTERN_CVAR (Bool, vid_vsync) @@ -207,17 +207,20 @@ void OpenGLFrameBuffer::Update() // //========================================================================== +CVAR(Bool, gl_finishbeforeswap, false, 0); + void OpenGLFrameBuffer::Swap() { Finish.Reset(); Finish.Clock(); - if (needsetgamma) + if (gl_finishbeforeswap) glFinish(); + if (needsetgamma) { //DoSetGamma(); needsetgamma = false; } SwapBuffers(); - glFinish(); + if (!gl_finishbeforeswap) glFinish(); Finish.Unclock(); swapped = true; FHardwareTexture::UnbindAll(); diff --git a/src/info.cpp b/src/info.cpp index 79c8e4268e..d3cb4e2743 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -43,7 +43,6 @@ #include "v_text.h" #include "gi.h" -#include "vm.h" #include "actor.h" #include "r_state.h" #include "i_system.h" @@ -52,8 +51,9 @@ #include "cmdlib.h" #include "g_level.h" #include "stats.h" -#include "thingdef/thingdef.h" +#include "thingdef.h" #include "d_player.h" +#include "doomerrors.h" extern void LoadActors (); extern void InitBotStuff(); @@ -66,7 +66,7 @@ cycle_t ActionCycles; void FState::SetAction(const char *name) { - ActionFunc = FindGlobalActionFunction(name)->Variants[0].Implementation; + ActionFunc = FindVMFunction(RUNTIME_CLASS(AActor), name); } bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, FState **stateret) @@ -75,8 +75,7 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, { ActionCycles.Clock(); - static VMFrameStack stack; - VMValue params[3] = { self, stateowner, VMValue(info, ATAG_STATEINFO) }; + VMValue params[3] = { self, stateowner, VMValue(info, ATAG_GENERIC) }; // If the function returns a state, store it at *stateret. // If it doesn't return a state but stateret is non-NULL, we need // to set *stateret to NULL. @@ -90,16 +89,35 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, stateret = NULL; } } - if (stateret == NULL) + try { - stack.Call(ActionFunc, params, countof(params), NULL, 0, NULL); + if (stateret == NULL) + { + GlobalVMStack.Call(ActionFunc, params, ActionFunc->ImplicitArgs, NULL, 0, NULL); + } + else + { + VMReturn ret; + ret.PointerAt((void **)stateret); + GlobalVMStack.Call(ActionFunc, params, ActionFunc->ImplicitArgs, &ret, 1, NULL); + } } - else + catch (CVMAbortException &err) { - VMReturn ret; - ret.PointerAt((void **)stateret); - stack.Call(ActionFunc, params, countof(params), &ret, 1, NULL); + err.MaybePrintMessage(); + auto owner = FState::StaticFindStateOwner(this); + int offs = int(this - owner->OwnedStates); + const char *callinfo = ""; + if (info != nullptr && info->mStateType == STATE_Psprite) + { + if (stateowner->IsKindOf(RUNTIME_CLASS(AWeapon)) && stateowner != self) callinfo = "weapon "; + else callinfo = "overlay "; + } + err.stacktrace.AppendFormat("Called from %sstate %s.%d in %s\n", callinfo, owner->TypeName.GetChars(), offs, stateowner->GetClass()->TypeName.GetChars()); + throw; + throw; } + ActionCycles.Unclock(); return true; } @@ -151,9 +169,18 @@ int GetSpriteIndex(const char * spritename, bool add) return (lastindex = (int)sprites.Push (temp)); } -IMPLEMENT_POINTY_CLASS(PClassActor) - DECLARE_POINTER(DropItems) -END_POINTERS +DEFINE_ACTION_FUNCTION(AActor, GetSpriteIndex) +{ + PARAM_PROLOGUE; + PARAM_NAME(sprt); + ACTION_RETURN_INT(GetSpriteIndex(sprt.GetChars(), false)); +} + +IMPLEMENT_CLASS(PClassActor, false, true) + +IMPLEMENT_POINTERS_START(PClassActor) + IMPLEMENT_POINTER(DropItems) +IMPLEMENT_POINTERS_END //========================================================================== // @@ -228,7 +255,6 @@ PClassActor::PClassActor() BurnHeight = -1; GibHealth = INT_MIN; WoundHealth = 6; - PoisonDamage = 0; FastSpeed = -1.; RDFactor = 1.; CameraHeight = INT_MIN; @@ -281,6 +307,7 @@ void PClassActor::DeriveData(PClass *newclass) assert(newclass->IsKindOf(RUNTIME_CLASS(PClassActor))); PClassActor *newa = static_cast(newclass); + newa->DefaultStateUsage = DefaultStateUsage; newa->Obituary = Obituary; newa->HitObituary = HitObituary; newa->DeathHeight = DeathHeight; @@ -288,7 +315,6 @@ void PClassActor::DeriveData(PClass *newclass) newa->BloodColor = BloodColor; newa->GibHealth = GibHealth; newa->WoundHealth = WoundHealth; - newa->PoisonDamage = PoisonDamage; newa->FastSpeed = FastSpeed; newa->RDFactor = RDFactor; newa->CameraHeight = CameraHeight; @@ -353,32 +379,71 @@ size_t PClassActor::PropagateMark() //========================================================================== // -// PClassActor :: InitializeNativeDefaults +// PClassActor :: SetReplacement // -// This is used by DECORATE to assign ActorInfos to internal classes +// Sets as a replacement class for another class. // //========================================================================== -void PClassActor::InitializeNativeDefaults() +bool PClassActor::SetReplacement(FName replaceName) { - Symbols.SetParentTable(&ParentClass->Symbols); - assert(Defaults == NULL); - Defaults = (BYTE *)M_Malloc(Size); - if (ParentClass->Defaults != NULL) + // Check for "replaces" + if (replaceName != NAME_None) { - memcpy(Defaults, ParentClass->Defaults, ParentClass->Size); - if (Size > ParentClass->Size) + // Get actor name + PClassActor *replacee = PClass::FindActor(replaceName); + + if (replacee == nullptr) { - memset(Defaults + ParentClass->Size, 0, Size - ParentClass->Size); + return false; + } + if (replacee != nullptr) + { + replacee->Replacement = this; + Replacee = replacee; } } - else + return true; +} + +//========================================================================== +// +// PClassActor :: SetDropItems +// +// Sets a new drop item list +// +//========================================================================== + +void PClassActor::SetDropItems(DDropItem *drops) +{ + DropItems = drops; + GC::WriteBarrier(this, DropItems); +} + + +//========================================================================== +// +// PClassActor :: Finalize +// +// Installs the parsed states and does some sanity checking +// +//========================================================================== + +void PClassActor::Finalize(FStateDefinitions &statedef) +{ + AActor *defaults = (AActor*)Defaults; + + try { - memset (Defaults, 0, Size); - // Non-DECORATE properties that must be set. - ((AActor*)Defaults)->DamageMultiply = 1.; // fixme: Make this a DECORATE property. - ((AActor*)Defaults)->ConversationRoot = -1; + statedef.FinishStates(this, defaults); } + catch (CRecoverableError &) + { + statedef.MakeStateDefines(NULL); + throw; + } + statedef.InstallStates(this, defaults); + statedef.MakeStateDefines(NULL); } //========================================================================== @@ -573,19 +638,18 @@ void PClassActor::SetPainChance(FName type, int chance) // //========================================================================== -void PClassActor::ReplaceClassRef(PClass *oldclass, PClass *newclass) +size_t PClassActor::PointerSubstitution(DObject *oldclass, DObject *newclass) { + auto changed = Super::PointerSubstitution(oldclass, newclass); for (unsigned i = 0; i < VisibleToPlayerClass.Size(); i++) { if (VisibleToPlayerClass[i] == oldclass) + { VisibleToPlayerClass[i] = static_cast(newclass); + changed++; + } } - AActor *def = (AActor*)Defaults; - if (def != NULL) - { - if (def->TeleFogSourceType == oldclass) def->TeleFogSourceType = static_cast(newclass); - if (def->TeleFogDestType == oldclass) def->TeleFogDestType = static_cast(newclass); - } + return changed; } //========================================================================== @@ -747,3 +811,43 @@ int DamageTypeDefinition::ApplyMobjDamageFactor(int damage, FName type, DmgFacto double factor = GetMobjDamageFactor(type, factors); return int(damage * factor); } + +//========================================================================== +// +// Reads a damage definition +// +//========================================================================== + +void FMapInfoParser::ParseDamageDefinition() +{ + sc.MustGetString(); + FName damageType = sc.String; + + DamageTypeDefinition dtd; + + ParseOpenBrace(); + while (sc.MustGetAnyToken(), sc.TokenType != '}') + { + if (sc.Compare("FACTOR")) + { + sc.MustGetStringName("="); + sc.MustGetFloat(); + dtd.DefaultFactor = sc.Float; + if (dtd.DefaultFactor == 0) dtd.ReplaceFactor = true; + } + else if (sc.Compare("REPLACEFACTOR")) + { + dtd.ReplaceFactor = true; + } + else if (sc.Compare("NOARMOR")) + { + dtd.NoArmor = true; + } + else + { + sc.ScriptError("Unexpected data (%s) in damagetype definition.", sc.String); + } + } + + dtd.Apply(damageType); +} diff --git a/src/info.h b/src/info.h index 0e49e1f8fb..54aac3e3c4 100644 --- a/src/info.h +++ b/src/info.h @@ -43,7 +43,6 @@ #include "dobject.h" #include "doomdef.h" -#include "vm.h" #include "s_sound.h" #include "m_fixed.h" @@ -53,8 +52,39 @@ struct Baggage; class FScanner; struct FActorInfo; class FIntCVar; +class FStateDefinitions; -enum EStateType +enum EStateDefineFlags +{ + SDF_NEXT = 0, + SDF_STATE = 1, + SDF_STOP = 2, + SDF_WAIT = 3, + SDF_LABEL = 4, + SDF_INDEX = 5, + SDF_MASK = 7, +}; + +enum EStateFlags +{ + STF_SLOW = 1, // State duration is extended when slow monsters is on. + STF_FAST = 2, // State duration is shortened when fast monsters is on. + STF_FULLBRIGHT = 4, // State is fullbright + STF_NODELAY = 8, // Spawn states executes its action normally + STF_SAMEFRAME = 16, // Ignore Frame (except when spawning actor) + STF_CANRAISE = 32, // Allows a monster to be resurrected without waiting for an infinate frame + STF_DEHACKED = 64, // Modified by Dehacked +}; + +enum EStateUseFlags +{ + SUF_ACTOR = 1, + SUF_OVERLAY = 2, + SUF_WEAPON = 4, + SUF_ITEM = 8, +}; + +enum EStateType : int // this must ensure proper alignment. { STATE_Actor, STATE_Psprite, @@ -81,32 +111,44 @@ struct FState { FState *NextState; VMFunction *ActionFunc; - WORD sprite; - SWORD Tics; - WORD TicRange; - BYTE Frame; - BYTE DefineFlags; // Unused byte so let's use it during state creation. - int Misc1; // Was changed to SBYTE, reverted to long for MBF compat - int Misc2; // Was changed to BYTE, reverted to long for MBF compat - short Light; - BYTE Fullbright:1; // State is fullbright - BYTE SameFrame:1; // Ignore Frame (except when spawning actor) - BYTE Fast:1; - BYTE NoDelay:1; // Spawn states executes its action normally - BYTE CanRaise:1; // Allows a monster to be resurrected without waiting for an infinate frame - BYTE Slow:1; // Inverse of fast - + int32_t sprite; + int16_t Tics; + uint16_t TicRange; + int16_t Light; + uint16_t StateFlags; + uint8_t Frame; + uint8_t UseFlags; + uint8_t DefineFlags; // Unused byte so let's use it during state creation. + int32_t Misc1; // Was changed to SBYTE, reverted to long for MBF compat + int32_t Misc2; // Was changed to BYTE, reverted to long for MBF compat +public: inline int GetFrame() const { return Frame; } inline bool GetSameFrame() const { - return SameFrame; + return !!(StateFlags & STF_SAMEFRAME); } inline int GetFullbright() const { - return Fullbright ? 0x10 /*RF_FULLBRIGHT*/ : 0; + return (StateFlags & STF_FULLBRIGHT)? 0x10 /*RF_FULLBRIGHT*/ : 0; + } + inline bool GetFast() const + { + return !!(StateFlags & STF_FAST); + } + inline bool GetSlow() const + { + return !!(StateFlags & STF_SLOW); + } + inline bool GetNoDelay() const + { + return !!(StateFlags & STF_NODELAY); + } + inline bool GetCanRaise() const + { + return !!(StateFlags & STF_CANRAISE); } inline int GetTics() const { @@ -128,14 +170,6 @@ struct FState { return NextState; } - inline bool GetNoDelay() const - { - return NoDelay; - } - inline bool GetCanRaise() const - { - return CanRaise; - } inline void SetFrame(BYTE frame) { Frame = frame - 'A'; @@ -214,14 +248,16 @@ public: PClassActor(); ~PClassActor(); - virtual void ReplaceClassRef(PClass *oldclass, PClass *newclass); + virtual size_t PointerSubstitution(DObject *oldclass, DObject *newclass); void BuildDefaults(); void ApplyDefaults(BYTE *defaults); void RegisterIDs(); void SetDamageFactor(FName type, double factor); void SetPainChance(FName type, int chance); size_t PropagateMark(); - void InitializeNativeDefaults(); + bool SetReplacement(FName replaceName); + void SetDropItems(DDropItem *drops); + virtual void Finalize(FStateDefinitions &statedef); FState *FindState(int numnames, FName *names, bool exact=false) const; FState *FindStateByString(const char *name, bool exact=false); @@ -243,6 +279,7 @@ public: PClassActor *Replacee; int NumOwnedStates; BYTE GameFilter; + uint8_t DefaultStateUsage; // state flag defaults for blocks without a qualifier. WORD SpawnID; WORD ConversationID; SWORD DoomEdNum; @@ -259,7 +296,6 @@ public: PalEntry BloodColor; // Colorized blood int GibHealth; // Negative health below which this monster dies an extreme death int WoundHealth; // Health needed to enter wound state - int PoisonDamage; // Amount of poison damage double FastSpeed; // speed in fast mode double RDFactor; // Radius damage factor double CameraHeight; // Height of camera when used as such @@ -298,6 +334,44 @@ struct FDoomEdEntry int Args[5]; }; +struct FStateLabelStorage +{ + TArray Storage; + + int AddPointer(FState *ptr) + { + if (ptr != nullptr) + { + int pos = Storage.Reserve(sizeof(ptr) + sizeof(int)); + memset(&Storage[pos], 0, sizeof(int)); + memcpy(&Storage[pos + sizeof(int)], &ptr, sizeof(ptr)); + return pos / 4 + 1; + } + else return 0; + } + + int AddNames(TArray &names) + { + int siz = names.Size(); + if (siz > 1) + { + int pos = Storage.Reserve(sizeof(int) + sizeof(FName) * names.Size()); + memcpy(&Storage[pos], &siz, sizeof(int)); + memcpy(&Storage[pos + sizeof(int)], &names[0], sizeof(FName) * names.Size()); + return pos / 4 + 1; + } + else + { + // don't store single name states in the array. + return names[0].GetIndex() + 0x10000000; + } + } + + FState *GetState(int pos, PClassActor *cls, bool exact = false); +}; + +extern FStateLabelStorage StateLabels; + enum ESpecialMapthings { SMT_Player1Start = 1, @@ -340,23 +414,4 @@ int GetSpriteIndex(const char * spritename, bool add = true); TArray &MakeStateNameList(const char * fname); void AddStateLight(FState *state, const char *lname); -// Standard parameters for all action functons -// self - Actor this action is to operate on (player if a weapon) -// stateowner - Actor this action really belongs to (may be an item) -// callingstate - State this action was called from -#define PARAM_ACTION_PROLOGUE_TYPE(type) \ - PARAM_PROLOGUE; \ - PARAM_OBJECT (self, type); \ - PARAM_OBJECT_OPT (stateowner, AActor) { stateowner = self; } \ - PARAM_STATEINFO_OPT (stateinfo) { stateinfo = nullptr; } \ - -#define PARAM_ACTION_PROLOGUE PARAM_ACTION_PROLOGUE_TYPE(AActor) - -// Number of action paramaters -#define NAP 3 - -#define PARAM_SELF_PROLOGUE(type) \ - PARAM_PROLOGUE; \ - PARAM_OBJECT(self, type); - #endif // __INFO_H__ diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp index ba4566e9d9..2aacd215b3 100644 --- a/src/intermission/intermission.cpp +++ b/src/intermission/intermission.cpp @@ -54,14 +54,16 @@ FIntermissionDescriptorList IntermissionDescriptors; -IMPLEMENT_CLASS(DIntermissionScreen) -IMPLEMENT_CLASS(DIntermissionScreenFader) -IMPLEMENT_CLASS(DIntermissionScreenText) -IMPLEMENT_CLASS(DIntermissionScreenCast) -IMPLEMENT_CLASS(DIntermissionScreenScroller) -IMPLEMENT_POINTY_CLASS(DIntermissionController) - DECLARE_POINTER(mScreen) -END_POINTERS +IMPLEMENT_CLASS(DIntermissionScreen, false, false) +IMPLEMENT_CLASS(DIntermissionScreenFader, false, false) +IMPLEMENT_CLASS(DIntermissionScreenText, false, false) +IMPLEMENT_CLASS(DIntermissionScreenCast, false, false) +IMPLEMENT_CLASS(DIntermissionScreenScroller, false, false) +IMPLEMENT_CLASS(DIntermissionController, false, true) + +IMPLEMENT_POINTERS_START(DIntermissionController) + IMPLEMENT_POINTER(mScreen) +IMPLEMENT_POINTERS_END extern int NoWipe; diff --git a/src/intermission/intermission.h b/src/intermission/intermission.h index 45779f895a..25b369a3ae 100644 --- a/src/intermission/intermission.h +++ b/src/intermission/intermission.h @@ -176,7 +176,7 @@ public: virtual int Responder (event_t *ev); virtual int Ticker (); virtual void Drawer (); - void Destroy(); + void Destroy() override; FTextureID GetBackground(bool *fill) { *fill = mFlatfill; @@ -301,7 +301,7 @@ public: bool Responder (event_t *ev); void Ticker (); void Drawer (); - void Destroy(); + void Destroy() override; friend void F_AdvanceIntermission(); }; diff --git a/src/m_argv.cpp b/src/m_argv.cpp index 5d4aa97a34..3958859860 100644 --- a/src/m_argv.cpp +++ b/src/m_argv.cpp @@ -37,7 +37,7 @@ #include "cmdlib.h" #include "i_system.h" -IMPLEMENT_CLASS (DArgs) +IMPLEMENT_CLASS(DArgs, false, false) //=========================================================================== // diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 7c110a52c9..53ae789c68 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -30,7 +30,6 @@ #include "doomstat.h" #include "gstrings.h" #include "p_local.h" -#include "a_strifeglobal.h" #include "gi.h" #include "p_enemy.h" #include "sbar.h" @@ -48,6 +47,8 @@ #include "serializer.h" #include "r_utility.h" #include "a_morph.h" +#include "a_armor.h" +#include "a_ammo.h" // [RH] Actually handle the cheat. The cheat code in st_stuff.c now just // writes some bytes to the network data stream, and the network code @@ -483,18 +484,27 @@ void cht_DoCheat (player_t *player, int cheat) case CHT_LEGO: if (player->mo != NULL && player->health >= 0) { - int oldpieces = ASigil::GiveSigilPiece (player->mo); - item = player->mo->FindInventory (RUNTIME_CLASS(ASigil)); - - if (item != NULL) + static VMFunction *gsp = nullptr; + if (gsp == nullptr) gsp = PClass::FindFunction(NAME_Sigil, NAME_GiveSigilPiece); + if (gsp) { - if (oldpieces == 5) + VMValue params[1] = { player->mo }; + VMReturn ret; + int oldpieces = 1; + ret.IntAt(&oldpieces); + GlobalVMStack.Call(gsp, params, 1, &ret, 1, nullptr); + item = player->mo->FindInventory(PClass::FindActor(NAME_Sigil)); + + if (item != NULL) { - item->Destroy (); - } - else - { - player->PendingWeapon = static_cast (item); + if (oldpieces == 5) + { + item->Destroy(); + } + else + { + player->PendingWeapon = static_cast (item); + } } } } @@ -1033,9 +1043,11 @@ public: } }; -IMPLEMENT_POINTY_CLASS(DSuicider) - DECLARE_POINTER(Pawn) -END_POINTERS +IMPLEMENT_CLASS(DSuicider, false, true) + +IMPLEMENT_POINTERS_START(DSuicider) + IMPLEMENT_POINTER(Pawn) +IMPLEMENT_POINTERS_END void cht_Suicide (player_t *plyr) { diff --git a/src/math/cmath.h b/src/math/cmath.h index 9fd0b570d1..5c02c4e87e 100644 --- a/src/math/cmath.h +++ b/src/math/cmath.h @@ -23,6 +23,7 @@ double c_tanh(double); double c_exp(double); double c_log(double); double c_log10(double); +double c_pow(double, double); } @@ -114,6 +115,7 @@ inline double cosdeg(double v) #define g_exp exp #define g_log log #define g_log10 log10 +#define g_pow pow #else #define g_asin c_asin #define g_acos c_acos @@ -139,6 +141,7 @@ inline double cosdeg(double v) #define g_exp c_exp #define g_log c_log #define g_log10 c_log10 +#define g_pow c_pow #endif diff --git a/src/math/pow.c b/src/math/pow.c new file mode 100644 index 0000000000..c55fa81fd3 --- /dev/null +++ b/src/math/pow.c @@ -0,0 +1,756 @@ +/* pow.c + * + * Power function + * + * + * + * SYNOPSIS: + * + * double x, y, z, pow(); + * + * z = pow( x, y ); + * + * + * + * DESCRIPTION: + * + * Computes x raised to the yth power. Analytically, + * + * x**y = exp( y log(x) ). + * + * Following Cody and Waite, this program uses a lookup table + * of 2**-i/16 and pseudo extended precision arithmetic to + * obtain an extra three bits of accuracy in both the logarithm + * and the exponential. + * + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -26,26 30000 4.2e-16 7.7e-17 + * DEC -26,26 60000 4.8e-17 9.1e-18 + * 1/26 < x < 26, with log(x) uniformly distributed. + * -26 < y < 26, y uniformly distributed. + * IEEE 0,8700 30000 1.5e-14 2.1e-15 + * 0.99 < x < 1.01, 0 < y < 8700, uniformly distributed. + * + * + * ERROR MESSAGES: + * + * message condition value returned + * pow overflow x**y > MAXNUM INFINITY + * pow underflow x**y < 1/MAXNUM 0.0 + * pow domain x<0 and y noninteger 0.0 + * + */ + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1995, 2000 by Stephen L. Moshier +*/ + + +#include "mconf.h" +static char fname[] = {"pow"}; + +#define SQRTH 0.70710678118654752440 + +#ifdef UNK +static double P[] = { + 4.97778295871696322025E-1, + 3.73336776063286838734E0, + 7.69994162726912503298E0, + 4.66651806774358464979E0 +}; +static double Q[] = { +/* 1.00000000000000000000E0, */ + 9.33340916416696166113E0, + 2.79999886606328401649E1, + 3.35994905342304405431E1, + 1.39995542032307539578E1 +}; +/* 2^(-i/16), IEEE precision */ +static double A[] = { + 1.00000000000000000000E0, + 9.57603280698573700036E-1, + 9.17004043204671215328E-1, + 8.78126080186649726755E-1, + 8.40896415253714502036E-1, + 8.05245165974627141736E-1, + 7.71105412703970372057E-1, + 7.38413072969749673113E-1, + 7.07106781186547572737E-1, + 6.77127773468446325644E-1, + 6.48419777325504820276E-1, + 6.20928906036742001007E-1, + 5.94603557501360513449E-1, + 5.69394317378345782288E-1, + 5.45253866332628844837E-1, + 5.22136891213706877402E-1, + 5.00000000000000000000E-1 +}; +static double B[] = { + 0.00000000000000000000E0, + 1.64155361212281360176E-17, + 4.09950501029074826006E-17, + 3.97491740484881042808E-17, +-4.83364665672645672553E-17, + 1.26912513974441574796E-17, + 1.99100761573282305549E-17, +-1.52339103990623557348E-17, + 0.00000000000000000000E0 +}; +static double R[] = { + 1.49664108433729301083E-5, + 1.54010762792771901396E-4, + 1.33335476964097721140E-3, + 9.61812908476554225149E-3, + 5.55041086645832347466E-2, + 2.40226506959099779976E-1, + 6.93147180559945308821E-1 +}; + +#define douba(k) A[k] +#define doubb(k) B[k] +#define MEXP 16383.0 +#ifdef DENORMAL +#define MNEXP -17183.0 +#else +#define MNEXP -16383.0 +#endif +#endif + +#ifdef DEC +static unsigned short P[] = { +0037776,0156313,0175332,0163602, +0040556,0167577,0052366,0174245, +0040766,0062753,0175707,0055564, +0040625,0052035,0131344,0155636, +}; +static unsigned short Q[] = { +/*0040200,0000000,0000000,0000000,*/ +0041025,0052644,0154404,0105155, +0041337,0177772,0007016,0047646, +0041406,0062740,0154273,0020020, +0041137,0177054,0106127,0044555, +}; +static unsigned short A[] = { +0040200,0000000,0000000,0000000, +0040165,0022575,0012444,0103314, +0040152,0140306,0163735,0022071, +0040140,0146336,0166052,0112341, +0040127,0042374,0145326,0116553, +0040116,0022214,0012437,0102201, +0040105,0063452,0010525,0003333, +0040075,0004243,0117530,0006067, +0040065,0002363,0031771,0157145, +0040055,0054076,0165102,0120513, +0040045,0177326,0124661,0050471, +0040036,0172462,0060221,0120422, +0040030,0033760,0050615,0134251, +0040021,0141723,0071653,0010703, +0040013,0112701,0161752,0105727, +0040005,0125303,0063714,0044173, +0040000,0000000,0000000,0000000 +}; +static unsigned short B[] = { +0000000,0000000,0000000,0000000, +0021473,0040265,0153315,0140671, +0121074,0062627,0042146,0176454, +0121413,0003524,0136332,0066212, +0121767,0046404,0166231,0012553, +0121257,0015024,0002357,0043574, +0021736,0106532,0043060,0056206, +0121310,0020334,0165705,0035326, +0000000,0000000,0000000,0000000 +}; + +static unsigned short R[] = { +0034173,0014076,0137624,0115771, +0035041,0076763,0003744,0111311, +0035656,0141766,0041127,0074351, +0036435,0112533,0073611,0116664, +0037143,0054106,0134040,0152223, +0037565,0176757,0176026,0025551, +0040061,0071027,0173721,0147572 +}; + +/* +static double R[] = { +0.14928852680595608186e-4, +0.15400290440989764601e-3, +0.13333541313585784703e-2, +0.96181290595172416964e-2, +0.55504108664085595326e-1, +0.24022650695909537056e0, +0.69314718055994529629e0 +}; +*/ +#define douba(k) (*(double *)&A[(k)<<2]) +#define doubb(k) (*(double *)&B[(k)<<2]) +#define MEXP 2031.0 +#define MNEXP -2031.0 +#endif + +#ifdef IBMPC +static unsigned short P[] = { +0x5cf0,0x7f5b,0xdb99,0x3fdf, +0xdf15,0xea9e,0xddef,0x400d, +0xeb6f,0x7f78,0xccbd,0x401e, +0x9b74,0xb65c,0xaa83,0x4012, +}; +static unsigned short Q[] = { +/*0x0000,0x0000,0x0000,0x3ff0,*/ +0x914e,0x9b20,0xaab4,0x4022, +0xc9f5,0x41c1,0xffff,0x403b, +0x6402,0x1b17,0xccbc,0x4040, +0xe92e,0x918a,0xffc5,0x402b, +}; +static unsigned short A[] = { +0x0000,0x0000,0x0000,0x3ff0, +0x90da,0xa2a4,0xa4af,0x3fee, +0xa487,0xdcfb,0x5818,0x3fed, +0x529c,0xdd85,0x199b,0x3fec, +0xd3ad,0x995a,0xe89f,0x3fea, +0xf090,0x82a3,0xc491,0x3fe9, +0xa0db,0x422a,0xace5,0x3fe8, +0x0187,0x73eb,0xa114,0x3fe7, +0x3bcd,0x667f,0xa09e,0x3fe6, +0x5429,0xdd48,0xab07,0x3fe5, +0x2a27,0xd536,0xbfda,0x3fe4, +0x3422,0x4c12,0xdea6,0x3fe3, +0xb715,0x0a31,0x06fe,0x3fe3, +0x6238,0x6e75,0x387a,0x3fe2, +0x517b,0x3c7d,0x72b8,0x3fe1, +0x890f,0x6cf9,0xb558,0x3fe0, +0x0000,0x0000,0x0000,0x3fe0 +}; +static unsigned short B[] = { +0x0000,0x0000,0x0000,0x0000, +0x3707,0xd75b,0xed02,0x3c72, +0xcc81,0x345d,0xa1cd,0x3c87, +0x4b27,0x5686,0xe9f1,0x3c86, +0x6456,0x13b2,0xdd34,0xbc8b, +0x42e2,0xafec,0x4397,0x3c6d, +0x82e4,0xd231,0xf46a,0x3c76, +0x8a76,0xb9d7,0x9041,0xbc71, +0x0000,0x0000,0x0000,0x0000 +}; +static unsigned short R[] = { +0x937f,0xd7f2,0x6307,0x3eef, +0x9259,0x60fc,0x2fbe,0x3f24, +0xef1d,0xc84a,0xd87e,0x3f55, +0x33b7,0x6ef1,0xb2ab,0x3f83, +0x1a92,0xd704,0x6b08,0x3fac, +0xc56d,0xff82,0xbfbd,0x3fce, +0x39ef,0xfefa,0x2e42,0x3fe6 +}; + +#define douba(k) (*(double *)&A[(k)<<2]) +#define doubb(k) (*(double *)&B[(k)<<2]) +#define MEXP 16383.0 +#ifdef DENORMAL +#define MNEXP -17183.0 +#else +#define MNEXP -16383.0 +#endif +#endif + +#ifdef MIEEE +static unsigned short P[] = { +0x3fdf,0xdb99,0x7f5b,0x5cf0, +0x400d,0xddef,0xea9e,0xdf15, +0x401e,0xccbd,0x7f78,0xeb6f, +0x4012,0xaa83,0xb65c,0x9b74 +}; +static unsigned short Q[] = { +0x4022,0xaab4,0x9b20,0x914e, +0x403b,0xffff,0x41c1,0xc9f5, +0x4040,0xccbc,0x1b17,0x6402, +0x402b,0xffc5,0x918a,0xe92e +}; +static unsigned short A[] = { +0x3ff0,0x0000,0x0000,0x0000, +0x3fee,0xa4af,0xa2a4,0x90da, +0x3fed,0x5818,0xdcfb,0xa487, +0x3fec,0x199b,0xdd85,0x529c, +0x3fea,0xe89f,0x995a,0xd3ad, +0x3fe9,0xc491,0x82a3,0xf090, +0x3fe8,0xace5,0x422a,0xa0db, +0x3fe7,0xa114,0x73eb,0x0187, +0x3fe6,0xa09e,0x667f,0x3bcd, +0x3fe5,0xab07,0xdd48,0x5429, +0x3fe4,0xbfda,0xd536,0x2a27, +0x3fe3,0xdea6,0x4c12,0x3422, +0x3fe3,0x06fe,0x0a31,0xb715, +0x3fe2,0x387a,0x6e75,0x6238, +0x3fe1,0x72b8,0x3c7d,0x517b, +0x3fe0,0xb558,0x6cf9,0x890f, +0x3fe0,0x0000,0x0000,0x0000 +}; +static unsigned short B[] = { +0x0000,0x0000,0x0000,0x0000, +0x3c72,0xed02,0xd75b,0x3707, +0x3c87,0xa1cd,0x345d,0xcc81, +0x3c86,0xe9f1,0x5686,0x4b27, +0xbc8b,0xdd34,0x13b2,0x6456, +0x3c6d,0x4397,0xafec,0x42e2, +0x3c76,0xf46a,0xd231,0x82e4, +0xbc71,0x9041,0xb9d7,0x8a76, +0x0000,0x0000,0x0000,0x0000 +}; +static unsigned short R[] = { +0x3eef,0x6307,0xd7f2,0x937f, +0x3f24,0x2fbe,0x60fc,0x9259, +0x3f55,0xd87e,0xc84a,0xef1d, +0x3f83,0xb2ab,0x6ef1,0x33b7, +0x3fac,0x6b08,0xd704,0x1a92, +0x3fce,0xbfbd,0xff82,0xc56d, +0x3fe6,0x2e42,0xfefa,0x39ef +}; + +#define douba(k) (*(double *)&A[(k)<<2]) +#define doubb(k) (*(double *)&B[(k)<<2]) +#define MEXP 16383.0 +#ifdef DENORMAL +#define MNEXP -17183.0 +#else +#define MNEXP -16383.0 +#endif +#endif + +/* log2(e) - 1 */ +#define LOG2EA 0.44269504088896340736 + +#define F W +#define Fa Wa +#define Fb Wb +#define G W +#define Ga Wa +#define Gb u +#define H W +#define Ha Wb +#define Hb Wb + +#ifdef ANSIPROT +extern double floor ( double ); +extern double fabs ( double ); +extern double frexp ( double, int * ); +extern double ldexp ( double, int ); +extern double polevl ( double, void *, int ); +extern double p1evl ( double, void *, int ); +extern double c_powi ( double, int ); +extern int signbit ( double ); +extern int isnan ( double ); +extern int isfinite ( double ); +static double reduc ( double ); +#else +double floor(), fabs(), frexp(), ldexp(); +double polevl(), p1evl(), c_powi(); +int signbit(), isnan(), isfinite(); +static double reduc(); +#endif +extern double MAXNUM; +#ifdef INFINITIES +extern double INFINITY; +#endif +#ifdef NANS +extern double NAN; +#endif +#ifdef MINUSZERO +extern double NEGZERO; +#endif + +double c_pow( x, y ) +double x, y; +{ +double w, z, W, Wa, Wb, ya, yb, u; +/* double F, Fa, Fb, G, Ga, Gb, H, Ha, Hb */ +double aw, ay, wy; +int e, i, nflg, iyflg, yoddint; + +if( y == 0.0 ) + return( 1.0 ); +#ifdef NANS +if( isnan(x) ) + return( x ); +if( isnan(y) ) + return( y ); +#endif +if( y == 1.0 ) + return( x ); + + +#ifdef INFINITIES +if( !isfinite(y) && (x == 1.0 || x == -1.0) ) + { + mtherr( "pow", DOMAIN ); +#ifdef NANS + return( NAN ); +#else + return( INFINITY ); +#endif + } +#endif + +if( x == 1.0 ) + return( 1.0 ); + +if( y >= MAXNUM ) + { +#ifdef INFINITIES + if( x > 1.0 ) + return( INFINITY ); +#else + if( x > 1.0 ) + return( MAXNUM ); +#endif + if( x > 0.0 && x < 1.0 ) + return( 0.0); + if( x < -1.0 ) + { +#ifdef INFINITIES + return( INFINITY ); +#else + return( MAXNUM ); +#endif + } + if( x > -1.0 && x < 0.0 ) + return( 0.0 ); + } +if( y <= -MAXNUM ) + { + if( x > 1.0 ) + return( 0.0 ); +#ifdef INFINITIES + if( x > 0.0 && x < 1.0 ) + return( INFINITY ); +#else + if( x > 0.0 && x < 1.0 ) + return( MAXNUM ); +#endif + if( x < -1.0 ) + return( 0.0 ); +#ifdef INFINITIES + if( x > -1.0 && x < 0.0 ) + return( INFINITY ); +#else + if( x > -1.0 && x < 0.0 ) + return( MAXNUM ); +#endif + } +if( x >= MAXNUM ) + { +#if INFINITIES + if( y > 0.0 ) + return( INFINITY ); +#else + if( y > 0.0 ) + return( MAXNUM ); +#endif + return(0.0); + } +/* Set iyflg to 1 if y is an integer. */ +iyflg = 0; +w = floor(y); +if( w == y ) + iyflg = 1; + +/* Test for odd integer y. */ +yoddint = 0; +if( iyflg ) + { + ya = fabs(y); + ya = floor(0.5 * ya); + yb = 0.5 * fabs(w); + if( ya != yb ) + yoddint = 1; + } + +if( x <= -MAXNUM ) + { + if( y > 0.0 ) + { +#ifdef INFINITIES + if( yoddint ) + return( -INFINITY ); + return( INFINITY ); +#else + if( yoddint ) + return( -MAXNUM ); + return( MAXNUM ); +#endif + } + if( y < 0.0 ) + { +#ifdef MINUSZERO + if( yoddint ) + return( NEGZERO ); +#endif + return( 0.0 ); + } + } + +nflg = 0; /* flag = 1 if x<0 raised to integer power */ +if( x <= 0.0 ) + { + if( x == 0.0 ) + { + if( y < 0.0 ) + { +#ifdef MINUSZERO + if( signbit(x) && yoddint ) + return( -INFINITY ); +#endif +#ifdef INFINITIES + return( INFINITY ); +#else + return( MAXNUM ); +#endif + } + if( y > 0.0 ) + { +#ifdef MINUSZERO + if( signbit(x) && yoddint ) + return( NEGZERO ); +#endif + return( 0.0 ); + } + return( 1.0 ); + } + else + { + if( iyflg == 0 ) + { /* noninteger power of negative number */ + mtherr( fname, DOMAIN ); +#ifdef NANS + return(NAN); +#else + return(0.0L); +#endif + } + nflg = 1; + } + } + +/* Integer power of an integer. */ + +if( iyflg ) + { + i = (int)w; + w = floor(x); + if( (w == x) && (fabs(y) < 32768.0) ) + { + w = c_powi( x, (int) y ); + return( w ); + } + } + +if( nflg ) + x = fabs(x); + +/* For results close to 1, use a series expansion. */ +w = x - 1.0; +aw = fabs(w); +ay = fabs(y); +wy = w * y; +ya = fabs(wy); +if((aw <= 1.0e-3 && ay <= 1.0) + || (ya <= 1.0e-3 && ay >= 1.0)) + { + z = (((((w*(y-5.)/720. + 1./120.)*w*(y-4.) + 1./24.)*w*(y-3.) + + 1./6.)*w*(y-2.) + 0.5)*w*(y-1.) )*wy + wy + 1.; + goto done; + } +/* These are probably too much trouble. */ +#if 0 +w = y * log(x); +if (aw > 1.0e-3 && fabs(w) < 1.0e-3) + { + z = (((((( + w/7. + 1.)*w/6. + 1.)*w/5. + 1.)*w/4. + 1.)*w/3. + 1.)*w/2. + 1.)*w + 1.; + goto done; + } + +if(ya <= 1.0e-3 && aw <= 1.0e-4) + { + z = ((((( + wy*1./720. + + (-w*1./48. + 1./120.) )*wy + + ((w*17./144. - 1./12.)*w + 1./24.) )*wy + + (((-w*5./16. + 7./24.)*w - 1./4.)*w + 1./6.) )*wy + + ((((w*137./360. - 5./12.)*w + 11./24.)*w - 1./2.)*w + 1./2.) )*wy + + (((((-w*1./6. + 1./5.)*w - 1./4)*w + 1./3.)*w -1./2.)*w ) )*wy + + wy + 1.0; + goto done; + } +#endif + +/* separate significand from exponent */ +x = frexp( x, &e ); + +#if 0 +/* For debugging, check for gross overflow. */ +if( (e * y) > (MEXP + 1024) ) + goto overflow; +#endif + +/* Find significand of x in antilog table A[]. */ +i = 1; +if( x <= douba(9) ) + i = 9; +if( x <= douba(i+4) ) + i += 4; +if( x <= douba(i+2) ) + i += 2; +if( x >= douba(1) ) + i = -1; +i += 1; + + +/* Find (x - A[i])/A[i] + * in order to compute log(x/A[i]): + * + * log(x) = log( a x/a ) = log(a) + log(x/a) + * + * log(x/a) = log(1+v), v = x/a - 1 = (x-a)/a + */ +x -= douba(i); +x -= doubb(i/2); +x /= douba(i); + + +/* rational approximation for log(1+v): + * + * log(1+v) = v - v**2/2 + v**3 P(v) / Q(v) + */ +z = x*x; +w = x * ( z * polevl( x, P, 3 ) / p1evl( x, Q, 4 ) ); +w = w - ldexp( z, -1 ); /* w - 0.5 * z */ + +/* Convert to base 2 logarithm: + * multiply by log2(e) + */ +w = w + LOG2EA * w; +/* Note x was not yet added in + * to above rational approximation, + * so do it now, while multiplying + * by log2(e). + */ +z = w + LOG2EA * x; +z = z + x; + +/* Compute exponent term of the base 2 logarithm. */ +w = -i; +w = ldexp( w, -4 ); /* divide by 16 */ +w += e; +/* Now base 2 log of x is w + z. */ + +/* Multiply base 2 log by y, in extended precision. */ + +/* separate y into large part ya + * and small part yb less than 1/16 + */ +ya = reduc(y); +yb = y - ya; + + +F = z * y + w * yb; +Fa = reduc(F); +Fb = F - Fa; + +G = Fa + w * ya; +Ga = reduc(G); +Gb = G - Ga; + +H = Fb + Gb; +Ha = reduc(H); +w = ldexp( Ga+Ha, 4 ); + +/* Test the power of 2 for overflow */ +if( w > MEXP ) + { +#ifndef INFINITIES + mtherr( fname, OVERFLOW ); +#endif +#ifdef INFINITIES + if( nflg && yoddint ) + return( -INFINITY ); + return( INFINITY ); +#else + if( nflg && yoddint ) + return( -MAXNUM ); + return( MAXNUM ); +#endif + } + +if( w < (MNEXP - 1) ) + { +#ifndef DENORMAL + mtherr( fname, UNDERFLOW ); +#endif +#ifdef MINUSZERO + if( nflg && yoddint ) + return( NEGZERO ); +#endif + return( 0.0 ); + } + +e = (int)w; +Hb = H - Ha; + +if( Hb > 0.0 ) + { + e += 1; + Hb -= 0.0625; + } + +/* Now the product y * log2(x) = Hb + e/16.0. + * + * Compute base 2 exponential of Hb, + * where -0.0625 <= Hb <= 0. + */ +z = Hb * polevl( Hb, R, 6 ); /* z = 2**Hb - 1 */ + +/* Express e/16 as an integer plus a negative number of 16ths. + * Find lookup table entry for the fractional power of 2. + */ +if( e < 0 ) + i = 0; +else + i = 1; +i = e/16 + i; +e = 16*i - e; +w = douba( e ); +z = w + w * z; /* 2**-e * ( 1 + (2**Hb-1) ) */ +z = ldexp( z, i ); /* multiply by integer power of 2 */ + +done: + +/* Negate if odd integer power of negative number */ +if( nflg && yoddint ) + { +#ifdef MINUSZERO + if( z == 0.0 ) + z = NEGZERO; + else +#endif + z = -z; + } +return( z ); +} + + +/* Find a multiple of 1/16 that is within 1/16 of x. */ +static double reduc(x) +double x; +{ +double t; + +t = ldexp( x, 4 ); +t = floor( t ); +t = ldexp( t, -4 ); +return(t); +} diff --git a/src/math/powi.c b/src/math/powi.c new file mode 100644 index 0000000000..ec80dc1d5f --- /dev/null +++ b/src/math/powi.c @@ -0,0 +1,186 @@ +/* powi.c + * + * Real raised to integer power + * + * + * + * SYNOPSIS: + * + * double x, y, powi(); + * int n; + * + * y = powi( x, n ); + * + * + * + * DESCRIPTION: + * + * Returns argument x raised to the nth power. + * The routine efficiently decomposes n as a sum of powers of + * two. The desired power is a product of two-to-the-kth + * powers of x. Thus to compute the 32767 power of x requires + * 28 multiplications instead of 32767 multiplications. + * + * + * + * ACCURACY: + * + * + * Relative error: + * arithmetic x domain n domain # trials peak rms + * DEC .04,26 -26,26 100000 2.7e-16 4.3e-17 + * IEEE .04,26 -26,26 50000 2.0e-15 3.8e-16 + * IEEE 1,2 -1022,1023 50000 8.6e-14 1.6e-14 + * + * Returns MAXNUM on overflow, zero on underflow. + * + */ + +/* powi.c */ + +/* +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1995, 2000 by Stephen L. Moshier +*/ + +#include "mconf.h" +#ifdef ANSIPROT +extern double log ( double ); +extern double frexp ( double, int * ); +extern int signbit ( double ); +#else +double log(), frexp(); +int signbit(); +#endif +extern double NEGZERO, INFINITY, MAXNUM, MAXLOG, MINLOG, LOGE2; + +double c_powi( x, nn ) +double x; +int nn; +{ +int n, e, sign, asign, lx; +double w, y, s; + +/* See pow.c for these tests. */ +if( x == 0.0 ) + { + if( nn == 0 ) + return( 1.0 ); + else if( nn < 0 ) + return( INFINITY ); + else + { + if( nn & 1 ) + return( x ); + else + return( 0.0 ); + } + } + +if( nn == 0 ) + return( 1.0 ); + +if( nn == -1 ) + return( 1.0/x ); + +if( x < 0.0 ) + { + asign = -1; + x = -x; + } +else + asign = 0; + + +if( nn < 0 ) + { + sign = -1; + n = -nn; + } +else + { + sign = 1; + n = nn; + } + +/* Even power will be positive. */ +if( (n & 1) == 0 ) + asign = 0; + +/* Overflow detection */ + +/* Calculate approximate logarithm of answer */ +s = frexp( x, &lx ); +e = (lx - 1)*n; +if( (e == 0) || (e > 64) || (e < -64) ) + { + s = (s - 7.0710678118654752e-1) / (s + 7.0710678118654752e-1); + s = (2.9142135623730950 * s - 0.5 + lx) * nn * LOGE2; + } +else + { + s = LOGE2 * e; + } + +if( s > MAXLOG ) + { + mtherr( "powi", OVERFLOW ); + y = INFINITY; + goto done; + } + +#if DENORMAL +if( s < MINLOG ) + { + y = 0.0; + goto done; + } + +/* Handle tiny denormal answer, but with less accuracy + * since roundoff error in 1.0/x will be amplified. + * The precise demarcation should be the gradual underflow threshold. + */ +if( (s < (-MAXLOG+2.0)) && (sign < 0) ) + { + x = 1.0/x; + sign = -sign; + } +#else +/* do not produce denormal answer */ +if( s < -MAXLOG ) + return(0.0); +#endif + + +/* First bit of the power */ +if( n & 1 ) + y = x; + +else + y = 1.0; + +w = x; +n >>= 1; +while( n ) + { + w = w * w; /* arg to the 2-to-the-kth power */ + if( n & 1 ) /* if that bit is set, then include in product */ + y *= w; + n >>= 1; + } + +if( sign < 0 ) + y = 1.0/y; + +done: + +if( asign ) + { + /* odd power of negative number */ + if( y == 0.0 ) + y = NEGZERO; + else + y = -y; + } +return(y); +} diff --git a/src/memarena.cpp b/src/memarena.cpp index b15fb12ea0..8ea8b5806b 100644 --- a/src/memarena.cpp +++ b/src/memarena.cpp @@ -43,8 +43,6 @@ #include "c_dispatch.h" #include "zstring.h" -#define BLOCK_SIZE (10*1024) - struct FMemArena::Block { Block *NextBlock; @@ -74,10 +72,11 @@ static inline void *RoundPointer(void *ptr) // //========================================================================== -FMemArena::FMemArena() +FMemArena::FMemArena(size_t blocksize) { TopBlock = NULL; FreeBlocks = NULL; + BlockSize = blocksize; } //========================================================================== @@ -191,14 +190,14 @@ FMemArena::Block *FMemArena::AddBlock(size_t size) if (mem == NULL) { // Allocate a new block - if (size < BLOCK_SIZE) + if (size < BlockSize) { - size = BLOCK_SIZE; + size = BlockSize; } else { // Stick some free space at the end so we can use this block for // other things. - size += BLOCK_SIZE/2; + size += BlockSize/2; } mem = (Block *)M_Malloc(size); mem->Limit = (BYTE *)mem + size; diff --git a/src/memarena.h b/src/memarena.h index 73dbb59323..3601469bf8 100644 --- a/src/memarena.h +++ b/src/memarena.h @@ -40,7 +40,7 @@ class FMemArena { public: - FMemArena(); + FMemArena(size_t blocksize = 10*1024); ~FMemArena(); void *Alloc(size_t size); @@ -55,6 +55,7 @@ protected: Block *TopBlock; Block *FreeBlocks; + size_t BlockSize; }; // An arena specializing in storage of FStrings. It knows how to free them, @@ -86,4 +87,4 @@ private: }; -#endif \ No newline at end of file +#endif diff --git a/src/menu/colorpickermenu.cpp b/src/menu/colorpickermenu.cpp index affcf7c9f1..e1ee3566d8 100644 --- a/src/menu/colorpickermenu.cpp +++ b/src/menu/colorpickermenu.cpp @@ -95,7 +95,7 @@ public: desc->CalcIndent(); } - void Destroy() + void Destroy() override { if (mStartItem >= 0) { @@ -331,7 +331,7 @@ public: } }; -IMPLEMENT_ABSTRACT_CLASS(DColorPickerMenu) +IMPLEMENT_CLASS(DColorPickerMenu, true, false) CCMD(undocolorpic) { diff --git a/src/menu/joystickmenu.cpp b/src/menu/joystickmenu.cpp index 174b45d4be..f715dce4ae 100644 --- a/src/menu/joystickmenu.cpp +++ b/src/menu/joystickmenu.cpp @@ -236,7 +236,7 @@ class DJoystickConfigMenu : public DOptionMenu DECLARE_CLASS(DJoystickConfigMenu, DOptionMenu) }; -IMPLEMENT_CLASS(DJoystickConfigMenu) +IMPLEMENT_CLASS(DJoystickConfigMenu, false, false) //============================================================================= // diff --git a/src/menu/listmenu.cpp b/src/menu/listmenu.cpp index bcb61d6eb4..455ea6c4bd 100644 --- a/src/menu/listmenu.cpp +++ b/src/menu/listmenu.cpp @@ -42,7 +42,7 @@ #include "d_event.h" #include "menu/menu.h" -IMPLEMENT_CLASS(DListMenu) +IMPLEMENT_CLASS(DListMenu, false, false) //============================================================================= // diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index 99c34ab3e4..73183ca220 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -103,7 +103,7 @@ protected: char savegamestring[SAVESTRINGSIZE]; DLoadSaveMenu(DMenu *parent = NULL, FListMenuDescriptor *desc = NULL); - void Destroy(); + void Destroy() override; int RemoveSaveSlot (int index); void UnloadSaveData (); @@ -119,7 +119,7 @@ public: }; -IMPLEMENT_CLASS(DLoadSaveMenu) +IMPLEMENT_CLASS(DLoadSaveMenu, false, false) TArray DLoadSaveMenu::SaveGames; int DLoadSaveMenu::LastSaved = -1; @@ -466,6 +466,7 @@ void DLoadSaveMenu::Destroy() if (currentSavePic != nullptr) delete currentSavePic; currentSavePic = nullptr; ClearSaveStuff (); + Super::Destroy(); } //============================================================================= @@ -927,14 +928,14 @@ class DSaveMenu : public DLoadSaveMenu public: DSaveMenu(DMenu *parent = NULL, FListMenuDescriptor *desc = NULL); - void Destroy(); + void Destroy() override; void DoSave (FSaveGameNode *node); bool Responder (event_t *ev); bool MenuEvent (int mkey, bool fromcontroller); }; -IMPLEMENT_CLASS(DSaveMenu) +IMPLEMENT_CLASS(DSaveMenu, false, false) //============================================================================= @@ -975,6 +976,7 @@ void DSaveMenu::Destroy() if (Selected == 0) Selected = -1; else Selected--; } + Super::Destroy(); } //============================================================================= @@ -1102,7 +1104,7 @@ public: bool MenuEvent (int mkey, bool fromcontroller); }; -IMPLEMENT_CLASS(DLoadMenu) +IMPLEMENT_CLASS(DLoadMenu, false, false) //============================================================================= diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index 7e938230e7..0c6019a5fb 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -91,9 +91,11 @@ static bool MenuEnabled = true; // //============================================================================ -IMPLEMENT_POINTY_CLASS (DMenu) - DECLARE_POINTER(mParentMenu) -END_POINTERS +IMPLEMENT_CLASS(DMenu, false, true) + +IMPLEMENT_POINTERS_START(DMenu) + IMPLEMENT_POINTER(mParentMenu) +IMPLEMENT_POINTERS_END DMenu::DMenu(DMenu *parent) { diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index 618189b4f0..d09cb40b6e 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -50,6 +50,7 @@ #include "m_joy.h" #include "gi.h" #include "i_sound.h" +#include "cmdlib.h" #include "optionmenuitems.h" @@ -399,10 +400,10 @@ static void ParseListMenuBody(FScanner &sc, FListMenuDescriptor *desc) int y = sc.Number; sc.MustGetStringName(","); sc.MustGetString(); - PalEntry c1 = V_GetColor(NULL, sc.String); + PalEntry c1 = V_GetColor(NULL, sc); sc.MustGetStringName(","); sc.MustGetString(); - PalEntry c2 = V_GetColor(NULL, sc.String); + PalEntry c2 = V_GetColor(NULL, sc); if (sc.CheckString(",")) { sc.MustGetNumber(); diff --git a/src/menu/menuinput.cpp b/src/menu/menuinput.cpp index 8921187420..cca4756f5b 100644 --- a/src/menu/menuinput.cpp +++ b/src/menu/menuinput.cpp @@ -40,10 +40,11 @@ #include "d_gui.h" #include "v_font.h" #include "v_palette.h" +#include "cmdlib.h" // [TP] New #includes #include "v_text.h" -IMPLEMENT_ABSTRACT_CLASS(DTextEnterMenu) +IMPLEMENT_CLASS(DTextEnterMenu, true, false) #define INPUTGRID_WIDTH 13 #define INPUTGRID_HEIGHT 5 diff --git a/src/menu/messagebox.cpp b/src/menu/messagebox.cpp index 601c3e7365..c406fc7011 100644 --- a/src/menu/messagebox.cpp +++ b/src/menu/messagebox.cpp @@ -32,6 +32,7 @@ ** */ +#include #include "menu/menu.h" #include "d_event.h" #include "d_gui.h" @@ -62,7 +63,7 @@ class DMessageBoxMenu : public DMenu public: DMessageBoxMenu(DMenu *parent = NULL, const char *message = NULL, int messagemode = 0, bool playsound = false, FName action = NAME_None); - void Destroy(); + void Destroy() override; void Init(DMenu *parent, const char *message, int messagemode, bool playsound = false); void Drawer(); bool Responder(event_t *ev); @@ -72,7 +73,7 @@ public: virtual void HandleResult(bool res); }; -IMPLEMENT_CLASS(DMessageBoxMenu) +IMPLEMENT_CLASS(DMessageBoxMenu, false, false) //============================================================================= // @@ -127,6 +128,7 @@ void DMessageBoxMenu::Destroy() { if (mMessage != NULL) V_FreeBrokenLines(mMessage); mMessage = NULL; + Super::Destroy(); } //============================================================================= @@ -364,7 +366,7 @@ public: virtual void HandleResult(bool res); }; -IMPLEMENT_CLASS(DQuitMenu) +IMPLEMENT_CLASS(DQuitMenu, false, false) //============================================================================= // @@ -457,7 +459,7 @@ public: virtual void HandleResult(bool res); }; -IMPLEMENT_CLASS(DEndGameMenu) +IMPLEMENT_CLASS(DEndGameMenu, false, false) //============================================================================= // @@ -535,7 +537,7 @@ public: virtual void HandleResult(bool res); }; -IMPLEMENT_CLASS(DQuickSaveMenu) +IMPLEMENT_CLASS(DQuickSaveMenu, false, false) //============================================================================= // @@ -631,7 +633,7 @@ public: virtual void HandleResult(bool res); }; -IMPLEMENT_CLASS(DQuickLoadMenu) +IMPLEMENT_CLASS(DQuickLoadMenu, false, false) //============================================================================= // diff --git a/src/menu/optionmenu.cpp b/src/menu/optionmenu.cpp index efea7d9107..f9a29b6f53 100644 --- a/src/menu/optionmenu.cpp +++ b/src/menu/optionmenu.cpp @@ -64,8 +64,7 @@ void M_DrawConText (int color, int x, int y, const char *str) TAG_DONE); } - -IMPLEMENT_CLASS(DOptionMenu) +IMPLEMENT_CLASS(DOptionMenu, false, false) //============================================================================= // @@ -579,7 +578,7 @@ public: } }; -IMPLEMENT_CLASS(DGameplayMenu) +IMPLEMENT_CLASS(DGameplayMenu, false, false) class DCompatibilityMenu : public DOptionMenu { @@ -601,4 +600,4 @@ public: } }; -IMPLEMENT_CLASS(DCompatibilityMenu) +IMPLEMENT_CLASS(DCompatibilityMenu, false, false) diff --git a/src/menu/optionmenuitems.h b/src/menu/optionmenuitems.h index 0fadeca374..c3cb7297a4 100644 --- a/src/menu/optionmenuitems.h +++ b/src/menu/optionmenuitems.h @@ -399,7 +399,7 @@ public: }; #ifndef NO_IMP -IMPLEMENT_ABSTRACT_CLASS(DEnterKey) +IMPLEMENT_CLASS(DEnterKey, true, false) #endif //============================================================================= diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index ce542c2f2c..9f5196367a 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -526,7 +526,7 @@ public: void Drawer (); }; -IMPLEMENT_CLASS(DPlayerMenu) +IMPLEMENT_CLASS(DPlayerMenu, false, false) //============================================================================= // diff --git a/src/menu/readthis.cpp b/src/menu/readthis.cpp index 0aa3c2fcd2..b8a3837ee0 100644 --- a/src/menu/readthis.cpp +++ b/src/menu/readthis.cpp @@ -54,7 +54,7 @@ public: bool MouseEvent(int type, int x, int y); }; -IMPLEMENT_CLASS(DReadThisMenu) +IMPLEMENT_CLASS(DReadThisMenu, false, false) //============================================================================= // diff --git a/src/menu/videomenu.cpp b/src/menu/videomenu.cpp index b1b4d792fd..d8edee8f1e 100644 --- a/src/menu/videomenu.cpp +++ b/src/menu/videomenu.cpp @@ -183,7 +183,7 @@ public: } }; -IMPLEMENT_CLASS(DVideoModeMenu) +IMPLEMENT_CLASS(DVideoModeMenu, false, false) //============================================================================= diff --git a/src/namedef.h b/src/namedef.h index 8def090fa4..62d513437c 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -120,6 +120,11 @@ xx(ArtiPoisonBag3) // Strife quests xx(QuestItem) +xx(Sigil) +xx(ScriptedMarine) +xx(GiveSigilPiece) +xx(SetWeapon) +xx(SetSprite) // Armor xx(BasicArmor) @@ -209,7 +214,7 @@ xx(XDeath) xx(Burn) //xx(Ice) // already defined above xx(Disintegrate) -xx(Brainexplode) +xx(Smash) // Weapon animator names. xx(Select) @@ -285,6 +290,8 @@ xx(FRandom) xx(Random2) xx(RandomPick) xx(FRandomPick) +xx(GetClass) +xx(GetDefaultByType) xx(Exp) xx(Log10) xx(Ceil) @@ -313,6 +320,7 @@ xx(WaterLevel) xx(X) xx(Y) xx(Z) +xx(XY) xx(MomX) xx(MomY) xx(MomZ) @@ -436,6 +444,9 @@ xx(Scale) xx(ScaleX) xx(ScaleY) xx(Floatbobphase) +xx(Target) +xx(Master) +xx(Tracer) xx(Blocking) xx(Blockmonsters) @@ -671,13 +682,16 @@ xx(PlayerClass) xx(Wi_NoAutostartMap) // Decorate compatibility functions -xx(DecoRandom) -xx(DecoFRandom) -xx(DecoCallLineSpecial) -xx(DecoNameToClass) -xx(DecoFindMultiNameState) -xx(DecoFindSingleNameState) -xx(DecoHandleRuntimeState) +xx(BuiltinTypeCheck) +xx(BuiltinRandom) +xx(BuiltinFRandom) +xx(BuiltinCallLineSpecial) +xx(BuiltinNameToClass) +xx(BuiltinFindMultiNameState) +xx(BuiltinFindSingleNameState) +xx(BuiltinHandleRuntimeState) +xx(BuiltinGetDefault) +xx(BuiltinClassCast) xx(Damage) // basic type names @@ -689,6 +703,10 @@ xx(uShort) xx(Int) xx(uInt) xx(Bool) +xx(uint8) +xx(int8) +xx(uint16) +xx(int16) xx(Float) xx(Float32) xx(Float64) @@ -697,9 +715,13 @@ xx(String) xx(Vector) xx(Map) xx(Array) +xx(Include) xx(Sound) xx(State) xx(Fixed) +xx(Vector2) +xx(Vector3) +xx(let) xx(Min) xx(Max) @@ -715,7 +737,62 @@ xx(Mant_Dig) xx(Min_10_Exp) xx(Max_10_Exp) +// implicit function parameters +xx(self) +xx(invoker) +xx(stateinfo) + xx(__decorate_internal_int__) xx(__decorate_internal_bool__) -xx(__decorate_internal_state__) xx(__decorate_internal_float__) +xx(ResolveState) + +xx(DamageFunction) +xx(Length) +xx(Unit) +xx(StateLabel) +xx(SpriteID) +xx(TextureID) +xx(Overlay) +xx(IsValid) +xx(IsNull) +xx(Exists) +xx(SetInvalid) +xx(SetNull) + +xx(A_Punch) +xx(A_FirePistol) +xx(A_FireShotgun) +xx(A_FireShotgun2) +xx(A_FireCGun) +xx(A_FireMissile) +xx(A_Saw) +xx(A_FirePlasma) +xx(A_FireBFG) +xx(A_FireOldBFG) +xx(A_FireRailgun) + +// color channels +xx(a) +xx(r) +xx(g) +xx(b) + +// Special translation names +xx(RainPillar1) +xx(RainPillar2) +xx(RainPillar3) +xx(RainPillar4) +xx(RainPillar5) +xx(RainPillar6) +xx(RainPillar7) +xx(RainPillar8) + +xx(Player1) +xx(Player2) +xx(Player3) +xx(Player4) +xx(Player5) +xx(Player6) +xx(Player7) +xx(Player8) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 1a60a0c4fb..6a7c9d10c7 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -58,8 +58,6 @@ #include "sbar.h" #include "m_swap.h" #include "a_sharedglobal.h" -#include "a_doomglobal.h" -#include "a_strifeglobal.h" #include "v_video.h" #include "w_wad.h" #include "r_sky.h" @@ -83,8 +81,10 @@ #include "a_morph.h" #include "i_music.h" #include "serializer.h" - -#include "g_shared/a_pickups.h" +#include "thingdef.h" +#include "a_pickups.h" +#include "a_armor.h" +#include "a_ammo.h" extern FILE *Logfile; @@ -1368,9 +1368,11 @@ private: DPlaneWatcher() {} }; -IMPLEMENT_POINTY_CLASS (DPlaneWatcher) - DECLARE_POINTER (Activator) -END_POINTERS +IMPLEMENT_CLASS(DPlaneWatcher, false, true) + +IMPLEMENT_POINTERS_START(DPlaneWatcher) + IMPLEMENT_POINTER(Activator) +IMPLEMENT_POINTERS_END DPlaneWatcher::DPlaneWatcher (AActor *it, line_t *line, int lineSide, bool ceiling, int tag, int height, int special, @@ -2857,10 +2859,12 @@ void FBehavior::StaticStopMyScripts (AActor *actor) //---- The ACS Interpreter ----// -IMPLEMENT_POINTY_CLASS (DACSThinker) - DECLARE_POINTER(LastScript) - DECLARE_POINTER(Scripts) -END_POINTERS +IMPLEMENT_CLASS(DACSThinker, false, true) + +IMPLEMENT_POINTERS_START(DACSThinker) + IMPLEMENT_POINTER(LastScript) + IMPLEMENT_POINTER(Scripts) +IMPLEMENT_POINTERS_END TObjPtr DACSThinker::ActiveThinker; @@ -2986,11 +2990,13 @@ void DACSThinker::StopScriptsFor (AActor *actor) } } -IMPLEMENT_POINTY_CLASS (DLevelScript) - DECLARE_POINTER(next) - DECLARE_POINTER(prev) - DECLARE_POINTER(activator) -END_POINTERS +IMPLEMENT_CLASS(DLevelScript, false, true) + +IMPLEMENT_POINTERS_START(DLevelScript) + IMPLEMENT_POINTER(next) + IMPLEMENT_POINTER(prev) + IMPLEMENT_POINTER(activator) +IMPLEMENT_POINTERS_END //========================================================================== // @@ -5388,11 +5394,11 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) { if (!looping) { - S_PlaySound(spot, chan, sid, vol, atten, local); + S_PlaySound(spot, chan, sid, vol, atten, !!local); } else if (!S_IsActorPlayingSomething(spot, chan & 7, sid)) { - S_PlaySound(spot, chan | CHAN_LOOP, sid, vol, atten, local); + S_PlaySound(spot, chan | CHAN_LOOP, sid, vol, atten, !!local); } } } @@ -6103,6 +6109,28 @@ static bool CharArrayParms(int &capacity, int &offset, int &a, int *Stack, int & return true; } +static void SetMarineWeapon(AActor *marine, int weapon) +{ + static VMFunction *smw = nullptr; + if (smw == nullptr) smw = PClass::FindFunction(NAME_ScriptedMarine, NAME_SetWeapon); + if (smw) + { + VMValue params[2] = { marine, weapon }; + GlobalVMStack.Call(smw, params, 2, nullptr, 0, nullptr); + } +} + +static void SetMarineSprite(AActor *marine, PClassActor *source) +{ + static VMFunction *sms = nullptr; + if (sms == nullptr) sms = PClass::FindFunction(NAME_ScriptedMarine, NAME_SetSprite); + if (sms) + { + VMValue params[2] = { marine, source }; + GlobalVMStack.Call(sms, params, 2, nullptr, 0, nullptr); + } +} + int DLevelScript::RunScript () { DACSThinker *controller = DACSThinker::ActiveThinker; @@ -8543,15 +8571,15 @@ scriptwait: case PCD_GETSIGILPIECES: { - ASigil *sigil; + AInventory *sigil; - if (activator == NULL || (sigil = activator->FindInventory()) == NULL) + if (activator == NULL || (sigil = activator->FindInventory(PClass::FindActor(NAME_Sigil))) == NULL) { PushToStack (0); } else { - PushToStack (sigil->NumPieces); + PushToStack (sigil->health); } } break; @@ -8939,20 +8967,19 @@ scriptwait: case PCD_SETMARINEWEAPON: if (STACK(2) != 0) { - AScriptedMarine *marine; - TActorIterator iterator (STACK(2)); + AActor *marine; + NActorIterator iterator("ScriptedMarine", STACK(2)); while ((marine = iterator.Next()) != NULL) { - marine->SetWeapon ((AScriptedMarine::EMarineWeapon)STACK(1)); + SetMarineWeapon(marine, STACK(1)); } } else { - if (activator != NULL && activator->IsKindOf (RUNTIME_CLASS(AScriptedMarine))) + if (activator != nullptr && activator->IsKindOf (PClass::FindClass("ScriptedMarine"))) { - barrier_cast(activator)->SetWeapon ( - (AScriptedMarine::EMarineWeapon)STACK(1)); + SetMarineWeapon(activator, STACK(1)); } } sp -= 2; @@ -8966,19 +8993,19 @@ scriptwait: { if (STACK(2) != 0) { - AScriptedMarine *marine; - TActorIterator iterator (STACK(2)); + AActor *marine; + NActorIterator iterator("ScriptedMarine", STACK(2)); while ((marine = iterator.Next()) != NULL) { - marine->SetSprite (type); + SetMarineSprite(marine, type); } } else { - if (activator != NULL && activator->IsKindOf (RUNTIME_CLASS(AScriptedMarine))) + if (activator != nullptr && activator->IsKindOf(PClass::FindClass("ScriptedMarine"))) { - barrier_cast(activator)->SetSprite (type); + SetMarineSprite(activator, type); } } } diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 73cade49a4..12645561bb 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -53,7 +53,6 @@ #include "p_lnspec.h" #include "p_effect.h" #include "p_enemy.h" -#include "a_action.h" #include "decallib.h" #include "m_random.h" #include "i_system.h" @@ -61,7 +60,6 @@ #include "c_console.h" #include "doomerrors.h" #include "a_sharedglobal.h" -#include "thingdef/thingdef.h" #include "v_video.h" #include "v_font.h" #include "doomstat.h" @@ -77,7 +75,11 @@ #include "p_maputl.h" #include "p_spec.h" #include "templates.h" +#include "v_text.h" +#include "thingdef.h" #include "math/cmath.h" +#include "a_armor.h" +#include "a_health.h" AActor *SingleActorFromTID(int tid, AActor *defactor); @@ -125,17 +127,32 @@ bool ACustomInventory::CallStateChain (AActor *actor, FState *state) while (state != NULL) { + if (!(state->UseFlags & SUF_ITEM)) + { + auto so = FState::StaticFindStateOwner(state); + Printf(TEXTCOLOR_RED "State %s.%d not flagged for use in CustomInventory state chains.\n", so->TypeName.GetChars(), int(state - so->OwnedStates)); + return false; + } + this->state = state; nextstate = NULL; // assume no jump if (state->ActionFunc != NULL) { - VMFrameStack stack; + if (state->ActionFunc->Unsafe) + { + // If an unsafe function (i.e. one that accesses user variables) is being detected, print a warning once and remove the bogus function. We may not call it because that would inevitably crash. + auto owner = FState::StaticFindStateOwner(state); + Printf(TEXTCOLOR_RED "Unsafe state call in state %s.%d to %s which accesses user variables. The action function has been removed from this state\n", + owner->TypeName.GetChars(), int(state - owner->OwnedStates), state->ActionFunc->PrintableName.GetChars()); + state->ActionFunc = nullptr; + } + PPrototype *proto = state->ActionFunc->Proto; VMReturn *wantret; FStateParamInfo stp = { state, STATE_StateChain, PSP_WEAPON }; - params[2] = VMValue(&stp, ATAG_STATEINFO); + params[2] = VMValue(&stp, ATAG_GENERIC); retval = true; // assume success wantret = NULL; // assume no return value wanted numret = 0; @@ -166,7 +183,19 @@ bool ACustomInventory::CallStateChain (AActor *actor, FState *state) numret = 2; } } - stack.Call(state->ActionFunc, params, countof(params), wantret, numret); + try + { + GlobalVMStack.Call(state->ActionFunc, params, state->ActionFunc->ImplicitArgs, wantret, numret); + } + catch (CVMAbortException &err) + { + err.MaybePrintMessage(); + auto owner = FState::StaticFindStateOwner(state); + int offs = int(state - owner->OwnedStates); + err.stacktrace.AppendFormat("Called from state %s.%d in inventory state chain in %s\n", owner->TypeName.GetChars(), offs, GetClass()->TypeName.GetChars()); + throw; + } + // As long as even one state succeeds, the whole chain succeeds unless aborted below. // A state that wants to jump does not count as "succeeded". if (nextstate == NULL) @@ -195,6 +224,22 @@ bool ACustomInventory::CallStateChain (AActor *actor, FState *state) return !!result; } + +//========================================================================== +// +// GetPointer +// +// resolve AAPTR_* +// +//========================================================================== + +DEFINE_ACTION_FUNCTION(AActor, GetPointer) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(ptr); + ACTION_RETURN_OBJECT(COPY_AAPTR(self, ptr)); +} + //========================================================================== // // CheckClass @@ -210,11 +255,11 @@ DEFINE_ACTION_FUNCTION(AActor, CheckClass) assert(ret != NULL); PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS (checktype, AActor); - PARAM_INT_OPT (pick_pointer) { pick_pointer = AAPTR_DEFAULT; } - PARAM_BOOL_OPT (match_superclass) { match_superclass = false; } + PARAM_INT_DEF (pick_pointer); + PARAM_BOOL_DEF (match_superclass); self = COPY_AAPTR(self, pick_pointer); - if (self == NULL) + if (self == nullptr || checktype == nullptr) { ret->SetInt(false); } @@ -246,8 +291,8 @@ DEFINE_ACTION_FUNCTION(AActor, GetMissileDamage) assert(ret != NULL); PARAM_SELF_PROLOGUE(AActor); PARAM_INT(mask); - PARAM_INT(add) - PARAM_INT_OPT(pick_pointer) { pick_pointer = AAPTR_DEFAULT; } + PARAM_INT(add); + PARAM_INT_DEF(pick_pointer); self = COPY_AAPTR(self, pick_pointer); if (self == NULL) @@ -263,29 +308,6 @@ DEFINE_ACTION_FUNCTION(AActor, GetMissileDamage) return 0; } -//========================================================================== -// -// IsPointerEqual -// -// NON-ACTION function to check if two pointers are equal. -// -//========================================================================== - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, IsPointerEqual) -{ - if (numret > 0) - { - assert(ret != NULL); - PARAM_SELF_PROLOGUE(AActor); - PARAM_INT (ptr_select1); - PARAM_INT (ptr_select2); - - ret->SetInt(COPY_AAPTR(self, ptr_select1) == COPY_AAPTR(self, ptr_select2)); - return 1; - } - return 0; -} - //========================================================================== // // CountInv @@ -294,14 +316,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, IsPointerEqual) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, CountInv) +DEFINE_ACTION_FUNCTION(AActor, CountInv) { if (numret > 0) { assert(ret != NULL); PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS(itemtype, AInventory); - PARAM_INT_OPT(pick_pointer) { pick_pointer = AAPTR_DEFAULT; } + PARAM_INT_DEF(pick_pointer); self = COPY_AAPTR(self, pick_pointer); if (self == NULL || itemtype == NULL) @@ -325,14 +347,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, CountInv) // NON-ACTION function to get the distance in double. // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetDistance) +DEFINE_ACTION_FUNCTION(AActor, GetDistance) { if (numret > 0) { assert(ret != NULL); PARAM_SELF_PROLOGUE(AActor); PARAM_BOOL(checkz); - PARAM_INT_OPT(ptr) { ptr = AAPTR_TARGET; } + PARAM_INT_DEF(ptr); AActor *target = COPY_AAPTR(self, ptr); @@ -368,14 +390,14 @@ enum GAFlags GAF_SWITCH = 1 << 1, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetAngle) +DEFINE_ACTION_FUNCTION(AActor, GetAngle) { if (numret > 0) { assert(ret != NULL); PARAM_SELF_PROLOGUE(AActor); PARAM_INT(flags); - PARAM_INT_OPT(ptr) { ptr = AAPTR_TARGET; } + PARAM_INT_DEF(ptr) AActor *target = COPY_AAPTR(self, ptr); @@ -401,7 +423,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetAngle) // GetSpawnHealth // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetSpawnHealth) +DEFINE_ACTION_FUNCTION(AActor, GetSpawnHealth) { if (numret > 0) { @@ -417,7 +439,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetSpawnHealth) // GetGibHealth // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetGibHealth) +DEFINE_ACTION_FUNCTION(AActor, GetGibHealth) { if (numret > 0) { @@ -434,13 +456,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetGibHealth) // // NON-ACTION function returns the sprite angle of a pointer. //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetSpriteAngle) +DEFINE_ACTION_FUNCTION(AActor, GetSpriteAngle) { if (numret > 0) { assert(ret != NULL); PARAM_SELF_PROLOGUE(AActor); - PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + PARAM_INT_DEF(ptr); AActor *target = COPY_AAPTR(self, ptr); if (target == nullptr) @@ -463,13 +485,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetSpriteAngle) // // NON-ACTION function returns the sprite rotation of a pointer. //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetSpriteRotation) +DEFINE_ACTION_FUNCTION(AActor, GetSpriteRotation) { if (numret > 0) { assert(ret != NULL); PARAM_SELF_PROLOGUE(AActor); - PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + PARAM_INT_DEF(ptr); AActor *target = COPY_AAPTR(self, ptr); if (target == nullptr) @@ -503,17 +525,17 @@ enum GZFlags GZF_NO3DFLOOR = 1 << 5, // Pass all 3D floors. }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetZAt) +DEFINE_ACTION_FUNCTION(AActor, GetZAt) { if (numret > 0) { assert(ret != NULL); PARAM_SELF_PROLOGUE(AActor); - PARAM_FLOAT_OPT(px) { px = 0.; } - PARAM_FLOAT_OPT(py) { py = 0.; } - PARAM_ANGLE_OPT(angle) { angle = 0.; } - PARAM_INT_OPT(flags) { flags = 0; } - PARAM_INT_OPT(pick_pointer) { pick_pointer = AAPTR_DEFAULT; } + PARAM_FLOAT_DEF(px); + PARAM_FLOAT_DEF(py); + PARAM_ANGLE_DEF(angle); + PARAM_INT_DEF(flags); + PARAM_INT_DEF(pick_pointer); AActor *mobj = COPY_AAPTR(self, pick_pointer); if (mobj == nullptr) @@ -591,13 +613,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetZAt) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetCrouchFactor) +DEFINE_ACTION_FUNCTION(AActor, GetCrouchFactor) { if (numret > 0) { assert(ret != NULL); PARAM_SELF_PROLOGUE(AActor); - PARAM_INT_OPT(ptr) { ptr = AAPTR_PLAYER1; } + PARAM_INT_DEF(ptr); AActor *mobj = COPY_AAPTR(self, ptr); if (!mobj || !mobj->player) @@ -621,7 +643,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetCrouchFactor) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetCVar) +DEFINE_ACTION_FUNCTION(AActor, GetCVar) { if (numret > 0) { @@ -651,14 +673,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetCVar) // Takes a pointer as anyone may or may not be a player. //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetPlayerInput) +DEFINE_ACTION_FUNCTION(AActor, GetPlayerInput) { if (numret > 0) { assert(ret != nullptr); PARAM_SELF_PROLOGUE(AActor); PARAM_INT (inputnum); - PARAM_INT_OPT (ptr) { ptr = AAPTR_DEFAULT; } + PARAM_INT_DEF(ptr); AActor *mobj = COPY_AAPTR(self, ptr); @@ -684,15 +706,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetPlayerInput) // Takes a pointer as anyone may or may not be a player. //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, CountProximity) +DEFINE_ACTION_FUNCTION(AActor, CountProximity) { if (numret > 0) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS(classname, AActor); PARAM_FLOAT(distance); - PARAM_INT_OPT(flags) { flags = 0; } - PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + PARAM_INT_DEF(flags); + PARAM_INT_DEF(ptr); AActor *mobj = COPY_AAPTR(self, ptr); if (mobj == nullptr) @@ -710,7 +732,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, CountProximity) //=========================================================================== // -// __decorate_internal_state__ // __decorate_internal_int__ // __decorate_internal_bool__ // __decorate_internal_float__ @@ -720,28 +741,21 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, CountProximity) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, __decorate_internal_state__) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(returnme); - ACTION_RETURN_STATE(returnme); -} - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, __decorate_internal_int__) +DEFINE_ACTION_FUNCTION(AActor, __decorate_internal_int__) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT(returnme); ACTION_RETURN_INT(returnme); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, __decorate_internal_bool__) +DEFINE_ACTION_FUNCTION(AActor, __decorate_internal_bool__) { PARAM_SELF_PROLOGUE(AActor); PARAM_BOOL(returnme); ACTION_RETURN_BOOL(returnme); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, __decorate_internal_float__) +DEFINE_ACTION_FUNCTION(AActor, __decorate_internal_float__) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(returnme); @@ -764,13 +778,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, __decorate_internal_float__) //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RearrangePointers) +DEFINE_ACTION_FUNCTION(AActor, A_RearrangePointers) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (ptr_target); - PARAM_INT_OPT (ptr_master) { ptr_master = AAPTR_DEFAULT; } - PARAM_INT_OPT (ptr_tracer) { ptr_tracer = AAPTR_TRACER; } - PARAM_INT_OPT (flags) { flags = 0; } + PARAM_INT_DEF (ptr_master); + PARAM_INT_DEF (ptr_tracer); + PARAM_INT_DEF (flags); // Rearrange pointers internally @@ -844,14 +858,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RearrangePointers) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TransferPointer) +DEFINE_ACTION_FUNCTION(AActor, A_TransferPointer) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (ptr_source); PARAM_INT (ptr_recipient); PARAM_INT (ptr_sourcefield); - PARAM_INT_OPT (ptr_recipientfield) { ptr_recipientfield = AAPTR_DEFAULT; } - PARAM_INT_OPT (flags) { flags = 0; } + PARAM_INT_DEF (ptr_recipientfield); + PARAM_INT_DEF (flags); AActor *source, *recipient; @@ -887,10 +901,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TransferPointer) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CopyFriendliness) +DEFINE_ACTION_FUNCTION(AActor, A_CopyFriendliness) { - PARAM_ACTION_PROLOGUE; - PARAM_INT_OPT (ptr_source) { ptr_source = AAPTR_MASTER; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT_DEF (ptr_source); if (self->player != NULL) { @@ -905,39 +919,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CopyFriendliness) return 0; } -//========================================================================== -// -// Simple flag changers -// -//========================================================================== -DEFINE_ACTION_FUNCTION(AActor, A_SetSolid) -{ - PARAM_ACTION_PROLOGUE; - self->flags |= MF_SOLID; - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_UnsetSolid) -{ - PARAM_ACTION_PROLOGUE; - self->flags &= ~MF_SOLID; - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_SetFloat) -{ - PARAM_ACTION_PROLOGUE; - self->flags |= MF_FLOAT; - return 0; -} - -DEFINE_ACTION_FUNCTION(AActor, A_UnsetFloat) -{ - PARAM_ACTION_PROLOGUE; - self->flags &= ~(MF_FLOAT|MF_INFLOAT); - return 0; -} - //========================================================================== // // Customizable attack functions which use actor parameters. @@ -978,7 +959,7 @@ static void DoAttack (AActor *self, bool domelee, bool domissile, DEFINE_ACTION_FUNCTION(AActor, A_MeleeAttack) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); int MeleeDamage = self->GetClass()->MeleeDamage; FSoundID MeleeSound = self->GetClass()->MeleeSound; DoAttack(self, true, false, MeleeDamage, MeleeSound, NULL, 0); @@ -987,7 +968,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MeleeAttack) DEFINE_ACTION_FUNCTION(AActor, A_MissileAttack) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); PClassActor *MissileType = PClass::FindActor(self->GetClass()->MissileName); DoAttack(self, false, true, 0, 0, MissileType, self->GetClass()->MissileHeight); return 0; @@ -995,7 +976,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MissileAttack) DEFINE_ACTION_FUNCTION(AActor, A_ComboAttack) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); int MeleeDamage = self->GetClass()->MeleeDamage; FSoundID MeleeSound = self->GetClass()->MeleeSound; PClassActor *MissileType = PClass::FindActor(self->GetClass()->MissileName); @@ -1003,7 +984,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ComboAttack) return 0; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BasicAttack) +DEFINE_ACTION_FUNCTION(AActor, A_BasicAttack) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (melee_damage); @@ -1024,15 +1005,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BasicAttack) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlaySound) +DEFINE_ACTION_FUNCTION(AActor, A_PlaySound) { - PARAM_ACTION_PROLOGUE; - PARAM_SOUND_OPT (soundid) { soundid = "weapons/pistol"; } - PARAM_INT_OPT (channel) { channel = CHAN_BODY; } - PARAM_FLOAT_OPT (volume) { volume = 1; } - PARAM_BOOL_OPT (looping) { looping = false; } - PARAM_FLOAT_OPT (attenuation) { attenuation = ATTN_NORM; } - PARAM_BOOL_OPT (local) { local = false; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_SOUND_DEF (soundid); + PARAM_INT_DEF (channel); + PARAM_FLOAT_DEF (volume); + PARAM_BOOL_DEF (looping); + PARAM_FLOAT_DEF (attenuation); + PARAM_BOOL_DEF (local); if (!looping) { @@ -1048,10 +1029,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlaySound) return 0; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StopSound) +DEFINE_ACTION_FUNCTION(AActor, A_StopSound) { - PARAM_ACTION_PROLOGUE; - PARAM_INT_OPT(slot) { slot = CHAN_VOICE; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT_DEF(slot); S_StopSound(self, slot); return 0; @@ -1066,22 +1047,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StopSound) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlayWeaponSound) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_SOUND(soundid); - - S_Sound(self, CHAN_WEAPON, soundid, 1, ATTN_NORM); - return 0; -} - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlaySoundEx) +DEFINE_ACTION_FUNCTION(AActor, A_PlaySoundEx) { PARAM_SELF_PROLOGUE(AActor); PARAM_SOUND (soundid); PARAM_NAME (channel); - PARAM_BOOL_OPT (looping) { looping = false; } - PARAM_INT_OPT (attenuation_raw) { attenuation_raw = 0; } + PARAM_BOOL_DEF (looping); + PARAM_INT_DEF (attenuation_raw); float attenuation; switch (attenuation_raw) @@ -1112,7 +1084,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlaySoundEx) return 0; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StopSoundEx) +DEFINE_ACTION_FUNCTION(AActor, A_StopSoundEx) { PARAM_SELF_PROLOGUE(AActor); PARAM_NAME(channel); @@ -1136,14 +1108,14 @@ enum SMF_PRECISE = 2, SMF_CURSPEED = 4, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SeekerMissile) +DEFINE_ACTION_FUNCTION(AActor, A_SeekerMissile) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT(ang1); PARAM_INT(ang2); - PARAM_INT_OPT(flags) { flags = 0; } - PARAM_INT_OPT(chance) { chance = 50; } - PARAM_INT_OPT(distance) { distance = 10; } + PARAM_INT_DEF(flags); + PARAM_INT_DEF(chance); + PARAM_INT_DEF(distance); if ((flags & SMF_LOOK) && (self->tracer == 0) && (pr_seekermissile() 0 && (maxchance >= 256 || pr_cajump() < maxchance)) { int jumpnum = (count == 1 ? 0 : (pr_cajump() % count)); - PARAM_STATE_AT(paramnum + jumpnum, jumpto); + PARAM_STATE_ACTION_AT(paramnum + jumpnum, jumpto); ACTION_RETURN_STATE(jumpto); } ACTION_RETURN_STATE(NULL); @@ -1214,137 +1186,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Jump) // State jump function // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfHealthLower) + +DEFINE_ACTION_FUNCTION(AActor, CheckInventory) { PARAM_SELF_PROLOGUE(AActor); - PARAM_INT (health); - PARAM_STATE (jump); - PARAM_INT_OPT (ptr_selector) { ptr_selector = AAPTR_DEFAULT; } - - AActor *measured; - - measured = COPY_AAPTR(self, ptr_selector); - - if (measured != NULL && measured->health < health) - { - ACTION_RETURN_STATE(jump); - } - ACTION_RETURN_STATE(NULL); -} - -//========================================================================== -// -// State jump function -// -//========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetOutsideMeleeRange) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(jump); - - if (!self->CheckMeleeRange()) - { - ACTION_RETURN_STATE(jump); - } - ACTION_RETURN_STATE(NULL); -} - -//========================================================================== -// -// State jump function -// -//========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInsideMeleeRange) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(jump); - - if (self->CheckMeleeRange()) - { - ACTION_RETURN_STATE(jump); - } - ACTION_RETURN_STATE(NULL); -} - -//========================================================================== -// -// State jump function -// -//========================================================================== -static int DoJumpIfCloser(AActor *target, VM_ARGS) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_FLOAT (dist); - PARAM_STATE (jump); - PARAM_BOOL_OPT(noz) { noz = false; } - - if (!target) - { // No target - no jump - ACTION_RETURN_STATE(NULL); - } - if (self->Distance2D(target) < dist && - (noz || - ((self->Z() > target->Z() && self->Z() - target->Top() < dist) || - (self->Z() <= target->Z() && target->Z() - self->Top() < dist)))) - { - ACTION_RETURN_STATE(jump); - } - ACTION_RETURN_STATE(NULL); -} - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfCloser) -{ - PARAM_SELF_PROLOGUE(AActor); - - AActor *target; - - if (self->player == NULL) - { - target = self->target; - } - else - { - // Does the player aim at something that can be shot? - FTranslatedLineTarget t; - P_BulletSlope(self, &t, ALF_PORTALRESTRICT); - target = t.linetarget; - } - return DoJumpIfCloser(target, VM_ARGS_NAMES); -} - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTracerCloser) -{ - PARAM_SELF_PROLOGUE(AActor); - return DoJumpIfCloser(self->tracer, VM_ARGS_NAMES); -} - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfMasterCloser) -{ - PARAM_SELF_PROLOGUE(AActor); - return DoJumpIfCloser(self->master, VM_ARGS_NAMES); -} - -//========================================================================== -// -// State jump function -// -//========================================================================== -int DoJumpIfInventory(AActor *owner, AActor *self, VMValue *param, int numparam, VMReturn *ret, int numret) -{ - int paramnum = 0; PARAM_CLASS (itemtype, AInventory); PARAM_INT (itemamount); - PARAM_STATE (label); - PARAM_INT_OPT (setowner) { setowner = AAPTR_DEFAULT; } + PARAM_INT_DEF (setowner); - if (itemtype == NULL) + if (itemtype == nullptr) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } - owner = COPY_AAPTR(owner, setowner); - if (owner == NULL) + AActor *owner = COPY_AAPTR(self, setowner); + if (owner == nullptr) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } AInventory *item = owner->FindInventory(itemtype); @@ -1355,48 +1212,32 @@ int DoJumpIfInventory(AActor *owner, AActor *self, VMValue *param, int numparam, { if (item->Amount >= itemamount) { - ACTION_RETURN_STATE(label); + ACTION_RETURN_BOOL(true); } } else if (item->Amount >= item->MaxAmount) { - ACTION_RETURN_STATE(label); + ACTION_RETURN_BOOL(true); } } - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInventory) -{ - PARAM_SELF_PROLOGUE(AActor); - return DoJumpIfInventory(self, self, param, numparam, ret, numret); -} - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetInventory) -{ - PARAM_SELF_PROLOGUE(AActor); - return DoJumpIfInventory(self->target, self, param, numparam, ret, numret); -} //========================================================================== // // State jump function // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfArmorType) +DEFINE_ACTION_FUNCTION(AActor, CheckArmorType) { PARAM_SELF_PROLOGUE(AActor); PARAM_NAME (type); - PARAM_STATE (label); - PARAM_INT_OPT(amount) { amount = 1; } + PARAM_INT_DEF(amount); ABasicArmor *armor = (ABasicArmor *)self->FindInventory(NAME_BasicArmor); - if (armor && armor->ArmorType == type && armor->Amount >= amount) - { - ACTION_RETURN_STATE(label); - } - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(armor && armor->ArmorType == type && armor->Amount >= amount); } //========================================================================== @@ -1410,20 +1251,21 @@ enum XF_HURTSOURCE = 1, XF_NOTMISSILE = 4, XF_NOACTORTYPE = 1 << 3, + XF_NOSPLASH = 16, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode) +DEFINE_ACTION_FUNCTION(AActor, A_Explode) { - PARAM_ACTION_PROLOGUE; - PARAM_INT_OPT (damage) { damage = -1; } - PARAM_INT_OPT (distance) { distance = -1; } - PARAM_INT_OPT (flags) { flags = XF_HURTSOURCE; } - PARAM_BOOL_OPT (alert) { alert = false; } - PARAM_INT_OPT (fulldmgdistance) { fulldmgdistance = 0; } - PARAM_INT_OPT (nails) { nails = 0; } - PARAM_INT_OPT (naildamage) { naildamage = 10; } - PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindActor(NAME_BulletPuff); } - PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT_DEF (damage); + PARAM_INT_DEF (distance); + PARAM_INT_DEF (flags); + PARAM_BOOL_DEF (alert); + PARAM_INT_DEF (fulldmgdistance); + PARAM_INT_DEF (nails); + PARAM_INT_DEF (naildamage); + PARAM_CLASS_DEF (pufftype, AActor); + PARAM_NAME_DEF (damagetype); if (damage < 0) // get parameters from metadata { @@ -1460,7 +1302,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode) if (flags & XF_NOTMISSILE) pflags |= RADF_SOURCEISSPOT; int count = P_RadiusAttack (self, self->target, damage, distance, damagetype, pflags, fulldmgdistance); - P_CheckSplash(self, distance); + if (!(flags & XF_NOSPLASH)) P_CheckSplash(self, distance); if (alert && self->target != NULL && self->target->player != NULL) { P_NoiseAlert(self->target, self); @@ -1481,13 +1323,13 @@ enum RTF_NOTMISSILE = 4, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusThrust) +DEFINE_ACTION_FUNCTION(AActor, A_RadiusThrust) { - PARAM_ACTION_PROLOGUE; - PARAM_INT_OPT (force) { force = 128; } - PARAM_INT_OPT (distance) { distance = -1; } - PARAM_INT_OPT (flags) { flags = RTF_AFFECTSOURCE; } - PARAM_INT_OPT (fullthrustdistance) { fullthrustdistance = 0; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT_DEF (force); + PARAM_INT_DEF (distance); + PARAM_INT_DEF (flags); + PARAM_INT_DEF (fullthrustdistance); bool sourcenothrust = false; @@ -1521,13 +1363,13 @@ enum RDSF_BFGDAMAGE = 1, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusDamageSelf) +DEFINE_ACTION_FUNCTION(AActor, A_RadiusDamageSelf) { - PARAM_ACTION_PROLOGUE; - PARAM_INT_OPT(damage) { damage = 128; } - PARAM_FLOAT_OPT(distance) { distance = 128; } - PARAM_INT_OPT(flags) { flags = 0; } - PARAM_CLASS_OPT(flashtype, AActor) { flashtype = NULL; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT_DEF(damage); + PARAM_FLOAT_DEF(distance); + PARAM_INT_DEF(flags); + PARAM_CLASS_DEF(flashtype, AActor); int i; int damageSteps; @@ -1582,15 +1424,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusDamageSelf) // Execute a line special / script // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CallSpecial) +DEFINE_ACTION_FUNCTION(AActor, A_CallSpecial) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (special); - PARAM_INT_OPT (arg1) { arg1 = 0; } - PARAM_INT_OPT (arg2) { arg2 = 0; } - PARAM_INT_OPT (arg3) { arg3 = 0; } - PARAM_INT_OPT (arg4) { arg4 = 0; } - PARAM_INT_OPT (arg5) { arg5 = 0; } + PARAM_INT_DEF (arg1); + PARAM_INT_DEF (arg2); + PARAM_INT_DEF (arg3); + PARAM_INT_DEF (arg4); + PARAM_INT_DEF (arg5); bool res = !!P_ExecuteSpecial(special, NULL, self, false, arg1, arg2, arg3, arg4, arg5); @@ -1615,16 +1457,16 @@ enum CM_Flags CMF_ABSOLUTEANGLE = 128 }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile) +DEFINE_ACTION_FUNCTION(AActor, A_CustomMissile) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS (ti, AActor); - PARAM_FLOAT_OPT (Spawnheight) { Spawnheight = 32; } - PARAM_FLOAT_OPT (Spawnofs_xy) { Spawnofs_xy = 0; } - PARAM_ANGLE_OPT (Angle) { Angle = 0.; } - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_ANGLE_OPT (Pitch) { Pitch = 0.; } - PARAM_INT_OPT (ptr) { ptr = AAPTR_TARGET; } + PARAM_FLOAT_DEF (Spawnheight); + PARAM_FLOAT_DEF (Spawnofs_xy); + PARAM_ANGLE_DEF (Angle); + PARAM_INT_DEF (flags); + PARAM_ANGLE_DEF (Pitch); + PARAM_INT_DEF (ptr); AActor *ref = COPY_AAPTR(self, ptr); @@ -1764,20 +1606,20 @@ enum CBA_Flags static void AimBulletMissile(AActor *proj, AActor *puff, int flags, bool temp, bool cba); -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) +DEFINE_ACTION_FUNCTION(AActor, A_CustomBulletAttack) { PARAM_SELF_PROLOGUE(AActor); PARAM_ANGLE (spread_xy); PARAM_ANGLE (spread_z); PARAM_INT (numbullets); PARAM_INT (damageperbullet); - PARAM_CLASS_OPT (pufftype, AActor) { pufftype = nullptr; } - PARAM_FLOAT_OPT (range) { range = 0; } - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_INT_OPT (ptr) { ptr = AAPTR_TARGET; } - PARAM_CLASS_OPT (missile, AActor) { missile = nullptr; } - PARAM_FLOAT_OPT (Spawnheight) { Spawnheight = 32; } - PARAM_FLOAT_OPT (Spawnofs_xy) { Spawnofs_xy = 0; } + PARAM_CLASS_DEF (pufftype, AActor); + PARAM_FLOAT_DEF (range); + PARAM_INT_DEF (flags); + PARAM_INT_DEF (ptr); + PARAM_CLASS_DEF (missile, AActor); + PARAM_FLOAT_DEF (Spawnheight); + PARAM_FLOAT_DEF (Spawnofs_xy); AActor *ref = COPY_AAPTR(self, ptr); @@ -1856,14 +1698,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) // A fully customizable melee attack // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMeleeAttack) +DEFINE_ACTION_FUNCTION(AActor, A_CustomMeleeAttack) { - PARAM_ACTION_PROLOGUE; - PARAM_INT_OPT (damage) { damage = 0; } - PARAM_SOUND_OPT (meleesound) { meleesound = 0; } - PARAM_SOUND_OPT (misssound) { misssound = 0; } - PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } - PARAM_BOOL_OPT (bleed) { bleed = true; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT_DEF (damage); + PARAM_SOUND_DEF (meleesound); + PARAM_SOUND_DEF (misssound); + PARAM_NAME_DEF (damagetype); + PARAM_BOOL_DEF (bleed); if (damagetype == NAME_None) damagetype = NAME_Melee; // Melee is the default type @@ -1893,15 +1735,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMeleeAttack) // A fully customizable combo attack // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomComboAttack) +DEFINE_ACTION_FUNCTION(AActor, A_CustomComboAttack) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS (ti, AActor); PARAM_FLOAT (spawnheight); PARAM_INT (damage); - PARAM_SOUND_OPT (meleesound) { meleesound = 0; } - PARAM_NAME_OPT (damagetype) { damagetype = NAME_Melee; } - PARAM_BOOL_OPT (bleed) { bleed = true; } + PARAM_SOUND_DEF (meleesound); + PARAM_NAME_DEF (damagetype); + PARAM_BOOL_DEF (bleed); if (!self->target) return 0; @@ -1943,10 +1785,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomComboAttack) // State jump function // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfNoAmmo) +DEFINE_ACTION_FUNCTION(AStateProvider, A_JumpIfNoAmmo) { - PARAM_ACTION_PROLOGUE; - PARAM_STATE(jump); + PARAM_ACTION_PROLOGUE(AStateProvider); + PARAM_STATE_ACTION(jump); if (!ACTION_CALL_FROM_PSPRITE() || self->player->ReadyWeapon == nullptr) { @@ -2014,19 +1856,19 @@ static void AimBulletMissile(AActor *proj, AActor *puff, int flags, bool temp, b } } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets) +DEFINE_ACTION_FUNCTION(AStateProvider, A_FireBullets) { - PARAM_ACTION_PROLOGUE; + PARAM_ACTION_PROLOGUE(AStateProvider); PARAM_ANGLE (spread_xy); PARAM_ANGLE (spread_z); PARAM_INT (numbullets); PARAM_INT (damageperbullet); - PARAM_CLASS_OPT (pufftype, AActor) { pufftype = nullptr; } - PARAM_INT_OPT (flags) { flags = FBF_USEAMMO; } - PARAM_FLOAT_OPT (range) { range = 0; } - PARAM_CLASS_OPT (missile, AActor) { missile = nullptr; } - PARAM_FLOAT_OPT (Spawnheight) { Spawnheight = 0; } - PARAM_FLOAT_OPT (Spawnofs_xy) { Spawnofs_xy = 0; } + PARAM_CLASS_DEF (pufftype, AActor); + PARAM_INT_DEF (flags); + PARAM_FLOAT_DEF (range); + PARAM_CLASS_DEF (missile, AActor); + PARAM_FLOAT_DEF (Spawnheight); + PARAM_FLOAT_DEF (Spawnofs_xy); if (!self->player) return 0; @@ -2144,16 +1986,16 @@ enum FP_Flags FPF_TRANSFERTRANSLATION = 2, FPF_NOAUTOAIM = 4, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireCustomMissile) +DEFINE_ACTION_FUNCTION(AStateProvider, A_FireCustomMissile) { - PARAM_ACTION_PROLOGUE; + PARAM_ACTION_PROLOGUE(AStateProvider); PARAM_CLASS (ti, AActor); - PARAM_ANGLE_OPT (angle) { angle = 0.; } - PARAM_BOOL_OPT (useammo) { useammo = true; } - PARAM_FLOAT_OPT (spawnofs_xy) { spawnofs_xy = 0; } - PARAM_FLOAT_OPT (spawnheight) { spawnheight = 0; } - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_ANGLE_OPT (pitch) { pitch = 0.; } + PARAM_ANGLE_DEF (angle); + PARAM_BOOL_DEF (useammo); + PARAM_FLOAT_DEF (spawnofs_xy); + PARAM_FLOAT_DEF (spawnheight); + PARAM_INT_DEF (flags); + PARAM_ANGLE_DEF (pitch); if (!self->player) return 0; @@ -2221,19 +2063,19 @@ enum CPF_STEALARMOR = 32, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) +DEFINE_ACTION_FUNCTION(AStateProvider, A_CustomPunch) { - PARAM_ACTION_PROLOGUE; + PARAM_ACTION_PROLOGUE(AStateProvider); PARAM_INT (damage); - PARAM_BOOL_OPT (norandom) { norandom = false; } - PARAM_INT_OPT (flags) { flags = CPF_USEAMMO; } - PARAM_CLASS_OPT (pufftype, AActor) { pufftype = NULL; } - PARAM_FLOAT_OPT (range) { range = 0; } - PARAM_FLOAT_OPT (lifesteal) { lifesteal = 0; } - PARAM_INT_OPT (lifestealmax) { lifestealmax = 0; } - PARAM_CLASS_OPT (armorbonustype, ABasicArmorBonus) { armorbonustype = NULL; } - PARAM_SOUND_OPT (MeleeSound) { MeleeSound = ""; } - PARAM_SOUND_OPT (MissSound) { MissSound = ""; } + PARAM_BOOL_DEF (norandom); + PARAM_INT_DEF (flags); + PARAM_CLASS_DEF (pufftype, AActor); + PARAM_FLOAT_DEF (range); + PARAM_FLOAT_DEF (lifesteal); + PARAM_INT_DEF (lifestealmax); + PARAM_CLASS_DEF (armorbonustype, ABasicArmorBonus); + PARAM_SOUND_DEF (MeleeSound); + PARAM_SOUND_DEF (MissSound); if (!self->player) return 0; @@ -2325,27 +2167,27 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) // customizable railgun attack function // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack) +DEFINE_ACTION_FUNCTION(AStateProvider, A_RailAttack) { - PARAM_ACTION_PROLOGUE; + PARAM_ACTION_PROLOGUE(AStateProvider); PARAM_INT (damage); - PARAM_INT_OPT (spawnofs_xy) { spawnofs_xy = 0; } - PARAM_BOOL_OPT (useammo) { useammo = true; } - PARAM_COLOR_OPT (color1) { color1 = 0; } - PARAM_COLOR_OPT (color2) { color2 = 0; } - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_FLOAT_OPT (maxdiff) { maxdiff = 0; } - PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindActor(NAME_BulletPuff); } - PARAM_ANGLE_OPT (spread_xy) { spread_xy = 0.; } - PARAM_ANGLE_OPT (spread_z) { spread_z = 0.; } - PARAM_FLOAT_OPT (range) { range = 0; } - PARAM_INT_OPT (duration) { duration = 0; } - PARAM_FLOAT_OPT (sparsity) { sparsity = 1; } - PARAM_FLOAT_OPT (driftspeed) { driftspeed = 1; } - PARAM_CLASS_OPT (spawnclass, AActor){ spawnclass = NULL; } - PARAM_FLOAT_OPT (spawnofs_z) { spawnofs_z = 0; } - PARAM_INT_OPT (SpiralOffset) { SpiralOffset = 270; } - PARAM_INT_OPT (limit) { limit = 0; } + PARAM_INT_DEF (spawnofs_xy); + PARAM_BOOL_DEF (useammo); + PARAM_COLOR_DEF (color1); + PARAM_COLOR_DEF (color2); + PARAM_INT_DEF (flags); + PARAM_FLOAT_DEF (maxdiff); + PARAM_CLASS_DEF (pufftype, AActor); + PARAM_ANGLE_DEF (spread_xy); + PARAM_ANGLE_DEF (spread_z); + PARAM_FLOAT_DEF (range) ; + PARAM_INT_DEF (duration); + PARAM_FLOAT_DEF (sparsity); + PARAM_FLOAT_DEF (driftspeed); + PARAM_CLASS_DEF (spawnclass, AActor); + PARAM_FLOAT_DEF (spawnofs_z); + PARAM_INT_DEF (SpiralOffset); + PARAM_INT_DEF (limit); if (range == 0) range = 8192; if (sparsity == 0) sparsity=1.0; @@ -2404,27 +2246,27 @@ enum CRF_EXPLICITANGLE = 4, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) +DEFINE_ACTION_FUNCTION(AActor, A_CustomRailgun) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (damage); - PARAM_INT_OPT (spawnofs_xy) { spawnofs_xy = 0; } - PARAM_COLOR_OPT (color1) { color1 = 0; } - PARAM_COLOR_OPT (color2) { color2 = 0; } - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_INT_OPT (aim) { aim = CRF_DONTAIM; } - PARAM_FLOAT_OPT (maxdiff) { maxdiff = 0; } - PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindActor(NAME_BulletPuff); } - PARAM_ANGLE_OPT (spread_xy) { spread_xy = 0.; } - PARAM_ANGLE_OPT (spread_z) { spread_z = 0.; } - PARAM_FLOAT_OPT (range) { range = 0; } - PARAM_INT_OPT (duration) { duration = 0; } - PARAM_FLOAT_OPT (sparsity) { sparsity = 1; } - PARAM_FLOAT_OPT (driftspeed) { driftspeed = 1; } - PARAM_CLASS_OPT (spawnclass, AActor){ spawnclass = NULL; } - PARAM_FLOAT_OPT (spawnofs_z) { spawnofs_z = 0; } - PARAM_INT_OPT (SpiralOffset) { SpiralOffset = 270; } - PARAM_INT_OPT (limit) { limit = 0; } + PARAM_INT_DEF (spawnofs_xy) + PARAM_COLOR_DEF (color1) + PARAM_COLOR_DEF (color2) + PARAM_INT_DEF (flags) + PARAM_INT_DEF (aim) + PARAM_FLOAT_DEF (maxdiff) + PARAM_CLASS_DEF (pufftype, AActor) + PARAM_ANGLE_DEF (spread_xy) + PARAM_ANGLE_DEF (spread_z) + PARAM_FLOAT_DEF (range) + PARAM_INT_DEF (duration) + PARAM_FLOAT_DEF (sparsity) + PARAM_FLOAT_DEF (driftspeed) + PARAM_CLASS_DEF (spawnclass, AActor) + PARAM_FLOAT_DEF (spawnofs_z) + PARAM_INT_DEF (SpiralOffset) + PARAM_INT_DEF (limit) if (range == 0) range = 8192.; if (sparsity == 0) sparsity = 1; @@ -2526,17 +2368,22 @@ static bool DoGiveInventory(AActor *receiver, bool orresult, VM_ARGS) { int paramnum = 0; PARAM_CLASS (mi, AInventory); - PARAM_INT_OPT (amount) { amount = 1; } + PARAM_INT_DEF (amount) if (!orresult) { - PARAM_INT_OPT(setreceiver) { setreceiver = AAPTR_DEFAULT; } + PARAM_INT_DEF(setreceiver) receiver = COPY_AAPTR(receiver, setreceiver); } if (receiver == NULL) { // If there's nothing to receive it, it's obviously a fail, right? return false; } + // Owned inventory items cannot own anything because their Inventory pointer is repurposed for the owner's linked list. + if (receiver->IsKindOf(RUNTIME_CLASS(AInventory)) && static_cast(receiver)->Owner != nullptr) + { + return false; + } if (amount <= 0) { @@ -2572,19 +2419,19 @@ static bool DoGiveInventory(AActor *receiver, bool orresult, VM_ARGS) return false; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveInventory) +DEFINE_ACTION_FUNCTION(AActor, A_GiveInventory) { PARAM_SELF_PROLOGUE(AActor); ACTION_RETURN_BOOL(DoGiveInventory(self, false, VM_ARGS_NAMES)); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToTarget) +DEFINE_ACTION_FUNCTION(AActor, A_GiveToTarget) { PARAM_SELF_PROLOGUE(AActor); ACTION_RETURN_BOOL(DoGiveInventory(self->target, false, VM_ARGS_NAMES)); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToChildren) +DEFINE_ACTION_FUNCTION(AActor, A_GiveToChildren) { PARAM_SELF_PROLOGUE(AActor); @@ -2602,7 +2449,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToChildren) ACTION_RETURN_INT(count); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToSiblings) +DEFINE_ACTION_FUNCTION(AActor, A_GiveToSiblings) { PARAM_SELF_PROLOGUE(AActor); @@ -2629,13 +2476,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToSiblings) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetInventory) +DEFINE_ACTION_FUNCTION(AActor, A_SetInventory) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS(itemtype, AInventory); PARAM_INT(amount); - PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } - PARAM_BOOL_OPT(beyondMax) { beyondMax = false; } + PARAM_INT_DEF(ptr); + PARAM_BOOL_DEF(beyondMax); bool res = false; @@ -2724,8 +2571,8 @@ bool DoTakeInventory(AActor *receiver, bool orresult, VM_ARGS) { int paramnum = 0; PARAM_CLASS (itemtype, AInventory); - PARAM_INT_OPT (amount) { amount = 0; } - PARAM_INT_OPT (flags) { flags = 0; } + PARAM_INT_DEF (amount); + PARAM_INT_DEF (flags); if (itemtype == NULL) { @@ -2733,7 +2580,7 @@ bool DoTakeInventory(AActor *receiver, bool orresult, VM_ARGS) } if (!orresult) { - PARAM_INT_OPT(setreceiver) { setreceiver = AAPTR_DEFAULT; } + PARAM_INT_DEF(setreceiver); receiver = COPY_AAPTR(receiver, setreceiver); } if (receiver == NULL) @@ -2744,19 +2591,19 @@ bool DoTakeInventory(AActor *receiver, bool orresult, VM_ARGS) return receiver->TakeInventory(itemtype, amount, true, (flags & TIF_NOTAKEINFINITE) != 0); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeInventory) +DEFINE_ACTION_FUNCTION(AActor, A_TakeInventory) { PARAM_SELF_PROLOGUE(AActor); ACTION_RETURN_BOOL(DoTakeInventory(self, false, VM_ARGS_NAMES)); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeFromTarget) +DEFINE_ACTION_FUNCTION(AActor, A_TakeFromTarget) { PARAM_SELF_PROLOGUE(AActor); ACTION_RETURN_BOOL(DoTakeInventory(self->target, false, VM_ARGS_NAMES)); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeFromChildren) +DEFINE_ACTION_FUNCTION(AActor, A_TakeFromChildren) { PARAM_SELF_PROLOGUE(AActor); TThinkerIterator it; @@ -2773,7 +2620,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeFromChildren) ACTION_RETURN_INT(count); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeFromSiblings) +DEFINE_ACTION_FUNCTION(AActor, A_TakeFromSiblings) { PARAM_SELF_PROLOGUE(AActor); TThinkerIterator it; @@ -3009,14 +2856,14 @@ static bool InitSpawnedItem(AActor *self, AActor *mo, int flags) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItem) +DEFINE_ACTION_FUNCTION(AActor, A_SpawnItem) { - PARAM_ACTION_PROLOGUE; - PARAM_CLASS_OPT (missile, AActor) { missile = PClass::FindActor("Unknown"); } - PARAM_FLOAT_OPT (distance) { distance = 0; } - PARAM_FLOAT_OPT (zheight) { zheight = 0; } - PARAM_BOOL_OPT (useammo) { useammo = true; } - PARAM_BOOL_OPT (transfer_translation) { transfer_translation = false; } + PARAM_ACTION_PROLOGUE(AActor); + PARAM_CLASS_DEF (missile, AActor) + PARAM_FLOAT_DEF (distance) + PARAM_FLOAT_DEF (zheight) + PARAM_BOOL_DEF (useammo) + PARAM_BOOL_DEF (transfer_translation) if (missile == NULL) { @@ -3057,20 +2904,20 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItem) // Enhanced spawning function // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) +DEFINE_ACTION_FUNCTION(AActor, A_SpawnItemEx) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS (missile, AActor); - PARAM_FLOAT_OPT (xofs) { xofs = 0; } - PARAM_FLOAT_OPT (yofs) { yofs = 0; } - PARAM_FLOAT_OPT (zofs) { zofs = 0; } - PARAM_FLOAT_OPT (xvel) { xvel = 0; } - PARAM_FLOAT_OPT (yvel) { yvel = 0; } - PARAM_FLOAT_OPT (zvel) { zvel = 0; } - PARAM_ANGLE_OPT (angle) { angle = 0.; } - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_INT_OPT (chance) { chance = 0; } - PARAM_INT_OPT (tid) { tid = 0; } + PARAM_FLOAT_DEF (xofs) + PARAM_FLOAT_DEF (yofs) + PARAM_FLOAT_DEF (zofs) + PARAM_FLOAT_DEF (xvel) + PARAM_FLOAT_DEF (yvel) + PARAM_FLOAT_DEF (zvel) + PARAM_ANGLE_DEF (angle) + PARAM_INT_DEF (flags) + PARAM_INT_DEF (chance) + PARAM_INT_DEF (tid) if (missile == NULL) { @@ -3141,14 +2988,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItemEx) // Throws a grenade (like Hexen's fighter flechette) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade) +DEFINE_ACTION_FUNCTION(AActor, A_ThrowGrenade) { - PARAM_ACTION_PROLOGUE; + PARAM_ACTION_PROLOGUE(AActor); PARAM_CLASS (missile, AActor); - PARAM_FLOAT_OPT (zheight) { zheight = 0; } - PARAM_FLOAT_OPT (xyvel) { xyvel = 0; } - PARAM_FLOAT_OPT (zvel) { zvel = 0; } - PARAM_BOOL_OPT (useammo) { useammo = true; } + PARAM_FLOAT_DEF (zheight) + PARAM_FLOAT_DEF (xyvel) + PARAM_FLOAT_DEF (zvel) + PARAM_BOOL_DEF (useammo) if (missile == NULL) { @@ -3219,7 +3066,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade) // A_Recoil // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Recoil) +DEFINE_ACTION_FUNCTION(AActor, A_Recoil) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(xyvel); @@ -3238,11 +3085,11 @@ enum SW_Flags { SWF_SELECTPRIORITY = 1, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SelectWeapon) +DEFINE_ACTION_FUNCTION(AActor, A_SelectWeapon) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS(cls, AWeapon); - PARAM_INT_OPT(flags) { flags = 0; } + PARAM_INT_DEF(flags); bool selectPriority = !!(flags & SWF_SELECTPRIORITY); @@ -3283,12 +3130,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SelectWeapon) //=========================================================================== EXTERN_CVAR(Float, con_midtime) -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Print) +DEFINE_ACTION_FUNCTION(AActor, A_Print) { PARAM_SELF_PROLOGUE(AActor); PARAM_STRING (text); - PARAM_FLOAT_OPT (time) { time = 0; } - PARAM_NAME_OPT (fontname) { fontname = NAME_None; } + PARAM_FLOAT_DEF (time); + PARAM_NAME_DEF (fontname); if (text[0] == '$') text = GStrings(&text[1]); if (self->CheckLocalView (consoleplayer) || @@ -3318,12 +3165,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Print) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PrintBold) +DEFINE_ACTION_FUNCTION(AActor, A_PrintBold) { PARAM_SELF_PROLOGUE(AActor); PARAM_STRING (text); - PARAM_FLOAT_OPT (time) { time = 0; } - PARAM_NAME_OPT (fontname) { fontname = NAME_None; } + PARAM_FLOAT_DEF (time); + PARAM_NAME_DEF (fontname); float saved = con_midtime; FFont *font = NULL; @@ -3349,7 +3196,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PrintBold) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Log) +DEFINE_ACTION_FUNCTION(AActor, A_Log) { PARAM_SELF_PROLOGUE(AActor); PARAM_STRING(text); @@ -3366,7 +3213,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Log) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LogInt) +DEFINE_ACTION_FUNCTION(AActor, A_LogInt) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT(num); @@ -3380,7 +3227,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LogInt) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LogFloat) +DEFINE_ACTION_FUNCTION(AActor, A_LogFloat) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(num); @@ -3395,11 +3242,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LogFloat) // A_SetTranslucent // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTranslucent) +DEFINE_ACTION_FUNCTION(AActor, A_SetTranslucent) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT (alpha); - PARAM_INT_OPT (mode) { mode = 0; } + PARAM_INT_DEF (mode); mode = mode == 0 ? STYLE_Translucent : mode == 2 ? STYLE_Fuzzy : STYLE_Add; @@ -3414,11 +3261,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTranslucent) // A_SetRenderStyle // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRenderStyle) +DEFINE_ACTION_FUNCTION(AActor, A_SetRenderStyle) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(alpha); - PARAM_INT_OPT(mode) { mode = 0; } + PARAM_INT_DEF(mode); self->Alpha = clamp(alpha, 0., 1.); self->RenderStyle = ERenderStyle(mode); @@ -3439,11 +3286,12 @@ enum FadeFlags FTF_CLAMP = 1 << 1, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeIn) +DEFINE_ACTION_FUNCTION(AActor, A_FadeIn) { - PARAM_ACTION_PROLOGUE; - PARAM_FLOAT_OPT(reduce) { reduce = 0.1; } - PARAM_INT_OPT(flags) { flags = 0; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT_DEF(reduce); + PARAM_INT_DEF(flags); + if (reduce == 0) { @@ -3473,11 +3321,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeIn) // fades the actor out and destroys it when done // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeOut) +DEFINE_ACTION_FUNCTION(AActor, A_FadeOut) { - PARAM_ACTION_PROLOGUE; - PARAM_FLOAT_OPT(reduce) { reduce = 0.1; } - PARAM_INT_OPT(flags) { flags = FTF_REMOVE; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT_DEF(reduce); + PARAM_INT_DEF(flags); if (reduce == 0) { @@ -3507,12 +3355,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeOut) // destroys it if so desired // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeTo) +DEFINE_ACTION_FUNCTION(AActor, A_FadeTo) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT (target); - PARAM_FLOAT_OPT (amount) { amount = 0.1; } - PARAM_INT_OPT (flags) { flags = 0; } + PARAM_FLOAT_DEF (amount); + PARAM_INT_DEF (flags); self->RenderStyle.Flags &= ~STYLEF_Alpha1; @@ -3545,62 +3393,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeTo) return 0; } -//=========================================================================== -// -// A_Scale(float scalex, optional float scaley) -// -// Scales the actor's graphics. If scaley is 0, use scalex. -// -//=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetScale) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_FLOAT (scalex); - PARAM_FLOAT_OPT (scaley) { scaley = scalex; } - PARAM_INT_OPT (ptr) { ptr = AAPTR_DEFAULT; } - PARAM_BOOL_OPT (usezero) { usezero = false; } - - AActor *ref = COPY_AAPTR(self, ptr); - - if (ref != NULL) - { - if (scaley == 0 && !usezero) - { - scaley = scalex; - } - ref->Scale = { scalex, scaley }; - } - return 0; -} - -//=========================================================================== -// -// A_SetMass(int mass) -// -// Sets the actor's mass. -// -//=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetMass) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_INT (mass); - - self->Mass = mass; - return 0; -} - //=========================================================================== // // A_SpawnDebris // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnDebris) +DEFINE_ACTION_FUNCTION(AActor, A_SpawnDebris) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS (debris, AActor); - PARAM_BOOL_OPT (transfer_translation) { transfer_translation = false; } - PARAM_FLOAT_OPT (mult_h) { mult_h = 1; } - PARAM_FLOAT_OPT (mult_v) { mult_v = 1; } + PARAM_BOOL_DEF (transfer_translation) + PARAM_FLOAT_DEF (mult_h) + PARAM_FLOAT_DEF (mult_v) int i; AActor *mo; @@ -3650,26 +3454,26 @@ enum SPFflag SPF_NOTIMEFREEZE = 1 << 5, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnParticle) +DEFINE_ACTION_FUNCTION(AActor, A_SpawnParticle) { PARAM_SELF_PROLOGUE(AActor); PARAM_COLOR (color); - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_INT_OPT (lifetime) { lifetime = 35; } - PARAM_FLOAT_OPT (size) { size = 1.; } - PARAM_ANGLE_OPT (angle) { angle = 0.; } - PARAM_FLOAT_OPT (xoff) { xoff = 0; } - PARAM_FLOAT_OPT (yoff) { yoff = 0; } - PARAM_FLOAT_OPT (zoff) { zoff = 0; } - PARAM_FLOAT_OPT (xvel) { xvel = 0; } - PARAM_FLOAT_OPT (yvel) { yvel = 0; } - PARAM_FLOAT_OPT (zvel) { zvel = 0; } - PARAM_FLOAT_OPT (accelx) { accelx = 0; } - PARAM_FLOAT_OPT (accely) { accely = 0; } - PARAM_FLOAT_OPT (accelz) { accelz = 0; } - PARAM_FLOAT_OPT (startalpha) { startalpha = 1.; } - PARAM_FLOAT_OPT (fadestep) { fadestep = -1.; } - PARAM_FLOAT_OPT (sizestep) { sizestep = 0.; } + PARAM_INT_DEF (flags) + PARAM_INT_DEF (lifetime) + PARAM_FLOAT_DEF (size) + PARAM_ANGLE_DEF (angle) + PARAM_FLOAT_DEF (xoff) + PARAM_FLOAT_DEF (yoff) + PARAM_FLOAT_DEF (zoff) + PARAM_FLOAT_DEF (xvel) + PARAM_FLOAT_DEF (yvel) + PARAM_FLOAT_DEF (zvel) + PARAM_FLOAT_DEF (accelx) + PARAM_FLOAT_DEF (accely) + PARAM_FLOAT_DEF (accelz) + PARAM_FLOAT_DEF (startalpha) + PARAM_FLOAT_DEF (fadestep) + PARAM_FLOAT_DEF (sizestep) startalpha = clamp(startalpha, 0., 1.); if (fadestep > 0) fadestep = clamp(fadestep, 0., 1.); @@ -3711,10 +3515,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnParticle) // jumps if no player can see this actor // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSight) +DEFINE_ACTION_FUNCTION(AActor, CheckIfSeen) { PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(jump); for (int i = 0; i < MAXPLAYERS; i++) { @@ -3723,17 +3526,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSight) // Always check sight from each player. if (P_CheckSight(players[i].mo, self, SF_IGNOREVISIBILITY)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } // If a player is viewing from a non-player, then check that too. if (players[i].camera != NULL && players[i].camera->player == NULL && P_CheckSight(players[i].camera, self, SF_IGNOREVISIBILITY)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } } } - ACTION_RETURN_STATE(jump); + ACTION_RETURN_BOOL(true); } //=========================================================================== @@ -3780,12 +3583,11 @@ static bool DoCheckSightOrRange(AActor *self, AActor *camera, double range, bool return false; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSightOrRange) +DEFINE_ACTION_FUNCTION(AActor, CheckSightOrRange) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(range); - PARAM_STATE(jump); - PARAM_BOOL_OPT(twodi) { twodi = false; } + PARAM_BOOL_DEF(twodi); range *= range; for (int i = 0; i < MAXPLAYERS; ++i) @@ -3795,26 +3597,25 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSightOrRange) // Always check from each player. if (DoCheckSightOrRange(self, players[i].mo, range, twodi, true)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } // If a player is viewing from a non-player, check that too. if (players[i].camera != NULL && players[i].camera->player == NULL && DoCheckSightOrRange(self, players[i].camera, range, twodi, true)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } } } - ACTION_RETURN_STATE(jump); + ACTION_RETURN_BOOL(true); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckRange) +DEFINE_ACTION_FUNCTION(AActor, CheckRange) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(range); - PARAM_STATE(jump); - PARAM_BOOL_OPT(twodi) { twodi = false; } + PARAM_BOOL_DEF(twodi); range *= range; for (int i = 0; i < MAXPLAYERS; ++i) @@ -3824,17 +3625,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckRange) // Always check from each player. if (DoCheckSightOrRange(self, players[i].mo, range, twodi, false)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } // If a player is viewing from a non-player, check that too. if (players[i].camera != NULL && players[i].camera->player == NULL && DoCheckSightOrRange(self, players[i].camera, range, twodi, false)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } } } - ACTION_RETURN_STATE(jump); + ACTION_RETURN_BOOL(true); } @@ -3843,7 +3644,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckRange) // Inventory drop // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DropInventory) +DEFINE_ACTION_FUNCTION(AActor, A_DropInventory) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS(drop, AInventory); @@ -3865,13 +3666,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DropInventory) // A_SetBlend // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetBlend) +DEFINE_ACTION_FUNCTION(AActor, A_SetBlend) { PARAM_SELF_PROLOGUE(AActor); PARAM_COLOR (color); PARAM_FLOAT (alpha); PARAM_INT (tics); - PARAM_COLOR_OPT (color2) { color2 = 0; } + PARAM_COLOR_DEF (color2); if (color == MAKEARGB(255,255,255,255)) color = 0; @@ -3887,31 +3688,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetBlend) } -//=========================================================================== -// -// A_JumpIf -// -//=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIf) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_BOOL (condition); - PARAM_STATE (jump); - - ACTION_RETURN_STATE(condition ? jump : NULL); -} - //=========================================================================== // // A_CountdownArg // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CountdownArg) +DEFINE_ACTION_FUNCTION(AActor, A_CountdownArg) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT(cnt); - PARAM_STATE_OPT(state) { state = self->FindState(NAME_Death); } + PARAM_STATE_DEF(state) if (cnt<0 || cnt >= 5) return 0; if (!self->args[cnt]--) @@ -3926,6 +3713,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CountdownArg) } else { + if (state == nullptr) state = self->FindState(NAME_Death); self->SetState(state); } } @@ -3938,7 +3726,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CountdownArg) // //============================================================================ -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Burst) +DEFINE_ACTION_FUNCTION(AActor, A_Burst) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS(chunk, AActor); @@ -3990,43 +3778,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Burst) return 0; } -//=========================================================================== -// -// A_CheckFloor -// [GRB] Jumps if actor is standing on floor -// -//=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckFloor) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(jump); - - if (self->Z() <= self->floorz) - { - ACTION_RETURN_STATE(jump); - } - ACTION_RETURN_STATE(NULL); -} - -//=========================================================================== -// -// A_CheckCeiling -// [GZ] Totally copied from A_CheckFloor, jumps if actor touches ceiling -// - -//=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckCeiling) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(jump); - - if (self->Top() >= self->ceilingz) // Height needs to be counted - { - ACTION_RETURN_STATE(jump); - } - ACTION_RETURN_STATE(NULL); -} - //=========================================================================== // // A_Stop @@ -4035,7 +3786,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckCeiling) //=========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_Stop) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); self->Vel.Zero(); if (self->player && self->player->mo == self && !(self->player->cheats & CF_PREDICTING)) { @@ -4062,8 +3813,6 @@ static void CheckStopped(AActor *self) // //=========================================================================== -DECLARE_ACTION(A_RestoreSpecialPosition) - enum RS_Flags { RSF_FOG=1, @@ -4071,10 +3820,10 @@ enum RS_Flags RSF_TELEFRAG=4, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn) +DEFINE_ACTION_FUNCTION(AActor, A_Respawn) { - PARAM_ACTION_PROLOGUE; - PARAM_INT_OPT(flags) { flags = RSF_FOG; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT_DEF(flags); bool oktorespawn = false; DVector3 pos = self->Pos(); @@ -4082,7 +3831,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn) self->flags |= MF_SOLID; self->Height = self->GetDefault()->Height; self->radius = self->GetDefault()->radius; - CALL_ACTION(A_RestoreSpecialPosition, self); + self->RestoreSpecialPosition(); if (flags & RSF_TELEFRAG) { @@ -4150,51 +3899,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlayerSkinCheck) +DEFINE_ACTION_FUNCTION(AActor, PlayerSkinCheck) { PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(jump); - if (self->player != NULL && - skins[self->player->userinfo.GetSkin()].othergame) - { - ACTION_RETURN_STATE(jump); - } - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(self->player != NULL && + skins[self->player->userinfo.GetSkin()].othergame); } -//=========================================================================== -// -// A_SetGravity -// -//=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetGravity) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_FLOAT(gravity); - - self->Gravity = clamp(gravity, 0., 10.); - return 0; -} - - // [KS] *** Start of my modifications *** -//=========================================================================== -// -// A_ClearTarget -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_ClearTarget) -{ - PARAM_ACTION_PROLOGUE; - self->target = NULL; - self->LastHeard = NULL; - self->lastenemy = NULL; - return 0; -} - //========================================================================== // // A_CheckLOF (state jump, int flags = CRF_AIM_VERT|CRF_AIM_HOR, @@ -4323,7 +4037,7 @@ ETraceStatus CheckLOFTraceFunc(FTraceResults &trace, void *userdata) return TRACE_Abort; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) +DEFINE_ACTION_FUNCTION(AActor, CheckLOF) { // Check line of fire @@ -4336,16 +4050,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) DVector3 vel; PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE (jump); - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_FLOAT_OPT (range) { range = 0; } - PARAM_FLOAT_OPT (minrange) { minrange = 0; } - PARAM_ANGLE_OPT (angle) { angle = 0.; } - PARAM_ANGLE_OPT (pitch) { pitch = 0.; } - PARAM_FLOAT_OPT (offsetheight) { offsetheight = 0; } - PARAM_FLOAT_OPT (offsetwidth) { offsetwidth = 0; } - PARAM_INT_OPT (ptr_target) { ptr_target = AAPTR_DEFAULT; } - PARAM_FLOAT_OPT (offsetforward) { offsetforward = 0; } + PARAM_INT_DEF (flags) + PARAM_FLOAT_DEF (range) + PARAM_FLOAT_DEF (minrange) + PARAM_ANGLE_DEF (angle) + PARAM_ANGLE_DEF (pitch) + PARAM_FLOAT_DEF (offsetheight) + PARAM_FLOAT_DEF (offsetwidth) + PARAM_INT_DEF (ptr_target) + PARAM_FLOAT_DEF (offsetforward) DAngle ang; @@ -4393,7 +4106,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) double distance = self->Distance3D(target); if (distance > range) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } } @@ -4442,7 +4155,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) } else { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } double cp = pitch.Cos(); @@ -4480,7 +4193,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) { if (minrange > 0 && trace.Distance < minrange) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } if ((trace.HitType == TRACE_HitActor) && (trace.Actor != NULL) && !(lof_data.BadActor)) { @@ -4488,9 +4201,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF) if (flags & (CLOFF_SETMASTER)) self->master = trace.Actor; if (flags & (CLOFF_SETTRACER)) self->tracer = trace.Actor; } - ACTION_RETURN_STATE(jump); + ACTION_RETURN_BOOL(true); } - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } //========================================================================== @@ -4525,14 +4238,13 @@ enum JLOS_flags JLOSF_CHECKTRACER = 1 << 12, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) +DEFINE_ACTION_FUNCTION(AActor, CheckIfTargetInLOS) { PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE (jump); - PARAM_ANGLE_OPT (fov) { fov = 0.; } - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_FLOAT_OPT (dist_max) { dist_max = 0; } - PARAM_FLOAT_OPT (dist_close) { dist_close = 0; } + PARAM_ANGLE_DEF (fov) + PARAM_INT_DEF (flags) + PARAM_FLOAT_DEF (dist_max) + PARAM_FLOAT_DEF (dist_close) AActor *target, *viewport; FTranslatedLineTarget t; @@ -4559,11 +4271,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) if (target == NULL) { // [KS] Let's not call P_CheckSight unnecessarily in this case. - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } if ((flags & JLOSF_DEADNOJUMP) && (target->health <= 0)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } doCheckSight = !(flags & JLOSF_NOSIGHT); @@ -4575,7 +4287,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) if (!t.linetarget) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } target = t.linetarget; @@ -4601,24 +4313,24 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) // [FDARI] If target is not a combatant, don't jump if ( (flags & JLOSF_COMBATANTONLY) && (!target->player) && !(target->flags3 & MF3_ISMONSTER)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } // [FDARI] If actors share team, don't jump if ((flags & JLOSF_ALLYNOJUMP) && self->IsFriend(target)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } double distance = self->Distance3D(target); if (dist_max && (distance > dist_max)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } if (dist_close && (distance < dist_close)) { if (flags & JLOSF_CLOSENOJUMP) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } if (flags & JLOSF_CLOSENOFOV) fov = 0.; @@ -4632,7 +4344,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) if (doCheckSight && !P_CheckSight (viewport, target, SF_IGNOREVISIBILITY)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } if (flags & JLOSF_FLIPFOV) @@ -4649,10 +4361,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) if (an > (fov / 2)) { - ACTION_RETURN_STATE(NULL); // [KS] Outside of FOV - return + ACTION_RETURN_BOOL(false); // [KS] Outside of FOV - return } } - ACTION_RETURN_STATE(jump); + ACTION_RETURN_BOOL(true); } @@ -4663,14 +4375,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) +DEFINE_ACTION_FUNCTION(AActor, CheckIfInTargetLOS) { PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE (jump); - PARAM_ANGLE_OPT (fov) { fov = 0.; } - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_FLOAT_OPT (dist_max) { dist_max = 0; } - PARAM_FLOAT_OPT (dist_close) { dist_close = 0; } + PARAM_ANGLE_DEF (fov) + PARAM_INT_DEF (flags) + PARAM_FLOAT_DEF (dist_max) + PARAM_FLOAT_DEF (dist_close) AActor *target; @@ -4692,19 +4403,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) if (target == NULL) { // [KS] Let's not call P_CheckSight unnecessarily in this case. - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } if ((flags & JLOSF_DEADNOJUMP) && (target->health <= 0)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } double distance = self->Distance3D(target); if (dist_max && (distance > dist_max)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } bool doCheckSight = !(flags & JLOSF_NOSIGHT); @@ -4713,7 +4424,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) { if (flags & JLOSF_CLOSENOJUMP) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } if (flags & JLOSF_CLOSENOFOV) fov = 0.; @@ -4728,14 +4439,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) if (an > (fov / 2)) { - ACTION_RETURN_STATE(NULL); // [KS] Outside of FOV - return + ACTION_RETURN_BOOL(false); // [KS] Outside of FOV - return } } if (doCheckSight && !P_CheckSight (target, self, SF_IGNOREVISIBILITY)) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } - ACTION_RETURN_STATE(jump); + ACTION_RETURN_BOOL(true); } //=========================================================================== @@ -4744,17 +4455,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckForReload) +DEFINE_ACTION_FUNCTION(AStateProvider, A_CheckForReload) { - PARAM_ACTION_PROLOGUE; + PARAM_ACTION_PROLOGUE(AStateProvider); if ( self->player == NULL || self->player->ReadyWeapon == NULL ) { ACTION_RETURN_STATE(NULL); } PARAM_INT (count); - PARAM_STATE (jump); - PARAM_BOOL_OPT (dontincrement) { dontincrement = false; } + PARAM_STATE_ACTION (jump); + PARAM_BOOL_DEF (dontincrement); if (numret > 0) { @@ -4797,9 +4508,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckForReload) // //=========================================================================== -DEFINE_ACTION_FUNCTION(AActor, A_ResetReloadCounter) +DEFINE_ACTION_FUNCTION(AStateProvider, A_ResetReloadCounter) { - PARAM_ACTION_PROLOGUE; + PARAM_ACTION_PROLOGUE(AStateProvider); if (self->player == NULL || self->player->ReadyWeapon == NULL) return 0; @@ -4814,7 +4525,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ResetReloadCounter) // A_ChangeFlag // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag) +DEFINE_ACTION_FUNCTION(AActor, A_ChangeFlag) { PARAM_SELF_PROLOGUE(AActor); PARAM_STRING (flagname); @@ -4830,27 +4541,51 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckFlag) +DEFINE_ACTION_FUNCTION(AActor, CheckFlag) { PARAM_SELF_PROLOGUE(AActor); PARAM_STRING (flagname); - PARAM_STATE (jumpto); - PARAM_INT_OPT (checkpointer) { checkpointer = AAPTR_DEFAULT; } + PARAM_INT_DEF (checkpointer); AActor *owner = COPY_AAPTR(self, checkpointer); - if (owner == NULL) - { - ACTION_RETURN_STATE(NULL); - } - - if (CheckActorFlag(owner, flagname)) - { - ACTION_RETURN_STATE(jumpto); - } - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(owner != nullptr && CheckActorFlag(owner, flagname)); } +DEFINE_ACTION_FUNCTION(AActor, A_ChangeCountFlags) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT_DEF(kill); + PARAM_INT_DEF(item); + PARAM_INT_DEF(secret); + + if (self->CountsAsKill() && self->health > 0) --level.total_monsters; + if (self->flags & MF_COUNTITEM) --level.total_items; + if (self->flags5 & MF5_COUNTSECRET) --level.total_secrets; + + if (kill != -1) + { + if (kill == 0) self->flags &= ~MF_COUNTKILL; + else self->flags |= MF_COUNTKILL; + } + + if (item != -1) + { + if (item == 0) self->flags &= ~MF_COUNTITEM; + else self->flags |= MF_COUNTITEM; + } + + if (secret != -1) + { + if (secret == 0) self->flags5 &= ~MF5_COUNTSECRET; + else self->flags5 |= MF5_COUNTSECRET; + } + if (self->CountsAsKill() && self->health > 0) ++level.total_monsters; + if (self->flags & MF_COUNTITEM) ++level.total_items; + if (self->flags5 & MF5_COUNTSECRET) ++level.total_secrets; + return 0; +} + //=========================================================================== // // A_RaiseMaster @@ -4858,8 +4593,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckFlag) //=========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_RaiseMaster) { - PARAM_ACTION_PROLOGUE; - PARAM_BOOL_OPT(copy) { copy = false; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_BOOL_DEF(copy); if (self->master != NULL) { @@ -4875,8 +4610,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseMaster) //=========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_RaiseChildren) { - PARAM_ACTION_PROLOGUE; - PARAM_BOOL_OPT(copy) { copy = false; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_BOOL_DEF(copy); TThinkerIterator it; AActor *mo; @@ -4898,8 +4633,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseChildren) //=========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_RaiseSiblings) { - PARAM_ACTION_PROLOGUE; - PARAM_BOOL_OPT(copy) { copy = false; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_BOOL_DEF(copy); TThinkerIterator it; AActor *mo; @@ -4917,18 +4652,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseSiblings) return 0; } - //=========================================================================== - // -// [TP] A_FaceConsolePlayer -// -//=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS (AActor, A_FaceConsolePlayer) -{ - // NOTE: It does nothing for ZDoom, since in a multiplayer game, each - // node has its own console player. - return 0; -} - //=========================================================================== // // A_MonsterRefire @@ -4936,7 +4659,7 @@ DEFINE_ACTION_FUNCTION_PARAMS (AActor, A_FaceConsolePlayer) // Keep firing unless target got out of sight // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MonsterRefire) +DEFINE_ACTION_FUNCTION(AActor, A_MonsterRefire) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (prob); @@ -4972,12 +4695,12 @@ enum }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetAngle) +DEFINE_ACTION_FUNCTION(AActor, A_SetAngle) { - PARAM_ACTION_PROLOGUE; - PARAM_FLOAT_OPT(angle) { angle = 0; } - PARAM_INT_OPT(flags) { flags = 0; } - PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT_DEF(angle); + PARAM_INT_DEF(flags); + PARAM_INT_DEF(ptr); AActor *ref = COPY_AAPTR(self, ptr); if (ref != NULL) @@ -4995,12 +4718,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetAngle) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetPitch) +DEFINE_ACTION_FUNCTION(AActor, A_SetPitch) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(pitch); - PARAM_INT_OPT(flags) { flags = 0; } - PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + PARAM_INT_DEF(flags); + PARAM_INT_DEF(ptr); AActor *ref = COPY_AAPTR(self, ptr); @@ -5019,12 +4742,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetPitch) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRoll) +DEFINE_ACTION_FUNCTION(AActor, A_SetRoll) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT (roll); - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_INT_OPT (ptr) { ptr = AAPTR_DEFAULT; } + PARAM_INT_DEF (flags); + PARAM_INT_DEF (ptr) ; AActor *ref = COPY_AAPTR(self, ptr); if (ref != NULL) @@ -5042,11 +4765,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRoll) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ScaleVelocity) +DEFINE_ACTION_FUNCTION(AActor, A_ScaleVelocity) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(scale); - PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + PARAM_INT_DEF(ptr); AActor *ref = COPY_AAPTR(self, ptr); @@ -5074,14 +4797,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ScaleVelocity) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeVelocity) +DEFINE_ACTION_FUNCTION(AActor, A_ChangeVelocity) { - PARAM_ACTION_PROLOGUE; - PARAM_FLOAT_OPT (x) { x = 0; } - PARAM_FLOAT_OPT (y) { y = 0; } - PARAM_FLOAT_OPT (z) { z = 0; } - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_INT_OPT (ptr) { ptr = AAPTR_DEFAULT; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT_DEF (x) + PARAM_FLOAT_DEF (y) + PARAM_FLOAT_DEF (z) + PARAM_INT_DEF (flags) + PARAM_INT_DEF (ptr) AActor *ref = COPY_AAPTR(self, ptr); @@ -5117,51 +4840,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeVelocity) return 0; } -//=========================================================================== -// -// A_SetArg -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetArg) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_INT(pos); - PARAM_INT(value); - - // Set the value of the specified arg - if ((size_t)pos < countof(self->args)) - { - self->args[pos] = value; - } - return 0; -} - -//=========================================================================== -// -// A_SetSpecial -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpecial) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_INT (spec); - PARAM_INT_OPT (arg0) { arg0 = 0; } - PARAM_INT_OPT (arg1) { arg1 = 0; } - PARAM_INT_OPT (arg2) { arg2 = 0; } - PARAM_INT_OPT (arg3) { arg3 = 0; } - PARAM_INT_OPT (arg4) { arg4 = 0; } - - self->special = spec; - self->args[0] = arg0; - self->args[1] = arg1; - self->args[2] = arg2; - self->args[3] = arg3; - self->args[4] = arg4; - return 0; -} - //=========================================================================== // // A_SetUserVar @@ -5172,7 +4850,7 @@ static PField *GetVar(DObject *self, FName varname) { PField *var = dyn_cast(self->GetClass()->Symbols.FindSymbol(varname, true)); - if (var == NULL || (var->Flags & VARF_Native) || !var->Type->IsKindOf(RUNTIME_CLASS(PBasicType))) + if (var == NULL || (var->Flags & (VARF_Native | VARF_Private | VARF_Protected | VARF_Static)) || !var->Type->IsKindOf(RUNTIME_CLASS(PBasicType))) { Printf("%s is not a user variable in class %s\n", varname.GetChars(), self->GetClass()->TypeName.GetChars()); @@ -5181,7 +4859,7 @@ static PField *GetVar(DObject *self, FName varname) return var; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserVar) +DEFINE_ACTION_FUNCTION(AActor, A_SetUserVar) { PARAM_SELF_PROLOGUE(DObject); PARAM_NAME (varname); @@ -5196,7 +4874,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserVar) return 0; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserVarFloat) +DEFINE_ACTION_FUNCTION(AActor, A_SetUserVarFloat) { PARAM_SELF_PROLOGUE(DObject); PARAM_NAME (varname); @@ -5221,7 +4899,7 @@ static PField *GetArrayVar(DObject *self, FName varname, int pos) { PField *var = dyn_cast(self->GetClass()->Symbols.FindSymbol(varname, true)); - if (var == NULL || (var->Flags & VARF_Native) || + if (var == NULL || (var->Flags & (VARF_Native | VARF_Private | VARF_Protected | VARF_Static)) || !var->Type->IsKindOf(RUNTIME_CLASS(PArray)) || !static_cast(var->Type)->ElementType->IsKindOf(RUNTIME_CLASS(PBasicType))) { @@ -5238,7 +4916,7 @@ static PField *GetArrayVar(DObject *self, FName varname, int pos) return var; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserArray) +DEFINE_ACTION_FUNCTION(AActor, A_SetUserArray) { PARAM_SELF_PROLOGUE(DObject); PARAM_NAME (varname); @@ -5255,7 +4933,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserArray) return 0; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserArrayFloat) +DEFINE_ACTION_FUNCTION(AActor, A_SetUserArrayFloat) { PARAM_SELF_PROLOGUE(DObject); PARAM_NAME (varname); @@ -5299,16 +4977,16 @@ enum T_Flags TF_SENSITIVEZ = 0x00000800, // Fail if the actor wouldn't fit in the position (for Z). }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) +DEFINE_ACTION_FUNCTION(AActor, A_Teleport) { - PARAM_ACTION_PROLOGUE; - PARAM_STATE_OPT (teleport_state) { teleport_state = NULL; } - PARAM_CLASS_OPT (target_type, ASpecialSpot) { target_type = PClass::FindActor("BossSpot"); } - PARAM_CLASS_OPT (fog_type, AActor) { fog_type = PClass::FindActor("TeleportFog"); } - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_FLOAT_OPT (mindist) { mindist = 128; } - PARAM_FLOAT_OPT (maxdist) { maxdist = 0; } - PARAM_INT_OPT (ptr) { ptr = AAPTR_DEFAULT; } + PARAM_ACTION_PROLOGUE(AActor); + PARAM_STATE_DEF (teleport_state) + PARAM_CLASS_DEF (target_type, ASpecialSpot) + PARAM_CLASS_DEF (fog_type, AActor) + PARAM_INT_DEF (flags) + PARAM_FLOAT_DEF (mindist) + PARAM_FLOAT_DEF (maxdist) + PARAM_INT_DEF (ptr) AActor *ref = COPY_AAPTR(self, ptr); @@ -5469,34 +5147,20 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) return numret; } -//=========================================================================== -// -// A_Turn -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Turn) -{ - PARAM_ACTION_PROLOGUE; - PARAM_FLOAT_OPT(angle) { angle = 0; } - self->Angles.Yaw += angle; - return 0; -} - //=========================================================================== // // A_Quake // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Quake) +DEFINE_ACTION_FUNCTION(AActor, A_Quake) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (intensity); PARAM_INT (duration); PARAM_INT (damrad); PARAM_INT (tremrad); - PARAM_SOUND_OPT (sound) { sound = "world/quake"; } + PARAM_SOUND_DEF (sound); P_StartQuake(self, 0, intensity, duration, damrad, tremrad, sound); return 0; @@ -5510,7 +5174,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Quake) // take flags. //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_QuakeEx) +DEFINE_ACTION_FUNCTION(AActor, A_QuakeEx) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT(intensityX); @@ -5519,15 +5183,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_QuakeEx) PARAM_INT(duration); PARAM_INT(damrad); PARAM_INT(tremrad); - PARAM_SOUND_OPT (sound) { sound = "world/quake"; } - PARAM_INT_OPT(flags) { flags = 0; } - PARAM_FLOAT_OPT(mulWaveX) { mulWaveX = 1.; } - PARAM_FLOAT_OPT(mulWaveY) { mulWaveY = 1.; } - PARAM_FLOAT_OPT(mulWaveZ) { mulWaveZ = 1.; } - PARAM_INT_OPT(falloff) { falloff = 0; } - PARAM_INT_OPT(highpoint) { highpoint = 0; } - PARAM_FLOAT_OPT(rollIntensity) { rollIntensity = 0.; } - PARAM_FLOAT_OPT(rollWave) { rollWave = 0.; } + PARAM_SOUND_DEF(sound); + PARAM_INT_DEF(flags); + PARAM_FLOAT_DEF(mulWaveX); + PARAM_FLOAT_DEF(mulWaveY); + PARAM_FLOAT_DEF(mulWaveZ); + PARAM_INT_DEF(falloff); + PARAM_INT_DEF(highpoint); + PARAM_FLOAT_DEF(rollIntensity); + PARAM_FLOAT_DEF(rollWave); P_StartQuakeXYZ(self, 0, intensityX, intensityY, intensityZ, duration, damrad, tremrad, sound, flags, mulWaveX, mulWaveY, mulWaveZ, falloff, highpoint, rollIntensity, rollWave); return 0; @@ -5581,7 +5245,7 @@ void A_Weave(AActor *self, int xyspeed, int zspeed, double xydist, double zdist) } } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Weave) +DEFINE_ACTION_FUNCTION(AActor, A_Weave) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (xspeed); @@ -5603,11 +5267,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Weave) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LineEffect) +DEFINE_ACTION_FUNCTION(AActor, A_LineEffect) { - PARAM_ACTION_PROLOGUE; - PARAM_INT_OPT(special) { special = 0; } - PARAM_INT_OPT(tag) { tag = 0; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT_DEF(special); + PARAM_INT_DEF(tag); line_t junk; maplinedef_t oldjunk; @@ -5638,18 +5302,18 @@ enum WolfAttackFlags WAF_USEPUFF = 2, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) +DEFINE_ACTION_FUNCTION(AActor, A_WolfAttack) { - PARAM_ACTION_PROLOGUE; - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_SOUND_OPT (sound) { sound = "weapons/pistol"; } - PARAM_FLOAT_OPT (snipe) { snipe = 1.; } - PARAM_INT_OPT (maxdamage) { maxdamage = 64; } - PARAM_INT_OPT (blocksize) { blocksize = 128; } - PARAM_INT_OPT (pointblank) { pointblank = 2; } - PARAM_INT_OPT (longrange) { longrange = 4; } - PARAM_FLOAT_OPT (runspeed) { runspeed = 160; } - PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindActor(NAME_BulletPuff); } + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT_DEF (flags) + PARAM_SOUND_DEF (sound) + PARAM_FLOAT_DEF (snipe) + PARAM_INT_DEF (maxdamage) + PARAM_INT_DEF (blocksize) + PARAM_INT_DEF (pointblank) + PARAM_INT_DEF (longrange) + PARAM_FLOAT_DEF (runspeed) + PARAM_CLASS_DEF (pufftype, AActor) if (!self->target) return 0; @@ -5743,19 +5407,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) +DEFINE_ACTION_FUNCTION(AActor, A_Warp) { - PARAM_ACTION_PROLOGUE; + PARAM_ACTION_PROLOGUE(AActor); PARAM_INT(destination_selector); - PARAM_FLOAT_OPT(xofs) { xofs = 0; } - PARAM_FLOAT_OPT(yofs) { yofs = 0; } - PARAM_FLOAT_OPT(zofs) { zofs = 0; } - PARAM_ANGLE_OPT(angle) { angle = 0.; } - PARAM_INT_OPT(flags) { flags = 0; } - PARAM_STATE_OPT(success_state) { success_state = NULL; } - PARAM_FLOAT_OPT(heightoffset) { heightoffset = 0; } - PARAM_FLOAT_OPT(radiusoffset) { radiusoffset = 0; } - PARAM_ANGLE_OPT(pitch) { pitch = 0.; } + PARAM_FLOAT_DEF(xofs) + PARAM_FLOAT_DEF(yofs) + PARAM_FLOAT_DEF(zofs) + PARAM_ANGLE_DEF(angle) + PARAM_INT_DEF(flags) + PARAM_STATE_DEF(success_state) + PARAM_FLOAT_DEF(heightoffset) + PARAM_FLOAT_DEF(radiusoffset) + PARAM_ANGLE_DEF(pitch) AActor *reference; @@ -5805,104 +5469,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) return numret; } -//========================================================================== -// -// ACS_Named* stuff - -// -// These are exactly like their un-named line special equivalents, except -// they take strings instead of integers to indicate which script to run. -// Some of these probably aren't very useful, but they are included for -// the sake of completeness. -// -//========================================================================== - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedExecuteWithResult) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_NAME (scriptname); - PARAM_INT_OPT (arg1) { arg1 = 0; } - PARAM_INT_OPT (arg2) { arg2 = 0; } - PARAM_INT_OPT (arg3) { arg3 = 0; } - PARAM_INT_OPT (arg4) { arg4 = 0; } - - int res = P_ExecuteSpecial(ACS_ExecuteWithResult, NULL, self, false, -scriptname, arg1, arg2, arg3, arg4); - ACTION_RETURN_INT(res); -} - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedExecute) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_NAME (scriptname); - PARAM_INT_OPT (mapnum) { mapnum = 0; } - PARAM_INT_OPT (arg1) { arg1 = 0; } - PARAM_INT_OPT (arg2) { arg2 = 0; } - PARAM_INT_OPT (arg3) { arg3 = 0; } - - int res = P_ExecuteSpecial(ACS_Execute, NULL, self, false, -scriptname, mapnum, arg1, arg2, arg3); - ACTION_RETURN_INT(res); -} - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedExecuteAlways) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_NAME (scriptname); - PARAM_INT_OPT (mapnum) { mapnum = 0; } - PARAM_INT_OPT (arg1) { arg1 = 0; } - PARAM_INT_OPT (arg2) { arg2 = 0; } - PARAM_INT_OPT (arg3) { arg3 = 0; } - - int res = P_ExecuteSpecial(ACS_ExecuteAlways, NULL, self, false, -scriptname, mapnum, arg1, arg2, arg3); - ACTION_RETURN_INT(res); -} - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedLockedExecute) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_NAME (scriptname); - PARAM_INT_OPT (mapnum) { mapnum = 0; } - PARAM_INT_OPT (arg1) { arg1 = 0; } - PARAM_INT_OPT (arg2) { arg2 = 0; } - PARAM_INT_OPT (lock) { lock = 0; } - - int res = P_ExecuteSpecial(ACS_LockedExecute, NULL, self, false, -scriptname, mapnum, arg1, arg2, lock); - ACTION_RETURN_INT(res); -} - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedLockedExecuteDoor) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_NAME (scriptname); - PARAM_INT_OPT (mapnum) { mapnum = 0; } - PARAM_INT_OPT (arg1) { arg1 = 0; } - PARAM_INT_OPT (arg2) { arg2 = 0; } - PARAM_INT_OPT (lock) { lock = 0; } - - int res = P_ExecuteSpecial(ACS_LockedExecuteDoor, NULL, self, false, -scriptname, mapnum, arg1, arg2, lock); - ACTION_RETURN_INT(res); -} - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedSuspend) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_NAME (scriptname); - PARAM_INT_OPT (mapnum) { mapnum = 0; } - - int res = P_ExecuteSpecial(ACS_Suspend, NULL, self, false, -scriptname, mapnum, 0, 0, 0); - ACTION_RETURN_INT(res); -} - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedTerminate) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_NAME (scriptname); - PARAM_INT_OPT (mapnum) { mapnum = 0; } - - int res = P_ExecuteSpecial(ACS_Terminate, NULL, self, false, -scriptname, mapnum, 0, 0, 0); - ACTION_RETURN_INT(res); -} - - static bool DoCheckSpecies(AActor *mo, FName filterSpecies, bool exclude) { FName actorSpecies = mo->GetSpecies(); @@ -6093,17 +5659,17 @@ static bool DoRadiusGive(AActor *self, AActor *thing, PClassActor *item, int amo return false; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) +DEFINE_ACTION_FUNCTION(AActor, A_RadiusGive) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS (item, AInventory); PARAM_FLOAT (distance); PARAM_INT (flags); - PARAM_INT_OPT (amount) { amount = 0; } - PARAM_CLASS_OPT (filter, AActor) { filter = nullptr; } - PARAM_NAME_OPT (species) { species = NAME_None; } - PARAM_FLOAT_OPT (mindist) { mindist = 0; } - PARAM_INT_OPT (limit) { limit = 0; } + PARAM_INT_DEF (amount); + PARAM_CLASS_DEF (filter, AActor); + PARAM_NAME_DEF (species); + PARAM_FLOAT_DEF (mindist); + PARAM_INT_DEF (limit); // We need a valid item, valid targets, and a valid range if (item == nullptr || (flags & RGF_MASK) == 0 || !flags || distance <= 0 || mindist >= distance) @@ -6140,36 +5706,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) ACTION_RETURN_INT(given); } -//=========================================================================== -// -// A_CheckSpecies -// -//=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSpecies) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(jump); - PARAM_NAME_OPT(species) { species = NAME_None; } - PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } - - AActor *mobj = COPY_AAPTR(self, ptr); - - if (mobj != NULL && jump && mobj->GetSpecies() == species) - { - ACTION_RETURN_STATE(jump); - } - ACTION_RETURN_STATE(NULL); -} - //========================================================================== // // A_SetTics // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTics) +DEFINE_ACTION_FUNCTION(AActor, A_SetTics) { - PARAM_ACTION_PROLOGUE; + PARAM_ACTION_PROLOGUE(AActor); PARAM_INT(tics_to_set); if (ACTION_CALL_FROM_PSPRITE()) @@ -6190,102 +5735,23 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTics) return 0; } -//========================================================================== -// -// A_SetDamageType -// -//========================================================================== - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetDamageType) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_NAME(damagetype); - - self->DamageType = damagetype; - return 0; -} - //========================================================================== // // A_DropItem // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DropItem) +DEFINE_ACTION_FUNCTION(AActor, A_DropItem) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS (spawntype, AActor); - PARAM_INT_OPT (amount) { amount = -1; } - PARAM_INT_OPT (chance) { chance = 256; } + PARAM_INT_DEF(amount); + PARAM_INT_DEF(chance); P_DropItem(self, spawntype, amount, chance); return 0; } -//========================================================================== -// -// A_SetSpeed -// -//========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpeed) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_FLOAT(speed); - PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } - - AActor *ref = COPY_AAPTR(self, ptr); - - if (ref != NULL) - { - ref->Speed = speed; - } - return 0; -} - -//========================================================================== -// -// A_SetFloatSpeed -// -//========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetFloatSpeed) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_FLOAT(speed); - PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } - - AActor *ref = COPY_AAPTR(self, ptr); - - if (!ref) - { - return 0; - } - - ref->FloatSpeed = speed; - return 0; -} - -//========================================================================== -// -// A_SetPainThreshold -// -//========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetPainThreshold) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_INT(threshold); - PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } - - AActor *ref = COPY_AAPTR(self, ptr); - - if (!ref) - { - return 0; - } - - ref->PainThreshold = threshold; - return 0; -} - //=========================================================================== // // Common A_Damage handler @@ -6356,16 +5822,16 @@ static void DoDamage(AActor *dmgtarget, AActor *inflictor, AActor *source, int a // // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageSelf) +DEFINE_ACTION_FUNCTION(AActor, A_DamageSelf) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (amount); - PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } - PARAM_NAME_OPT (species) { species = NAME_None; } - PARAM_INT_OPT (src) { src = AAPTR_DEFAULT; } - PARAM_INT_OPT (inflict) { inflict = AAPTR_DEFAULT; } + PARAM_NAME_DEF (damagetype) + PARAM_INT_DEF (flags) + PARAM_CLASS_DEF (filter, AActor) + PARAM_NAME_DEF (species) + PARAM_INT_DEF (src) + PARAM_INT_DEF (inflict) AActor *source = COPY_AAPTR(self, src); AActor *inflictor = COPY_AAPTR(self, inflict); @@ -6379,16 +5845,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageSelf) // // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageTarget) +DEFINE_ACTION_FUNCTION(AActor, A_DamageTarget) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (amount); - PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } - PARAM_NAME_OPT (species) { species = NAME_None; } - PARAM_INT_OPT (src) { src = AAPTR_DEFAULT; } - PARAM_INT_OPT (inflict) { inflict = AAPTR_DEFAULT; } + PARAM_NAME_DEF (damagetype) + PARAM_INT_DEF (flags) + PARAM_CLASS_DEF (filter, AActor) + PARAM_NAME_DEF (species) + PARAM_INT_DEF (src) + PARAM_INT_DEF (inflict) AActor *source = COPY_AAPTR(self, src); AActor *inflictor = COPY_AAPTR(self, inflict); @@ -6403,16 +5869,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageTarget) // // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageTracer) +DEFINE_ACTION_FUNCTION(AActor, A_DamageTracer) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (amount); - PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } - PARAM_NAME_OPT (species) { species = NAME_None; } - PARAM_INT_OPT (src) { src = AAPTR_DEFAULT; } - PARAM_INT_OPT (inflict) { inflict = AAPTR_DEFAULT; } + PARAM_NAME_DEF (damagetype) + PARAM_INT_DEF (flags) + PARAM_CLASS_DEF (filter, AActor) + PARAM_NAME_DEF (species) + PARAM_INT_DEF (src) + PARAM_INT_DEF (inflict) AActor *source = COPY_AAPTR(self, src); AActor *inflictor = COPY_AAPTR(self, inflict); @@ -6427,16 +5893,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageTracer) // // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageMaster) +DEFINE_ACTION_FUNCTION(AActor, A_DamageMaster) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (amount); - PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } - PARAM_NAME_OPT (species) { species = NAME_None; } - PARAM_INT_OPT (src) { src = AAPTR_DEFAULT; } - PARAM_INT_OPT (inflict) { inflict = AAPTR_DEFAULT; } + PARAM_NAME_DEF (damagetype) + PARAM_INT_DEF (flags) + PARAM_CLASS_DEF (filter, AActor) + PARAM_NAME_DEF (species) + PARAM_INT_DEF (src) + PARAM_INT_DEF (inflict) AActor *source = COPY_AAPTR(self, src); AActor *inflictor = COPY_AAPTR(self, inflict); @@ -6451,16 +5917,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageMaster) // // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageChildren) +DEFINE_ACTION_FUNCTION(AActor, A_DamageChildren) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (amount); - PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } - PARAM_NAME_OPT (species) { species = NAME_None; } - PARAM_INT_OPT (src) { src = AAPTR_DEFAULT; } - PARAM_INT_OPT (inflict) { inflict = AAPTR_DEFAULT; } + PARAM_NAME_DEF (damagetype) + PARAM_INT_DEF (flags) + PARAM_CLASS_DEF (filter, AActor) + PARAM_NAME_DEF (species) + PARAM_INT_DEF (src) + PARAM_INT_DEF (inflict) AActor *source = COPY_AAPTR(self, src); AActor *inflictor = COPY_AAPTR(self, inflict); @@ -6481,16 +5947,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageChildren) // // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageSiblings) +DEFINE_ACTION_FUNCTION(AActor, A_DamageSiblings) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (amount); - PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } - PARAM_NAME_OPT (species) { species = NAME_None; } - PARAM_INT_OPT (src) { src = AAPTR_DEFAULT; } - PARAM_INT_OPT (inflict) { inflict = AAPTR_DEFAULT; } + PARAM_NAME_DEF (damagetype) + PARAM_INT_DEF (flags) + PARAM_CLASS_DEF (filter, AActor) + PARAM_NAME_DEF (species) + PARAM_INT_DEF (src) + PARAM_INT_DEF (inflict) AActor *source = COPY_AAPTR(self, src); AActor *inflictor = COPY_AAPTR(self, inflict); @@ -6564,15 +6030,15 @@ static void DoKill(AActor *killtarget, AActor *inflictor, AActor *source, FName // A_KillTarget(damagetype, int flags) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillTarget) +DEFINE_ACTION_FUNCTION(AActor, A_KillTarget) { - PARAM_ACTION_PROLOGUE; - PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } - PARAM_NAME_OPT (species) { species = NAME_None; } - PARAM_INT_OPT (src) { src = AAPTR_DEFAULT; } - PARAM_INT_OPT (inflict) { inflict = AAPTR_DEFAULT; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_NAME_DEF (damagetype) + PARAM_INT_DEF (flags) + PARAM_CLASS_DEF (filter, AActor) + PARAM_NAME_DEF (species) + PARAM_INT_DEF (src) + PARAM_INT_DEF (inflict) AActor *source = COPY_AAPTR(self, src); AActor *inflictor = COPY_AAPTR(self, inflict); @@ -6587,15 +6053,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillTarget) // A_KillTracer(damagetype, int flags) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillTracer) +DEFINE_ACTION_FUNCTION(AActor, A_KillTracer) { - PARAM_ACTION_PROLOGUE; - PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } - PARAM_NAME_OPT (species) { species = NAME_None; } - PARAM_INT_OPT (src) { src = AAPTR_DEFAULT; } - PARAM_INT_OPT (inflict) { inflict = AAPTR_DEFAULT; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_NAME_DEF (damagetype) + PARAM_INT_DEF (flags) + PARAM_CLASS_DEF (filter, AActor) + PARAM_NAME_DEF (species) + PARAM_INT_DEF (src) + PARAM_INT_DEF (inflict) AActor *source = COPY_AAPTR(self, src); AActor *inflictor = COPY_AAPTR(self, inflict); @@ -6610,17 +6076,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillTracer) // A_KillMaster(damagetype, int flags) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillMaster) +DEFINE_ACTION_FUNCTION(AActor, A_KillMaster) { - PARAM_ACTION_PROLOGUE; - PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } - PARAM_NAME_OPT (species) { species = NAME_None; } - PARAM_INT_OPT (src) { src = AAPTR_DEFAULT; } - PARAM_INT_OPT (inflict) { inflict = AAPTR_DEFAULT; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_NAME_DEF (damagetype) + PARAM_INT_DEF (flags) + PARAM_CLASS_DEF (filter, AActor) + PARAM_NAME_DEF (species) + PARAM_INT_DEF (src) + PARAM_INT_DEF (inflict) - AActor *source = COPY_AAPTR(self, src); + AActor *source = COPY_AAPTR(self, src); AActor *inflictor = COPY_AAPTR(self, inflict); if (self->master != NULL) @@ -6633,15 +6099,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillMaster) // A_KillChildren(damagetype, int flags) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillChildren) +DEFINE_ACTION_FUNCTION(AActor, A_KillChildren) { - PARAM_ACTION_PROLOGUE; - PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } - PARAM_NAME_OPT (species) { species = NAME_None; } - PARAM_INT_OPT (src) { src = AAPTR_DEFAULT; } - PARAM_INT_OPT (inflict) { inflict = AAPTR_DEFAULT; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_NAME_DEF (damagetype) + PARAM_INT_DEF (flags) + PARAM_CLASS_DEF (filter, AActor) + PARAM_NAME_DEF (species) + PARAM_INT_DEF (src) + PARAM_INT_DEF (inflict) AActor *source = COPY_AAPTR(self, src); AActor *inflictor = COPY_AAPTR(self, inflict); @@ -6664,15 +6130,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillChildren) // A_KillSiblings(damagetype, int flags) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillSiblings) +DEFINE_ACTION_FUNCTION(AActor, A_KillSiblings) { - PARAM_ACTION_PROLOGUE; - PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } - PARAM_NAME_OPT (species) { species = NAME_None; } - PARAM_INT_OPT (src) { src = AAPTR_DEFAULT; } - PARAM_INT_OPT (inflict) { inflict = AAPTR_DEFAULT; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_NAME_DEF (damagetype) + PARAM_INT_DEF (flags) + PARAM_CLASS_DEF (filter, AActor) + PARAM_NAME_DEF (species) + PARAM_INT_DEF (src) + PARAM_INT_DEF (inflict) AActor *source = COPY_AAPTR(self, src); AActor *inflictor = COPY_AAPTR(self, inflict); @@ -6740,12 +6206,12 @@ static void DoRemove(AActor *removetarget, int flags, PClassActor *filter, FName // A_RemoveTarget // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveTarget) +DEFINE_ACTION_FUNCTION(AActor, A_RemoveTarget) { - PARAM_ACTION_PROLOGUE; - PARAM_INT_OPT(flags) { flags = 0; } - PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } - PARAM_NAME_OPT (species) { species = NAME_None; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT_DEF(flags); + PARAM_CLASS_DEF(filter, AActor); + PARAM_NAME_DEF(species); if (self->target != NULL) { @@ -6759,12 +6225,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveTarget) // A_RemoveTracer // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveTracer) +DEFINE_ACTION_FUNCTION(AActor, A_RemoveTracer) { - PARAM_ACTION_PROLOGUE; - PARAM_INT_OPT(flags) { flags = 0; } - PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } - PARAM_NAME_OPT (species) { species = NAME_None; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT_DEF(flags); + PARAM_CLASS_DEF(filter, AActor); + PARAM_NAME_DEF(species); if (self->tracer != NULL) { @@ -6778,12 +6244,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveTracer) // A_RemoveMaster // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveMaster) +DEFINE_ACTION_FUNCTION(AActor, A_RemoveMaster) { - PARAM_ACTION_PROLOGUE; - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } - PARAM_NAME_OPT (species) { species = NAME_None; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT_DEF(flags); + PARAM_CLASS_DEF(filter, AActor); + PARAM_NAME_DEF(species); if (self->master != NULL) { @@ -6797,13 +6263,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveMaster) // A_RemoveChildren // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveChildren) +DEFINE_ACTION_FUNCTION(AActor, A_RemoveChildren) { - PARAM_ACTION_PROLOGUE; - PARAM_BOOL_OPT (removeall) { removeall = false; } - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } - PARAM_NAME_OPT (species) { species = NAME_None; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_BOOL_DEF(removeall); + PARAM_INT_DEF(flags); + PARAM_CLASS_DEF(filter, AActor); + PARAM_NAME_DEF(species); TThinkerIterator it; AActor *mo; @@ -6823,13 +6289,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveChildren) // A_RemoveSiblings // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveSiblings) +DEFINE_ACTION_FUNCTION(AActor, A_RemoveSiblings) { - PARAM_ACTION_PROLOGUE; - PARAM_BOOL_OPT (removeall) { removeall = false; } - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } - PARAM_NAME_OPT (species) { species = NAME_None; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_BOOL_DEF(removeall); + PARAM_INT_DEF(flags); + PARAM_CLASS_DEF(filter, AActor); + PARAM_NAME_DEF(species); TThinkerIterator it; AActor *mo; @@ -6852,13 +6318,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveSiblings) // A_Remove // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Remove) +DEFINE_ACTION_FUNCTION(AActor, A_Remove) { PARAM_SELF_PROLOGUE(AActor); - PARAM_INT (removee); - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } - PARAM_NAME_OPT (species) { species = NAME_None; } + PARAM_INT(removee); + PARAM_INT_DEF(flags); + PARAM_CLASS_DEF(filter, AActor); + PARAM_NAME_DEF(species); AActor *reference = COPY_AAPTR(self, removee); if (reference != NULL) @@ -6876,7 +6342,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Remove) // Takes a name of the classes for the source and destination. //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTeleFog) +DEFINE_ACTION_FUNCTION(AActor, A_SetTeleFog) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS(oldpos, AActor); @@ -6896,7 +6362,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTeleFog) DEFINE_ACTION_FUNCTION(AActor, A_SwapTeleFog) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); if ((self->TeleFogSourceType != self->TeleFogDestType)) //Does nothing if they're the same. { PClassActor *temp = self->TeleFogSourceType; @@ -6913,18 +6379,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_SwapTeleFog) // Changes the FloatBobPhase of the actor. //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetFloatBobPhase) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_INT(bob); - - //Respect float bob phase limits. - if (self && (bob >= 0 && bob <= 63)) - { - self->FloatBobPhase = bob; - } - return 0; -} //=========================================================================== // A_SetHealth @@ -6933,11 +6387,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetFloatBobPhase) // Takes a pointer as well. //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetHealth) +DEFINE_ACTION_FUNCTION(AActor, A_SetHealth) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT (health); - PARAM_INT_OPT (ptr) { ptr = AAPTR_DEFAULT; } + PARAM_INT_DEF (ptr); AActor *mobj = COPY_AAPTR(self, ptr); @@ -6971,10 +6425,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetHealth) // Takes a pointer. //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ResetHealth) +DEFINE_ACTION_FUNCTION(AActor, A_ResetHealth) { - PARAM_ACTION_PROLOGUE; - PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT_DEF(ptr); AActor *mobj = COPY_AAPTR(self, ptr); @@ -6995,54 +6449,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ResetHealth) return 0; } -//=========================================================================== -// A_JumpIfHigherOrLower -// -// Jumps if a target, master, or tracer is higher or lower than the calling -// actor. Can also specify how much higher/lower the actor needs to be than -// itself. Can also take into account the height of the actor in question, -// depending on which it's checking. This means adding height of the -// calling actor's self if the pointer is higher, or height of the pointer -// if its lower. -//=========================================================================== - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfHigherOrLower) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(high); - PARAM_STATE(low); - PARAM_FLOAT_OPT(offsethigh) { offsethigh = 0; } - PARAM_FLOAT_OPT(offsetlow) { offsetlow = 0; } - PARAM_BOOL_OPT(includeHeight) { includeHeight = true; } - PARAM_INT_OPT(ptr) { ptr = AAPTR_TARGET; } - - AActor *mobj = COPY_AAPTR(self, ptr); - - - if (mobj != NULL && mobj != self) //AAPTR_DEFAULT is completely useless in this regard. - { - if ((high) && (mobj->Z() > ((includeHeight ? self->Height : 0) + self->Z() + offsethigh))) - { - ACTION_RETURN_STATE(high); - } - else if ((low) && (mobj->Z() + (includeHeight ? mobj->Height : 0)) < (self->Z() + offsetlow)) - { - ACTION_RETURN_STATE(low); - } - } - ACTION_RETURN_STATE(NULL); -} - //=========================================================================== // A_SetSpecies(str species, ptr) // // Sets the species of the calling actor('s pointer). //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpecies) +DEFINE_ACTION_FUNCTION(AActor, A_SetSpecies) { PARAM_SELF_PROLOGUE(AActor); PARAM_NAME(species); - PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + PARAM_INT_DEF(ptr); AActor *mobj = COPY_AAPTR(self, ptr); if (!mobj) @@ -7054,48 +6470,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpecies) return 0; } -//=========================================================================== -// -// A_SetRipperLevel(int level) -// -// Sets the ripper level of the calling actor. -//=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRipperLevel) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_INT(level); - self->RipperLevel = level; - return 0; -} - -//=========================================================================== -// -// A_SetRipMin(int min) -// -// Sets the minimum level a ripper must be in order to rip through this actor. -//=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRipMin) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_INT(min); - self->RipLevelMin = min; - return 0; -} - -//=========================================================================== -// -// A_SetRipMax(int max) -// -// Sets the minimum level a ripper must be in order to rip through this actor. -//=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRipMax) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_INT(max); - self->RipLevelMax = max; - return 0; -} - //=========================================================================== // // A_SetChaseThreshold(int threshold, bool def, int ptr) @@ -7104,12 +6478,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRipMax) // changes the default threshold which the actor resets to once it switches // targets and doesn't have the +QUICKTORETALIATE flag. //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetChaseThreshold) +DEFINE_ACTION_FUNCTION(AActor, A_SetChaseThreshold) { PARAM_SELF_PROLOGUE(AActor); PARAM_INT(threshold); - PARAM_BOOL_OPT(def) { def = false; } - PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + PARAM_BOOL_DEF(def); + PARAM_INT_DEF(ptr); AActor *mobj = COPY_AAPTR(self, ptr); @@ -7131,29 +6505,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetChaseThreshold) // Checks to see if a certain actor class is close to the // actor/pointer within distance, in numbers. //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckProximity) +DEFINE_ACTION_FUNCTION(AActor, CheckProximity) { PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(jump); PARAM_CLASS(classname, AActor); PARAM_FLOAT(distance); - PARAM_INT_OPT(count) { count = 1; } - PARAM_INT_OPT(flags) { flags = 0; } - PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + PARAM_INT_DEF(count); + PARAM_INT_DEF(flags); + PARAM_INT_DEF(ptr); - if (!jump) - { - if (!(flags & (CPXF_SETTARGET | CPXF_SETMASTER | CPXF_SETTRACER))) - { - ACTION_RETURN_STATE(NULL); - } - } - - if (P_Thing_CheckProximity(self, classname, distance, count, flags, ptr) && jump) - { - ACTION_RETURN_STATE(jump); - } - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(!!P_Thing_CheckProximity(self, classname, distance, count, flags, ptr)); } /*=========================================================================== @@ -7177,23 +6538,22 @@ enum CBF CBF_ABSOLUTEANGLE = 1 << 8, //Absolute angle for offsets. }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckBlock) +DEFINE_ACTION_FUNCTION(AActor, CheckBlock) { PARAM_SELF_PROLOGUE(AActor); - PARAM_STATE(block) - PARAM_INT_OPT(flags) { flags = 0; } - PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } - PARAM_FLOAT_OPT(xofs) { xofs = 0; } - PARAM_FLOAT_OPT(yofs) { yofs = 0; } - PARAM_FLOAT_OPT(zofs) { zofs = 0; } - PARAM_ANGLE_OPT(angle) { angle = 0.; } + PARAM_INT_DEF(flags) + PARAM_INT_DEF(ptr) + PARAM_FLOAT_DEF(xofs) + PARAM_FLOAT_DEF(yofs) + PARAM_FLOAT_DEF(zofs) + PARAM_ANGLE_DEF(angle) AActor *mobj = COPY_AAPTR(self, ptr); //Needs at least one state jump to work. if (!mobj) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } if (!(flags & CBF_ABSOLUTEANGLE)) @@ -7243,7 +6603,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckBlock) if (checker) { - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL(false); } if (mobj->BlockingMobj) @@ -7257,23 +6617,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckBlock) } } - //[MC] If modders don't want jumping, but just getting the pointer, only abort at - //this point. I.e. A_CheckBlock("",CBF_SETTRACER) is like having CBF_NOLINES. - //It gets the mobj blocking, if any, and doesn't jump at all. - if (!block) - { - ACTION_RETURN_STATE(NULL); - } //[MC] I don't know why I let myself be persuaded not to include a flag. //If an actor is loaded with pointers, they don't really have any options to spare. //Also, fail if a dropoff or a step is too great to pass over when checking for dropoffs. - if ((!(flags & CBF_NOACTORS) && (mobj->BlockingMobj)) || (!(flags & CBF_NOLINES) && mobj->BlockingLine != NULL) || - ((flags & CBF_DROPOFF) && !checker)) - { - ACTION_RETURN_STATE(block); - } - ACTION_RETURN_STATE(NULL); + ACTION_RETURN_BOOL((!(flags & CBF_NOACTORS) && (mobj->BlockingMobj)) || (!(flags & CBF_NOLINES) && mobj->BlockingLine != NULL) || + ((flags & CBF_DROPOFF) && !checker)); } //=========================================================================== @@ -7288,14 +6637,14 @@ enum FMDFlags FMDF_INTERPOLATE = 1 << 1, FMDF_NOANGLE = 1 << 2, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceMovementDirection) +DEFINE_ACTION_FUNCTION(AActor, A_FaceMovementDirection) { - PARAM_ACTION_PROLOGUE; - PARAM_ANGLE_OPT(offset) { offset = 0.; } - PARAM_ANGLE_OPT(anglelimit) { anglelimit = 0.; } - PARAM_ANGLE_OPT(pitchlimit) { pitchlimit = 0.; } - PARAM_INT_OPT(flags) { flags = 0; } - PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_ANGLE_DEF(offset) + PARAM_ANGLE_DEF(anglelimit) + PARAM_ANGLE_DEF(pitchlimit) + PARAM_INT_DEF(flags) + PARAM_INT_DEF(ptr) AActor *mobj = COPY_AAPTR(self, ptr); @@ -7382,12 +6731,12 @@ enum CPSFFlags CPSF_NOFRAME = 1 << 1, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CopySpriteFrame) +DEFINE_ACTION_FUNCTION(AActor, A_CopySpriteFrame) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); PARAM_INT(from); PARAM_INT(to); - PARAM_INT_OPT(flags) { flags = 0; } + PARAM_INT_DEF(flags); AActor *copyfrom = COPY_AAPTR(self, from); AActor *copyto = COPY_AAPTR(self, to); @@ -7402,52 +6751,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CopySpriteFrame) ACTION_RETURN_BOOL(true); } -//========================================================================== -// -// A_SetSpriteAngle(angle, ptr) -// -// Specifies which angle the actor must always draw its sprite from. -//========================================================================== - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpriteAngle) -{ - PARAM_ACTION_PROLOGUE; - PARAM_FLOAT_OPT(angle) { angle = 0.; } - PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } - - AActor *mobj = COPY_AAPTR(self, ptr); - - if (mobj == nullptr) - { - ACTION_RETURN_BOOL(false); - } - mobj->SpriteAngle = angle; - ACTION_RETURN_BOOL(true); -} - -//========================================================================== -// -// A_SetSpriteRotation(angle, ptr) -// -// Specifies how much to fake a sprite rotation. -//========================================================================== - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpriteRotation) -{ - PARAM_ACTION_PROLOGUE; - PARAM_ANGLE_OPT(angle) { angle = 0.; } - PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } - - AActor *mobj = COPY_AAPTR(self, ptr); - - if (mobj == nullptr) - { - ACTION_RETURN_BOOL(false); - } - mobj->SpriteRotation = angle; - ACTION_RETURN_BOOL(true); -} - //========================================================================== // // A_SetMaskRotation(anglestart, angleend, pitchstart, pitchend, flags, ptr) @@ -7463,15 +6766,15 @@ enum VRFFlags VRF_NOPITCHEND = 1 << 3, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetVisibleRotation) +DEFINE_ACTION_FUNCTION(AActor, A_SetVisibleRotation) { - PARAM_ACTION_PROLOGUE; - PARAM_ANGLE_OPT(anglestart) { anglestart = 0.; } - PARAM_ANGLE_OPT(angleend) { angleend = 0.; } - PARAM_ANGLE_OPT(pitchstart) { pitchstart = 0.; } - PARAM_ANGLE_OPT(pitchend) { pitchend = 0.; } - PARAM_INT_OPT(flags) { flags = 0; } - PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_ANGLE_DEF(anglestart) + PARAM_ANGLE_DEF(angleend) + PARAM_ANGLE_DEF(pitchstart) + PARAM_ANGLE_DEF(pitchend) + PARAM_INT_DEF(flags) + PARAM_INT_DEF(ptr) AActor *mobj = COPY_AAPTR(self, ptr); @@ -7506,11 +6809,40 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetVisibleRotation) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTranslation) +DEFINE_ACTION_FUNCTION(AActor, A_SetTranslation) { PARAM_SELF_PROLOGUE(AActor); - PARAM_STRING(trname); + PARAM_NAME(trname); self->SetTranslation(trname); return 0; } + +//========================================================================== +// +// +// +//========================================================================== + +DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain) +{ + PARAM_SELF_PROLOGUE(AActor); + + sector_t *sec = self->Sector; + + if (self->Z() == sec->floorplane.ZatPoint(self) && sec->PortalBlocksMovement(sector_t::floor)) + { + if (sec->special == Damage_InstantDeath) + { + P_DamageMobj(self, NULL, NULL, 999, NAME_InstantDeath); + } + else if (sec->special == Scroll_StrifeCurrent) + { + int anglespeed = tagManager.GetFirstSectorTag(sec) - 100; + double speed = (anglespeed % 10) / 16.; + DAngle an = (anglespeed / 10) * (360 / 8.); + self->Thrust(an, speed); + } + } + return 0; +} diff --git a/src/p_buildmap.cpp b/src/p_buildmap.cpp index 7e65bf05df..4d1909da5d 100644 --- a/src/p_buildmap.cpp +++ b/src/p_buildmap.cpp @@ -865,7 +865,7 @@ public: void BeginPlay (); }; -IMPLEMENT_CLASS (ACustomSprite) +IMPLEMENT_CLASS(ACustomSprite, false, false) void ACustomSprite::BeginPlay () { diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp index 29b0c50950..4da81db46d 100644 --- a/src/p_ceiling.cpp +++ b/src/p_ceiling.cpp @@ -38,7 +38,7 @@ // //============================================================================ -IMPLEMENT_CLASS (DCeiling) +IMPLEMENT_CLASS(DCeiling, false, false) DCeiling::DCeiling () { @@ -458,6 +458,22 @@ bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int t return ceiling != NULL; } +DEFINE_ACTION_FUNCTION(DCeiling, CreateCeiling) +{ + PARAM_PROLOGUE; + PARAM_POINTER_NOT_NULL(sec, sector_t); + PARAM_INT(type); + PARAM_POINTER(ln, line_t); + PARAM_FLOAT(speed); + PARAM_FLOAT(speed2); + PARAM_FLOAT_DEF(height); + PARAM_INT_DEF(crush); + PARAM_INT_DEF(silent); + PARAM_INT_DEF(change); + PARAM_INT_DEF(crushmode); + ACTION_RETURN_BOOL(P_CreateCeiling(sec, (DCeiling::ECeiling)type, ln, 0, speed, speed2, height, crush, silent, change, (DCeiling::ECrushMode)crushmode)); +} + //============================================================================ // // EV_DoCeiling diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 0208e64775..5fd21e73b3 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -44,7 +44,6 @@ #include "m_random.h" #include "gi.h" #include "templates.h" -#include "a_strifeglobal.h" #include "a_keys.h" #include "p_enemy.h" #include "gstrings.h" @@ -646,7 +645,7 @@ static void TakeStrifeItem (player_t *player, PClassActor *itemtype, int amount) return; // Don't take the sigil. - if (itemtype == RUNTIME_CLASS(ASigil)) + if (itemtype->GetClass()->TypeName == NAME_Sigil) return; player->mo->TakeInventory(itemtype, amount); @@ -834,6 +833,7 @@ public: V_FreeBrokenLines(mDialogueLines); mDialogueLines = NULL; I_SetMusicVolume (1.f); + Super::Destroy(); } bool DimAllowed() @@ -1052,18 +1052,22 @@ public: if (ShowGold) { - AInventory *coin = cp->ConversationPC->FindInventory (RUNTIME_CLASS(ACoin)); - char goldstr[32]; + auto cointype = PClass::FindActor("Coin"); + if (cointype) + { + AInventory *coin = cp->ConversationPC->FindInventory(cointype); + char goldstr[32]; - mysnprintf (goldstr, countof(goldstr), "%d", coin != NULL ? coin->Amount : 0); - screen->DrawText (SmallFont, CR_GRAY, 21, 191, goldstr, DTA_320x200, true, - DTA_FillColor, 0, DTA_AlphaF, HR_SHADOW, TAG_DONE); - screen->DrawTexture (TexMan(((AInventory *)GetDefaultByType (RUNTIME_CLASS(ACoin)))->Icon), - 3, 190, DTA_320x200, true, - DTA_FillColor, 0, DTA_AlphaF, HR_SHADOW, TAG_DONE); - screen->DrawText (SmallFont, CR_GRAY, 20, 190, goldstr, DTA_320x200, true, TAG_DONE); - screen->DrawTexture (TexMan(((AInventory *)GetDefaultByType (RUNTIME_CLASS(ACoin)))->Icon), - 2, 189, DTA_320x200, true, TAG_DONE); + mysnprintf(goldstr, countof(goldstr), "%d", coin != NULL ? coin->Amount : 0); + screen->DrawText(SmallFont, CR_GRAY, 21, 191, goldstr, DTA_320x200, true, + DTA_FillColor, 0, DTA_AlphaF, HR_SHADOW, TAG_DONE); + screen->DrawTexture(TexMan(((AInventory *)GetDefaultByType(cointype))->Icon), + 3, 190, DTA_320x200, true, + DTA_FillColor, 0, DTA_AlphaF, HR_SHADOW, TAG_DONE); + screen->DrawText(SmallFont, CR_GRAY, 20, 190, goldstr, DTA_320x200, true, TAG_DONE); + screen->DrawTexture(TexMan(((AInventory *)GetDefaultByType(cointype))->Icon), + 2, 189, DTA_320x200, true, TAG_DONE); + } } y = mYpos; @@ -1103,7 +1107,7 @@ public: }; -IMPLEMENT_ABSTRACT_CLASS(DConversationMenu) +IMPLEMENT_CLASS(DConversationMenu, true, false) int DConversationMenu::mSelection; // needs to be preserved if the same dialogue is restarted @@ -1352,7 +1356,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply } } - if (reply->GiveType->IsDescendantOf(RUNTIME_CLASS(ASlideshowStarter))) + if (reply->GiveType->IsDescendantOf(PClass::FindActor("SlideshowStarter"))) gameaction = ga_slideshow; } else diff --git a/src/p_doors.cpp b/src/p_doors.cpp index 33e37218d7..aa59e5463f 100644 --- a/src/p_doors.cpp +++ b/src/p_doors.cpp @@ -45,7 +45,7 @@ // //============================================================================ -IMPLEMENT_CLASS (DDoor) +IMPLEMENT_CLASS(DDoor, false, false) DDoor::DDoor () { @@ -513,7 +513,7 @@ bool EV_DoDoor (DDoor::EVlDoor type, line_t *line, AActor *thing, // //============================================================================ -IMPLEMENT_CLASS (DAnimatedDoor) +IMPLEMENT_CLASS(DAnimatedDoor, false, false) DAnimatedDoor::DAnimatedDoor () { diff --git a/src/p_effect.cpp b/src/p_effect.cpp index ec051c2990..42e82d7405 100644 --- a/src/p_effect.cpp +++ b/src/p_effect.cpp @@ -574,6 +574,16 @@ void P_DrawSplash (int count, const DVector3 &pos, DAngle angle, int kind) } } +DEFINE_ACTION_FUNCTION(AActor, DrawSplash) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(count); + PARAM_FLOAT(angle); + PARAM_INT(kind); + P_DrawSplash(count, self->Pos(), angle, kind); + return 0; +} + void P_DrawSplash2 (int count, const DVector3 &pos, DAngle angle, int updown, int kind) { int color1, color2, zadd; diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index b7ad540957..da4e3cc45a 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -42,8 +42,6 @@ #include "c_cvars.h" #include "p_enemy.h" #include "a_sharedglobal.h" -#include "a_action.h" -#include "thingdef/thingdef.h" #include "d_dehacked.h" #include "g_level.h" #include "r_utility.h" @@ -53,6 +51,7 @@ #include "p_spec.h" #include "p_checkposition.h" #include "math/cmath.h" +#include "a_ammo.h" #include "gi.h" @@ -263,7 +262,80 @@ void P_NoiseAlert (AActor *target, AActor *emitter, bool splash, double maxdist) } } +DEFINE_ACTION_FUNCTION(AActor, NoiseAlert) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(target, AActor); + PARAM_BOOL_DEF(splash); + PARAM_FLOAT_DEF(maxdist); + // Note that the emitter is self, not the target of the alert! Target can be NULL. + P_NoiseAlert(target, self, splash, maxdist); + return 0; +} +//============================================================================ +// +// P_DaggerAlert +// +//============================================================================ + +void P_DaggerAlert(AActor *target, AActor *emitter) +{ + AActor *looker; + sector_t *sec = emitter->Sector; + + if (emitter->LastHeard != NULL) + return; + if (emitter->health <= 0) + return; + if (!(emitter->flags3 & MF3_ISMONSTER)) + return; + if (emitter->flags4 & MF4_INCOMBAT) + return; + emitter->flags4 |= MF4_INCOMBAT; + + emitter->target = target; + FState *painstate = emitter->FindState(NAME_Pain, NAME_Dagger); + if (painstate != NULL) + { + emitter->SetState(painstate); + } + + for (looker = sec->thinglist; looker != NULL; looker = looker->snext) + { + if (looker == emitter || looker == target) + continue; + + if (looker->health <= 0) + continue; + + if (!(looker->flags4 & MF4_SEESDAGGERS)) + continue; + + if (!(looker->flags4 & MF4_INCOMBAT)) + { + if (!P_CheckSight(looker, target) && !P_CheckSight(looker, emitter)) + continue; + + looker->target = target; + if (looker->SeeSound) + { + S_Sound(looker, CHAN_VOICE, looker->SeeSound, 1, ATTN_NORM); + } + looker->SetState(looker->SeeState); + looker->flags4 |= MF4_INCOMBAT; + } + } +} + +DEFINE_ACTION_FUNCTION(AActor, DaggerAlert) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(target, AActor); + // Note that the emitter is self, not the target of the alert! Target can be NULL. + P_DaggerAlert(target, self); + return 0; +} //---------------------------------------------------------------------------- @@ -309,6 +381,12 @@ bool AActor::CheckMeleeRange () return true; } +DEFINE_ACTION_FUNCTION(AActor, CheckMeleeRange) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_INT(self->CheckMeleeRange()); +} + //---------------------------------------------------------------------------- // // FUNC P_CheckMeleeRange2 @@ -352,6 +430,12 @@ bool P_CheckMeleeRange2 (AActor *actor) return true; } +DEFINE_ACTION_FUNCTION(AActor, CheckMeleeRange2) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_INT(P_CheckMeleeRange2(self)); +} + //============================================================================= // @@ -407,6 +491,12 @@ bool P_CheckMissileRange (AActor *actor) return actor->SuggestMissileAttack (dist); } +DEFINE_ACTION_FUNCTION(AActor, CheckMissileRange) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_BOOL(P_CheckMissileRange(self)); +} + bool AActor::SuggestMissileAttack (double dist) { // new version encapsulates the different behavior in flags instead of virtual functions @@ -454,6 +544,12 @@ bool P_HitFriend(AActor * self) return false; } +DEFINE_ACTION_FUNCTION(AActor, HitFriend) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_BOOL(P_HitFriend(self)); +} + // // P_Move // Move in the current direction, @@ -694,6 +790,11 @@ bool P_Move (AActor *actor) } return true; } +DEFINE_ACTION_FUNCTION(AActor, MonsterMove) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_BOOL(P_Move(self)); +} //============================================================================= @@ -1017,7 +1118,12 @@ void P_NewChaseDir(AActor * actor) } - +DEFINE_ACTION_FUNCTION(AActor, NewChaseDir) +{ + PARAM_SELF_PROLOGUE(AActor); + P_NewChaseDir(self); + return 0; +} //============================================================================= @@ -1178,6 +1284,14 @@ void P_RandomChaseDir (AActor *actor) actor->movedir = DI_NODIR; // cannot move } +DEFINE_ACTION_FUNCTION(AActor, RandomChaseDir) +{ + PARAM_SELF_PROLOGUE(AActor); + P_RandomChaseDir(self); + return 0; +} + + //--------------------------------------------------------------------------- // // P_IsVisible @@ -1193,6 +1307,11 @@ bool P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams double mindist; DAngle fov; + if (other == nullptr) + { + return false; + } + if (params != NULL) { maxdist = params->maxDist; @@ -1230,6 +1349,15 @@ bool P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams return P_CheckSight(lookee, other, SF_SEEPASTSHOOTABLELINES); } +DEFINE_ACTION_FUNCTION(AActor, IsVisible) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(other, AActor); + PARAM_BOOL(allaround); + PARAM_POINTER_DEF(params, FLookExParams); + ACTION_RETURN_BOOL(P_IsVisible(self, other, allaround, params)); +} + //--------------------------------------------------------------------------- // // FUNC P_LookForMonsters @@ -1283,6 +1411,12 @@ bool P_LookForMonsters (AActor *actor) return false; } +DEFINE_ACTION_FUNCTION(AActor, LookForMonsters) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_BOOL(P_LookForMonsters(self)); +} + //============================================================================ // // LookForTIDinBlock @@ -1455,6 +1589,14 @@ bool P_LookForTID (AActor *actor, INTBOOL allaround, FLookExParams *params) return false; } +DEFINE_ACTION_FUNCTION(AActor, LookForTID) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_BOOL(allaround); + PARAM_POINTER_DEF(params, FLookExParams); + ACTION_RETURN_BOOL(P_LookForTID(self, allaround, params)); +} + //============================================================================ // // LookForEnemiesinBlock @@ -1594,6 +1736,15 @@ bool P_LookForEnemies (AActor *actor, INTBOOL allaround, FLookExParams *params) return false; } +DEFINE_ACTION_FUNCTION(AActor, LookForEnemies) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_BOOL(allaround); + PARAM_POINTER_DEF(params, FLookExParams); + ACTION_RETURN_BOOL(P_LookForEnemies(self, allaround, params)); +} + + /* ================ = @@ -1777,6 +1928,14 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params) } } +DEFINE_ACTION_FUNCTION(AActor, LookForPlayers) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_BOOL(allaround); + PARAM_POINTER_DEF(params, FLookExParams); + ACTION_RETURN_BOOL(P_LookForPlayers(self, allaround, params)); +} + // // ACTION ROUTINES // @@ -1788,7 +1947,7 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params) // DEFINE_ACTION_FUNCTION(AActor, A_Look) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); AActor *targ; @@ -1906,15 +2065,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) +DEFINE_ACTION_FUNCTION(AActor, A_LookEx) { - PARAM_ACTION_PROLOGUE; - PARAM_INT_OPT (flags) { flags = 0; } - PARAM_FLOAT_OPT (minseedist) { minseedist = 0; } - PARAM_FLOAT_OPT (maxseedist) { maxseedist = 0; } - PARAM_FLOAT_OPT (maxheardist) { maxheardist = 0; } - PARAM_ANGLE_OPT (fov) { fov = 0.; } - PARAM_STATE_OPT (seestate) { seestate = NULL; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT_DEF (flags) + PARAM_FLOAT_DEF (minseedist) + PARAM_FLOAT_DEF (maxseedist) + PARAM_FLOAT_DEF (maxheardist) + PARAM_ANGLE_DEF (fov) + PARAM_STATE_DEF (seestate) AActor *targ = NULL; // Shuts up gcc double dist; @@ -2100,7 +2259,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) DEFINE_ACTION_FUNCTION(AActor, A_ClearLastHeard) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); self->LastHeard = NULL; return 0; } @@ -2123,20 +2282,14 @@ enum ChaseFlags CHF_STOPIFBLOCKED = 256, }; -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Wander) +DEFINE_ACTION_FUNCTION(AActor, A_Wander) { - PARAM_ACTION_PROLOGUE; - PARAM_INT_OPT(flags) { flags = 0; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT_DEF(flags); A_Wander(self, flags); return 0; } -// [MC] I had to move this out from within A_Wander in order to allow flags to -// pass into it. That meant replacing the CALL_ACTION(A_Wander) functions with -// just straight up defining A_Wander in order to compile. Looking around though, -// actors from the games themselves just do a straight A_Chase call itself so -// I saw no harm in it. - void A_Wander(AActor *self, int flags) { // [RH] Strife probably clears this flag somewhere, but I couldn't find where. @@ -2185,7 +2338,7 @@ void A_Wander(AActor *self, int flags) //========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_Look2) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); AActor *targ; @@ -2249,7 +2402,7 @@ nosee: //============================================================================= #define CLASS_BOSS_STRAFE_RANGE 64*10 -void A_DoChase (VMFrameStack *stack, AActor *actor, bool fastchase, FState *meleestate, FState *missilestate, bool playactive, bool nightmarefast, bool dontmove, int flags) +void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missilestate, bool playactive, bool nightmarefast, bool dontmove, int flags) { if (actor->flags5 & MF5_INCONVERSATION) @@ -2379,7 +2532,7 @@ void A_DoChase (VMFrameStack *stack, AActor *actor, bool fastchase, FState *mele { if (actor->flags & MF_FRIENDLY) { - //CALL_ACTION(A_Look, actor); + //A_Look(actor); if (actor->target == NULL) { if (!dontmove) A_Wander(actor); @@ -2487,7 +2640,7 @@ void A_DoChase (VMFrameStack *stack, AActor *actor, bool fastchase, FState *mele DAngle ang = actor->AngleTo(actor->target); if (pr_chase() < 128) ang += 90.; else ang -= 90.; - actor->VelFromAngle(ang, 13.); + actor->VelFromAngle(13., ang); actor->FastChaseStrafeCount = 3; // strafe time } } @@ -2765,64 +2918,64 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates) // //========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Chase) +DEFINE_ACTION_FUNCTION(AActor, A_Chase) { - PARAM_ACTION_PROLOGUE; - PARAM_STATE_OPT (melee) { melee = NULL; } - PARAM_STATE_OPT (missile) { missile = NULL; } - PARAM_INT_OPT (flags) { flags = 0; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_STATE_DEF (melee) + PARAM_STATE_DEF (missile) + PARAM_INT_DEF (flags) - if (numparam >= NAP + 1) + if (numparam > 1) { if ((flags & CHF_RESURRECT) && P_CheckForResurrection(self, false)) return 0; - A_DoChase(stack, self, !!(flags&CHF_FASTCHASE), melee, missile, !(flags&CHF_NOPLAYACTIVE), + A_DoChase(self, !!(flags&CHF_FASTCHASE), melee, missile, !(flags&CHF_NOPLAYACTIVE), !!(flags&CHF_NIGHTMAREFAST), !!(flags&CHF_DONTMOVE), flags); } else // this is the old default A_Chase { - A_DoChase(stack, self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false, flags); + A_DoChase(self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false, flags); } return 0; } DEFINE_ACTION_FUNCTION(AActor, A_FastChase) { - PARAM_ACTION_PROLOGUE; - A_DoChase(stack, self, true, self->MeleeState, self->MissileState, true, true, false, 0); + PARAM_SELF_PROLOGUE(AActor); + A_DoChase(self, true, self->MeleeState, self->MissileState, true, true, false, 0); return 0; } DEFINE_ACTION_FUNCTION(AActor, A_VileChase) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); if (!P_CheckForResurrection(self, true)) { - A_DoChase(stack, self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false, 0); + A_DoChase(self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false, 0); } return 0; } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ExtChase) +DEFINE_ACTION_FUNCTION(AActor, A_ExtChase) { PARAM_SELF_PROLOGUE(AActor); PARAM_BOOL (domelee); PARAM_BOOL (domissile); - PARAM_BOOL_OPT (playactive) { playactive = true; } - PARAM_BOOL_OPT (nightmarefast) { nightmarefast = false; } + PARAM_BOOL_DEF (playactive); + PARAM_BOOL_DEF (nightmarefast); // Now that A_Chase can handle state label parameters, this function has become rather useless... - A_DoChase(stack, self, false, + A_DoChase(self, false, domelee ? self->MeleeState : NULL, domissile ? self->MissileState : NULL, playactive, nightmarefast, false, 0); return 0; } // for internal use -void A_Chase(VMFrameStack *stack, AActor *self) +void A_Chase(AActor *self) { - A_DoChase(stack, self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false, 0); + A_DoChase(self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false, 0); } //============================================================================= @@ -2944,45 +3097,18 @@ void A_FaceTarget(AActor *self) A_Face(self, self->target); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceTarget) +DEFINE_ACTION_FUNCTION(AActor, A_Face) { - PARAM_ACTION_PROLOGUE; - PARAM_ANGLE_OPT(max_turn) { max_turn = 0.; } - PARAM_ANGLE_OPT(max_pitch) { max_pitch = 270.; } - PARAM_ANGLE_OPT(ang_offset) { ang_offset = 0.; } - PARAM_ANGLE_OPT(pitch_offset) { pitch_offset = 0.; } - PARAM_INT_OPT(flags) { flags = 0; } - PARAM_FLOAT_OPT(z_add) { z_add = 0; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(faceto, AActor) + PARAM_ANGLE_DEF(max_turn) + PARAM_ANGLE_DEF(max_pitch) + PARAM_ANGLE_DEF(ang_offset) + PARAM_ANGLE_DEF(pitch_offset) + PARAM_INT_DEF(flags) + PARAM_FLOAT_DEF(z_add) - A_Face(self, self->target, max_turn, max_pitch, ang_offset, pitch_offset, flags, z_add); - return 0; -} - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceMaster) -{ - PARAM_ACTION_PROLOGUE; - PARAM_ANGLE_OPT(max_turn) { max_turn = 0.; } - PARAM_ANGLE_OPT(max_pitch) { max_pitch = 270.; } - PARAM_ANGLE_OPT(ang_offset) { ang_offset = 0.; } - PARAM_ANGLE_OPT(pitch_offset) { pitch_offset = 0.; } - PARAM_INT_OPT(flags) { flags = 0; } - PARAM_FLOAT_OPT(z_add) { z_add = 0; } - - A_Face(self, self->master, max_turn, max_pitch, ang_offset, pitch_offset, flags, z_add); - return 0; -} - -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceTracer) -{ - PARAM_ACTION_PROLOGUE; - PARAM_ANGLE_OPT(max_turn) { max_turn = 0.; } - PARAM_ANGLE_OPT(max_pitch) { max_pitch = 270.; } - PARAM_ANGLE_OPT(ang_offset) { ang_offset = 0.; } - PARAM_ANGLE_OPT(pitch_offset) { pitch_offset = 0.; } - PARAM_INT_OPT(flags) { flags = 0; } - PARAM_FLOAT_OPT(z_add) { z_add = 0; } - - A_Face(self, self->tracer, max_turn, max_pitch, ang_offset, pitch_offset, flags, z_add); + A_Face(self, faceto, max_turn, max_pitch, ang_offset, pitch_offset, flags, z_add); return 0; } @@ -2995,7 +3121,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceTracer) //=========================================================================== DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); if (!self->target) return 0; @@ -3041,7 +3167,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail) DEFINE_ACTION_FUNCTION(AActor, A_Scream) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); if (self->DeathSound) { // Check for bosses. @@ -3060,7 +3186,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Scream) DEFINE_ACTION_FUNCTION(AActor, A_XScream) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); if (self->player) S_Sound (self, CHAN_VOICE, "*gibbed", 1, ATTN_NORM); else @@ -3068,20 +3194,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_XScream) return 0; } -//=========================================================================== -// -// A_ScreamAndUnblock -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_ScreamAndUnblock) -{ - PARAM_ACTION_PROLOGUE; - CALL_ACTION(A_Scream, self); - A_Unblock(self, true); - return 0; -} - //=========================================================================== // // A_ActiveSound @@ -3090,28 +3202,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_ScreamAndUnblock) DEFINE_ACTION_FUNCTION(AActor, A_ActiveSound) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); if (self->ActiveSound) { - S_Sound (self, CHAN_VOICE, self->ActiveSound, 1, ATTN_NORM); + S_Sound(self, CHAN_VOICE, self->ActiveSound, 1, ATTN_NORM); } return 0; } -//=========================================================================== -// -// A_ActiveAndUnblock -// -//=========================================================================== - -DEFINE_ACTION_FUNCTION(AActor, A_ActiveAndUnblock) -{ - PARAM_ACTION_PROLOGUE; - CALL_ACTION(A_ActiveSound, self); - A_Unblock(self, true); - return 0; -} - //--------------------------------------------------------------------------- // // Modifies the drop amount of this item according to the current skill's @@ -3216,7 +3314,7 @@ AInventory *P_DropItem (AActor *source, PClassActor *type, int dropamount, int c AInventory *inv = static_cast(mo); ModifyDropAmount(inv, dropamount); inv->ItemFlags |= IF_TOSSED; - if (inv->SpecialDropAction (source)) + if (inv->CallSpecialDropAction (source)) { // The special action indicates that the item should not spawn inv->Destroy(); @@ -3256,7 +3354,7 @@ void P_TossItem (AActor *item) DEFINE_ACTION_FUNCTION(AActor, A_Pain) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); // [RH] Vary player pain sounds depending on health (ala Quake2) if (self->player && self->player->morphTics == 0) @@ -3302,16 +3400,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_Pain) return 0; } -// killough 11/98: kill an object -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Die) -{ - PARAM_ACTION_PROLOGUE; - PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } - - P_DamageMobj(self, NULL, NULL, self->health, damagetype, DMG_FORCED); - return 0; -} - // // A_Detonate // killough 8/9/98: same as A_Explode, except that the damage is variable @@ -3319,7 +3407,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Die) DEFINE_ACTION_FUNCTION(AActor, A_Detonate) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); int damage = self->GetMissileDamage(0, 1); P_RadiusAttack (self, self->target, damage, damage, self->DamageType, RADF_HURTSOURCE); P_CheckSplash(self, damage); @@ -3356,6 +3444,12 @@ bool CheckBossDeath (AActor *actor) return true; } +DEFINE_ACTION_FUNCTION(AActor, CheckBossDeath) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_BOOL(CheckBossDeath(self)); +} + // // A_BossDeath // Possibly trigger special effects if on a boss level @@ -3462,7 +3556,7 @@ void A_BossDeath(AActor *self) DEFINE_ACTION_FUNCTION(AActor, A_BossDeath) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); A_BossDeath(self); return 0; } @@ -3497,50 +3591,9 @@ int P_Massacre () return killcount; } -// -// A_SinkMobj -// Sink a mobj incrementally into the floor -// - -bool A_SinkMobj (AActor *actor, double speed) -{ - if (actor->Floorclip < actor->Height) - { - actor->Floorclip += speed; - return false; - } - return true; -} - -// -// A_RaiseMobj -// Raise a mobj incrementally from the floor to -// - -bool A_RaiseMobj (AActor *actor, double speed) -{ - bool done = true; - - // Raise a mobj from the ground - if (actor->Floorclip > 0) - { - actor->Floorclip -= speed; - if (actor->Floorclip <= 0) - { - actor->Floorclip = 0; - done = true; - } - else - { - done = false; - } - } - return done; // Reached target height -} - DEFINE_ACTION_FUNCTION(AActor, A_ClassBossHealth) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); if (multiplayer && !deathmatch) // co-op only { if (!self->special1) diff --git a/src/p_enemy.h b/src/p_enemy.h index 1be77a4eca..a0e829c712 100644 --- a/src/p_enemy.h +++ b/src/p_enemy.h @@ -1,7 +1,8 @@ #ifndef __P_ENEMY_H__ #define __P_ENEMY_H__ -#include "thingdef/thingdef.h" +#include "dobject.h" +#include "vectors.h" struct sector_t; class AActor; @@ -59,24 +60,13 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params); void A_Weave(AActor *self, int xyspeed, int zspeed, double xydist, double zdist); void A_Unblock(AActor *self, bool drop); -DECLARE_ACTION(A_Look) -DECLARE_ACTION(A_BossDeath) -DECLARE_ACTION(A_Pain) -DECLARE_ACTION(A_MonsterRail) -DECLARE_ACTION(A_NoBlocking) -DECLARE_ACTION(A_Scream) -DECLARE_ACTION(A_FreezeDeath) -DECLARE_ACTION(A_FreezeDeathChunks) void A_BossDeath(AActor *self); void A_Wander(AActor *self, int flags = 0); -void A_Chase(VMFrameStack *stack, AActor *self); +void A_Chase(AActor *self); void A_FaceTarget(AActor *actor); void A_Face(AActor *self, AActor *other, DAngle max_turn = 0., DAngle max_pitch = 270., DAngle ang_offset = 0., DAngle pitch_offset = 0., int flags = 0, double z_add = 0); -bool A_RaiseMobj (AActor *, double speed); -bool A_SinkMobj (AActor *, double speed); - bool CheckBossDeath (AActor *); int P_Massacre (); bool P_CheckMissileRange (AActor *actor); diff --git a/src/p_floor.cpp b/src/p_floor.cpp index 62479e3404..4b1f243d5b 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -64,7 +64,7 @@ static void StartFloorSound (sector_t *sec) // //========================================================================== -IMPLEMENT_CLASS (DFloor) +IMPLEMENT_CLASS(DFloor, false, false) DFloor::DFloor () { @@ -492,6 +492,21 @@ bool P_CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *line, return true; } +DEFINE_ACTION_FUNCTION(DFloor, CreateFloor) +{ + PARAM_PROLOGUE; + PARAM_POINTER_NOT_NULL(sec, sector_t); + PARAM_INT(floortype); + PARAM_POINTER(ln, line_t); + PARAM_FLOAT(speed); + PARAM_FLOAT_DEF(height); + PARAM_INT_DEF(crush); + PARAM_INT_DEF(change); + PARAM_BOOL_DEF(hereticlower); + PARAM_BOOL_DEF(hexencrush); + ACTION_RETURN_BOOL(P_CreateFloor(sec, (DFloor::EFloor)floortype, ln, speed, height, crush, change, hexencrush, hereticlower)); +} + //========================================================================== // // HANDLE FLOOR TYPES @@ -815,10 +830,12 @@ bool EV_DoDonut (int tag, line_t *line, double pillarspeed, double slimespeed) // //========================================================================== -IMPLEMENT_POINTY_CLASS (DElevator) - DECLARE_POINTER(m_Interp_Floor) - DECLARE_POINTER(m_Interp_Ceiling) -END_POINTERS +IMPLEMENT_CLASS(DElevator, false, true) + +IMPLEMENT_POINTERS_START(DElevator) + IMPLEMENT_POINTER(m_Interp_Floor) + IMPLEMENT_POINTER(m_Interp_Ceiling) +IMPLEMENT_POINTERS_END DElevator::DElevator () { @@ -1103,10 +1120,9 @@ bool EV_DoChange (line_t *line, EChange changetype, int tag) // //========================================================================== -IMPLEMENT_CLASS (DWaggleBase) - -IMPLEMENT_CLASS (DFloorWaggle) -IMPLEMENT_CLASS (DCeilingWaggle) +IMPLEMENT_CLASS(DWaggleBase, false, false) +IMPLEMENT_CLASS(DFloorWaggle, false, false) +IMPLEMENT_CLASS(DCeilingWaggle, false, false) DWaggleBase::DWaggleBase () { @@ -1140,11 +1156,6 @@ DWaggleBase::DWaggleBase (sector_t *sec) { } -void DWaggleBase::Destroy() -{ - Super::Destroy(); -} - //========================================================================== // // diff --git a/src/p_glnodes.cpp b/src/p_glnodes.cpp index 39c8f8e0dc..26e341aab7 100644 --- a/src/p_glnodes.cpp +++ b/src/p_glnodes.cpp @@ -1356,7 +1356,6 @@ subsector_t *P_PointInSubsector (double x, double y) return (subsector_t *)((BYTE *)node - 1); } - //========================================================================== // // PointOnLine diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 261cfb8f3d..9aa178e64d 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -58,6 +58,8 @@ #include "d_net.h" #include "d_netinf.h" #include "a_morph.h" +#include "virtual.h" +#include "a_health.h" static FRandom pr_obituary ("Obituary"); static FRandom pr_botrespawn ("BotRespawn"); @@ -104,8 +106,7 @@ void P_TouchSpecialThing (AActor *special, AActor *toucher) toucher->player->Bot->prev = toucher->player->Bot->dest; toucher->player->Bot->dest = NULL; } - - special->Touch (toucher); + special->CallTouch (toucher); } @@ -342,7 +343,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) realthis->health = realgibhealth -1; // if morphed was gibbed, so must original be (where allowed)l } } - realthis->Die(source, inflictor, dmgflags); + realthis->CallDie(source, inflictor, dmgflags); } return; } @@ -761,7 +762,25 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) } } +DEFINE_ACTION_FUNCTION(AActor, Die) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(source, AActor); + PARAM_OBJECT(inflictor, AActor); + PARAM_INT_DEF(dmgflags); + self->Die(source, inflictor, dmgflags); + return 0; +} +void AActor::CallDie(AActor *source, AActor *inflictor, int dmgflags) +{ + IFVIRTUAL(AActor, Die) + { + VMValue params[4] = { (DObject*)this, source, inflictor, dmgflags }; + GlobalVMStack.Call(func, params, 4, nullptr, 0, nullptr); + } + else return Die(source, inflictor, dmgflags); +} //--------------------------------------------------------------------------- @@ -1071,7 +1090,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, } } - damage = inflictor->DoSpecialDamage(target, damage, mod); + damage = inflictor->CallDoSpecialDamage(target, damage, mod); if (damage < 0) { return -1; @@ -1085,15 +1104,15 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, damage = int(damage * source->DamageMultiply); // Handle active damage modifiers (e.g. PowerDamage) - if (damage > 0 && source->Inventory != NULL) + if (damage > 0) { - source->Inventory->ModifyDamage(damage, mod, damage, false); + damage = source->GetModifiedDamage(mod, damage, false); } } // Handle passive damage modifiers (e.g. PowerProtection), provided they are not afflicted with protection penetrating powers. - if (damage > 0 && (target->Inventory != NULL) && !(flags & DMG_NO_PROTECT)) + if (damage > 0 && !(flags & DMG_NO_PROTECT)) { - target->Inventory->ModifyDamage(damage, mod, damage, true); + damage = target->GetModifiedDamage(mod, damage, true); } if (damage > 0 && !(flags & DMG_NO_FACTOR)) { @@ -1102,7 +1121,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, if (damage >= 0) { - damage = target->TakeSpecialDamage(inflictor, source, damage, mod); + damage = target->CallTakeSpecialDamage(inflictor, source, damage, mod); } // '<0' is handled below. This only handles the case where damage gets reduced to 0. @@ -1242,6 +1261,11 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, // if (player) { + // Don't allow DMG_FORCED to work on ultimate degreeslessness/buddha and nodamage. + if ((player->cheats & (CF_GODMODE2 | CF_BUDDHA2)) || (player->mo->flags5 & MF5_NODAMAGE)) + { + flags &= ~DMG_FORCED; + } //Added by MC: Lets bots look allround for enemies if they survive an ambush. if (player->Bot != NULL) { @@ -1438,7 +1462,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, source = source->tracer; } } - target->Die (source, inflictor, flags); + target->CallDie (source, inflictor, flags); return damage; } } @@ -1555,6 +1579,18 @@ dopain: return damage; } +DEFINE_ACTION_FUNCTION(AActor, DamageMobj) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(inflictor, AActor); + PARAM_OBJECT(source, AActor); + PARAM_INT(damage); + PARAM_NAME(mod); + PARAM_INT_DEF(flags); + PARAM_FLOAT_DEF(angle); + ACTION_RETURN_INT(P_DamageMobj(self, inflictor, source, damage, mod, flags, angle)); +} + void P_PoisonMobj (AActor *target, AActor *inflictor, AActor *source, int damage, int duration, int period, FName type) { // Check for invulnerability. @@ -1600,6 +1636,20 @@ void P_PoisonMobj (AActor *target, AActor *inflictor, AActor *source, int damage } +DEFINE_ACTION_FUNCTION(AActor, PoisonMobj) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(inflictor, AActor); + PARAM_OBJECT(source, AActor); + PARAM_INT(damage); + PARAM_INT(duration); + PARAM_INT(period); + PARAM_NAME(mod); + P_PoisonMobj(self, inflictor, source, damage, duration, period, mod); + return 0; +} + + bool AActor::OkayToSwitchTarget (AActor *other) { if (other == this) @@ -1697,14 +1747,22 @@ bool P_PoisonPlayer (player_t *player, AActor *poisoner, AActor *source, int poi return true; } +DEFINE_ACTION_FUNCTION(_PlayerInfo, PoisonPlayer) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_OBJECT(poisoner, AActor); + PARAM_OBJECT(source, AActor); + PARAM_INT(poison); + ACTION_RETURN_BOOL(P_PoisonPlayer(self, poisoner, source, poison)); +} + //========================================================================== // // P_PoisonDamage - Similar to P_DamageMobj // //========================================================================== -void P_PoisonDamage (player_t *player, AActor *source, int damage, - bool playPainSound) +void P_PoisonDamage (player_t *player, AActor *source, int damage, bool playPainSound) { AActor *target; @@ -1725,10 +1783,7 @@ void P_PoisonDamage (player_t *player, AActor *source, int damage, // Take half damage in trainer mode damage = int(damage * G_SkillProperty(SKILLP_DamageFactor)); // Handle passive damage modifiers (e.g. PowerProtection) - if (target->Inventory != NULL) - { - target->Inventory->ModifyDamage(damage, player->poisontype, damage, true); - } + damage = target->GetModifiedDamage(player->poisontype, damage, true); // Modify with damage factors damage = target->ApplyDamageFactor(player->poisontype, damage); @@ -1777,7 +1832,7 @@ void P_PoisonDamage (player_t *player, AActor *source, int damage, target->DamageType = player->poisontype; } } - target->Die(source, source); + target->CallDie(source, source); return; } } @@ -1799,6 +1854,15 @@ void P_PoisonDamage (player_t *player, AActor *source, int damage, */ } +DEFINE_ACTION_FUNCTION(_PlayerInfo, PoisonDamage) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_OBJECT(source, AActor); + PARAM_INT(damage); + PARAM_BOOL(playsound); + P_PoisonDamage(self, source, damage, playsound); + return 0; +} CCMD (kill) { diff --git a/src/p_lights.cpp b/src/p_lights.cpp index fb3ab339e4..910c52a648 100644 --- a/src/p_lights.cpp +++ b/src/p_lights.cpp @@ -173,7 +173,7 @@ private: // //----------------------------------------------------------------------------- -IMPLEMENT_CLASS (DLighting) +IMPLEMENT_CLASS(DLighting, false, false) DLighting::DLighting () { @@ -191,7 +191,7 @@ DLighting::DLighting (sector_t *sector) // //----------------------------------------------------------------------------- -IMPLEMENT_CLASS (DFireFlicker) +IMPLEMENT_CLASS(DFireFlicker, false, false) DFireFlicker::DFireFlicker () { @@ -258,7 +258,7 @@ DFireFlicker::DFireFlicker (sector_t *sector, int upper, int lower) // //----------------------------------------------------------------------------- -IMPLEMENT_CLASS (DFlicker) +IMPLEMENT_CLASS(DFlicker, false, false) DFlicker::DFlicker () { @@ -334,7 +334,7 @@ void EV_StartLightFlickering (int tag, int upper, int lower) // //----------------------------------------------------------------------------- -IMPLEMENT_CLASS (DLightFlash) +IMPLEMENT_CLASS(DLightFlash, false, false) DLightFlash::DLightFlash () { @@ -409,7 +409,7 @@ DLightFlash::DLightFlash (sector_t *sector, int min, int max) // //----------------------------------------------------------------------------- -IMPLEMENT_CLASS (DStrobe) +IMPLEMENT_CLASS(DStrobe, false, false) DStrobe::DStrobe () { @@ -667,7 +667,7 @@ void EV_LightChange (int tag, int value) // //----------------------------------------------------------------------------- -IMPLEMENT_CLASS (DGlow) +IMPLEMENT_CLASS(DGlow, false, false) DGlow::DGlow () { @@ -736,7 +736,7 @@ DGlow::DGlow (sector_t *sector) // //----------------------------------------------------------------------------- -IMPLEMENT_CLASS (DGlow2) +IMPLEMENT_CLASS(DGlow2, false, false) DGlow2::DGlow2 () { @@ -869,7 +869,7 @@ void EV_StartLightFading (int tag, int value, int tics) // //----------------------------------------------------------------------------- -IMPLEMENT_CLASS (DPhased) +IMPLEMENT_CLASS(DPhased, false, false) DPhased::DPhased () { diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index cf50a1dfa5..d368739e16 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -50,7 +50,6 @@ #include "gi.h" #include "m_random.h" #include "p_conversation.h" -#include "a_strifeglobal.h" #include "r_data/r_translate.h" #include "p_3dmidtex.h" #include "d_net.h" @@ -350,7 +349,7 @@ FUNC(LS_Floor_LowerToHighest) } FUNC(LS_Floor_LowerToHighestEE) -// Floor_LowerToHighest (tag, speed, change) +// Floor_LowerToHighestEE (tag, speed, change) { return EV_DoFloor (DFloor::floorLowerToHighest, ln, arg0, SPEED(arg1), 0, -1, CHANGE(arg2), false); } @@ -1371,7 +1370,7 @@ void DoActivateThing(AActor * thing, AActor * activator) if (thing->activationtype & THINGSPEC_Switch) // Set other flag if switching thing->activationtype |= THINGSPEC_Deactivate; } - thing->Activate (activator); + thing->CallActivate (activator); } void DoDeactivateThing(AActor * thing, AActor * activator) @@ -1382,7 +1381,7 @@ void DoDeactivateThing(AActor * thing, AActor * activator) if (thing->activationtype & THINGSPEC_Switch) // Set other flag if switching thing->activationtype |= THINGSPEC_Activate; } - thing->Deactivate (activator); + thing->CallDeactivate (activator); } FUNC(LS_Thing_Activate) @@ -3155,17 +3154,7 @@ FUNC(LS_ClearForceField) sector_t *sec = §ors[secnum]; rtn = true; - for (int i = 0; i < sec->linecount; ++i) - { - line_t *line = sec->lines[i]; - if (line->backsector != NULL && line->special == ForceField) - { - line->flags &= ~(ML_BLOCKING|ML_BLOCKEVERYTHING); - line->special = 0; - line->sidedef[0]->SetTexture(side_t::mid, FNullTextureID()); - line->sidedef[1]->SetTexture(side_t::mid, FNullTextureID()); - } - } + sec->RemoveForceField(); } return rtn; } @@ -3233,8 +3222,8 @@ FUNC(LS_GlassBreak) if (it != NULL) { it->GiveInventoryType (QuestItemClasses[28]); - it->GiveInventoryType (RUNTIME_CLASS(AUpgradeAccuracy)); - it->GiveInventoryType (RUNTIME_CLASS(AUpgradeStamina)); + it->GiveInventoryType (PClass::FindActor("UpgradeAccuracy")); + it->GiveInventoryType (PClass::FindActor("UpgradeStamina")); } } } diff --git a/src/p_local.h b/src/p_local.h index d759828dce..12b4a40a3c 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -238,7 +238,7 @@ enum PCM AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, int, void *), void *params = NULL); -AActor *P_RoughMonsterSearch (AActor *mo, int distance, bool onlyseekable=false); +AActor *P_RoughMonsterSearch (AActor *mo, int distance, bool onlyseekable=false, bool frontonly = false); // // P_MAP diff --git a/src/p_map.cpp b/src/p_map.cpp index 475cd3569c..16a5933d5a 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -46,6 +46,7 @@ #include "r_utility.h" #include "p_blockmap.h" #include "p_3dmidtex.h" +#include "virtual.h" #include "s_sound.h" #include "decallib.h" @@ -297,6 +298,14 @@ void P_FindFloorCeiling(AActor *actor, int flags) } } +DEFINE_ACTION_FUNCTION(AActor, FindFloorCeiling) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT_DEF(flags); + P_FindFloorCeiling(self, flags); + return 0; +} + // Debug CCMD for checking errors in the MultiBlockLinesIterator (needs to be removed when this code is complete) CCMD(ffcf) { @@ -444,6 +453,17 @@ bool P_TeleportMove(AActor* thing, const DVector3 &pos, bool telefrag, bool modi return true; } +DEFINE_ACTION_FUNCTION(AActor, TeleportMove) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_BOOL(telefrag); + PARAM_BOOL_DEF(modify); + ACTION_RETURN_BOOL(P_TeleportMove(self, DVector3(x, y, z), telefrag, modify)); +} + //========================================================================== // // [RH] P_PlayerStartStomp @@ -650,6 +670,21 @@ double P_GetMoveFactor(const AActor *mo, double *frictionp) return movefactor; } +DEFINE_ACTION_FUNCTION(AActor, GetFriction) +{ + PARAM_SELF_PROLOGUE(AActor); + double friction, movefactor = P_GetMoveFactor(self, &friction); + if (numret > 1) + { + numret = 2; + ret[1].SetFloat(movefactor); + } + if (numret > 0) + { + ret[0].SetFloat(friction); + } + return numret; +} //========================================================================== // @@ -1100,6 +1135,12 @@ static bool CanAttackHurt(AActor *victim, AActor *shooter) // //========================================================================== +DEFINE_ACTION_FUNCTION(AActor, CanCollideWith) +{ + // No need to check the parameters, as they are not even used. + ACTION_RETURN_BOOL(true); +} + bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::CheckResult &cres, const FBoundingBox &box, FCheckPosition &tm) { AActor *thing = cres.thing; @@ -1188,15 +1229,55 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch (thing->flags5 & MF5_DONTRIP) || ((tm.thing->flags6 & MF6_NOBOSSRIP) && (thing->flags2 & MF2_BOSS))) { - if (tm.thing->flags3 & thing->flags3 & MF3_DONTOVERLAP) - { // Some things prefer not to overlap each other, if possible - return unblocking; + // Some things prefer not to overlap each other, if possible (Q: Is this even needed anymore? It was just for dealing with some deficiencies in the code below in Heretic.) + if (!(tm.thing->flags3 & thing->flags3 & MF3_DONTOVERLAP)) + { + if ((tm.thing->Z() >= topz) || (tm.thing->Top() <= thing->Z())) + return true; } - if ((tm.thing->Z() >= topz) || (tm.thing->Top() <= thing->Z())) - return true; + // If they are not allowed to overlap, the rest of this function still needs to be executed. } } + // Call the script callback. This must be done before any other checks that perform some actual action or may already return a 'block'. + // The checks here are to do this only for conditions that would later result in an action, calling this for everything would be too much of a drag if + // too many scripted overrides were being used, as PIT_CheckThing is even called for touching all the monster corpses lying around. + if (((thing->flags & MF_SOLID) || (thing->flags6 & (MF6_TOUCHY | MF6_BUMPSPECIAL))) && + ((tm.thing->flags & (MF_SOLID|MF_MISSILE)) || (tm.thing->flags2 & MF2_BLASTED) || (tm.thing->flags6 & MF6_BLOCKEDBYSOLIDACTORS) || (tm.thing->BounceFlags & BOUNCE_MBF))) + { + static unsigned VIndex = ~0u; + if (VIndex == ~0u) + { + VIndex = GetVirtualIndex(RUNTIME_CLASS(AActor), "CanCollideWith"); + assert(VIndex != ~0u); + } + + VMValue params[3] = { tm.thing, thing, false }; + VMReturn ret; + int retval; + ret.IntAt(&retval); + + auto clss = tm.thing->GetClass(); + VMFunction *func = clss->Virtuals.Size() > VIndex ? clss->Virtuals[VIndex] : nullptr; + if (func != nullptr) + { + GlobalVMStack.Call(func, params, 3, &ret, 1, nullptr); + if (!retval) return true; + } + std::swap(params[0].a, params[1].a); + params[2].i = true; + + // re-get for the other actor. + clss = thing->GetClass(); + func = clss->Virtuals.Size() > VIndex ? clss->Virtuals[VIndex] : nullptr; + if (func != nullptr) + { + GlobalVMStack.Call(func, params, 3, &ret, 1, nullptr); + if (!retval) return true; + } + } + + if (tm.thing->player == NULL || !(tm.thing->player->cheats & CF_PREDICTING)) { // touchy object is alive, toucher is solid @@ -1234,7 +1315,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch // Check for skulls slamming into things if (tm.thing->flags & MF_SKULLFLY) { - bool res = tm.thing->Slam(tm.thing->BlockingMobj); + bool res = tm.thing->CallSlam(tm.thing->BlockingMobj); tm.thing->BlockingMobj = NULL; return res; } @@ -1729,6 +1810,15 @@ bool P_CheckPosition(AActor *thing, const DVector2 &pos, bool actorsonly) return P_CheckPosition(thing, pos, tm, actorsonly); } +DEFINE_ACTION_FUNCTION(AActor, CheckPosition) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_BOOL_DEF(actorsonly); + ACTION_RETURN_BOOL(P_CheckPosition(self, DVector2(x, y), actorsonly)); +} + //---------------------------------------------------------------------------- // // FUNC P_TestMobjLocation @@ -1757,6 +1847,11 @@ bool P_TestMobjLocation(AActor *mobj) return false; } +DEFINE_ACTION_FUNCTION(AActor, TestMobjLocation) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_BOOL(P_TestMobjLocation(self)); +} //============================================================================= // @@ -1860,6 +1955,26 @@ bool P_TestMobjZ(AActor *actor, bool quick, AActor **pOnmobj) return onmobj == NULL; } +DEFINE_ACTION_FUNCTION(AActor, TestMobjZ) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_BOOL_DEF(quick); + + AActor *on = nullptr;; + bool retv = P_TestMobjZ(self, quick, &on); + if (numret > 1) + { + numret = 2; + ret[1].SetPointer(on, ATAG_OBJECT); + } + if (numret > 0) + { + ret[0].SetInt(retv); + } + return numret; +} + + //============================================================================= // // P_FakeZMovement @@ -2489,6 +2604,14 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, return P_TryMove(thing, pos, dropoff, onfloor, tm); } +DEFINE_ACTION_FUNCTION(AActor, TryMove) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_INT(dropoff); + ACTION_RETURN_BOOL(P_TryMove(self, DVector2(x, y), dropoff)); +} //========================================================================== @@ -3245,7 +3368,7 @@ bool FSlide::BounceWall(AActor *mo) if (mo->flags & MF_MISSILE) P_ExplodeMissile(mo, line, NULL); else - mo->Die(NULL, NULL); + mo->CallDie(NULL, NULL); return true; } @@ -3465,6 +3588,7 @@ struct aim_t res.linetarget = th; res.pitch = pitch; res.angleFromSource = (th->Pos() - startpos).Angle(); + res.attackAngleFromSource = res.angleFromSource; // at this point we do not have an attack angle so it's the same as the actual angle between actors. res.unlinked = unlinked; res.frac = frac; } @@ -4045,6 +4169,18 @@ DAngle P_AimLineAttack(AActor *t1, DAngle angle, double distance, FTranslatedLin return result->linetarget ? result->pitch : t1->Angles.Pitch; } +DEFINE_ACTION_FUNCTION(AActor, AimLineAttack) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_ANGLE(angle); + PARAM_FLOAT(distance); + PARAM_POINTER_DEF(pLineTarget, FTranslatedLineTarget); + PARAM_ANGLE_DEF(vrange); + PARAM_INT_DEF(flags); + PARAM_OBJECT_DEF(target, AActor); + PARAM_OBJECT_DEF(friender, AActor); + ACTION_RETURN_FLOAT(P_AimLineAttack(self, angle, distance, pLineTarget, vrange, flags, target, friender).Degrees); +} //========================================================================== // @@ -4371,7 +4507,9 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance, if (victim != NULL) { victim->linetarget = trace.Actor; - victim->angleFromSource = trace.SrcAngleFromTarget; + victim->attackAngleFromSource = trace.SrcAngleFromTarget; + // With arbitrary portals this cannot be calculated so using the actual attack angle is the only option. + victim->angleFromSource = trace.unlinked? victim->attackAngleFromSource : t1->AngleTo(trace.Actor); victim->unlinked = trace.unlinked; } } @@ -4412,6 +4550,26 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance, } } +DEFINE_ACTION_FUNCTION(AActor, LineAttack) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_ANGLE(angle); + PARAM_FLOAT(distance); + PARAM_ANGLE(pitch); + PARAM_INT(damage); + PARAM_NAME(damageType); + PARAM_CLASS(puffType, AActor); + PARAM_INT_DEF(flags); + PARAM_POINTER_DEF(victim, FTranslatedLineTarget); + + int acdmg; + if (puffType == nullptr) puffType = PClass::FindActor("BulletPuff"); // P_LineAttack does not work without a puff to take info from. + auto puff = P_LineAttack(self, angle, distance, pitch, damage, damageType, puffType, flags, victim, &acdmg); + if (numret > 0) ret[0].SetPointer(puff, ATAG_OBJECT); + if (numret > 1) ret[1].SetInt(acdmg), numret = 2; + return numret; +} + //========================================================================== // // P_LinePickActor @@ -4547,6 +4705,18 @@ void P_TraceBleed(int damage, AActor *target, DAngle angle, DAngle pitch) P_TraceBleed(damage, target->PosPlusZ(target->Height/2), target, angle, pitch); } +DEFINE_ACTION_FUNCTION(AActor, TraceBleedAngle) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(damage); + PARAM_FLOAT(angle); + PARAM_FLOAT(pitch); + + P_TraceBleed(damage, self, angle, pitch); + return 0; +} + + //========================================================================== // // @@ -4593,6 +4763,17 @@ void P_TraceBleed(int damage, FTranslatedLineTarget *t, AActor *puff) P_TraceBleed(damage, t->linetarget->PosPlusZ(t->linetarget->Height/2), t->linetarget, t->angleFromSource, pitch); } +DEFINE_ACTION_FUNCTION(_FTranslatedLineTarget, TraceBleed) +{ + PARAM_SELF_STRUCT_PROLOGUE(FTranslatedLineTarget); + PARAM_INT(damage); + PARAM_OBJECT_NOT_NULL(missile, AActor); + + P_TraceBleed(damage, self, missile); + return 0; +} + + //========================================================================== // // @@ -4609,6 +4790,18 @@ void P_TraceBleed(int damage, AActor *target) } } +DEFINE_ACTION_FUNCTION(AActor, TraceBleed) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(damage); + PARAM_OBJECT(missile, AActor); + + if (missile) P_TraceBleed(damage, self, missile); + else P_TraceBleed(damage, self); + return 0; +} + + //========================================================================== // // [RH] Rail gun stuffage @@ -6673,7 +6866,7 @@ bool P_ActivateThingSpecial(AActor * thing, AActor * trigger, bool death) thing->activationtype &= ~THINGSPEC_Activate; // Clear flag if (thing->activationtype & THINGSPEC_Switch) // Set other flag if switching thing->activationtype |= THINGSPEC_Deactivate; - thing->Activate(trigger); + thing->CallActivate(trigger); res = true; } // If not, can it be deactivated? @@ -6682,7 +6875,7 @@ bool P_ActivateThingSpecial(AActor * thing, AActor * trigger, bool death) thing->activationtype &= ~THINGSPEC_Deactivate; // Clear flag if (thing->activationtype & THINGSPEC_Switch) // Set other flag if switching thing->activationtype |= THINGSPEC_Activate; - thing->Deactivate(trigger); + thing->CallDeactivate(trigger); res = true; } } diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index a3d4d0e9eb..31b4125988 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -45,7 +45,6 @@ #include "templates.h" #include "po_man.h" -static AActor *RoughBlockCheck (AActor *mo, int index, void *); sector_t *P_PointInSectorBuggy(double x, double y); int P_VanillaPointOnDivlineSide(double x, double y, const divline_t* line); @@ -386,6 +385,14 @@ bool AActor::FixMapthingPos() return success; } +DEFINE_ACTION_FUNCTION(AActor, UnlinkFromWorld) +{ + PARAM_SELF_PROLOGUE(AActor); + self->UnlinkFromWorld(); + return 0; +} + + //========================================================================== // // P_SetThingPosition @@ -508,6 +515,13 @@ void AActor::LinkToWorld(bool spawningmapthing, sector_t *sector) if (!spawningmapthing) UpdateRenderSectorList(); } +DEFINE_ACTION_FUNCTION(AActor, LinkToWorld) +{ + PARAM_SELF_PROLOGUE(AActor); + self->LinkToWorld(); + return 0; +} + void AActor::SetOrigin(double x, double y, double z, bool moving) { UnlinkFromWorld (); @@ -517,6 +531,17 @@ void AActor::SetOrigin(double x, double y, double z, bool moving) if (!moving) ClearInterpolation(); } +DEFINE_ACTION_FUNCTION(AActor, SetOrigin) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_BOOL(moving); + self->SetOrigin(x, y, z, moving); + return 0; +} + //=========================================================================== // // FBlockNode - allows to link actors into multiple blocks in the blockmap @@ -1127,6 +1152,75 @@ void FMultiBlockThingsIterator::Reset() startIteratorForGroup(basegroup); } +//=========================================================================== +// +// and the scriptable version +// +//=========================================================================== + +class DBlockThingsIterator : public DObject, public FMultiBlockThingsIterator +{ + DECLARE_CLASS(DBlockThingsIterator, DObject); + FPortalGroupArray check; +public: + FMultiBlockThingsIterator::CheckResult cres; + +public: + bool Next() + { + return FMultiBlockThingsIterator::Next(&cres); + } + + DBlockThingsIterator(AActor *origin = nullptr, double checkradius = -1, bool ignorerestricted = false) + : FMultiBlockThingsIterator(check, origin, checkradius, ignorerestricted) + { + cres.thing = nullptr; + cres.Position.Zero(); + cres.portalflags = 0; + } + + DBlockThingsIterator(double checkx, double checky, double checkz, double checkh, double checkradius, bool ignorerestricted, sector_t *newsec) + : FMultiBlockThingsIterator(check, checkx, checky, checkz, checkh, checkradius, ignorerestricted, newsec) + { + cres.thing = nullptr; + cres.Position.Zero(); + cres.portalflags = 0; + } +}; + +IMPLEMENT_CLASS(DBlockThingsIterator, false, false); + +DEFINE_ACTION_FUNCTION(DBlockThingsIterator, Create) +{ + PARAM_PROLOGUE; + PARAM_OBJECT_NOT_NULL(origin, AActor); + PARAM_FLOAT_DEF(radius); + PARAM_BOOL_DEF(ignore); + ACTION_RETURN_OBJECT(new DBlockThingsIterator(origin, radius, ignore)); +} + +DEFINE_ACTION_FUNCTION(DBlockThingsIterator, CreateFromPos) +{ + PARAM_PROLOGUE; + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_FLOAT(h); + PARAM_FLOAT(radius); + PARAM_BOOL(ignore); + ACTION_RETURN_OBJECT(new DBlockThingsIterator(x, y, z, h, radius, ignore, nullptr)); +} + +DEFINE_ACTION_FUNCTION(DBlockThingsIterator, Next) +{ + PARAM_SELF_PROLOGUE(DBlockThingsIterator); + ACTION_RETURN_BOOL(self->Next()); +} + +DEFINE_FIELD_NAMED(DBlockThingsIterator, cres.thing, thing); +DEFINE_FIELD_NAMED(DBlockThingsIterator, cres.Position, position); +DEFINE_FIELD_NAMED(DBlockThingsIterator, cres.portalflags, portalflags); + //=========================================================================== // // FPathTraverse :: Intercepts @@ -1659,11 +1753,6 @@ FPathTraverse::~FPathTraverse() // distance is in MAPBLOCKUNITS //=========================================================================== -AActor *P_RoughMonsterSearch (AActor *mo, int distance, bool onlyseekable) -{ - return P_BlockmapSearch (mo, distance, RoughBlockCheck, (void *)onlyseekable); -} - AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, int, void *), void *params) { int blockX; @@ -1753,6 +1842,13 @@ AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, in return NULL; } +struct BlockCheckInfo +{ + bool onlyseekable; + bool frontonly; + divline_t frontline; +}; + //=========================================================================== // // RoughBlockCheck @@ -1761,14 +1857,19 @@ AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, in static AActor *RoughBlockCheck (AActor *mo, int index, void *param) { - bool onlyseekable = param != NULL; + BlockCheckInfo *info = (BlockCheckInfo *)param; + FBlockNode *link; for (link = blocklinks[index]; link != NULL; link = link->NextActor) { if (link->Me != mo) { - if (onlyseekable && !mo->CanSeek(link->Me)) + if (info->onlyseekable && !mo->CanSeek(link->Me)) + { + continue; + } + if (info->frontonly && P_PointOnDivlineSide(link->Me->X(), link->Me->Y(), &info->frontline) != 0) { continue; } @@ -1781,6 +1882,30 @@ static AActor *RoughBlockCheck (AActor *mo, int index, void *param) return NULL; } +AActor *P_RoughMonsterSearch(AActor *mo, int distance, bool onlyseekable, bool frontonly) +{ + BlockCheckInfo info; + info.onlyseekable = onlyseekable; + if ((info.frontonly = frontonly)) + { + info.frontline.x = mo->X(); + info.frontline.y = mo->Y(); + info.frontline.dx = -mo->Angles.Yaw.Sin(); + info.frontline.dy = -mo->Angles.Yaw.Cos(); + } + + return P_BlockmapSearch(mo, distance, RoughBlockCheck, (void *)&info); +} + +DEFINE_ACTION_FUNCTION(AActor, RoughMonsterSearch) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(distance); + PARAM_BOOL_DEF(onlyseekable); + PARAM_BOOL_DEF(frontonly); + ACTION_RETURN_OBJECT(P_RoughMonsterSearch(self, distance, onlyseekable, frontonly)); +} + //========================================================================== // // [RH] LinkToWorldForMapThing @@ -1915,4 +2040,3 @@ sector_t *P_PointInSectorBuggy(double x, double y) subsector_t *ssec = (subsector_t *)((BYTE *)node - 1); return ssec->sector; } - diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 62da260492..b527bf6813 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -22,7 +22,6 @@ //----------------------------------------------------------------------------- // HEADER FILES ------------------------------------------------------------ - #include #include "templates.h" #include "i_system.h" @@ -42,18 +41,14 @@ #include "c_dispatch.h" #include "b_bot.h" //Added by MC: #include "stats.h" -#include "a_hexenglobal.h" #include "a_sharedglobal.h" #include "gi.h" #include "sbar.h" #include "p_acs.h" #include "cmdlib.h" #include "decallib.h" -#include "ravenshared.h" -#include "a_action.h" #include "a_keys.h" #include "p_conversation.h" -#include "thingdef/thingdef.h" #include "g_game.h" #include "teaminfo.h" #include "r_data/r_translate.h" @@ -71,6 +66,12 @@ #include "p_checkposition.h" #include "serializer.h" #include "r_utility.h" +#include "thingdef.h" +#include "d_player.h" +#include "virtual.h" +#include "a_armor.h" +#include "a_ammo.h" +#include "a_health.h" // MACROS ------------------------------------------------------------------ @@ -130,19 +131,23 @@ CVAR (Int, cl_bloodtype, 0, CVAR_ARCHIVE); // CODE -------------------------------------------------------------------- -IMPLEMENT_POINTY_CLASS (AActor) - DECLARE_POINTER (target) - DECLARE_POINTER (lastenemy) - DECLARE_POINTER (tracer) - DECLARE_POINTER (goal) - DECLARE_POINTER (LastLookActor) - DECLARE_POINTER (Inventory) - DECLARE_POINTER (LastHeard) - DECLARE_POINTER (master) - DECLARE_POINTER (Poisoner) - DECLARE_POINTER (DamageFunc) - DECLARE_POINTER (alternative) -END_POINTERS +IMPLEMENT_CLASS(AActor, false, true) + +IMPLEMENT_POINTERS_START(AActor) + IMPLEMENT_POINTER(target) + IMPLEMENT_POINTER(lastenemy) + IMPLEMENT_POINTER(tracer) + IMPLEMENT_POINTER(goal) + IMPLEMENT_POINTER(LastLookActor) + IMPLEMENT_POINTER(Inventory) + IMPLEMENT_POINTER(LastHeard) + IMPLEMENT_POINTER(master) + IMPLEMENT_POINTER(Poisoner) + IMPLEMENT_POINTER(DamageFunc) + IMPLEMENT_POINTER(alternative) + IMPLEMENT_POINTER(TeleFogSourceType) + IMPLEMENT_POINTER(TeleFogDestType) +IMPLEMENT_POINTERS_END AActor::~AActor () { @@ -150,6 +155,186 @@ AActor::~AActor () // Use Destroy() instead. } +extern FFlagDef InternalActorFlagDefs[]; +extern FFlagDef ActorFlagDefs[]; + +DEFINE_FIELD(AActor, snext) +DEFINE_FIELD(AActor, player) +DEFINE_FIELD_NAMED(AActor, __Pos, pos) +DEFINE_FIELD_NAMED(AActor, __Pos.X, x) +DEFINE_FIELD_NAMED(AActor, __Pos.Y, y) +DEFINE_FIELD_NAMED(AActor, __Pos.Z, z) +DEFINE_FIELD(AActor, Prev) +DEFINE_FIELD(AActor, SpriteAngle) +DEFINE_FIELD(AActor, SpriteRotation) +DEFINE_FIELD(AActor, VisibleStartAngle) +DEFINE_FIELD(AActor, VisibleStartPitch) +DEFINE_FIELD(AActor, VisibleEndAngle) +DEFINE_FIELD(AActor, VisibleEndPitch) +DEFINE_FIELD_NAMED(AActor, Angles.Yaw, angle) +DEFINE_FIELD_NAMED(AActor, Angles.Pitch, pitch) +DEFINE_FIELD_NAMED(AActor, Angles.Roll, roll) +DEFINE_FIELD(AActor, Vel) +DEFINE_FIELD_NAMED(AActor, Vel.X, velx) +DEFINE_FIELD_NAMED(AActor, Vel.Y, vely) +DEFINE_FIELD_NAMED(AActor, Vel.Z, velz) +DEFINE_FIELD_NAMED(AActor, Vel.X, momx) +DEFINE_FIELD_NAMED(AActor, Vel.Y, momy) +DEFINE_FIELD_NAMED(AActor, Vel.Z, momz) +DEFINE_FIELD(AActor, Speed) +DEFINE_FIELD(AActor, FloatSpeed) +DEFINE_FIELD(AActor, sprite) +DEFINE_FIELD(AActor, frame) +DEFINE_FIELD(AActor, Scale) +DEFINE_FIELD_NAMED(AActor, Scale.X, scalex) +DEFINE_FIELD_NAMED(AActor, Scale.Y, scaley) +DEFINE_FIELD(AActor, RenderStyle) +DEFINE_FIELD(AActor, picnum) +DEFINE_FIELD(AActor, Alpha) +DEFINE_FIELD(AActor, fillcolor) +DEFINE_FIELD_NAMED(AActor, Sector, CurSector) // clashes with type 'sector'. +DEFINE_FIELD(AActor, subsector) +DEFINE_FIELD(AActor, ceilingz) +DEFINE_FIELD(AActor, floorz) +DEFINE_FIELD(AActor, dropoffz) +DEFINE_FIELD(AActor, floorsector) +DEFINE_FIELD(AActor, floorpic) +DEFINE_FIELD(AActor, floorterrain) +DEFINE_FIELD(AActor, ceilingsector) +DEFINE_FIELD(AActor, ceilingpic) +DEFINE_FIELD(AActor, Height) +DEFINE_FIELD(AActor, radius) +DEFINE_FIELD(AActor, projectilepassheight) +DEFINE_FIELD(AActor, tics) +DEFINE_FIELD_NAMED(AActor, state, curstate) // clashes with type 'state'. +DEFINE_FIELD_NAMED(AActor, DamageVal, Damage) // name differs for historic reasons +DEFINE_FIELD(AActor, projectileKickback) +DEFINE_FIELD(AActor, VisibleToTeam) +DEFINE_FIELD(AActor, special1) +DEFINE_FIELD(AActor, special2) +DEFINE_FIELD(AActor, specialf1) +DEFINE_FIELD(AActor, specialf2) +DEFINE_FIELD(AActor, weaponspecial) +DEFINE_FIELD(AActor, health) +DEFINE_FIELD(AActor, movedir) +DEFINE_FIELD(AActor, visdir) +DEFINE_FIELD(AActor, movecount) +DEFINE_FIELD(AActor, strafecount) +DEFINE_FIELD(AActor, target) +DEFINE_FIELD(AActor, master) +DEFINE_FIELD(AActor, tracer) +DEFINE_FIELD(AActor, LastHeard) +DEFINE_FIELD(AActor, lastenemy) +DEFINE_FIELD(AActor, LastLookActor) +DEFINE_FIELD(AActor, reactiontime) +DEFINE_FIELD(AActor, threshold) +DEFINE_FIELD(AActor, DefThreshold) +DEFINE_FIELD(AActor, SpawnPoint) +DEFINE_FIELD(AActor, SpawnAngle) +DEFINE_FIELD(AActor, StartHealth) +DEFINE_FIELD(AActor, WeaveIndexXY) +DEFINE_FIELD(AActor, WeaveIndexZ) +DEFINE_FIELD(AActor, skillrespawncount) +DEFINE_FIELD(AActor, args) +DEFINE_FIELD(AActor, Mass) +DEFINE_FIELD(AActor, special) +DEFINE_FIELD(AActor, tid) +DEFINE_FIELD(AActor, TIDtoHate) +DEFINE_FIELD(AActor, waterlevel) +DEFINE_FIELD(AActor, Score) +DEFINE_FIELD(AActor, accuracy) +DEFINE_FIELD(AActor, stamina) +DEFINE_FIELD(AActor, meleerange) +DEFINE_FIELD(AActor, PainThreshold) +DEFINE_FIELD(AActor, Gravity) +DEFINE_FIELD(AActor, Floorclip) +DEFINE_FIELD(AActor, DamageType) +DEFINE_FIELD(AActor, DamageTypeReceived) +DEFINE_FIELD(AActor, FloatBobPhase) +DEFINE_FIELD(AActor, RipperLevel) +DEFINE_FIELD(AActor, RipLevelMin) +DEFINE_FIELD(AActor, RipLevelMax) +DEFINE_FIELD(AActor, Species) +DEFINE_FIELD(AActor, alternative) +DEFINE_FIELD(AActor, goal) +DEFINE_FIELD(AActor, MinMissileChance) +DEFINE_FIELD(AActor, LastLookPlayerNumber) +DEFINE_FIELD(AActor, SpawnFlags) +DEFINE_FIELD(AActor, meleethreshold) +DEFINE_FIELD(AActor, maxtargetrange) +DEFINE_FIELD(AActor, bouncefactor) +DEFINE_FIELD(AActor, wallbouncefactor) +DEFINE_FIELD(AActor, bouncecount) +DEFINE_FIELD(AActor, Friction) +DEFINE_FIELD(AActor, FastChaseStrafeCount) +DEFINE_FIELD(AActor, pushfactor) +DEFINE_FIELD(AActor, lastpush) +DEFINE_FIELD(AActor, activationtype) +DEFINE_FIELD(AActor, lastbump) +DEFINE_FIELD(AActor, DesignatedTeam) +DEFINE_FIELD(AActor, BlockingMobj) +DEFINE_FIELD(AActor, BlockingLine) +DEFINE_FIELD(AActor, PoisonDamage) +DEFINE_FIELD(AActor, PoisonDamageType) +DEFINE_FIELD(AActor, PoisonDuration) +DEFINE_FIELD(AActor, PoisonPeriod) +DEFINE_FIELD(AActor, PoisonDamageReceived) +DEFINE_FIELD(AActor, PoisonDamageTypeReceived) +DEFINE_FIELD(AActor, PoisonDurationReceived) +DEFINE_FIELD(AActor, PoisonPeriodReceived) +DEFINE_FIELD(AActor, Poisoner) +DEFINE_FIELD_NAMED(AActor, Inventory, Inv) // clashes with type 'Inventory'. +DEFINE_FIELD(AActor, smokecounter) +DEFINE_FIELD(AActor, FriendPlayer) +DEFINE_FIELD(AActor, Translation) +DEFINE_FIELD(AActor, AttackSound) +DEFINE_FIELD(AActor, DeathSound) +DEFINE_FIELD(AActor, SeeSound) +DEFINE_FIELD(AActor, PainSound) +DEFINE_FIELD(AActor, ActiveSound) +DEFINE_FIELD(AActor, UseSound) +DEFINE_FIELD(AActor, BounceSound) +DEFINE_FIELD(AActor, WallBounceSound) +DEFINE_FIELD(AActor, CrushPainSound) +DEFINE_FIELD(AActor, MaxDropOffHeight) +DEFINE_FIELD(AActor, MaxStepHeight) +DEFINE_FIELD(AActor, PainChance) +DEFINE_FIELD(AActor, PainType) +DEFINE_FIELD(AActor, DeathType) +DEFINE_FIELD(AActor, DamageFactor) +DEFINE_FIELD(AActor, DamageMultiply) +DEFINE_FIELD(AActor, TeleFogSourceType) +DEFINE_FIELD(AActor, TeleFogDestType) +DEFINE_FIELD(AActor, SpawnState) +DEFINE_FIELD(AActor, SeeState) +DEFINE_FIELD(AActor, MeleeState) +DEFINE_FIELD(AActor, MissileState) +DEFINE_FIELD(AActor, ConversationRoot) +DEFINE_FIELD(AActor, Conversation) +DEFINE_FIELD(AActor, DecalGenerator) + +DEFINE_FIELD(PClassActor, Obituary) +DEFINE_FIELD(PClassActor, HitObituary) +DEFINE_FIELD(PClassActor, DeathHeight) +DEFINE_FIELD(PClassActor, BurnHeight) +DEFINE_FIELD(PClassActor, BloodColor) +DEFINE_FIELD(PClassActor, GibHealth) +DEFINE_FIELD(PClassActor, WoundHealth) +DEFINE_FIELD(PClassActor, FastSpeed) +DEFINE_FIELD(PClassActor, RDFactor) +DEFINE_FIELD(PClassActor, CameraHeight) +DEFINE_FIELD(PClassActor, HowlSound) +DEFINE_FIELD(PClassActor, BloodType) +DEFINE_FIELD(PClassActor, BloodType2) +DEFINE_FIELD(PClassActor, BloodType3) +DEFINE_FIELD(PClassActor, DontHurtShooter) +DEFINE_FIELD(PClassActor, ExplosionRadius) +DEFINE_FIELD(PClassActor, ExplosionDamage) +DEFINE_FIELD(PClassActor, MeleeDamage) +DEFINE_FIELD(PClassActor, MeleeSound) +DEFINE_FIELD(PClassActor, MissileName) +DEFINE_FIELD(PClassActor, MissileHeight) + //========================================================================== // // AActor :: Serialize @@ -388,6 +573,13 @@ bool AActor::InStateSequence(FState * newstate, FState * basestate) return false; } +DEFINE_ACTION_FUNCTION(AActor, InStateSequence) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_POINTER(newstate, FState); + PARAM_POINTER(basestate, FState); + ACTION_RETURN_BOOL(self->InStateSequence(newstate, basestate)); +} //========================================================================== // // AActor::GetTics @@ -401,11 +593,11 @@ bool AActor::InStateSequence(FState * newstate, FState * basestate) int AActor::GetTics(FState * newstate) { int tics = newstate->GetTics(); - if (isFast() && newstate->Fast) + if (isFast() && newstate->GetFast()) { return tics - (tics>>1); } - else if (isSlow() && newstate->Slow) + else if (isSlow() && newstate->GetSlow()) { return tics<<1; } @@ -442,6 +634,14 @@ bool AActor::SetState (FState *newstate, bool nofunction) { prevsprite = -1; } + if (!(newstate->UseFlags & SUF_ACTOR)) + { + auto so = FState::StaticFindStateOwner(newstate); + Printf(TEXTCOLOR_RED "State %s.%d in %s not flagged for use as an actor sprite\n", so->TypeName.GetChars(), int(newstate - so->OwnedStates), GetClass()->TypeName.GetChars()); + state = nullptr; + Destroy(); + return false; + } state = newstate; tics = GetTics(newstate); renderflags = (renderflags & ~RF_FULLBRIGHT) | ActorRenderFlags::FromInt (newstate->GetFullbright()); @@ -509,6 +709,14 @@ bool AActor::SetState (FState *newstate, bool nofunction) return true; } +DEFINE_ACTION_FUNCTION(AActor, SetState) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_POINTER(state, FState); + PARAM_BOOL_DEF(nofunction); + ACTION_RETURN_BOOL(self->SetState(state, nofunction)); +}; + //============================================================================ // // AActor :: AddInventory @@ -540,6 +748,15 @@ void AActor::AddInventory (AInventory *item) Inventory->InventoryID = InventoryID++; } +DEFINE_ACTION_FUNCTION(AActor, AddInventory) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(item, AInventory); + self->AddInventory(item); + return 0; +} + + //============================================================================ // // AActor :: GiveInventory @@ -599,6 +816,14 @@ bool AActor::GiveInventory(PClassInventory *type, int amount, bool givecheat) return result; } +DEFINE_ACTION_FUNCTION(AActor, Inventory) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(item, AInventory); + ACTION_RETURN_BOOL(self->UseInventory(item)); +} + + //============================================================================ // // AActor :: RemoveInventory @@ -626,6 +851,15 @@ void AActor::RemoveInventory(AInventory *item) } } +DEFINE_ACTION_FUNCTION(AActor, RemoveInventory) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(item, AInventory); + self->RemoveInventory(item); + return 0; +} + + //============================================================================ // // AActor :: TakeInventory @@ -757,7 +991,7 @@ bool AActor::UseInventory (AInventory *item) { return false; } - if (!item->Use (false)) + if (!item->CallUse (false)) { return false; } @@ -772,6 +1006,13 @@ bool AActor::UseInventory (AInventory *item) return true; } +DEFINE_ACTION_FUNCTION(AActor, UseInventory) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(item, AInventory); + ACTION_RETURN_BOOL(self->UseInventory(item)); +} + //=========================================================================== // // AActor :: DropInventory @@ -782,7 +1023,7 @@ bool AActor::UseInventory (AInventory *item) AInventory *AActor::DropInventory (AInventory *item) { - AInventory *drop = item->CreateTossable (); + AInventory *drop = item->CallCreateTossable (); if (drop == NULL) { @@ -798,6 +1039,13 @@ AInventory *AActor::DropInventory (AInventory *item) return drop; } +DEFINE_ACTION_FUNCTION(AActor, DropInventory) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(item, AInventory); + ACTION_RETURN_OBJECT(self->DropInventory(item)); +} + //============================================================================ // // AActor :: FindInventory @@ -837,6 +1085,14 @@ AInventory *AActor::FindInventory (FName type) return FindInventory(PClass::FindActor(type)); } +DEFINE_ACTION_FUNCTION(AActor, FindInventory) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_CLASS(type, AInventory); + PARAM_BOOL_DEF(subclass); + ACTION_RETURN_OBJECT(self->FindInventory(type, subclass)); +} + //============================================================================ // // AActor :: GiveInventoryType @@ -859,6 +1115,13 @@ AInventory *AActor::GiveInventoryType (PClassActor *type) return item; } +DEFINE_ACTION_FUNCTION(AActor, GiveInventoryType) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_CLASS(type, AInventory); + ACTION_RETURN_OBJECT(self->GiveInventoryType(type)); +} + //============================================================================ // // AActor :: GiveAmmo @@ -887,6 +1150,14 @@ bool AActor::GiveAmmo (PClassAmmo *type, int amount) return false; } +DEFINE_ACTION_FUNCTION(AActor, GiveAmmo) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_CLASS(type, AAmmo); + PARAM_INT(amount); + ACTION_RETURN_BOOL(self->GiveAmmo(type, amount)); +} + //============================================================================ // // AActor :: ClearInventory @@ -953,6 +1224,14 @@ void AActor::ClearInventory() } } +DEFINE_ACTION_FUNCTION(AActor, ClearInventory) +{ + PARAM_SELF_PROLOGUE(AActor); + self->ClearInventory(); + return 0; +} + + //============================================================================ // // AActor :: CopyFriendliness @@ -981,6 +1260,15 @@ void AActor::CopyFriendliness (AActor *other, bool changeTarget, bool resetHealt level.total_monsters += CountsAsKill(); } +DEFINE_ACTION_FUNCTION(AActor, CopyFriendliness) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(other, AActor); + PARAM_BOOL_DEF(changetarget); + PARAM_BOOL_DEF(resethealth); + self->CopyFriendliness(other, changetarget, resethealth); + return 0; +} //============================================================================ // // AActor :: ObtainInventory @@ -1045,6 +1333,13 @@ bool AActor::CheckLocalView (int playernum) const return false; } +DEFINE_ACTION_FUNCTION(AActor, CheckLocalView) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(cp); + ACTION_RETURN_BOOL(self->CheckLocalView(cp)); +} + //============================================================================ // // AActor :: IsInsideVisibleAngles @@ -1188,6 +1483,24 @@ void AActor::Touch (AActor *toucher) { } +DEFINE_ACTION_FUNCTION(AActor, Touch) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(toucher, AActor); + self->Touch(toucher); + return 0; +} + +void AActor::CallTouch(AActor *toucher) +{ + IFVIRTUAL(AActor, Touch) + { + VMValue params[2] = { (DObject*)this, toucher }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } + else Touch(toucher); +} + //============================================================================ // // AActor :: Grind @@ -1499,6 +1812,15 @@ void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target) } } +DEFINE_ACTION_FUNCTION(AActor, ExplodeMissile) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_POINTER_DEF(line, line_t); + PARAM_OBJECT_DEF(target, AActor); + P_ExplodeMissile(self, line, target); + return 0; +} + void AActor::PlayBounceSound(bool onfloor) { @@ -1541,7 +1863,7 @@ bool AActor::FloorBounceMissile (secplane_t &plane) if (flags & MF_MISSILE) P_ExplodeMissile(this, NULL, NULL); else - Die(NULL, NULL); + CallDie(NULL, NULL); return true; } if (!(BounceFlags & BOUNCE_CanBounceWater)) @@ -1568,7 +1890,7 @@ bool AActor::FloorBounceMissile (secplane_t &plane) if (flags & MF_MISSILE) P_ExplodeMissile(this, NULL, NULL); else - Die(NULL, NULL); + CallDie(NULL, NULL); return true; } @@ -1675,6 +1997,13 @@ bool AActor::CanSeek(AActor *target) const return true; } +DEFINE_ACTION_FUNCTION(AActor, CanSeek) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(target, AActor); + ACTION_RETURN_BOOL(self->CanSeek(target)); +} + //---------------------------------------------------------------------------- // // FUNC P_SeekerMissile @@ -2541,7 +2870,10 @@ void P_ZMovement (AActor *mo, double oldfloorz) return; } // Let the actor do something special for hitting the floor - mo->HitFloor (); + if (mo->flags7 & MF7_SMASHABLE) + { + P_DamageMobj(mo, nullptr, nullptr, mo->health, NAME_Smash); + } if (mo->player) { if (mo->player->jumpTics < 0 || mo->Vel.Z < minvel) @@ -2882,6 +3214,25 @@ void AActor::RemoveFromHash () tid = 0; } +DEFINE_ACTION_FUNCTION(AActor, RemoveFromHash) +{ + PARAM_SELF_PROLOGUE(AActor); + self->RemoveFromHash(); + return 0; +} + +DEFINE_ACTION_FUNCTION(AActor, ChangeTid) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(tid); + self->RemoveFromHash(); + self->tid = tid; + self->AddToHash(); + return 0; +} + + + //========================================================================== // // P_IsTIDUsed @@ -2964,6 +3315,17 @@ int P_FindUniqueTID(int start_tid, int limit) return 0; } +DEFINE_ACTION_FUNCTION(AActor, FindUniqueTid) +{ + PARAM_PROLOGUE; + PARAM_INT_DEF(start); + PARAM_INT_DEF(limit); + ACTION_RETURN_INT(P_FindUniqueTID(start, limit)); +} + + + + CCMD(utid) { Printf("%d\n", @@ -2999,16 +3361,14 @@ int AActor::GetMissileDamage (int mask, int add) assert(false && "No damage function found"); return 0; } - VMFrameStack stack; VMValue param = this; - VMReturn results[2]; + VMReturn result; - int amount, calculated = false; + int amount; - results[0].IntAt(&amount); - results[1].IntAt(&calculated); + result.IntAt(&amount); - if (stack.Call(DamageFunc, ¶m, 1, results, 2) < 1) + if (GlobalVMStack.Call(DamageFunc, ¶m, 1, &result, 1) < 1) { // No results return 0; } @@ -3024,8 +3384,11 @@ void AActor::Howl () } } -void AActor::HitFloor () +DEFINE_ACTION_FUNCTION(AActor, Howl) { + PARAM_SELF_PROLOGUE(AActor); + self->Howl(); + return 0; } bool AActor::Slam (AActor *thing) @@ -3055,14 +3418,43 @@ bool AActor::Slam (AActor *thing) return false; // stop moving } -bool AActor::SpecialBlastHandling (AActor *source, double strength) +DEFINE_ACTION_FUNCTION(AActor, Slam) { - return true; + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(thing, AActor); + ACTION_RETURN_BOOL(self->Slam(thing)); } +bool AActor::CallSlam(AActor *thing) +{ + IFVIRTUAL(AActor, Slam) + { + VMValue params[2] = { (DObject*)this, thing }; + VMReturn ret; + int retval; + ret.IntAt(&retval); + GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); + return !!retval; + + } + else return Slam(thing); +} + + + +// This virtual method only exists on the script side. int AActor::SpecialMissileHit (AActor *victim) { - return -1; + IFVIRTUAL(AActor, SpecialMissileHit) + { + VMValue params[2] = { (DObject*)this, victim }; + VMReturn ret; + int retval; + ret.IntAt(&retval); + GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); + return retval; + } + else return -1; } bool AActor::AdjustReflectionAngle (AActor *thing, DAngle &angle) @@ -3076,8 +3468,7 @@ bool AActor::AdjustReflectionAngle (AActor *thing, DAngle &angle) if (absangle(angle, thing->Angles.Yaw) > 45) return true; // Let missile explode - if (thing->IsKindOf (RUNTIME_CLASS(AHolySpirit))) // shouldn't this be handled by another flag??? - return true; + if (thing->flags7 & MF7_NOSHIELDREFLECT) return true; if (pr_reflect () < 128) angle += 45; @@ -3122,6 +3513,13 @@ void AActor::PlayActiveSound () } } +DEFINE_ACTION_FUNCTION(AActor, PlayActiveSound) +{ + PARAM_SELF_PROLOGUE(AActor); + self->PlayActiveSound(); + return 0; +} + bool AActor::IsOkayToAttack (AActor *link) { if (!(player // Original AActor::IsOkayToAttack was only for players @@ -3189,6 +3587,14 @@ void AActor::SetShade (int r, int g, int b) fillcolor = MAKEARGB(ColorMatcher.Pick (r, g, b), r, g, b); } +DEFINE_ACTION_FUNCTION(AActor, SetShade) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(color); + self->SetShade(color); + return 0; +} + void AActor::SetPitch(DAngle p, bool interpolate, bool forceclamp) { if (player != NULL || forceclamp) @@ -3880,6 +4286,14 @@ void AActor::Tick () } } +DEFINE_ACTION_FUNCTION(AActor, Tick) +{ + PARAM_SELF_PROLOGUE(AActor); + self->Tick(); + return 0; +} + + //========================================================================== // // AActor :: CheckNoDelay @@ -4224,7 +4638,7 @@ AActor *AActor::StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t a actor->UpdateWaterLevel (false); if (!SpawningMapThing) { - actor->BeginPlay (); + actor->CallBeginPlay (); if (actor->ObjectFlags & OF_EuthanizeMe) { return NULL; @@ -4252,6 +4666,17 @@ AActor *AActor::StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t a return actor; } +DEFINE_ACTION_FUNCTION(AActor, Spawn) +{ + PARAM_PROLOGUE; + PARAM_CLASS_NOT_NULL(type, AActor); + PARAM_FLOAT_DEF(x); + PARAM_FLOAT_DEF(y); + PARAM_FLOAT_DEF(z); + PARAM_INT_DEF(flags); + ACTION_RETURN_OBJECT(AActor::StaticSpawn(type, DVector3(x, y, z), replace_t(flags))); +} + PClassActor *ClassForSpawn(FName classname) { PClass *cls = PClass::FindClass(classname); @@ -4289,7 +4714,7 @@ void AActor::HandleSpawnFlags () } if (SpawnFlags & MTF_DORMANT) { - Deactivate (NULL); + CallDeactivate (NULL); } if (SpawnFlags & MTF_STANDSTILL) { @@ -4333,10 +4758,29 @@ void AActor::BeginPlay () if (flags2 & MF2_DORMANT) { flags2 &= ~MF2_DORMANT; - Deactivate (NULL); + CallDeactivate (NULL); } } +DEFINE_ACTION_FUNCTION(AActor, BeginPlay) +{ + PARAM_SELF_PROLOGUE(AActor); + self->BeginPlay(); + return 0; +} + +void AActor::CallBeginPlay() +{ + IFVIRTUAL(AActor, BeginPlay) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DObject*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } + else BeginPlay(); +} + + void AActor::PostBeginPlay () { if (Renderer != NULL) @@ -4372,6 +4816,12 @@ bool AActor::isSlow() return !!G_SkillProperty(SKILLP_SlowMonsters); } +//=========================================================================== +// +// Activate +// +//=========================================================================== + void AActor::Activate (AActor *activator) { if ((flags3 & MF3_ISMONSTER) && (health > 0 || (flags & MF_ICECORPSE))) @@ -4392,6 +4842,32 @@ void AActor::Activate (AActor *activator) } } +DEFINE_ACTION_FUNCTION(AActor, Activate) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(activator, AActor); + self->Activate(activator); + return 0; +} + +void AActor::CallActivate(AActor *activator) +{ + IFVIRTUAL(AActor, Activate) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[2] = { (DObject*)this, (DObject*)activator }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } + else Activate(activator); +} + + +//=========================================================================== +// +// Deactivate +// +//=========================================================================== + void AActor::Deactivate (AActor *activator) { if ((flags3 & MF3_ISMONSTER) && (health > 0 || (flags & MF_ICECORPSE))) @@ -4412,10 +4888,30 @@ void AActor::Deactivate (AActor *activator) } } +DEFINE_ACTION_FUNCTION(AActor, Deactivate) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(activator, AActor); + self->Deactivate(activator); + return 0; +} +void AActor::CallDeactivate(AActor *activator) +{ + IFVIRTUAL(AActor, Deactivate) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[2] = { (DObject*)this, (DObject*)activator }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } + else Deactivate(activator); +} + +//=========================================================================== // -// P_RemoveMobj +// Destroy // +//=========================================================================== void AActor::Destroy () { @@ -4492,6 +4988,13 @@ void AActor::AdjustFloorClip () } } +DEFINE_ACTION_FUNCTION(AActor, AdjustFloorClip) +{ + PARAM_SELF_PROLOGUE(AActor); + self->AdjustFloorClip(); + return 0; +} + // // P_SpawnPlayer // Called when a player is spawned on the level. @@ -5119,7 +5622,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) if (mthing->fillcolor) mobj->fillcolor = mthing->fillcolor; - mobj->BeginPlay (); + mobj->CallBeginPlay (); if (!(mobj->ObjectFlags & OF_EuthanizeMe)) { mobj->LevelSpawned (); @@ -5130,7 +5633,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) else mobj->health = -mthing->health; if (mthing->health == 0) - mobj->Die(NULL, NULL); + mobj->CallDie(NULL, NULL); else if (mthing->health != 1) mobj->StartHealth = mobj->health; @@ -5153,6 +5656,8 @@ AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, const DVector3 &pos1 AActor *puff; DVector3 pos = pos1; + if (pufftype == nullptr) return nullptr; + if (!(flags & PF_NORANDOMZ)) pos.Z += pr_spawnpuff.Random2() / 64.; puff = Spawn(pufftype, pos, ALLOW_REPLACE); if (puff == NULL) return NULL; @@ -5218,7 +5723,20 @@ AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, const DVector3 &pos1 return puff; } - +DEFINE_ACTION_FUNCTION(AActor, SpawnPuff) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_CLASS(pufftype, AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_ANGLE(hitdir); + PARAM_ANGLE(particledir); + PARAM_INT(updown); + PARAM_INT_DEF(flags); + PARAM_OBJECT_DEF(victim, AActor); + ACTION_RETURN_OBJECT(P_SpawnPuff(self, pufftype, DVector3(x, y, z), hitdir, particledir, updown, flags, victim)); +} //--------------------------------------------------------------------------- // @@ -5316,6 +5834,19 @@ void P_SpawnBlood (const DVector3 &pos1, DAngle dir, int damage, AActor *origina P_DrawSplash2 (40, pos, dir, 2, bloodcolor); } +DEFINE_ACTION_FUNCTION(AActor, SpawnBlood) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_ANGLE(dir); + PARAM_INT(damage); + P_SpawnBlood(DVector3(x, y, z), dir, damage, self); + return 0; +} + + //--------------------------------------------------------------------------- // // PROC P_BloodSplatter @@ -5398,6 +5929,20 @@ void P_BloodSplatter2 (const DVector3 &pos, AActor *originator, DAngle hitangle) } } +DEFINE_ACTION_FUNCTION(AActor, BloodSplatter) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_ANGLE(dir); + PARAM_BOOL_DEF(axe); + if (axe) P_BloodSplatter2(DVector3(x, y, z), self, dir); + else P_BloodSplatter(DVector3(x, y, z), self, dir); + return 0; +} + + //--------------------------------------------------------------------------- // // PROC P_RipperBlood @@ -5463,6 +6008,13 @@ int P_GetThingFloorType (AActor *thing) } } +DEFINE_ACTION_FUNCTION(AActor, GetFloorTerrain) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_POINTER(&Terrains[P_GetThingFloorType(self)]); +} + + //--------------------------------------------------------------------------- // // FUNC P_HitWater @@ -5610,6 +6162,20 @@ foundone: return plane == &sec->floorplane ? Terrains[terrainnum].IsLiquid : false; } +DEFINE_ACTION_FUNCTION(AActor, HitWater) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_POINTER_NOT_NULL(sec, sector_t); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_BOOL_DEF(checkabove); + PARAM_BOOL_DEF(alert); + PARAM_BOOL_DEF(force); + ACTION_RETURN_BOOL(P_HitWater(self, sec, DVector3(x, y, z), checkabove, alert, force)); +} + + //--------------------------------------------------------------------------- // // FUNC P_HitFloor @@ -5665,6 +6231,12 @@ bool P_HitFloor (AActor *thing) return P_HitWater (thing, m->m_sector, pos); } +DEFINE_ACTION_FUNCTION(AActor, HitFloor) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_BOOL(P_HitFloor(self)); +} + //--------------------------------------------------------------------------- // // P_CheckSplash @@ -5771,6 +6343,13 @@ bool P_CheckMissileSpawn (AActor* th, double maxdist) return true; } +DEFINE_ACTION_FUNCTION(AActor, CheckMissileSpawn) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(add); + ACTION_RETURN_BOOL(P_CheckMissileSpawn(self, add)); +} + //--------------------------------------------------------------------------- // @@ -5803,6 +6382,15 @@ void P_PlaySpawnSound(AActor *missile, AActor *spawner) } } +DEFINE_ACTION_FUNCTION(AActor, PlaySpawnSound) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(missile, AActor); + P_PlaySpawnSound(missile, self); + return 0; +} + + static double GetDefaultSpeed(PClassActor *type) { if (type == NULL) @@ -5813,6 +6401,13 @@ static double GetDefaultSpeed(PClassActor *type) return GetDefaultByType(type)->Speed; } +DEFINE_ACTION_FUNCTION(AActor, GetDefaultSpeed) +{ + PARAM_PROLOGUE; + PARAM_CLASS(type, AActor); + ACTION_RETURN_FLOAT(GetDefaultSpeed(type)); +} + //--------------------------------------------------------------------------- // // FUNC P_SpawnMissile @@ -5822,29 +6417,11 @@ static double GetDefaultSpeed(PClassActor *type) // //--------------------------------------------------------------------------- -AActor *P_SpawnMissile (AActor *source, AActor *dest, PClassActor *type, AActor *owner) -{ - if (source == NULL) - { - return NULL; - } - return P_SpawnMissileXYZ (source->PosPlusZ(32 + source->GetBobOffset()), source, dest, type, true, owner); -} - -AActor *P_SpawnMissileZ (AActor *source, double z, AActor *dest, PClassActor *type) -{ - if (source == NULL) - { - return NULL; - } - return P_SpawnMissileXYZ (source->PosAtZ(z), source, dest, type); -} - AActor *P_SpawnMissileXYZ (DVector3 pos, AActor *source, AActor *dest, PClassActor *type, bool checkspawn, AActor *owner) { - if (source == NULL) + if (source == nullptr || type == nullptr) { - return NULL; + return nullptr; } if (dest == NULL) @@ -5913,11 +6490,62 @@ AActor *P_SpawnMissileXYZ (DVector3 pos, AActor *source, AActor *dest, PClassAct return (!checkspawn || P_CheckMissileSpawn (th, source->radius)) ? th : NULL; } +DEFINE_ACTION_FUNCTION(AActor, SpawnMissileXYZ) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_OBJECT_NOT_NULL(dest, AActor); + PARAM_CLASS(type, AActor); + PARAM_BOOL_DEF(check); + PARAM_OBJECT_DEF(owner, AActor); + ACTION_RETURN_OBJECT(P_SpawnMissileXYZ(DVector3(x,y,z), self, dest, type, check, owner)); +} + +AActor *P_SpawnMissile(AActor *source, AActor *dest, PClassActor *type, AActor *owner) +{ + if (source == nullptr) + { + return nullptr; + } + return P_SpawnMissileXYZ(source->PosPlusZ(32 + source->GetBobOffset()), source, dest, type, true, owner); +} + +DEFINE_ACTION_FUNCTION(AActor, SpawnMissile) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(dest, AActor); + PARAM_CLASS(type, AActor); + PARAM_OBJECT_DEF(owner, AActor); + ACTION_RETURN_OBJECT(P_SpawnMissile(self, dest, type, owner)); +} + +AActor *P_SpawnMissileZ(AActor *source, double z, AActor *dest, PClassActor *type) +{ + if (source == nullptr) + { + return nullptr; + } + return P_SpawnMissileXYZ(source->PosAtZ(z), source, dest, type); +} + +DEFINE_ACTION_FUNCTION(AActor, SpawnMissileZ) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(z); + PARAM_OBJECT_NOT_NULL(dest, AActor); + PARAM_CLASS(type, AActor); + ACTION_RETURN_OBJECT(P_SpawnMissileZ(self, z, dest, type)); +} + + + AActor *P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassActor *type) { - if (source == NULL) + if (source == nullptr || type == nullptr) { - return NULL; + return nullptr; } AActor *th = Spawn (type, source->PosPlusZ(32.), ALLOW_REPLACE); @@ -5940,6 +6568,16 @@ AActor *P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassAct return th; } +DEFINE_ACTION_FUNCTION(AActor, OldSpawnMissile) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(dest, AActor); + PARAM_CLASS(type, AActor); + PARAM_OBJECT_DEF(owner, AActor); + ACTION_RETURN_OBJECT(P_OldSpawnMissile(self, owner, dest, type)); +} + + //--------------------------------------------------------------------------- // // FUNC P_SpawnMissileAngle @@ -5951,7 +6589,7 @@ AActor *P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassAct AActor *P_SpawnMissileAngle (AActor *source, PClassActor *type, DAngle angle, double vz) { - if (source == NULL) + if (source == nullptr || type == nullptr) { return NULL; } @@ -5960,14 +6598,18 @@ AActor *P_SpawnMissileAngle (AActor *source, PClassActor *type, DAngle angle, do AActor *P_SpawnMissileAngleZ (AActor *source, double z, PClassActor *type, DAngle angle, double vz) { + if (type == nullptr) + { + return nullptr; + } return P_SpawnMissileAngleZSpeed (source, z, type, angle, vz, GetDefaultSpeed (type)); } AActor *P_SpawnMissileZAimed (AActor *source, double z, AActor *dest, PClassActor *type) { - if (source == NULL) + if (source == nullptr || type == nullptr) { - return NULL; + return nullptr; } DAngle an; double dist; @@ -5987,6 +6629,15 @@ AActor *P_SpawnMissileZAimed (AActor *source, double z, AActor *dest, PClassActo return P_SpawnMissileAngleZSpeed (source, z, type, an, vz, speed); } +DEFINE_ACTION_FUNCTION(AActor, SpawnMissileZAimed) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(z); + PARAM_OBJECT_NOT_NULL(dest, AActor); + PARAM_CLASS(type, AActor); + ACTION_RETURN_OBJECT(P_SpawnMissileZAimed(self, z, dest, type)); +} + //--------------------------------------------------------------------------- // // FUNC P_SpawnMissileAngleZSpeed @@ -5999,9 +6650,9 @@ AActor *P_SpawnMissileZAimed (AActor *source, double z, AActor *dest, PClassActo AActor *P_SpawnMissileAngleZSpeed (AActor *source, double z, PClassActor *type, DAngle angle, double vz, double speed, AActor *owner, bool checkspawn) { - if (source == NULL) + if (source == nullptr || type == nullptr) { - return NULL; + return nullptr; } AActor *mo; @@ -6027,6 +6678,61 @@ AActor *P_SpawnMissileAngleZSpeed (AActor *source, double z, return (!checkspawn || P_CheckMissileSpawn(mo, source->radius)) ? mo : NULL; } +DEFINE_ACTION_FUNCTION(AActor, SpawnMissileAngleZSpeed) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(z); + PARAM_CLASS(type, AActor); + PARAM_ANGLE(angle); + PARAM_FLOAT(vz); + PARAM_FLOAT(speed); + PARAM_OBJECT_DEF(owner, AActor); + PARAM_BOOL_DEF(checkspawn); + ACTION_RETURN_OBJECT(P_SpawnMissileAngleZSpeed(self, z, type, angle, vz, speed, owner, checkspawn)); +} + + +AActor *P_SpawnSubMissile(AActor *source, PClassActor *type, AActor *target) +{ + AActor *other = Spawn(type, source->Pos(), ALLOW_REPLACE); + + if (source == nullptr || type == nullptr) + { + return nullptr; + } + + other->target = target; + other->Angles.Yaw = source->Angles.Yaw; + other->VelFromAngle(); + + if (other->flags4 & MF4_SPECTRAL) + { + if (source->flags & MF_MISSILE && source->flags4 & MF4_SPECTRAL) + { + other->FriendPlayer = source->FriendPlayer; + } + else + { + other->SetFriendPlayer(target->player); + } + } + + if (P_CheckMissileSpawn(other, source->radius)) + { + DAngle pitch = P_AimLineAttack(source, source->Angles.Yaw, 1024.); + other->Vel.Z = -other->Speed * pitch.Sin(); + return other; + } + return NULL; +} + +DEFINE_ACTION_FUNCTION(AActor, SpawnSubMissile) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_CLASS(cls, AActor); + PARAM_OBJECT_NOT_NULL(target, AActor); + ACTION_RETURN_OBJECT(P_SpawnSubMissile(self, cls, target)); +} /* ================ = @@ -6054,6 +6760,11 @@ AActor *P_SpawnPlayerMissile (AActor *source, double x, double y, double z, PClassActor *type, DAngle angle, FTranslatedLineTarget *pLineTarget, AActor **pMissileActor, bool nofreeaim, bool noautoaim, int aimflags) { + if (source == nullptr || type == nullptr) + { + return nullptr; + } + static const double angdiff[3] = { -5.625, 5.625, 0 }; DAngle an = angle; DAngle pitch; @@ -6061,10 +6772,6 @@ AActor *P_SpawnPlayerMissile (AActor *source, double x, double y, double z, AActor *defaultobject = GetDefaultByType(type); DAngle vrange = nofreeaim ? 35. : 0.; - if (source == NULL) - { - return NULL; - } if (!pLineTarget) pLineTarget = &scratch; if (source->player && source->player->ReadyWeapon && ((source->player->ReadyWeapon->WeaponFlags & WIF_NOAUTOAIM) || noautoaim)) { @@ -6149,6 +6856,27 @@ AActor *P_SpawnPlayerMissile (AActor *source, double x, double y, double z, return NULL; } +DEFINE_ACTION_FUNCTION(AActor, SpawnPlayerMissile) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_CLASS(type, AActor); + PARAM_ANGLE_DEF(angle); + PARAM_FLOAT_DEF(x); + PARAM_FLOAT_DEF(y); + PARAM_FLOAT_DEF(z); + PARAM_POINTER_DEF(lt, FTranslatedLineTarget); + PARAM_BOOL_DEF(nofreeaim); + PARAM_BOOL_DEF(noautoaim); + PARAM_INT_DEF(aimflags); + AActor *missileactor; + if (numparam == 2) angle = self->Angles.Yaw; + AActor *misl = P_SpawnPlayerMissile(self, x, y, z, type, angle, lt, &missileactor, nofreeaim, noautoaim, aimflags); + if (numret > 0) ret[0].SetPointer(misl, ATAG_OBJECT); + if (numret > 1) ret[1].SetPointer(missileactor, ATAG_OBJECT), numret = 2; + return numret; +} + + int AActor::GetTeam() { if (player) @@ -6187,6 +6915,13 @@ bool AActor::IsTeammate (AActor *other) return false; } +DEFINE_ACTION_FUNCTION(AActor, isTeammate) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(other, AActor); + ACTION_RETURN_BOOL(self->IsTeammate(other)); +} + //========================================================================== // // AActor :: GetSpecies @@ -6220,6 +6955,12 @@ FName AActor::GetSpecies() return Species = thistype->TypeName; // [GZ] Speeds up future calls. } +DEFINE_ACTION_FUNCTION(AActor, GetSpecies) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_INT(self->GetSpecies()); +} + //========================================================================== // // AActor :: IsFriend @@ -6246,6 +6987,13 @@ bool AActor::IsFriend (AActor *other) return false; } +DEFINE_ACTION_FUNCTION(AActor, isFriend) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(other, AActor); + ACTION_RETURN_BOOL(self->IsFriend(other)); +} + //========================================================================== // // AActor :: IsHostile @@ -6276,6 +7024,22 @@ bool AActor::IsHostile (AActor *other) return true; } +DEFINE_ACTION_FUNCTION(AActor, isHostile) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(other, AActor); + ACTION_RETURN_BOOL(self->IsHostile(other)); +} + + +//========================================================================== +// +// AActor :: DoSpecialDamage +// +// override this for special damage effects. +// +//========================================================================== + int AActor::DoSpecialDamage (AActor *target, int damage, FName damagetype) { if (target->player && target->player->mo == target && damage < 1000 && @@ -6299,6 +7063,37 @@ int AActor::DoSpecialDamage (AActor *target, int damage, FName damagetype) } } +DEFINE_ACTION_FUNCTION(AActor, DoSpecialDamage) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(target, AActor); + PARAM_INT(damage); + PARAM_NAME(damagetype); + ACTION_RETURN_INT(self->DoSpecialDamage(target, damage, damagetype)); +} + +int AActor::CallDoSpecialDamage(AActor *target, int damage, FName damagetype) +{ + IFVIRTUAL(AActor, DoSpecialDamage) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[4] = { (DObject*)this, (DObject*)target, damage, damagetype.GetIndex() }; + VMReturn ret; + int retval; + ret.IntAt(&retval); + GlobalVMStack.Call(func, params, 4, &ret, 1, nullptr); + return retval; + } + else return DoSpecialDamage(target, damage, damagetype); + +} + +//========================================================================== +// +// AActor :: TakeSpecialDamage +// +//========================================================================== + int AActor::TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype) { FState *death; @@ -6333,6 +7128,31 @@ int AActor::TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FN return (death == NULL) ? -1 : damage; } +DEFINE_ACTION_FUNCTION(AActor, TakeSpecialDamage) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(inflictor, AActor); + PARAM_OBJECT(source, AActor); + PARAM_INT(damage); + PARAM_NAME(damagetype); + ACTION_RETURN_INT(self->TakeSpecialDamage(inflictor, source, damage, damagetype)); +} + +int AActor::CallTakeSpecialDamage(AActor *inflictor, AActor *source, int damage, FName damagetype) +{ + IFVIRTUAL(AActor, TakeSpecialDamage) + { + VMValue params[5] = { (DObject*)this, inflictor, source, damage, damagetype.GetIndex() }; + VMReturn ret; + int retval; + ret.IntAt(&retval); + GlobalVMStack.Call(func, params, 5, &ret, 1, nullptr); + return retval; + } + else return TakeSpecialDamage(inflictor, source, damage, damagetype); + +} + void AActor::Crash() { // [RC] Weird that this forces the Crash state regardless of flag. @@ -6382,6 +7202,14 @@ void AActor::SetIdle(bool nofunction) SetState(idle, nofunction); } +DEFINE_ACTION_FUNCTION(AActor, SetIdle) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_BOOL_DEF(nofunction); + self->SetIdle(nofunction); + return 0; +} + int AActor::SpawnHealth() const { int defhealth = StartHealth ? StartHealth : GetDefault()->health; @@ -6401,6 +7229,12 @@ int AActor::SpawnHealth() const } } +DEFINE_ACTION_FUNCTION(AActor, SpawnHealth) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_INT(self->SpawnHealth()); +} + FState *AActor::GetRaiseState() { if (!(flags & MF_CORPSE)) @@ -6464,17 +7298,37 @@ double AActor::GetCameraHeight() const return GetClass()->CameraHeight == INT_MIN ? Height / 2 : GetClass()->CameraHeight; } +DEFINE_ACTION_FUNCTION(AActor, GetCameraHeight) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_FLOAT(self->GetCameraHeight()); +} + + DDropItem *AActor::GetDropItems() const { return GetClass()->DropItems; } +DEFINE_ACTION_FUNCTION(AActor, GetDropItems) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_OBJECT(self->GetDropItems()); +} + double AActor::GetGravity() const { if (flags & MF_NOGRAVITY) return 0; return level.gravity * Sector->gravity * Gravity * 0.00125; } +DEFINE_ACTION_FUNCTION(AActor, GetGravity) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_FLOAT(self->GetGravity()); +} + + // killough 11/98: // Whether an object is "sentient" or not. Used for environmental influences. // (left precisely the same as MBF even though it doesn't make much sense.) @@ -6510,16 +7364,26 @@ const char *AActor::GetTag(const char *def) const } } +DEFINE_ACTION_FUNCTION(AActor, GetTag) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_STRING(def); + ACTION_RETURN_STRING(self->GetTag(def.Len() == 0? nullptr : def.GetChars())); +} + void AActor::SetTag(const char *def) { - if (def == NULL || *def == 0) - { - Tag = NULL; - } - else - { - Tag = mStringPropertyData.Alloc(def); - } + if (def == NULL || *def == 0) Tag = nullptr; + else Tag = mStringPropertyData.Alloc(def); +} + +DEFINE_ACTION_FUNCTION(AActor, SetTag) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_STRING(def); + if (def.IsEmpty()) self->Tag = nullptr; + else self->Tag = self->mStringPropertyData.Alloc(def); + return 0; } @@ -6544,6 +7408,29 @@ void AActor::ClearCounters() } } +DEFINE_ACTION_FUNCTION(AActor, ClearCounters) +{ + PARAM_SELF_PROLOGUE(AActor); + self->ClearCounters(); + return 0; +} + +int AActor::GetModifiedDamage(FName damagetype, int damage, bool passive) +{ + if (Inventory != nullptr) + Inventory->ModifyDamage(damage, damagetype, damage, passive); + + return damage; +} + +DEFINE_ACTION_FUNCTION(AActor, GetModifiedDamage) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_NAME(type); + PARAM_INT(damage); + PARAM_BOOL(passive); + ACTION_RETURN_INT(self->GetModifiedDamage(type, damage, passive)); +} int AActor::ApplyDamageFactor(FName damagetype, int damage) const { @@ -6555,10 +7442,19 @@ int AActor::ApplyDamageFactor(FName damagetype, int damage) const return damage; } - -void AActor::SetTranslation(const char *trname) +DEFINE_ACTION_FUNCTION(AActor, ApplyDamageFactor) { - if (*trname == 0) + PARAM_SELF_PROLOGUE(AActor); + PARAM_NAME(type); + PARAM_INT(damage); + ACTION_RETURN_INT(self->ApplyDamageFactor(type, damage)); +} + + +void AActor::SetTranslation(FName trname) +{ + // There is no constant for the empty name... + if (trname.GetChars()[0] == 0) { // an empty string resets to the default Translation = GetDefault()->Translation; @@ -6573,14 +7469,396 @@ void AActor::SetTranslation(const char *trname) // silently ignore if the name does not exist, this would create some insane message spam otherwise. } +//--------------------------------------------------------------------------- +// +// PROP A_RestoreSpecialPosition +// +//--------------------------------------------------------------------------- +static FRandom pr_restore("RestorePos"); + +void AActor::RestoreSpecialPosition() +{ + // Move item back to its original location + DVector2 sp = SpawnPoint; + + UnlinkFromWorld(); + SetXY(sp); + LinkToWorld(true); + SetZ(Sector->floorplane.ZatPoint(sp)); + P_FindFloorCeiling(this, FFCF_ONLYSPAWNPOS | FFCF_NOPORTALS); // no portal checks here so that things get spawned in this sector. + + if (flags & MF_SPAWNCEILING) + { + SetZ(ceilingz - Height - SpawnPoint.Z); + } + else if (flags2 & MF2_SPAWNFLOAT) + { + double space = ceilingz - Height - floorz; + if (space > 48) + { + space -= 40; + SetZ((space * pr_restore()) / 256. + floorz + 40); + } + else + { + SetZ(floorz); + } + } + else + { + SetZ(SpawnPoint.Z + floorz); + } + // Redo floor/ceiling check, in case of 3D floors and portals + P_FindFloorCeiling(this, FFCF_SAMESECTOR | FFCF_ONLY3DFLOORS | FFCF_3DRESTRICT); + if (Z() < floorz) + { // Do not reappear under the floor, even if that's where we were for the + // initial spawn. + SetZ(floorz); + } + if ((flags & MF_SOLID) && (Top() > ceilingz)) + { // Do the same for the ceiling. + SetZ(ceilingz - Height); + } + // Do not interpolate from the position the actor was at when it was + // picked up, in case that is different from where it is now. + ClearInterpolation(); +} + +DEFINE_ACTION_FUNCTION(AActor, A_RestoreSpecialPosition) +{ + PARAM_SELF_PROLOGUE(AActor); + self->RestoreSpecialPosition(); + return 0; +} + + + + +class DActorIterator : public DObject, public NActorIterator +{ + DECLARE_CLASS(DActorIterator, DObject) + +public: + DActorIterator(PClassActor *cls= nullptr, int tid = 0) + : NActorIterator(cls, tid) + { + } +}; + +IMPLEMENT_CLASS(DActorIterator, false, false); +DEFINE_ACTION_FUNCTION(DActorIterator, Create) +{ + PARAM_PROLOGUE; + PARAM_INT(tid); + PARAM_CLASS_DEF(type, AActor); + ACTION_RETURN_OBJECT(new DActorIterator(type, tid)); +} + +DEFINE_ACTION_FUNCTION(DActorIterator, Next) +{ + PARAM_SELF_PROLOGUE(DActorIterator); + ACTION_RETURN_OBJECT(self->Next()); +} + +DEFINE_ACTION_FUNCTION(DActorIterator, Reinit) +{ + PARAM_SELF_PROLOGUE(DActorIterator); + self->Reinit(); + return 0; +} + + + +DEFINE_ACTION_FUNCTION(AActor, deltaangle) // should this be global? +{ + PARAM_PROLOGUE; + PARAM_FLOAT(a1); + PARAM_FLOAT(a2); + ACTION_RETURN_FLOAT(deltaangle(DAngle(a1), DAngle(a2)).Degrees); +} + +DEFINE_ACTION_FUNCTION(AActor, absangle) // should this be global? +{ + PARAM_PROLOGUE; + PARAM_FLOAT(a1); + PARAM_FLOAT(a2); + ACTION_RETURN_FLOAT(absangle(DAngle(a1), DAngle(a2)).Degrees); +} + +DEFINE_ACTION_FUNCTION(AActor, Distance2D) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(other, AActor); + ACTION_RETURN_FLOAT(self->Distance2D(other)); +} + +DEFINE_ACTION_FUNCTION(AActor, Distance3D) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(other, AActor); + ACTION_RETURN_FLOAT(self->Distance3D(other)); +} + +DEFINE_ACTION_FUNCTION(AActor, AddZ) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(addz); + PARAM_BOOL_DEF(moving); + self->AddZ(addz, moving); + return 0; +} + +DEFINE_ACTION_FUNCTION(AActor, SetZ) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(z); + self->SetZ(z); + return 0; +} + +DEFINE_ACTION_FUNCTION(AActor, SetDamage) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(dmg); + self->SetDamage(dmg); + return 0; +} + +DEFINE_ACTION_FUNCTION(AActor, GetDefaultByType) +{ + PARAM_PROLOGUE; + PARAM_CLASS(cls, AActor); + ACTION_RETURN_OBJECT(cls == nullptr? nullptr : GetDefaultByType(cls)); +} + +DEFINE_ACTION_FUNCTION(AActor, GetBobOffset) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT_DEF(frac); + ACTION_RETURN_FLOAT(self->GetBobOffset(frac)); +} + +// This combines all 3 variations of the internal function +DEFINE_ACTION_FUNCTION(AActor, VelFromAngle) +{ + PARAM_SELF_PROLOGUE(AActor); + if (numparam == 1) + { + self->VelFromAngle(); + } + else + { + PARAM_FLOAT(speed); + if (numparam == 2) + { + self->VelFromAngle(speed); + } + else + { + PARAM_ANGLE(angle); + self->VelFromAngle(speed, angle); + } + } + return 0; +} + +// This combines all 3 variations of the internal function +DEFINE_ACTION_FUNCTION(AActor, Vel3DFromAngle) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(speed); + PARAM_ANGLE(angle); + PARAM_ANGLE(pitch); + self->Vel3DFromAngle(pitch, angle, speed); + return 0; +} + +// This combines all 3 variations of the internal function +DEFINE_ACTION_FUNCTION(AActor, Thrust) +{ + PARAM_SELF_PROLOGUE(AActor); + if (numparam == 1) + { + self->Thrust(); + } + else + { + PARAM_FLOAT(speed); + if (numparam == 2) + { + self->Thrust(speed); + } + else + { + PARAM_ANGLE(angle); + self->Thrust(angle, speed); + } + } + return 0; +} + +DEFINE_ACTION_FUNCTION(AActor, AngleTo) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(targ, AActor); + PARAM_BOOL_DEF(absolute); + ACTION_RETURN_FLOAT(self->AngleTo(targ, absolute).Degrees); +} + +DEFINE_ACTION_FUNCTION(AActor, AngleToVector) +{ + PARAM_PROLOGUE; + PARAM_ANGLE(angle); + PARAM_FLOAT_DEF(length); + ACTION_RETURN_VEC2(angle.ToVector(length)); +} + +DEFINE_ACTION_FUNCTION(AActor, RotateVector) +{ + PARAM_PROLOGUE; + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_ANGLE(angle); + ACTION_RETURN_VEC2(DVector2(x, y).Rotated(angle)); +} + +DEFINE_ACTION_FUNCTION(AActor, DistanceBySpeed) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(targ, AActor); + PARAM_FLOAT(speed); + ACTION_RETURN_FLOAT(self->DistanceBySpeed(targ, speed)); +} + +DEFINE_ACTION_FUNCTION(AActor, SetXYZ) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + self->SetXYZ(x, y, z); + return 0; +} + +DEFINE_ACTION_FUNCTION(AActor, Vec2Angle) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(length); + PARAM_ANGLE(angle); + PARAM_BOOL_DEF(absolute); + ACTION_RETURN_VEC2(self->Vec2Angle(length, angle, absolute)); +} + + +DEFINE_ACTION_FUNCTION(AActor, Vec3To) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(t, AActor) + ACTION_RETURN_VEC3(self->Vec3To(t)); +} + +DEFINE_ACTION_FUNCTION(AActor, Vec2To) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(t, AActor) + ACTION_RETURN_VEC2(self->Vec2To(t)); +} + +DEFINE_ACTION_FUNCTION(AActor, Vec3Angle) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(length) + PARAM_ANGLE(angle); + PARAM_FLOAT(z); + PARAM_BOOL_DEF(absolute); + ACTION_RETURN_VEC3(self->Vec3Angle(length, angle, z, absolute)); +} + +DEFINE_ACTION_FUNCTION(AActor, Vec2OffsetZ) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_BOOL_DEF(absolute); + ACTION_RETURN_VEC3(self->Vec2OffsetZ(x, y, z, absolute)); +} + +DEFINE_ACTION_FUNCTION(AActor, Vec2Offset) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_BOOL_DEF(absolute); + ACTION_RETURN_VEC2(self->Vec2Offset(x, y, absolute)); +} + +DEFINE_ACTION_FUNCTION(AActor, Vec3Offset) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_BOOL_DEF(absolute); + ACTION_RETURN_VEC3(self->Vec3Offset(x, y, z, absolute)); +} + +DEFINE_ACTION_FUNCTION(AActor, RestoreDamage) +{ + PARAM_SELF_PROLOGUE(AActor); + self->RestoreDamage(); + return 0; +} + +DEFINE_ACTION_FUNCTION(AActor, PlayerNumber) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_INT(self->player ? int(self->player - players) : 0); +} + +DEFINE_ACTION_FUNCTION(AActor, SetFriendPlayer) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_POINTER(player, player_t); + self->SetFriendPlayer(player); + return 0; +} + +DEFINE_ACTION_FUNCTION(AActor, ClearBounce) +{ + PARAM_SELF_PROLOGUE(AActor); + self->BounceFlags = 0; + return 0; +} + +DEFINE_ACTION_FUNCTION(AActor, AccuracyFactor) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_FLOAT(self->AccuracyFactor()); +} + +DEFINE_ACTION_FUNCTION(AActor, CountsAsKill) +{ + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_FLOAT(self->CountsAsKill()); +} + //---------------------------------------------------------------------------- // // DropItem handling // //---------------------------------------------------------------------------- -IMPLEMENT_POINTY_CLASS(DDropItem) - DECLARE_POINTER(Next) -END_POINTERS + +IMPLEMENT_CLASS(DDropItem, false, true) + +IMPLEMENT_POINTERS_START(DDropItem) +IMPLEMENT_POINTER(Next) +IMPLEMENT_POINTERS_END + +DEFINE_FIELD(DDropItem, Next) +DEFINE_FIELD(DDropItem, Name) +DEFINE_FIELD(DDropItem, Probability) +DEFINE_FIELD(DDropItem, Amount) void PrintMiscActorInfo(AActor *query) { @@ -6643,5 +7921,6 @@ void PrintMiscActorInfo(AActor *query) query->floorz, query->ceilingz); Printf("\nSpeed= %f, velocity= x:%f, y:%f, z:%f, combined:%f.\n", query->Speed, query->Vel.X, query->Vel.Y, query->Vel.Z, query->Vel.Length()); + Printf("Scale: x:%f, y:%f\n", query->Scale.X, query->Scale.Y); } } diff --git a/src/p_pillar.cpp b/src/p_pillar.cpp index a55bd5cdb8..b0ea0e4a3a 100644 --- a/src/p_pillar.cpp +++ b/src/p_pillar.cpp @@ -40,10 +40,12 @@ #include "serializer.h" #include "r_data/r_interpolate.h" -IMPLEMENT_POINTY_CLASS (DPillar) - DECLARE_POINTER(m_Interp_Floor) - DECLARE_POINTER(m_Interp_Ceiling) -END_POINTERS +IMPLEMENT_CLASS(DPillar, false, true) + +IMPLEMENT_POINTERS_START(DPillar) + IMPLEMENT_POINTER(m_Interp_Floor) + IMPLEMENT_POINTER(m_Interp_Ceiling) +IMPLEMENT_POINTERS_END DPillar::DPillar () { diff --git a/src/p_plats.cpp b/src/p_plats.cpp index 868f471383..43e8eefb49 100644 --- a/src/p_plats.cpp +++ b/src/p_plats.cpp @@ -35,7 +35,7 @@ static FRandom pr_doplat ("DoPlat"); -IMPLEMENT_CLASS (DPlat) +IMPLEMENT_CLASS(DPlat, false, false) DPlat::DPlat () { diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 2e591e20d9..2bd3696d42 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -25,10 +25,11 @@ #include "gi.h" #include "p_pspr.h" #include "templates.h" -#include "thingdef/thingdef.h" #include "g_level.h" #include "d_player.h" #include "serializer.h" +#include "v_text.h" +#include "cmdlib.h" // MACROS ------------------------------------------------------------------ @@ -79,7 +80,6 @@ CVAR(Int, sv_fastweapons, false, CVAR_SERVERINFO); // PRIVATE DATA DEFINITIONS ------------------------------------------------ static FRandom pr_wpnreadysnd ("WpnReadySnd"); -static FRandom pr_gunshot ("GunShot"); static const FGenericButtons ButtonChecks[] = { @@ -99,10 +99,32 @@ static const FGenericButtons ButtonChecks[] = // //------------------------------------------------------------------------ -IMPLEMENT_POINTY_CLASS(DPSprite) - DECLARE_POINTER(Caller) - DECLARE_POINTER(Next) -END_POINTERS +IMPLEMENT_CLASS(DPSprite, false, true) + +IMPLEMENT_POINTERS_START(DPSprite) + IMPLEMENT_POINTER(Caller) + IMPLEMENT_POINTER(Next) +IMPLEMENT_POINTERS_END + +DEFINE_FIELD_NAMED(DPSprite, State, CurState) // deconflict with same named type +DEFINE_FIELD(DPSprite, Caller) +DEFINE_FIELD(DPSprite, Next) +DEFINE_FIELD(DPSprite, Owner) +DEFINE_FIELD(DPSprite, Sprite) +DEFINE_FIELD(DPSprite, Frame) +DEFINE_FIELD(DPSprite, ID) +DEFINE_FIELD(DPSprite, processPending) +DEFINE_FIELD(DPSprite, x) +DEFINE_FIELD(DPSprite, y) +DEFINE_FIELD(DPSprite, oldx) +DEFINE_FIELD(DPSprite, oldy) +DEFINE_FIELD(DPSprite, firstTic) +DEFINE_FIELD(DPSprite, Tics) +DEFINE_FIELD_BIT(DPSprite, Flags, bAddWeapon, PSPF_ADDWEAPON) +DEFINE_FIELD_BIT(DPSprite, Flags, bAddBob, PSPF_ADDBOB) +DEFINE_FIELD_BIT(DPSprite, Flags, bPowDouble, PSPF_POWDOUBLE) +DEFINE_FIELD_BIT(DPSprite, Flags, bCVarFast, PSPF_CVARFAST) +DEFINE_FIELD_BIT(DPSprite, Flags, bFlip, PSPF_FLIP) //------------------------------------------------------------------------ // @@ -170,6 +192,14 @@ DPSprite *player_t::FindPSprite(int layer) return pspr; } +DEFINE_ACTION_FUNCTION(_PlayerInfo, FindPSprite) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_INT(id); + ACTION_RETURN_OBJECT(self->FindPSprite((PSPLayers)id)); +} + + //------------------------------------------------------------------------ // // @@ -182,6 +212,16 @@ void P_SetPsprite(player_t *player, PSPLayers id, FState *state, bool pending) player->GetPSprite(id)->SetState(state, pending); } +DEFINE_ACTION_FUNCTION(_PlayerInfo, SetPSprite) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_INT(id); + PARAM_POINTER(state, FState); + PARAM_BOOL_DEF(pending); + P_SetPsprite(self, (PSPLayers)id, state, pending); + return 0; +} + DPSprite *player_t::GetPSprite(PSPLayers layer) { AActor *oldcaller = nullptr; @@ -243,6 +283,14 @@ DPSprite *player_t::GetPSprite(PSPLayers layer) return pspr; } +DEFINE_ACTION_FUNCTION(_PlayerInfo, GetPSprite) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_INT(id); + ACTION_RETURN_OBJECT(self->GetPSprite((PSPLayers)id)); +} + + //--------------------------------------------------------------------------- // // PROC P_NewPspriteTick @@ -293,6 +341,27 @@ void DPSprite::SetState(FState *newstate, bool pending) Destroy(); return; } + + if (!(newstate->UseFlags & (SUF_OVERLAY|SUF_WEAPON))) // Weapon and overlay are mostly the same, the main difference is that weapon states restrict the self pointer to class Actor. + { + auto so = FState::StaticFindStateOwner(newstate); + Printf(TEXTCOLOR_RED "State %s.%d not flagged for use in overlays or weapons\n", so->TypeName.GetChars(), int(newstate - so->OwnedStates)); + State = nullptr; + Destroy(); + return; + } + else if (!(newstate->UseFlags & SUF_WEAPON)) + { + if (Caller->IsKindOf(RUNTIME_CLASS(AWeapon))) + { + auto so = FState::StaticFindStateOwner(newstate); + Printf(TEXTCOLOR_RED "State %s.%d not flagged for use in weapons\n", so->TypeName.GetChars(), int(newstate - so->OwnedStates)); + State = nullptr; + Destroy(); + return; + } + } + State = newstate; if (newstate->sprite != SPR_FIXED) @@ -335,6 +404,14 @@ void DPSprite::SetState(FState *newstate, bool pending) { FState *nextstate; FStateParamInfo stp = { newstate, STATE_Psprite, ID }; + if (newstate->ActionFunc != nullptr && newstate->ActionFunc->Unsafe) + { + // If an unsafe function (i.e. one that accesses user variables) is being detected, print a warning once and remove the bogus function. We may not call it because that would inevitably crash. + auto owner = FState::StaticFindStateOwner(newstate); + Printf(TEXTCOLOR_RED "Unsafe state call in state %s.%d to %s which accesses user variables. The action function has been removed from this state\n", + owner->TypeName.GetChars(), int(newstate - owner->OwnedStates), newstate->ActionFunc->PrintableName.GetChars()); + newstate->ActionFunc = nullptr; + } if (newstate->CallAction(Owner->mo, Caller, &stp, &nextstate)) { // It's possible this call resulted in this very layer being replaced. @@ -362,6 +439,15 @@ void DPSprite::SetState(FState *newstate, bool pending) return; } +DEFINE_ACTION_FUNCTION(DPSprite, SetState) +{ + PARAM_SELF_PROLOGUE(DPSprite); + PARAM_POINTER(state, FState); + PARAM_BOOL_DEF(pending); + self->SetState(state, pending); + return 0; +} + //--------------------------------------------------------------------------- // // PROC P_BringUpWeapon @@ -740,10 +826,10 @@ void DoReadyWeapon(AActor *self) DoReadyWeaponToGeneric(self, ~0); } -DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady) +DEFINE_ACTION_FUNCTION(AStateProvider, A_WeaponReady) { - PARAM_ACTION_PROLOGUE; - PARAM_INT_OPT(flags) { flags = 0; } + PARAM_ACTION_PROLOGUE(AStateProvider); + PARAM_INT_DEF(flags); DoReadyWeaponToSwitch(self, !(flags & WRF_NoSwitch)); if ((flags & WRF_NoFire) != WRF_NoFire) DoReadyWeaponToFire(self, !(flags & WRF_NoPrimary), !(flags & WRF_NoSecondary)); @@ -872,10 +958,10 @@ static void P_CheckWeaponButtons (player_t *player) // //--------------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_ReFire) +DEFINE_ACTION_FUNCTION(AStateProvider, A_ReFire) { - PARAM_ACTION_PROLOGUE; - PARAM_STATE_OPT(state) { state = NULL; } + PARAM_ACTION_PROLOGUE(AStateProvider); + PARAM_STATE_ACTION_DEF(state); A_ReFire(self, state); return 0; } @@ -910,9 +996,9 @@ void A_ReFire(AActor *self, FState *state) } } -DEFINE_ACTION_FUNCTION(AInventory, A_ClearReFire) +DEFINE_ACTION_FUNCTION(AStateProvider, A_ClearReFire) { - PARAM_ACTION_PROLOGUE; + PARAM_ACTION_PROLOGUE(AStateProvider); player_t *player = self->player; if (NULL != player) @@ -932,9 +1018,9 @@ DEFINE_ACTION_FUNCTION(AInventory, A_ClearReFire) // //--------------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION(AInventory, A_CheckReload) +DEFINE_ACTION_FUNCTION(AStateProvider, A_CheckReload) { - PARAM_ACTION_PROLOGUE; + PARAM_ACTION_PROLOGUE(AStateProvider); if (self->player != NULL) { @@ -1001,21 +1087,21 @@ void A_OverlayOffset(AActor *self, int layer, double wx, double wy, int flags) DEFINE_ACTION_FUNCTION(AActor, A_OverlayOffset) { - PARAM_ACTION_PROLOGUE; - PARAM_INT_OPT(layer) { layer = PSP_WEAPON; } - PARAM_FLOAT_OPT(wx) { wx = 0.; } - PARAM_FLOAT_OPT(wy) { wy = 32.; } - PARAM_INT_OPT(flags) { flags = 0; } + PARAM_ACTION_PROLOGUE(AActor); + PARAM_INT_DEF(layer) + PARAM_FLOAT_DEF(wx) + PARAM_FLOAT_DEF(wy) + PARAM_INT_DEF(flags) A_OverlayOffset(self, ((layer != 0) ? layer : stateinfo->mPSPIndex), wx, wy, flags); return 0; } DEFINE_ACTION_FUNCTION(AActor, A_WeaponOffset) { - PARAM_ACTION_PROLOGUE; - PARAM_FLOAT_OPT(wx) { wx = 0.; } - PARAM_FLOAT_OPT(wy) { wy = 32.; } - PARAM_INT_OPT(flags) { flags = 0; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT_DEF(wx) + PARAM_FLOAT_DEF(wy) + PARAM_INT_DEF(flags) A_OverlayOffset(self, PSP_WEAPON, wx, wy, flags); return 0; } @@ -1028,7 +1114,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_WeaponOffset) DEFINE_ACTION_FUNCTION(AActor, A_OverlayFlags) { - PARAM_ACTION_PROLOGUE; + PARAM_ACTION_PROLOGUE(AActor); PARAM_INT(layer); PARAM_INT(flags); PARAM_BOOL(set); @@ -1071,8 +1157,8 @@ static double GetOverlayPosition(AActor *self, int layer, bool gety) DEFINE_ACTION_FUNCTION(AActor, OverlayX) { - PARAM_ACTION_PROLOGUE; - PARAM_INT_OPT(layer) { layer = 0; } + PARAM_ACTION_PROLOGUE(AActor); + PARAM_INT_DEF(layer); if (ACTION_CALL_FROM_PSPRITE()) { @@ -1084,8 +1170,8 @@ DEFINE_ACTION_FUNCTION(AActor, OverlayX) DEFINE_ACTION_FUNCTION(AActor, OverlayY) { - PARAM_ACTION_PROLOGUE; - PARAM_INT_OPT(layer) { layer = 0; } + PARAM_ACTION_PROLOGUE(AActor); + PARAM_INT_DEF(layer); if (ACTION_CALL_FROM_PSPRITE()) { @@ -1103,7 +1189,7 @@ DEFINE_ACTION_FUNCTION(AActor, OverlayY) DEFINE_ACTION_FUNCTION(AActor, OverlayID) { - PARAM_ACTION_PROLOGUE; + PARAM_ACTION_PROLOGUE(AActor); if (ACTION_CALL_FROM_PSPRITE()) { @@ -1120,9 +1206,9 @@ DEFINE_ACTION_FUNCTION(AActor, OverlayID) // //--------------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION(AInventory, A_Lower) +DEFINE_ACTION_FUNCTION(AStateProvider, A_Lower) { - PARAM_ACTION_PROLOGUE; + PARAM_ACTION_PROLOGUE(AStateProvider); player_t *player = self->player; DPSprite *psp; @@ -1168,9 +1254,9 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Lower) // //--------------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION(AInventory, A_Raise) +DEFINE_ACTION_FUNCTION(AStateProvider, A_Raise) { - PARAM_ACTION_PROLOGUE; + PARAM_ACTION_PROLOGUE(AStateProvider); if (self == nullptr) { @@ -1209,12 +1295,12 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Raise) // //--------------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Overlay) +DEFINE_ACTION_FUNCTION(AActor, A_Overlay) { - PARAM_ACTION_PROLOGUE; + PARAM_ACTION_PROLOGUE(AActor); PARAM_INT (layer); - PARAM_STATE_OPT (state) { state = nullptr; } - PARAM_BOOL_OPT (dontoverride) { dontoverride = false; } + PARAM_STATE_ACTION_DEF(state); + PARAM_BOOL_DEF(dontoverride); player_t *player = self->player; @@ -1229,12 +1315,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Overlay) ACTION_RETURN_BOOL(true); } -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ClearOverlays) +DEFINE_ACTION_FUNCTION(AActor, A_ClearOverlays) { - PARAM_ACTION_PROLOGUE; - PARAM_INT_OPT(start) { start = 0; } - PARAM_INT_OPT(stop) { stop = 0; } - PARAM_BOOL_OPT(safety) { safety = true; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT_DEF(start); + PARAM_INT_DEF(stop); + PARAM_BOOL_DEF(safety) if (self->player == nullptr) ACTION_RETURN_INT(0); @@ -1280,11 +1366,11 @@ enum GF_Flags GFF_NOEXTCHANGE = 1, }; -DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_GunFlash) +DEFINE_ACTION_FUNCTION(AStateProvider, A_GunFlash) { - PARAM_ACTION_PROLOGUE; - PARAM_STATE_OPT(flash) { flash = nullptr; } - PARAM_INT_OPT (flags) { flags = 0; } + PARAM_ACTION_PROLOGUE(AStateProvider); + PARAM_STATE_ACTION_DEF(flash); + PARAM_INT_DEF(flags); player_t *player = self->player; @@ -1350,69 +1436,26 @@ DAngle P_BulletSlope (AActor *mo, FTranslatedLineTarget *pLineTarget, int aimfla return pitch; } - -// -// P_GunShot -// -void P_GunShot (AActor *mo, bool accurate, PClassActor *pufftype, DAngle pitch) +DEFINE_ACTION_FUNCTION(AActor, BulletSlope) { - DAngle angle; - int damage; - - damage = 5*(pr_gunshot()%3+1); - angle = mo->Angles.Yaw; - - if (!accurate) - { - angle += pr_gunshot.Random2 () * (5.625 / 256); - } - - P_LineAttack (mo, angle, PLAYERMISSILERANGE, pitch, damage, NAME_Hitscan, pufftype); + PARAM_SELF_PROLOGUE(AActor); + PARAM_POINTER_DEF(t, FTranslatedLineTarget); + PARAM_INT_DEF(aimflags); + ACTION_RETURN_FLOAT(P_BulletSlope(self, t, aimflags).Degrees); } -DEFINE_ACTION_FUNCTION(AInventory, A_Light0) -{ - PARAM_ACTION_PROLOGUE; - if (self->player != NULL) - { - self->player->extralight = 0; - } - return 0; +AActor *P_AimTarget(AActor *mo) +{ + FTranslatedLineTarget t; + P_BulletSlope(mo, &t, ALF_PORTALRESTRICT); + return t.linetarget; } -DEFINE_ACTION_FUNCTION(AInventory, A_Light1) +DEFINE_ACTION_FUNCTION(AActor, AimTarget) { - PARAM_ACTION_PROLOGUE; - - if (self->player != NULL) - { - self->player->extralight = 1; - } - return 0; -} - -DEFINE_ACTION_FUNCTION(AInventory, A_Light2) -{ - PARAM_ACTION_PROLOGUE; - - if (self->player != NULL) - { - self->player->extralight = 2; - } - return 0; -} - -DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_Light) -{ - PARAM_ACTION_PROLOGUE; - PARAM_INT(light); - - if (self->player != NULL) - { - self->player->extralight = clamp(light, -20, 20); - } - return 0; + PARAM_SELF_PROLOGUE(AActor); + ACTION_RETURN_OBJECT(P_AimTarget(self)); } //------------------------------------------------------------------------ @@ -1551,6 +1594,65 @@ void player_t::DestroyPSprites() } } +//------------------------------------------------------------------------------------ +// +// 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) +{ + if (flashstate != nullptr) + { + 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(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); +} + +DEFINE_ACTION_FUNCTION(_PlayerInfo, SetSafeFlash) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_OBJECT_NOT_NULL(weapon, AWeapon); + PARAM_POINTER(state, FState); + PARAM_INT(index); + P_SetSafeFlash(weapon, self, state, index); + return 0; +} + //------------------------------------------------------------------------ // // diff --git a/src/p_pspr.h b/src/p_pspr.h index 4b50d9d0c2..9c535e7d0a 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -25,7 +25,6 @@ // Basic data types. // Needs fixed point, and BAM angles. -#include "thingdef/thingdef.h" #define WEAPONBOTTOM 128. @@ -88,8 +87,9 @@ private: void Serialize(FSerializer &arc); void Tick(); - void Destroy(); + void Destroy() override; +public: // must be public to be able to generate the field export tables. Grrr... TObjPtr Caller; TObjPtr Next; player_t *Owner; @@ -111,15 +111,13 @@ void P_FireWeapon (player_t *player); void P_DropWeapon (player_t *player); void P_BobWeapon (player_t *player, float *x, float *y, double ticfrac); DAngle P_BulletSlope (AActor *mo, FTranslatedLineTarget *pLineTarget = NULL, int aimflags = 0); - -void P_GunShot (AActor *mo, bool accurate, PClassActor *pufftype, DAngle pitch); +AActor *P_AimTarget(AActor *mo); void DoReadyWeapon(AActor *self); void DoReadyWeaponToBob(AActor *self); void DoReadyWeaponToFire(AActor *self, bool primary = true, bool secondary = true); void DoReadyWeaponToSwitch(AActor *self, bool switchable = true); -DECLARE_ACTION(A_Raise) void A_ReFire(AActor *self, FState *state = NULL); #endif // __P_PSPR_H__ diff --git a/src/p_pusher.cpp b/src/p_pusher.cpp index 38c9c9720f..1cf0041203 100644 --- a/src/p_pusher.cpp +++ b/src/p_pusher.cpp @@ -74,10 +74,11 @@ protected: friend bool PIT_PushThing (AActor *thing); }; +IMPLEMENT_CLASS(DPusher, false, true) -IMPLEMENT_POINTY_CLASS (DPusher) - DECLARE_POINTER (m_Source) -END_POINTERS +IMPLEMENT_POINTERS_START(DPusher) + IMPLEMENT_POINTER(m_Source) +IMPLEMENT_POINTERS_END DPusher::DPusher () { diff --git a/src/p_scroll.cpp b/src/p_scroll.cpp index f2ece8b3de..25789d9448 100644 --- a/src/p_scroll.cpp +++ b/src/p_scroll.cpp @@ -44,7 +44,7 @@ public: DScroller (EScroll type, double dx, double dy, int control, int affectee, int accel, EScrollPos scrollpos = EScrollPos::scw_all); DScroller (double dx, double dy, const line_t *l, int control, int accel, EScrollPos scrollpos = EScrollPos::scw_all); - void Destroy(); + void Destroy() override; void Serialize(FSerializer &arc); void Tick (); @@ -73,12 +73,13 @@ private: } }; +IMPLEMENT_CLASS(DScroller, false, true) -IMPLEMENT_POINTY_CLASS (DScroller) - DECLARE_POINTER (m_Interpolations[0]) - DECLARE_POINTER (m_Interpolations[1]) - DECLARE_POINTER (m_Interpolations[2]) -END_POINTERS +IMPLEMENT_POINTERS_START(DScroller) + IMPLEMENT_POINTER(m_Interpolations[0]) + IMPLEMENT_POINTER(m_Interpolations[1]) + IMPLEMENT_POINTER(m_Interpolations[2]) +IMPLEMENT_POINTERS_END //----------------------------------------------------------------------------- diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 5ed4cd1442..22ef883580 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -22,6 +22,7 @@ //----------------------------------------------------------------------------- #include "p_spec.h" +#include "p_lnspec.h" #include "c_cvars.h" #include "doomstat.h" #include "g_level.h" @@ -699,6 +700,16 @@ void sector_t::SetColor(int r, int g, int b, int desat) P_RecalculateAttachedLights(this); } +DEFINE_ACTION_FUNCTION(_Sector, SetColor) +{ + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + PARAM_COLOR(color); + PARAM_INT(desat); + self->ColorMap = GetSpecialLights(color, self->ColorMap->Fade, desat); + P_RecalculateAttachedLights(self); + return 0; +} + void sector_t::SetFade(int r, int g, int b) { PalEntry fade = PalEntry (r,g,b); @@ -706,6 +717,16 @@ void sector_t::SetFade(int r, int g, int b) P_RecalculateAttachedLights(this); } +DEFINE_ACTION_FUNCTION(_Sector, SetFade) +{ + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + PARAM_COLOR(fade); + self->ColorMap = GetSpecialLights(self->ColorMap->Color, fade, self->ColorMap->Desaturate); + P_RecalculateAttachedLights(self); + return 0; +} + + //=========================================================================== // // sector_t :: ClosestPoint @@ -960,7 +981,7 @@ double sector_t::NextHighestCeilingAt(double x, double y, double bottomz, double } } if ((flags & FFCF_NOPORTALS) || sec->PortalBlocksMovement(ceiling) || planeheight >= sec->GetPortalPlaneZ(ceiling)) - { // Use sector's floor + { // Use sector's ceiling if (resultffloor) *resultffloor = NULL; if (resultsec) *resultsec = sec; return realceil; @@ -976,6 +997,34 @@ double sector_t::NextHighestCeilingAt(double x, double y, double bottomz, double } } +DEFINE_ACTION_FUNCTION(_Sector, NextHighestCeilingAt) +{ + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(bottomz); + PARAM_FLOAT(topz); + PARAM_INT_DEF(flags); + sector_t *resultsec; + F3DFloor *resultff; + double resultheight = self->NextHighestCeilingAt(x, y, bottomz, topz, flags, &resultsec, &resultff); + + if (numret > 2) + { + ret[2].SetPointer(resultff, ATAG_GENERIC); + numret = 3; + } + if (numret > 1) + { + ret[1].SetPointer(resultsec, ATAG_GENERIC); + } + if (numret > 0) + { + ret[0].SetFloat(resultheight); + } + return numret; +} + double sector_t::NextLowestFloorAt(double x, double y, double z, int flags, double steph, sector_t **resultsec, F3DFloor **resultffloor) { sector_t *sec = this; @@ -1021,6 +1070,35 @@ double sector_t::NextLowestFloorAt(double x, double y, double z, int flags, doub } } +DEFINE_ACTION_FUNCTION(_Sector, NextLowestFloorAt) +{ + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_INT_DEF(flags); + PARAM_FLOAT_DEF(steph); + sector_t *resultsec; + F3DFloor *resultff; + double resultheight = self->NextLowestFloorAt(x, y, z, flags, steph, &resultsec, &resultff); + + if (numret > 2) + { + ret[2].SetPointer(resultff, ATAG_GENERIC); + numret = 3; + } + if (numret > 1) + { + ret[1].SetPointer(resultsec, ATAG_GENERIC); + } + if (numret > 0) + { + ret[0].SetFloat(resultheight); + } + return numret; +} + + //=========================================================================== // // @@ -1047,6 +1125,43 @@ double sector_t::NextLowestFloorAt(double x, double y, double z, int flags, doub } } + //=========================================================================== + // + // + // + //=========================================================================== + + void sector_t::RemoveForceField() + { + for (int i = 0; i < linecount; ++i) + { + line_t *line = lines[i]; + if (line->backsector != NULL && line->special == ForceField) + { + line->flags &= ~(ML_BLOCKING | ML_BLOCKEVERYTHING); + line->special = 0; + line->sidedef[0]->SetTexture(side_t::mid, FNullTextureID()); + line->sidedef[1]->SetTexture(side_t::mid, FNullTextureID()); + } + } + } + + DEFINE_ACTION_FUNCTION(_Sector, RemoveForceField) + { + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + self->RemoveForceField(); + return 0; + } + + + DEFINE_ACTION_FUNCTION(_Sector, PointInSector) + { + PARAM_PROLOGUE; + PARAM_FLOAT(x); + PARAM_FLOAT(y); + ACTION_RETURN_POINTER(P_PointInSector(x, y)); + } + //=========================================================================== // // @@ -1237,3 +1352,64 @@ int side_t::GetLightLevel (bool foggy, int baselight, bool is3dlight, int *pfake } return baselight; } + + +DEFINE_FIELD_X(Sector, sector_t, floorplane) +DEFINE_FIELD_X(Sector, sector_t, ceilingplane) +DEFINE_FIELD_X(Sector, sector_t, ColorMap) +DEFINE_FIELD_X(Sector, sector_t, SoundTarget) +DEFINE_FIELD_X(Sector, sector_t, special) +DEFINE_FIELD_X(Sector, sector_t, lightlevel) +DEFINE_FIELD_X(Sector, sector_t, seqType) +DEFINE_FIELD_X(Sector, sector_t, sky) +DEFINE_FIELD_X(Sector, sector_t, SeqName) +DEFINE_FIELD_X(Sector, sector_t, centerspot) +DEFINE_FIELD_X(Sector, sector_t, validcount) +DEFINE_FIELD_X(Sector, sector_t, thinglist) +DEFINE_FIELD_X(Sector, sector_t, friction) +DEFINE_FIELD_X(Sector, sector_t, movefactor) +DEFINE_FIELD_X(Sector, sector_t, terrainnum) +DEFINE_FIELD_X(Sector, sector_t, floordata) +DEFINE_FIELD_X(Sector, sector_t, ceilingdata) +DEFINE_FIELD_X(Sector, sector_t, lightingdata) +DEFINE_FIELD_X(Sector, sector_t, interpolations) +DEFINE_FIELD_X(Sector, sector_t, soundtraversed) +DEFINE_FIELD_X(Sector, sector_t, stairlock) +DEFINE_FIELD_X(Sector, sector_t, prevsec) +DEFINE_FIELD_X(Sector, sector_t, nextsec) +DEFINE_FIELD_X(Sector, sector_t, linecount) +DEFINE_FIELD_X(Sector, sector_t, lines) +DEFINE_FIELD_X(Sector, sector_t, heightsec) +DEFINE_FIELD_X(Sector, sector_t, bottommap) +DEFINE_FIELD_X(Sector, sector_t, midmap) +DEFINE_FIELD_X(Sector, sector_t, topmap) +DEFINE_FIELD_X(Sector, sector_t, touching_thinglist) +DEFINE_FIELD_X(Sector, sector_t, render_thinglist) +DEFINE_FIELD_X(Sector, sector_t, gravity) +DEFINE_FIELD_X(Sector, sector_t, damagetype) +DEFINE_FIELD_X(Sector, sector_t, damageamount) +DEFINE_FIELD_X(Sector, sector_t, damageinterval) +DEFINE_FIELD_X(Sector, sector_t, leakydamage) +DEFINE_FIELD_X(Sector, sector_t, ZoneNumber) +DEFINE_FIELD_X(Sector, sector_t, MoreFlags) +DEFINE_FIELD_X(Sector, sector_t, Flags) +DEFINE_FIELD_X(Sector, sector_t, SecActTarget) +DEFINE_FIELD_X(Sector, sector_t, Portals) +DEFINE_FIELD_X(Sector, sector_t, PortalGroup) +DEFINE_FIELD_X(Sector, sector_t, sectornum) + +DEFINE_FIELD_X(Line, line_t, v1) +DEFINE_FIELD_X(Line, line_t, v2) +DEFINE_FIELD_X(Line, line_t, delta) +DEFINE_FIELD_X(Line, line_t, flags) +DEFINE_FIELD_X(Line, line_t, activation) +DEFINE_FIELD_X(Line, line_t, special) +DEFINE_FIELD_X(Line, line_t, args) +DEFINE_FIELD_X(Line, line_t, alpha) +DEFINE_FIELD_X(Line, line_t, sidedef) +DEFINE_FIELD_X(Line, line_t, bbox) +DEFINE_FIELD_X(Line, line_t, frontsector) +DEFINE_FIELD_X(Line, line_t, backsector) +DEFINE_FIELD_X(Line, line_t, validcount) +DEFINE_FIELD_X(Line, line_t, locknumber) +DEFINE_FIELD_X(Line, line_t, portalindex) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index aafed854b0..11aef9d8db 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1688,7 +1688,7 @@ static void SetMapThingUserData(AActor *actor, unsigned udi) udi++; - if (var == NULL || (var->Flags & VARF_Native) || !var->Type->IsKindOf(RUNTIME_CLASS(PBasicType))) + if (var == NULL || (var->Flags & (VARF_Native|VARF_Private|VARF_Protected|VARF_Static)) || !var->Type->IsKindOf(RUNTIME_CLASS(PBasicType))) { DPrintf(DMSG_WARNING, "%s is not a user variable in class %s\n", varname.GetChars(), actor->GetClass()->TypeName.GetChars()); diff --git a/src/p_sight.cpp b/src/p_sight.cpp index c10365eea3..21aa1bbe3d 100644 --- a/src/p_sight.cpp +++ b/src/p_sight.cpp @@ -905,6 +905,14 @@ done: return res; } +DEFINE_ACTION_FUNCTION(AActor, CheckSight) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(target, AActor); + PARAM_INT_DEF(flags); + ACTION_RETURN_BOOL(P_CheckSight(self, target, flags)); +} + ADD_STAT (sight) { FString out; diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 901016c14f..ccfafedaca 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -552,6 +552,15 @@ void P_GiveSecret(AActor *actor, bool printmessage, bool playsound, int sectornu level.found_secrets++; } +DEFINE_ACTION_FUNCTION(AActor, GiveSecret) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_BOOL(printmessage); + PARAM_BOOL(playsound); + P_GiveSecret(self, printmessage, playsound, -1); + return 0; +} + //============================================================================ // // P_PlayerOnSpecialFlat @@ -660,7 +669,7 @@ protected: short LastLight; }; -IMPLEMENT_CLASS (DLightTransfer) +IMPLEMENT_CLASS(DLightTransfer, false, false) void DLightTransfer::Serialize(FSerializer &arc) { @@ -750,7 +759,7 @@ protected: BYTE Flags; }; -IMPLEMENT_CLASS (DWallLightTransfer) +IMPLEMENT_CLASS(DWallLightTransfer, false, false) void DWallLightTransfer::Serialize(FSerializer &arc) { @@ -1609,3 +1618,4 @@ void sector_t::AdjustFloorClip () const } } } + diff --git a/src/p_spec.h b/src/p_spec.h index 41d47c7216..8a0729d6a1 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -243,7 +243,7 @@ public: void Serialize(FSerializer &arc); void Tick (); - void Destroy(); + void Destroy() override; protected: EPillar m_Type; @@ -572,7 +572,7 @@ public: DElevator (sector_t *sec); - void Destroy(); + void Destroy() override; void Serialize(FSerializer &arc); void Tick (); @@ -617,7 +617,6 @@ protected: int offset, int timer, bool ceiling); void DoWaggle (bool ceiling); - void Destroy(); DWaggleBase (); }; diff --git a/src/p_states.cpp b/src/p_states.cpp index 1a8116e53b..87a1bae2fe 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -39,7 +39,10 @@ #include "i_system.h" #include "c_dispatch.h" #include "v_text.h" -#include "thingdef/thingdef.h" +#include "thingdef.h" + +// stores indices for symbolic state labels for some old-style DECORATE functions. +FStateLabelStorage StateLabels; // Each state is owned by an actor. Actors can own any number of // states, but a single state cannot be owned by more than one @@ -257,7 +260,95 @@ FState *PClassActor::FindStateByString(const char *name, bool exact) } +//========================================================================== +// +// validate a runtime state index. +// +//========================================================================== +static bool VerifyJumpTarget(PClassActor *cls, FState *CallingState, int index) +{ + while (cls != RUNTIME_CLASS(AActor)) + { + // both calling and target state need to belong to the same class. + if (cls->OwnsState(CallingState)) + { + return cls->OwnsState(CallingState + index); + } + + // We can safely assume the ParentClass is of type PClassActor + // since we stop when we see the Actor base class. + cls = static_cast(cls->ParentClass); + } + return false; +} + +//========================================================================== +// +// Get a statw pointer from a symbolic label +// +//========================================================================== + +FState *FStateLabelStorage::GetState(int pos, PClassActor *cls, bool exact) +{ + if (pos > 0x10000000) + { + return cls? cls->FindState(ENamedName(pos - 0x10000000)) : nullptr; + } + else if (pos < 0) + { + // decode the combined value produced by the script. + int index = (pos >> 16) & 32767; + pos = ((pos & 65535) - 1) * 4; + FState *state; + memcpy(&state, &Storage[pos + sizeof(int)], sizeof(state)); + if (VerifyJumpTarget(cls, state, index)) + return state + index; + else + return nullptr; + } + else if (pos > 0) + { + int val; + pos = (pos - 1) * 4; + memcpy(&val, &Storage[pos], sizeof(int)); + + if (val == 0) + { + FState *state; + memcpy(&state, &Storage[pos + sizeof(int)], sizeof(state)); + return state; + } + else if (cls != nullptr) + { + FName *labels = (FName*)&Storage[pos + sizeof(int)]; + return cls->FindState(val, labels, exact); + } + } + return nullptr; +} + +//========================================================================== +// +// State label conversion function for scripts +// +//========================================================================== + +DEFINE_ACTION_FUNCTION(AActor, FindState) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(newstate); + PARAM_BOOL_DEF(exact) + ACTION_RETURN_STATE(StateLabels.GetState(newstate, self->GetClass(), exact)); +} + +// same as above but context aware. +DEFINE_ACTION_FUNCTION(AActor, ResolveState) +{ + PARAM_ACTION_PROLOGUE(AActor); + PARAM_STATE_ACTION(newstate); + ACTION_RETURN_STATE(newstate); +} //========================================================================== // @@ -432,6 +523,11 @@ FStateLabels *FStateDefinitions::CreateStateLabelList(TArray & sta void FStateDefinitions::InstallStates(PClassActor *info, AActor *defaults) { + if (defaults == nullptr) + { + I_Error("Called InstallStates without actor defaults in %s", info->TypeName.GetChars()); + } + // First ensure we have a valid spawn state. FState *state = FindState("Spawn"); @@ -817,7 +913,7 @@ bool FStateDefinitions::SetLoop() // //========================================================================== -int FStateDefinitions::AddStates(FState *state, const char *framechars) +int FStateDefinitions::AddStates(FState *state, const char *framechars, const FScriptPosition &sc) { bool error = false; int frame = 0; @@ -828,9 +924,9 @@ int FStateDefinitions::AddStates(FState *state, const char *framechars) if (*framechars == '#') noframe = true; - else if (*framechars == '^') + else if (*framechars == '^') frame = '\\' - 'A'; - else + else frame = (*framechars & 223) - 'A'; framechars++; @@ -841,12 +937,14 @@ int FStateDefinitions::AddStates(FState *state, const char *framechars) } state->Frame = frame; - state->SameFrame = noframe; + if (noframe) state->StateFlags |= STF_SAMEFRAME; + else state->StateFlags &= ~STF_SAMEFRAME; StateArray.Push(*state); + SourceLines.Push(sc); ++count; // NODELAY flag is not carried past the first state - state->NoDelay = false; + state->StateFlags &= ~STF_NODELAY; } laststate = &StateArray[StateArray.Size() - 1]; laststatebeforelabel = laststate; @@ -872,6 +970,7 @@ int FStateDefinitions::FinishStates(PClassActor *actor, AActor *defaults) memcpy(realstates, &StateArray[0], count*sizeof(FState)); actor->OwnedStates = realstates; actor->NumOwnedStates = count; + SaveStateSourceLines(realstates, SourceLines); // adjust the state pointers // In the case new states are added these must be adjusted, too! @@ -916,6 +1015,7 @@ int FStateDefinitions::FinishStates(PClassActor *actor, AActor *defaults) } + //========================================================================== // // Prints all state label info to the logfile @@ -956,3 +1056,39 @@ CCMD(dumpstates) Printf(PRINT_LOG, "----------------------------\n"); } } + +//========================================================================== +// +// sets up the script-side version of states +// +//========================================================================== + +DEFINE_FIELD(FState, NextState) +DEFINE_FIELD(FState, sprite) +DEFINE_FIELD(FState, Tics) +DEFINE_FIELD(FState, TicRange) +DEFINE_FIELD(FState, Frame) +DEFINE_FIELD(FState, UseFlags) +DEFINE_FIELD(FState, Misc1) +DEFINE_FIELD(FState, Misc2) +DEFINE_FIELD_BIT(FState, StateFlags, bSlow, STF_SLOW) +DEFINE_FIELD_BIT(FState, StateFlags, bFast, STF_FAST) +DEFINE_FIELD_BIT(FState, StateFlags, bFullbright, STF_FULLBRIGHT) +DEFINE_FIELD_BIT(FState, StateFlags, bNoDelay, STF_NODELAY) +DEFINE_FIELD_BIT(FState, StateFlags, bSameFrame, STF_SAMEFRAME) +DEFINE_FIELD_BIT(FState, StateFlags, bCanRaise, STF_CANRAISE) +DEFINE_FIELD_BIT(FState, StateFlags, bDehacked, STF_DEHACKED) + +DEFINE_ACTION_FUNCTION(FState, DistanceTo) +{ + PARAM_SELF_STRUCT_PROLOGUE(FState); + PARAM_POINTER(other, FState); + int retv = INT_MIN; + if (other != nullptr) + { + // Safely calculate the distance between two states. + auto o1 = FState::StaticFindStateOwner(self); + if (other >= o1->OwnedStates && other < o1->OwnedStates + o1->NumOwnedStates) retv = int(other - self); + } + ACTION_RETURN_INT(retv); +} diff --git a/src/p_switch.cpp b/src/p_switch.cpp index c60b0fdcda..ae7cf21432 100644 --- a/src/p_switch.cpp +++ b/src/p_switch.cpp @@ -320,7 +320,7 @@ bool P_ChangeSwitchTexture (side_t *side, int useAgain, BYTE special, bool *ques // //========================================================================== -IMPLEMENT_CLASS (DActiveButton) +IMPLEMENT_CLASS(DActiveButton, false, false) DActiveButton::DActiveButton () { diff --git a/src/p_teleport.cpp b/src/p_teleport.cpp index f65e2f4028..e9752ee53e 100644 --- a/src/p_teleport.cpp +++ b/src/p_teleport.cpp @@ -47,7 +47,7 @@ extern void P_CalcHeight (player_t *player); CVAR (Bool, telezoom, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); -IMPLEMENT_CLASS (ATeleportFog) +IMPLEMENT_CLASS(ATeleportFog, false, false) void ATeleportFog::PostBeginPlay () { @@ -96,6 +96,18 @@ void P_SpawnTeleportFog(AActor *mobj, const DVector3 &pos, bool beforeTele, bool mo->target = mobj; } +DEFINE_ACTION_FUNCTION(AActor, SpawnTeleportFog) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_BOOL(before); + PARAM_BOOL(settarget); + P_SpawnTeleportFog(self, DVector3(x, y, z), before, settarget); + return 0; +} + // // TELEPORTATION // @@ -226,6 +238,17 @@ bool P_Teleport (AActor *thing, DVector3 pos, DAngle angle, int flags) return true; } +DEFINE_ACTION_FUNCTION(AActor, Teleport) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + PARAM_FLOAT(z); + PARAM_ANGLE(an); + PARAM_INT(flags); + ACTION_RETURN_BOOL(P_Teleport(self, DVector3(x, y, z), an, flags)); +} + static AActor *SelectTeleDest (int tid, int tag, bool norandom) { AActor *searcher; diff --git a/src/p_terrain.cpp b/src/p_terrain.cpp index 2504bad94e..3adc94876d 100644 --- a/src/p_terrain.cpp +++ b/src/p_terrain.cpp @@ -724,3 +724,18 @@ FName P_GetTerrainName(int terrainnum) } } +DEFINE_FIELD_NAMED(FTerrainDef, Name, TerrainName) +DEFINE_FIELD(FTerrainDef, Splash) +DEFINE_FIELD(FTerrainDef, DamageAmount) +DEFINE_FIELD(FTerrainDef, DamageMOD) +DEFINE_FIELD(FTerrainDef, DamageTimeMask) +DEFINE_FIELD(FTerrainDef, FootClip) +DEFINE_FIELD(FTerrainDef, StepVolume) +DEFINE_FIELD(FTerrainDef, WalkStepTics) +DEFINE_FIELD(FTerrainDef, RunStepTics) +DEFINE_FIELD(FTerrainDef, LeftStepSound) +DEFINE_FIELD(FTerrainDef, RightStepSound) +DEFINE_FIELD(FTerrainDef, IsLiquid) +DEFINE_FIELD(FTerrainDef, AllowProtection) +DEFINE_FIELD(FTerrainDef, Friction) +DEFINE_FIELD(FTerrainDef, MoveFactor) diff --git a/src/p_things.cpp b/src/p_things.cpp index ba377abebb..6aac786f07 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -520,6 +520,13 @@ PClassActor *P_GetSpawnableType(int spawnnum) return NULL; } +DEFINE_ACTION_FUNCTION(AActor, GetSpawnableType) +{ + PARAM_PROLOGUE; + PARAM_INT(num); + ACTION_RETURN_OBJECT(P_GetSpawnableType(num)); +} + struct MapinfoSpawnItem { FName classname; // DECORATE is read after MAPINFO so we do not have the actual classes available here yet. diff --git a/src/p_user.cpp b/src/p_user.cpp index 4a15e7f180..b808dd9c3d 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -48,7 +48,6 @@ #include "doomdef.h" #include "c_dispatch.h" #include "tarray.h" -#include "thingdef/thingdef.h" #include "g_level.h" #include "d_net.h" #include "gstrings.h" @@ -59,6 +58,9 @@ #include "p_blockmap.h" #include "a_morph.h" #include "p_spec.h" +#include "virtual.h" +#include "a_armor.h" +#include "a_ammo.h" static FRandom pr_skullpop ("SkullPop"); @@ -486,14 +488,33 @@ void player_t::SetLogNumber (int num) } } +DEFINE_ACTION_FUNCTION(_PlayerInfo, SetLogNumber) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_INT(log); + self->SetLogNumber(log); + return 0; +} + void player_t::SetLogText (const char *text) { LogText = text; - // Print log text to console - AddToConsole(-1, TEXTCOLOR_GOLD); - AddToConsole(-1, LogText); - AddToConsole(-1, "\n"); + if (mo->CheckLocalView(consoleplayer)) + { + // Print log text to console + AddToConsole(-1, TEXTCOLOR_GOLD); + AddToConsole(-1, LogText); + AddToConsole(-1, "\n"); + } +} + +DEFINE_ACTION_FUNCTION(_PlayerInfo, SetLogText) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_STRING(log); + self->SetLogText(log); + return 0; } int player_t::GetSpawnClass() @@ -508,7 +529,7 @@ int player_t::GetSpawnClass() // //=========================================================================== -IMPLEMENT_CLASS(PClassPlayerPawn) +IMPLEMENT_CLASS(PClassPlayerPawn, false, false) PClassPlayerPawn::PClassPlayerPawn() { @@ -586,16 +607,6 @@ bool PClassPlayerPawn::GetPainFlash(FName type, PalEntry *color) const return false; } -void PClassPlayerPawn::ReplaceClassRef(PClass *oldclass, PClass *newclass) -{ - Super::ReplaceClassRef(oldclass, newclass); - APlayerPawn *def = (APlayerPawn*)Defaults; - if (def != NULL) - { - if (def->FlechetteType == oldclass) def->FlechetteType = static_cast(newclass); - } -} - //=========================================================================== // // player_t :: SendPitchLimits @@ -622,12 +633,15 @@ void player_t::SendPitchLimits() const // //=========================================================================== -IMPLEMENT_POINTY_CLASS (APlayerPawn) - DECLARE_POINTER(InvFirst) - DECLARE_POINTER(InvSel) -END_POINTERS +IMPLEMENT_CLASS(APlayerPawn, false, true) -IMPLEMENT_CLASS (APlayerChunk) +IMPLEMENT_POINTERS_START(APlayerPawn) + IMPLEMENT_POINTER(InvFirst) + IMPLEMENT_POINTER(InvSel) + IMPLEMENT_POINTER(FlechetteType) +IMPLEMENT_POINTERS_END + +IMPLEMENT_CLASS(APlayerChunk, false, false) void APlayerPawn::Serialize(FSerializer &arc) { @@ -1205,6 +1219,12 @@ int APlayerPawn::GetMaxHealth() const return MaxHealth > 0? MaxHealth : ((i_compatflags&COMPATF_DEHHEALTH)? 100 : deh.MaxHealth); } +DEFINE_ACTION_FUNCTION(APlayerPawn, GetMaxHealth) +{ + PARAM_SELF_PROLOGUE(APlayerPawn); + ACTION_RETURN_INT(self->GetMaxHealth()); +} + //=========================================================================== // // APlayerPawn :: UpdateWaterLevel @@ -1258,6 +1278,13 @@ bool APlayerPawn::ResetAirSupply (bool playgasp) return wasdrowning; } +DEFINE_ACTION_FUNCTION(APlayerPawn, ResetAirSupply) +{ + PARAM_SELF_PROLOGUE(APlayerPawn); + PARAM_BOOL_DEF(playgasp); + ACTION_RETURN_BOOL(self->ResetAirSupply(playgasp)); +} + //=========================================================================== // // Animations @@ -1266,28 +1293,38 @@ bool APlayerPawn::ResetAirSupply (bool playgasp) void APlayerPawn::PlayIdle () { - if (InStateSequence(state, SeeState)) - SetState (SpawnState); + IFVIRTUAL(APlayerPawn, PlayIdle) + { + VMValue params[1] = { (DObject*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } } void APlayerPawn::PlayRunning () { - if (InStateSequence(state, SpawnState) && SeeState != NULL) - SetState (SeeState); + IFVIRTUAL(APlayerPawn, PlayRunning) + { + VMValue params[1] = { (DObject*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } } void APlayerPawn::PlayAttacking () { - if (MissileState != NULL) SetState (MissileState); + IFVIRTUAL(APlayerPawn, PlayAttacking) + { + VMValue params[1] = { (DObject*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } } void APlayerPawn::PlayAttacking2 () { - if (MeleeState != NULL) SetState (MeleeState); -} - -void APlayerPawn::ThrowPoisonBag () -{ + IFVIRTUAL(APlayerPawn, PlayAttacking2) + { + VMValue params[1] = { (DObject*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } } //=========================================================================== @@ -1373,6 +1410,11 @@ void APlayerPawn::GiveDefaultInventory () void APlayerPawn::MorphPlayerThink () { + IFVIRTUAL(APlayerPawn, MorphPlayerThink) + { + VMValue params[1] = { (DObject*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } } void APlayerPawn::ActivateMorphWeapon () @@ -1428,7 +1470,7 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor, int dmgflags) if (player != NULL && player->mo != this) { // Make the real player die, too - player->mo->Die (source, inflictor, dmgflags); + player->mo->CallDie (source, inflictor, dmgflags); } else { @@ -1549,7 +1591,7 @@ void APlayerPawn::TweakSpeeds (double &forward, double &side) DEFINE_ACTION_FUNCTION(AActor, A_PlayerScream) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); int sound = 0; int chan = CHAN_VOICE; @@ -1623,10 +1665,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_PlayerScream) // //---------------------------------------------------------------------------- -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SkullPop) +DEFINE_ACTION_FUNCTION(AActor, A_SkullPop) { - PARAM_ACTION_PROLOGUE; - PARAM_CLASS_OPT(spawntype, APlayerChunk) { spawntype = NULL; } + PARAM_SELF_PROLOGUE(AActor); + PARAM_CLASS_DEF(spawntype, APlayerChunk); APlayerPawn *mo; player_t *player; @@ -1675,7 +1717,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SkullPop) DEFINE_ACTION_FUNCTION(AActor, A_CheckPlayerDone) { - PARAM_ACTION_PROLOGUE; + PARAM_SELF_PROLOGUE(AActor); if (self->player == NULL) { @@ -3117,3 +3159,135 @@ bool P_IsPlayerTotallyFrozen(const player_t *player) player->cheats & CF_TOTALLYFROZEN || ((level.flags2 & LEVEL2_FROZEN) && player->timefreezer == 0); } + + +//========================================================================== +// +// native members +// +//========================================================================== + +DEFINE_FIELD(APlayerPawn, crouchsprite) +DEFINE_FIELD(APlayerPawn, MaxHealth) +DEFINE_FIELD(APlayerPawn, MugShotMaxHealth) +DEFINE_FIELD(APlayerPawn, RunHealth) +DEFINE_FIELD(APlayerPawn, PlayerFlags) +DEFINE_FIELD(APlayerPawn, InvFirst) +DEFINE_FIELD(APlayerPawn, InvSel) +DEFINE_FIELD(APlayerPawn, JumpZ) +DEFINE_FIELD(APlayerPawn, GruntSpeed) +DEFINE_FIELD(APlayerPawn, FallingScreamMinSpeed) +DEFINE_FIELD(APlayerPawn, FallingScreamMaxSpeed) +DEFINE_FIELD(APlayerPawn, ViewHeight) +DEFINE_FIELD(APlayerPawn, ForwardMove1) +DEFINE_FIELD(APlayerPawn, ForwardMove2) +DEFINE_FIELD(APlayerPawn, SideMove1) +DEFINE_FIELD(APlayerPawn, SideMove2) +DEFINE_FIELD(APlayerPawn, ScoreIcon) +DEFINE_FIELD(APlayerPawn, SpawnMask) +DEFINE_FIELD(APlayerPawn, MorphWeapon) +DEFINE_FIELD(APlayerPawn, AttackZOffset) +DEFINE_FIELD(APlayerPawn, UseRange) +DEFINE_FIELD(APlayerPawn, AirCapacity) +DEFINE_FIELD(APlayerPawn, FlechetteType) +DEFINE_FIELD(APlayerPawn, DamageFade) +DEFINE_FIELD(APlayerPawn, ViewBob) + +DEFINE_FIELD(PClassPlayerPawn, HealingRadiusType) +DEFINE_FIELD(PClassPlayerPawn, DisplayName) +DEFINE_FIELD(PClassPlayerPawn, SoundClass) +DEFINE_FIELD(PClassPlayerPawn, Face) +DEFINE_FIELD(PClassPlayerPawn, Portrait) +DEFINE_FIELD(PClassPlayerPawn, Slot) +DEFINE_FIELD(PClassPlayerPawn, InvulMode) +DEFINE_FIELD(PClassPlayerPawn, HexenArmor) +DEFINE_FIELD(PClassPlayerPawn, ColorRangeStart) +DEFINE_FIELD(PClassPlayerPawn, ColorRangeEnd) +DEFINE_FIELD(PClassPlayerPawn, ColorSets) +DEFINE_FIELD(PClassPlayerPawn, PainFlashes) + +DEFINE_FIELD_X(PlayerInfo, player_t, mo) +DEFINE_FIELD_X(PlayerInfo, player_t, playerstate) +DEFINE_FIELD_X(PlayerInfo, player_t, original_oldbuttons) +DEFINE_FIELD_X(PlayerInfo, player_t, cls) +DEFINE_FIELD_X(PlayerInfo, player_t, DesiredFOV) +DEFINE_FIELD_X(PlayerInfo, player_t, FOV) +DEFINE_FIELD_X(PlayerInfo, player_t, viewz) +DEFINE_FIELD_X(PlayerInfo, player_t, viewheight) +DEFINE_FIELD_X(PlayerInfo, player_t, deltaviewheight) +DEFINE_FIELD_X(PlayerInfo, player_t, bob) +DEFINE_FIELD_X(PlayerInfo, player_t, Vel) +DEFINE_FIELD_X(PlayerInfo, player_t, centering) +DEFINE_FIELD_X(PlayerInfo, player_t, turnticks) +DEFINE_FIELD_X(PlayerInfo, player_t, attackdown) +DEFINE_FIELD_X(PlayerInfo, player_t, usedown) +DEFINE_FIELD_X(PlayerInfo, player_t, oldbuttons) +DEFINE_FIELD_X(PlayerInfo, player_t, health) +DEFINE_FIELD_X(PlayerInfo, player_t, inventorytics) +DEFINE_FIELD_X(PlayerInfo, player_t, CurrentPlayerClass) +DEFINE_FIELD_X(PlayerInfo, player_t, frags) +DEFINE_FIELD_X(PlayerInfo, player_t, fragcount) +DEFINE_FIELD_X(PlayerInfo, player_t, lastkilltime) +DEFINE_FIELD_X(PlayerInfo, player_t, multicount) +DEFINE_FIELD_X(PlayerInfo, player_t, spreecount) +DEFINE_FIELD_X(PlayerInfo, player_t, WeaponState) +DEFINE_FIELD_X(PlayerInfo, player_t, ReadyWeapon) +DEFINE_FIELD_X(PlayerInfo, player_t, PendingWeapon) +DEFINE_FIELD_X(PlayerInfo, player_t, psprites) +DEFINE_FIELD_X(PlayerInfo, player_t, cheats) +DEFINE_FIELD_X(PlayerInfo, player_t, timefreezer) +DEFINE_FIELD_X(PlayerInfo, player_t, refire) +DEFINE_FIELD_NAMED_X(PlayerInfo, player_t, inconsistant, inconsistent) +DEFINE_FIELD_X(PlayerInfo, player_t, waiting) +DEFINE_FIELD_X(PlayerInfo, player_t, killcount) +DEFINE_FIELD_X(PlayerInfo, player_t, itemcount) +DEFINE_FIELD_X(PlayerInfo, player_t, secretcount) +DEFINE_FIELD_X(PlayerInfo, player_t, damagecount) +DEFINE_FIELD_X(PlayerInfo, player_t, bonuscount) +DEFINE_FIELD_X(PlayerInfo, player_t, hazardcount) +DEFINE_FIELD_X(PlayerInfo, player_t, hazardinterval) +DEFINE_FIELD_X(PlayerInfo, player_t, hazardtype) +DEFINE_FIELD_X(PlayerInfo, player_t, poisoncount) +DEFINE_FIELD_X(PlayerInfo, player_t, poisontype) +DEFINE_FIELD_X(PlayerInfo, player_t, poisonpaintype) +DEFINE_FIELD_X(PlayerInfo, player_t, poisoner) +DEFINE_FIELD_X(PlayerInfo, player_t, attacker) +DEFINE_FIELD_X(PlayerInfo, player_t, extralight) +DEFINE_FIELD_X(PlayerInfo, player_t, fixedcolormap) +DEFINE_FIELD_X(PlayerInfo, player_t, fixedlightlevel) +DEFINE_FIELD_X(PlayerInfo, player_t, morphTics) +DEFINE_FIELD_X(PlayerInfo, player_t, MorphedPlayerClass) +DEFINE_FIELD_X(PlayerInfo, player_t, MorphStyle) +DEFINE_FIELD_X(PlayerInfo, player_t, MorphExitFlash) +DEFINE_FIELD_X(PlayerInfo, player_t, PremorphWeapon) +DEFINE_FIELD_X(PlayerInfo, player_t, chickenPeck) +DEFINE_FIELD_X(PlayerInfo, player_t, jumpTics) +DEFINE_FIELD_X(PlayerInfo, player_t, onground) +DEFINE_FIELD_X(PlayerInfo, player_t, respawn_time) +DEFINE_FIELD_X(PlayerInfo, player_t, camera) +DEFINE_FIELD_X(PlayerInfo, player_t, air_finished) +DEFINE_FIELD_X(PlayerInfo, player_t, LastDamageType) +DEFINE_FIELD_X(PlayerInfo, player_t, MUSINFOactor) +DEFINE_FIELD_X(PlayerInfo, player_t, MUSINFOtics) +DEFINE_FIELD_X(PlayerInfo, player_t, settings_controller) +DEFINE_FIELD_X(PlayerInfo, player_t, crouching) +DEFINE_FIELD_X(PlayerInfo, player_t, crouchdir) +DEFINE_FIELD_X(PlayerInfo, player_t, Bot) +DEFINE_FIELD_X(PlayerInfo, player_t, BlendR) +DEFINE_FIELD_X(PlayerInfo, player_t, BlendG) +DEFINE_FIELD_X(PlayerInfo, player_t, BlendB) +DEFINE_FIELD_X(PlayerInfo, player_t, BlendA) +DEFINE_FIELD_X(PlayerInfo, player_t, LogText) +DEFINE_FIELD_X(PlayerInfo, player_t, MinPitch) +DEFINE_FIELD_X(PlayerInfo, player_t, MaxPitch) +DEFINE_FIELD_X(PlayerInfo, player_t, crouchfactor) +DEFINE_FIELD_X(PlayerInfo, player_t, crouchoffset) +DEFINE_FIELD_X(PlayerInfo, player_t, crouchviewdelta) +DEFINE_FIELD_X(PlayerInfo, player_t, ConversationNPC) +DEFINE_FIELD_X(PlayerInfo, player_t, ConversationPC) +DEFINE_FIELD_X(PlayerInfo, player_t, ConversationNPCAngle) +DEFINE_FIELD_X(PlayerInfo, player_t, ConversationFaceTalker) +DEFINE_FIELD_X(PlayerInfo, player_t, cmd) +DEFINE_FIELD_X(PlayerInfo, player_t, original_cmd) +DEFINE_FIELD_X(PlayerInfo, player_t, userinfo) +DEFINE_FIELD_X(PlayerInfo, player_t, weapons) diff --git a/src/po_man.cpp b/src/po_man.cpp index 05d067e527..15c8d5a52c 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -172,9 +172,11 @@ static FPolyNode *FreePolyNodes; // //========================================================================== -IMPLEMENT_POINTY_CLASS (DPolyAction) - DECLARE_POINTER(m_Interpolation) -END_POINTERS +IMPLEMENT_CLASS(DPolyAction, false, true) + +IMPLEMENT_POINTERS_START(DPolyAction) + IMPLEMENT_POINTER(m_Interpolation) +IMPLEMENT_POINTERS_END DPolyAction::DPolyAction () { @@ -238,7 +240,7 @@ void DPolyAction::StopInterpolation () // //========================================================================== -IMPLEMENT_CLASS (DRotatePoly) +IMPLEMENT_CLASS(DRotatePoly, false, false) DRotatePoly::DRotatePoly () { @@ -255,7 +257,7 @@ DRotatePoly::DRotatePoly (int polyNum) // //========================================================================== -IMPLEMENT_CLASS (DMovePoly) +IMPLEMENT_CLASS(DMovePoly, false, false) DMovePoly::DMovePoly () { @@ -282,7 +284,7 @@ DMovePoly::DMovePoly (int polyNum) // //========================================================================== -IMPLEMENT_CLASS(DMovePolyTo) +IMPLEMENT_CLASS(DMovePolyTo, false, false) DMovePolyTo::DMovePolyTo() { @@ -307,7 +309,7 @@ DMovePolyTo::DMovePolyTo(int polyNum) // //========================================================================== -IMPLEMENT_CLASS (DPolyDoor) +IMPLEMENT_CLASS(DPolyDoor, false, false) DPolyDoor::DPolyDoor () { diff --git a/src/po_man.h b/src/po_man.h index ec6a3901b9..4d78fa1796 100644 --- a/src/po_man.h +++ b/src/po_man.h @@ -12,7 +12,7 @@ class DPolyAction : public DThinker public: DPolyAction(int polyNum); void Serialize(FSerializer &arc); - void Destroy(); + void Destroy() override; void Stop(); double GetSpeed() const { return m_Speed; } diff --git a/src/posix/sdl/sdlglvideo.cpp b/src/posix/sdl/sdlglvideo.cpp index 173a84d801..7eabfcd6ac 100644 --- a/src/posix/sdl/sdlglvideo.cpp +++ b/src/posix/sdl/sdlglvideo.cpp @@ -29,7 +29,7 @@ // TYPES ------------------------------------------------------------------- -IMPLEMENT_ABSTRACT_CLASS(SDLGLFB) +IMPLEMENT_ABSTRACT_CLASS(SDLGLFB, false, false, false, false) struct MiniModeInfo { diff --git a/src/posix/sdl/sdlvideo.cpp b/src/posix/sdl/sdlvideo.cpp index 04c3a3f2ef..4a68330260 100644 --- a/src/posix/sdl/sdlvideo.cpp +++ b/src/posix/sdl/sdlvideo.cpp @@ -78,7 +78,8 @@ private: SDLFB () {} }; -IMPLEMENT_CLASS(SDLFB) + +IMPLEMENT_CLASS(SDLFB, false, false) struct MiniModeInfo { diff --git a/src/r_data/r_interpolate.cpp b/src/r_data/r_interpolate.cpp index e60223bac1..92dc683a86 100644 --- a/src/r_data/r_interpolate.cpp +++ b/src/r_data/r_interpolate.cpp @@ -62,7 +62,7 @@ public: DSectorPlaneInterpolation() {} DSectorPlaneInterpolation(sector_t *sector, bool plane, bool attach); - void Destroy(); + void Destroy() override; void UpdateInterpolation(); void Restore(); void Interpolate(double smoothratio); @@ -91,7 +91,7 @@ public: DSectorScrollInterpolation() {} DSectorScrollInterpolation(sector_t *sector, bool plane); - void Destroy(); + void Destroy() override; void UpdateInterpolation(); void Restore(); void Interpolate(double smoothratio); @@ -119,7 +119,7 @@ public: DWallScrollInterpolation() {} DWallScrollInterpolation(side_t *side, int part); - void Destroy(); + void Destroy() override; void UpdateInterpolation(); void Restore(); void Interpolate(double smoothratio); @@ -146,7 +146,7 @@ public: DPolyobjInterpolation() {} DPolyobjInterpolation(FPolyObj *poly); - void Destroy(); + void Destroy() override; void UpdateInterpolation(); void Restore(); void Interpolate(double smoothratio); @@ -161,14 +161,17 @@ public: // //========================================================================== -IMPLEMENT_ABSTRACT_POINTY_CLASS(DInterpolation) -DECLARE_POINTER(Next) -DECLARE_POINTER(Prev) -END_POINTERS -IMPLEMENT_CLASS(DSectorPlaneInterpolation) -IMPLEMENT_CLASS(DSectorScrollInterpolation) -IMPLEMENT_CLASS(DWallScrollInterpolation) -IMPLEMENT_CLASS(DPolyobjInterpolation) +IMPLEMENT_CLASS(DInterpolation, true, true) + +IMPLEMENT_POINTERS_START(DInterpolation) + IMPLEMENT_POINTER(Next) + IMPLEMENT_POINTER(Prev) +IMPLEMENT_POINTERS_END + +IMPLEMENT_CLASS(DSectorPlaneInterpolation, false, false) +IMPLEMENT_CLASS(DSectorScrollInterpolation, false, false) +IMPLEMENT_CLASS(DWallScrollInterpolation, false, false) +IMPLEMENT_CLASS(DPolyobjInterpolation, false, false) //========================================================================== // diff --git a/src/r_data/r_interpolate.h b/src/r_data/r_interpolate.h index 092cbe5eec..44ff9bed06 100644 --- a/src/r_data/r_interpolate.h +++ b/src/r_data/r_interpolate.h @@ -27,7 +27,7 @@ public: int AddRef(); int DelRef(bool force = false); - virtual void Destroy(); + void Destroy() override; virtual void UpdateInterpolation() = 0; virtual void Restore() = 0; virtual void Interpolate(double smoothratio) = 0; diff --git a/src/r_data/r_translate.cpp b/src/r_data/r_translate.cpp index fe8ff890a0..78d6e22c9f 100644 --- a/src/r_data/r_translate.cpp +++ b/src/r_data/r_translate.cpp @@ -1205,20 +1205,37 @@ void R_GetPlayerTranslation (int color, const FPlayerColorSet *colorset, FPlayer //---------------------------------------------------------------------------- static TMap customTranslationMap; -int R_FindCustomTranslation(const char *name) +int R_FindCustomTranslation(FName name) { - if (name == nullptr) - { - return -1; - } - // Ice is a special case which will remain in its original slot. - if (!stricmp(name, "Ice")) + switch (name) { + case NAME_Ice: + // Ice is a special case which will remain in its original slot. return TRANSLATION(TRANSLATION_Standard, 7); - } - else if (!stricmp(name, "None")) - { + + case NAME_None: return 0; + + case NAME_RainPillar1: + case NAME_RainPillar2: + case NAME_RainPillar3: + case NAME_RainPillar4: + case NAME_RainPillar5: + case NAME_RainPillar6: + case NAME_RainPillar7: + case NAME_RainPillar8: + return TRANSLATION(TRANSLATION_RainPillar, name.GetIndex() - NAME_RainPillar1); + + case NAME_Player1: + case NAME_Player2: + case NAME_Player3: + case NAME_Player4: + case NAME_Player5: + case NAME_Player6: + case NAME_Player7: + case NAME_Player8: + return TRANSLATION(TRANSLATION_Players, name.GetIndex() - NAME_Player1); + } int *t = customTranslationMap.CheckKey(FName(name, true)); return (t != nullptr)? *t : -1; diff --git a/src/r_data/r_translate.h b/src/r_data/r_translate.h index 4ca2f203fc..1680f4df08 100644 --- a/src/r_data/r_translate.h +++ b/src/r_data/r_translate.h @@ -110,7 +110,7 @@ extern TArray BloodTranslationColors; int CreateBloodTranslation(PalEntry color); -int R_FindCustomTranslation(const char *name); +int R_FindCustomTranslation(FName name); void R_ParseTrnslate(); diff --git a/src/r_defs.h b/src/r_defs.h index f172a84a6a..0f5ed0017b 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -278,7 +278,7 @@ class ASectorAction : public AActor DECLARE_CLASS (ASectorAction, AActor) public: ASectorAction (bool activatedByUse = false); - void Destroy (); + void Destroy () override; void BeginPlay (); void Activate (AActor *source); void Deactivate (AActor *source); @@ -658,6 +658,7 @@ public: sector_t *NextSpecialSector (int type, sector_t *prev) const; // [RH] double FindLowestCeilingPoint(vertex_t **v) const; double FindHighestFloorPoint(vertex_t **v) const; + void RemoveForceField(); void AdjustFloorClip () const; void SetColor(int r, int g, int b, int desat); @@ -1030,8 +1031,8 @@ public: BYTE soundtraversed; // 0 = untraversed, 1,2 = sndlines -1 // jff 2/26/98 lockout machinery for stairbuilding SBYTE stairlock; // -2 on first locked -1 after thinker done 0 normally - SWORD prevsec; // -1 or number of sector for previous step - SWORD nextsec; // -1 or number of next step sector + int prevsec; // -1 or number of sector for previous step + int nextsec; // -1 or number of next step sector short linecount; struct line_t **lines; // [linecount] size @@ -1276,9 +1277,7 @@ struct side_t struct line_t { vertex_t *v1, *v2; // vertices, from v1 to v2 -private: DVector2 delta; // precalculated v2 - v1 for side checking -public: uint32_t flags; uint32_t activation; // activation type int special; diff --git a/src/r_utility.cpp b/src/r_utility.cpp index b009912f03..1588349299 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -1104,3 +1104,27 @@ void FCanvasTextureInfo::Mark() } } + +//========================================================================== +// +// CVAR transsouls +// +// How translucent things drawn with STYLE_SoulTrans are. Normally, only +// Lost Souls have this render 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; + } +} diff --git a/src/resourcefiles/file_zip.cpp b/src/resourcefiles/file_zip.cpp index 8011d56cfe..3ae7088230 100644 --- a/src/resourcefiles/file_zip.cpp +++ b/src/resourcefiles/file_zip.cpp @@ -53,50 +53,58 @@ static bool UncompressZipLump(char *Cache, FileReader *Reader, int Method, int LumpSize, int CompressedSize, int GPFlags) { - switch (Method) + try { - case METHOD_STORED: - { - Reader->Read(Cache, LumpSize); - break; - } + switch (Method) + { + case METHOD_STORED: + { + Reader->Read(Cache, LumpSize); + break; + } - case METHOD_DEFLATE: - { - FileReaderZ frz(*Reader, true); - frz.Read(Cache, LumpSize); - break; - } + case METHOD_DEFLATE: + { + FileReaderZ frz(*Reader, true); + frz.Read(Cache, LumpSize); + break; + } - case METHOD_BZIP2: - { - FileReaderBZ2 frz(*Reader); - frz.Read(Cache, LumpSize); - break; - } + case METHOD_BZIP2: + { + FileReaderBZ2 frz(*Reader); + frz.Read(Cache, LumpSize); + break; + } - case METHOD_LZMA: - { - FileReaderLZMA frz(*Reader, LumpSize, true); - frz.Read(Cache, LumpSize); - break; - } + case METHOD_LZMA: + { + FileReaderLZMA frz(*Reader, LumpSize, true); + frz.Read(Cache, LumpSize); + break; + } - case METHOD_IMPLODE: - { - FZipExploder exploder; - exploder.Explode((unsigned char *)Cache, LumpSize, Reader, CompressedSize, GPFlags); - break; - } + case METHOD_IMPLODE: + { + FZipExploder exploder; + exploder.Explode((unsigned char *)Cache, LumpSize, Reader, CompressedSize, GPFlags); + break; + } - case METHOD_SHRINK: - { - ShrinkLoop((unsigned char *)Cache, LumpSize, Reader, CompressedSize); - break; - } + case METHOD_SHRINK: + { + ShrinkLoop((unsigned char *)Cache, LumpSize, Reader, CompressedSize); + break; + } - default: - assert(0); + default: + assert(0); + return false; + } + } + catch (CRecoverableError &err) + { + Printf("%s\n", err.GetMessage()); return false; } return true; diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index 0db9365c20..083e0eeef5 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -2213,7 +2213,7 @@ private: int NextCheck; }; -IMPLEMENT_CLASS (AAmbientSound) +IMPLEMENT_CLASS(AAmbientSound, false, false) //========================================================================== // @@ -2346,7 +2346,7 @@ void AAmbientSound::SetTicker (struct FAmbientSound *ambient) void AAmbientSound::BeginPlay () { Super::BeginPlay (); - Activate (NULL); + CallActivate (NULL); } //========================================================================== @@ -2470,7 +2470,7 @@ public: virtual void PostBeginPlay(); }; -IMPLEMENT_CLASS(AMusicChanger) +IMPLEMENT_CLASS(AMusicChanger, false, false) bool AMusicChanger::DoTriggerAction (AActor *triggerer, int activationType) { diff --git a/src/s_sndseq.cpp b/src/s_sndseq.cpp index 3b39965ff6..28786ef8f0 100644 --- a/src/s_sndseq.cpp +++ b/src/s_sndseq.cpp @@ -105,7 +105,7 @@ class DSeqActorNode : public DSeqNode HAS_OBJECT_POINTERS public: DSeqActorNode(AActor *actor, int sequence, int modenum); - void Destroy(); + void Destroy() override; void Serialize(FSerializer &arc); void MakeSound(int loop, FSoundID id) { @@ -133,7 +133,7 @@ class DSeqPolyNode : public DSeqNode DECLARE_CLASS(DSeqPolyNode, DSeqNode) public: DSeqPolyNode(FPolyObj *poly, int sequence, int modenum); - void Destroy(); + void Destroy() override; void Serialize(FSerializer &arc); void MakeSound(int loop, FSoundID id) { @@ -161,7 +161,7 @@ class DSeqSectorNode : public DSeqNode DECLARE_CLASS(DSeqSectorNode, DSeqNode) public: DSeqSectorNode(sector_t *sec, int chan, int sequence, int modenum); - void Destroy(); + void Destroy() override; void Serialize(FSerializer &arc); void MakeSound(int loop, FSoundID id) { @@ -285,12 +285,14 @@ void DSeqNode::SerializeSequences (FSerializer &arc) arc("sndseqlisthead", SequenceListHead); } -IMPLEMENT_POINTY_CLASS (DSeqNode) - DECLARE_POINTER(m_ChildSeqNode) - DECLARE_POINTER(m_ParentSeqNode) - DECLARE_POINTER(m_Next) - DECLARE_POINTER(m_Prev) -END_POINTERS +IMPLEMENT_CLASS(DSeqNode, false, true) + +IMPLEMENT_POINTERS_START(DSeqNode) + IMPLEMENT_POINTER(m_ChildSeqNode) + IMPLEMENT_POINTER(m_ParentSeqNode) + IMPLEMENT_POINTER(m_Next) + IMPLEMENT_POINTER(m_Prev) +IMPLEMENT_POINTERS_END DSeqNode::DSeqNode () : m_SequenceChoices(0) @@ -427,9 +429,11 @@ FName DSeqNode::GetSequenceName () const return Sequences[m_Sequence]->SeqName; } -IMPLEMENT_POINTY_CLASS (DSeqActorNode) - DECLARE_POINTER (m_Actor) -END_POINTERS +IMPLEMENT_CLASS(DSeqActorNode, false, true) + +IMPLEMENT_POINTERS_START(DSeqActorNode) + IMPLEMENT_POINTER(m_Actor) +IMPLEMENT_POINTERS_END void DSeqActorNode::Serialize(FSerializer &arc) { @@ -437,7 +441,7 @@ void DSeqActorNode::Serialize(FSerializer &arc) arc("actor", m_Actor); } -IMPLEMENT_CLASS (DSeqPolyNode) +IMPLEMENT_CLASS(DSeqPolyNode, false, false) void DSeqPolyNode::Serialize(FSerializer &arc) { @@ -445,7 +449,7 @@ void DSeqPolyNode::Serialize(FSerializer &arc) arc("poly", m_Poly); } -IMPLEMENT_CLASS (DSeqSectorNode) +IMPLEMENT_CLASS(DSeqSectorNode, false, false) void DSeqSectorNode::Serialize(FSerializer &arc) { diff --git a/src/s_sndseq.h b/src/s_sndseq.h index 74ded5af47..13444f8628 100644 --- a/src/s_sndseq.h +++ b/src/s_sndseq.h @@ -22,7 +22,7 @@ class DSeqNode : public DObject public: void Serialize(FSerializer &arc); void StopAndDestroy (); - void Destroy (); + void Destroy() override; void Tick (); void ChangeData (int seqOffset, int delayTics, float volume, FSoundID currentSoundID); void AddChoice (int seqnum, seqtype_t type); diff --git a/src/s_sound.cpp b/src/s_sound.cpp index a51a7101be..fd15b94910 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -1232,6 +1232,16 @@ void S_Sound (int channel, FSoundID sound_id, float volume, float attenuation) S_StartSound (NULL, NULL, NULL, NULL, channel, sound_id, volume, attenuation); } +DEFINE_ACTION_FUNCTION(DObject, S_Sound) +{ + PARAM_PROLOGUE; + PARAM_SOUND(id); + PARAM_INT(channel); + PARAM_FLOAT_DEF(volume); + PARAM_FLOAT_DEF(attn); + return 0; +} + //========================================================================== // // S_Sound - An actor is source @@ -2597,6 +2607,17 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) return false; } +DEFINE_ACTION_FUNCTION(DObject, S_ChangeMusic) +{ + PARAM_PROLOGUE; + PARAM_STRING(music); + PARAM_INT_DEF(order); + PARAM_BOOL(looping); + PARAM_BOOL(force); + ACTION_RETURN_BOOL(S_ChangeMusic(music, order, looping, force)); +} + + //========================================================================== // // S_RestartMusic diff --git a/src/sc_man.cpp b/src/sc_man.cpp index 3f5530ff36..ccfb01ac52 100644 --- a/src/sc_man.cpp +++ b/src/sc_man.cpp @@ -1006,6 +1006,8 @@ void FScanner::CheckOpen() // //========================================================================== int FScriptPosition::ErrorCounter; +int FScriptPosition::WarnCounter; +bool FScriptPosition::StrictErrors; // makes all OPTERROR messages real errors. FScriptPosition::FScriptPosition(const FScriptPosition &other) { @@ -1044,10 +1046,13 @@ void FScriptPosition::Message (int severity, const char *message, ...) const { FString composed; - if ((severity == MSG_DEBUG || severity == MSG_DEBUGLOG) && developer < DMSG_NOTIFY) return; + if (severity == MSG_DEBUGLOG && developer < DMSG_NOTIFY) return; + if (severity == MSG_DEBUGERROR && developer < DMSG_ERROR) return; + if (severity == MSG_DEBUGWARN && developer < DMSG_WARNING) return; + if (severity == MSG_DEBUGMSG && developer < DMSG_NOTIFY) return; if (severity == MSG_OPTERROR) { - severity = strictdecorate ? MSG_ERROR : MSG_WARNING; + severity = StrictErrors || strictdecorate ? MSG_ERROR : MSG_WARNING; } if (message == NULL) @@ -1071,8 +1076,11 @@ void FScriptPosition::Message (int severity, const char *message, ...) const return; case MSG_WARNING: + case MSG_DEBUGWARN: + case MSG_DEBUGERROR: // This is intentionally not being printed as an 'error', the difference to MSG_DEBUGWARN is only the severity level at which it gets triggered. + WarnCounter++; type = "warning"; - color = TEXTCOLOR_YELLOW; + color = TEXTCOLOR_ORANGE; break; case MSG_ERROR: @@ -1082,7 +1090,7 @@ void FScriptPosition::Message (int severity, const char *message, ...) const break; case MSG_MESSAGE: - case MSG_DEBUG: + case MSG_DEBUGMSG: type = "message"; color = TEXTCOLOR_GREEN; break; diff --git a/src/sc_man.h b/src/sc_man.h index 359dd81405..fde6efbed3 100644 --- a/src/sc_man.h +++ b/src/sc_man.h @@ -125,7 +125,9 @@ enum MSG_FATAL, MSG_ERROR, MSG_OPTERROR, - MSG_DEBUG, + MSG_DEBUGERROR, + MSG_DEBUGWARN, + MSG_DEBUGMSG, MSG_LOG, MSG_DEBUGLOG, MSG_MESSAGE @@ -139,7 +141,9 @@ enum struct FScriptPosition { + static int WarnCounter; static int ErrorCounter; + static bool StrictErrors; FString FileName; int ScriptLine; @@ -154,6 +158,7 @@ struct FScriptPosition void Message(int severity, const char *message,...) const; static void ResetErrorCounter() { + WarnCounter = 0; ErrorCounter = 0; } }; diff --git a/src/sc_man_scanner.re b/src/sc_man_scanner.re index 92702f9186..8e4b42f690 100644 --- a/src/sc_man_scanner.re +++ b/src/sc_man_scanner.re @@ -111,6 +111,10 @@ std2: 'sbyte' { RET(TK_SByte); } 'short' { RET(TK_Short); } 'ushort' { RET(TK_UShort); } + 'int8' { RET(TK_Int8); } + 'uint8' { RET(TK_UInt8); } + 'int16' { RET(TK_Int16); } + 'uint16' { RET(TK_UInt16); } 'int' { RET(TK_Int); } 'uint' { RET(TK_UInt); } 'long' { RET(TK_Long); } @@ -118,14 +122,14 @@ std2: 'void' { RET(TK_Void); } 'struct' { RET(TK_Struct); } 'class' { RET(TK_Class); } - 'mode' { RET(TK_Mode); } 'enum' { RET(TK_Enum); } 'name' { RET(TK_Name); } 'string' { RET(TK_String); } 'sound' { RET(TK_Sound); } 'state' { RET(TK_State); } 'color' { RET(TK_Color); } - 'vector' { RET(TK_Vector); } + 'vector2' { RET(TK_Vector2); } + 'vector3' { RET(TK_Vector3); } 'map' { RET(TK_Map); } 'array' { RET(TK_Array); } 'in' { RET(TK_In); } @@ -152,26 +156,25 @@ std2: 'transient' { RET(TK_Transient); } 'final' { RET(TK_Final); } 'throws' { RET(TK_Throws); } - 'extends' { RET(TK_Extends); } + 'extend' { RET(TK_Extend); } 'public' { RET(TK_Public); } 'protected' { RET(TK_Protected); } 'private' { RET(TK_Private); } 'dot' { RET(TK_Dot); } 'cross' { RET(TK_Cross); } - 'ignores' { RET(TK_Ignores); } 'localized' { RET(TK_Localized); } 'latent' { RET(TK_Latent); } 'singular' { RET(TK_Singular); } 'config' { RET(TK_Config); } 'coerce' { RET(TK_Coerce); } - 'iterator' { RET(TK_Iterator); } 'optional' { RET(TK_Optional); } 'export' { RET(TK_Export); } 'virtual' { RET(TK_Virtual); } + 'override' { RET(TK_Override); } 'super' { RET(TK_Super); } 'global' { RET(TK_Global); } - 'self' { RET(TK_Self); } 'stop' { RET(TK_Stop); } + 'null' { RET(TK_Null); } 'is' { RET(TK_Is); } 'replaces' { RET(TK_Replaces); } @@ -180,6 +183,7 @@ std2: 'deprecated' { RET(TK_Deprecated); } 'action' { RET(TK_Action); } 'readonly' { RET(TK_ReadOnly); } + 'let' { RET(TK_Let); } /* Actor state options */ 'bright' { RET(StateOptions ? TK_Bright : TK_Identifier); } @@ -235,6 +239,7 @@ std2: "<>=" { RET(TK_LtGtEq); } "**" { RET(TK_MulMul); } "::" { RET(TK_ColonColon); } + "->" { RET(TK_Arrow); } ";" { StateOptions = false; RET(';'); } "{" { StateOptions = false; RET('{'); } "}" { RET('}'); } diff --git a/src/sc_man_tokens.h b/src/sc_man_tokens.h index 2464629409..efa479cf37 100644 --- a/src/sc_man_tokens.h +++ b/src/sc_man_tokens.h @@ -33,6 +33,7 @@ xx(TK_Neq, "'!='") xx(TK_ApproxEq, "'~=='") xx(TK_LtGtEq, "'<>='") xx(TK_MulMul, "'**'") +xx(TK_Arrow, "'->'") xx(TK_Action, "'action'") xx(TK_Break, "'break'") xx(TK_Case, "'case'") @@ -49,12 +50,17 @@ xx(TK_Until, "'until'") xx(TK_While, "'while'") xx(TK_Bool, "'bool'") xx(TK_Float, "'float'") +xx(TK_Float32, "'float32'") xx(TK_Double, "'double'") xx(TK_Char, "'char'") xx(TK_Byte, "'byte'") xx(TK_SByte, "'sbyte'") xx(TK_Short, "'short'") xx(TK_UShort, "'ushort'") +xx(TK_Int8, "'int8'") +xx(TK_UInt8, "'uint8'") +xx(TK_Int16, "'int16'") +xx(TK_UInt16, "'uint16'") xx(TK_Int, "'int'") xx(TK_UInt, "'uint'") xx(TK_Long, "'long'") @@ -62,7 +68,6 @@ xx(TK_ULong, "'ulong'") xx(TK_Void, "'void'") xx(TK_Struct, "'struct'") xx(TK_Class, "'class'") -xx(TK_Mode, "'mode'") xx(TK_Enum, "'enum'") xx(TK_Name, "'name'") xx(TK_String, "'string'") @@ -90,7 +95,7 @@ xx(TK_Transient, "'transient'") xx(TK_Volatile, "'volatile'") xx(TK_Final, "'final'") xx(TK_Throws, "'throws'") -xx(TK_Extends, "'extends'") +xx(TK_Extend, "'extend'") xx(TK_Public, "'public'") xx(TK_Protected, "'protected'") xx(TK_Private, "'private'") @@ -106,15 +111,17 @@ xx(TK_Iterator, "'iterator'") xx(TK_Optional, "'optional'") xx(TK_Export, "'expert'") xx(TK_Virtual, "'virtual'") +xx(TK_Override, "'override'") xx(TK_Super, "'super'") +xx(TK_Null, "'null'") xx(TK_Global, "'global'") -xx(TK_Self, "'self'") xx(TK_Stop, "'stop'") xx(TK_Include, "'include'") xx(TK_Is, "'is'") xx(TK_Replaces, "'replaces'") -xx(TK_Vector, "'vector'") +xx(TK_Vector2, "'vector2'") +xx(TK_Vector3, "'vector3'") xx(TK_Map, "'map'") xx(TK_Array, "'array'") xx(TK_In, "'in'") @@ -135,4 +142,5 @@ xx(TK_NoDelay, "'nodelay'") xx(TK_Offset, "'offset'") xx(TK_Slow, "'slow'") xx(TK_Bright, "'bright'") +xx(TK_Let, "'let'") #undef xx diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp new file mode 100644 index 0000000000..3895441d80 --- /dev/null +++ b/src/scripting/codegeneration/codegen.cpp @@ -0,0 +1,10141 @@ +/* +** thingdef_expression.cpp +** +** Expression evaluation +** +**--------------------------------------------------------------------------- +** Copyright 2008 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be +** covered by the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or (at +** your option) any later version. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include "actor.h" +#include "sc_man.h" +#include "tarray.h" +#include "templates.h" +#include "cmdlib.h" +#include "i_system.h" +#include "m_random.h" +#include "a_pickups.h" +#include "thingdef.h" +#include "p_lnspec.h" +#include "doomstat.h" +#include "codegen.h" +#include "m_fixed.h" +#include "vmbuilder.h" +#include "v_text.h" +#include "w_wad.h" +#include "math/cmath.h" + +extern FRandom pr_exrandom; +FMemArena FxAlloc(65536); + +struct FLOP +{ + ENamedName Name; + int Flop; + double (*Evaluate)(double); +}; + +// Decorate operates on degrees, so the evaluate functions need to convert +// degrees to radians for those that work with angles. +static const FLOP FxFlops[] = +{ + { NAME_Exp, FLOP_EXP, [](double v) { return g_exp(v); } }, + { NAME_Log, FLOP_LOG, [](double v) { return g_log(v); } }, + { NAME_Log10, FLOP_LOG10, [](double v) { return g_log10(v); } }, + { NAME_Sqrt, FLOP_SQRT, [](double v) { return g_sqrt(v); } }, + { NAME_Ceil, FLOP_CEIL, [](double v) { return ceil(v); } }, + { NAME_Floor, FLOP_FLOOR, [](double v) { return floor(v); } }, + + { NAME_ACos, FLOP_ACOS_DEG, [](double v) { return g_acos(v) * (180.0 / M_PI); } }, + { NAME_ASin, FLOP_ASIN_DEG, [](double v) { return g_asin(v) * (180.0 / M_PI); } }, + { NAME_ATan, FLOP_ATAN_DEG, [](double v) { return g_atan(v) * (180.0 / M_PI); } }, + { NAME_Cos, FLOP_COS_DEG, [](double v) { return g_cosdeg(v); } }, + { NAME_Sin, FLOP_SIN_DEG, [](double v) { return g_sindeg(v); } }, + { NAME_Tan, FLOP_TAN_DEG, [](double v) { return g_tan(v * (M_PI / 180.0)); } }, + + { NAME_CosH, FLOP_COSH, [](double v) { return g_cosh(v); } }, + { NAME_SinH, FLOP_SINH, [](double v) { return g_sinh(v); } }, + { NAME_TanH, FLOP_TANH, [](double v) { return g_tanh(v); } }, +}; + +//========================================================================== +// +// FCompileContext +// +//========================================================================== + +FCompileContext::FCompileContext(PFunction *fnc, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump) + : ReturnProto(ret), Function(fnc), Class(nullptr), FromDecorate(fromdecorate), StateIndex(stateindex), StateCount(statecount), Lump(lump) +{ + if (fnc != nullptr) Class = fnc->OwningClass; +} + +FCompileContext::FCompileContext(PStruct *cls, bool fromdecorate) + : ReturnProto(nullptr), Function(nullptr), Class(cls), FromDecorate(fromdecorate), StateIndex(-1), StateCount(0), Lump(-1) +{ +} + +PSymbol *FCompileContext::FindInClass(FName identifier, PSymbolTable *&symt) +{ + return Class != nullptr? Class->Symbols.FindSymbolInTable(identifier, symt) : nullptr; +} + +PSymbol *FCompileContext::FindInSelfClass(FName identifier, PSymbolTable *&symt) +{ + // If we have no self we cannot retrieve any values from it. + if (Function == nullptr || Function->Variants[0].SelfClass == nullptr) return nullptr; + return Function->Variants[0].SelfClass->Symbols.FindSymbolInTable(identifier, symt); +} +PSymbol *FCompileContext::FindGlobal(FName identifier) +{ + return GlobalSymbols.FindSymbol(identifier, true); +} + +void FCompileContext::CheckReturn(PPrototype *proto, FScriptPosition &pos) +{ + assert(proto != nullptr); + bool fail = false; + + if (ReturnProto == nullptr) + { + ReturnProto = proto; + return; + } + + // A prototype that defines fewer return types can be compatible with + // one that defines more if the shorter one matches the initial types + // for the longer one. + if (ReturnProto->ReturnTypes.Size() < proto->ReturnTypes.Size()) + { // Make proto the shorter one to avoid code duplication below. + swapvalues(proto, ReturnProto); + } + // If one prototype returns nothing, they both must. + if (proto->ReturnTypes.Size() == 0) + { + if (ReturnProto->ReturnTypes.Size() != 0) + { + fail = true; + } + } + else + { + for (unsigned i = 0; i < proto->ReturnTypes.Size(); i++) + { + if (ReturnProto->ReturnTypes[i] != proto->ReturnTypes[i]) + { // Incompatible + fail = true; + break; + } + } + } + + if (fail) + { + pos.Message(MSG_ERROR, "Return type mismatch"); + } +} + +bool FCompileContext::CheckReadOnly(int flags) +{ + if (!(flags & VARF_ReadOnly)) return false; + if (!(flags & VARF_InternalAccess)) return true; + return Wads.GetLumpFile(Lump) != 0; +} + +FxLocalVariableDeclaration *FCompileContext::FindLocalVariable(FName name) +{ + if (Block == nullptr) + { + return nullptr; + } + else + { + return Block->FindLocalVariable(name, *this); + } +} + +static PStruct *FindStructType(FName name) +{ + PStruct *ccls = PClass::FindClass(name); + if (ccls == nullptr) + { + ccls = dyn_cast(TypeTable.FindType(RUNTIME_CLASS(PStruct), 0, (intptr_t)name, nullptr)); + if (ccls == nullptr) ccls = dyn_cast(TypeTable.FindType(RUNTIME_CLASS(PNativeStruct), 0, (intptr_t)name, nullptr)); + } + return ccls; +} +//========================================================================== +// +// ExpEmit +// +//========================================================================== + +ExpEmit::ExpEmit(VMFunctionBuilder *build, int type, int count) +: RegNum(build->Registers[type].Get(count)), RegType(type), RegCount(count), Konst(false), Fixed(false), Final(false), Target(false) +{ +} + +void ExpEmit::Free(VMFunctionBuilder *build) +{ + if (!Fixed && !Konst && RegType <= REGT_TYPE) + { + build->Registers[RegType].Return(RegNum, RegCount); + } +} + +void ExpEmit::Reuse(VMFunctionBuilder *build) +{ + if (!Fixed && !Konst) + { + assert(RegCount == 1); + bool success = build->Registers[RegType].Reuse(RegNum); + assert(success && "Attempt to reuse a register that is already in use"); + } +} + +//========================================================================== +// +// FindBuiltinFunction +// +// Returns the symbol for a decorate utility function. If not found, create +// it and install it a local symbol table. +// +//========================================================================== + +static PSymbol *FindBuiltinFunction(FName funcname, VMNativeFunction::NativeCallType func) +{ + PSymbol *sym = GlobalSymbols.FindSymbol(funcname, false); + if (sym == nullptr) + { + PSymbolVMFunction *symfunc = new PSymbolVMFunction(funcname); + VMNativeFunction *calldec = new VMNativeFunction(func, funcname); + calldec->PrintableName = funcname.GetChars(); + symfunc->Function = calldec; + sym = symfunc; + GlobalSymbols.AddSymbol(sym); + } + return sym; +} + +//========================================================================== +// +// +// +//========================================================================== + +static bool AreCompatiblePointerTypes(PType *dest, PType *source, bool forcompare = false) +{ + if (dest->IsKindOf(RUNTIME_CLASS(PPointer)) && source->IsKindOf(RUNTIME_CLASS(PPointer))) + { + // Pointers to different types are only compatible if both point to an object and the source type is a child of the destination type. + auto fromtype = static_cast(source); + auto totype = static_cast(dest); + if (fromtype == nullptr) return true; + if (!forcompare && totype->IsConst != fromtype->IsConst) return false; + if (fromtype == totype) return true; + if (fromtype->PointedType->IsKindOf(RUNTIME_CLASS(PClass)) && totype->PointedType->IsKindOf(RUNTIME_CLASS(PClass))) + { + auto fromcls = static_cast(fromtype->PointedType); + auto tocls = static_cast(totype->PointedType); + if (forcompare && tocls->IsDescendantOf(fromcls)) return true; + return (fromcls->IsDescendantOf(tocls)); + } + } + return false; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxExpression::Emit (VMFunctionBuilder *build) +{ + ScriptPosition.Message(MSG_ERROR, "Unemitted expression found"); + return ExpEmit(); +} + + +//========================================================================== +// +// Emits a statement and records its position in the source. +// +//========================================================================== + +void FxExpression::EmitStatement(VMFunctionBuilder *build) +{ + build->BeginStatement(this); + ExpEmit exp = Emit(build); + exp.Free(build); + build->EndStatement(); +} + + +//========================================================================== +// +// +// +//========================================================================== + +void FxExpression::EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no) +{ + ExpEmit op = Emit(build); + ExpEmit i; + assert(op.RegType != REGT_NIL && op.RegCount == 1 && !op.Konst); + switch (op.RegType) + { + case REGT_INT: + build->Emit(OP_EQ_K, !invert, op.RegNum, build->GetConstantInt(0)); + break; + + case REGT_FLOAT: + build->Emit(OP_EQF_K, !invert, op.RegNum, build->GetConstantFloat(0)); + break; + + case REGT_POINTER: + build->Emit(OP_EQA_K, !invert, op.RegNum, build->GetConstantAddress(0, ATAG_GENERIC)); + break; + + case REGT_STRING: + i = ExpEmit(build, REGT_INT); + build->Emit(OP_LENS, i.RegNum, op.RegNum); + build->Emit(OP_EQ_K, !invert, i.RegNum, build->GetConstantInt(0)); + i.Free(build); + break; + + default: + break; + } + patchspots_no.Push(build->Emit(OP_JMP, 0)); + op.Free(build); +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FxExpression::isConstant() const +{ + return false; +} + +//========================================================================== +// +// +// +//========================================================================== + +VMFunction *FxExpression::GetDirectFunction() +{ + return nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxExpression::Resolve(FCompileContext &ctx) +{ + isresolved = true; + return this; +} + +//========================================================================== +// +// Returns true if we can write to the address. +// +//========================================================================== + +bool FxExpression::RequestAddress(FCompileContext &ctx, bool *writable) +{ + if (writable != nullptr) *writable = false; + return false; +} + +//========================================================================== +// +// Called by return statements. +// +//========================================================================== + +PPrototype *FxExpression::ReturnProto() +{ + assert(ValueType != nullptr); + + TArray ret(0); + TArray none(0); + if (ValueType != TypeVoid) + { + ret.Push(ValueType); + } + + return NewPrototype(ret, none); +} + +//========================================================================== +// +// +// +//========================================================================== + +static int EncodeRegType(ExpEmit reg) +{ + int regtype = reg.RegType; + if (reg.Konst) + { + regtype |= REGT_KONST; + } + else if (reg.RegCount == 2) + { + regtype |= REGT_MULTIREG2; + + } + else if (reg.RegCount == 3) + { + regtype |= REGT_MULTIREG3; + } + return regtype; +} + +//========================================================================== +// +// +// +//========================================================================== + +static int EmitParameter(VMFunctionBuilder *build, FxExpression *operand, const FScriptPosition &pos) +{ + ExpEmit where = operand->Emit(build); + + if (where.RegType == REGT_NIL) + { + pos.Message(MSG_ERROR, "Attempted to pass a non-value"); + build->Emit(OP_PARAM, 0, where.RegType, where.RegNum); + return 1; + } + else + { + build->Emit(OP_PARAM, 0, EncodeRegType(where), where.RegNum); + where.Free(build); + return where.RegCount; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxConstant::MakeConstant(PSymbol *sym, const FScriptPosition &pos) +{ + FxExpression *x; + PSymbolConstNumeric *csym = dyn_cast(sym); + if (csym != nullptr) + { + if (csym->ValueType->IsA(RUNTIME_CLASS(PInt))) + { + x = new FxConstant(csym->Value, pos); + } + else if (csym->ValueType->IsA(RUNTIME_CLASS(PFloat))) + { + x = new FxConstant(csym->Float, pos); + } + else + { + pos.Message(MSG_ERROR, "Invalid constant '%s'\n", csym->SymbolName.GetChars()); + return nullptr; + } + } + else + { + pos.Message(MSG_ERROR, "'%s' is not a constant\n", sym->SymbolName.GetChars()); + x = nullptr; + } + return x; +} + +ExpEmit FxConstant::Emit(VMFunctionBuilder *build) +{ + ExpEmit out; + + out.Konst = true; + int regtype = value.Type->GetRegType(); + out.RegType = regtype; + if (regtype == REGT_INT) + { + out.RegNum = build->GetConstantInt(value.Int); + } + else if (regtype == REGT_FLOAT) + { + out.RegNum = build->GetConstantFloat(value.Float); + } + else if (regtype == REGT_POINTER) + { + VM_ATAG tag = ATAG_GENERIC; + if (value.Type == TypeState) + { + tag = ATAG_STATE; + } + else if (value.Type->GetLoadOp() == OP_LO) + { + tag = ATAG_OBJECT; + } + out.RegNum = build->GetConstantAddress(value.pointer, tag); + } + else if (regtype == REGT_STRING) + { + out.RegNum = build->GetConstantString(value.GetString()); + } + else + { + ScriptPosition.Message(MSG_ERROR, "Cannot emit needed constant"); + out.RegNum = 0; + } + return out; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxVectorValue::FxVectorValue(FxExpression *x, FxExpression *y, FxExpression *z, const FScriptPosition &sc) + :FxExpression(EFX_VectorValue, sc) +{ + xyz[0] = x; + xyz[1] = y; + xyz[2] = z; + isConst = false; + ValueType = TypeVoid; // we do not know yet +} + +FxVectorValue::~FxVectorValue() +{ + for (auto &a : xyz) + { + SAFE_DELETE(a); + } +} + +FxExpression *FxVectorValue::Resolve(FCompileContext&ctx) +{ + bool fails = false; + + for (auto &a : xyz) + { + if (a != nullptr) + { + a = a->Resolve(ctx); + if (a == nullptr) fails = true; + else + { + if (a->ValueType != TypeVector2) // a vec3 may be initialized with (vec2, z) + { + a = new FxFloatCast(a); + a = a->Resolve(ctx); + fails |= (a == nullptr); + } + } + } + } + if (fails) + { + delete this; + return nullptr; + } + // at this point there are three legal cases: + // * two floats = vector2 + // * three floats = vector3 + // * vector2 + float = vector3 + if (xyz[0]->ValueType == TypeVector2) + { + if (xyz[1]->ValueType != TypeFloat64 || xyz[2] != nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Not a valid vector"); + delete this; + return nullptr; + } + ValueType = TypeVector3; + if (xyz[0]->ExprType == EFX_VectorValue) + { + // If two vector initializers are nested, unnest them now. + auto vi = static_cast(xyz[0]); + xyz[2] = xyz[1]; + xyz[1] = vi->xyz[1]; + xyz[0] = vi->xyz[0]; + vi->xyz[0] = vi->xyz[1] = nullptr; // Don't delete our own expressions. + delete vi; + } + } + else if (xyz[0]->ValueType == TypeFloat64 && xyz[1]->ValueType == TypeFloat64) + { + ValueType = xyz[2] == nullptr ? TypeVector2 : TypeVector3; + } + else + { + ScriptPosition.Message(MSG_ERROR, "Not a valid vector"); + delete this; + return nullptr; + } + + // check if all elements are constant. If so this can be emitted as a constant vector. + isConst = true; + for (auto &a : xyz) + { + if (a != nullptr && !a->isConstant()) isConst = false; + } + return this; +} + +static ExpEmit EmitKonst(VMFunctionBuilder *build, ExpEmit &emit) +{ + if (emit.Konst) + { + ExpEmit out(build, REGT_FLOAT); + build->Emit(OP_LKF, out.RegNum, emit.RegNum); + return out; + } + return emit; +} + +ExpEmit FxVectorValue::Emit(VMFunctionBuilder *build) +{ + // no const handling here. Ultimately it's too rarely used (i.e. the only fully constant vector ever allocated in ZDoom is the 0-vector in a very few places) + // and the negatives (excessive allocation of float constants) outweigh the positives (saved a few instructions) + assert(xyz[0] != nullptr); + assert(xyz[1] != nullptr); + if (ValueType == TypeVector2) + { + ExpEmit tempxval = xyz[0]->Emit(build); + ExpEmit tempyval = xyz[1]->Emit(build); + ExpEmit xval = EmitKonst(build, tempxval); + ExpEmit yval = EmitKonst(build, tempyval); + assert(xval.RegType == REGT_FLOAT && yval.RegType == REGT_FLOAT); + if (yval.RegNum == xval.RegNum + 1) + { + // The results are already in two continuous registers so just return them as-is. + xval.RegCount++; + return xval; + } + else + { + // The values are not in continuous registers so they need to be copied together now. + ExpEmit out(build, REGT_FLOAT, 2); + build->Emit(OP_MOVEF, out.RegNum, xval.RegNum); + build->Emit(OP_MOVEF, out.RegNum + 1, yval.RegNum); + xval.Free(build); + yval.Free(build); + return out; + } + } + else if (xyz[0]->ValueType == TypeVector2) // vec2+float + { + ExpEmit xyval = xyz[0]->Emit(build); + ExpEmit tempzval = xyz[1]->Emit(build); + ExpEmit zval = EmitKonst(build, tempzval); + assert(xyval.RegType == REGT_FLOAT && xyval.RegCount == 2 && zval.RegType == REGT_FLOAT); + if (zval.RegNum == xyval.RegNum + 2) + { + // The results are already in three continuous registers so just return them as-is. + xyval.RegCount++; + return xyval; + } + else + { + // The values are not in continuous registers so they need to be copied together now. + ExpEmit out(build, REGT_FLOAT, 3); + build->Emit(OP_MOVEV2, out.RegNum, xyval.RegNum); + build->Emit(OP_MOVEF, out.RegNum + 2, zval.RegNum); + xyval.Free(build); + zval.Free(build); + return out; + } + } + else // 3*float + { + assert(xyz[2] != nullptr); + ExpEmit tempxval = xyz[0]->Emit(build); + ExpEmit tempyval = xyz[1]->Emit(build); + ExpEmit tempzval = xyz[2]->Emit(build); + ExpEmit xval = EmitKonst(build, tempxval); + ExpEmit yval = EmitKonst(build, tempyval); + ExpEmit zval = EmitKonst(build, tempzval); + assert(xval.RegType == REGT_FLOAT && yval.RegType == REGT_FLOAT && zval.RegType == REGT_FLOAT); + if (yval.RegNum == xval.RegNum + 1 && zval.RegNum == xval.RegNum + 2) + { + // The results are already in three continuous registers so just return them as-is. + xval.RegCount += 2; + return xval; + } + else + { + // The values are not in continuous registers so they need to be copied together now. + ExpEmit out(build, REGT_FLOAT, 3); + //Try to optimize a bit... + if (yval.RegNum == xval.RegNum + 1) + { + build->Emit(OP_MOVEV2, out.RegNum, xval.RegNum); + build->Emit(OP_MOVEF, out.RegNum + 2, zval.RegNum); + } + else if (zval.RegNum == yval.RegNum + 1) + { + build->Emit(OP_MOVEF, out.RegNum, xval.RegNum); + build->Emit(OP_MOVEV2, out.RegNum+1, yval.RegNum); + } + else + { + build->Emit(OP_MOVEF, out.RegNum, xval.RegNum); + build->Emit(OP_MOVEF, out.RegNum + 1, yval.RegNum); + build->Emit(OP_MOVEF, out.RegNum + 2, zval.RegNum); + } + xval.Free(build); + yval.Free(build); + zval.Free(build); + return out; + } + } +} + +//========================================================================== +// +// +// +//========================================================================== + +FxBoolCast::FxBoolCast(FxExpression *x, bool needvalue) + : FxExpression(EFX_BoolCast, x->ScriptPosition) +{ + basex = x; + ValueType = TypeBool; + NeedValue = needvalue; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxBoolCast::~FxBoolCast() +{ + SAFE_DELETE(basex); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxBoolCast::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(basex, ctx); + + if (basex->ValueType == TypeBool) + { + FxExpression *x = basex; + basex = nullptr; + delete this; + return x; + } + else if (basex->IsBoolCompat()) + { + if (basex->isConstant()) + { + assert(basex->ValueType != TypeState && "We shouldn't be able to generate a constant state ref"); + + ExpVal constval = static_cast(basex)->GetValue(); + FxExpression *x = new FxConstant(constval.GetBool(), ScriptPosition); + delete this; + return x; + } + return this; + } + ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxBoolCast::Emit(VMFunctionBuilder *build) +{ + ExpEmit from = basex->Emit(build); + assert(!from.Konst); + assert(basex->ValueType->GetRegType() == REGT_INT || basex->ValueType->GetRegType() == REGT_FLOAT || basex->ValueType->GetRegType() == REGT_POINTER); + + if (NeedValue) + { + ExpEmit to(build, REGT_INT); + from.Free(build); + build->Emit(OP_CASTB, to.RegNum, from.RegNum, from.RegType == REGT_INT ? CASTB_I : from.RegType == REGT_FLOAT ? CASTB_F : CASTB_A); + return to; + } + else + { + return from; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +void FxBoolCast::EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no) +{ + basex->EmitCompare(build, invert, patchspots_yes, patchspots_no); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxIntCast::FxIntCast(FxExpression *x, bool nowarn, bool explicitly) +: FxExpression(EFX_IntCast, x->ScriptPosition) +{ + basex=x; + ValueType = TypeSInt32; + NoWarn = nowarn; + Explicit = explicitly; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxIntCast::~FxIntCast() +{ + SAFE_DELETE(basex); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxIntCast::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(basex, ctx); + + if (basex->ValueType->GetRegType() == REGT_INT) + { + if (basex->ValueType->isNumeric() || Explicit) // names can be converted to int, but only with an explicit type cast. + { + FxExpression *x = basex; + x->ValueType = ValueType; + basex = nullptr; + delete this; + return x; + } + else + { + // Ugh. This should abort, but too many mods fell into this logic hole somewhere, so this serious error needs to be reduced to a warning. :( + // At least in ZScript, MSG_OPTERROR always means to report an error, not a warning so the problem only exists in DECORATE. + if (!basex->isConstant()) + ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got a name"); + else ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got \"%s\"", static_cast(basex)->GetValue().GetName().GetChars()); + FxExpression * x = new FxConstant(0, ScriptPosition); + delete this; + return x; + } + } + else if (basex->IsFloat()) + { + if (basex->isConstant()) + { + ExpVal constval = static_cast(basex)->GetValue(); + FxExpression *x = new FxConstant(constval.GetInt(), ScriptPosition); + if (constval.GetInt() != constval.GetFloat()) + { + ScriptPosition.Message(MSG_WARNING, "Truncation of floating point constant %f", constval.GetFloat()); + } + + delete this; + return x; + } + else if (!NoWarn) + { + ScriptPosition.Message(MSG_DEBUGWARN, "Truncation of floating point value"); + } + + return this; + } + ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxIntCast::Emit(VMFunctionBuilder *build) +{ + ExpEmit from = basex->Emit(build); + assert(!from.Konst); + assert(basex->ValueType->GetRegType() == REGT_FLOAT); + from.Free(build); + ExpEmit to(build, REGT_INT); + build->Emit(OP_CAST, to.RegNum, from.RegNum, ValueType == TypeUInt32? CAST_F2U : CAST_F2I); + return to; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxFloatCast::FxFloatCast(FxExpression *x) + : FxExpression(EFX_FloatCast, x->ScriptPosition) +{ + basex = x; + ValueType = TypeFloat64; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxFloatCast::~FxFloatCast() +{ + SAFE_DELETE(basex); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxFloatCast::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(basex, ctx); + + if (basex->IsFloat()) + { + FxExpression *x = basex; + basex = nullptr; + delete this; + return x; + } + else if (basex->ValueType->GetRegType() == REGT_INT) + { + if (basex->ValueType->isNumeric()) + { + if (basex->isConstant()) + { + ExpVal constval = static_cast(basex)->GetValue(); + FxExpression *x = new FxConstant(constval.GetFloat(), ScriptPosition); + delete this; + return x; + } + return this; + } + else + { + // Ugh. This should abort, but too many mods fell into this logic hole somewhere, so this seroious error needs to be reduced to a warning. :( + // At least in ZScript, MSG_OPTERROR always means to report an error, not a warning so the problem only exists in DECORATE. + if (!basex->isConstant()) ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got a name"); + else ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got \"%s\"", static_cast(basex)->GetValue().GetName().GetChars()); + FxExpression *x = new FxConstant(0.0, ScriptPosition); + delete this; + return x; + } + } + else + { + ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return nullptr; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxFloatCast::Emit(VMFunctionBuilder *build) +{ + ExpEmit from = basex->Emit(build); + assert(!from.Konst); + assert(basex->ValueType->GetRegType() == REGT_INT); + from.Free(build); + ExpEmit to(build, REGT_FLOAT); + build->Emit(OP_CAST, to.RegNum, from.RegNum, basex->ValueType == TypeUInt32? CAST_U2F : CAST_I2F); + return to; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxNameCast::FxNameCast(FxExpression *x) + : FxExpression(EFX_NameCast, x->ScriptPosition) +{ + basex = x; + ValueType = TypeName; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxNameCast::~FxNameCast() +{ + SAFE_DELETE(basex); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxNameCast::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(basex, ctx); + + if (basex->ValueType == TypeName) + { + FxExpression *x = basex; + basex = nullptr; + delete this; + return x; + } + else if (basex->ValueType == TypeString) + { + if (basex->isConstant()) + { + ExpVal constval = static_cast(basex)->GetValue(); + FxExpression *x = new FxConstant(constval.GetName(), ScriptPosition); + delete this; + return x; + } + return this; + } + else + { + ScriptPosition.Message(MSG_ERROR, "Cannot convert to name"); + delete this; + return nullptr; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxNameCast::Emit(VMFunctionBuilder *build) +{ + ExpEmit from = basex->Emit(build); + assert(!from.Konst); + assert(basex->ValueType == TypeString); + from.Free(build); + ExpEmit to(build, REGT_INT); + build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_S2N); + return to; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxStringCast::FxStringCast(FxExpression *x) + : FxExpression(EFX_StringCast, x->ScriptPosition) +{ + basex = x; + ValueType = TypeString; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxStringCast::~FxStringCast() +{ + SAFE_DELETE(basex); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxStringCast::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(basex, ctx); + + if (basex->ValueType == TypeString) + { + FxExpression *x = basex; + basex = nullptr; + delete this; + return x; + } + else if (basex->ValueType == TypeName) + { + if (basex->isConstant()) + { + ExpVal constval = static_cast(basex)->GetValue(); + FxExpression *x = new FxConstant(constval.GetString(), ScriptPosition); + delete this; + return x; + } + return this; + } + else if (basex->ValueType == TypeSound) + { + if (basex->isConstant()) + { + ExpVal constval = static_cast(basex)->GetValue(); + FxExpression *x = new FxConstant(S_sfx[constval.GetInt()].name, ScriptPosition); + delete this; + return x; + } + return this; + } + // although it could be done, let's not convert colors back to strings. + else + { + ScriptPosition.Message(MSG_ERROR, "Cannot convert to string"); + delete this; + return nullptr; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxStringCast::Emit(VMFunctionBuilder *build) +{ + ExpEmit from = basex->Emit(build); + assert(!from.Konst); + + from.Free(build); + ExpEmit to(build, REGT_STRING); + if (basex->ValueType == TypeName) + { + build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_N2S); + } + else if (basex->ValueType == TypeSound) + { + build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_So2S); + } + return to; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxColorCast::FxColorCast(FxExpression *x) + : FxExpression(EFX_ColorCast, x->ScriptPosition) +{ + basex = x; + ValueType = TypeColor; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxColorCast::~FxColorCast() +{ + SAFE_DELETE(basex); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxColorCast::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(basex, ctx); + + if (basex->ValueType == TypeColor || basex->ValueType->GetClass() == RUNTIME_CLASS(PInt)) + { + FxExpression *x = basex; + x->ValueType = TypeColor; + basex = nullptr; + delete this; + return x; + } + else if (basex->ValueType == TypeString) + { + if (basex->isConstant()) + { + ExpVal constval = static_cast(basex)->GetValue(); + if (constval.GetString().Len() == 0) + { + // empty string means 'no state'. This would otherwise just cause endless errors and have the same result anyway. + FxExpression *x = new FxConstant(-1, ScriptPosition); + delete this; + return x; + } + else + { + FxExpression *x = new FxConstant(V_GetColor(nullptr, constval.GetString(), &ScriptPosition), ScriptPosition); + delete this; + return x; + } + } + return this; + } + else + { + ScriptPosition.Message(MSG_ERROR, "Cannot convert to color"); + delete this; + return nullptr; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxColorCast::Emit(VMFunctionBuilder *build) +{ + ExpEmit from = basex->Emit(build); + assert(!from.Konst); + assert(basex->ValueType == TypeString); + from.Free(build); + ExpEmit to(build, REGT_INT); + build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_S2Co); + return to; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxSoundCast::FxSoundCast(FxExpression *x) + : FxExpression(EFX_SoundCast, x->ScriptPosition) +{ + basex = x; + ValueType = TypeSound; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxSoundCast::~FxSoundCast() +{ + SAFE_DELETE(basex); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxSoundCast::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(basex, ctx); + + if (basex->ValueType == TypeSound || basex->ValueType->GetClass() == RUNTIME_CLASS(PInt)) + { + FxExpression *x = basex; + x->ValueType = TypeSound; + basex = nullptr; + delete this; + return x; + } + else if (basex->ValueType == TypeString) + { + if (basex->isConstant()) + { + ExpVal constval = static_cast(basex)->GetValue(); + FxExpression *x = new FxConstant(FSoundID(constval.GetString()), ScriptPosition); + delete this; + return x; + } + return this; + } + else + { + ScriptPosition.Message(MSG_ERROR, "Cannot convert to sound"); + delete this; + return nullptr; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxSoundCast::Emit(VMFunctionBuilder *build) +{ + ExpEmit from = basex->Emit(build); + assert(!from.Konst); + assert(basex->ValueType == TypeString); + from.Free(build); + ExpEmit to(build, REGT_INT); + build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_S2So); + return to; +} + +//========================================================================== +// +// generic type cast operator +// +//========================================================================== + +FxTypeCast::FxTypeCast(FxExpression *x, PType *type, bool nowarn, bool explicitly) + : FxExpression(EFX_TypeCast, x->ScriptPosition) +{ + basex = x; + ValueType = type; + NoWarn = nowarn; + Explicit = explicitly; + assert(ValueType != nullptr); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxTypeCast::~FxTypeCast() +{ + SAFE_DELETE(basex); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(basex, ctx); + + // first deal with the simple types + if (ValueType == TypeError || basex->ValueType == TypeError) + { + ScriptPosition.Message(MSG_ERROR, "Trying to cast to invalid type."); + delete this; + return nullptr; + } + else if (ValueType == TypeVoid) // this should never happen + { + goto errormsg; + } + else if (basex->ValueType == TypeVoid) + { + goto errormsg; + } + else if (basex->ValueType == ValueType) + { + // don't go through the entire list if the types are the same. + goto basereturn; + } + else if (basex->ValueType == TypeNullPtr && (ValueType == TypeState || ValueType->IsKindOf(RUNTIME_CLASS(PPointer)))) + { + goto basereturn; + } + else if (IsFloat()) + { + FxExpression *x = new FxFloatCast(basex); + x = x->Resolve(ctx); + basex = nullptr; + delete this; + return x; + } + else if (ValueType->IsA(RUNTIME_CLASS(PInt))) + { + // This is only for casting to actual ints. Subtypes representing an int will be handled elsewhere. + FxExpression *x = new FxIntCast(basex, NoWarn, Explicit); + x = x->Resolve(ctx); + basex = nullptr; + delete this; + return x; + } + else if (ValueType == TypeBool) + { + FxExpression *x = new FxBoolCast(basex); + x = x->Resolve(ctx); + basex = nullptr; + delete this; + return x; + } + else if (ValueType == TypeString) + { + FxExpression *x = new FxStringCast(basex); + x = x->Resolve(ctx); + basex = nullptr; + delete this; + return x; + } + else if (ValueType == TypeName) + { + FxExpression *x = new FxNameCast(basex); + x = x->Resolve(ctx); + basex = nullptr; + delete this; + return x; + } + else if (ValueType == TypeSound) + { + FxExpression *x = new FxSoundCast(basex); + x = x->Resolve(ctx); + basex = nullptr; + delete this; + return x; + } + else if (ValueType == TypeColor) + { + FxExpression *x = new FxColorCast(basex); + x = x->Resolve(ctx); + basex = nullptr; + delete this; + return x; + } + else if (ValueType == TypeSpriteID && basex->IsInteger()) + { + basex->ValueType = TypeSpriteID; + auto x = basex; + basex = nullptr; + delete this; + return x; + } + else if (ValueType == TypeStateLabel) + { + if (basex->ValueType == TypeNullPtr) + { + auto x = new FxConstant(0, ScriptPosition); + x->ValueType = TypeStateLabel; + delete this; + return x; + } + // Right now this only supports string constants. There should be an option to pass a string variable, too. + if (basex->isConstant() && (basex->ValueType == TypeString || basex->ValueType == TypeName)) + { + FString s= static_cast(basex)->GetValue().GetString(); + if (s.Len() == 0 && !ctx.FromDecorate) // DECORATE should never get here at all, but let's better be safe. + { + ScriptPosition.Message(MSG_ERROR, "State jump to empty label."); + delete this; + return nullptr; + } + FxExpression *x = new FxMultiNameState(s, basex->ScriptPosition); + x = x->Resolve(ctx); + basex = nullptr; + delete this; + return x; + } + else if (basex->IsNumeric() && basex->ValueType != TypeSound && basex->ValueType != TypeColor) + { + if (ctx.StateIndex < 0) + { + ScriptPosition.Message(MSG_ERROR, "State jumps with index can only be used in anonymous state functions."); + delete this; + return nullptr; + } + if (ctx.StateCount != 1) + { + ScriptPosition.Message(MSG_ERROR, "State jumps with index cannot be used on multistate definitions"); + delete this; + return nullptr; + } + if (basex->isConstant()) + { + int i = static_cast(basex)->GetValue().GetInt(); + if (i <= 0) + { + ScriptPosition.Message(MSG_ERROR, "State index must be positive"); + delete this; + return nullptr; + } + FxExpression *x = new FxStateByIndex(ctx.StateIndex + i, ScriptPosition); + x = x->Resolve(ctx); + basex = nullptr; + delete this; + return x; + } + else + { + FxExpression *x = new FxRuntimeStateIndex(basex); + x = x->Resolve(ctx); + basex = nullptr; + delete this; + return x; + } + } + } + else if (ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer))) + { + FxExpression *x = new FxClassTypeCast(static_cast(ValueType), basex); + x = x->Resolve(ctx); + basex = nullptr; + delete this; + return x; + } + /* else if (ValueType->IsKindOf(RUNTIME_CLASS(PEnum))) + { + // this is not yet ready and does not get assigned to actual values. + } + */ + else if (ValueType->IsKindOf(RUNTIME_CLASS(PClass))) // this should never happen because the VM doesn't handle plain class types - just pointers + { + if (basex->ValueType->IsKindOf(RUNTIME_CLASS(PClass))) + { + // class types are only compatible if the base type is a descendant of the result type. + auto fromtype = static_cast(basex->ValueType); + auto totype = static_cast(ValueType); + if (fromtype->IsDescendantOf(totype)) goto basereturn; + } + } + else if (AreCompatiblePointerTypes(ValueType, basex->ValueType)) + { + goto basereturn; + } + // todo: pointers to class objects. + // All other types are only compatible to themselves and have already been handled above by the equality check. + // Anything that falls through here is not compatible and must print an error. + +errormsg: + ScriptPosition.Message(MSG_ERROR, "Cannot convert %s to %s", basex->ValueType->DescriptiveName(), ValueType->DescriptiveName()); + delete this; + return nullptr; + +basereturn: + auto x = basex; + x->ValueType = ValueType; + basex = nullptr; + delete this; + return x; + +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxTypeCast::Emit(VMFunctionBuilder *build) +{ + assert(false); + // This should never be reached + return ExpEmit(); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxPlusSign::FxPlusSign(FxExpression *operand) +: FxExpression(EFX_PlusSign, operand->ScriptPosition) +{ + Operand=operand; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxPlusSign::~FxPlusSign() +{ + SAFE_DELETE(Operand); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxPlusSign::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Operand, ctx); + + if (Operand->IsNumeric() || Operand->IsVector()) + { + FxExpression *e = Operand; + Operand = nullptr; + delete this; + return e; + } + else + { + ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return nullptr; + } +} + +ExpEmit FxPlusSign::Emit(VMFunctionBuilder *build) +{ + return Operand->Emit(build); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxMinusSign::FxMinusSign(FxExpression *operand) +: FxExpression(EFX_MinusSign, operand->ScriptPosition) +{ + Operand=operand; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxMinusSign::~FxMinusSign() +{ + SAFE_DELETE(Operand); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxMinusSign::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Operand, ctx); + + if (Operand->IsNumeric() || Operand->IsVector()) + { + if (Operand->isConstant()) + { + ExpVal val = static_cast(Operand)->GetValue(); + FxExpression *e = val.Type->GetRegType() == REGT_INT ? + new FxConstant(-val.Int, ScriptPosition) : + new FxConstant(-val.Float, ScriptPosition); + delete this; + return e; + } + ValueType = Operand->ValueType; + return this; + } + else + { + ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return nullptr; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxMinusSign::Emit(VMFunctionBuilder *build) +{ + assert(ValueType == Operand->ValueType); + ExpEmit from = Operand->Emit(build); + ExpEmit to; + assert(from.Konst == 0); + assert(ValueType->GetRegCount() == from.RegCount); + // Do it in-place, unless a local variable + if (from.Fixed) + { + to = ExpEmit(build, from.RegType, from.RegCount); + from.Free(build); + } + else + { + to = from; + } + + if (ValueType->GetRegType() == REGT_INT) + { + build->Emit(OP_NEG, to.RegNum, from.RegNum, 0); + } + else + { + assert(ValueType->GetRegType() == REGT_FLOAT); + switch (from.RegCount) + { + case 1: + build->Emit(OP_FLOP, to.RegNum, from.RegNum, FLOP_NEG); + break; + + case 2: + build->Emit(OP_NEGV2, to.RegNum, from.RegNum); + break; + + case 3: + build->Emit(OP_NEGV3, to.RegNum, from.RegNum); + break; + + } + } + return to; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxUnaryNotBitwise::FxUnaryNotBitwise(FxExpression *operand) +: FxExpression(EFX_UnaryNotBitwise, operand->ScriptPosition) +{ + Operand=operand; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxUnaryNotBitwise::~FxUnaryNotBitwise() +{ + SAFE_DELETE(Operand); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Operand, ctx); + + if (ctx.FromDecorate && Operand->IsFloat() /* lax */) + { + // DECORATE allows floats here so cast them to int. + Operand = new FxIntCast(Operand, true); + Operand = Operand->Resolve(ctx); + if (Operand == nullptr) + { + delete this; + return nullptr; + } + } + + // Names were not blocked in DECORATE here after the scripting branch merge. Now they are again. + if (!Operand->IsInteger()) + { + ScriptPosition.Message(MSG_ERROR, "Integer type expected"); + delete this; + return nullptr; + } + + if (Operand->isConstant()) + { + int result = ~static_cast(Operand)->GetValue().GetInt(); + FxExpression *e = new FxConstant(result, ScriptPosition); + e->ValueType = Operand->ValueType == TypeUInt32 ? TypeUInt32 : TypeSInt32; + delete this; + return e; + } + ValueType = Operand->ValueType == TypeUInt32? TypeUInt32 : TypeSInt32; + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxUnaryNotBitwise::Emit(VMFunctionBuilder *build) +{ + assert(Operand->ValueType->GetRegType() == REGT_INT); + ExpEmit from = Operand->Emit(build); + assert(!from.Konst); + // Do it in-place. + build->Emit(OP_NOT, from.RegNum, from.RegNum, 0); + return from; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxUnaryNotBoolean::FxUnaryNotBoolean(FxExpression *operand) +: FxExpression(EFX_UnaryNotBoolean, operand->ScriptPosition) +{ + Operand=operand; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxUnaryNotBoolean::~FxUnaryNotBoolean() +{ + SAFE_DELETE(Operand); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Operand, ctx); + + if (Operand->ValueType != TypeBool) + { + Operand = new FxBoolCast(Operand); + SAFE_RESOLVE(Operand, ctx); + } + + if (Operand->isConstant()) + { + bool result = !static_cast(Operand)->GetValue().GetBool(); + FxExpression *e = new FxConstant(result, ScriptPosition); + delete this; + return e; + } + + ValueType = TypeBool; + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build) +{ + assert(Operand->ValueType == TypeBool); + assert(ValueType == TypeBool || IsInteger()); // this may have been changed by an int cast. + ExpEmit from = Operand->Emit(build); + from.Free(build); + ExpEmit to(build, REGT_INT); + assert(!from.Konst); + // boolean not is the same as XOR-ing the lowest bit + + build->Emit(OP_XOR_RK, to.RegNum, from.RegNum, build->GetConstantInt(1)); + return to; +} + +//========================================================================== +// +// +// +//========================================================================== + +void FxUnaryNotBoolean::EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no) +{ + Operand->EmitCompare(build, !invert, patchspots_yes, patchspots_no); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxSizeAlign::FxSizeAlign(FxExpression *operand, int which) + : FxExpression(EFX_SizeAlign, operand->ScriptPosition) +{ + Operand = operand; + Which = which; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxSizeAlign::~FxSizeAlign() +{ + SAFE_DELETE(Operand); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxSizeAlign::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Operand, ctx); + + auto type = Operand->ValueType; + if (Operand->isConstant()) + { + ScriptPosition.Message(MSG_ERROR, "cannot determine %s of a constant", Which == TK_AlignOf? "alignment" : "size"); + delete this; + return nullptr; + } + else if (!Operand->RequestAddress(ctx, nullptr)) + { + ScriptPosition.Message(MSG_ERROR, "Operand must be addressable to determine %s", Which == TK_AlignOf ? "alignment" : "size"); + delete this; + return nullptr; + } + else + { + FxExpression *x = new FxConstant(Which == TK_AlignOf ? int(type->Align) : int(type->Size), Operand->ScriptPosition); + delete this; + return x->Resolve(ctx); + } +} + +ExpEmit FxSizeAlign::Emit(VMFunctionBuilder *build) +{ + return ExpEmit(); +} + +//========================================================================== +// +// FxPreIncrDecr +// +//========================================================================== + +FxPreIncrDecr::FxPreIncrDecr(FxExpression *base, int token) +: FxExpression(EFX_PreIncrDecr, base->ScriptPosition), Token(token), Base(base) +{ + AddressRequested = false; + AddressWritable = false; +} + +FxPreIncrDecr::~FxPreIncrDecr() +{ + SAFE_DELETE(Base); +} + +bool FxPreIncrDecr::RequestAddress(FCompileContext &ctx, bool *writable) +{ + AddressRequested = true; + if (writable != nullptr) *writable = AddressWritable; + return true; +} + +FxExpression *FxPreIncrDecr::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Base, ctx); + + ValueType = Base->ValueType; + + if (!Base->IsNumeric()) + { + ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return nullptr; + } + else if (Base->ValueType == TypeBool) + { + ScriptPosition.Message(MSG_ERROR, "%s is not allowed on type bool", FScanner::TokenName(Token).GetChars()); + delete this; + return nullptr; + } + if (!Base->RequestAddress(ctx, &AddressWritable) || !AddressWritable ) + { + ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value"); + delete this; + return nullptr; + } + + return this; +} + +ExpEmit FxPreIncrDecr::Emit(VMFunctionBuilder *build) +{ + assert(Token == TK_Incr || Token == TK_Decr); + assert(ValueType == Base->ValueType && IsNumeric()); + + int zero = build->GetConstantInt(0); + int regtype = ValueType->GetRegType(); + ExpEmit pointer = Base->Emit(build); + ExpEmit value = pointer; + + if (!pointer.Target) + { + value = ExpEmit(build, regtype); + build->Emit(ValueType->GetLoadOp(), value.RegNum, pointer.RegNum, zero); + } + + if (regtype == REGT_INT) + { + build->Emit(OP_ADDI, value.RegNum, value.RegNum, uint8_t((Token == TK_Incr) ? 1 : -1)); + } + else + { + build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, value.RegNum, value.RegNum, build->GetConstantFloat(1.)); + } + + if (!pointer.Target) + { + build->Emit(ValueType->GetStoreOp(), pointer.RegNum, value.RegNum, zero); + } + + if (AddressRequested) + { + value.Free(build); + return pointer; + } + + pointer.Free(build); + return value; +} + +//========================================================================== +// +// FxPostIncrDecr +// +//========================================================================== + +FxPostIncrDecr::FxPostIncrDecr(FxExpression *base, int token) +: FxExpression(EFX_PostIncrDecr, base->ScriptPosition), Token(token), Base(base) +{ +} + +FxPostIncrDecr::~FxPostIncrDecr() +{ + SAFE_DELETE(Base); +} + +FxExpression *FxPostIncrDecr::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Base, ctx); + bool AddressWritable; + + ValueType = Base->ValueType; + + if (!Base->IsNumeric()) + { + ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return nullptr; + } + else if (Base->ValueType == TypeBool) + { + ScriptPosition.Message(MSG_ERROR, "%s is not allowed on type bool", FScanner::TokenName(Token).GetChars()); + delete this; + return nullptr; + } + if (!Base->RequestAddress(ctx, &AddressWritable) || !AddressWritable) + { + ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value"); + delete this; + return nullptr; + } + + return this; +} + +ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build) +{ + assert(Token == TK_Incr || Token == TK_Decr); + assert(ValueType == Base->ValueType && IsNumeric()); + + int zero = build->GetConstantInt(0); + int regtype = ValueType->GetRegType(); + ExpEmit pointer = Base->Emit(build); + + if (!pointer.Target) + { + ExpEmit out(build, regtype); + build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, zero); + ExpEmit assign(build, regtype); + if (regtype == REGT_INT) + { + build->Emit(OP_ADDI, assign.RegNum, out.RegNum, uint8_t((Token == TK_Incr) ? 1 : -1)); + } + else + { + build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, assign.RegNum, out.RegNum, build->GetConstantFloat(1.)); + } + build->Emit(ValueType->GetStoreOp(), pointer.RegNum, assign.RegNum, zero); + pointer.Free(build); + assign.Free(build); + return out; + } + else if (NeedResult) + { + ExpEmit out(build, regtype); + if (regtype == REGT_INT) + { + build->Emit(OP_MOVE, out.RegNum, pointer.RegNum); + build->Emit(OP_ADDI, pointer.RegNum, pointer.RegNum, uint8_t((Token == TK_Incr) ? 1 : -1)); + } + else + { + build->Emit(OP_MOVEF, out.RegNum, pointer.RegNum); + build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, pointer.RegNum, pointer.RegNum, build->GetConstantFloat(1.)); + } + pointer.Free(build); + return out; + } + else + { + if (regtype == REGT_INT) + { + build->Emit(OP_ADDI, pointer.RegNum, pointer.RegNum, uint8_t((Token == TK_Incr) ? 1 : -1)); + } + else + { + build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, pointer.RegNum, pointer.RegNum, build->GetConstantFloat(1.)); + } + pointer.Free(build); + return ExpEmit(); + } +} + +//========================================================================== +// +// FxAssign +// +//========================================================================== + +FxAssign::FxAssign(FxExpression *base, FxExpression *right, bool ismodify) +: FxExpression(EFX_Assign, base->ScriptPosition), Base(base), Right(right), IsBitWrite(-1), IsModifyAssign(ismodify) +{ + AddressRequested = false; + AddressWritable = false; +} + +FxAssign::~FxAssign() +{ + SAFE_DELETE(Base); + SAFE_DELETE(Right); +} + +/* I don't think we should allow constructs like (a = b) = c;... +bool FxAssign::RequestAddress(FCompileContext &ctx, bool *writable) +{ + AddressRequested = true; + if (writable != nullptr) *writable = AddressWritable; + return true; +} +*/ + +FxExpression *FxAssign::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Base, ctx); + + ValueType = Base->ValueType; + + SAFE_RESOLVE(Right, ctx); + + if (IsModifyAssign && Base->ValueType == TypeBool && Right->ValueType != TypeBool) + { + // If the modify operation resulted in a type promotion from bool to int, this must be blocked. + // (this means, for bool, only &=, ^= and |= are allowed, although DECORATE is more lax.) + ScriptPosition.Message(MSG_ERROR, "Invalid modify/assign operation with a boolean operand"); + delete this; + return nullptr; + } + + // keep the redundant handling for numeric types here to avoid problems with DECORATE. + // for non-numerics FxTypeCast can be used without issues. + if (Base->IsNumeric() && Right->IsNumeric()) + { + if (Right->ValueType != ValueType) + { + if (ValueType == TypeBool) + { + Right = new FxBoolCast(Right); + } + else if (ValueType->GetRegType() == REGT_INT) + { + Right = new FxIntCast(Right, ctx.FromDecorate); + } + else + { + Right = new FxFloatCast(Right); + } + SAFE_RESOLVE(Right, ctx); + } + } + else if (Base->ValueType == Right->ValueType) + { + if (Base->ValueType->IsKindOf(RUNTIME_CLASS(PArray))) + { + ScriptPosition.Message(MSG_ERROR, "Cannot assign arrays"); + delete this; + return nullptr; + } + if (!Base->IsVector() && Base->ValueType->IsKindOf(RUNTIME_CLASS(PStruct))) + { + ScriptPosition.Message(MSG_ERROR, "Struct assignment not implemented yet"); + delete this; + return nullptr; + } + // Both types are the same so this is ok. + } + else if (Right->ValueType->IsA(RUNTIME_CLASS(PNativeStruct)) && Base->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(Base->ValueType)->PointedType == Right->ValueType) + { + // allow conversion of native structs to pointers of the same type. This is necessary to assign elements from global arrays like players, sectors, etc. to local pointers. + // For all other types this is not needed. Structs are not assignable and classes can only exist as references. + bool writable; + Right->RequestAddress(ctx, &writable); + Right->ValueType = Base->ValueType; + } + else + { + // pass it to FxTypeCast for complete handling. + Right = new FxTypeCast(Right, Base->ValueType, false); + SAFE_RESOLVE(Right, ctx); + } + + if (!Base->RequestAddress(ctx, &AddressWritable) || !AddressWritable) + { + ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value"); + delete this; + return nullptr; + } + + // Special case: Assignment to a bitfield. + IsBitWrite = Base->GetBitValue(); + return this; +} + +ExpEmit FxAssign::Emit(VMFunctionBuilder *build) +{ + static const BYTE loadops[] = { OP_LK, OP_LKF, OP_LKS, OP_LKP }; + assert(ValueType == Base->ValueType); + assert(ValueType->GetRegType() == Right->ValueType->GetRegType()); + + ExpEmit pointer = Base->Emit(build); + Address = pointer; + + ExpEmit result; + bool intconst = false; + int intconstval; + + if (Right->isConstant() && Right->ValueType->GetRegType() == REGT_INT) + { + intconst = true; + intconstval = static_cast(Right)->GetValue().GetInt(); + result.Konst = true; + result.RegType = REGT_INT; + } + else + { + result = Right->Emit(build); + } + assert(result.RegType <= REGT_TYPE); + + if (pointer.Target) + { + if (result.Konst) + { + if (intconst) build->EmitLoadInt(pointer.RegNum, intconstval); + else build->Emit(loadops[result.RegType], pointer.RegNum, result.RegNum); + } + else + { + build->Emit(Right->ValueType->GetMoveOp(), pointer.RegNum, result.RegNum); + } + } + else + { + if (result.Konst) + { + ExpEmit temp(build, result.RegType); + if (intconst) build->EmitLoadInt(temp.RegNum, intconstval); + else build->Emit(loadops[result.RegType], temp.RegNum, result.RegNum); + result.Free(build); + result = temp; + } + + if (IsBitWrite == -1) + { + build->Emit(ValueType->GetStoreOp(), pointer.RegNum, result.RegNum, build->GetConstantInt(0)); + } + else + { + build->Emit(OP_SBIT, pointer.RegNum, result.RegNum, 1 << IsBitWrite); + } + + } + + if (AddressRequested) + { + result.Free(build); + return pointer; + } + + pointer.Free(build); + return result; +} + +//========================================================================== +// +// FxAssignSelf +// +//========================================================================== + +FxAssignSelf::FxAssignSelf(const FScriptPosition &pos) +: FxExpression(EFX_AssignSelf, pos) +{ + Assignment = nullptr; +} + +FxExpression *FxAssignSelf::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + + // This should never happen if FxAssignSelf is used correctly + assert(Assignment != nullptr); + + ValueType = Assignment->ValueType; + + return this; +} + +ExpEmit FxAssignSelf::Emit(VMFunctionBuilder *build) +{ + assert(ValueType == Assignment->ValueType); + ExpEmit pointer = Assignment->Address; // FxAssign should have already emitted it + if (!pointer.Target) + { + ExpEmit out(build, ValueType->GetRegType(), ValueType->GetRegCount()); + if (Assignment->IsBitWrite != -1) + { + build->Emit(OP_LBIT, out.RegNum, pointer.RegNum, 1 << Assignment->IsBitWrite); + } + else + { + build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, build->GetConstantInt(0)); + } + return out; + } + else + { + return pointer; + } +} + + +//========================================================================== +// +// +// +//========================================================================== + +FxMultiAssign::FxMultiAssign(FArgumentList &base, FxExpression *right, const FScriptPosition &pos) + :FxExpression(EFX_MultiAssign, pos) +{ + Base = std::move(base); + Right = right; + LocalVarContainer = new FxCompoundStatement(ScriptPosition); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxMultiAssign::~FxMultiAssign() +{ + SAFE_DELETE(Right); + SAFE_DELETE(LocalVarContainer); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxMultiAssign::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Right, ctx); + if (Right->ExprType != EFX_VMFunctionCall) + { + Right->ScriptPosition.Message(MSG_ERROR, "Function call expected on right side of multi-assigment"); + delete this; + return nullptr; + } + auto VMRight = static_cast(Right); + auto rets = VMRight->GetReturnTypes(); + if (rets.Size() < Base.Size()) + { + Right->ScriptPosition.Message(MSG_ERROR, "Insufficient returns in function %s", VMRight->Function->SymbolName.GetChars()); + delete this; + return nullptr; + } + // Pack the generated data (temp local variables for the results and necessary type casts and single assignments) into a compound statement for easier management. + for (unsigned i = 0; i < Base.Size(); i++) + { + auto singlevar = new FxLocalVariableDeclaration(rets[i], NAME_None, nullptr, 0, ScriptPosition); + LocalVarContainer->Add(singlevar); + Base[i] = Base[i]->Resolve(ctx); + ABORT(Base[i]); + auto varaccess = new FxLocalVariable(singlevar, ScriptPosition); + auto assignee = new FxTypeCast(varaccess, Base[i]->ValueType, false); + LocalVarContainer->Add(new FxAssign(Base[i], assignee, false)); + } + auto x = LocalVarContainer->Resolve(ctx); + LocalVarContainer = nullptr; + ABORT(x); + LocalVarContainer = static_cast(x); + static_cast(Right)->AssignCount = Base.Size(); + ValueType = TypeVoid; + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxMultiAssign::Emit(VMFunctionBuilder *build) +{ + Right->Emit(build); + for (unsigned i = 0; i < Base.Size(); i++) + { + LocalVarContainer->LocalVars[i]->SetReg(static_cast(Right)->ReturnRegs[i]); + } + static_cast(Right)->ReturnRegs.Clear(); + static_cast(Right)->ReturnRegs.ShrinkToFit(); + return LocalVarContainer->Emit(build); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxBinary::FxBinary(int o, FxExpression *l, FxExpression *r) +: FxExpression(EFX_Binary, l->ScriptPosition) +{ + Operator=o; + left=l; + right=r; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxBinary::~FxBinary() +{ + SAFE_DELETE(left); + SAFE_DELETE(right); +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FxBinary::Promote(FCompileContext &ctx, bool forceint) +{ + // math operations of unsigned ints results in an unsigned int. (16 and 8 bit values never get here, they get promoted to regular ints elsewhere already.) + if (left->ValueType == TypeUInt32 && right->ValueType == TypeUInt32) + { + ValueType = TypeUInt32; + } + else if (left->IsInteger() && right->IsInteger()) + { + ValueType = TypeSInt32; // Addition and subtraction forces all integer-derived types to signed int. + } + else if (!forceint) + { + ValueType = TypeFloat64; + if (left->IsFloat() && right->IsInteger()) + { + right = (new FxFloatCast(right))->Resolve(ctx); + } + else if (left->IsInteger() && right->IsFloat()) + { + left = (new FxFloatCast(left))->Resolve(ctx); + } + } + else if (ctx.FromDecorate) + { + // For DECORATE which allows floats here. ZScript does not. + if (left->IsFloat()) + { + left = new FxIntCast(left, ctx.FromDecorate); + left = left->Resolve(ctx); + } + if (right->IsFloat()) + { + right = new FxIntCast(right, ctx.FromDecorate); + right = right->Resolve(ctx); + } + if (left == nullptr || right == nullptr) + { + delete this; + return false; + } + ValueType = TypeSInt32; + + } + else + { + ScriptPosition.Message(MSG_ERROR, "Integer operand expected"); + delete this; + return false; + } + return true; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxAddSub::FxAddSub(int o, FxExpression *l, FxExpression *r) +: FxBinary(o, l, r) +{ +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxAddSub::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + + RESOLVE(left, ctx); + RESOLVE(right, ctx); + if (!left || !right) + { + delete this; + return nullptr; + } + + if (left->ValueType == TypeState && right->IsInteger() && Operator == '+' && !left->isConstant()) + { + // This is the only special case of pointer addition that will be accepted - because it is used quite often in the existing game code. + ValueType = TypeState; + right = new FxMulDiv('*', right, new FxConstant((int)sizeof(FState), ScriptPosition)); // multiply by size here, so that constants can be better optimized. + right = right->Resolve(ctx); + ABORT(right); + } + else if (left->IsVector() && right->IsVector()) + { + // a vector2 can be added to or subtracted from a vector 3 but it needs to be the right operand. + if (left->ValueType == right->ValueType || (left->ValueType == TypeVector3 && right->ValueType == TypeVector2)) + { + ValueType = left->ValueType; + } + else + { + goto error; + } + } + else if (left->IsNumeric() && right->IsNumeric()) + { + Promote(ctx); + } + else + { + // To check: It may be that this could pass in DECORATE, although setting TypeVoid here would pretty much prevent that. + goto error; + } + + if (left->isConstant() && right->isConstant()) + { + if (IsFloat()) + { + double v; + double v1 = static_cast(left)->GetValue().GetFloat(); + double v2 = static_cast(right)->GetValue().GetFloat(); + + v = Operator == '+'? v1 + v2 : + Operator == '-'? v1 - v2 : 0; + + FxExpression *e = new FxConstant(v, ScriptPosition); + delete this; + return e; + } + else + { + int v; + int v1 = static_cast(left)->GetValue().GetInt(); + int v2 = static_cast(right)->GetValue().GetInt(); + + v = Operator == '+'? v1 + v2 : + Operator == '-'? v1 - v2 : 0; + + FxExpression *e = new FxConstant(v, ScriptPosition); + delete this; + return e; + + } + } + return this; + +error: + ScriptPosition.Message(MSG_ERROR, "Incompatible operands for %s", Operator == '+' ? "addition" : "subtraction"); + delete this; + return nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxAddSub::Emit(VMFunctionBuilder *build) +{ + assert(Operator == '+' || Operator == '-'); + ExpEmit op1 = left->Emit(build); + ExpEmit op2 = right->Emit(build); + if (Operator == '+') + { + if (op1.RegType == REGT_POINTER) + { + assert(!op1.Konst); + assert(op2.RegType == REGT_INT); + op1.Free(build); + op2.Free(build); + ExpEmit opout(build, REGT_POINTER); + build->Emit(op2.Konst? OP_ADDA_RK : OP_ADDA_RR, opout.RegNum, op1.RegNum, op2.RegNum); + return opout; + } + // Since addition is commutative, only the second operand may be a constant. + if (op1.Konst) + { + swapvalues(op1, op2); + } + assert(!op1.Konst); + op1.Free(build); + op2.Free(build); + ExpEmit to(build, ValueType->GetRegType(), ValueType->GetRegCount()); + if (IsVector()) + { + assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); + build->Emit(right->ValueType == TypeVector2? OP_ADDV2_RR : OP_ADDV3_RR, to.RegNum, op1.RegNum, op2.RegNum); + if (left->ValueType == TypeVector3 && right->ValueType == TypeVector2 && to.RegNum != op1.RegNum) + { + // must move the z-coordinate + build->Emit(OP_MOVEF, to.RegNum + 2, op1.RegNum + 2); + } + return to; + } + else if (ValueType->GetRegType() == REGT_FLOAT) + { + assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); + build->Emit(op2.Konst ? OP_ADDF_RK : OP_ADDF_RR, to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + else + { + assert(ValueType->GetRegType() == REGT_INT); + assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT); + build->Emit(op2.Konst ? OP_ADD_RK : OP_ADD_RR, to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + } + else + { + // Subtraction is not commutative, so either side may be constant (but not both). + assert(!op1.Konst || !op2.Konst); + op1.Free(build); + op2.Free(build); + ExpEmit to(build, ValueType->GetRegType(), ValueType->GetRegCount()); + if (IsVector()) + { + assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); + build->Emit(right->ValueType == TypeVector2 ? OP_SUBV2_RR : OP_SUBV3_RR, to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + else if (ValueType->GetRegType() == REGT_FLOAT) + { + assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); + build->Emit(op1.Konst ? OP_SUBF_KR : op2.Konst ? OP_SUBF_RK : OP_SUBF_RR, to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + else + { + assert(ValueType->GetRegType() == REGT_INT); + assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT); + build->Emit(op1.Konst ? OP_SUB_KR : op2.Konst ? OP_SUB_RK : OP_SUB_RR, to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + } +} + +//========================================================================== +// +// +// +//========================================================================== + +FxMulDiv::FxMulDiv(int o, FxExpression *l, FxExpression *r) +: FxBinary(o, l, r) +{ +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + + RESOLVE(left, ctx); + RESOLVE(right, ctx); + if (!left || !right) + { + delete this; + return nullptr; + } + + if (left->IsVector() || right->IsVector()) + { + switch (Operator) + { + case '/': + // For division, the vector must be the first operand. + if (right->IsVector()) goto error; + + case '*': + if (left->IsVector() && right->IsNumeric()) + { + if (right->IsInteger()) + { + right = new FxFloatCast(right); + right = right->Resolve(ctx); + if (right == nullptr) + { + delete this; + return nullptr; + } + } + ValueType = left->ValueType; + } + else if (right->IsVector() && left->IsNumeric()) + { + if (left->IsInteger()) + { + left = new FxFloatCast(left); + left = left->Resolve(ctx); + if (left == nullptr) + { + delete this; + return nullptr; + } + } + ValueType = right->ValueType; + } + break; + + default: + // Vector modulus is not permitted + goto error; + + } + } + else if (left->IsNumeric() && right->IsNumeric()) + { + Promote(ctx); + } + else + { + // To check: It may be that this could pass in DECORATE, although setting TypeVoid here would pretty much prevent that. + goto error; + } + + if (left->isConstant() && right->isConstant()) + { + if (IsFloat()) + { + double v; + double v1 = static_cast(left)->GetValue().GetFloat(); + double v2 = static_cast(right)->GetValue().GetFloat(); + + if (Operator != '*' && v2 == 0) + { + ScriptPosition.Message(MSG_ERROR, "Division by 0"); + delete this; + return nullptr; + } + + v = Operator == '*'? v1 * v2 : + Operator == '/'? v1 / v2 : + Operator == '%'? fmod(v1, v2) : 0; + + FxExpression *e = new FxConstant(v, ScriptPosition); + delete this; + return e; + } + else + { + int v; + int v1 = static_cast(left)->GetValue().GetInt(); + int v2 = static_cast(right)->GetValue().GetInt(); + + if (Operator != '*' && v2 == 0) + { + ScriptPosition.Message(MSG_ERROR, "Division by 0"); + delete this; + return nullptr; + } + + v = Operator == '*'? v1 * v2 : + Operator == '/'? v1 / v2 : + Operator == '%'? v1 % v2 : 0; + + FxExpression *e = new FxConstant(v, ScriptPosition); + delete this; + return e; + + } + } + return this; + +error: + ScriptPosition.Message(MSG_ERROR, "Incompatible operands for %s", Operator == '*' ? "multiplication" : Operator == '%' ? "modulus" : "division"); + delete this; + return nullptr; + +} + + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build) +{ + ExpEmit op1 = left->Emit(build); + ExpEmit op2 = right->Emit(build); + + if (IsVector()) + { + assert(Operator != '%'); + if (right->IsVector()) + { + swapvalues(op1, op2); + } + int op; + if (op2.Konst) + { + op = Operator == '*' ? (ValueType == TypeVector2 ? OP_MULVF2_RK : OP_MULVF3_RK) : (ValueType == TypeVector2 ? OP_DIVVF2_RK : OP_DIVVF3_RK); + } + else + { + op = Operator == '*' ? (ValueType == TypeVector2 ? OP_MULVF2_RR : OP_MULVF3_RR) : (ValueType == TypeVector2 ? OP_DIVVF2_RR : OP_DIVVF3_RR); + } + op1.Free(build); + op2.Free(build); + ExpEmit to(build, ValueType->GetRegType(), ValueType->GetRegCount()); + build->Emit(op, to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + + if (Operator == '*') + { + // Multiplication is commutative, so only the second operand may be constant. + if (op1.Konst) + { + swapvalues(op1, op2); + } + assert(!op1.Konst); + op1.Free(build); + op2.Free(build); + ExpEmit to(build, ValueType->GetRegType()); + if (ValueType->GetRegType() == REGT_FLOAT) + { + assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); + build->Emit(op2.Konst ? OP_MULF_RK : OP_MULF_RR, to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + else + { + assert(ValueType->GetRegType() == REGT_INT); + assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT); + build->Emit(op2.Konst ? OP_MUL_RK : OP_MUL_RR, to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + } + else + { + // Division is not commutative, so either side may be constant (but not both). + assert(!op1.Konst || !op2.Konst); + assert(Operator == '%' || Operator == '/'); + op1.Free(build); + op2.Free(build); + ExpEmit to(build, ValueType->GetRegType()); + if (ValueType->GetRegType() == REGT_FLOAT) + { + assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); + build->Emit(Operator == '/' ? (op1.Konst ? OP_DIVF_KR : op2.Konst ? OP_DIVF_RK : OP_DIVF_RR) + : (op1.Konst ? OP_MODF_KR : op2.Konst ? OP_MODF_RK : OP_MODF_RR), + to.RegNum, op1.RegNum, op2.RegNum); + return to; + } + else + { + assert(ValueType->GetRegType() == REGT_INT); + assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT); + if (ValueType == TypeUInt32) + { + build->Emit(Operator == '/' ? (op1.Konst ? OP_DIVU_KR : op2.Konst ? OP_DIVU_RK : OP_DIVU_RR) + : (op1.Konst ? OP_MODU_KR : op2.Konst ? OP_MODU_RK : OP_MODU_RR), + to.RegNum, op1.RegNum, op2.RegNum); + } + else + { + build->Emit(Operator == '/' ? (op1.Konst ? OP_DIV_KR : op2.Konst ? OP_DIV_RK : OP_DIV_RR) + : (op1.Konst ? OP_MOD_KR : op2.Konst ? OP_MOD_RK : OP_MOD_RR), + to.RegNum, op1.RegNum, op2.RegNum); + } + return to; + } + } +} + +//========================================================================== +// +// +// +//========================================================================== + +FxPow::FxPow(FxExpression *l, FxExpression *r) + : FxBinary(TK_MulMul, new FxFloatCast(l), new FxFloatCast(r)) +{ +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxPow::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + + RESOLVE(left, ctx); + RESOLVE(right, ctx); + if (!left || !right) + { + delete this; + return nullptr; + } + if (!left->IsNumeric() || !right->IsNumeric()) + { + ScriptPosition.Message(MSG_ERROR, "Numeric type expected for '**'"); + delete this; + return nullptr; + } + if (!left->IsFloat()) + { + left = (new FxFloatCast(left))->Resolve(ctx); + ABORT(left); + } + if (!right->IsFloat()) + { + right = (new FxFloatCast(right))->Resolve(ctx); + ABORT(right); + } + if (left->isConstant() && right->isConstant()) + { + double v1 = static_cast(left)->GetValue().GetFloat(); + double v2 = static_cast(right)->GetValue().GetFloat(); + return new FxConstant(g_pow(v1, v2), left->ScriptPosition); + } + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxPow::Emit(VMFunctionBuilder *build) +{ + ExpEmit op1 = left->Emit(build); + ExpEmit op2 = right->Emit(build); + + // Pow is not commutative, so either side may be constant (but not both). + assert(!op1.Konst || !op2.Konst); + op1.Free(build); + op2.Free(build); + assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); + ExpEmit to(build, REGT_FLOAT); + build->Emit((op1.Konst ? OP_POWF_KR : op2.Konst ? OP_POWF_RK : OP_POWF_RR), to.RegNum, op1.RegNum, op2.RegNum); + return to; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxCompareRel::FxCompareRel(int o, FxExpression *l, FxExpression *r) +: FxBinary(o, l, r) +{ +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + + RESOLVE(left, ctx); + RESOLVE(right, ctx); + if (!left || !right) + { + delete this; + return nullptr; + } + + if (left->ValueType == TypeString || right->ValueType == TypeString) + { + if (left->ValueType != TypeString) + { + left = new FxStringCast(left); + left = left->Resolve(ctx); + if (left == nullptr) + { + delete this; + return nullptr; + } + } + if (right->ValueType != TypeString) + { + right = new FxStringCast(right); + right = right->Resolve(ctx); + if (right == nullptr) + { + delete this; + return nullptr; + } + } + ValueType = TypeString; + } + else if (left->IsNumeric() && right->IsNumeric()) + { + Promote(ctx); + } + else + { + ScriptPosition.Message(MSG_ERROR, "Incompatible operands for relative comparison"); + delete this; + return nullptr; + } + + if (left->isConstant() && right->isConstant()) + { + int v; + + if (ValueType == TypeString) + { + FString v1 = static_cast(left)->GetValue().GetString(); + FString v2 = static_cast(right)->GetValue().GetString(); + int res = v1.Compare(v2); + v = Operator == '<' ? res < 0 : + Operator == '>' ? res > 0 : + Operator == TK_Geq ? res >= 0 : + Operator == TK_Leq ? res <= 0 : 0; + } + else if (IsFloat()) + { + double v1 = static_cast(left)->GetValue().GetFloat(); + double v2 = static_cast(right)->GetValue().GetFloat(); + v = Operator == '<'? v1 < v2 : + Operator == '>'? v1 > v2 : + Operator == TK_Geq? v1 >= v2 : + Operator == TK_Leq? v1 <= v2 : 0; + } + else if (ValueType == TypeUInt32) + { + int v1 = static_cast(left)->GetValue().GetUInt(); + int v2 = static_cast(right)->GetValue().GetUInt(); + v = Operator == '<'? v1 < v2 : + Operator == '>'? v1 > v2 : + Operator == TK_Geq? v1 >= v2 : + Operator == TK_Leq? v1 <= v2 : 0; + } + else + { + int v1 = static_cast(left)->GetValue().GetInt(); + int v2 = static_cast(right)->GetValue().GetInt(); + v = Operator == '<' ? v1 < v2 : + Operator == '>' ? v1 > v2 : + Operator == TK_Geq ? v1 >= v2 : + Operator == TK_Leq ? v1 <= v2 : 0; + } + FxExpression *e = new FxConstant(v, ScriptPosition); + delete this; + return e; + } + CompareType = ValueType; // needs to be preserved for detection of unsigned compare. + ValueType = TypeBool; + return this; +} + + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxCompareRel::EmitCommon(VMFunctionBuilder *build, bool forcompare, bool invert) +{ + ExpEmit op1 = left->Emit(build); + ExpEmit op2 = right->Emit(build); + assert(op1.RegType == op2.RegType); + assert(!op1.Konst || !op2.Konst); + + if (op1.RegType == REGT_STRING) + { + ExpEmit to(build, REGT_INT); + int a = Operator == '<' ? CMP_LT : + Operator == '>' ? CMP_LE | CMP_CHECK : + Operator == TK_Geq ? CMP_LT | CMP_CHECK : CMP_LE; + + if (op1.Konst) + { + a |= CMP_BK; + } + else + { + op1.Free(build); + } + if (op2.Konst) + { + a |= CMP_CK; + } + else + { + op2.Free(build); + } + if (invert) a ^= CMP_CHECK; + + if (!forcompare) build->Emit(OP_LI, to.RegNum, 0, 0); + build->Emit(OP_CMPS, a, op1.RegNum, op2.RegNum); + if (!forcompare) + { + build->Emit(OP_JMP, 1); + build->Emit(OP_LI, to.RegNum, 1); + } + return to; + } + else + { + assert(op1.RegType == REGT_INT || op1.RegType == REGT_FLOAT); + assert(Operator == '<' || Operator == '>' || Operator == TK_Geq || Operator == TK_Leq); + static const VM_UBYTE InstrMap[][4] = + { + { OP_LT_RR, OP_LTF_RR, OP_LTU_RR, 0 }, // < + { OP_LE_RR, OP_LEF_RR, OP_LEU_RR, 1 }, // > + { OP_LT_RR, OP_LTF_RR, OP_LTU_RR, 1 }, // >= + { OP_LE_RR, OP_LEF_RR, OP_LEU_RR, 0 } // <= + }; + int instr, check; + ExpEmit to(build, REGT_INT); + int index = Operator == '<' ? 0 : + Operator == '>' ? 1 : + Operator == TK_Geq ? 2 : 3; + + int mode = op1.RegType == REGT_FLOAT ? 1 : CompareType == TypeUInt32 ? 2 : 0; + instr = InstrMap[index][mode]; + check = InstrMap[index][3]; + if (op2.Konst) + { + instr += 1; + } + else + { + op2.Free(build); + } + if (op1.Konst) + { + instr += 2; + } + else + { + op1.Free(build); + } + if (invert) check ^= 1; + + // See FxBoolCast for comments, since it's the same thing. + if (!forcompare) build->Emit(OP_LI, to.RegNum, 0, 0); + build->Emit(instr, check, op1.RegNum, op2.RegNum); + if (!forcompare) + { + build->Emit(OP_JMP, 1); + build->Emit(OP_LI, to.RegNum, 1); + } + return to; + } +} + +ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build) +{ + return EmitCommon(build, false, false); +} + +void FxCompareRel::EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no) +{ + ExpEmit emit = EmitCommon(build, true, invert); + emit.Free(build); + patchspots_no.Push(build->Emit(OP_JMP, 0)); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxCompareEq::FxCompareEq(int o, FxExpression *l, FxExpression *r) +: FxBinary(o, l, r) +{ +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxCompareEq::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + + RESOLVE(left, ctx); + RESOLVE(right, ctx); + if (!left || !right) + { + delete this; + return nullptr; + } + + if (left->ValueType != right->ValueType) // identical types are always comparable, if they can be placed in a register, so we can save most checks if this is the case. + { + // Special cases: Compare strings and names with names, sounds, colors, state labels and class types. + // These are all types a string can be implicitly cast into, so for convenience, so they should when doing a comparison. + if ((left->ValueType == TypeString || left->ValueType == TypeName) && + (right->ValueType == TypeName || right->ValueType == TypeSound || right->ValueType == TypeColor || right->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) || right->ValueType == TypeStateLabel)) + { + left = new FxTypeCast(left, right->ValueType, false, true); + left = left->Resolve(ctx); + ABORT(left); + ValueType = right->ValueType; + } + else if ((right->ValueType == TypeString || right->ValueType == TypeName) && + (left->ValueType == TypeName || left->ValueType == TypeSound || left->ValueType == TypeColor || left->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) || left->ValueType == TypeStateLabel)) + { + right = new FxTypeCast(right, left->ValueType, false, true); + right = right->Resolve(ctx); + ABORT(right); + ValueType = left->ValueType; + } + else if (left->IsNumeric() && right->IsNumeric()) + { + Promote(ctx); + } + else if (left->ValueType->GetRegType() == REGT_POINTER && right->ValueType->GetRegType() == REGT_POINTER) + { + if (left->ValueType != right->ValueType && right->ValueType != TypeNullPtr && left->ValueType != TypeNullPtr && + !AreCompatiblePointerTypes(left->ValueType, right->ValueType, true)) + { + goto error; + } + } + else + { + goto error; + } + } + else if (left->ValueType->GetRegType() == REGT_NIL) + { + goto error; + } + else + { + ValueType = left->ValueType; + } + + if (Operator == TK_ApproxEq && ValueType->GetRegType() != REGT_FLOAT && ValueType->GetRegType() != REGT_STRING) + { + // Only floats, vectors and strings have handling for '~==', for all other types this is an error. + goto error; + } + + if (left->isConstant() && right->isConstant()) + { + int v; + + if (ValueType == TypeString) + { + FString v1 = static_cast(left)->GetValue().GetString(); + FString v2 = static_cast(right)->GetValue().GetString(); + if (Operator == TK_ApproxEq) v = !v1.CompareNoCase(v2); + else + { + v = !!v1.Compare(v2); + if (Operator == TK_Eq) v = !v; + } + } + else if (ValueType->GetRegType() == REGT_FLOAT) + { + double v1 = static_cast(left)->GetValue().GetFloat(); + double v2 = static_cast(right)->GetValue().GetFloat(); + v = Operator == TK_Eq? v1 == v2 : Operator == TK_Neq? v1 != v2 : fabs(v1-v2) < VM_EPSILON; + } + else + { + int v1 = static_cast(left)->GetValue().GetInt(); + int v2 = static_cast(right)->GetValue().GetInt(); + v = Operator == TK_Eq? v1 == v2 : v1 != v2; + } + FxExpression *e = new FxConstant(v, ScriptPosition); + delete this; + return e; + } + else + { + // also simplify comparisons against zero. For these a bool cast/unary not on the other value will do just as well and create better code. + if (Operator != TK_ApproxEq) + { + if (left->isConstant()) + { + bool leftisnull; + switch (left->ValueType->GetRegType()) + { + case REGT_INT: + leftisnull = static_cast(left)->GetValue().GetInt() == 0; + break; + + case REGT_FLOAT: + assert(left->ValueType->GetRegCount() == 1); // vectors should not be able to get here. + leftisnull = static_cast(left)->GetValue().GetFloat() == 0; + break; + + case REGT_POINTER: + leftisnull = static_cast(left)->GetValue().GetPointer() == nullptr; + break; + + default: + leftisnull = false; + } + if (leftisnull) + { + FxExpression *x; + if (Operator == TK_Eq) x = new FxUnaryNotBoolean(right); + else x = new FxBoolCast(right); + right = nullptr; + delete this; + return x->Resolve(ctx); + } + + } + if (right->isConstant()) + { + bool rightisnull; + switch (right->ValueType->GetRegType()) + { + case REGT_INT: + rightisnull = static_cast(right)->GetValue().GetInt() == 0; + break; + + case REGT_FLOAT: + assert(right->ValueType->GetRegCount() == 1); // vectors should not be able to get here. + rightisnull = static_cast(right)->GetValue().GetFloat() == 0; + break; + + case REGT_POINTER: + rightisnull = static_cast(right)->GetValue().GetPointer() == nullptr; + break; + + default: + rightisnull = false; + } + if (rightisnull) + { + FxExpression *x; + if (Operator == TK_Eq) x = new FxUnaryNotBoolean(left); + else x = new FxBoolCast(left); + left = nullptr; + delete this; + return x->Resolve(ctx); + } + } + } + } + ValueType = TypeBool; + return this; + +error: + ScriptPosition.Message(MSG_ERROR, "Incompatible operands for %s comparison", Operator == TK_Eq ? "==" : Operator == TK_Neq ? "!=" : "~=="); + delete this; + return nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxCompareEq::EmitCommon(VMFunctionBuilder *build, bool forcompare, bool invert) +{ + ExpEmit op1 = left->Emit(build); + ExpEmit op2 = right->Emit(build); + assert(op1.RegType == op2.RegType); + int instr; + + if (op1.RegType == REGT_STRING) + { + ExpEmit to(build, REGT_INT); + assert(Operator == TK_Eq || Operator == TK_Neq || Operator == TK_ApproxEq); + int a = Operator == TK_Eq ? CMP_EQ : + Operator == TK_Neq ? CMP_EQ | CMP_CHECK : CMP_EQ | CMP_APPROX; + + if (op1.Konst) a |= CMP_BK; + if (op2.Konst) a |= CMP_CK; + if (invert) a ^= CMP_CHECK; + + if (!forcompare) build->Emit(OP_LI, to.RegNum, 0, 0); + build->Emit(OP_CMPS, a, op1.RegNum, op2.RegNum); + if (!forcompare) + { + build->Emit(OP_JMP, 1); + build->Emit(OP_LI, to.RegNum, 1); + } + op1.Free(build); + op2.Free(build); + return to; + } + else + { + + // Only the second operand may be constant. + if (op1.Konst) + { + swapvalues(op1, op2); + } + assert(!op1.Konst); + assert(op1.RegCount >= 1 && op1.RegCount <= 3); + + ExpEmit to(build, REGT_INT); + + static int flops[] = { OP_EQF_R, OP_EQV2_R, OP_EQV3_R }; + instr = op1.RegType == REGT_INT ? OP_EQ_R : + op1.RegType == REGT_FLOAT ? flops[op1.RegCount - 1] : + OP_EQA_R; + op1.Free(build); + if (!op2.Konst) + { + op2.Free(build); + } + else + { + instr += 1; + } + + // See FxUnaryNotBoolean for comments, since it's the same thing. + if (!forcompare) build->Emit(OP_LI, to.RegNum, 0, 0); + build->Emit(instr, int(invert) ^ (Operator == TK_ApproxEq ? CMP_APPROX : ((Operator != TK_Eq) ? CMP_CHECK : 0)), op1.RegNum, op2.RegNum); + if (!forcompare) + { + build->Emit(OP_JMP, 1); + build->Emit(OP_LI, to.RegNum, 1); + } + return to; + } +} + +ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build) +{ + return EmitCommon(build, false, false); +} + +void FxCompareEq::EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no) +{ + ExpEmit emit = EmitCommon(build, true, invert); + emit.Free(build); + patchspots_no.Push(build->Emit(OP_JMP, 0)); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxBitOp::FxBitOp(int o, FxExpression *l, FxExpression *r) +: FxBinary(o, l, r) +{ + ValueType = TypeSInt32; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxBitOp::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + + RESOLVE(left, ctx); + RESOLVE(right, ctx); + if (!left || !right) + { + delete this; + return nullptr; + } + + if (left->ValueType == TypeBool && right->ValueType == TypeBool) + { + ValueType = TypeBool; + } + else if (left->IsNumeric() && right->IsNumeric()) + { + if (!Promote(ctx, true)) return nullptr; + } + else + { + ScriptPosition.Message(MSG_ERROR, "Incompatible operands for bit operation"); + delete this; + return nullptr; + } + + if (left->isConstant() && right->isConstant()) + { + int v1 = static_cast(left)->GetValue().GetInt(); + int v2 = static_cast(right)->GetValue().GetInt(); + + FxExpression *e = new FxConstant( + Operator == '&'? v1 & v2 : + Operator == '|'? v1 | v2 : + Operator == '^'? v1 ^ v2 : 0, ScriptPosition); + + delete this; + return e; + } + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxBitOp::Emit(VMFunctionBuilder *build) +{ + assert(left->ValueType->GetRegType() == REGT_INT); + assert(right->ValueType->GetRegType() == REGT_INT); + int instr, rop; + ExpEmit op1, op2; + + op1 = left->Emit(build); + op2 = right->Emit(build); + if (op1.Konst) + { + swapvalues(op1, op2); + } + assert(!op1.Konst); + rop = op2.RegNum; + op2.Free(build); + op1.Free(build); + + instr = Operator == '&' ? OP_AND_RR : + Operator == '|' ? OP_OR_RR : + Operator == '^' ? OP_XOR_RR : -1; + + assert(instr > 0); + ExpEmit to(build, REGT_INT); + build->Emit(instr + op2.Konst, to.RegNum, op1.RegNum, rop); + return to; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxShift::FxShift(int o, FxExpression *l, FxExpression *r) + : FxBinary(o, l, r) +{ + ValueType = TypeSInt32; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxShift::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + RESOLVE(left, ctx); + RESOLVE(right, ctx); + if (!left || !right) + { + delete this; + return nullptr; + } + + if (left->IsNumeric() && right->IsNumeric()) + { + if (!Promote(ctx, true)) return nullptr; + if (ValueType == TypeUInt32 && Operator == TK_RShift) Operator = TK_URShift; + } + else + { + ScriptPosition.Message(MSG_ERROR, "Incompatible operands for shift operation"); + delete this; + return nullptr; + } + + if (left->isConstant() && right->isConstant()) + { + int v1 = static_cast(left)->GetValue().GetInt(); + int v2 = static_cast(right)->GetValue().GetInt(); + + FxExpression *e = new FxConstant( + Operator == TK_LShift ? v1 << v2 : + Operator == TK_RShift ? v1 >> v2 : + Operator == TK_URShift ? int((unsigned int)(v1) >> v2) : 0, ScriptPosition); + + delete this; + return e; + } + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxShift::Emit(VMFunctionBuilder *build) +{ + assert(left->ValueType->GetRegType() == REGT_INT); + assert(right->ValueType->GetRegType() == REGT_INT); + static const VM_UBYTE InstrMap[][4] = + { + { OP_SLL_RR, OP_SLL_KR, OP_SLL_RI }, // TK_LShift + { OP_SRA_RR, OP_SRA_KR, OP_SRA_RI }, // TK_RShift + { OP_SRL_RR, OP_SRL_KR, OP_SRL_RI }, // TK_URShift + }; + int index, instr, rop; + ExpEmit op1, op2; + + index = Operator == TK_LShift ? 0 : + Operator == TK_RShift ? 1 : + Operator == TK_URShift ? 2 : -1; + assert(index >= 0); + op1 = left->Emit(build); + + // Shift instructions use right-hand immediates instead of constant registers. + if (right->isConstant()) + { + rop = static_cast(right)->GetValue().GetInt(); + op2.Konst = true; + } + else + { + op2 = right->Emit(build); + assert(!op2.Konst); + op2.Free(build); + rop = op2.RegNum; + } + + if (!op1.Konst) + { + op1.Free(build); + instr = InstrMap[index][op2.Konst? 2:0]; + } + else + { + assert(!op2.Konst); + instr = InstrMap[index][1]; + } + assert(instr != 0); + ExpEmit to(build, REGT_INT); + build->Emit(instr, to.RegNum, op1.RegNum, rop); + return to; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxLtGtEq::FxLtGtEq(FxExpression *l, FxExpression *r) + : FxBinary(TK_LtGtEq, l, r) +{ + ValueType = TypeSInt32; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxLtGtEq::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + + RESOLVE(left, ctx); + RESOLVE(right, ctx); + if (!left || !right) + { + delete this; + return nullptr; + } + + if (left->IsNumeric() && right->IsNumeric()) + { + Promote(ctx); + } + else + { + ScriptPosition.Message(MSG_ERROR, "<>= expects two numeric operands"); + delete this; + return nullptr; + } + + if (left->isConstant() && right->isConstant()) + { + // let's cut this short and always compare doubles. For integers the result will be exactly the same as with an integer comparison, either signed or unsigned. + auto v1 = static_cast(left)->GetValue().GetFloat(); + auto v2 = static_cast(right)->GetValue().GetFloat(); + auto e = new FxConstant(v1 < v2 ? -1 : v1 > v2 ? 1 : 0, ScriptPosition); + delete this; + return e; + } + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxLtGtEq::Emit(VMFunctionBuilder *build) +{ + ExpEmit op1 = left->Emit(build); + ExpEmit op2 = right->Emit(build); + + assert(op1.RegType == op2.RegType); + assert(op1.RegType == REGT_INT || op1.RegType == REGT_FLOAT); + assert(!op1.Konst || !op2.Konst); + + ExpEmit to(build, REGT_INT); + + int instr = op1.RegType == REGT_INT ? (left->ValueType == TypeUInt32? OP_LTU_RR : OP_LT_RR) : OP_LTF_RR; + if (op1.Konst) instr += 2; + if (op2.Konst) instr++; + + + build->Emit(OP_LI, to.RegNum, 1); // default to 1 + build->Emit(instr, 0, op1.RegNum, op2.RegNum); // if (left < right) + auto j1 = build->Emit(OP_JMP, 1); + build->Emit(OP_LI, to.RegNum, -1); // result is -1 + auto j2 = build->Emit(OP_JMP, 1); // jump to end + build->BackpatchToHere(j1); + build->Emit(instr + OP_LE_RR - OP_LT_RR, 0, op1.RegNum, op2.RegNum); // if (left == right) + auto j3 = build->Emit(OP_JMP, 1); + build->Emit(OP_LI, to.RegNum, 0); // result is 0 + build->BackpatchToHere(j2); + build->BackpatchToHere(j3); + + return to; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxConcat::FxConcat(FxExpression *l, FxExpression *r) + : FxBinary(TK_DotDot, l, r) +{ + ValueType = TypeString; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxConcat::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + + RESOLVE(left, ctx); + RESOLVE(right, ctx); + if (!left || !right) + { + delete this; + return nullptr; + } + + // To concatenate two operands the only requirement is that they are integral types, i.e. can occupy a register + if (left->ValueType->GetRegType() == REGT_NIL || right->ValueType->GetRegType() == REGT_NIL) + { + ScriptPosition.Message(MSG_ERROR, "Invalid operand for string concatenation"); + delete this; + return nullptr; + } + + if (left->isConstant() && right->isConstant() && (left->ValueType == TypeString || left->ValueType == TypeName) && (right->ValueType == TypeString || right->ValueType == TypeName)) + { + // for now this is only types which have a constant string representation. + auto v1 = static_cast(left)->GetValue().GetString(); + auto v2 = static_cast(right)->GetValue().GetString(); + auto e = new FxConstant(v1 + v2, ScriptPosition); + delete this; + return e; + } + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxConcat::Emit(VMFunctionBuilder *build) +{ + ExpEmit op1 = left->Emit(build); + ExpEmit op2 = right->Emit(build); + ExpEmit strng, strng2; + + if (op1.RegType == REGT_STRING && op1.Konst) + { + strng = ExpEmit(build, REGT_STRING); + build->Emit(OP_LKS, strng.RegNum, op1.RegNum); + } + else if (op1.RegType == REGT_STRING) + { + strng = op1; + } + else + { + int cast; + strng = ExpEmit(build, REGT_STRING); + if (op1.Konst) + { + ExpEmit nonconst(build, op1.RegType); + build->Emit(op1.RegType == REGT_INT ? OP_LK : op1.RegType == REGT_FLOAT ? OP_LKF : OP_LKP, nonconst.RegNum, op1.RegNum); + op1 = nonconst; + } + if (op1.RegType == REGT_FLOAT) cast = op1.RegCount == 1 ? CAST_F2S : op1.RegCount == 2 ? CAST_V22S : CAST_V32S; + else if (left->ValueType == TypeUInt32) cast = CAST_U2S; + else if (left->ValueType == TypeName) cast = CAST_N2S; + else if (left->ValueType == TypeSound) cast = CAST_So2S; + else if (left->ValueType == TypeColor) cast = CAST_Co2S; + else if (left->ValueType == TypeSpriteID) cast = CAST_SID2S; + else if (left->ValueType == TypeTextureID) cast = CAST_TID2S; + else if (op1.RegType == REGT_POINTER) cast = CAST_P2S; + else if (op1.RegType == REGT_INT) cast = CAST_I2S; + else assert(false && "Bad type for string concatenation"); + build->Emit(OP_CAST, strng.RegNum, op1.RegNum, cast); + op1.Free(build); + } + + if (op2.RegType == REGT_STRING && op2.Konst) + { + strng2 = ExpEmit(build, REGT_STRING); + build->Emit(OP_LKS, strng2.RegNum, op2.RegNum); + } + else if (op2.RegType == REGT_STRING) + { + strng2 = op2; + } + else + { + int cast; + strng2 = ExpEmit(build, REGT_STRING); + if (op2.Konst) + { + ExpEmit nonconst(build, op2.RegType); + build->Emit(op2.RegType == REGT_INT ? OP_LK : op2.RegType == REGT_FLOAT ? OP_LKF : OP_LKP, nonconst.RegNum, op2.RegNum); + op2 = nonconst; + } + if (op2.RegType == REGT_FLOAT) cast = op2.RegCount == 1 ? CAST_F2S : op2.RegCount == 2 ? CAST_V22S : CAST_V32S; + else if (right->ValueType == TypeUInt32) cast = CAST_U2S; + else if (right->ValueType == TypeName) cast = CAST_N2S; + else if (right->ValueType == TypeSound) cast = CAST_So2S; + else if (right->ValueType == TypeColor) cast = CAST_Co2S; + else if (right->ValueType == TypeSpriteID) cast = CAST_SID2S; + else if (right->ValueType == TypeTextureID) cast = CAST_TID2S; + else if (op2.RegType == REGT_POINTER) cast = CAST_P2S; + else if (op2.RegType == REGT_INT) cast = CAST_I2S; + else assert(false && "Bad type for string concatenation"); + build->Emit(OP_CAST, strng2.RegNum, op2.RegNum, cast); + op2.Free(build); + } + strng.Free(build); + strng2.Free(build); + ExpEmit dest(build, REGT_STRING); + assert(strng.RegType == strng2.RegType && strng.RegType == REGT_STRING); + build->Emit(OP_CONCAT, dest.RegNum, strng.RegNum, strng2.RegNum); + return dest; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxBinaryLogical::FxBinaryLogical(int o, FxExpression *l, FxExpression *r) +: FxExpression(EFX_BinaryLogical, l->ScriptPosition) +{ + Operator=o; + left=l; + right=r; + ValueType = TypeBool; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxBinaryLogical::~FxBinaryLogical() +{ + SAFE_DELETE(left); + SAFE_DELETE(right); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + RESOLVE(left, ctx); + RESOLVE(right, ctx); + ABORT(right && left); + + if (left->ValueType != TypeBool) + { + left = new FxBoolCast(left); + SAFE_RESOLVE(left, ctx); + } + if (right->ValueType != TypeBool) + { + right = new FxBoolCast(right); + SAFE_RESOLVE(right, ctx); + } + + int b_left=-1, b_right=-1; + if (left->isConstant()) b_left = static_cast(left)->GetValue().GetBool(); + if (right->isConstant()) b_right = static_cast(right)->GetValue().GetBool(); + + // Do some optimizations. This will throw out all sub-expressions that are not + // needed to retrieve the final result. + if (Operator == TK_AndAnd) + { + if (b_left==0 || b_right==0) + { + FxExpression *x = new FxConstant(true, ScriptPosition); + delete this; + return x; + } + else if (b_left==1 && b_right==1) + { + FxExpression *x = new FxConstant(false, ScriptPosition); + delete this; + return x; + } + else if (b_left==1) + { + FxExpression *x = right; + right=nullptr; + delete this; + return x; + } + else if (b_right==1) + { + FxExpression *x = left; + left=nullptr; + delete this; + return x; + } + } + else if (Operator == TK_OrOr) + { + if (b_left==1 || b_right==1) + { + FxExpression *x = new FxConstant(true, ScriptPosition); + delete this; + return x; + } + if (b_left==0 && b_right==0) + { + FxExpression *x = new FxConstant(false, ScriptPosition); + delete this; + return x; + } + else if (b_left==0) + { + FxExpression *x = right; + right=nullptr; + delete this; + return x; + } + else if (b_right==0) + { + FxExpression *x = left; + left=nullptr; + delete this; + return x; + } + } + Flatten(); + return this; +} + +//========================================================================== +// +// flatten a list of the same operator into a single node. +// +//========================================================================== + +void FxBinaryLogical::Flatten() +{ + if (left->ExprType == EFX_BinaryLogical && static_cast(left)->Operator == Operator) + { + list = std::move(static_cast(left)->list); + delete left; + } + else + { + list.Push(left); + } + + if (right->ExprType == EFX_BinaryLogical && static_cast(right)->Operator == Operator) + { + auto &rlist = static_cast(right)->list; + auto cnt = rlist.Size(); + auto v = list.Reserve(cnt); + for (unsigned i = 0; i < cnt; i++) + { + list[v + i] = rlist[i]; + rlist[i] = nullptr; + } + delete right; + } + else + { + list.Push(right); + } + left = right = nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxBinaryLogical::Emit(VMFunctionBuilder *build) +{ + TArray yes, no; + bool invert = Operator == TK_OrOr; + + for (unsigned i = 0; i < list.Size(); i++) + { + list[i]->EmitCompare(build, invert, yes, no); + } + build->BackpatchListToHere(yes); + ExpEmit to(build, REGT_INT); + build->Emit(OP_LI, to.RegNum, (Operator == TK_AndAnd) ? 1 : 0); + build->Emit(OP_JMP, 1); + build->BackpatchListToHere(no); + auto ctarget = build->Emit(OP_LI, to.RegNum, (Operator == TK_AndAnd) ? 0 : 1); + list.DeleteAndClear(); + list.ShrinkToFit(); + return to; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxDotCross::FxDotCross(int o, FxExpression *l, FxExpression *r) + : FxExpression(EFX_DotCross, l->ScriptPosition) +{ + Operator = o; + left = l; + right = r; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxDotCross::~FxDotCross() +{ + SAFE_DELETE(left); + SAFE_DELETE(right); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxDotCross::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + RESOLVE(left, ctx); + RESOLVE(right, ctx); + ABORT(right && left); + + if (!left->IsVector() || left->ValueType != right->ValueType || (Operator == TK_Cross && left->ValueType != TypeVector3)) + { + ScriptPosition.Message(MSG_ERROR, "Incompatible operants for %sproduct", Operator == TK_Cross ? "cross-" : "dot-"); + delete this; + return nullptr; + } + ValueType = Operator == TK_Cross ? (PType*)TypeVector3 : TypeFloat64; + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxDotCross::Emit(VMFunctionBuilder *build) +{ + ExpEmit to(build, ValueType->GetRegType(), ValueType->GetRegCount()); + ExpEmit op1 = left->Emit(build); + ExpEmit op2 = right->Emit(build); + int op = Operator == TK_Cross ? OP_CROSSV_RR : left->ValueType == TypeVector3 ? OP_DOTV3_RR : OP_DOTV2_RR; + build->Emit(op, to.RegNum, op1.RegNum, op2.RegNum); + op1.Free(build); + op2.Free(build); + return to; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxTypeCheck::FxTypeCheck(FxExpression *l, FxExpression *r) + : FxExpression(EFX_TypeCheck, l->ScriptPosition) +{ + left = new FxTypeCast(l, NewPointer(RUNTIME_CLASS(DObject)), false); + right = new FxClassTypeCast(NewClassPointer(RUNTIME_CLASS(DObject)), r); + EmitTail = false; + ValueType = TypeBool; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxTypeCheck::~FxTypeCheck() +{ + SAFE_DELETE(left); + SAFE_DELETE(right); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxTypeCheck::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + RESOLVE(left, ctx); + RESOLVE(right, ctx); + ABORT(right && left); + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxTypeCheck::EmitCommon(VMFunctionBuilder *build) +{ + ExpEmit castee = left->Emit(build); + ExpEmit casttype = right->Emit(build); + castee.Free(build); + casttype.Free(build); + ExpEmit ares(build, REGT_POINTER); + build->Emit(casttype.Konst ? OP_DYNCAST_K : OP_DYNCAST_R, ares.RegNum, castee.RegNum, casttype.RegNum); + return ares; +} + +ExpEmit FxTypeCheck::Emit(VMFunctionBuilder *build) +{ + ExpEmit ares = EmitCommon(build); + ares.Free(build); + ExpEmit bres(build, REGT_INT); + build->Emit(OP_CASTB, bres.RegNum, ares.RegNum, CASTB_A); + return bres; +} + +void FxTypeCheck::EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no) +{ + ExpEmit ares = EmitCommon(build); + ares.Free(build); + build->Emit(OP_EQA_K, !invert, ares.RegNum, build->GetConstantAddress(nullptr, ATAG_OBJECT)); + patchspots_no.Push(build->Emit(OP_JMP, 0)); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxDynamicCast::FxDynamicCast(PClass * cls, FxExpression *r) + : FxExpression(EFX_DynamicCast, r->ScriptPosition) +{ + expr = r; + CastType = cls; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxDynamicCast::~FxDynamicCast() +{ + SAFE_DELETE(expr); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxDynamicCast::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(expr, ctx); + if (expr->ExprType == EFX_GetDefaultByType) + { + int a = 0; + } + bool constflag = expr->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(expr->ValueType)->IsConst; + if (constflag) + { + // readonly pointers are normally only used for class defaults which lack type information to be cast properly, so we have to error out here. + ScriptPosition.Message(MSG_ERROR, "Cannot cast a readonly pointer"); + delete this; + return nullptr; + } + expr = new FxTypeCast(expr, NewPointer(RUNTIME_CLASS(DObject), constflag), true, true); + expr = expr->Resolve(ctx); + if (expr == nullptr) + { + delete this; + return nullptr; + } + ValueType = NewPointer(CastType, constflag); + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxDynamicCast::Emit(VMFunctionBuilder *build) +{ + ExpEmit castee = expr->Emit(build); + castee.Free(build); + ExpEmit ares(build, REGT_POINTER); + build->Emit(OP_DYNCAST_K, ares.RegNum, castee.RegNum, build->GetConstantAddress(CastType, ATAG_OBJECT)); + return ares; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxConditional::FxConditional(FxExpression *c, FxExpression *t, FxExpression *f) +: FxExpression(EFX_Conditional, c->ScriptPosition) +{ + condition = c; + truex=t; + falsex=f; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxConditional::~FxConditional() +{ + SAFE_DELETE(condition); + SAFE_DELETE(truex); + SAFE_DELETE(falsex); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxConditional::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + RESOLVE(condition, ctx); + RESOLVE(truex, ctx); + RESOLVE(falsex, ctx); + ABORT(condition && truex && falsex); + + if (truex->ValueType == falsex->ValueType) + ValueType = truex->ValueType; + else if (truex->ValueType == TypeBool && falsex->ValueType == TypeBool) + ValueType = TypeBool; + else if (truex->IsInteger() && falsex->IsInteger()) + ValueType = TypeSInt32; + else if (truex->IsNumeric() && falsex->IsNumeric()) + ValueType = TypeFloat64; + else if (truex->IsPointer() && falsex->ValueType == TypeNullPtr) + ValueType = truex->ValueType; + else if (falsex->IsPointer() && truex->ValueType == TypeNullPtr) + ValueType = falsex->ValueType; + else + ValueType = TypeVoid; + //else if (truex->ValueType != falsex->ValueType) + + if (ValueType->GetRegType() == REGT_NIL) + { + ScriptPosition.Message(MSG_ERROR, "Incompatible types for ?: operator"); + delete this; + return nullptr; + } + + if (condition->ValueType != TypeBool) + { + condition = new FxBoolCast(condition); + SAFE_RESOLVE(condition, ctx); + } + + if (condition->isConstant()) + { + ExpVal condval = static_cast(condition)->GetValue(); + bool result = condval.GetBool(); + + FxExpression *e = result? truex:falsex; + delete (result? falsex:truex); + falsex = truex = nullptr; + delete this; + return e; + } + + if (IsFloat()) + { + if (truex->ValueType->GetRegType() != REGT_FLOAT) + { + truex = new FxFloatCast(truex); + RESOLVE(truex, ctx); + } + if (falsex->ValueType->GetRegType() != REGT_FLOAT) + { + falsex = new FxFloatCast(falsex); + RESOLVE(falsex, ctx); + } + } + + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxConditional::Emit(VMFunctionBuilder *build) +{ + size_t truejump; + ExpEmit out, falseout; + + // The true and false expressions ought to be assigned to the + // same temporary instead of being copied to it. Oh well; good enough + // for now. + TArray yes, no; + condition->EmitCompare(build, false, yes, no); + + build->BackpatchListToHere(yes); + + if (truex->isConstant() && truex->ValueType->GetRegType() == REGT_INT) + { + out = ExpEmit(build, REGT_INT); + build->EmitLoadInt(out.RegNum, static_cast(truex)->GetValue().GetInt()); + } + else + { + ExpEmit trueop = truex->Emit(build); + if (trueop.Konst) + { + trueop.Free(build); + if (trueop.RegType == REGT_FLOAT) + { + out = ExpEmit(build, REGT_FLOAT); + build->Emit(OP_LKF, out.RegNum, trueop.RegNum); + } + else if (trueop.RegType == REGT_POINTER) + { + out = ExpEmit(build, REGT_POINTER); + build->Emit(OP_LKP, out.RegNum, trueop.RegNum); + } + else + { + assert(trueop.RegType == REGT_STRING); + out = ExpEmit(build, REGT_STRING); + build->Emit(OP_LKS, out.RegNum, trueop.RegNum); + } + } + else + { + // Use the register returned by the true condition as the + // target for the false condition. + out = trueop; + } + } + // Make sure to skip the false path. + truejump = build->Emit(OP_JMP, 0); + + // Evaluate false expression. + build->BackpatchListToHere(no); + if (falsex->isConstant() && falsex->ValueType->GetRegType() == REGT_INT) + { + build->EmitLoadInt(out.RegNum, static_cast(falsex)->GetValue().GetInt()); + } + else + { + ExpEmit falseop = falsex->Emit(build); + if (falseop.Konst) + { + if (falseop.RegType == REGT_FLOAT) + { + build->Emit(OP_LKF, out.RegNum, falseop.RegNum); + } + else if (falseop.RegType == REGT_POINTER) + { + build->Emit(OP_LKP, out.RegNum, falseop.RegNum); + } + else + { + assert(falseop.RegType == REGT_STRING); + build->Emit(OP_LKS, out.RegNum, falseop.RegNum); + } + falseop.Free(build); + } + else + { + // Move result from the register returned by "false" to the one + // returned by "true" so that only one register is returned by + // this tree. + falseop.Free(build); + build->Emit(falsex->ValueType->GetMoveOp(), out.RegNum, falseop.RegNum, 0); + } + } + build->BackpatchToHere(truejump); + + return out; +} + +//========================================================================== +// +// +// +//========================================================================== +FxAbs::FxAbs(FxExpression *v) +: FxExpression(EFX_Abs, v->ScriptPosition) +{ + val = v; + ValueType = v->ValueType; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxAbs::~FxAbs() +{ + SAFE_DELETE(val); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxAbs::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(val, ctx); + + if (val->ValueType == TypeBool) // abs of a boolean is always the same as the operand + { + auto v = val; + val = nullptr; + delete this; + return v; + } + if (!val->IsNumeric()) + { + ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return nullptr; + } + else if (val->isConstant()) + { + ExpVal value = static_cast(val)->GetValue(); + switch (value.Type->GetRegType()) + { + case REGT_INT: + value.Int = abs(value.Int); + break; + + case REGT_FLOAT: + value.Float = fabs(value.Float); + break; + + default: + // shouldn't happen + delete this; + return nullptr; + } + FxExpression *x = new FxConstant(value, ScriptPosition); + delete this; + return x; + } + ValueType = val->ValueType; + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxAbs::Emit(VMFunctionBuilder *build) +{ + assert(ValueType == val->ValueType); + ExpEmit from = val->Emit(build); + ExpEmit to; + assert(from.Konst == 0); + assert(ValueType->GetRegCount() == 1); + // Do it in-place, unless a local variable + if (from.Fixed) + { + to = ExpEmit(build, from.RegType); + from.Free(build); + } + else + { + to = from; + } + + if (ValueType->GetRegType() == REGT_INT) + { + build->Emit(OP_ABS, to.RegNum, from.RegNum, 0); + } + else + { + build->Emit(OP_FLOP, to.RegNum, from.RegNum, FLOP_ABS); + } + return to; +} + +//========================================================================== +// +// +// +//========================================================================== +FxATan2::FxATan2(FxExpression *y, FxExpression *x, const FScriptPosition &pos) +: FxExpression(EFX_ATan2, pos) +{ + yval = y; + xval = x; +} + +//========================================================================== +// +// +// +//========================================================================== +FxATan2::~FxATan2() +{ + SAFE_DELETE(yval); + SAFE_DELETE(xval); +} + +//========================================================================== +// +// +// +//========================================================================== +FxExpression *FxATan2::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(yval, ctx); + SAFE_RESOLVE(xval, ctx); + + if (!yval->IsNumeric() || !xval->IsNumeric()) + { + ScriptPosition.Message(MSG_ERROR, "numeric value expected for parameter"); + delete this; + return nullptr; + } + if (yval->isConstant() && xval->isConstant()) + { + double y = static_cast(yval)->GetValue().GetFloat(); + double x = static_cast(xval)->GetValue().GetFloat(); + FxExpression *z = new FxConstant(g_atan2(y, x) * (180 / M_PI), ScriptPosition); + delete this; + return z; + } + if (yval->ValueType->GetRegType() != REGT_FLOAT && !yval->isConstant()) + { + yval = new FxFloatCast(yval); + } + if (xval->ValueType->GetRegType() != REGT_FLOAT && !xval->isConstant()) + { + xval = new FxFloatCast(xval); + } + ValueType = TypeFloat64; + return this; +} + +//========================================================================== +// +// +// +//========================================================================== +ExpEmit FxATan2::Emit(VMFunctionBuilder *build) +{ + ExpEmit yreg = ToReg(build, yval); + ExpEmit xreg = ToReg(build, xval); + yreg.Free(build); + xreg.Free(build); + ExpEmit out(build, REGT_FLOAT); + build->Emit(OP_ATAN2, out.RegNum, yreg.RegNum, xreg.RegNum); + return out; +} + +//========================================================================== +// +// The atan2 opcode only takes registers as parameters, so any constants +// must be loaded into registers first. +// +//========================================================================== +ExpEmit FxATan2::ToReg(VMFunctionBuilder *build, FxExpression *val) +{ + if (val->isConstant()) + { + ExpEmit reg(build, REGT_FLOAT); + build->Emit(OP_LKF, reg.RegNum, build->GetConstantFloat(static_cast(val)->GetValue().GetFloat())); + return reg; + } + return val->Emit(build); +} + +//========================================================================== +// +// +// +//========================================================================== +FxMinMax::FxMinMax(TArray &expr, FName type, const FScriptPosition &pos) +: FxExpression(EFX_MinMax, pos), Type(type) +{ + assert(expr.Size() > 0); + assert(type == NAME_Min || type == NAME_Max); + + choices.Resize(expr.Size()); + for (unsigned i = 0; i < expr.Size(); ++i) + { + choices[i] = expr[i]; + expr[i] = nullptr; + } +} + +//========================================================================== +// +// +// +//========================================================================== +FxExpression *FxMinMax::Resolve(FCompileContext &ctx) +{ + unsigned int i; + int intcount, floatcount; + + CHECKRESOLVED(); + + // Determine if float or int + intcount = floatcount = 0; + for (i = 0; i < choices.Size(); ++i) + { + RESOLVE(choices[i], ctx); + ABORT(choices[i]); + + if (choices[i]->IsFloat()) + { + floatcount++; + } + else if (choices[i]->IsInteger()) + { + intcount++; + } + else + { + ScriptPosition.Message(MSG_ERROR, "Arguments must be of type int or float"); + delete this; + return nullptr; + } + } + if (floatcount != 0) + { + ValueType = TypeFloat64; + if (intcount != 0) + { // There are some ints that need to be cast to floats + for (i = 0; i < choices.Size(); ++i) + { + if (choices[i]->ValueType->GetRegType() == REGT_INT) + { + choices[i] = new FxFloatCast(choices[i]); + RESOLVE(choices[i], ctx); + ABORT(choices[i]); + } + } + } + } + else + { + ValueType = TypeSInt32; + } + + // If at least two arguments are constants, they can be solved now. + + // Look for first constant + for (i = 0; i < choices.Size(); ++i) + { + if (choices[i]->isConstant()) + { + ExpVal best = static_cast(choices[i])->GetValue(); + // Compare against remaining constants, which are removed. + // The best value gets stored in this one. + for (unsigned j = i + 1; j < choices.Size(); ) + { + if (!choices[j]->isConstant()) + { + j++; + } + else + { + ExpVal value = static_cast(choices[j])->GetValue(); + assert(value.Type == ValueType); + if (Type == NAME_Min) + { + if (value.Type->GetRegType() == REGT_FLOAT) + { + if (value.Float < best.Float) + { + best.Float = value.Float; + } + } + else + { + if (value.Int < best.Int) + { + best.Int = value.Int; + } + } + } + else + { + if (value.Type->GetRegType() == REGT_FLOAT) + { + if (value.Float > best.Float) + { + best.Float = value.Float; + } + } + else + { + if (value.Int > best.Int) + { + best.Int = value.Int; + } + } + } + delete choices[j]; + choices[j] = nullptr; + choices.Delete(j); + } + } + FxExpression *x = new FxConstant(best, ScriptPosition); + if (i == 0 && choices.Size() == 1) + { // Every choice was constant + delete this; + return x; + } + delete choices[i]; + choices[i] = x; + break; + } + } + return this; +} + +//========================================================================== +// +// +// +//========================================================================== +static void EmitLoad(VMFunctionBuilder *build, const ExpEmit resultreg, const ExpVal &value) +{ + if (resultreg.RegType == REGT_FLOAT) + { + build->Emit(OP_LKF, resultreg.RegNum, build->GetConstantFloat(value.GetFloat())); + } + else + { + build->EmitLoadInt(resultreg.RegNum, value.GetInt()); + } +} + +ExpEmit FxMinMax::Emit(VMFunctionBuilder *build) +{ + unsigned i; + int opcode; + + assert(choices.Size() > 0); + assert(OP_MAXF_RK == OP_MAXF_RR+1); + assert(OP_MAX_RK == OP_MAX_RR+1); + assert(OP_MIN_RK == OP_MIN_RR+1); + assert(OP_MIN_RK == OP_MIN_RR+1); + + if (Type == NAME_Min) + { + opcode = ValueType->GetRegType() == REGT_FLOAT ? OP_MINF_RR : OP_MIN_RR; + } + else + { + opcode = ValueType->GetRegType() == REGT_FLOAT ? OP_MAXF_RR : OP_MAX_RR; + } + + ExpEmit bestreg; + + // Get first value into a register. This will also be the result register. + if (choices[0]->isConstant()) + { + bestreg = ExpEmit(build, ValueType->GetRegType()); + EmitLoad(build, bestreg, static_cast(choices[0])->GetValue()); + } + else + { + bestreg = choices[0]->Emit(build); + } + + // Compare every choice. Better matches get copied to the bestreg. + for (i = 1; i < choices.Size(); ++i) + { + ExpEmit checkreg = choices[i]->Emit(build); + assert(checkreg.RegType == bestreg.RegType); + build->Emit(opcode + checkreg.Konst, bestreg.RegNum, bestreg.RegNum, checkreg.RegNum); + checkreg.Free(build); + } + return bestreg; +} + +//========================================================================== +// +// +// +//========================================================================== +FxRandom::FxRandom(FRandom * r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos, bool nowarn) +: FxExpression(EFX_Random, pos) +{ + EmitTail = false; + if (mi != nullptr && ma != nullptr) + { + min = new FxIntCast(mi, nowarn); + max = new FxIntCast(ma, nowarn); + } + else min = max = nullptr; + rng = r; + ValueType = TypeSInt32; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxRandom::~FxRandom() +{ + SAFE_DELETE(min); + SAFE_DELETE(max); +} + +//========================================================================== +// +// +// +//========================================================================== + +PPrototype *FxRandom::ReturnProto() +{ + EmitTail = true; + return FxExpression::ReturnProto(); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxRandom::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + if (min && max) + { + RESOLVE(min, ctx); + RESOLVE(max, ctx); + ABORT(min && max); + assert(min->ValueType == ValueType); + assert(max->ValueType == ValueType); + } + return this; +}; + + +//========================================================================== +// +// +// +//========================================================================== + +int BuiltinRandom(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) +{ + assert(numparam >= 1 && numparam <= 3); + FRandom *rng = reinterpret_cast(param[0].a); + if (numparam == 1) + { + ACTION_RETURN_INT((*rng)()); + } + else if (numparam == 2) + { + int maskval = param[1].i; + ACTION_RETURN_INT(rng->Random2(maskval)); + } + else if (numparam == 3) + { + int min = param[1].i, max = param[2].i; + if (max < min) + { + swapvalues(max, min); + } + ACTION_RETURN_INT((*rng)(max - min + 1) + min); + } + + // Shouldn't happen + return 0; +} + +ExpEmit FxRandom::Emit(VMFunctionBuilder *build) +{ + // Call DecoRandom to generate a random number. + VMFunction *callfunc; + PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom, BuiltinRandom); + + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); + assert(((PSymbolVMFunction *)sym)->Function != nullptr); + callfunc = ((PSymbolVMFunction *)sym)->Function; + + int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); + + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); + if (min != nullptr && max != nullptr) + { + EmitParameter(build, min, ScriptPosition); + EmitParameter(build, max, ScriptPosition); + build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); + } + else + { + build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 1, 1); + } + + if (EmitTail) + { + ExpEmit call; + call.Final = true; + return call; + } + + ExpEmit out(build, REGT_INT); + build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum); + return out; +} + +//========================================================================== +// +// +// +//========================================================================== +FxRandomPick::FxRandomPick(FRandom *r, TArray &expr, bool floaty, const FScriptPosition &pos, bool nowarn) +: FxExpression(EFX_RandomPick, pos) +{ + assert(expr.Size() > 0); + choices.Resize(expr.Size()); + for (unsigned int index = 0; index < expr.Size(); index++) + { + if (floaty) + { + choices[index] = new FxFloatCast(expr[index]); + expr[index] = nullptr; + } + else + { + choices[index] = new FxIntCast(expr[index], nowarn); + expr[index] = nullptr; + } + + } + rng = r; + if (floaty) + { + ValueType = TypeFloat64; + } + else + { + ValueType = TypeSInt32; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +FxRandomPick::~FxRandomPick() +{ +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxRandomPick::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + for (unsigned int index = 0; index < choices.Size(); index++) + { + RESOLVE(choices[index], ctx); + ABORT(choices[index]); + assert(choices[index]->ValueType == ValueType); + } + return this; +}; + + +//========================================================================== +// +// FxPick :: Emit +// +// The expression: +// a = pick[rng](i_0, i_1, i_2, ..., i_n) +// [where i_x is a complete expression and not just a value] +// is syntactic sugar for: +// +// switch(random[rng](0, n)) { +// case 0: a = i_0; +// case 1: a = i_1; +// case 2: a = i_2; +// ... +// case n: a = i_n; +// } +// +//========================================================================== + +ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build) +{ + unsigned i; + + assert(choices.Size() > 0); + + // Call BuiltinRandom to generate a random number. + VMFunction *callfunc; + PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom, BuiltinRandom); + + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); + assert(((PSymbolVMFunction *)sym)->Function != nullptr); + callfunc = ((PSymbolVMFunction *)sym)->Function; + + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); + build->EmitParamInt(0); + build->EmitParamInt(choices.Size() - 1); + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); + + ExpEmit resultreg(build, REGT_INT); + build->Emit(OP_RESULT, 0, REGT_INT, resultreg.RegNum); + build->Emit(OP_IJMP, resultreg.RegNum, 0); + + // Free the result register now. The simple code generation algorithm should + // automatically pick it as the destination register for each case. + resultreg.Free(build); + + // For floating point results, we need to get a new register, since we can't + // reuse the integer one used to store the random result. + if (ValueType->GetRegType() == REGT_FLOAT) + { + resultreg = ExpEmit(build, REGT_FLOAT); + resultreg.Free(build); + } + + // Allocate space for the jump table. + size_t jumptable = build->Emit(OP_JMP, 0); + for (i = 1; i < choices.Size(); ++i) + { + build->Emit(OP_JMP, 0); + } + + // Emit each case + TArray finishes(choices.Size() - 1); + for (unsigned i = 0; i < choices.Size(); ++i) + { + build->BackpatchToHere(jumptable + i); + if (choices[i]->isConstant()) + { + EmitLoad(build, resultreg, static_cast(choices[i])->GetValue()); + } + else + { + ExpEmit casereg = choices[i]->Emit(build); + if (casereg.RegNum != resultreg.RegNum) + { // The result of the case is in a different register from what + // was expected. Copy it to the one we wanted. + + resultreg.Reuse(build); // This is really just for the assert in Reuse() + build->Emit(ValueType->GetRegType() == REGT_INT ? OP_MOVE : OP_MOVEF, resultreg.RegNum, casereg.RegNum, 0); + resultreg.Free(build); + } + // Free this register so the remaining cases can use it. + casereg.Free(build); + } + // All but the final case needs a jump to the end of the expression's code. + if (i + 1 < choices.Size()) + { + size_t loc = build->Emit(OP_JMP, 0); + finishes.Push(loc); + } + } + // Backpatch each case (except the last, since it ends here) to jump to here. + for (i = 0; i < choices.Size() - 1; ++i) + { + build->BackpatchToHere(finishes[i]); + } + // The result register needs to be in-use when we return. + // It should have been freed earlier, so restore its in-use flag. + resultreg.Reuse(build); + choices.DeleteAndClear(); + choices.ShrinkToFit(); + return resultreg; +} + +//========================================================================== +// +// +// +//========================================================================== +FxFRandom::FxFRandom(FRandom *r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos) +: FxRandom(r, nullptr, nullptr, pos, true) +{ + if (mi != nullptr && ma != nullptr) + { + min = new FxFloatCast(mi); + max = new FxFloatCast(ma); + } + ValueType = TypeFloat64; + ExprType = EFX_FRandom; +} + +//========================================================================== +// +// +// +//========================================================================== + +int BuiltinFRandom(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) +{ + assert(numparam == 1 || numparam == 3); + FRandom *rng = reinterpret_cast(param[0].a); + + int random = (*rng)(0x40000000); + double frandom = random / double(0x40000000); + + if (numparam == 3) + { + double min = param[1].f, max = param[2].f; + if (max < min) + { + swapvalues(max, min); + } + ACTION_RETURN_FLOAT(frandom * (max - min) + min); + } + else + { + ACTION_RETURN_FLOAT(frandom); + } +} + +ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) +{ + // Call the BuiltinFRandom function to generate a floating point random number.. + VMFunction *callfunc; + PSymbol *sym = FindBuiltinFunction(NAME_BuiltinFRandom, BuiltinFRandom); + + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); + assert(((PSymbolVMFunction *)sym)->Function != nullptr); + callfunc = ((PSymbolVMFunction *)sym)->Function; + + int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); + + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); + if (min != nullptr && max != nullptr) + { + EmitParameter(build, min, ScriptPosition); + EmitParameter(build, max, ScriptPosition); + build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); + } + else + { + build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 1, 1); + } + + if (EmitTail) + { + ExpEmit call; + call.Final = true; + return call; + } + + ExpEmit out(build, REGT_FLOAT); + build->Emit(OP_RESULT, 0, REGT_FLOAT, out.RegNum); + return out; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxRandom2::FxRandom2(FRandom *r, FxExpression *m, const FScriptPosition &pos, bool nowarn) +: FxExpression(EFX_Random2, pos) +{ + EmitTail = false; + rng = r; + if (m) mask = new FxIntCast(m, nowarn); + else mask = new FxConstant(-1, pos); + ValueType = TypeSInt32; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxRandom2::~FxRandom2() +{ + SAFE_DELETE(mask); +} + +//========================================================================== +// +// +// +//========================================================================== + +PPrototype *FxRandom2::ReturnProto() +{ + EmitTail = true; + return FxExpression::ReturnProto(); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxRandom2::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(mask, ctx); + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) +{ + // Call the BuiltinRandom function to generate the random number. + VMFunction *callfunc; + PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandom, BuiltinRandom); + + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); + assert(((PSymbolVMFunction *)sym)->Function != nullptr); + callfunc = ((PSymbolVMFunction *)sym)->Function; + + int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); + + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); + EmitParameter(build, mask, ScriptPosition); + build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1); + + if (EmitTail) + { + ExpEmit call; + call.Final = true; + return call; + } + + ExpEmit out(build, REGT_INT); + build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum); + return out; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxIdentifier::FxIdentifier(FName name, const FScriptPosition &pos) +: FxExpression(EFX_Identifier, pos) +{ + Identifier = name; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) +{ + PSymbol * sym; + FxExpression *newex = nullptr; + int num; + + CHECKRESOLVED(); + + // Local variables have highest priority. + FxLocalVariableDeclaration *local = ctx.FindLocalVariable(Identifier); + if (local != nullptr) + { + if (local->ExprType == EFX_StaticArray) + { + auto x = new FxStaticArrayVariable(local, ScriptPosition); + delete this; + return x->Resolve(ctx); + } + else if (local->ValueType->GetRegType() != REGT_NIL) + { + auto x = new FxLocalVariable(local, ScriptPosition); + delete this; + return x->Resolve(ctx); + } + else + { + auto x = new FxStackVariable(local->ValueType, local->StackOffset, ScriptPosition); + delete this; + return x->Resolve(ctx); + } + } + + if (Identifier == NAME_Default) + { + if (ctx.Function->Variants[0].SelfClass == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unable to access class defaults from static function"); + delete this; + return nullptr; + } + if (!ctx.Function->Variants[0].SelfClass->IsKindOf(RUNTIME_CLASS(PClassActor))) + { + ScriptPosition.Message(MSG_ERROR, "'Default' requires an actor type."); + delete this; + return nullptr; + } + + FxExpression * x = new FxClassDefaults(new FxSelf(ScriptPosition), ScriptPosition); + delete this; + return x->Resolve(ctx); + } + + // Ugh, the horror. Constants need to be taken from the owning class, but members from the self class to catch invalid accesses here... + // see if the current class (if valid) defines something with this name. + PSymbolTable *symtbl; + + // first check fields in self + if ((sym = ctx.FindInSelfClass(Identifier, symtbl)) != nullptr) + { + if (sym->IsKindOf(RUNTIME_CLASS(PField))) + { + FxExpression *self = new FxSelf(ScriptPosition); + self = self->Resolve(ctx); + newex = ResolveMember(ctx, ctx.Function->Variants[0].SelfClass, self, ctx.Function->Variants[0].SelfClass); + ABORT(newex); + goto foundit; + } + } + + // now check in the owning class. + if (newex == nullptr && (sym = ctx.FindInClass(Identifier, symtbl)) != nullptr) + { + if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) + { + ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as class constant\n", Identifier.GetChars()); + newex = FxConstant::MakeConstant(sym, ScriptPosition); + goto foundit; + } + // Do this check for ZScript as well, so that a clearer error message can be printed. MSG_OPTERROR will default to MSG_ERROR there. + else if (ctx.Function->Variants[0].SelfClass != ctx.Class && sym->IsKindOf(RUNTIME_CLASS(PField))) + { + FxExpression *self = new FxSelf(ScriptPosition, true); + self = self->Resolve(ctx); + newex = ResolveMember(ctx, ctx.Class, self, ctx.Class); + ABORT(newex); + ScriptPosition.Message(MSG_OPTERROR, "Self pointer used in ambiguous context; VM execution may abort!"); + ctx.Unsafe = true; + goto foundit; + } + else + { + if (sym->IsKindOf(RUNTIME_CLASS(PFunction))) + { + ScriptPosition.Message(MSG_ERROR, "Function '%s' used without ().\n", Identifier.GetChars()); + } + else + { + ScriptPosition.Message(MSG_ERROR, "Invalid member identifier '%s'.\n", Identifier.GetChars()); + } + delete this; + return nullptr; + } + } + + if (noglobal) + { + // This is needed to properly resolve class names on the left side of the member access operator + ValueType = TypeError; + return this; + } + + // now check the global identifiers. + if (newex == nullptr && (sym = ctx.FindGlobal(Identifier)) != nullptr) + { + if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) + { + ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as global constant\n", Identifier.GetChars()); + newex = FxConstant::MakeConstant(sym, ScriptPosition); + goto foundit; + } + else if (sym->IsKindOf(RUNTIME_CLASS(PField))) + { + // internally defined global variable + ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as global variable\n", Identifier.GetChars()); + newex = new FxGlobalVariable(static_cast(sym), ScriptPosition); + goto foundit; + } + else + { + ScriptPosition.Message(MSG_ERROR, "Invalid global identifier '%s'\n", Identifier.GetChars()); + delete this; + return nullptr; + } + } + + // and line specials + if (newex == nullptr && (num = P_FindLineSpecial(Identifier, nullptr, nullptr))) + { + ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as line special %d\n", Identifier.GetChars(), num); + newex = new FxConstant(num, ScriptPosition); + goto foundit; + } + + if (auto *cvar = FindCVar(Identifier.GetChars(), nullptr)) + { + if (cvar->GetFlags() & CVAR_USERINFO) + { + ScriptPosition.Message(MSG_ERROR, "Cannot access userinfo CVARs directly. Use GetCVar() instead."); + delete this; + return nullptr; + } + newex = new FxCVar(cvar, ScriptPosition); + goto foundit; + } + + ScriptPosition.Message(MSG_ERROR, "Unknown identifier '%s'", Identifier.GetChars()); + delete this; + return nullptr; + +foundit: + delete this; + return newex? newex->Resolve(ctx) : nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PStruct *classctx, FxExpression *&object, PStruct *objtype) +{ + PSymbol *sym; + PSymbolTable *symtbl; + bool isclass = objtype->IsKindOf(RUNTIME_CLASS(PClass)); + + if (Identifier == NAME_Default) + { + if (!objtype->IsKindOf(RUNTIME_CLASS(PClassActor))) + { + ScriptPosition.Message(MSG_ERROR, "'Default' requires an actor type."); + delete this; + return nullptr; + } + + FxExpression * x = new FxClassDefaults(object, ScriptPosition); + object = nullptr; + delete this; + return x->Resolve(ctx); + } + + if ((sym = objtype->Symbols.FindSymbolInTable(Identifier, symtbl)) != nullptr) + { + if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) + { + ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as %s constant\n", Identifier.GetChars(), isclass ? "class" : "struct"); + delete object; + object = nullptr; + return FxConstant::MakeConstant(sym, ScriptPosition); + } + else if (sym->IsKindOf(RUNTIME_CLASS(PField))) + { + PField *vsym = static_cast(sym); + + // We have 4 cases to consider here: + // 1. The symbol is a static/meta member (not implemented yet) which is always accessible. + // 2. This is a static function + // 3. This is an action function with a restricted self pointer + // 4. This is a normal member or unrestricted action function. + if (vsym->Flags & VARF_Deprecated && !ctx.FromDecorate) + { + ScriptPosition.Message(MSG_WARNING, "Accessing deprecated member variable %s", vsym->SymbolName.GetChars()); + } + if ((vsym->Flags & VARF_Private) && symtbl != &classctx->Symbols) + { + ScriptPosition.Message(MSG_ERROR, "Private member %s not accessible", vsym->SymbolName.GetChars()); + return nullptr; + } + + auto x = isclass ? new FxClassMember(object, vsym, ScriptPosition) : new FxStructMember(object, vsym, ScriptPosition); + object = nullptr; + return x->Resolve(ctx); + } + else + { + if (sym->IsKindOf(RUNTIME_CLASS(PFunction))) + { + ScriptPosition.Message(MSG_ERROR, "Function '%s' used without ().\n", Identifier.GetChars()); + } + else + { + ScriptPosition.Message(MSG_ERROR, "Invalid member identifier '%s'.\n", Identifier.GetChars()); + } + delete object; + object = nullptr; + return nullptr; + } + } + else + { + ScriptPosition.Message(MSG_ERROR, "Unknown identifier '%s'", Identifier.GetChars()); + delete object; + object = nullptr; + return nullptr; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +FxMemberIdentifier::FxMemberIdentifier(FxExpression *left, FName name, const FScriptPosition &pos) + : FxIdentifier(name, pos) +{ + Object = left; + ExprType = EFX_MemberIdentifier; +} + +FxMemberIdentifier::~FxMemberIdentifier() +{ + SAFE_DELETE(Object); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) +{ + PStruct *ccls = nullptr; + CHECKRESOLVED(); + + if (Object->ExprType == EFX_Identifier) + { + // If the left side is a class name for a static member function call it needs to be resolved manually + // because the resulting value type would cause problems in nearly every other place where identifiers are being used. + ccls = FindStructType(static_cast(Object)->Identifier); + if (ccls != nullptr) static_cast(Object)->noglobal = true; + } + + SAFE_RESOLVE(Object, ctx); + + if (Identifier == FName("allmap")) + { + int a = 2; + } + + // check for class or struct constants if the left side is a type name. + if (Object->ValueType == TypeError) + { + if (ccls != nullptr) + { + if (!ccls->IsKindOf(RUNTIME_CLASS(PClass)) || static_cast(ccls)->bExported) + { + PSymbol *sym; + if ((sym = ccls->Symbols.FindSymbol(Identifier, true)) != nullptr) + { + if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) + { + ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s.%s' as constant\n", ccls->TypeName.GetChars(), Identifier.GetChars()); + delete this; + return FxConstant::MakeConstant(sym, ScriptPosition); + } + else + { + ScriptPosition.Message(MSG_ERROR, "Unable to access '%s.%s' in a static context\n", ccls->TypeName.GetChars(), Identifier.GetChars()); + delete this; + return nullptr; + } + } + } + } + } + + // allow accessing the color channels by mapping the type to a matching struct which defines them. + if (Object->ValueType == TypeColor) + { + Object->ValueType = TypeColorStruct; + } + + else if (Object->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) + { + auto ptype = static_cast(Object->ValueType)->PointedType; + if (ptype->IsKindOf(RUNTIME_CLASS(PStruct))) + { + auto ret = ResolveMember(ctx, ctx.Class, Object, static_cast(ptype)); + delete this; + return ret; + } + } + else if (Object->ValueType->IsKindOf(RUNTIME_CLASS(PStruct))) + { + auto ret = ResolveMember(ctx, ctx.Class, Object, static_cast(Object->ValueType)); + delete this; + return ret; + } + + ScriptPosition.Message(MSG_ERROR, "Left side of %s is not a struct or class", Identifier.GetChars()); + delete this; + return nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxLocalVariable::FxLocalVariable(FxLocalVariableDeclaration *var, const FScriptPosition &sc) + : FxExpression(EFX_LocalVariable, sc) +{ + Variable = var; + ValueType = var->ValueType; + AddressRequested = false; + RegOffset = 0; +} + +FxExpression *FxLocalVariable::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + return this; +} + +bool FxLocalVariable::RequestAddress(FCompileContext &ctx, bool *writable) +{ + AddressRequested = true; + if (writable != nullptr) *writable = !ctx.CheckReadOnly(Variable->VarFlags); + return true; +} + +ExpEmit FxLocalVariable::Emit(VMFunctionBuilder *build) +{ + // 'Out' variables are actually pointers but this fact must be hidden to the script. + if (Variable->VarFlags & VARF_Out) + { + if (!AddressRequested) + { + ExpEmit reg(build, ValueType->GetRegType(), ValueType->GetRegCount()); + build->Emit(ValueType->GetLoadOp(), reg.RegNum, Variable->RegNum, build->GetConstantInt(RegOffset)); + return reg; + } + else + { + if (RegOffset == 0) return ExpEmit(Variable->RegNum, REGT_POINTER, false, true); + ExpEmit reg(build, REGT_POINTER); + build->Emit(OP_ADDA_RK, reg.RegNum, Variable->RegNum, build->GetConstantInt(RegOffset)); + return reg; + } + } + else + { + ExpEmit ret(Variable->RegNum + RegOffset, Variable->ValueType->GetRegType(), false, true); + ret.RegCount = ValueType->GetRegCount(); + if (AddressRequested) ret.Target = true; + return ret; + } +} + + +//========================================================================== +// +// +// +//========================================================================== + +FxStaticArrayVariable::FxStaticArrayVariable(FxLocalVariableDeclaration *var, const FScriptPosition &sc) + : FxExpression(EFX_StaticArrayVariable, sc) +{ + Variable = static_cast(var); + ValueType = Variable->ValueType; +} + +FxExpression *FxStaticArrayVariable::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + return this; +} + +bool FxStaticArrayVariable::RequestAddress(FCompileContext &ctx, bool *writable) +{ + AddressRequested = true; + if (writable != nullptr) *writable = false; + return true; +} + +ExpEmit FxStaticArrayVariable::Emit(VMFunctionBuilder *build) +{ + // returns the first const register for this array + return ExpEmit(Variable->StackOffset, Variable->ElementType->GetRegType(), true, false); +} + + +//========================================================================== +// +// +// +//========================================================================== + +FxSelf::FxSelf(const FScriptPosition &pos, bool deccheck) +: FxExpression(EFX_Self, pos) +{ + check = deccheck; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxSelf::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + if (ctx.Function == nullptr || ctx.Function->Variants[0].SelfClass == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "self used outside of a member function"); + delete this; + return nullptr; + } + ValueType = NewPointer(ctx.Function->Variants[0].SelfClass); + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxSelf::Emit(VMFunctionBuilder *build) +{ + if (check) + { + build->Emit(OP_EQA_R, 1, 0, 1); + build->Emit(OP_JMP, 1); + build->Emit(OP_THROW, 2, X_BAD_SELF); + } + // self is always the first pointer passed to the function + return ExpEmit(0, REGT_POINTER, false, true); +} + + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxSuper::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + if (ctx.Function == nullptr || ctx.Function->Variants[0].SelfClass == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "super used outside of a member function"); + delete this; + return nullptr; + } + ValueType = TypeError; // this intentionally resolves to an invalid type so that it cannot be used outside of super calls. + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxClassDefaults::FxClassDefaults(FxExpression *X, const FScriptPosition &pos) + : FxExpression(EFX_ClassDefaults, pos) +{ + obj = X; + EmitTail = false; +} + +FxClassDefaults::~FxClassDefaults() +{ + SAFE_DELETE(obj); +} + + +//========================================================================== +// +// +// +//========================================================================== + +PPrototype *FxClassDefaults::ReturnProto() +{ + EmitTail = true; + return FxExpression::ReturnProto(); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxClassDefaults::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(obj, ctx); + assert(obj->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))); + ValueType = NewPointer(static_cast(obj->ValueType)->PointedType, true); + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build) +{ + ExpEmit ob = obj->Emit(build); + ob.Free(build); + ExpEmit meta(build, REGT_POINTER); + build->Emit(OP_META, meta.RegNum, ob.RegNum); + build->Emit(OP_LO, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); + return meta; + +} + +//========================================================================== +// +// +// +//========================================================================== + +FxGlobalVariable::FxGlobalVariable(PField* mem, const FScriptPosition &pos) + : FxExpression(EFX_GlobalVariable, pos) +{ + membervar = mem; + AddressRequested = false; + AddressWritable = true; // must be true unless classx tells us otherwise if requested. +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FxGlobalVariable::RequestAddress(FCompileContext &ctx, bool *writable) +{ + AddressRequested = true; + if (writable != nullptr) *writable = AddressWritable && !ctx.CheckReadOnly(membervar->Flags); + return true; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxGlobalVariable::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + ValueType = membervar->Type; + return this; +} + +ExpEmit FxGlobalVariable::Emit(VMFunctionBuilder *build) +{ + ExpEmit obj(build, REGT_POINTER); + + build->Emit(OP_LKP, obj.RegNum, build->GetConstantAddress((void*)(intptr_t)membervar->Offset, ATAG_GENERIC)); + if (AddressRequested) + { + return obj; + } + + ExpEmit loc(build, membervar->Type->GetRegType(), membervar->Type->GetRegCount()); + + if (membervar->BitValue == -1) + { + int offsetreg = build->GetConstantInt(0); + build->Emit(membervar->Type->GetLoadOp(), loc.RegNum, obj.RegNum, offsetreg); + } + else + { + build->Emit(OP_LBIT, loc.RegNum, obj.RegNum, 1 << membervar->BitValue); + } + obj.Free(build); + return loc; +} + + +//========================================================================== +// +// +// +//========================================================================== + +FxCVar::FxCVar(FBaseCVar *cvar, const FScriptPosition &pos) + : FxExpression(EFX_CVar, pos) +{ + CVar = cvar; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxCVar::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + switch (CVar->GetRealType()) + { + case CVAR_Bool: + case CVAR_DummyBool: + ValueType = TypeBool; + break; + + case CVAR_Int: + case CVAR_DummyInt: + ValueType = TypeSInt32; + break; + + case CVAR_Color: + ValueType = TypeColor; + break; + + case CVAR_Float: + ValueType = TypeFloat64; + break; + + case CVAR_String: + ValueType = TypeString; + break; + + default: + ScriptPosition.Message(MSG_ERROR, "Unknown CVar type for %s", CVar->GetName()); + delete this; + return nullptr; + } + return this; +} + +ExpEmit FxCVar::Emit(VMFunctionBuilder *build) +{ + ExpEmit dest(build, ValueType->GetRegType()); + ExpEmit addr(build, REGT_POINTER); + int nul = build->GetConstantInt(0); + switch (CVar->GetRealType()) + { + case CVAR_Int: + build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->Value, ATAG_GENERIC)); + build->Emit(OP_LW, dest.RegNum, addr.RegNum, nul); + break; + + case CVAR_Color: + build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->Value, ATAG_GENERIC)); + build->Emit(OP_LW, dest.RegNum, addr.RegNum, nul); + break; + + case CVAR_Float: + build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->Value, ATAG_GENERIC)); + build->Emit(OP_LSP, dest.RegNum, addr.RegNum, nul); + break; + + case CVAR_Bool: + build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->Value, ATAG_GENERIC)); + build->Emit(OP_LBU, dest.RegNum, addr.RegNum, nul); + break; + + case CVAR_String: + build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast(CVar)->Value, ATAG_GENERIC)); + build->Emit(OP_LS, dest.RegNum, addr.RegNum, nul); + break; + + case CVAR_DummyBool: + { + auto cv = static_cast(CVar); + build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&cv->ValueVar.Value, ATAG_GENERIC)); + build->Emit(OP_LW, dest.RegNum, addr.RegNum, nul); + build->Emit(OP_SRL_RI, dest.RegNum, dest.RegNum, cv->BitNum); + build->Emit(OP_AND_RK, dest.RegNum, dest.RegNum, build->GetConstantInt(1)); + break; + } + + case CVAR_DummyInt: + { + auto cv = static_cast(CVar); + build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&cv->ValueVar.Value, ATAG_GENERIC)); + build->Emit(OP_LW, dest.RegNum, addr.RegNum, nul); + build->Emit(OP_AND_RK, dest.RegNum, dest.RegNum, build->GetConstantInt(cv->BitVal)); + build->Emit(OP_SRL_RI, dest.RegNum, dest.RegNum, cv->BitNum); + break; + } + + default: + assert(false && "Unsupported CVar type"); + break; + } + addr.Free(build); + return dest; +} + + +//========================================================================== +// +// +// +//========================================================================== + +FxStackVariable::FxStackVariable(PType *type, int offset, const FScriptPosition &pos) + : FxExpression(EFX_StackVariable, pos) +{ + membervar = new PField(NAME_None, type, 0, offset); + AddressRequested = false; + AddressWritable = true; // must be true unless classx tells us otherwise if requested. +} + +//========================================================================== +// +// force delete the PField because we know we won't need it anymore +// and it won't get GC'd until the compiler finishes. +// +//========================================================================== + +FxStackVariable::~FxStackVariable() +{ + // Q: Is this good or bad? Needs testing if this is fine or better left to the GC anyway. DObject's destructor is anything but cheap. + membervar->ObjectFlags |= OF_YesReallyDelete; + delete membervar; +} + +//========================================================================== +// +// +//========================================================================== + +void FxStackVariable::ReplaceField(PField *newfield) +{ + membervar->ObjectFlags |= OF_YesReallyDelete; + delete membervar; + membervar = newfield; +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FxStackVariable::RequestAddress(FCompileContext &ctx, bool *writable) +{ + AddressRequested = true; + if (writable != nullptr) *writable = AddressWritable && !ctx.CheckReadOnly(membervar->Flags); + return true; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxStackVariable::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + ValueType = membervar->Type; + return this; +} + +ExpEmit FxStackVariable::Emit(VMFunctionBuilder *build) +{ + int offsetreg = -1; + + if (membervar->Offset != 0) offsetreg = build->GetConstantInt((int)membervar->Offset); + + if (AddressRequested) + { + if (offsetreg >= 0) + { + ExpEmit obj(build, REGT_POINTER); + build->Emit(OP_ADDA_RK, obj.RegNum, build->FramePointer.RegNum, offsetreg); + return obj; + } + else + { + return build->FramePointer; + } + } + ExpEmit loc(build, membervar->Type->GetRegType(), membervar->Type->GetRegCount()); + + if (membervar->BitValue == -1) + { + if (offsetreg == -1) offsetreg = build->GetConstantInt(0); + build->Emit(membervar->Type->GetLoadOp(), loc.RegNum, build->FramePointer.RegNum, offsetreg); + } + else + { + ExpEmit obj(build, REGT_POINTER); + if (offsetreg >= 0) build->Emit(OP_ADDA_RK, obj.RegNum, build->FramePointer.RegNum, offsetreg); + obj.Free(build); + build->Emit(OP_LBIT, loc.RegNum, obj.RegNum, 1 << membervar->BitValue); + } + return loc; +} + + +//========================================================================== +// +// +// +//========================================================================== + +FxStructMember::FxStructMember(FxExpression *x, PField* mem, const FScriptPosition &pos) + : FxExpression(EFX_StructMember, pos) +{ + classx = x; + membervar = mem; + AddressRequested = false; + AddressWritable = true; // must be true unless classx tells us otherwise if requested. +} + +//========================================================================== +// +// +// +//========================================================================== + +FxStructMember::~FxStructMember() +{ + SAFE_DELETE(classx); +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FxStructMember::RequestAddress(FCompileContext &ctx, bool *writable) +{ + // Cannot take the address of metadata variables. + if (membervar->Flags & VARF_Static) + { + return false; + } + AddressRequested = true; + if (writable != nullptr) *writable = (AddressWritable && !ctx.CheckReadOnly(membervar->Flags) && + (!classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) || !static_cast(classx->ValueType)->IsConst)); + return true; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxStructMember::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(classx, ctx); + + if (membervar->SymbolName == NAME_Default) + { + if (!classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) + || !static_cast(classx->ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(AActor))) + { + ScriptPosition.Message(MSG_ERROR, "'Default' requires an actor type."); + delete this; + return nullptr; + } + FxExpression * x = new FxClassDefaults(classx, ScriptPosition); + classx = nullptr; + delete this; + return x->Resolve(ctx); + } + + if (classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) + { + PPointer *ptrtype = dyn_cast(classx->ValueType); + if (ptrtype == nullptr || !ptrtype->PointedType->IsKindOf(RUNTIME_CLASS(PStruct))) + { + ScriptPosition.Message(MSG_ERROR, "Member variable requires a struct or class object."); + delete this; + return nullptr; + } + } + else if (classx->ValueType->IsKindOf(RUNTIME_CLASS(PStruct))) + { + // if this is a struct within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset. + if (classx->ExprType == EFX_ClassMember || classx->ExprType == EFX_StructMember) + { + auto parentfield = static_cast(classx)->membervar; + // PFields are garbage collected so this will be automatically taken care of later. + auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset); + newfield->BitValue = membervar->BitValue; + static_cast(classx)->membervar = newfield; + classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. + auto x = classx->Resolve(ctx); + classx = nullptr; + return x; + } + else if (classx->ExprType == EFX_GlobalVariable) + { + auto parentfield = static_cast(classx)->membervar; + auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset); + newfield->BitValue = membervar->BitValue; + static_cast(classx)->membervar = newfield; + classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. + auto x = classx->Resolve(ctx); + classx = nullptr; + return x; + } + else if (classx->ExprType == EFX_StackVariable) + { + auto parentfield = static_cast(classx)->membervar; + auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset); + newfield->BitValue = membervar->BitValue; + static_cast(classx)->ReplaceField(newfield); + classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. + auto x = classx->Resolve(ctx); + classx = nullptr; + return x; + } + else if (classx->ExprType == EFX_LocalVariable && classx->IsVector()) // vectors are a special case because they are held in registers + { + // since this is a vector, all potential things that may get here are single float or an xy-vector. + auto locvar = static_cast(classx); + locvar->RegOffset = int(membervar->Offset / 8); + locvar->ValueType = membervar->Type; + classx = nullptr; + delete this; + return locvar; + } + else if (classx->ExprType == EFX_LocalVariable && classx->ValueType == TypeColorStruct) + { + // This needs special treatment because it'd require accessing the register via address. + // Fortunately this is the only place where this kind of access is ever needed so an explicit handling is acceptable. + int bits; + switch (membervar->SymbolName.GetIndex()) + { + case NAME_a: bits = 24; break; + case NAME_r: bits = 16; break; + case NAME_g: bits = 8; break; + case NAME_b: default: bits = 0; break; + } + classx->ValueType = TypeColor; // need to set it back. + FxExpression *x = classx; + if (bits > 0) x = new FxShift(TK_URShift, x, new FxConstant(bits, ScriptPosition)); + x = new FxBitOp('&', x, new FxConstant(255, ScriptPosition)); + classx = nullptr; + delete this; + return x->Resolve(ctx); + } + else + { + if (!(classx->RequestAddress(ctx, &AddressWritable))) + { + ScriptPosition.Message(MSG_ERROR, "unable to dereference left side of %s", membervar->SymbolName.GetChars()); + delete this; + return nullptr; + } + } + } + ValueType = membervar->Type; + return this; +} + +ExpEmit FxStructMember::Emit(VMFunctionBuilder *build) +{ + ExpEmit obj = classx->Emit(build); + assert(obj.RegType == REGT_POINTER); + + if (obj.Konst) + { + // If the situation where we are dereferencing a constant + // pointer is common, then it would probably be worthwhile + // to add new opcodes for those. But as of right now, I + // don't expect it to be a particularly common case. + ExpEmit newobj(build, REGT_POINTER); + build->Emit(OP_LKP, newobj.RegNum, obj.RegNum); + obj = newobj; + } + + if (membervar->Flags & VARF_Static) + { + obj.Free(build); + ExpEmit meta(build, REGT_POINTER); + build->Emit(OP_META, meta.RegNum, obj.RegNum); + obj = meta; + } + + if (AddressRequested) + { + if (membervar->Offset == 0) + { + return obj; + } + obj.Free(build); + ExpEmit out(build, REGT_POINTER); + build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, build->GetConstantInt((int)membervar->Offset)); + return out; + } + + int offsetreg = build->GetConstantInt((int)membervar->Offset); + ExpEmit loc(build, membervar->Type->GetRegType(), membervar->Type->GetRegCount()); + + if (membervar->BitValue == -1) + { + build->Emit(membervar->Type->GetLoadOp(), loc.RegNum, obj.RegNum, offsetreg); + } + else + { + ExpEmit out(build, REGT_POINTER); + build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, offsetreg); + build->Emit(OP_LBIT, loc.RegNum, out.RegNum, 1 << membervar->BitValue); + out.Free(build); + } + obj.Free(build); + return loc; +} + + +//========================================================================== +// +// not really needed at the moment but may become useful with meta properties +// and some other class-specific extensions. +// +//========================================================================== + +FxClassMember::FxClassMember(FxExpression *x, PField* mem, const FScriptPosition &pos) +: FxStructMember(x, mem, pos) +{ + ExprType = EFX_ClassMember; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxArrayElement::FxArrayElement(FxExpression *base, FxExpression *_index) +:FxExpression(EFX_ArrayElement, base->ScriptPosition) +{ + Array=base; + index = _index; + AddressRequested = false; + AddressWritable = false; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxArrayElement::~FxArrayElement() +{ + SAFE_DELETE(Array); + SAFE_DELETE(index); +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FxArrayElement::RequestAddress(FCompileContext &ctx, bool *writable) +{ + AddressRequested = true; + if (writable != nullptr) *writable = AddressWritable; + return true; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Array,ctx); + SAFE_RESOLVE(index,ctx); + + if (index->ValueType->GetRegType() == REGT_FLOAT /* lax */) + { + // DECORATE allows floats here so cast them to int. + index = new FxIntCast(index, ctx.FromDecorate); + index = index->Resolve(ctx); + if (index == nullptr) + { + delete this; + return nullptr; + } + } + if (!index->IsInteger()) + { + ScriptPosition.Message(MSG_ERROR, "Array index must be integer"); + delete this; + return nullptr; + } + + PArray *arraytype = dyn_cast(Array->ValueType); + if (arraytype == nullptr) + { + // Check if we got a pointer to an array. Some native data structures (like the line list in sectors) use this. + PPointer *ptype = dyn_cast(Array->ValueType); + if (ptype == nullptr || !ptype->PointedType->IsKindOf(RUNTIME_CLASS(PArray))) + { + ScriptPosition.Message(MSG_ERROR, "'[]' can only be used with arrays."); + delete this; + return nullptr; + } + arraytype = static_cast(ptype->PointedType); + arrayispointer = true; + } + if (index->isConstant()) + { + unsigned indexval = static_cast(index)->GetValue().GetInt(); + if (indexval >= arraytype->ElementCount) + { + ScriptPosition.Message(MSG_ERROR, "Array index out of bounds"); + delete this; + return nullptr; + } + + if (!arrayispointer) + { + // if this is an array within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset. + if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember) + { + auto parentfield = static_cast(Array)->membervar; + // PFields are garbage collected so this will be automatically taken care of later. + auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); + static_cast(Array)->membervar = newfield; + Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. + auto x = Array->Resolve(ctx); + Array = nullptr; + return x; + } + else if (Array->ExprType == EFX_GlobalVariable) + { + auto parentfield = static_cast(Array)->membervar; + auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); + static_cast(Array)->membervar = newfield; + Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. + auto x = Array->Resolve(ctx); + Array = nullptr; + return x; + } + else if (Array->ExprType == EFX_StackVariable) + { + auto parentfield = static_cast(Array)->membervar; + auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset); + static_cast(Array)->ReplaceField(newfield); + Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. + auto x = Array->Resolve(ctx); + Array = nullptr; + return x; + } + } + } + + ValueType = arraytype->ElementType; + if (!Array->RequestAddress(ctx, &AddressWritable)) + { + ScriptPosition.Message(MSG_ERROR, "Unable to dereference array."); + delete this; + return nullptr; + } + return this; +} + +//========================================================================== +// +// in its current state this won't be able to do more than handle the args array. +// +//========================================================================== + +ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) +{ + PArray *arraytype; + + if (arrayispointer) + { + arraytype = static_cast(static_cast(Array->ValueType)->PointedType); + } + else + { + arraytype = static_cast(Array->ValueType); + } + ExpEmit start = Array->Emit(build); + + /* what was this for? + if (start.Konst) + { + ExpEmit tmpstart(build, REGT_POINTER); + build->Emit(OP_LKP, tmpstart.RegNum, start.RegNum); + start.Free(build); + start = tmpstart; + } + */ + if (index->isConstant()) + { + unsigned indexval = static_cast(index)->GetValue().GetInt(); + assert(indexval < arraytype->ElementCount && "Array index out of bounds"); + + if (AddressRequested) + { + if (indexval != 0) + { + indexval *= arraytype->ElementSize; + if (!start.Fixed) + { + build->Emit(OP_ADDA_RK, start.RegNum, start.RegNum, build->GetConstantInt(indexval)); + } + else + { + // do not clobber local variables. + ExpEmit temp(build, start.RegType); + build->Emit(OP_ADDA_RK, temp.RegNum, start.RegNum, build->GetConstantInt(indexval)); + start.Free(build); + start = temp; + } + } + return start; + } + else if (!start.Konst) + { + start.Free(build); + ExpEmit dest(build, ValueType->GetRegType()); + build->Emit(arraytype->ElementType->GetLoadOp(), dest.RegNum, start.RegNum, build->GetConstantInt(indexval* arraytype->ElementSize)); + return dest; + } + else + { + static int LK_Ops[] = { OP_LK, OP_LKF, OP_LKS, OP_LKP }; + assert(start.RegType == ValueType->GetRegType()); + ExpEmit dest(build, start.RegType); + build->Emit(LK_Ops[start.RegType], dest.RegNum, start.RegNum + indexval); + return dest; + } + } + else + { + ExpEmit indexv(index->Emit(build)); + // Todo: For dynamically allocated arrays (like global sector and linedef tables) we need to get the bound value in here somehow. + // Right now their bounds are not properly checked for. + if (arraytype->ElementCount > 65535) + { + build->Emit(OP_BOUND_K, indexv.RegNum, build->GetConstantInt(arraytype->ElementCount)); + } + else + { + build->Emit(OP_BOUND, indexv.RegNum, arraytype->ElementCount); + } + + if (!start.Konst) + { + int shiftbits = 0; + while (1u << shiftbits < arraytype->ElementSize) + { + shiftbits++; + } + ExpEmit indexwork = indexv.Fixed && arraytype->ElementSize > 1 ? ExpEmit(build, indexv.RegType) : indexv; + if (1u << shiftbits == arraytype->ElementSize) + { + if (shiftbits > 0) + { + build->Emit(OP_SLL_RI, indexwork.RegNum, indexv.RegNum, shiftbits); + } + } + else + { + // A shift won't do, so use a multiplication + build->Emit(OP_MUL_RK, indexwork.RegNum, indexv.RegNum, build->GetConstantInt(arraytype->ElementSize)); + } + indexwork.Free(build); + + if (AddressRequested) + { + if (!start.Fixed) + { + build->Emit(OP_ADDA_RR, start.RegNum, start.RegNum, indexwork.RegNum); + } + else + { + start.Free(build); + // do not clobber local variables. + ExpEmit temp(build, start.RegType); + build->Emit(OP_ADDA_RR, temp.RegNum, start.RegNum, indexwork.RegNum); + start = temp; + } + return start; + } + else + { + start.Free(build); + ExpEmit dest(build, ValueType->GetRegType()); + // added 1 to use the *_R version that takes the offset from a register + build->Emit(arraytype->ElementType->GetLoadOp() + 1, dest.RegNum, start.RegNum, indexwork.RegNum); + return dest; + } + } + else + { + static int LKR_Ops[] = { OP_LK_R, OP_LKF_R, OP_LKS_R, OP_LKP_R }; + assert(start.RegType == ValueType->GetRegType()); + ExpEmit dest(build, start.RegType); + if (start.RegNum <= 255) + { + // Since large constant tables are the exception, the constant component in C is an immediate value here. + build->Emit(LKR_Ops[start.RegType], dest.RegNum, indexv.RegNum, start.RegNum); + } + else + { + build->Emit(OP_ADD_RK, indexv.RegNum, indexv.RegNum, build->GetConstantInt(start.RegNum)); + build->Emit(LKR_Ops[start.RegType], dest.RegNum, indexv.RegNum, 0); + } + indexv.Free(build); + return dest; + } + } +} + +//========================================================================== +// +// Checks if a function may be called from the current context. +// +//========================================================================== + +static bool CheckFunctionCompatiblity(FScriptPosition &ScriptPosition, PFunction *caller, PFunction *callee) +{ + if (callee->Variants[0].Flags & VARF_Method) + { + // The called function must support all usage modes of the current function. It may support more, but must not support less. + if ((callee->Variants[0].UseFlags & caller->Variants[0].UseFlags) != caller->Variants[0].UseFlags) + { + ScriptPosition.Message(MSG_ERROR, "Function %s incompatible with current context\n", callee->SymbolName.GetChars()); + return false; + } + + if (!(caller->Variants[0].Flags & VARF_Method)) + { + ScriptPosition.Message(MSG_ERROR, "Call to non-static function %s from a static context", callee->SymbolName.GetChars()); + return false; + } + else + { + auto callingself = caller->Variants[0].SelfClass; + auto calledself = callee->Variants[0].SelfClass; + bool match = (callingself == calledself); + if (!match) + { + auto callingselfcls = dyn_cast(caller->Variants[0].SelfClass); + auto calledselfcls = dyn_cast(callee->Variants[0].SelfClass); + match = callingselfcls != nullptr && calledselfcls != nullptr && callingselfcls->IsDescendantOf(calledselfcls); + } + + if (!match) + { + ScriptPosition.Message(MSG_ERROR, "Call to member function %s with incompatible self pointer.", callee->SymbolName.GetChars()); + return false; + } + } + } + return true; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxFunctionCall::FxFunctionCall(FName methodname, FName rngname, FArgumentList &args, const FScriptPosition &pos) +: FxExpression(EFX_FunctionCall, pos) +{ + MethodName = methodname; + RNG = &pr_exrandom; + ArgList = std::move(args); + if (rngname != NAME_None) + { + switch (MethodName) + { + case NAME_Random: + case NAME_FRandom: + case NAME_RandomPick: + case NAME_FRandomPick: + case NAME_Random2: + RNG = FRandom::StaticFindRNG(rngname.GetChars()); + break; + + default: + pos.Message(MSG_ERROR, "Cannot use named RNGs with %s", MethodName.GetChars()); + break; + + } + } +} + +//========================================================================== +// +// +// +//========================================================================== + +FxFunctionCall::~FxFunctionCall() +{ +} + +//========================================================================== +// +// Check function that gets called +// +//========================================================================== + +static bool CheckArgSize(FName fname, FArgumentList &args, int min, int max, FScriptPosition &sc) +{ + int s = args.Size(); + if (s < min) + { + sc.Message(MSG_ERROR, "Insufficient arguments in call to %s, expected %d, got %d", fname.GetChars(), min, s); + return false; + } + else if (s > max && max >= 0) + { + sc.Message(MSG_ERROR, "Too many arguments in call to %s, expected %d, got %d", fname.GetChars(), min, s); + return false; + } + return true; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) +{ + ABORT(ctx.Class); + bool error = false; + + for (auto a : ArgList) + { + if (a == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Empty function argument."); + delete this; + return nullptr; + } + } + + PFunction *afd = FindClassMemberFunction(ctx.Class, ctx.Class, MethodName, ScriptPosition, &error); + + if (afd != nullptr) + { + if (!CheckFunctionCompatiblity(ScriptPosition, ctx.Function, afd)) + { + delete this; + return nullptr; + } + + auto self = (afd->Variants[0].Flags & VARF_Method)? new FxSelf(ScriptPosition) : nullptr; + auto x = new FxVMFunctionCall(self, afd, ArgList, ScriptPosition, false); + delete this; + return x->Resolve(ctx); + } + + for (size_t i = 0; i < countof(FxFlops); ++i) + { + if (MethodName == FxFlops[i].Name) + { + FxExpression *x = new FxFlopFunctionCall(i, ArgList, ScriptPosition); + delete this; + return x->Resolve(ctx); + } + } + + int min, max, special; + if (MethodName == NAME_ACS_NamedExecuteWithResult || MethodName == NAME_CallACS) + { + special = -ACS_ExecuteWithResult; + min = 1; + max = 5; + } + else + { + special = P_FindLineSpecial(MethodName.GetChars(), &min, &max); + } + if (special != 0 && min >= 0) + { + int paramcount = ArgList.Size(); + if (paramcount < min) + { + ScriptPosition.Message(MSG_ERROR, "Not enough parameters for '%s' (expected %d, got %d)", + MethodName.GetChars(), min, paramcount); + delete this; + return nullptr; + } + else if (paramcount > max) + { + ScriptPosition.Message(MSG_ERROR, "too many parameters for '%s' (expected %d, got %d)", + MethodName.GetChars(), max, paramcount); + delete this; + return nullptr; + } + FxExpression *self = (ctx.Function && ctx.Function->Variants[0].Flags & VARF_Method) ? new FxSelf(ScriptPosition) : nullptr; + FxExpression *x = new FxActionSpecialCall(self, special, ArgList, ScriptPosition); + delete this; + return x->Resolve(ctx); + } + + PClass *cls = PClass::FindClass(MethodName); + if (cls != nullptr && cls->bExported) + { + if (CheckArgSize(MethodName, ArgList, 1, 1, ScriptPosition)) + { + FxExpression *x = new FxDynamicCast(cls, ArgList[0]); + ArgList[0] = nullptr; + delete this; + return x->Resolve(ctx); + } + else + { + delete this; + return nullptr; + } + } + + + // Last but not least: Check builtins and type casts. The random functions can take a named RNG if specified. + // Note that for all builtins the used arguments have to be nulled in the ArgList so that they won't get deleted before they get used. + FxExpression *func = nullptr; + + switch (MethodName) + { + case NAME_Color: + if (ArgList.Size() == 3 || ArgList.Size() == 4) + { + func = new FxColorLiteral(ArgList, ScriptPosition); + break; + } + // fall through + case NAME_Bool: + case NAME_Int: + case NAME_uInt: + case NAME_Float: + case NAME_Double: + case NAME_Name: + case NAME_Sound: + case NAME_State: + case NAME_SpriteID: + case NAME_TextureID: + if (CheckArgSize(MethodName, ArgList, 1, 1, ScriptPosition)) + { + PType *type = + MethodName == NAME_Bool ? TypeBool : + MethodName == NAME_Int ? TypeSInt32 : + MethodName == NAME_uInt ? TypeUInt32 : + MethodName == NAME_Float ? TypeFloat64 : + MethodName == NAME_Double ? TypeFloat64 : + MethodName == NAME_Name ? TypeName : + MethodName == NAME_SpriteID ? TypeSpriteID : + MethodName == NAME_TextureID ? TypeTextureID : + MethodName == NAME_State ? TypeState : + MethodName == NAME_Color ? TypeColor : (PType*)TypeSound; + + func = new FxTypeCast(ArgList[0], type, true, true); + ArgList[0] = nullptr; + } + break; + + case NAME_GetClass: + if (CheckArgSize(NAME_GetClass, ArgList, 0, 0, ScriptPosition)) + { + func = new FxGetClass(new FxSelf(ScriptPosition)); + } + break; + + case NAME_GetDefaultByType: + if (CheckArgSize(NAME_GetDefaultByType, ArgList, 1, 1, ScriptPosition)) + { + func = new FxGetDefaultByType(ArgList[0]); + ArgList[0] = nullptr; + } + break; + + case NAME_Random: + // allow calling Random without arguments to default to (0, 255) + if (ArgList.Size() == 0) + { + func = new FxRandom(RNG, new FxConstant(0, ScriptPosition), new FxConstant(255, ScriptPosition), ScriptPosition, ctx.FromDecorate); + } + else if (CheckArgSize(NAME_Random, ArgList, 2, 2, ScriptPosition)) + { + func = new FxRandom(RNG, ArgList[0], ArgList[1], ScriptPosition, ctx.FromDecorate); + ArgList[0] = ArgList[1] = nullptr; + } + break; + + case NAME_FRandom: + if (CheckArgSize(NAME_FRandom, ArgList, 2, 2, ScriptPosition)) + { + func = new FxFRandom(RNG, ArgList[0], ArgList[1], ScriptPosition); + ArgList[0] = ArgList[1] = nullptr; + } + break; + + case NAME_RandomPick: + case NAME_FRandomPick: + if (CheckArgSize(MethodName, ArgList, 1, -1, ScriptPosition)) + { + func = new FxRandomPick(RNG, ArgList, MethodName == NAME_FRandomPick, ScriptPosition, ctx.FromDecorate); + } + break; + + case NAME_Random2: + if (CheckArgSize(NAME_Random2, ArgList, 0, 1, ScriptPosition)) + { + func = new FxRandom2(RNG, ArgList.Size() == 0? nullptr : ArgList[0], ScriptPosition, ctx.FromDecorate); + if (ArgList.Size() > 0) ArgList[0] = nullptr; + } + break; + + case NAME_Min: + case NAME_Max: + if (CheckArgSize(MethodName, ArgList, 2, -1, ScriptPosition)) + { + func = new FxMinMax(ArgList, MethodName, ScriptPosition); + } + break; + + case NAME_Clamp: + if (CheckArgSize(MethodName, ArgList, 3, 3, ScriptPosition)) + { + TArray pass; + pass.Resize(2); + pass[0] = ArgList[0]; + pass[1] = ArgList[1]; + pass[0] = new FxMinMax(pass, NAME_Max, ScriptPosition); + pass[1] = ArgList[2]; + func = new FxMinMax(pass, NAME_Min, ScriptPosition); + ArgList[0] = ArgList[1] = ArgList[2] = nullptr; + } + break; + + case NAME_Abs: + if (CheckArgSize(MethodName, ArgList, 1, 1, ScriptPosition)) + { + func = new FxAbs(ArgList[0]); + ArgList[0] = nullptr; + } + break; + + case NAME_ATan2: + case NAME_VectorAngle: + if (CheckArgSize(MethodName, ArgList, 2, 2, ScriptPosition)) + { + func = MethodName == NAME_ATan2 ? new FxATan2(ArgList[0], ArgList[1], ScriptPosition) : new FxATan2(ArgList[1], ArgList[0], ScriptPosition); + ArgList[0] = ArgList[1] = nullptr; + } + break; + + default: + ScriptPosition.Message(MSG_ERROR, "Call to unknown function '%s'", MethodName.GetChars()); + break; + } + if (func != nullptr) + { + delete this; + return func->Resolve(ctx); + } + delete this; + return nullptr; +} + + +//========================================================================== +// +// +// +//========================================================================== + +FxMemberFunctionCall::FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &args, const FScriptPosition &pos) + : FxExpression(EFX_MemberFunctionCall, pos) +{ + Self = self; + MethodName = methodname; + ArgList = std::move(args); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxMemberFunctionCall::~FxMemberFunctionCall() +{ + SAFE_DELETE(Self); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) +{ + ABORT(ctx.Class); + PStruct *cls; + bool staticonly = false; + bool novirtual = false; + + PStruct *ccls = nullptr; + + for (auto a : ArgList) + { + if (a == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Empty function argument."); + delete this; + return nullptr; + } + } + + if (Self->ExprType == EFX_Identifier) + { + // If the left side is a class name for a static member function call it needs to be resolved manually + // because the resulting value type would cause problems in nearly every other place where identifiers are being used. + ccls = FindStructType(static_cast(Self)->Identifier); + if (ccls != nullptr) static_cast(Self)->noglobal = true; + } + + SAFE_RESOLVE(Self, ctx); + + if (Self->ValueType == TypeError) + { + if (ccls != nullptr) + { + if (!ccls->IsKindOf(RUNTIME_CLASS(PClass)) || static_cast(ccls)->bExported) + { + cls = ccls; + staticonly = true; + goto isresolved; + } + } + } + + if (Self->ExprType == EFX_Super) + { + auto clstype = dyn_cast(ctx.Function->Variants[0].SelfClass); + if (clstype != nullptr) + { + // give the node the proper value type now that we know it's properly used. + cls = clstype->ParentClass; + Self->ValueType = NewPointer(cls); + Self->ExprType = EFX_Self; + novirtual = true; // super calls are always non-virtual + } + else + { + ScriptPosition.Message(MSG_ERROR, "Super requires a class type"); + } + } + + // Note: These builtins would better be relegated to the actual type objects, instead of polluting this file, but that's a task for later. + + // Texture builtins. + if (Self->ValueType == TypeTextureID) + { + if (MethodName == NAME_IsValid || MethodName == NAME_IsNull || MethodName == NAME_Exists || MethodName == NAME_SetInvalid || MethodName == NAME_SetNull) + { + if (ArgList.Size() > 0) + { + ScriptPosition.Message(MSG_ERROR, "too many parameters in call to %s", MethodName.GetChars()); + delete this; + return nullptr; + } + // No need to create a dedicated node here, all builtins map directly to trivial operations. + Self->ValueType = TypeSInt32; // all builtins treat the texture index as integer. + FxExpression *x; + switch (MethodName) + { + case NAME_IsValid: + x = new FxCompareRel('>', Self, new FxConstant(0, ScriptPosition)); + break; + + case NAME_IsNull: + x = new FxCompareEq(TK_Eq, Self, new FxConstant(0, ScriptPosition)); + break; + + case NAME_Exists: + x = new FxCompareRel(TK_Geq, Self, new FxConstant(0, ScriptPosition)); + break; + + case NAME_SetInvalid: + x = new FxAssign(Self, new FxConstant(-1, ScriptPosition)); + break; + + case NAME_SetNull: + x = new FxAssign(Self, new FxConstant(0, ScriptPosition)); + break; + } + Self = nullptr; + SAFE_RESOLVE(x, ctx); + if (MethodName == NAME_SetInvalid || MethodName == NAME_SetNull) x->ValueType = TypeVoid; // override the default type of the assignment operator. + delete this; + return x; + } + } + + if (Self->IsVector()) + { + // handle builtins: Vectors got 2: Length and Unit. + if (MethodName == NAME_Length || MethodName == NAME_Unit) + { + if (ArgList.Size() > 0) + { + ScriptPosition.Message(MSG_ERROR, "too many parameters in call to %s", MethodName.GetChars()); + delete this; + return nullptr; + } + auto x = new FxVectorBuiltin(Self, MethodName); + Self = nullptr; + delete this; + return x->Resolve(ctx); + } + } + + if (Self->ValueType == TypeString) + { + // same for String methods. It also uses a hidden struct type to define them. + Self->ValueType = TypeStringStruct; + } + + if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) + { + auto ptype = static_cast(Self->ValueType)->PointedType; + if (ptype->IsKindOf(RUNTIME_CLASS(PStruct))) + { + if (ptype->IsKindOf(RUNTIME_CLASS(PClass)) && MethodName == NAME_GetClass) + { + if (ArgList.Size() > 0) + { + ScriptPosition.Message(MSG_ERROR, "too many parameters in call to %s", MethodName.GetChars()); + delete this; + return nullptr; + } + auto x = new FxGetClass(Self); + return x->Resolve(ctx); + } + cls = static_cast(ptype); + } + else + { + ScriptPosition.Message(MSG_ERROR, "Left hand side of %s must point to a class object\n", MethodName.GetChars()); + delete this; + return nullptr; + } + } + else if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PStruct))) + { + bool writable; + if (Self->RequestAddress(ctx, &writable) && writable) + { + cls = static_cast(Self->ValueType); + Self->ValueType = NewPointer(Self->ValueType); + } + else + { + // Cannot be made writable so we cannot use its methods. + ScriptPosition.Message(MSG_ERROR, "Invalid expression on left hand side of %s\n", MethodName.GetChars()); + delete this; + return nullptr; + } + } + else + { + ScriptPosition.Message(MSG_ERROR, "Invalid expression on left hand side of %s\n", MethodName.GetChars()); + delete this; + return nullptr; + } + + // Todo: handle member calls from instantiated structs. + +isresolved: + bool error = false; + PFunction *afd = FindClassMemberFunction(cls, ctx.Class, MethodName, ScriptPosition, &error); + if (error) + { + delete this; + return nullptr; + } + + if (afd == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unknown function %s\n", MethodName.GetChars()); + delete this; + return nullptr; + } + + if (staticonly && (afd->Variants[0].Flags & VARF_Method)) + { + auto clstype = dyn_cast(ctx.Class); + auto ccls = dyn_cast(cls); + if (clstype == nullptr || ccls == nullptr || !clstype->IsDescendantOf(ccls)) + { + ScriptPosition.Message(MSG_ERROR, "Cannot call non-static function %s::%s from here\n", cls->TypeName.GetChars(), MethodName.GetChars()); + delete this; + return nullptr; + } + else + { + // Todo: If this is a qualified call to a parent class function, let it through (but this needs to disable virtual calls later.) + ScriptPosition.Message(MSG_ERROR, "Qualified member call to parent class not yet implemented\n", cls->TypeName.GetChars(), MethodName.GetChars()); + delete this; + return nullptr; + } + } + + if (afd->Variants[0].Flags & VARF_Method) + { + if (Self->ExprType == EFX_Self) + { + if (!CheckFunctionCompatiblity(ScriptPosition, ctx.Function, afd)) + { + delete this; + return nullptr; + } + } + else + { + // Functions with no Actor usage may not be called through a pointer because they will lose their context. + if (!(afd->Variants[0].UseFlags & SUF_ACTOR)) + { + ScriptPosition.Message(MSG_ERROR, "Function %s cannot be used with a non-self object\n", afd->SymbolName.GetChars()); + delete this; + return nullptr; + } + } + } + + // do not pass the self pointer to static functions. + auto self = (afd->Variants[0].Flags & VARF_Method) ? Self : nullptr; + auto x = new FxVMFunctionCall(self, afd, ArgList, ScriptPosition, staticonly|novirtual); + if (Self == self) Self = nullptr; + delete this; + return x->Resolve(ctx); +} + + +//========================================================================== +// +// FxActionSpecialCall +// +// If special is negative, then the first argument will be treated as a +// name for ACS_NamedExecuteWithResult. +// +//========================================================================== + +FxActionSpecialCall::FxActionSpecialCall(FxExpression *self, int special, FArgumentList &args, const FScriptPosition &pos) +: FxExpression(EFX_ActionSpecialCall, pos) +{ + Self = self; + Special = special; + ArgList = std::move(args); + EmitTail = false; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxActionSpecialCall::~FxActionSpecialCall() +{ + SAFE_DELETE(Self); +} + +//========================================================================== +// +// +// +//========================================================================== + +PPrototype *FxActionSpecialCall::ReturnProto() +{ + EmitTail = true; + return FxExpression::ReturnProto(); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + bool failed = false; + + SAFE_RESOLVE_OPT(Self, ctx); + for (unsigned i = 0; i < ArgList.Size(); i++) + { + ArgList[i] = ArgList[i]->Resolve(ctx); + if (ArgList[i] == nullptr) + { + failed = true; + } + else if (Special < 0 && i == 0) + { + if (ArgList[i]->ValueType == TypeString) + { + ArgList[i] = new FxNameCast(ArgList[i]); + ArgList[i] = ArgList[i]->Resolve(ctx); + if (ArgList[i] == nullptr) + { + failed = true; + } + } + else if (ArgList[i]->ValueType != TypeName) + { + ScriptPosition.Message(MSG_ERROR, "Name expected for parameter %d", i); + failed = true; + } + } + else if (!ArgList[i]->IsInteger()) + { + if (ArgList[i]->ValueType->GetRegType() == REGT_FLOAT /* lax */) + { + ArgList[i] = new FxIntCast(ArgList[i], ctx.FromDecorate); + } + else + { + ScriptPosition.Message(MSG_ERROR, "Integer expected for parameter %d", i); + failed = true; + } + } + } + if (failed) + { + delete this; + return nullptr; + } + ValueType = TypeSInt32; + return this; +} + + +//========================================================================== +// +// +// +//========================================================================== + +int BuiltinCallLineSpecial(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) +{ + assert(numparam > 2 && numparam < 8); + assert(param[0].Type == REGT_INT); + assert(param[1].Type == REGT_POINTER); + int v[5] = { 0 }; + + for (int i = 2; i < numparam; ++i) + { + v[i - 2] = param[i].i; + } + ACTION_RETURN_INT(P_ExecuteSpecial(param[0].i, nullptr, reinterpret_cast(param[1].a), false, v[0], v[1], v[2], v[3], v[4])); +} + +ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) +{ + unsigned i = 0; + + build->Emit(OP_PARAMI, abs(Special)); // pass special number + // fixme: This really should use the Self pointer that got passed to this class instead of just using the first argument from the function. + // Once static functions are possible, or specials can be called through a member access operator this won't work anymore. + build->Emit(OP_PARAM, 0, REGT_POINTER, 0); // pass self + for (; i < ArgList.Size(); ++i) + { + FxExpression *argex = ArgList[i]; + if (Special < 0 && i == 0) + { + assert(argex->ValueType == TypeName); + assert(argex->isConstant()); + build->EmitParamInt(-static_cast(argex)->GetValue().GetName()); + } + else + { + assert(argex->ValueType->GetRegType() == REGT_INT); + if (argex->isConstant()) + { + build->EmitParamInt(static_cast(argex)->GetValue().GetInt()); + } + else + { + ExpEmit arg(argex->Emit(build)); + build->Emit(OP_PARAM, 0, arg.RegType, arg.RegNum); + arg.Free(build); + } + } + } + // Call the BuiltinCallLineSpecial function to perform the desired special. + VMFunction *callfunc; + PSymbol *sym = FindBuiltinFunction(NAME_BuiltinCallLineSpecial, BuiltinCallLineSpecial); + + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); + assert(((PSymbolVMFunction *)sym)->Function != nullptr); + callfunc = ((PSymbolVMFunction *)sym)->Function; + ArgList.DeleteAndClear(); + ArgList.ShrinkToFit(); + + if (EmitTail) + { + build->Emit(OP_TAIL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2 + i, 0); + ExpEmit call; + call.Final = true; + return call; + } + + ExpEmit dest(build, REGT_INT); + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2 + i, 1); + build->Emit(OP_RESULT, 0, REGT_INT, dest.RegNum); + return dest; +} + +//========================================================================== +// +// FxVMFunctionCall +// +//========================================================================== + +FxVMFunctionCall::FxVMFunctionCall(FxExpression *self, PFunction *func, FArgumentList &args, const FScriptPosition &pos, bool novirtual) +: FxExpression(EFX_VMFunctionCall, pos) +{ + Self = self; + Function = func; + ArgList = std::move(args); + EmitTail = false; + NoVirtual = novirtual; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxVMFunctionCall::~FxVMFunctionCall() +{ +} + +//========================================================================== +// +// +// +//========================================================================== + +PPrototype *FxVMFunctionCall::ReturnProto() +{ + EmitTail = true; + return Function->Variants[0].Proto; +} + +//========================================================================== +// +// +// +//========================================================================== + +VMFunction *FxVMFunctionCall::GetDirectFunction() +{ + // If this return statement calls a non-virtual function with no arguments, + // then it can be a "direct" function. That is, the DECORATE + // definition can call that function directly without wrapping + // it inside VM code. + if (ArgList.Size() == 0 && !(Function->Variants[0].Flags & VARF_Virtual)) + { + unsigned imp = Function->GetImplicitArgs(); + if (Function->Variants[0].ArgFlags.Size() > imp && !(Function->Variants[0].ArgFlags[imp] & VARF_Optional)) return nullptr; + return Function->Variants[0].Implementation; + } + + return nullptr; +} + +//========================================================================== +// +// FxVMFunctionCall :: Resolve +// +//========================================================================== + +FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE_OPT(Self, ctx); + bool failed = false; + auto proto = Function->Variants[0].Proto; + auto &argtypes = proto->ArgumentTypes; + auto &argnames = Function->Variants[0].ArgNames; + auto &argflags = Function->Variants[0].ArgFlags; + auto &defaults = Function->Variants[0].Implementation->DefaultArgs; + + int implicit = Function->GetImplicitArgs(); + + // This should never happen. + if (Self == nullptr && (Function->Variants[0].Flags & VARF_Method)) + { + ScriptPosition.Message(MSG_ERROR, "Call to non-static function without a self pointer"); + delete this; + return nullptr; + } + + if (ArgList.Size() > 0) + { + bool foundvarargs = false; + PType * type = nullptr; + int flag = 0; + if (argtypes.Last() != nullptr && ArgList.Size() + implicit > argtypes.Size()) + { + ScriptPosition.Message(MSG_ERROR, "Too many arguments in call to %s", Function->SymbolName.GetChars()); + delete this; + return nullptr; + } + + for (unsigned i = 0; i < ArgList.Size(); i++) + { + // Varargs must all have the same type as the last typed argument. A_Jump is the only function using it. + if (!foundvarargs) + { + if (argtypes[i + implicit] == nullptr) foundvarargs = true; + else + { + type = argtypes[i + implicit]; + flag = argflags[i + implicit]; + } + } + assert(type != nullptr); + + if (ArgList[i]->ExprType == EFX_NamedNode) + { + if (!(flag & VARF_Optional)) + { + ScriptPosition.Message(MSG_ERROR, "Cannot use a named argument here - not all required arguments have been passed."); + delete this; + return nullptr; + } + if (foundvarargs) + { + ScriptPosition.Message(MSG_ERROR, "Cannot use a named argument in the varargs part of the parameter list."); + delete this; + return nullptr; + } + unsigned j; + bool done = false; + FName name = static_cast(ArgList[i])->name; + for (j = 0; j < argnames.Size() - implicit; j++) + { + if (argnames[j + implicit] == name) + { + if (j < i) + { + ScriptPosition.Message(MSG_ERROR, "Named argument %s comes before current position in argument list.", name.GetChars()); + delete this; + return nullptr; + } + // copy the original argument into the list + auto old = static_cast(ArgList[i]); + ArgList[i] = old->value; + old->value = nullptr; + delete old; + // now fill the gap with constants created from the default list so that we got a full list of arguments. + int insert = j - i; + for (int k = 0; k < insert; k++) + { + auto ntype = argtypes[i + k + implicit]; + // If this is a reference argument, the pointer type must be undone because the code below expects the pointed type as value type. + if (argflags[i + k + implicit] & VARF_Ref) + { + assert(ntype->IsKindOf(RUNTIME_CLASS(PPointer))); + ntype = TypeNullPtr; // the default of a reference type can only be a null pointer + } + auto x = new FxConstant(ntype, defaults[i + k + implicit], ScriptPosition); + ArgList.Insert(i + k, x); + } + done = true; + break; + } + } + if (!done) + { + ScriptPosition.Message(MSG_ERROR, "Named argument %s not found.", name.GetChars()); + delete this; + return nullptr; + } + // re-get the proper info for the inserted node. + type = argtypes[i + implicit]; + flag = argflags[i + implicit]; + } + + FxExpression *x; + if (!(flag & (VARF_Ref|VARF_Out))) + { + x = new FxTypeCast(ArgList[i], type, false); + x = x->Resolve(ctx); + } + else + { + bool writable; + ArgList[i] = ArgList[i]->Resolve(ctx); // nust be resolved before the address is requested. + if (ArgList[i] != nullptr && ArgList[i]->ValueType != TypeNullPtr) + { + ArgList[i]->RequestAddress(ctx, &writable); + if (flag & VARF_Ref) ArgList[i]->ValueType = NewPointer(ArgList[i]->ValueType); + // For a reference argument the types must match 100%. + if (type != ArgList[i]->ValueType) + { + ScriptPosition.Message(MSG_ERROR, "Type mismatch in reference argument", Function->SymbolName.GetChars()); + x = nullptr; + } + else + { + x = ArgList[i]; + } + } + else x = ArgList[i]; + } + failed |= (x == nullptr); + ArgList[i] = x; + } + int numargs = ArgList.Size() + implicit; + if ((unsigned)numargs < argtypes.Size() && argtypes[numargs] != nullptr) + { + auto flags = Function->Variants[0].ArgFlags[numargs]; + if (!(flags & VARF_Optional)) + { + ScriptPosition.Message(MSG_ERROR, "Insufficient arguments in call to %s", Function->SymbolName.GetChars()); + delete this; + return nullptr; + } + } + } + else + { + if ((unsigned)implicit < argtypes.Size() && argtypes[implicit] != nullptr) + { + auto flags = Function->Variants[0].ArgFlags[implicit]; + if (!(flags & VARF_Optional)) + { + ScriptPosition.Message(MSG_ERROR, "Insufficient arguments in call to %s", Function->SymbolName.GetChars()); + delete this; + return nullptr; + } + } + } + if (failed) + { + delete this; + return nullptr; + } + TArray &rets = proto->ReturnTypes; + if (rets.Size() > 0) + { + ValueType = rets[0]; + } + else + { + ValueType = TypeVoid; + } + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) +{ + assert(build->Registers[REGT_POINTER].GetMostUsed() >= build->NumImplicits); + int count = 0; + + if (count == 1) + { + ExpEmit reg; + if (CheckEmitCast(build, EmitTail, reg)) + { + ArgList.DeleteAndClear(); + ArgList.ShrinkToFit(); + return reg; + } + } + + VMFunction *vmfunc = Function->Variants[0].Implementation; + bool staticcall = (vmfunc->Final || vmfunc->VirtualIndex == ~0u || NoVirtual); + + count = 0; + // Emit code to pass implied parameters + ExpEmit selfemit; + if (Function->Variants[0].Flags & VARF_Method) + { + assert(Self != nullptr); + selfemit = Self->Emit(build); + assert((selfemit.RegType == REGT_POINTER) || (selfemit.Fixed && selfemit.Target)); + if (selfemit.Fixed && selfemit.Target) + { + // Address of a local variable. + build->Emit(OP_PARAM, 0, selfemit.RegType | REGT_ADDROF, selfemit.RegNum); + } + else + { + build->Emit(OP_PARAM, 0, selfemit.RegType, selfemit.RegNum); + } + count += 1; + if (Function->Variants[0].Flags & VARF_Action) + { + static_assert(NAP == 3, "This code needs to be updated if NAP changes"); + if (build->NumImplicits == NAP && selfemit.RegNum == 0) // only pass this function's stateowner and stateinfo if the subfunction is run in self's context. + { + build->Emit(OP_PARAM, 0, REGT_POINTER, 1); + build->Emit(OP_PARAM, 0, REGT_POINTER, 2); + } + else + { + // pass self as stateowner, otherwise all attempts of the subfunction to retrieve a state from a name would fail. + build->Emit(OP_PARAM, 0, selfemit.RegType, selfemit.RegNum); + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(nullptr, ATAG_GENERIC)); + } + count += 2; + } + if (staticcall) selfemit.Free(build); + } + else staticcall = true; + // Emit code to pass explicit parameters + for (unsigned i = 0; i < ArgList.Size(); ++i) + { + count += EmitParameter(build, ArgList[i], ScriptPosition); + } + ArgList.DeleteAndClear(); + ArgList.ShrinkToFit(); + + // Get a constant register for this function + if (staticcall) + { + int funcaddr = build->GetConstantAddress(vmfunc, ATAG_OBJECT); + // Emit the call + if (EmitTail) + { // Tail call + build->Emit(OP_TAIL_K, funcaddr, count, 0); + ExpEmit call; + call.Final = true; + return call; + } + else if (vmfunc->Proto->ReturnTypes.Size() > 0) + { // Call, expecting one result + build->Emit(OP_CALL_K, funcaddr, count, MAX(1, AssignCount)); + goto handlereturns; + } + else + { // Call, expecting no results + build->Emit(OP_CALL_K, funcaddr, count, 0); + return ExpEmit(); + } + } + else + { + selfemit.Free(build); + ExpEmit funcreg(build, REGT_POINTER); + build->Emit(OP_VTBL, funcreg.RegNum, selfemit.RegNum, vmfunc->VirtualIndex); + if (EmitTail) + { // Tail call + build->Emit(OP_TAIL, funcreg.RegNum, count, 0); + ExpEmit call; + call.Final = true; + return call; + } + else if (vmfunc->Proto->ReturnTypes.Size() > 0) + { // Call, expecting one result + build->Emit(OP_CALL, funcreg.RegNum, count, MAX(1, AssignCount)); + goto handlereturns; + } + else + { // Call, expecting no results + build->Emit(OP_CALL, funcreg.RegNum, count, 0); + return ExpEmit(); + } + } +handlereturns: + if (AssignCount == 0) + { + // Regular call, will not write to ReturnRegs + ExpEmit reg(build, vmfunc->Proto->ReturnTypes[0]->GetRegType(), vmfunc->Proto->ReturnTypes[0]->GetRegCount()); + build->Emit(OP_RESULT, 0, EncodeRegType(reg), reg.RegNum); + return reg; + } + else + { + // Multi-Assignment call, this must fill in the ReturnRegs array so that the multi-assignment operator can dispatch the return values. + assert((unsigned)AssignCount <= vmfunc->Proto->ReturnTypes.Size()); + for (int i = 0; i < AssignCount; i++) + { + ExpEmit reg(build, vmfunc->Proto->ReturnTypes[i]->GetRegType(), vmfunc->Proto->ReturnTypes[i]->GetRegCount()); + build->Emit(OP_RESULT, 0, EncodeRegType(reg), reg.RegNum); + ReturnRegs.Push(reg); + } + return ExpEmit(); + } +} + +//========================================================================== +// +// If calling one of the casting kludge functions, don't bother calling the +// function; just use the parameter directly. Returns true if this was a +// kludge function, false otherwise. +// +//========================================================================== + +bool FxVMFunctionCall::CheckEmitCast(VMFunctionBuilder *build, bool returnit, ExpEmit ®) +{ + FName funcname = Function->SymbolName; + if (funcname == NAME___decorate_internal_int__ || + funcname == NAME___decorate_internal_bool__ || + funcname == NAME___decorate_internal_float__) + { + FxExpression *arg = ArgList[0]; + if (returnit) + { + if (arg->isConstant() && + (funcname == NAME___decorate_internal_int__ || + funcname == NAME___decorate_internal_bool__)) + { // Use immediate version for integers in range + build->EmitRetInt(0, true, static_cast(arg)->GetValue().Int); + } + else + { + ExpEmit where = arg->Emit(build); + build->Emit(OP_RET, RET_FINAL, EncodeRegType(where), where.RegNum); + where.Free(build); + } + reg = ExpEmit(); + reg.Final = true; + } + else + { + reg = arg->Emit(build); + } + return true; + } + return false; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxFlopFunctionCall::FxFlopFunctionCall(size_t index, FArgumentList &args, const FScriptPosition &pos) +: FxExpression(EFX_FlopFunctionCall, pos) +{ + assert(index < countof(FxFlops) && "FLOP index out of range"); + Index = (int)index; + ArgList = std::move(args); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxFlopFunctionCall::~FxFlopFunctionCall() +{ +} + +FxExpression *FxFlopFunctionCall::Resolve(FCompileContext& ctx) +{ + CHECKRESOLVED(); + + if (ArgList.Size() != 1) + { + ScriptPosition.Message(MSG_ERROR, "%s only has one parameter", FName(FxFlops[Index].Name).GetChars()); + delete this; + return nullptr; + } + + ArgList[0] = ArgList[0]->Resolve(ctx); + if (ArgList[0] == nullptr) + { + delete this; + return nullptr; + } + + if (!ArgList[0]->IsNumeric()) + { + ScriptPosition.Message(MSG_ERROR, "numeric value expected for parameter"); + delete this; + return nullptr; + } + if (ArgList[0]->isConstant()) + { + double v = static_cast(ArgList[0])->GetValue().GetFloat(); + v = FxFlops[Index].Evaluate(v); + FxExpression *x = new FxConstant(v, ScriptPosition); + delete this; + return x; + } + if (ArgList[0]->ValueType->GetRegType() == REGT_INT) + { + ArgList[0] = new FxFloatCast(ArgList[0]); + } + ValueType = TypeFloat64; + return this; +} + +//========================================================================== +// +// +//========================================================================== + +ExpEmit FxFlopFunctionCall::Emit(VMFunctionBuilder *build) +{ + assert(ValueType == ArgList[0]->ValueType); + ExpEmit from = ArgList[0]->Emit(build); + ExpEmit to; + assert(from.Konst == 0); + assert(ValueType->GetRegCount() == 1); + // Do it in-place, unless a local variable + if (from.Fixed) + { + to = ExpEmit(build, from.RegType); + from.Free(build); + } + else + { + to = from; + } + + build->Emit(OP_FLOP, to.RegNum, from.RegNum, FxFlops[Index].Flop); + ArgList.DeleteAndClear(); + ArgList.ShrinkToFit(); + return to; +} + + +//========================================================================== +// +// +//========================================================================== + +FxVectorBuiltin::FxVectorBuiltin(FxExpression *self, FName name) + :FxExpression(EFX_VectorBuiltin, self->ScriptPosition) +{ + Self = self; + Function = name; +} + +FxVectorBuiltin::~FxVectorBuiltin() +{ + SAFE_DELETE(Self); +} + +FxExpression *FxVectorBuiltin::Resolve(FCompileContext &ctx) +{ + SAFE_RESOLVE(Self, ctx); + assert(Self->IsVector()); // should never be created for anything else. + ValueType = Function == NAME_Length ? TypeFloat64 : Self->ValueType; + return this; +} + +ExpEmit FxVectorBuiltin::Emit(VMFunctionBuilder *build) +{ + ExpEmit to(build, ValueType->GetRegType(), ValueType->GetRegCount()); + ExpEmit op = Self->Emit(build); + if (Function == NAME_Length) + { + build->Emit(Self->ValueType == TypeVector2 ? OP_LENV2 : OP_LENV3, to.RegNum, op.RegNum); + } + else + { + ExpEmit len(build, REGT_FLOAT); + build->Emit(Self->ValueType == TypeVector2 ? OP_LENV2 : OP_LENV3, len.RegNum, op.RegNum); + build->Emit(Self->ValueType == TypeVector2 ? OP_DIVVF2_RR : OP_DIVVF3_RR, to.RegNum, op.RegNum, len.RegNum); + len.Free(build); + } + op.Free(build); + return to; +} + +//========================================================================== +// +// +//========================================================================== + +FxGetClass::FxGetClass(FxExpression *self) + :FxExpression(EFX_GetClass, self->ScriptPosition) +{ + Self = self; +} + +FxGetClass::~FxGetClass() +{ + SAFE_DELETE(Self); +} + +FxExpression *FxGetClass::Resolve(FCompileContext &ctx) +{ + SAFE_RESOLVE(Self, ctx); + if (!Self->IsObject()) + { + ScriptPosition.Message(MSG_ERROR, "GetClass() requires an object"); + delete this; + return nullptr; + } + ValueType = NewClassPointer(static_cast(static_cast(Self->ValueType)->PointedType)); + return this; +} + +ExpEmit FxGetClass::Emit(VMFunctionBuilder *build) +{ + ExpEmit op = Self->Emit(build); + op.Free(build); + ExpEmit to(build, REGT_POINTER); + build->Emit(OP_META, to.RegNum, op.RegNum); + return to; +} + +//========================================================================== +// +// +//========================================================================== + +FxGetDefaultByType::FxGetDefaultByType(FxExpression *self) + :FxExpression(EFX_GetDefaultByType, self->ScriptPosition) +{ + Self = self; +} + +FxGetDefaultByType::~FxGetDefaultByType() +{ + SAFE_DELETE(Self); +} + +FxExpression *FxGetDefaultByType::Resolve(FCompileContext &ctx) +{ + SAFE_RESOLVE(Self, ctx); + PClass *cls = nullptr; + + if (Self->ValueType == TypeString || Self->ValueType == TypeName) + { + if (Self->isConstant()) + { + cls = PClass::FindActor(static_cast(Self)->GetValue().GetName()); + if (cls == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "GetDefaultByType() requires an actor class type, but got %s", static_cast(Self)->GetValue().GetString().GetChars()); + delete this; + return nullptr; + } + Self = new FxConstant(cls, NewClassPointer(cls), ScriptPosition); + } + else + { + // this is the ugly case. We do not know what we have and cannot do proper type casting. + // For now error out and let this case require explicit handling on the user side. + ScriptPosition.Message(MSG_ERROR, "GetDefaultByType() requires an actor class type", static_cast(Self)->GetValue().GetString().GetChars()); + delete this; + return nullptr; + } + } + else + { + auto cp = dyn_cast(Self->ValueType); + if (cp == nullptr || !cp->ClassRestriction->IsDescendantOf(RUNTIME_CLASS(AActor))) + { + ScriptPosition.Message(MSG_ERROR, "GetDefaultByType() requires an actor class type"); + delete this; + return nullptr; + } + cls = cp->ClassRestriction; + } + ValueType = NewPointer(cls, true); + return this; +} + +ExpEmit FxGetDefaultByType::Emit(VMFunctionBuilder *build) +{ + ExpEmit op = Self->Emit(build); + op.Free(build); + ExpEmit to(build, REGT_POINTER); + if (op.Konst) + { + build->Emit(OP_LKP, to.RegNum, op.RegNum); + op = to; + } + build->Emit(OP_LO, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults))); + return to; +} + +//========================================================================== +// +// +//========================================================================== + +FxColorLiteral::FxColorLiteral(FArgumentList &args, FScriptPosition &sc) + :FxExpression(EFX_ColorLiteral, sc) +{ + ArgList = std::move(args); +} + +FxExpression *FxColorLiteral::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + unsigned constelements = 0; + assert(ArgList.Size() == 3 || ArgList.Size() == 4); + if (ArgList.Size() == 3) ArgList.Insert(0, nullptr); + for (int i = 0; i < 4; i++) + { + if (ArgList[i] != nullptr) + { + SAFE_RESOLVE(ArgList[i], ctx); + if (!ArgList[i]->IsInteger()) + { + ScriptPosition.Message(MSG_ERROR, "Integer expected for color component"); + delete this; + return nullptr; + } + if (ArgList[i]->isConstant()) + { + constval += clamp(static_cast(ArgList[i])->GetValue().GetInt(), 0, 255) << (24 - i * 8); + delete ArgList[i]; + ArgList[i] = nullptr; + constelements++; + } + } + else constelements++; + } + if (constelements == 4) + { + auto x = new FxConstant(constval, ScriptPosition); + x->ValueType = TypeColor; + delete this; + return x; + } + ValueType = TypeColor; + return this; +} + +ExpEmit FxColorLiteral::Emit(VMFunctionBuilder *build) +{ + ExpEmit out(build, REGT_INT); + build->Emit(OP_LK, out.RegNum, build->GetConstantInt(constval)); + for (int i = 0; i < 4; i++) + { + if (ArgList[i] != nullptr) + { + assert(!ArgList[i]->isConstant()); + ExpEmit in = ArgList[i]->Emit(build); + in.Free(build); + ExpEmit work(build, REGT_INT); + build->Emit(OP_MAX_RK, work.RegNum, in.RegNum, build->GetConstantInt(0)); + build->Emit(OP_MIN_RK, work.RegNum, work.RegNum, build->GetConstantInt(255)); + if (i != 3) build->Emit(OP_SLL_RI, work.RegNum, work.RegNum, 24 - (i * 8)); + build->Emit(OP_OR_RR, out.RegNum, out.RegNum, work.RegNum); + } + } + return out; +} + +//========================================================================== +// +// FxSequence :: Resolve +// +//========================================================================== + +FxExpression *FxSequence::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + bool fail = false; + for (unsigned i = 0; i < Expressions.Size(); ++i) + { + if (nullptr == (Expressions[i] = Expressions[i]->Resolve(ctx))) + { + fail = true; + } + else if (Expressions[i]->ValueType == TypeError) + { + ScriptPosition.Message(MSG_ERROR, "Invalid statement"); + fail = true; + } + } + if (fail) + { + delete this; + return nullptr; + } + return this; +} + +//========================================================================== +// +// FxSequence :: CheckReturn +// +//========================================================================== + +bool FxSequence::CheckReturn() +{ + // a sequence always returns when its last element returns. + return Expressions.Size() > 0 && Expressions.Last()->CheckReturn(); +} + +//========================================================================== +// +// FxSequence :: Emit +// +//========================================================================== + +ExpEmit FxSequence::Emit(VMFunctionBuilder *build) +{ + for (unsigned i = 0; i < Expressions.Size(); ++i) + { + Expressions[i]->EmitStatement(build); + } + return ExpEmit(); +} + +//========================================================================== +// +// FxSequence :: GetDirectFunction +// +//========================================================================== + +VMFunction *FxSequence::GetDirectFunction() +{ + if (Expressions.Size() == 1) + { + return Expressions[0]->GetDirectFunction(); + } + return nullptr; +} + +//========================================================================== +// +// FxCompoundStatement :: Resolve +// +//========================================================================== + +FxExpression *FxCompoundStatement::Resolve(FCompileContext &ctx) +{ + auto outer = ctx.Block; + Outer = ctx.Block; + ctx.Block = this; + auto x = FxSequence::Resolve(ctx); + ctx.Block = outer; + return x; +} + +//========================================================================== +// +// FxCompoundStatement :: Emit +// +//========================================================================== + +ExpEmit FxCompoundStatement::Emit(VMFunctionBuilder *build) +{ + auto e = FxSequence::Emit(build); + // Release all local variables in this block. + for (auto l : LocalVars) + { + l->Release(build); + } + return e; +} + +//========================================================================== +// +// FxCompoundStatement :: FindLocalVariable +// +// Looks for a variable name in any of the containing compound statements +// This does a simple linear search on each block's variables. +// The lists here normally don't get large enough to justify something more complex. +// +//========================================================================== + +FxLocalVariableDeclaration *FxCompoundStatement::FindLocalVariable(FName name, FCompileContext &ctx) +{ + auto block = this; + while (block != nullptr) + { + for (auto l : block->LocalVars) + { + if (l->Name == name) + { + return l; + } + } + block = block->Outer; + } + // finally check the context for function arguments + for (auto arg : ctx.FunctionArgs) + { + if (arg->Name == name) + { + return arg; + } + } + return nullptr; +} + +//========================================================================== +// +// FxCompoundStatement :: CheckLocalVariable +// +// Checks if the current block already contains a local variable +// of the given name. +// +//========================================================================== + +bool FxCompoundStatement::CheckLocalVariable(FName name) +{ + for (auto l : LocalVars) + { + if (l->Name == name) + { + return true; + } + } + return false; +} + +//========================================================================== +// +// FxSwitchStatement +// +//========================================================================== + +FxSwitchStatement::FxSwitchStatement(FxExpression *cond, FArgumentList &content, const FScriptPosition &pos) + : FxExpression(EFX_SwitchStatement, pos) +{ + Condition = cond; + Content = std::move(content); +} + +FxSwitchStatement::~FxSwitchStatement() +{ + SAFE_DELETE(Condition); +} + +FxExpression *FxSwitchStatement::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Condition, ctx); + + if (Condition->ValueType != TypeName) + { + Condition = new FxIntCast(Condition, false); + SAFE_RESOLVE(Condition, ctx); + } + + if (Content.Size() == 0) + { + ScriptPosition.Message(MSG_WARNING, "Empty switch statement"); + if (Condition->isConstant()) + { + return new FxNop(ScriptPosition); + } + else + { + // The condition may have a side effect so it should be processed (possible to-do: Analyze all nodes in there and delete if not.) + auto x = Condition; + Condition = nullptr; + delete this; + x->NeedResult = false; + return x; + } + } + + auto outerctrl = ctx.ControlStmt; + ctx.ControlStmt = this; + + for (auto &line : Content) + { + SAFE_RESOLVE(line, ctx); + line->NeedResult = false; + } + ctx.ControlStmt = outerctrl; + + if (Condition->isConstant()) + { + ScriptPosition.Message(MSG_WARNING, "Case expression is constant"); + auto &content = Content; + int defaultindex = -1; + int defaultbreak = -1; + int caseindex = -1; + int casebreak = -1; + // look for a case label with a matching value + for (unsigned i = 0; i < content.Size(); i++) + { + if (content[i] != nullptr) + { + if (content[i]->ExprType == EFX_CaseStatement) + { + auto casestmt = static_cast(content[i]); + if (casestmt->Condition == nullptr) defaultindex = i; + else if (casestmt->CaseValue == static_cast(Condition)->GetValue().GetInt()) caseindex = i; + if (casestmt->Condition && casestmt->Condition->ValueType != Condition->ValueType) + { + casestmt->Condition->ScriptPosition.Message(MSG_ERROR, "Type mismatch in case statement"); + delete this; + return nullptr; + } + } + if (content[i]->ExprType == EFX_JumpStatement && static_cast(content[i])->Token == TK_Break) + { + if (defaultindex >= 0 && defaultbreak < 0) defaultbreak = i; + if (caseindex >= 0 && casebreak < 0) + { + casebreak = i; + break; // when we find this we do not need to look any further. + } + } + } + } + if (caseindex < 0) + { + caseindex = defaultindex; + casebreak = defaultbreak; + } + if (caseindex > 0 && casebreak - caseindex > 1) + { + auto seq = new FxSequence(ScriptPosition); + for (int i = caseindex + 1; i < casebreak; i++) + { + if (content[i] != nullptr && content[i]->ExprType != EFX_CaseStatement) + { + seq->Add(content[i]); + content[i] = nullptr; + } + } + delete this; + return seq->Resolve(ctx); + } + delete this; + return new FxNop(ScriptPosition); + } + + int mincase = INT_MAX; + int maxcase = INT_MIN; + for (auto line : Content) + { + if (line->ExprType == EFX_CaseStatement) + { + auto casestmt = static_cast(line); + if (casestmt->Condition != nullptr) + { + CaseAddr ca = { casestmt->CaseValue, 0 }; + CaseAddresses.Push(ca); + if (ca.casevalue < mincase) mincase = ca.casevalue; + if (ca.casevalue > maxcase) maxcase = ca.casevalue; + } + } + } + return this; +} + +ExpEmit FxSwitchStatement::Emit(VMFunctionBuilder *build) +{ + assert(Condition != nullptr); + ExpEmit emit = Condition->Emit(build); + assert(emit.RegType == REGT_INT); + // todo: + // - sort jump table by value. + // - optimize the switch dispatcher to run in native code instead of executing each single branch instruction on its own. + // e.g.: build->Emit(OP_SWITCH, emit.RegNum, build->GetConstantInt(CaseAddresses.Size()); + for (auto &ca : CaseAddresses) + { + if (ca.casevalue >= 0 && ca.casevalue <= 0xffff) + { + build->Emit(OP_TEST, emit.RegNum, (VM_SHALF)ca.casevalue); + } + else if (ca.casevalue < 0 && ca.casevalue >= -0xffff) + { + build->Emit(OP_TESTN, emit.RegNum, (VM_SHALF)-ca.casevalue); + } + else + { + build->Emit(OP_EQ_K, 1, emit.RegNum, build->GetConstantInt(ca.casevalue)); + } + ca.jumpaddress = build->Emit(OP_JMP, 0); + } + size_t DefaultAddress = build->Emit(OP_JMP, 0); + bool defaultset = false; + + for (auto line : Content) + { + switch (line->ExprType) + { + case EFX_CaseStatement: + if (static_cast(line)->Condition != nullptr) + { + for (auto &ca : CaseAddresses) + { + if (ca.casevalue == static_cast(line)->CaseValue) + { + build->BackpatchToHere(ca.jumpaddress); + break; + } + } + } + else + { + build->BackpatchToHere(DefaultAddress); + defaultset = true; + } + break; + + default: + line->EmitStatement(build); + break; + } + } + for (auto addr : Breaks) + { + build->BackpatchToHere(addr->Address); + } + if (!defaultset) build->BackpatchToHere(DefaultAddress); + Content.DeleteAndClear(); + Content.ShrinkToFit(); + return ExpEmit(); +} + +//========================================================================== +// +// FxSequence :: CheckReturn +// +//========================================================================== + +bool FxSwitchStatement::CheckReturn() +{ + //A switch statement returns when it contains no breaks and ends with a return + for (auto line : Content) + { + if (line->ExprType == EFX_JumpStatement) + { + return false; // Break means that the end of the statement will be reached, Continue cannot happen in the last statement of the last block. + } + } + return Content.Size() > 0 && Content.Last()->CheckReturn(); +} + +//========================================================================== +// +// FxCaseStatement +// +//========================================================================== + +FxCaseStatement::FxCaseStatement(FxExpression *cond, const FScriptPosition &pos) + : FxExpression(EFX_CaseStatement, pos) +{ + Condition = cond; +} + +FxCaseStatement::~FxCaseStatement() +{ + SAFE_DELETE(Condition); +} + +FxExpression *FxCaseStatement::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE_OPT(Condition, ctx); + + if (Condition != nullptr) + { + if (!Condition->isConstant()) + { + ScriptPosition.Message(MSG_ERROR, "Case label must be a constant value"); + delete this; + return nullptr; + } + // Case labels can be ints or names. + if (Condition->ValueType != TypeName) + { + Condition = new FxIntCast(Condition, false); + SAFE_RESOLVE(Condition, ctx); + CaseValue = static_cast(Condition)->GetValue().GetInt(); + } + else + { + CaseValue = static_cast(Condition)->GetValue().GetName(); + } + } + return this; +} + +//========================================================================== +// +// FxIfStatement +// +//========================================================================== + +FxIfStatement::FxIfStatement(FxExpression *cond, FxExpression *true_part, + FxExpression *false_part, const FScriptPosition &pos) +: FxExpression(EFX_IfStatement, pos) +{ + Condition = cond; + WhenTrue = true_part; + WhenFalse = false_part; + if (WhenTrue != nullptr) WhenTrue->NeedResult = false; + if (WhenFalse != nullptr) WhenFalse->NeedResult = false; + assert(cond != nullptr); +} + +FxIfStatement::~FxIfStatement() +{ + SAFE_DELETE(Condition); + SAFE_DELETE(WhenTrue); + SAFE_DELETE(WhenFalse); +} + +FxExpression *FxIfStatement::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + + if (WhenTrue == nullptr && WhenFalse == nullptr) + { // We don't do anything either way, so disappear + delete this; + ScriptPosition.Message(MSG_WARNING, "empty if statement"); + return new FxNop(ScriptPosition); + } + + SAFE_RESOLVE(Condition, ctx); + + if (Condition->ValueType != TypeBool) + { + Condition = new FxBoolCast(Condition, false); + SAFE_RESOLVE(Condition, ctx); + } + + if (WhenTrue != nullptr) + { + WhenTrue = WhenTrue->Resolve(ctx); + ABORT(WhenTrue); + } + if (WhenFalse != nullptr) + { + WhenFalse = WhenFalse->Resolve(ctx); + ABORT(WhenFalse); + } + + ValueType = TypeVoid; + + if (Condition->isConstant()) + { + ExpVal condval = static_cast(Condition)->GetValue(); + bool result = condval.GetBool(); + + FxExpression *e = result ? WhenTrue : WhenFalse; + delete (result ? WhenFalse : WhenTrue); + WhenTrue = WhenFalse = nullptr; + if (e == nullptr) e = new FxNop(ScriptPosition); // create a dummy if this statement gets completely removed by optimizing out the constant parts. + delete this; + return e; + } + + return this; +} + +ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build) +{ + ExpEmit v; + size_t jumpspot = ~0u; + + TArray yes, no; + Condition->EmitCompare(build, false, yes, no); + + if (WhenTrue != nullptr) + { + build->BackpatchListToHere(yes); + WhenTrue->EmitStatement(build); + } + if (WhenFalse != nullptr) + { + if (!WhenTrue->CheckReturn()) jumpspot = build->Emit(OP_JMP, 0); // no need to emit a jump if the block returns. + build->BackpatchListToHere(no); + WhenFalse->EmitStatement(build); + if (jumpspot != ~0u) build->BackpatchToHere(jumpspot); + if (WhenTrue == nullptr) build->BackpatchListToHere(yes); + } + else + { + build->BackpatchListToHere(no); + } + return ExpEmit(); +} + + +//========================================================================== +// +// FxIfStatement :: CheckReturn +// +//========================================================================== + +bool FxIfStatement::CheckReturn() +{ + //An if statement returns if both branches return. Both branches must be present. + return WhenTrue != nullptr && WhenTrue->CheckReturn() && + WhenFalse != nullptr && WhenFalse->CheckReturn(); +} + +//========================================================================== +// +// FxLoopStatement :: Resolve +// +// saves the loop pointer in the context and sets this object as the current loop +// so that continues and breaks always resolve to the innermost loop. +// +//========================================================================== + +FxExpression *FxLoopStatement::Resolve(FCompileContext &ctx) +{ + auto outerctrl = ctx.ControlStmt; + auto outer = ctx.Loop; + ctx.ControlStmt = this; + ctx.Loop = this; + auto x = DoResolve(ctx); + ctx.Loop = outer; + ctx.ControlStmt = outerctrl; + return x; +} + +void FxLoopStatement::Backpatch(VMFunctionBuilder *build, size_t loopstart, size_t loopend) +{ + // Give a proper address to any break/continue statement within this loop. + for (unsigned int i = 0; i < Jumps.Size(); i++) + { + if (Jumps[i]->Token == TK_Break) + { + build->Backpatch(Jumps[i]->Address, loopend); + } + else + { // Continue statement. + build->Backpatch(Jumps[i]->Address, loopstart); + } + } +} + +//========================================================================== +// +// FxWhileLoop +// +//========================================================================== + +FxWhileLoop::FxWhileLoop(FxExpression *condition, FxExpression *code, const FScriptPosition &pos) +: FxLoopStatement(EFX_WhileLoop, pos), Condition(condition), Code(code) +{ + ValueType = TypeVoid; +} + +FxWhileLoop::~FxWhileLoop() +{ + SAFE_DELETE(Condition); + SAFE_DELETE(Code); +} + +FxExpression *FxWhileLoop::DoResolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Condition, ctx); + SAFE_RESOLVE_OPT(Code, ctx); + + if (Condition->ValueType != TypeBool) + { + Condition = new FxBoolCast(Condition); + SAFE_RESOLVE(Condition, ctx); + } + + if (Condition->isConstant()) + { + if (static_cast(Condition)->GetValue().GetBool() == false) + { // Nothing happens + FxExpression *nop = new FxNop(ScriptPosition); + delete this; + return nop; + } + else if (Code == nullptr) + { // "while (true) { }" + // Someone could be using this for testing. + ScriptPosition.Message(MSG_WARNING, "Infinite empty loop"); + } + } + + return this; +} + +ExpEmit FxWhileLoop::Emit(VMFunctionBuilder *build) +{ + assert(Condition->ValueType == TypeBool); + + size_t loopstart, loopend; + TArray yes, no; + + // Evaluate the condition and execute/break out of the loop. + loopstart = build->GetAddress(); + if (!Condition->isConstant()) + { + Condition->EmitCompare(build, false, yes, no); + } + else assert(static_cast(Condition)->GetValue().GetBool() == true); + + build->BackpatchListToHere(yes); + // Execute the loop's content. + if (Code != nullptr) + { + Code->EmitStatement(build); + } + + // Loop back. + build->Backpatch(build->Emit(OP_JMP, 0), loopstart); + build->BackpatchListToHere(no); + loopend = build->GetAddress(); + Backpatch(build, loopstart, loopend); + return ExpEmit(); +} + +//========================================================================== +// +// FxDoWhileLoop +// +//========================================================================== + +FxDoWhileLoop::FxDoWhileLoop(FxExpression *condition, FxExpression *code, const FScriptPosition &pos) +: FxLoopStatement(EFX_DoWhileLoop, pos), Condition(condition), Code(code) +{ + ValueType = TypeVoid; +} + +FxDoWhileLoop::~FxDoWhileLoop() +{ + SAFE_DELETE(Condition); + SAFE_DELETE(Code); +} + +FxExpression *FxDoWhileLoop::DoResolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Condition, ctx); + SAFE_RESOLVE_OPT(Code, ctx); + + if (Condition->ValueType != TypeBool) + { + Condition = new FxBoolCast(Condition); + SAFE_RESOLVE(Condition, ctx); + } + + if (Condition->isConstant()) + { + if (static_cast(Condition)->GetValue().GetBool() == false) + { // The code executes once, if any. + if (Jumps.Size() == 0) + { // We would still have to handle the jumps however. + FxExpression *e = Code; + if (e == nullptr) e = new FxNop(ScriptPosition); + Code = nullptr; + delete this; + return e; + } + } + else if (Code == nullptr) + { // "do { } while (true);" + // Someone could be using this for testing. + ScriptPosition.Message(MSG_WARNING, "Infinite empty loop"); + } + } + + return this; +} + +ExpEmit FxDoWhileLoop::Emit(VMFunctionBuilder *build) +{ + assert(Condition->ValueType == TypeBool); + + size_t loopstart, loopend; + size_t codestart; + + // Execute the loop's content. + codestart = build->GetAddress(); + if (Code != nullptr) + { + Code->EmitStatement(build); + } + + // Evaluate the condition and execute/break out of the loop. + loopstart = build->GetAddress(); + if (!Condition->isConstant()) + { + TArray yes, no; + Condition->EmitCompare(build, true, yes, no); + build->BackpatchList(no, codestart); + build->BackpatchListToHere(yes); + } + else if (static_cast(Condition)->GetValue().GetBool() == true) + { // Always looping + build->Backpatch(build->Emit(OP_JMP, 0), codestart); + } + loopend = build->GetAddress(); + Backpatch(build, loopstart, loopend); + + return ExpEmit(); +} + +//========================================================================== +// +// FxForLoop +// +//========================================================================== + +FxForLoop::FxForLoop(FxExpression *init, FxExpression *condition, FxExpression *iteration, FxExpression *code, const FScriptPosition &pos) +: FxLoopStatement(EFX_ForLoop, pos), Init(init), Condition(condition), Iteration(iteration), Code(code) +{ + ValueType = TypeVoid; + if (Iteration != nullptr) Iteration->NeedResult = false; + if (Code != nullptr) Code->NeedResult = false; +} + +FxForLoop::~FxForLoop() +{ + SAFE_DELETE(Init); + SAFE_DELETE(Condition); + SAFE_DELETE(Iteration); + SAFE_DELETE(Code); +} + +FxExpression *FxForLoop::DoResolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE_OPT(Init, ctx); + SAFE_RESOLVE_OPT(Condition, ctx); + SAFE_RESOLVE_OPT(Iteration, ctx); + SAFE_RESOLVE_OPT(Code, ctx); + + if (Condition != nullptr) + { + if (Condition->ValueType != TypeBool) + { + Condition = new FxBoolCast(Condition); + SAFE_RESOLVE(Condition, ctx); + } + + if (Condition->isConstant()) + { + if (static_cast(Condition)->GetValue().GetBool() == false) + { // Nothing happens + FxExpression *nop = new FxNop(ScriptPosition); + delete this; + return nop; + } + else + { // "for (..; true; ..)" + delete Condition; + Condition = nullptr; + } + } + } + if (Condition == nullptr && Code == nullptr) + { // "for (..; ; ..) { }" + // Someone could be using this for testing. + ScriptPosition.Message(MSG_WARNING, "Infinite empty loop"); + } + + return this; +} + +ExpEmit FxForLoop::Emit(VMFunctionBuilder *build) +{ + assert((Condition && Condition->ValueType == TypeBool && !Condition->isConstant()) || Condition == nullptr); + + size_t loopstart, loopend; + size_t codestart; + TArray yes, no; + + // Init statement (only used by DECORATE. ZScript is pulling it before the loop statement and enclosing the entire loop in a compound statement so that Init can have local variables.) + if (Init != nullptr) + { + ExpEmit init = Init->Emit(build); + init.Free(build); + } + + // Evaluate the condition and execute/break out of the loop. + codestart = build->GetAddress(); + if (Condition != nullptr) + { + Condition->EmitCompare(build, false, yes, no); + } + + build->BackpatchListToHere(yes); + // Execute the loop's content. + if (Code != nullptr) + { + Code->EmitStatement(build); + } + + // Iteration statement. + loopstart = build->GetAddress(); + if (Iteration != nullptr) + { + ExpEmit iter = Iteration->Emit(build); + iter.Free(build); + } + build->Backpatch(build->Emit(OP_JMP, 0), codestart); + + // End of loop. + loopend = build->GetAddress(); + build->BackpatchListToHere(no); + + Backpatch(build, loopstart, loopend); + return ExpEmit(); +} + +//========================================================================== +// +// FxJumpStatement +// +//========================================================================== + +FxJumpStatement::FxJumpStatement(int token, const FScriptPosition &pos) +: FxExpression(EFX_JumpStatement, pos), Token(token) +{ + ValueType = TypeVoid; +} + +FxExpression *FxJumpStatement::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + + if (ctx.ControlStmt != nullptr) + { + if (ctx.ControlStmt == ctx.Loop || Token == TK_Continue) + { + ctx.Loop->Jumps.Push(this); + } + else + { + // break in switch. + static_cast(ctx.ControlStmt)->Breaks.Push(this); + } + return this; + } + else + { + ScriptPosition.Message(MSG_ERROR, "'%s' outside of a loop", Token == TK_Break ? "break" : "continue"); + delete this; + return nullptr; + } +} + +ExpEmit FxJumpStatement::Emit(VMFunctionBuilder *build) +{ + Address = build->Emit(OP_JMP, 0); + + return ExpEmit(); +} + +//========================================================================== +// +//========================================================================== + +FxReturnStatement::FxReturnStatement(FxExpression *value, const FScriptPosition &pos) +: FxExpression(EFX_ReturnStatement, pos), Value(value) +{ + ValueType = TypeVoid; +} + +FxReturnStatement::~FxReturnStatement() +{ + SAFE_DELETE(Value); +} + +FxExpression *FxReturnStatement::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE_OPT(Value, ctx); + + PPrototype *retproto; + if (Value == nullptr) + { + TArray none(0); + retproto = NewPrototype(none, none); + } + else + { + // If we already know the real return type we need at least try to cast the value to its proper type (unless in an anonymous function.) + if (ctx.ReturnProto != nullptr && ctx.ReturnProto->ReturnTypes.Size() > 0 && ctx.Function->SymbolName != NAME_None) + { + Value = new FxTypeCast(Value, ctx.ReturnProto->ReturnTypes[0], false, false); + Value = Value->Resolve(ctx); + ABORT(Value); + } + retproto = Value->ReturnProto(); + } + + ctx.CheckReturn(retproto, ScriptPosition); + + return this; +} + +ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build) +{ + ExpEmit out(0, REGT_NIL); + + // If we return nothing, use a regular RET opcode. + // Otherwise just return the value we're given. + if (Value == nullptr) + { + build->Emit(OP_RET, RET_FINAL, REGT_NIL, 0); + } + else + { + out = Value->Emit(build); + + // Check if it is a function call that simplified itself + // into a tail call in which case we don't emit anything. + if (!out.Final) + { + if (Value->ValueType == TypeVoid) + { // Nothing is returned. + build->Emit(OP_RET, RET_FINAL, REGT_NIL, 0); + } + else + { + build->Emit(OP_RET, RET_FINAL, EncodeRegType(out), out.RegNum); + } + } + } + + out.Final = true; + return out; +} + +VMFunction *FxReturnStatement::GetDirectFunction() +{ + if (Value != nullptr) + { + return Value->GetDirectFunction(); + } + return nullptr; +} + +//========================================================================== +// +//========================================================================== + +FxClassTypeCast::FxClassTypeCast(PClassPointer *dtype, FxExpression *x) +: FxExpression(EFX_ClassTypeCast, x->ScriptPosition) +{ + ValueType = dtype; + desttype = dtype->ClassRestriction; + basex=x; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxClassTypeCast::~FxClassTypeCast() +{ + SAFE_DELETE(basex); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(basex, ctx); + + if (basex->ValueType == TypeNullPtr) + { + basex->ValueType = ValueType; + auto x = basex; + basex = nullptr; + delete this; + return x; + } + auto to = static_cast(ValueType); + if (basex->ValueType->GetClass() == RUNTIME_CLASS(PClassPointer)) + { + auto from = static_cast(basex->ValueType); + if (from->ClassRestriction->IsDescendantOf(to->ClassRestriction)) + { + basex->ValueType = to; + auto x = basex; + basex = nullptr; + delete this; + return x; + } + ScriptPosition.Message(MSG_ERROR, "Cannot convert from %s to %s: Incompatible class types", from->ClassRestriction->TypeName.GetChars(), to->ClassRestriction->TypeName.GetChars()); + delete this; + return nullptr; + } + + if (basex->ValueType != TypeName && basex->ValueType != TypeString) + { + ScriptPosition.Message(MSG_ERROR, "Cannot convert %s to class type", basex->ValueType->DescriptiveName()); + delete this; + return nullptr; + } + + if (basex->isConstant()) + { + FName clsname = static_cast(basex)->GetValue().GetName(); + PClass *cls = nullptr; + + if (clsname != NAME_None) + { + cls = PClass::FindClass(clsname); + if (cls == nullptr) + { + /* lax */ + // Since this happens in released WADs it must pass without a terminal error... :( + ScriptPosition.Message(MSG_OPTERROR, + "Unknown class name '%s'", + clsname.GetChars(), desttype->TypeName.GetChars()); + } + else + { + if (!cls->IsDescendantOf(desttype)) + { + ScriptPosition.Message(MSG_OPTERROR, "class '%s' is not compatible with '%s'", clsname.GetChars(), desttype->TypeName.GetChars()); + cls = nullptr; + } + else ScriptPosition.Message(MSG_DEBUGLOG, "resolving '%s' as class name", clsname.GetChars()); + } + } + FxExpression *x = new FxConstant(cls, to, ScriptPosition); + delete this; + return x; + } + if (basex->ValueType == TypeString) + { + basex = new FxNameCast(basex); + } + return this; +} + +//========================================================================== +// +// +// +//========================================================================== + +int BuiltinNameToClass(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) +{ + assert(numparam == 2); + assert(numret == 1); + assert(param[0].Type == REGT_INT); + assert(param[1].Type == REGT_POINTER); + assert(ret->RegType == REGT_POINTER); + + FName clsname = ENamedName(param[0].i); + if (clsname != NAME_None) + { + const PClass *cls = PClass::FindClass(clsname); + const PClass *desttype = reinterpret_cast(param[1].a); + + if (!cls->IsDescendantOf(desttype)) + { + // Let the caller check this. Making this an error with a message is only taking away options from the user. + cls = nullptr; + } + ret->SetPointer(const_cast(cls), ATAG_OBJECT); + } + else ret->SetPointer(nullptr, ATAG_OBJECT); + return 1; +} + +ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build) +{ + if (basex->ValueType != TypeName) + { + return ExpEmit(build->GetConstantAddress(nullptr, ATAG_OBJECT), REGT_POINTER, true); + } + ExpEmit clsname = basex->Emit(build); + assert(!clsname.Konst); + ExpEmit dest(build, REGT_POINTER); + build->Emit(OP_PARAM, 0, clsname.RegType, clsname.RegNum); + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(const_cast(desttype), ATAG_OBJECT)); + + // Call the BuiltinNameToClass function to convert from 'name' to class. + VMFunction *callfunc; + PSymbol *sym = FindBuiltinFunction(NAME_BuiltinNameToClass, BuiltinNameToClass); + + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); + assert(((PSymbolVMFunction *)sym)->Function != nullptr); + callfunc = ((PSymbolVMFunction *)sym)->Function; + + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1); + build->Emit(OP_RESULT, 0, REGT_POINTER, dest.RegNum); + clsname.Free(build); + return dest; +} + +//========================================================================== +// +//========================================================================== + +FxClassPtrCast::FxClassPtrCast(PClass *dtype, FxExpression *x) + : FxExpression(EFX_ClassPtrCast, x->ScriptPosition) +{ + ValueType = NewClassPointer(dtype); + desttype = dtype; + basex = x; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxClassPtrCast::~FxClassPtrCast() +{ + SAFE_DELETE(basex); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxClassPtrCast::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(basex, ctx); + + if (basex->ValueType == TypeNullPtr) + { + basex->ValueType = ValueType; + auto x = basex; + basex = nullptr; + delete this; + return x; + } + auto to = static_cast(ValueType); + if (basex->ValueType->GetClass() == RUNTIME_CLASS(PClassPointer)) + { + auto from = static_cast(basex->ValueType); + // Downcast is always ok. + if (from->ClassRestriction->IsDescendantOf(to->ClassRestriction)) + { + basex->ValueType = to; + auto x = basex; + basex = nullptr; + delete this; + return x; + } + // Upcast needs a runtime check. + else if (to->ClassRestriction->IsDescendantOf(from->ClassRestriction)) + { + return this; + } + } + else if (basex->ValueType == TypeString || basex->ValueType == TypeName) + { + FxExpression *x = new FxClassTypeCast(to, basex); + basex = nullptr; + delete this; + return x->Resolve(ctx); + } + // Everything else is an error. + ScriptPosition.Message(MSG_ERROR, "Cannot cast %s to %s. The types are incompatible.", basex->ValueType->DescriptiveName(), to->DescriptiveName()); + delete this; + return nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +int BuiltinClassCast(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) +{ + PARAM_PROLOGUE; + PARAM_CLASS(from, DObject); + PARAM_CLASS(to, DObject); + ACTION_RETURN_OBJECT(from && to && from->IsDescendantOf(to) ? from : nullptr); +} + +ExpEmit FxClassPtrCast::Emit(VMFunctionBuilder *build) +{ + ExpEmit clsname = basex->Emit(build); + + build->Emit(OP_PARAM, 0, clsname.RegType, clsname.RegNum); + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(desttype, ATAG_OBJECT)); + + VMFunction *callfunc; + PSymbol *sym = FindBuiltinFunction(NAME_BuiltinClassCast, BuiltinClassCast); + + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); + assert(((PSymbolVMFunction *)sym)->Function != nullptr); + callfunc = ((PSymbolVMFunction *)sym)->Function; + clsname.Free(build); + ExpEmit dest(build, REGT_POINTER); + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1); + build->Emit(OP_RESULT, 0, REGT_POINTER, dest.RegNum); + return dest; +} + +//========================================================================== +// +// Symbolic state labels. +// Conversion will not happen inside the compiler anymore because it causes +// just too many problems. +// +//========================================================================== + +FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + ABORT(ctx.Class); + auto aclass = dyn_cast(ctx.Class); + + // This expression type can only be used from actors, for everything else it has already produced a compile error. + assert(aclass != nullptr && aclass->NumOwnedStates > 0); + + if (aclass->NumOwnedStates <= index) + { + ScriptPosition.Message(MSG_ERROR, "%s: Attempt to jump to non existing state index %d", + ctx.Class->TypeName.GetChars(), index); + delete this; + return nullptr; + } + int symlabel = StateLabels.AddPointer(aclass->OwnedStates + index); + FxExpression *x = new FxConstant(symlabel, ScriptPosition); + x->ValueType = TypeStateLabel; + delete this; + return x; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxRuntimeStateIndex::FxRuntimeStateIndex(FxExpression *index) +: FxExpression(EFX_RuntimeStateIndex, index->ScriptPosition), Index(index) +{ + ValueType = TypeStateLabel; +} + +FxRuntimeStateIndex::~FxRuntimeStateIndex() +{ + SAFE_DELETE(Index); +} + +FxExpression *FxRuntimeStateIndex::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Index, ctx); + + if (!Index->IsNumeric()) + { + ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return nullptr; + } + else if (Index->isConstant()) + { + int index = static_cast(Index)->GetValue().GetInt(); + if (index < 0 || (index == 0 && !ctx.FromDecorate)) + { + ScriptPosition.Message(MSG_ERROR, "State index must be positive"); + delete this; + return nullptr; + } + else if (index == 0) + { + int symlabel = StateLabels.AddPointer(nullptr); + auto x = new FxConstant(symlabel, ScriptPosition); + delete this; + x->ValueType = TypeStateLabel; + return x; + } + else + { + auto x = new FxStateByIndex(ctx.StateIndex + index, ScriptPosition); + delete this; + return x->Resolve(ctx); + } + } + else if (Index->ValueType->GetRegType() != REGT_INT) + { // Float. + Index = new FxIntCast(Index, ctx.FromDecorate); + SAFE_RESOLVE(Index, ctx); + } + auto aclass = dyn_cast(ctx.Class); + assert(aclass != nullptr && aclass->NumOwnedStates > 0); + symlabel = StateLabels.AddPointer(aclass->OwnedStates + ctx.StateIndex); + ValueType = TypeStateLabel; + return this; +} + +ExpEmit FxRuntimeStateIndex::Emit(VMFunctionBuilder *build) +{ + ExpEmit out = Index->Emit(build); + // out = (clamp(Index, 0, 32767) << 16) | symlabel | 0x80000000; 0x80000000 is here to make it negative. + build->Emit(OP_MAX_RK, out.RegNum, out.RegNum, build->GetConstantInt(0)); + build->Emit(OP_MIN_RK, out.RegNum, out.RegNum, build->GetConstantInt(32767)); + build->Emit(OP_SLL_RI, out.RegNum, out.RegNum, 16); + build->Emit(OP_OR_RK, out.RegNum, out.RegNum, build->GetConstantInt(symlabel|0x80000000)); + return out; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxMultiNameState::FxMultiNameState(const char *_statestring, const FScriptPosition &pos) + :FxExpression(EFX_MultiNameState, pos) +{ + FName scopename; + FString statestring = _statestring; + int scopeindex = statestring.IndexOf("::"); + + if (scopeindex >= 0) + { + scopename = FName(statestring, scopeindex, false); + statestring = statestring.Right(statestring.Len() - scopeindex - 2); + } + else + { + scopename = NAME_None; + } + names = MakeStateNameList(statestring); + names.Insert(0, scopename); + scope = nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + ABORT(ctx.Class); + int symlabel; + auto clstype = dyn_cast(ctx.Class); + + if (names[0] == NAME_None) + { + scope = nullptr; + } + else if (clstype == nullptr) + { + // not in an actor, so any further checks are pointless. + ScriptPosition.Message(MSG_ERROR, "'%s' is not an ancestor of '%s'", names[0].GetChars(), ctx.Class->TypeName.GetChars()); + delete this; + return nullptr; + } + else if (names[0] == NAME_Super) + { + scope = dyn_cast(clstype->ParentClass); + } + else + { + scope = PClass::FindActor(names[0]); + if (scope == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Unknown class '%s' in state label", names[0].GetChars()); + delete this; + return nullptr; + } + else if (!scope->IsAncestorOf(clstype)) + { + ScriptPosition.Message(MSG_ERROR, "'%s' is not an ancestor of '%s'", names[0].GetChars(), ctx.Class->TypeName.GetChars()); + delete this; + return nullptr; + } + } + if (scope != nullptr) + { + FState *destination = nullptr; + // If the label is class specific we can resolve it right here + if (names[1] != NAME_None) + { + destination = scope->FindState(names.Size()-1, &names[1], false); + if (destination == nullptr) + { + ScriptPosition.Message(MSG_OPTERROR, "Unknown state jump destination"); + /* lax */ + return this; + } + } + symlabel = StateLabels.AddPointer(destination); + } + else + { + names.Delete(0); + symlabel = StateLabels.AddNames(names); + } + FxExpression *x = new FxConstant(symlabel, ScriptPosition); + x->ValueType = TypeStateLabel; + delete this; + return x; +} + +//========================================================================== +// +// declares a single local variable (no arrays) +// +//========================================================================== + +FxLocalVariableDeclaration::FxLocalVariableDeclaration(PType *type, FName name, FxExpression *initval, int varflags, const FScriptPosition &p) + :FxExpression(EFX_LocalVariableDeclaration, p) +{ + ValueType = type; + VarFlags = varflags; + Name = name; + RegCount = type == TypeVector2 ? 2 : type == TypeVector3 ? 3 : 1; + Init = initval; +} + +FxLocalVariableDeclaration::~FxLocalVariableDeclaration() +{ + SAFE_DELETE(Init); +} + +FxExpression *FxLocalVariableDeclaration::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + if (ctx.Block == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Variable declaration outside compound statement"); + delete this; + return nullptr; + } + if (ValueType->RegType == REGT_NIL && ValueType != TypeAuto) + { + auto sfunc = static_cast(ctx.Function->Variants[0].Implementation); + StackOffset = sfunc->AllocExtraStack(ValueType); + // Todo: Process the compound initializer once implemented. + if (Init != nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Cannot initialize non-scalar variable %s here", Name.GetChars()); + delete this; + return nullptr; + } + } + else if (ValueType !=TypeAuto) + { + if (Init) Init = new FxTypeCast(Init, ValueType, false); + SAFE_RESOLVE_OPT(Init, ctx); + } + else + { + if (Init == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Automatic type deduction requires an initializer for variable %s", Name.GetChars()); + delete this; + return nullptr; + } + SAFE_RESOLVE_OPT(Init, ctx); + if (Init->ValueType->RegType == REGT_NIL) + { + ScriptPosition.Message(MSG_ERROR, "Cannot initialize non-scalar variable %s here", Name.GetChars()); + delete this; + return nullptr; + } + ValueType = Init->ValueType; + // check for undersized ints and floats. These are not allowed as local variables. + if (IsInteger() && ValueType->Align < sizeof(int)) ValueType = TypeSInt32; + else if (IsFloat() && ValueType->Align < sizeof(double)) ValueType = TypeFloat64; + } + if (Name != NAME_None) + { + for (auto l : ctx.Block->LocalVars) + { + if (l->Name == Name) + { + ScriptPosition.Message(MSG_ERROR, "Local variable %s already defined", Name.GetChars()); + l->ScriptPosition.Message(MSG_ERROR, "Original definition is here "); + delete this; + return nullptr; + } + } + } + ctx.Block->LocalVars.Push(this); + return this; +} + +void FxLocalVariableDeclaration::SetReg(ExpEmit emit) +{ + assert(ValueType->GetRegType() == emit.RegType && ValueType->GetRegCount() == emit.RegCount); + RegNum = emit.RegNum; +} + +ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build) +{ + if (ValueType->RegType != REGT_NIL) + { + if (Init == nullptr) + { + if (RegNum == -1) + { + if (!(VarFlags & VARF_Out)) RegNum = build->Registers[ValueType->GetRegType()].Get(RegCount); + else RegNum = build->Registers[REGT_POINTER].Get(1); + } + } + else + { + assert(!(VarFlags & VARF_Out)); // 'out' variables should never be initialized, they can only exist as function parameters. + ExpEmit emitval = Init->Emit(build); + + int regtype = emitval.RegType; + if (regtype < REGT_INT || regtype > REGT_TYPE) + { + ScriptPosition.Message(MSG_ERROR, "Attempted to assign a non-value"); + return ExpEmit(); + } + if (emitval.Konst) + { + auto constval = static_cast(Init); + RegNum = build->Registers[regtype].Get(1); + switch (regtype) + { + default: + case REGT_INT: + build->Emit(OP_LK, RegNum, build->GetConstantInt(constval->GetValue().GetInt())); + break; + + case REGT_FLOAT: + build->Emit(OP_LKF, RegNum, build->GetConstantFloat(constval->GetValue().GetFloat())); + break; + + case REGT_POINTER: + { + bool isobject = ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) || (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass))); + build->Emit(OP_LKP, RegNum, build->GetConstantAddress(constval->GetValue().GetPointer(), isobject ? ATAG_OBJECT : ATAG_GENERIC)); + break; + } + case REGT_STRING: + build->Emit(OP_LKS, RegNum, build->GetConstantString(constval->GetValue().GetString())); + } + emitval.Free(build); + } + else if (Init->ExprType != EFX_LocalVariable) + { + // take over the register that got allocated while emitting the Init expression. + RegNum = emitval.RegNum; + } + else + { + ExpEmit out(build, emitval.RegType, emitval.RegCount); + build->Emit(ValueType->GetMoveOp(), out.RegNum, emitval.RegNum); + RegNum = out.RegNum; + } + } + } + else + { + // Init arrays and structs. + } + return ExpEmit(); +} + +void FxLocalVariableDeclaration::Release(VMFunctionBuilder *build) +{ + // Release the register after the containing block gets closed + if(RegNum != -1) + { + build->Registers[ValueType->GetRegType()].Return(RegNum, RegCount); + } + // Stack space will not be released because that would make controlled destruction impossible. + // For that all local stack variables need to live for the entire execution of a function. +} + + +FxStaticArray::FxStaticArray(PType *type, FName name, FArgumentList &args, const FScriptPosition &pos) + : FxLocalVariableDeclaration(NewArray(type, args.Size()), name, nullptr, VARF_Static|VARF_ReadOnly, pos) +{ + ElementType = type; + ExprType = EFX_StaticArray; + values = std::move(args); +} + +FxExpression *FxStaticArray::Resolve(FCompileContext &ctx) +{ + bool fail = false; + for (unsigned i = 0; i < values.Size(); i++) + { + values[i] = new FxTypeCast(values[i], ElementType, false); + values[i] = values[i]->Resolve(ctx); + if (values[i] == nullptr) fail = true; + else if (!values[i]->isConstant()) + { + ScriptPosition.Message(MSG_ERROR, "Initializer must be constant"); + fail = true; + } + } + if (fail) + { + delete this; + return nullptr; + } + if (ElementType->GetRegType() == REGT_NIL) + { + ScriptPosition.Message(MSG_ERROR, "Invalid type for constant array"); + delete this; + return nullptr; + } + + ctx.Block->LocalVars.Push(this); + return this; +} + +ExpEmit FxStaticArray::Emit(VMFunctionBuilder *build) +{ + switch (ElementType->GetRegType()) + { + default: + assert(false && "Invalid register type"); + break; + + case REGT_INT: + { + TArray cvalues; + for (auto v : values) cvalues.Push(static_cast(v)->GetValue().GetInt()); + StackOffset = build->AllocConstantsInt(cvalues.Size(), &cvalues[0]); + break; + } + case REGT_FLOAT: + { + TArray cvalues; + for (auto v : values) cvalues.Push(static_cast(v)->GetValue().GetFloat()); + StackOffset = build->AllocConstantsFloat(cvalues.Size(), &cvalues[0]); + break; + } + case REGT_STRING: + { + TArray cvalues; + for (auto v : values) cvalues.Push(static_cast(v)->GetValue().GetString()); + StackOffset = build->AllocConstantsString(cvalues.Size(), &cvalues[0]); + break; + } + case REGT_POINTER: + { + TArray cvalues; + for (auto v : values) cvalues.Push(static_cast(v)->GetValue().GetPointer()); + StackOffset = build->AllocConstantsAddress(cvalues.Size(), &cvalues[0], ElementType->GetLoadOp() == OP_LO ? ATAG_OBJECT : ATAG_GENERIC); + break; + } + } + return ExpEmit(); +} diff --git a/src/thingdef/thingdef_exp.h b/src/scripting/codegeneration/codegen.h similarity index 51% rename from src/thingdef/thingdef_exp.h rename to src/scripting/codegeneration/codegen.h index 5fe8f252f9..c18754cb85 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/scripting/codegeneration/codegen.h @@ -41,6 +41,10 @@ */ #include "m_random.h" +#include "sc_man.h" +#include "s_sound.h" +#include "actor.h" +#include "vmbuilder.h" #define CHECKRESOLVED() if (isresolved) return this; isresolved=true; @@ -53,25 +57,45 @@ class VMFunctionBuilder; class FxJumpStatement; +extern FMemArena FxAlloc; + //========================================================================== // // // //========================================================================== +struct FScriptPosition; +class FxLoopStatement; +class FxCompoundStatement; +class FxLocalVariableDeclaration; +typedef TDeletingArray FArgumentList; struct FCompileContext { - TArray Jumps; + FxExpression *ControlStmt = nullptr; + FxLoopStatement *Loop = nullptr; + FxCompoundStatement *Block = nullptr; PPrototype *ReturnProto; - PClassActor *Class; + PFunction *Function; // The function that is currently being compiled (or nullptr for constant evaluation.) + PStruct *Class; // The type of the owning class. + bool FromDecorate; // DECORATE must silence some warnings and demote some errors. + int StateIndex; // index in actor's state table for anonymous functions, otherwise -1 (not used by DECORATE which pre-resolves state indices) + int StateCount; // amount of states an anoymous function is being used on (must be 1 for state indices to be allowed.) + int Lump; + bool Unsafe = false; + TDeletingArray FunctionArgs; - FCompileContext(PClassActor *cls = nullptr, PPrototype *ret = nullptr); + FCompileContext(PFunction *func, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump); + FCompileContext(PStruct *cls, bool fromdecorate); // only to be used to resolve constants! - PSymbol *FindInClass(FName identifier); + PSymbol *FindInClass(FName identifier, PSymbolTable *&symt); + PSymbol *FindInSelfClass(FName identifier, PSymbolTable *&symt); PSymbol *FindGlobal(FName identifier); void HandleJumps(int token, FxExpression *handler); void CheckReturn(PPrototype *proto, FScriptPosition &pos); + bool CheckReadOnly(int flags); + FxLocalVariableDeclaration *FindLocalVariable(FName name); }; //========================================================================== @@ -147,10 +171,22 @@ struct ExpVal return regtype == REGT_INT ? Int : regtype == REGT_FLOAT ? int(Float) : 0; } + unsigned GetUInt() const + { + int regtype = Type->GetRegType(); + return regtype == REGT_INT ? unsigned(Int) : regtype == REGT_FLOAT ? unsigned(Float) : 0; + } + double GetFloat() const { int regtype = Type->GetRegType(); - return regtype == REGT_INT ? double(Int) : regtype == REGT_FLOAT ? Float : 0; + return regtype == REGT_INT ? (Type == TypeUInt32? double(unsigned(Int)) : double(Int)) : regtype == REGT_FLOAT ? Float : 0; + } + + void *GetPointer() const + { + int regtype = Type->GetRegType(); + return regtype == REGT_POINTER ? pointer : nullptr; } const FString GetString() const @@ -166,20 +202,95 @@ struct ExpVal FName GetName() const { + if (Type == TypeString) + { + if (((FString *)&pointer)->Len() == 0) return NAME_None; + return FName(*(FString *)&pointer); + } return Type == TypeName ? ENamedName(Int) : NAME_None; } }; -struct ExpEmit +enum EFxType { - ExpEmit() : RegNum(0), RegType(REGT_NIL), Konst(false), Fixed(false), Final(false) {} - ExpEmit(int reg, int type) : RegNum(reg), RegType(type), Konst(false), Fixed(false), Final(false) {} - ExpEmit(int reg, int type, bool konst) : RegNum(reg), RegType(type), Konst(konst), Fixed(false), Final(false) {} - ExpEmit(VMFunctionBuilder *build, int type); - void Free(VMFunctionBuilder *build); - void Reuse(VMFunctionBuilder *build); - - BYTE RegNum, RegType, Konst:1, Fixed:1, Final:1; + EFX_Expression, + EFX_Identifier, + EFX_MemberIdentifier, + EFX_ClassDefaults, + EFX_Constant, + EFX_BoolCast, + EFX_IntCast, + EFX_FloatCast, + EFX_NameCast, + EFX_StringCast, + EFX_ColorCast, + EFX_SoundCast, + EFX_TypeCast, + EFX_PlusSign, + EFX_MinusSign, + EFX_UnaryNotBitwise, + EFX_UnaryNotBoolean, + EFX_SizeAlign, + EFX_PreIncrDecr, + EFX_PostIncrDecr, + EFX_Assign, + EFX_AssignSelf, + EFX_Binary, // one token fits all, the operator is enough to distinguish them. + EFX_BinaryLogical, + EFX_DotCross, + EFX_Conditional, + EFX_Abs, + EFX_ATan2, + EFX_MinMax, + EFX_Random, + EFX_RandomPick, + EFX_FRandom, + EFX_Random2, + EFX_ClassMember, + EFX_StructMember, + EFX_LocalVariable, + EFX_Self, + EFX_ArrayElement, + EFX_FunctionCall, + EFX_MemberFunctionCall, + EFX_ActionSpecialCall, + EFX_FlopFunctionCall, + EFX_VMFunctionCall, + EFX_Sequence, + EFX_CompoundStatement, + EFX_IfStatement, + EFX_LoopStatement, + EFX_WhileLoop, + EFX_DoWhileLoop, + EFX_ForLoop, + EFX_JumpStatement, + EFX_ReturnStatement, + EFX_ClassTypeCast, + EFX_ClassPtrCast, + EFX_StateByIndex, + EFX_RuntimeStateIndex, + EFX_MultiNameState, + EFX_DamageValue, + EFX_Nop, + EFX_LocalVariableDeclaration, + EFX_SwitchStatement, + EFX_CaseStatement, + EFX_VectorValue, + EFX_VectorBuiltin, + EFX_TypeCheck, + EFX_DynamicCast, + EFX_GlobalVariable, + EFX_Super, + EFX_StackVariable, + EFX_MultiAssign, + EFX_StaticArray, + EFX_StaticArrayVariable, + EFX_CVar, + EFX_NamedNode, + EFX_GetClass, + EFX_ColorLiteral, + EFX_GetDefaultByType, + EFX_COUNT }; //========================================================================== @@ -191,32 +302,49 @@ struct ExpEmit class FxExpression { protected: - FxExpression(const FScriptPosition &pos) - : ScriptPosition(pos) + FxExpression(EFxType type, const FScriptPosition &pos) + : ScriptPosition(pos), ExprType(type) { - isresolved = false; - ScriptPosition = pos; - ValueType = NULL; } -public: + +public: + FxExpression *CheckIntForName(); + virtual ~FxExpression() {} virtual FxExpression *Resolve(FCompileContext &ctx); virtual bool isConstant() const; - virtual bool RequestAddress(); + virtual bool RequestAddress(FCompileContext &ctx, bool *writable); virtual PPrototype *ReturnProto(); virtual VMFunction *GetDirectFunction(); - bool IsNumeric() const { return ValueType != TypeName && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT); } + virtual bool CheckReturn() { return false; } + virtual int GetBitValue() { return -1; } + bool IsNumeric() const { return ValueType->isNumeric(); } + bool IsFloat() const { return ValueType->GetRegType() == REGT_FLOAT && ValueType->GetRegCount() == 1; } + bool IsInteger() const { return ValueType->isNumeric() && (ValueType->GetRegType() == REGT_INT); } bool IsPointer() const { return ValueType->GetRegType() == REGT_POINTER; } + bool IsVector() const { return ValueType == TypeVector2 || ValueType == TypeVector3; }; + bool IsBoolCompat() const { return ValueType->GetRegCount() == 1 && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT || ValueType->GetRegType() == REGT_POINTER); } + bool IsObject() const { return ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) && ValueType != TypeNullPtr && static_cast(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass)); } virtual ExpEmit Emit(VMFunctionBuilder *build); - - TArray JumpAddresses; + void EmitStatement(VMFunctionBuilder *build); + virtual void EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no); FScriptPosition ScriptPosition; - PType *ValueType; + PType *ValueType = nullptr; - bool isresolved; + bool isresolved = false; + bool NeedResult = true; // should be set to false if not needed and properly handled by all nodes for their subnodes to eliminate redundant code + EFxType ExprType; + + void *operator new(size_t size) + { + return FxAlloc.Alloc(size); + } + + void operator delete(void *block) {} + void operator delete[](void *block) {} }; //========================================================================== @@ -227,31 +355,33 @@ public: class FxIdentifier : public FxExpression { - FName Identifier; - public: + FName Identifier; + bool noglobal = false; + FxIdentifier(FName i, const FScriptPosition &p); FxExpression *Resolve(FCompileContext&); + FxExpression *ResolveMember(FCompileContext&, PStruct*, FxExpression*&, PStruct*); }; //========================================================================== // -// FxDotIdentifier +// FxMemberIdentifier // //========================================================================== -class FxDotIdentifier : public FxExpression +class FxMemberIdentifier : public FxIdentifier { - FxExpression *container; - FName Identifier; + FxExpression *Object; public: - FxDotIdentifier(FxExpression*, FName, const FScriptPosition &); - ~FxDotIdentifier(); + FxMemberIdentifier(FxExpression *obj, FName i, const FScriptPosition &p); + ~FxMemberIdentifier(); FxExpression *Resolve(FCompileContext&); }; + //========================================================================== // // FxClassDefaults @@ -261,12 +391,14 @@ public: class FxClassDefaults : public FxExpression { FxExpression *obj; + bool EmitTail; public: - FxClassDefaults(FxExpression*, const FScriptPosition &); + FxClassDefaults(FxExpression *, const FScriptPosition &); ~FxClassDefaults(); + PPrototype *ReturnProto(); FxExpression *Resolve(FCompileContext&); - bool IsDefaultObject() const; + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -280,69 +412,100 @@ class FxConstant : public FxExpression ExpVal value; public: - FxConstant(bool val, const FScriptPosition &pos) : FxExpression(pos) + FxConstant(bool val, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) { ValueType = value.Type = TypeBool; value.Int = val; isresolved = true; } - FxConstant(int val, const FScriptPosition &pos) : FxExpression(pos) + FxConstant(int val, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) { ValueType = value.Type = TypeSInt32; value.Int = val; isresolved = true; } - FxConstant(double val, const FScriptPosition &pos) : FxExpression(pos) + FxConstant(double val, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) { ValueType = value.Type = TypeFloat64; value.Float = val; isresolved = true; } - FxConstant(FSoundID val, const FScriptPosition &pos) : FxExpression(pos) + FxConstant(FSoundID val, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) { ValueType = value.Type = TypeSound; value.Int = val; isresolved = true; } - FxConstant(FName val, const FScriptPosition &pos) : FxExpression(pos) + FxConstant(FName val, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) { ValueType = value.Type = TypeName; value.Int = val; isresolved = true; } - FxConstant(const FString &str, const FScriptPosition &pos) : FxExpression(pos) + FxConstant(const FString &str, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) { ValueType = TypeString; value = ExpVal(str); isresolved = true; } - FxConstant(ExpVal cv, const FScriptPosition &pos) : FxExpression(pos) + FxConstant(ExpVal cv, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) { value = cv; ValueType = cv.Type; isresolved = true; } - FxConstant(PClass *val, const FScriptPosition &pos) : FxExpression(pos) + FxConstant(PClass *val, PClassPointer *valtype, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) { value.pointer = (void*)val; - ValueType = val; - value.Type = NewClassPointer(RUNTIME_CLASS(AActor)); + value.Type = ValueType = valtype; isresolved = true; } - FxConstant(FState *state, const FScriptPosition &pos) : FxExpression(pos) + FxConstant(FState *state, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) { value.pointer = state; ValueType = value.Type = TypeState; isresolved = true; } + + FxConstant(const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) + { + value.pointer = nullptr; + ValueType = value.Type = TypeNullPtr; + isresolved = true; + } + + FxConstant(PType *type, VMValue &vmval, const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) + { + ValueType = value.Type = type; + isresolved = true; + switch (vmval.Type) + { + default: + case REGT_INT: + value.Int = vmval.i; + break; + + case REGT_FLOAT: + value.Float = vmval.f; + break; + + case REGT_STRING: + value = ExpVal(vmval.s()); + break; + + case REGT_POINTER: + value.pointer = vmval.a; + break; + } + } static FxExpression *MakeConstant(PSymbol *sym, const FScriptPosition &pos); @@ -358,6 +521,33 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// +// +//========================================================================== + +class FxVectorValue : public FxExpression +{ + FxExpression *xyz[3]; + bool isConst; // gets set to true if all element are const (used by function defaults parser) + +public: + + friend class ZCCCompiler; + + FxVectorValue(FxExpression *x, FxExpression *y, FxExpression *z, const FScriptPosition &sc); + ~FxVectorValue(); + FxExpression *Resolve(FCompileContext&); + bool isConstVector(int dim) + { + if (!isConst) return false; + return dim == 2 ? xyz[2] == nullptr : xyz[2] != nullptr; + } + + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // @@ -368,23 +558,27 @@ public: class FxBoolCast : public FxExpression { FxExpression *basex; + bool NeedValue; public: - FxBoolCast(FxExpression *x); + FxBoolCast(FxExpression *x, bool needvalue = true); ~FxBoolCast(); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); + void EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no); }; class FxIntCast : public FxExpression { FxExpression *basex; + bool NoWarn; + bool Explicit; public: - FxIntCast(FxExpression *x); + FxIntCast(FxExpression *x, bool nowarn, bool explicitly = false); ~FxIntCast(); FxExpression *Resolve(FCompileContext&); @@ -404,6 +598,79 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +class FxNameCast : public FxExpression +{ + FxExpression *basex; + +public: + + FxNameCast(FxExpression *x); + ~FxNameCast(); + FxExpression *Resolve(FCompileContext&); + + ExpEmit Emit(VMFunctionBuilder *build); +}; + +class FxStringCast : public FxExpression +{ + FxExpression *basex; + +public: + + FxStringCast(FxExpression *x); + ~FxStringCast(); + FxExpression *Resolve(FCompileContext&); + + ExpEmit Emit(VMFunctionBuilder *build); +}; + +class FxColorCast : public FxExpression +{ + FxExpression *basex; + +public: + + FxColorCast(FxExpression *x); + ~FxColorCast(); + FxExpression *Resolve(FCompileContext&); + + ExpEmit Emit(VMFunctionBuilder *build); +}; + +class FxSoundCast : public FxExpression +{ + FxExpression *basex; + +public: + + FxSoundCast(FxExpression *x); + ~FxSoundCast(); + FxExpression *Resolve(FCompileContext&); + + ExpEmit Emit(VMFunctionBuilder *build); +}; + +//========================================================================== +// +// FxTypeCast +// +//========================================================================== + +class FxTypeCast : public FxExpression +{ + FxExpression *basex; + bool NoWarn; + bool Explicit; + +public: + + FxTypeCast(FxExpression *x, PType *type, bool nowarn, bool explicitly = false); + ~FxTypeCast(); + FxExpression *Resolve(FCompileContext&); + + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxSign @@ -470,6 +737,25 @@ public: ~FxUnaryNotBoolean(); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); + void EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no); +}; + +//========================================================================== +// +// FxSign +// +//========================================================================== + +class FxSizeAlign : public FxExpression +{ + FxExpression *Operand; + int Which; + +public: + FxSizeAlign(FxExpression*, int which); + ~FxSizeAlign(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== @@ -489,7 +775,7 @@ public: FxPreIncrDecr(FxExpression *base, int token); ~FxPreIncrDecr(); FxExpression *Resolve(FCompileContext&); - bool RequestAddress(); + bool RequestAddress(FCompileContext &ctx, bool *writable); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -521,19 +807,45 @@ class FxAssign : public FxExpression { FxExpression *Base; FxExpression *Right; + int IsBitWrite; bool AddressRequested; bool AddressWritable; + bool IsModifyAssign; + + friend class FxAssignSelf; public: - FxAssign(FxExpression *base, FxExpression *right); + FxAssign(FxExpression *base, FxExpression *right, bool ismodify = false); ~FxAssign(); FxExpression *Resolve(FCompileContext&); - bool RequestAddress(); + //bool RequestAddress(FCompileContext &ctx, bool *writable); ExpEmit Emit(VMFunctionBuilder *build); ExpEmit Address; }; +//========================================================================== +// +// FxAssign +// +//========================================================================== +class FxCompoundStatement; + +class FxMultiAssign : public FxExpression +{ + FxCompoundStatement *LocalVarContainer; // for handling the temporary variables of the results, which may need type casts. + FArgumentList Base; + FxExpression *Right; + bool AddressRequested = false; + bool AddressWritable = false; + +public: + FxMultiAssign(FArgumentList &base, FxExpression *right, const FScriptPosition &pos); + ~FxMultiAssign(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxAssignSelf @@ -565,8 +877,7 @@ public: FxBinary(int, FxExpression*, FxExpression*); ~FxBinary(); - bool ResolveLR(FCompileContext& ctx, bool castnumeric); - void Promote(FCompileContext &ctx); + bool Promote(FCompileContext &ctx, bool forceint = false); }; //========================================================================== @@ -605,13 +916,31 @@ public: // //========================================================================== +class FxPow : public FxBinary +{ +public: + + FxPow(FxExpression*, FxExpression*); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + +//========================================================================== +// +// FxBinary +// +//========================================================================== + class FxCompareRel : public FxBinary { + PType *CompareType; public: FxCompareRel(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); + ExpEmit EmitCommon(VMFunctionBuilder *build, bool forcompare, bool invert); ExpEmit Emit(VMFunctionBuilder *build); + void EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no); }; //========================================================================== @@ -626,6 +955,23 @@ public: FxCompareEq(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); + ExpEmit EmitCommon(VMFunctionBuilder *build, bool forcompare, bool invert); + ExpEmit Emit(VMFunctionBuilder *build); + void EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no); +}; + +//========================================================================== +// +// FxBinary +// +//========================================================================== + +class FxBitOp : public FxBinary +{ +public: + + FxBitOp(int, FxExpression*, FxExpression*); + FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -635,15 +981,45 @@ public: // //========================================================================== -class FxBinaryInt : public FxBinary +class FxShift : public FxBinary { public: - FxBinaryInt(int, FxExpression*, FxExpression*); + FxShift(int, FxExpression*, FxExpression*); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// +// +//========================================================================== + +class FxLtGtEq : public FxBinary +{ +public: + FxLtGtEq(FxExpression*, FxExpression*); + FxExpression *Resolve(FCompileContext&); + + ExpEmit Emit(VMFunctionBuilder *build); +}; + +//========================================================================== +// +// +// +//========================================================================== + +class FxConcat : public FxBinary +{ +public: + FxConcat(FxExpression*, FxExpression*); + FxExpression *Resolve(FCompileContext&); + + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxBinaryLogical @@ -656,9 +1032,72 @@ public: int Operator; FxExpression *left; FxExpression *right; + TDeletingArray list; FxBinaryLogical(int, FxExpression*, FxExpression*); ~FxBinaryLogical(); + void Flatten(); + FxExpression *Resolve(FCompileContext&); + + ExpEmit Emit(VMFunctionBuilder *build); +}; + +//========================================================================== +// +// FxBinaryLogical +// +//========================================================================== + +class FxDotCross : public FxExpression +{ +public: + int Operator; + FxExpression *left; + FxExpression *right; + + FxDotCross(int, FxExpression*, FxExpression*); + ~FxDotCross(); + FxExpression *Resolve(FCompileContext&); + + ExpEmit Emit(VMFunctionBuilder *build); +}; + +//========================================================================== +// +// +// +//========================================================================== + +class FxTypeCheck : public FxExpression +{ +public: + FxExpression *left; + FxExpression *right; + bool EmitTail; + + FxTypeCheck(FxExpression*, FxExpression*); + ~FxTypeCheck(); + FxExpression *Resolve(FCompileContext&); + + ExpEmit EmitCommon(VMFunctionBuilder *build); + ExpEmit Emit(VMFunctionBuilder *build); + void EmitCompare(VMFunctionBuilder *build, bool invert, TArray &patchspots_yes, TArray &patchspots_no); +}; + +//========================================================================== +// +// +// +//========================================================================== + +class FxDynamicCast : public FxExpression +{ + PClass *CastType; +public: + FxExpression *expr; + + FxDynamicCast(PClass*, FxExpression*); + ~FxDynamicCast(); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); @@ -757,7 +1196,7 @@ protected: public: - FxRandom(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos); + FxRandom(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos, bool nowarn); ~FxRandom(); FxExpression *Resolve(FCompileContext&); PPrototype *ReturnProto(); @@ -778,7 +1217,7 @@ protected: public: - FxRandomPick(FRandom *, TArray &expr, bool floaty, const FScriptPosition &pos); + FxRandomPick(FRandom *, TArray &expr, bool floaty, const FScriptPosition &pos, bool nowarn); ~FxRandomPick(); FxExpression *Resolve(FCompileContext&); @@ -812,7 +1251,7 @@ class FxRandom2 : public FxExpression public: - FxRandom2(FRandom *, FxExpression *m, const FScriptPosition &pos); + FxRandom2(FRandom *, FxExpression *m, const FScriptPosition &pos, bool nowarn); ~FxRandom2(); FxExpression *Resolve(FCompileContext&); PPrototype *ReturnProto(); @@ -820,23 +1259,127 @@ public: }; +//========================================================================== +// +// FxGlobalVariaböe +// +//========================================================================== + +class FxGlobalVariable : public FxExpression +{ +public: + PField *membervar; + bool AddressRequested; + bool AddressWritable; + + FxGlobalVariable(PField*, const FScriptPosition&); + FxExpression *Resolve(FCompileContext&); + bool RequestAddress(FCompileContext &ctx, bool *writable); + ExpEmit Emit(VMFunctionBuilder *build); + virtual int GetBitValue() { return membervar->BitValue; } +}; + +class FxCVar : public FxExpression +{ + FBaseCVar *CVar; +public: + FxCVar(FBaseCVar*, const FScriptPosition&); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxClassMember // //========================================================================== -class FxClassMember : public FxExpression +class FxStructMember : public FxExpression { public: FxExpression *classx; PField *membervar; bool AddressRequested; + bool AddressWritable; + + FxStructMember(FxExpression*, PField*, const FScriptPosition&); + ~FxStructMember(); + FxExpression *Resolve(FCompileContext&); + bool RequestAddress(FCompileContext &ctx, bool *writable); + ExpEmit Emit(VMFunctionBuilder *build); + virtual int GetBitValue() { return membervar->BitValue; } +}; + +//========================================================================== +// +// FxClassMember +// +//========================================================================== + +class FxClassMember : public FxStructMember +{ +public: FxClassMember(FxExpression*, PField*, const FScriptPosition&); - ~FxClassMember(); +}; + +//========================================================================== +// +// FxLocalVariable +// +//========================================================================== + +class FxLocalVariable : public FxExpression +{ +public: + FxLocalVariableDeclaration *Variable; + bool AddressRequested; + int RegOffset; + + FxLocalVariable(FxLocalVariableDeclaration*, const FScriptPosition&); FxExpression *Resolve(FCompileContext&); - bool RequestAddress(); + bool RequestAddress(FCompileContext &ctx, bool *writable); + ExpEmit Emit(VMFunctionBuilder *build); +}; + +//========================================================================== +// +// FxLocalVariable +// +//========================================================================== + +class FxStackVariable : public FxExpression +{ +public: + PField *membervar; + bool AddressRequested; + bool AddressWritable; + + FxStackVariable(PType *type, int offset, const FScriptPosition&); + ~FxStackVariable(); + void ReplaceField(PField *newfield); + FxExpression *Resolve(FCompileContext&); + bool RequestAddress(FCompileContext &ctx, bool *writable); + ExpEmit Emit(VMFunctionBuilder *build); + virtual int GetBitValue() { return membervar->BitValue; } +}; + +//========================================================================== +// +// FxLocalVariable +// +//========================================================================== +class FxStaticArray; + +class FxStaticArrayVariable : public FxExpression +{ +public: + FxStaticArray *Variable; + bool AddressRequested; + + FxStaticArrayVariable(FxLocalVariableDeclaration*, const FScriptPosition&); + FxExpression *Resolve(FCompileContext&); + bool RequestAddress(FCompileContext &ctx, bool *writable); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -848,12 +1391,31 @@ public: class FxSelf : public FxExpression { + bool check; + public: - FxSelf(const FScriptPosition&); + FxSelf(const FScriptPosition&, bool deccheck = false); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxSuper +// +//========================================================================== + +class FxSuper : public FxSelf +{ +public: + FxSuper(const FScriptPosition&pos) + : FxSelf(pos) + { + ExprType = EFX_Super; + } + FxExpression *Resolve(FCompileContext&); +}; + //========================================================================== // // FxArrayElement @@ -867,11 +1429,12 @@ public: FxExpression *index; bool AddressRequested; bool AddressWritable; + bool arrayispointer = false; FxArrayElement(FxExpression*, FxExpression*); ~FxArrayElement(); FxExpression *Resolve(FCompileContext&); - bool RequestAddress(); + bool RequestAddress(FCompileContext &ctx, bool *writable); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -882,22 +1445,40 @@ public: // //========================================================================== -typedef TDeletingArray FArgumentList; - class FxFunctionCall : public FxExpression { - FxExpression *Self; FName MethodName; - FArgumentList *ArgList; + FRandom *RNG; + FArgumentList ArgList; public: - FxFunctionCall(FxExpression *self, FName methodname, FArgumentList *args, const FScriptPosition &pos); + FxFunctionCall(FName methodname, FName rngname, FArgumentList &args, const FScriptPosition &pos); ~FxFunctionCall(); FxExpression *Resolve(FCompileContext&); }; +//========================================================================== +// +// FxFunctionCall +// +//========================================================================== + +class FxMemberFunctionCall : public FxExpression +{ + FxExpression *Self; + FName MethodName; + FArgumentList ArgList; + +public: + + FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &args, const FScriptPosition &pos); + ~FxMemberFunctionCall(); + FxExpression *Resolve(FCompileContext&); +}; + + //========================================================================== // // FxActionSpecialCall @@ -909,11 +1490,11 @@ class FxActionSpecialCall : public FxExpression int Special; bool EmitTail; FxExpression *Self; - FArgumentList *ArgList; + FArgumentList ArgList; public: - FxActionSpecialCall(FxExpression *self, int special, FArgumentList *args, const FScriptPosition &pos); + FxActionSpecialCall(FxExpression *self, int special, FArgumentList &args, const FScriptPosition &pos); ~FxActionSpecialCall(); FxExpression *Resolve(FCompileContext&); PPrototype *ReturnProto(); @@ -929,16 +1510,89 @@ public: class FxFlopFunctionCall : public FxExpression { int Index; - FArgumentList *ArgList; + FArgumentList ArgList; public: - FxFlopFunctionCall(size_t index, FArgumentList *args, const FScriptPosition &pos); + FxFlopFunctionCall(size_t index, FArgumentList &args, const FScriptPosition &pos); ~FxFlopFunctionCall(); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxFlopFunctionCall +// +//========================================================================== + +class FxVectorBuiltin : public FxExpression +{ + FName Function; + FxExpression *Self; + +public: + + FxVectorBuiltin(FxExpression *self, FName name); + ~FxVectorBuiltin(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + +//========================================================================== +// +// FxFlopFunctionCall +// +//========================================================================== + +class FxGetClass : public FxExpression +{ + FxExpression *Self; + +public: + + FxGetClass(FxExpression *self); + ~FxGetClass(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + +//========================================================================== +// +// FxFlopFunctionCall +// +//========================================================================== + +class FxGetDefaultByType : public FxExpression +{ + FxExpression *Self; + +public: + + FxGetDefaultByType(FxExpression *self); + ~FxGetDefaultByType(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + +//========================================================================== +// +// FxColorLiteral +// +//========================================================================== + +class FxColorLiteral : public FxExpression +{ + FArgumentList ArgList; + int constval = 0; + +public: + + FxColorLiteral(FArgumentList &args, FScriptPosition &sc); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxVMFunctionCall @@ -947,36 +1601,121 @@ public: class FxVMFunctionCall : public FxExpression { + friend class FxMultiAssign; + bool EmitTail; + bool NoVirtual; + FxExpression *Self; PFunction *Function; - FArgumentList *ArgList; + FArgumentList ArgList; + // for multi assignment + int AssignCount = 0; + TArray ReturnRegs; public: - FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos); + FxVMFunctionCall(FxExpression *self, PFunction *func, FArgumentList &args, const FScriptPosition &pos, bool novirtual); ~FxVMFunctionCall(); FxExpression *Resolve(FCompileContext&); PPrototype *ReturnProto(); VMFunction *GetDirectFunction(); ExpEmit Emit(VMFunctionBuilder *build); bool CheckEmitCast(VMFunctionBuilder *build, bool returnit, ExpEmit ®); + TArray &GetReturnTypes() const + { + return Function->Variants[0].Proto->ReturnTypes; + } }; //========================================================================== // -// FxSequence +// FxSequence (a list of statements with no semantics attached - used to return multiple nodes as one) // //========================================================================== +class FxLocalVariableDeclaration; class FxSequence : public FxExpression { TDeletingArray Expressions; public: - FxSequence(const FScriptPosition &pos) : FxExpression(pos) {} + FxSequence(const FScriptPosition &pos) : FxExpression(EFX_Sequence, pos) {} FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); - void Add(FxExpression *expr) { if (expr != NULL) Expressions.Push(expr); } + void Add(FxExpression *expr) { if (expr != NULL) Expressions.Push(expr); expr->NeedResult = false; } VMFunction *GetDirectFunction(); + bool CheckReturn(); +}; + +//========================================================================== +// +// FxCompoundStatement (like a list but implements maintenance of local variables) +// +//========================================================================== +class FxLocalVariableDeclaration; + +class FxCompoundStatement : public FxSequence +{ + TArray LocalVars; + FxCompoundStatement *Outer = nullptr; + + friend class FxLocalVariableDeclaration; + friend class FxStaticArray; + friend class FxMultiAssign; + +public: + FxCompoundStatement(const FScriptPosition &pos) : FxSequence(pos) {} + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); + FxLocalVariableDeclaration *FindLocalVariable(FName name, FCompileContext &ctx); + bool CheckLocalVariable(FName name); +}; + +//========================================================================== +// +// FxSwitchStatement +// +//========================================================================== + +class FxSwitchStatement : public FxExpression +{ + FxExpression *Condition; + FArgumentList Content; + + struct CaseAddr + { + int casevalue; + size_t jumpaddress; + }; + + TArray CaseAddresses; + +public: + TArray Breaks; + + FxSwitchStatement(FxExpression *cond, FArgumentList &content, const FScriptPosition &pos); + ~FxSwitchStatement(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); + bool CheckReturn(); +}; + +//========================================================================== +// +// FxSwitchStatement +// +//========================================================================== + +class FxCaseStatement : public FxExpression +{ + FxExpression *Condition; + int CaseValue; // copy the value to here for easier access. + + friend class FxSwitchStatement; + +public: + FxCaseStatement(FxExpression *cond, const FScriptPosition &pos); + ~FxCaseStatement(); + FxExpression *Resolve(FCompileContext&); }; //========================================================================== @@ -996,6 +1735,29 @@ public: ~FxIfStatement(); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); + bool CheckReturn(); +}; + +//========================================================================== +// +// Base class for loops +// +//========================================================================== + +class FxLoopStatement : public FxExpression +{ +protected: + FxLoopStatement(EFxType etype, const FScriptPosition &pos) + : FxExpression(etype, pos) + { + } + + void Backpatch(VMFunctionBuilder *build, size_t loopstart, size_t loopend); + FxExpression *Resolve(FCompileContext&) final; + virtual FxExpression *DoResolve(FCompileContext&) = 0; + +public: + TArray Jumps; }; //========================================================================== @@ -1004,7 +1766,7 @@ public: // //========================================================================== -class FxWhileLoop : public FxExpression +class FxWhileLoop : public FxLoopStatement { FxExpression *Condition; FxExpression *Code; @@ -1012,7 +1774,7 @@ class FxWhileLoop : public FxExpression public: FxWhileLoop(FxExpression *condition, FxExpression *code, const FScriptPosition &pos); ~FxWhileLoop(); - FxExpression *Resolve(FCompileContext&); + FxExpression *DoResolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -1022,7 +1784,7 @@ public: // //========================================================================== -class FxDoWhileLoop : public FxExpression +class FxDoWhileLoop : public FxLoopStatement { FxExpression *Condition; FxExpression *Code; @@ -1030,7 +1792,7 @@ class FxDoWhileLoop : public FxExpression public: FxDoWhileLoop(FxExpression *condition, FxExpression *code, const FScriptPosition &pos); ~FxDoWhileLoop(); - FxExpression *Resolve(FCompileContext&); + FxExpression *DoResolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -1040,7 +1802,7 @@ public: // //========================================================================== -class FxForLoop : public FxExpression +class FxForLoop : public FxLoopStatement { FxExpression *Init; FxExpression *Condition; @@ -1050,7 +1812,7 @@ class FxForLoop : public FxExpression public: FxForLoop(FxExpression *init, FxExpression *condition, FxExpression *iteration, FxExpression *code, const FScriptPosition &pos); ~FxForLoop(); - FxExpression *Resolve(FCompileContext&); + FxExpression *DoResolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -1069,7 +1831,6 @@ public: int Token; size_t Address; - FxExpression *AddressResolver; }; //========================================================================== @@ -1088,6 +1849,7 @@ public: FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); VMFunction *GetDirectFunction(); + bool CheckReturn() { return true; } }; //========================================================================== @@ -1103,12 +1865,31 @@ class FxClassTypeCast : public FxExpression public: - FxClassTypeCast(PClass *dtype, FxExpression *x); + FxClassTypeCast(PClassPointer *dtype, FxExpression *x); ~FxClassTypeCast(); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// +// +//========================================================================== + +class FxClassPtrCast : public FxExpression +{ + PClass *desttype; + FxExpression *basex; + +public: + + FxClassPtrCast(PClass *dtype, FxExpression *x); + ~FxClassPtrCast(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // Only used to resolve the old jump by index feature of DECORATE @@ -1121,7 +1902,7 @@ class FxStateByIndex : public FxExpression public: - FxStateByIndex(int i, const FScriptPosition &pos) : FxExpression(pos) + FxStateByIndex(int i, const FScriptPosition &pos) : FxExpression(EFX_StateByIndex, pos) { index = i; } @@ -1137,14 +1918,13 @@ public: class FxRuntimeStateIndex : public FxExpression { - bool EmitTail; FxExpression *Index; + int symlabel; public: FxRuntimeStateIndex(FxExpression *index); ~FxRuntimeStateIndex(); FxExpression *Resolve(FCompileContext&); - PPrototype *ReturnProto(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -1162,29 +1942,6 @@ public: FxMultiNameState(const char *statestring, const FScriptPosition &pos); FxExpression *Resolve(FCompileContext&); - ExpEmit Emit(VMFunctionBuilder *build); -}; - -//========================================================================== -// -// -// -//========================================================================== - -class FxDamageValue : public FxExpression -{ - FxExpression *val; - VMScriptFunction *MyFunction; - -public: - - FxDamageValue(FxExpression *v); - ~FxDamageValue(); - FxExpression *Resolve(FCompileContext&); - - ExpEmit Emit(VMFunctionBuilder *build); - VMScriptFunction *GetFunction() const { return MyFunction; } - void SetFunction(VMScriptFunction *func) { MyFunction = func; } }; //========================================================================== @@ -1197,7 +1954,7 @@ class FxNop : public FxExpression { public: FxNop(const FScriptPosition &p) - : FxExpression(p) + : FxExpression(EFX_Nop, p) { isresolved = true; } @@ -1207,7 +1964,73 @@ public: } }; -FxExpression *ParseExpression (FScanner &sc, PClassActor *cls, bool mustresolve = false); +//========================================================================== +// +// +// +//========================================================================== +class FxLocalVariableDeclaration : public FxExpression +{ + friend class FxCompoundStatement; + friend class FxLocalVariable; + friend class FxStaticArrayVariable; + + FName Name; + FxExpression *Init; + int VarFlags; + int RegCount; +public: + int StackOffset = -1; + int RegNum = -1; + + FxLocalVariableDeclaration(PType *type, FName name, FxExpression *initval, int varflags, const FScriptPosition &p); + ~FxLocalVariableDeclaration(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); + void Release(VMFunctionBuilder *build); + void SetReg(ExpEmit reginfo); + +}; + +//========================================================================== +// +// +// +//========================================================================== + +class FxStaticArray : public FxLocalVariableDeclaration +{ + friend class FxStaticArrayVariable; + + PType *ElementType; + FArgumentList values; + +public: + + FxStaticArray(PType *type, FName name, FArgumentList &args, const FScriptPosition &pos); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + +class FxNamedNode : public FxExpression +{ +public: + FName name; + FxExpression *value; + FxNamedNode(FName n, FxExpression *x, const FScriptPosition &pos) + : FxExpression(EFX_NamedNode, pos), name(n), value(x) + { + } + + FxExpression *Resolve(FCompileContext&) + { + // This should never reach the backend in a supported context, + // it's just needed to extend argument lists with the skipped parameters and needs to be resolved by the parent node. + ScriptPosition.Message(MSG_ERROR, "Named arguments not supported here"); + delete this; + return nullptr; + } +}; #endif diff --git a/src/thingdef/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp similarity index 95% rename from src/thingdef/olddecorations.cpp rename to src/scripting/decorate/olddecorations.cpp index 9afbfc965a..400444340f 100644 --- a/src/thingdef/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -44,11 +44,10 @@ #include "s_sound.h" #include "cmdlib.h" #include "p_lnspec.h" -#include "a_action.h" #include "decallib.h" #include "i_system.h" #include "thingdef.h" -#include "thingdef_exp.h" +#include "codegeneration/codegen.h" #include "r_data/r_translate.h" // TYPES ------------------------------------------------------------------- @@ -95,15 +94,18 @@ public: // The special was already executed by TryPickup, so do nothing here } }; -IMPLEMENT_CLASS (AFakeInventory) + +IMPLEMENT_CLASS(AFakeInventory, false, false) + +DEFINE_FIELD(AFakeInventory, Respawnable) // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- static void ParseInsideDecoration (Baggage &bag, AActor *defaults, - FExtraInfo &extra, EDefinitionType def, FScanner &sc, TArray &StateArray); -static void ParseSpriteFrames (PClassActor *info, TArray &states, FScanner &sc); + FExtraInfo &extra, EDefinitionType def, FScanner &sc, TArray &StateArray, TArray &SourceLines); +static void ParseSpriteFrames (PClassActor *info, TArray &states, TArray &SourceLines, FScanner &sc); // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -146,6 +148,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) { Baggage bag; TArray StateArray; + TArray SourceLines; FExtraInfo extra; PClassActor *type; PClassActor *parent; @@ -158,6 +161,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) type = DecoDerivedClass(FScriptPosition(sc), parent, typeName); ResetBaggage(&bag, parent); bag.Info = type; + bag.fromDecorate = true; #ifdef _DEBUG bag.ClassName = type->TypeName; #endif @@ -166,7 +170,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) sc.MustGetStringName("{"); memset (&extra, 0, sizeof(extra)); - ParseInsideDecoration (bag, (AActor *)(type->Defaults), extra, def, sc, StateArray); + ParseInsideDecoration (bag, (AActor *)(type->Defaults), extra, def, sc, StateArray, SourceLines); bag.Info->NumOwnedStates = StateArray.Size(); if (bag.Info->NumOwnedStates == 0) @@ -190,11 +194,14 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) { // Make a copy of the final frozen frame for A_FreezeDeathChunks FState icecopy = StateArray[extra.IceDeathEnd-1]; + FScriptPosition icepos = SourceLines[extra.IceDeathEnd - 1]; StateArray.Push (icecopy); + SourceLines.Push(icepos); type->NumOwnedStates += 1; } type->OwnedStates = new FState[type->NumOwnedStates]; + SaveStateSourceLines(type->OwnedStates, SourceLines); memcpy (type->OwnedStates, &StateArray[0], type->NumOwnedStates * sizeof(type->OwnedStates[0])); if (type->NumOwnedStates == 1) { @@ -351,7 +358,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) //========================================================================== static void ParseInsideDecoration (Baggage &bag, AActor *defaults, - FExtraInfo &extra, EDefinitionType def, FScanner &sc, TArray &StateArray) + FExtraInfo &extra, EDefinitionType def, FScanner &sc, TArray &StateArray, TArray &SourceLines) { AFakeInventory *const inv = static_cast(defaults); char sprite[5] = "TNT1"; @@ -401,7 +408,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, { sc.MustGetString (); extra.SpawnStart = StateArray.Size(); - ParseSpriteFrames (bag.Info, StateArray, sc); + ParseSpriteFrames (bag.Info, StateArray, SourceLines, sc); extra.SpawnEnd = StateArray.Size(); } else if ((def == DEF_BreakableDecoration || def == DEF_Projectile) && @@ -409,21 +416,21 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, { sc.MustGetString (); extra.DeathStart = StateArray.Size(); - ParseSpriteFrames (bag.Info, StateArray, sc); + ParseSpriteFrames (bag.Info, StateArray, SourceLines, sc); extra.DeathEnd = StateArray.Size(); } else if (def == DEF_BreakableDecoration && sc.Compare ("IceDeathFrames")) { sc.MustGetString (); extra.IceDeathStart = StateArray.Size(); - ParseSpriteFrames (bag.Info, StateArray, sc); + ParseSpriteFrames (bag.Info, StateArray, SourceLines, sc); extra.IceDeathEnd = StateArray.Size(); } else if (def == DEF_BreakableDecoration && sc.Compare ("BurnDeathFrames")) { sc.MustGetString (); extra.FireDeathStart = StateArray.Size(); - ParseSpriteFrames (bag.Info, StateArray, sc); + ParseSpriteFrames (bag.Info, StateArray, SourceLines, sc); extra.FireDeathEnd = StateArray.Size(); } else if (def == DEF_BreakableDecoration && sc.Compare ("GenericIceDeath")) @@ -648,12 +655,13 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults, // "10:A, 15:B, 8:C, 6:B" //========================================================================== -static void ParseSpriteFrames (PClassActor *info, TArray &states, FScanner &sc) +static void ParseSpriteFrames (PClassActor *info, TArray &states, TArray &SourceLines, FScanner &sc) { FState state; char *token = strtok (sc.String, ",\t\n\r"); memset (&state, 0, sizeof(state)); + state.UseFlags = info->DefaultStateUsage; while (token != NULL) { @@ -692,7 +700,7 @@ static void ParseSpriteFrames (PClassActor *info, TArray &states, FScann { sc.ScriptError ("* must come after a frame"); } - state.Fullbright = true; + state.StateFlags |= STF_FULLBRIGHT; } else if (*token < 'A' || *token > ']') { @@ -703,6 +711,7 @@ static void ParseSpriteFrames (PClassActor *info, TArray &states, FScann if (!firstState) { states.Push (state); + SourceLines.Push(sc); } firstState = false; state.Frame = *token-'A'; @@ -712,6 +721,7 @@ static void ParseSpriteFrames (PClassActor *info, TArray &states, FScann if (!firstState) { states.Push (state); + SourceLines.Push(sc); } token = strtok (NULL, ",\t\n\r"); diff --git a/src/thingdef/thingdef_exp.cpp b/src/scripting/decorate/thingdef_exp.cpp similarity index 92% rename from src/thingdef/thingdef_exp.cpp rename to src/scripting/decorate/thingdef_exp.cpp index cad6198f04..a0ab095100 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/scripting/decorate/thingdef_exp.cpp @@ -5,6 +5,7 @@ ** **--------------------------------------------------------------------------- ** Copyright 2005 Jan Cholasta +** Copyright 2005-2016 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -48,7 +49,7 @@ #include "thingdef.h" #include "p_lnspec.h" #include "doomstat.h" -#include "thingdef_exp.h" +#include "codegeneration/codegen.h" FRandom pr_exrandom ("EX_Random"); @@ -87,7 +88,7 @@ FxExpression *ParseExpression (FScanner &sc, PClassActor *cls, bool mustresolve) if (mustresolve) { - FCompileContext ctx(cls); + FCompileContext ctx(cls, true); data = data->Resolve(ctx); } @@ -139,27 +140,27 @@ static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls) break; case TK_LShiftEq: - exp = new FxBinaryInt(TK_LShift, left, nullptr); + exp = new FxShift(TK_LShift, left, nullptr); break; case TK_RShiftEq: - exp = new FxBinaryInt(TK_RShift, left, nullptr); + exp = new FxShift(TK_RShift, left, nullptr); break; case TK_URShiftEq: - exp = new FxBinaryInt(TK_URShift, left, nullptr); + exp = new FxShift(TK_URShift, left, nullptr); break; case TK_AndEq: - exp = new FxBinaryInt('&', left, nullptr); + exp = new FxBitOp('&', left, nullptr); break; case TK_XorEq: - exp = new FxBinaryInt('^', left, nullptr); + exp = new FxBitOp('^', left, nullptr); break; case TK_OrEq: - exp = new FxBinaryInt('|', left, nullptr); + exp = new FxBitOp('|', left, nullptr); break; default: @@ -170,7 +171,7 @@ static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls) exp->right = ParseExpressionM(sc, cls); - FxAssign *ret = new FxAssign(base, exp); + FxAssign *ret = new FxAssign(base, exp, true); left->Assignment = ret; return ret; } @@ -207,7 +208,7 @@ static FxExpression *ParseExpressionJ (FScanner &sc, PClassActor *cls) while (sc.CheckToken('|')) { FxExpression *right = ParseExpressionI (sc, cls); - tmp = new FxBinaryInt('|', tmp, right); + tmp = new FxBitOp('|', tmp, right); } return tmp; } @@ -219,7 +220,7 @@ static FxExpression *ParseExpressionI (FScanner &sc, PClassActor *cls) while (sc.CheckToken('^')) { FxExpression *right = ParseExpressionH (sc, cls); - tmp = new FxBinaryInt('^', tmp, right); + tmp = new FxBitOp('^', tmp, right); } return tmp; } @@ -231,7 +232,7 @@ static FxExpression *ParseExpressionH (FScanner &sc, PClassActor *cls) while (sc.CheckToken('&')) { FxExpression *right = ParseExpressionG (sc, cls); - tmp = new FxBinaryInt('&', tmp, right); + tmp = new FxBitOp('&', tmp, right); } return tmp; } @@ -272,7 +273,7 @@ static FxExpression *ParseExpressionE (FScanner &sc, PClassActor *cls) { int token = sc.TokenType; FxExpression *right = ParseExpressionD (sc, cls); - tmp = new FxBinaryInt(token, tmp, right); + tmp = new FxShift(token, tmp, right); } if (!sc.End) sc.UnGet(); return tmp; @@ -448,7 +449,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) sc.MustGetToken('('); FxExpression *exp = ParseExpressionM(sc, cls); sc.MustGetToken(')'); - return new FxIntCast(exp); + return new FxIntCast(exp, true); } else if (sc.CheckToken(TK_Float)) { @@ -476,13 +477,19 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) { exp = new FxRuntimeStateIndex(ParseExpressionM(sc, cls)); } + // The parsed expression is of type 'statelabel', but we want a real state here so we must convert it. + if (!exp->isConstant()) + { + FArgumentList args; + args.Push(exp); + exp = new FxFunctionCall(NAME_ResolveState, NAME_None, args, sc); + } sc.MustGetToken(')'); return exp; } else if (sc.CheckToken(TK_Identifier)) { FName identifier = FName(sc.String); - FArgumentList *args; PFunction *func; switch (identifier) @@ -503,19 +510,13 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) // There is an action function ACS_NamedExecuteWithResult which must be ignored here for this to work. if (func != nullptr && identifier != NAME_ACS_NamedExecuteWithResult) { - args = new FArgumentList; + FArgumentList args; if (sc.CheckToken('(')) { sc.UnGet(); - ParseFunctionParameters(sc, cls, *args, func, "", nullptr); + ParseFunctionParameters(sc, cls, args, func, "", nullptr); } - if (args->Size() == 0) - { - delete args; - args = nullptr; - } - - return new FxVMFunctionCall(func, args, sc); + return new FxVMFunctionCall(new FxSelf(sc), func, args, sc, false); } } @@ -536,26 +537,17 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) case NAME_VectorAngle: return ParseAtan2(sc, identifier, cls); default: - args = new FArgumentList; - try + FArgumentList args; + if (!sc.CheckToken(')')) { - if (!sc.CheckToken(')')) + do { - do - { - args->Push(ParseExpressionM (sc, cls)); - } - while (sc.CheckToken(',')); - sc.MustGetToken(')'); + args.Push(ParseExpressionM (sc, cls)); } - return new FxFunctionCall(NULL, identifier, args, sc); + while (sc.CheckToken(',')); + sc.MustGetToken(')'); } - catch (...) - { - delete args; - throw; - } - break; + return new FxFunctionCall(identifier, NAME_None, args, sc); } } else @@ -600,7 +592,7 @@ static FxExpression *ParseRandom(FScanner &sc, FName identifier, PClassActor *cl if (identifier == NAME_Random) { - return new FxRandom(rng, min, max, sc); + return new FxRandom(rng, min, max, sc, true); } else { @@ -627,7 +619,7 @@ static FxExpression *ParseRandomPick(FScanner &sc, FName identifier, PClassActor break; sc.MustGetToken(','); } - return new FxRandomPick(rng, list, floaty, sc); + return new FxRandomPick(rng, list, floaty, sc, true); } static FxExpression *ParseRandom2(FScanner &sc, PClassActor *cls) @@ -642,7 +634,7 @@ static FxExpression *ParseRandom2(FScanner &sc, PClassActor *cls) mask = ParseExpressionM(sc, cls); sc.MustGetToken(')'); } - return new FxRandom2(rng, mask, sc); + return new FxRandom2(rng, mask, sc, true); } static FxExpression *ParseAbs(FScanner &sc, PClassActor *cls) diff --git a/src/thingdef/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp similarity index 77% rename from src/thingdef/thingdef_parse.cpp rename to src/scripting/decorate/thingdef_parse.cpp index 963165ab13..f53b970067 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -4,8 +4,8 @@ ** Actor definitions - all parser related code ** **--------------------------------------------------------------------------- -** Copyright 2002-2007 Christoph Oelckers -** Copyright 2004-2007 Randy Heit +** Copyright 2002-2016 Christoph Oelckers +** Copyright 2004-2016 Randy Heit ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -49,7 +49,7 @@ #include "v_palette.h" #include "doomerrors.h" #include "i_system.h" -#include "thingdef_exp.h" +#include "codegeneration/codegen.h" #include "w_wad.h" #include "v_video.h" #include "version.h" @@ -57,6 +57,45 @@ #include "m_argv.h" void ParseOldDecoration(FScanner &sc, EDefinitionType def); +EXTERN_CVAR(Bool, strictdecorate); + + +//========================================================================== +// +// DecoDerivedClass +// +// Create a derived class and performs some additional sanity checks +// +//========================================================================== + +PClassActor *DecoDerivedClass(const FScriptPosition &sc, PClassActor *parent, FName typeName) +{ + PClassActor *type = static_cast(parent->CreateDerivedClass(typeName, parent->Size)); + if (type == nullptr) + { + FString newname = typeName.GetChars(); + FString sourcefile = sc.FileName; + + sourcefile.Substitute(":", "@"); + newname << '@' << sourcefile; + if (strictdecorate) + { + sc.Message(MSG_ERROR, "Tried to define class '%s' more than once.", typeName.GetChars()); + } + else + { + // Due to backwards compatibility issues this cannot be an unconditional error. + sc.Message(MSG_WARNING, "Tried to define class '%s' more than once. Renaming class to '%s'", typeName.GetChars(), newname.GetChars()); + } + type = static_cast(parent->CreateDerivedClass(newname, parent->Size)); + if (type == nullptr) + { + // This we cannot handle cleanly anymore. Let's just abort and forget about the odd mod out that was this careless. + sc.Message(MSG_FATAL, "Tried to define class '%s' more than twice in the same file.", typeName.GetChars()); + } + } + return type; +} //========================================================================== // @@ -92,7 +131,7 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c } else if (type == TypeSInt32) { - x = new FxIntCast(x); + x = new FxIntCast(x, true); } else { @@ -126,7 +165,7 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c } else { - int c = V_GetColor (NULL, sc.String); + int c = V_GetColor (NULL, sc); // 0 needs to be the default so we have to mark the color. v = MAKEARGB(1, RPART(c), GPART(c), BPART(c)); } @@ -135,22 +174,19 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c val.Int = v; x = new FxConstant(val, sc); } - else if (type == TypeState) + else if (type == TypeStateLabel) { // This forces quotation marks around the state name. if (sc.CheckToken(TK_StringConst)) { if (sc.String[0] == 0 || sc.Compare("None")) { - x = new FxConstant((FState*)NULL, sc); + x = new FxConstant(0, sc); + x->ValueType = TypeStateLabel; } else if (sc.Compare("*")) { - if (constant) - { - x = new FxConstant((FState*)(intptr_t)-1, sc); - } - else sc.ScriptError("Invalid state name '*'"); + sc.ScriptError("Invalid state name '*'"); } else { @@ -168,7 +204,7 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c sc.SetEscape(true); sc.MustGetString(); sc.SetEscape(false); - x = new FxClassTypeCast(static_cast(type)->ClassRestriction, new FxConstant(FName(sc.String), sc)); + x = new FxClassTypeCast(static_cast(type), new FxConstant(FName(sc.String), sc)); } else { @@ -295,248 +331,6 @@ static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClassActor *cls) sc.MustGetToken(';'); } -//========================================================================== -// -// ParseArgListDef -// -// Parses the argument list from a function declaration. -// -//========================================================================== - -static void ParseArgListDef(FScanner &sc, PClassActor *cls, - TArray &args, TArray &argflags) -{ - if (!sc.CheckToken(')')) - { - while (sc.TokenType != ')') - { - int flags = 0; - PType *type = NULL; - PClass *restrict = NULL; - - // Retrieve flags before type name - for (;;) - { - if (sc.CheckToken(TK_Coerce) || sc.CheckToken(TK_Native)) - { - } - else - { - break; - } - } - // Read the variable type - sc.MustGetAnyToken(); - switch (sc.TokenType) - { - case TK_Bool: - type = TypeBool; - break; - - case TK_Int: - type = TypeSInt32; - break; - - case TK_Float: - type = TypeFloat64; - break; - - case TK_Sound: type = TypeSound; break; - case TK_String: type = TypeString; break; - case TK_Name: type = TypeName; break; - case TK_State: type = TypeState; break; - case TK_Color: type = TypeColor; break; - case TK_Class: - sc.MustGetToken('<'); - sc.MustGetToken(TK_Identifier); // Get class name - restrict = PClass::FindClass(sc.String); - if (restrict == NULL) - { - sc.ScriptMessage("Unknown class type %s", sc.String); - FScriptPosition::ErrorCounter++; - } - else - { - type = NewClassPointer(restrict); - } - sc.MustGetToken('>'); - break; - case TK_Ellipsis: - // Making the final type NULL signals a varargs function. - type = NULL; - sc.MustGetToken(')'); - sc.UnGet(); - break; - default: - sc.ScriptMessage ("Unknown variable type %s", sc.TokenName(sc.TokenType, sc.String).GetChars()); - type = TypeSInt32; - FScriptPosition::ErrorCounter++; - break; - } - // Read the optional variable name - if (!sc.CheckToken(',') && !sc.CheckToken(')')) - { - sc.MustGetToken(TK_Identifier); - } - else - { - sc.UnGet(); - } - - if (sc.CheckToken('=')) - { - flags |= VARF_Optional; - FxExpression *def = ParseParameter(sc, cls, type, true); - delete def; - } - - args.Push(type); - argflags.Push(flags); - sc.MustGetAnyToken(); - if (sc.TokenType != ',' && sc.TokenType != ')') - { - sc.ScriptError ("Expected ',' or ')' but got %s instead", sc.TokenName(sc.TokenType, sc.String).GetChars()); - } - } - } - sc.MustGetToken(';'); -} - -//========================================================================== -// -// SetImplicitArgs -// -// Adds the parameters implied by the function flags. -// -//========================================================================== - -void SetImplicitArgs(TArray *args, TArray *argflags, PClassActor *cls, DWORD funcflags) -{ - // Must be called before adding any other arguments. - assert(args == NULL || args->Size() == 0); - assert(argflags == NULL || argflags->Size() == 0); - - if (funcflags & VARF_Method) - { - // implied self pointer - if (args != NULL) args->Push(NewClassPointer(cls)); - if (argflags != NULL) argflags->Push(0); - } - if (funcflags & VARF_Action) - { - // implied stateowner and callingstate pointers - if (args != NULL) - { - args->Push(NewClassPointer(RUNTIME_CLASS(AActor))); - args->Push(TypeState); - } - if (argflags != NULL) - { - argflags->Push(0); - argflags->Push(0); - } - } -} - -//========================================================================== -// -// ParseFunctionDef -// -// Parses a native function's parameters and adds it to the class, -// if possible. -// -//========================================================================== - -void ParseFunctionDef(FScanner &sc, PClassActor *cls, FName funcname, - TArray &rets, DWORD funcflags) -{ - assert(cls != NULL); - - const AFuncDesc *afd; - TArray args; - TArray argflags; - - afd = FindFunction(funcname); - if (afd == NULL) - { - sc.ScriptMessage ("The function '%s' has not been exported from the executable.", funcname.GetChars()); - FScriptPosition::ErrorCounter++; - } - sc.MustGetToken('('); - - SetImplicitArgs(&args, &argflags, cls, funcflags); - ParseArgListDef(sc, cls, args, argflags); - - if (afd != NULL) - { - PFunction *sym = new PFunction(funcname); - sym->AddVariant(NewPrototype(rets, args), argflags, *(afd->VMPointer)); - sym->Flags = funcflags; - if (cls->Symbols.AddSymbol(sym) == NULL) - { - delete sym; - sc.ScriptMessage ("'%s' is already defined in class '%s'.", - funcname.GetChars(), cls->TypeName.GetChars()); - FScriptPosition::ErrorCounter++; - } - } -} - -//========================================================================== -// -// ParseNativeFunction -// -// Parses a non-action function declaration. -// -//========================================================================== - -static void ParseNativeFunction(FScanner &sc, PClassActor *cls) -{ - TArray rets(1); - - if (sc.LumpNum == -1 || Wads.GetLumpFile(sc.LumpNum) > 0) - { - sc.ScriptMessage ("functions can only be declared by native actors!"); - FScriptPosition::ErrorCounter++; - } - - // Read the type and make sure it's acceptable. - sc.MustGetAnyToken(); - switch (sc.TokenType) - { - case TK_Bool: - rets.Push(TypeBool); - break; - - case TK_Int: - rets.Push(TypeSInt32); - break; - - case TK_Float: - rets.Push(TypeFloat64); - break; - - case TK_State: - rets.Push(TypeState); - break; - - case TK_Void: - break; - - case TK_Identifier: - rets.Push(NewPointer(RUNTIME_CLASS(DObject))); - // Todo: Object type - sc.ScriptError("Object type variables not implemented yet!"); - break; - - default: - sc.ScriptError("Invalid return type %s", sc.String); - return; - } - sc.MustGetToken(TK_Identifier); - ParseFunctionDef(sc, cls, sc.String, rets, VARF_Method); -} - //========================================================================== // // ParseUserVariable @@ -867,7 +661,7 @@ static bool ParsePropertyParams(FScanner &sc, FPropertyInfo *prop, AActor *defau { conv.i = -1; params.Push(conv); - x = new FxDamageValue(new FxIntCast(ParseExpression(sc, bag.Info))); + x = ParseExpression(sc, bag.Info); sc.MustGetStringName(")"); conv.exp = x; params.Push(conv); @@ -1063,7 +857,7 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag) } else { - sc.ScriptMessage("\"%s\" requires an actor of type \"%s\"\n", propname.GetChars(), (*prop->cls)->TypeName.GetChars()); + sc.ScriptMessage("'%s' requires an actor of type '%s'\n", propname.GetChars(), (*prop->cls)->TypeName.GetChars()); FScriptPosition::ErrorCounter++; } } @@ -1073,57 +867,54 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag) } else { - sc.ScriptError("\"%s\" is an unknown actor property\n", propname.GetChars()); + sc.ScriptError("'%s' is an unknown actor property\n", propname.GetChars()); } } //========================================================================== // -// ActorActionDef -// -// Parses an action function definition. A lot of this is essentially -// documentation in the declaration for when I have a proper language -// ready. +// Starts a new actor definition // //========================================================================== - -static void ParseActionDef (FScanner &sc, PClassActor *cls) +PClassActor *CreateNewActor(const FScriptPosition &sc, FName typeName, FName parentName) { - unsigned int error = 0; - FName funcname; - TArray rets; - - if (sc.LumpNum == -1 || Wads.GetLumpFile(sc.LumpNum) > 0) - { - sc.ScriptMessage ("Action functions can only be imported by internal class and actor definitions!"); - FScriptPosition::ErrorCounter++; - } + PClassActor *replacee = NULL; + PClassActor *ti = NULL; - sc.MustGetToken(TK_Native); - // check for a return value - do + PClassActor *parent = RUNTIME_CLASS(AActor); + + if (parentName != NAME_None) { - if (sc.CheckToken(TK_Bool)) + parent = PClass::FindActor(parentName); + + PClassActor *p = parent; + while (p != NULL) { - rets.Push(TypeBool); + if (p->TypeName == typeName) + { + sc.Message(MSG_ERROR, "'%s' inherits from a class with the same name", typeName.GetChars()); + break; + } + p = dyn_cast(p->ParentClass); } - else if (sc.CheckToken(TK_Int)) + + if (parent == NULL) { - rets.Push(TypeSInt32); + sc.Message(MSG_ERROR, "Parent type '%s' not found in %s", parentName.GetChars(), typeName.GetChars()); + parent = RUNTIME_CLASS(AActor); } - else if (sc.CheckToken(TK_State)) + else if (!parent->IsDescendantOf(RUNTIME_CLASS(AActor))) { - rets.Push(TypeState); - } - else if (sc.CheckToken(TK_Float)) - { - rets.Push(TypeFloat64); + sc.Message(MSG_ERROR, "Parent type '%s' is not an actor in %s", parentName.GetChars(), typeName.GetChars()); + parent = RUNTIME_CLASS(AActor); } } - while (sc.CheckToken(',')); - sc.MustGetToken(TK_Identifier); - funcname = sc.String; - ParseFunctionDef(sc, cls, funcname, rets, VARF_Method | VARF_Action); + ti = DecoDerivedClass(sc, parent, typeName); + ti->bDecorateClass = true; // we only set this for 'modern' DECORATE. The original stuff is so limited that it cannot do anything that may require flagging. + + ti->Replacee = ti->Replacement = NULL; + ti->DoomEdNum = -1; + return ti; } //========================================================================== @@ -1207,16 +998,20 @@ static PClassActor *ParseActorHeader(FScanner &sc, Baggage *bag) if (sc.CheckString("native")) { - native = true; + sc.ScriptMessage("Cannot define native classes in DECORATE"); + FScriptPosition::ErrorCounter++; } try { - PClassActor *info = CreateNewActor(sc, typeName, parentName, native); + PClassActor *info = CreateNewActor(sc, typeName, parentName); info->DoomEdNum = DoomEdNum > 0 ? DoomEdNum : -1; info->SourceLumpName = Wads.GetLumpFullPath(sc.LumpNum); - SetReplacement(sc, info, replaceName); + if (!info->SetReplacement(replaceName)) + { + sc.ScriptMessage("Replaced type '%s' not found for %s", replaceName.GetChars(), info->TypeName.GetChars()); + } ResetBaggage (bag, info == RUNTIME_CLASS(AActor) ? NULL : static_cast(info->ParentClass)); bag->Info = info; @@ -1243,16 +1038,13 @@ static void ParseActor(FScanner &sc) PClassActor *info = NULL; Baggage bag; + bag.fromDecorate = true; info = ParseActorHeader(sc, &bag); sc.MustGetToken('{'); while (sc.MustGetAnyToken(), sc.TokenType != '}') { switch (sc.TokenType) { - case TK_Action: - ParseActionDef (sc, info); - break; - case TK_Const: ParseConstant (sc, &info->Symbols, info); break; @@ -1261,10 +1053,6 @@ static void ParseActor(FScanner &sc) ParseEnum (sc, &info->Symbols, info); break; - case TK_Native: - ParseNativeFunction (sc, info); - break; - case TK_Var: ParseUserVariable (sc, &info->Symbols, info); break; @@ -1274,11 +1062,6 @@ static void ParseActor(FScanner &sc) break; case TK_States: - if (bag.StateSet) - { - sc.ScriptMessage("'%s' contains multiple state declarations", bag.Info->TypeName.GetChars()); - FScriptPosition::ErrorCounter++; - } ParseStates(sc, bag.Info, (AActor *)bag.Info->Defaults, bag); bag.StateSet = true; break; @@ -1293,7 +1076,18 @@ static void ParseActor(FScanner &sc) break; } } - FinishActor(sc, info, bag); + if (bag.DropItemSet) + { + bag.Info->SetDropItems(bag.DropItemList); + } + try + { + info->Finalize(bag.statedef); + } + catch (CRecoverableError &err) + { + sc.ScriptError("%s", err.GetMessage()); + } sc.SetCMode (false); } @@ -1432,3 +1226,14 @@ void ParseDecorate (FScanner &sc) } } } + +void ParseAllDecorate() +{ + int lastlump = 0, lump; + + while ((lump = Wads.FindLump("DECORATE", &lastlump)) != -1) + { + FScanner sc(lump); + ParseDecorate(sc); + } +} \ No newline at end of file diff --git a/src/thingdef/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp similarity index 86% rename from src/thingdef/thingdef_states.cpp rename to src/scripting/decorate/thingdef_states.cpp index 707de30451..671481de13 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/scripting/decorate/thingdef_states.cpp @@ -4,8 +4,8 @@ ** Actor definitions - the state parser ** **--------------------------------------------------------------------------- -** Copyright 2002-2007 Christoph Oelckers -** Copyright 2004-2007 Randy Heit +** Copyright 2002-2016 Christoph Oelckers +** Copyright 2004-2016 Randy Heit ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -38,14 +38,13 @@ ** */ -#include "actor.h" +#include "a_pickups.h" #include "info.h" #include "sc_man.h" #include "tarray.h" #include "templates.h" #include "cmdlib.h" #include "p_lnspec.h" -#include "a_action.h" #include "p_local.h" #include "v_palette.h" #include "doomerrors.h" @@ -54,11 +53,10 @@ #include "s_sound.h" #include "i_system.h" #include "colormatcher.h" -#include "thingdef_exp.h" +#include "codegeneration/codegen.h" #include "version.h" #include "templates.h" - -TDeletingArray StateTempCalls; +#include "vmbuilder.h" //========================================================================== //*** @@ -76,8 +74,8 @@ FxVMFunctionCall *DoActionSpecials(FScanner &sc, FState & state, Baggage &bag) if (special > 0 && min_args >= 0) { - FArgumentList *args = new FArgumentList; - args->Push(new FxConstant(special, sc)); + FArgumentList args; + args.Push(new FxConstant(special, sc)); i = 0; // Make this consistent with all other parameter parsing @@ -85,7 +83,7 @@ FxVMFunctionCall *DoActionSpecials(FScanner &sc, FState & state, Baggage &bag) { while (i < 5) { - args->Push(new FxIntCast(ParseExpression(sc, bag.Info))); + args.Push(new FxIntCast(ParseExpression(sc, bag.Info), true)); i++; if (!sc.CheckToken (',')) break; } @@ -100,7 +98,9 @@ FxVMFunctionCall *DoActionSpecials(FScanner &sc, FState & state, Baggage &bag) { sc.ScriptError ("Too many arguments to %s", specname.GetChars()); } - return new FxVMFunctionCall(FindGlobalActionFunction("A_CallSpecial"), args, sc); + auto f = dyn_cast(RUNTIME_CLASS(AActor)->Symbols.FindSymbol("A_CallSpecial", false)); + assert(f != nullptr); + return new FxVMFunctionCall(new FxSelf(sc), f, args, sc, false); } return NULL; } @@ -131,7 +131,7 @@ static FString ParseStateString(FScanner &sc) } //========================================================================== -//*** +// // ParseStates // parses a state block // @@ -141,14 +141,33 @@ void ParseStates(FScanner &sc, PClassActor * actor, AActor * defaults, Baggage & FString statestring; FState state; char lastsprite[5] = ""; - FStateTempCall *tcall = NULL; - FArgumentList *args = NULL; + FxExpression *ScriptCode; + FArgumentList *args = nullptr; + int flagdef = actor->DefaultStateUsage; + FScriptPosition scp; + + if (sc.CheckString("(")) + { + flagdef = 0; + do + { + sc.MustGetString(); + if (sc.Compare("Actor")) flagdef |= SUF_ACTOR; + else if (sc.Compare("Overlay")) flagdef |= SUF_OVERLAY; + else if (sc.Compare("Weapon")) flagdef |= SUF_WEAPON; + else if (sc.Compare("Item")) flagdef |= SUF_ITEM; + else sc.ScriptError("Unknown state block qualifier %s", sc.String); + } while (sc.CheckString(",")); + sc.MustGetStringName(")"); + } sc.MustGetStringName ("{"); sc.SetEscape(false); // disable escape sequences in the state parser while (!sc.CheckString ("}") && !sc.End) { + ScriptCode = nullptr; memset(&state,0,sizeof(state)); + state.UseFlags = (uint8_t)flagdef; statestring = ParseStateString(sc); if (!statestring.CompareNoCase("GOTO")) { @@ -219,15 +238,12 @@ do_stop: sc.ScriptError ("Sprite names must be exactly 4 characters\n"); } + scp = sc; state.sprite = GetSpriteIndex(statestring); state.Misc1 = state.Misc2 = 0; sc.MustGetString(); statestring = sc.String; - if (tcall == NULL) - { - tcall = new FStateTempCall; - } if (sc.CheckString("RANDOM")) { int min, max; @@ -257,24 +273,24 @@ do_stop: { if (sc.Compare("BRIGHT")) { - state.Fullbright = true; + state.StateFlags |= STF_FULLBRIGHT; continue; } if (sc.Compare("FAST")) { - state.Fast = true; + state.StateFlags |= STF_FAST; continue; } if (sc.Compare("SLOW")) { - state.Slow = true; + state.StateFlags |= STF_SLOW; continue; } if (sc.Compare("NODELAY")) { if (bag.statedef.GetStateLabelIndex(NAME_Spawn) == bag.statedef.GetStateCount()) { - state.NoDelay = true; + state.StateFlags |= STF_NODELAY; } else { @@ -310,40 +326,33 @@ do_stop: } if (sc.Compare("CANRAISE")) { - state.CanRaise = true; + state.StateFlags |= STF_CANRAISE; continue; } bool hasfinalret; - tcall->Code = ParseActions(sc, state, statestring, bag, hasfinalret); - if (!hasfinalret && tcall->Code != nullptr) + ScriptCode = ParseActions(sc, state, statestring, bag, hasfinalret); + if (!hasfinalret && ScriptCode != nullptr) { - static_cast(tcall->Code)->Add(new FxReturnStatement(nullptr, sc)); + static_cast(ScriptCode)->Add(new FxReturnStatement(nullptr, sc)); } goto endofstate; } sc.UnGet(); endofstate: - int count = bag.statedef.AddStates(&state, statestring); + if (ScriptCode != nullptr) + { + auto funcsym = CreateAnonymousFunction(actor, nullptr, state.UseFlags); + state.ActionFunc = FunctionBuildList.AddFunction(funcsym, ScriptCode, FStringf("%s.StateFunction.%d", actor->TypeName.GetChars(), bag.statedef.GetStateCount()), true, bag.statedef.GetStateCount(), int(statestring.Len()), sc.LumpNum); + } + int count = bag.statedef.AddStates(&state, statestring, scp); if (count < 0) { - sc.ScriptError ("Invalid frame character string '%s'", statestring.GetChars()); + sc.ScriptError("Invalid frame character string '%s'", statestring.GetChars()); count = -count; } - if (tcall->Code != NULL) - { - tcall->ActorClass = actor; - tcall->FirstState = bag.statedef.GetStateCount() - count; - tcall->NumStates = count; - StateTempCalls.Push(tcall); - tcall = NULL; - } } } - if (tcall != NULL) - { - delete tcall; - } if (args != NULL) { delete args; @@ -485,7 +494,7 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg const FScriptPosition pos(sc); - FxSequence *seq = NULL; + FxCompoundStatement *seq = NULL; bool lastwasret = false; sc.MustGetString(); @@ -547,7 +556,7 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg { if (seq == NULL) { - seq = new FxSequence(pos); + seq = new FxCompoundStatement(pos); } seq->Add(add); } @@ -580,13 +589,9 @@ FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, B PFunction *afd = dyn_cast(bag.Info->Symbols.FindSymbol(symname, true)); if (afd != NULL) { - FArgumentList *args = new FArgumentList; - ParseFunctionParameters(sc, bag.Info, *args, afd, statestring, &bag.statedef); - call = new FxVMFunctionCall(afd, args->Size() > 0 ? args : NULL, sc); - if (args->Size() == 0) - { - delete args; - } + FArgumentList args; + ParseFunctionParameters(sc, bag.Info, args, afd, statestring, &bag.statedef); + call = new FxVMFunctionCall(new FxSelf(sc), afd, args, sc, false); return call; } sc.ScriptError("Invalid parameter '%s'\n", sc.String); @@ -607,22 +612,22 @@ FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, B void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray &out_params, PFunction *afd, FString statestring, FStateDefinitions *statedef) { - const TArray ¶ms = afd->Variants[0].Implementation->Proto->ArgumentTypes; + const TArray ¶ms = afd->Variants[0].Proto->ArgumentTypes; const TArray ¶mflags = afd->Variants[0].ArgFlags; int numparams = (int)params.Size(); int pnum = 0; bool zeroparm; - if (afd->Flags & VARF_Method) + if (afd->Variants[0].Flags & VARF_Action) + { + numparams -= NAP; + pnum += NAP; + } + else if (afd->Variants[0].Flags & VARF_Method) { numparams--; pnum++; } - if (afd->Flags & VARF_Action) - { - numparams -= 2; - pnum += 2; - } assert(numparams >= 0); zeroparm = numparams == 0; if (numparams > 0 && !(paramflags[pnum] & VARF_Optional)) @@ -639,7 +644,7 @@ void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray 0) { FxExpression *x; - if (statedef != NULL && params[pnum] == TypeState && sc.CheckNumber()) + if (statedef != NULL && params[pnum] == TypeStateLabel && sc.CheckNumber()) { // Special case: State label as an offset if (sc.Number > 0 && statestring.Len() > 1) @@ -659,7 +664,8 @@ void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArrayValueType = TypeStateLabel; } } else @@ -716,7 +722,7 @@ FName CheckCastKludges(FName in) case NAME_Bool: return NAME___decorate_internal_bool__; case NAME_State: - return NAME___decorate_internal_state__; + return NAME_ResolveState; case NAME_Float: return NAME___decorate_internal_float__; default: diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp new file mode 100644 index 0000000000..5d2d251a9f --- /dev/null +++ b/src/scripting/thingdef.cpp @@ -0,0 +1,445 @@ +/* +** thingdef.cpp +** +** Actor definitions +** +**--------------------------------------------------------------------------- +** Copyright 2002-2008 Christoph Oelckers +** Copyright 2004-2008 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be +** covered by the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or (at +** your option) any later version. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include "gi.h" +#include "actor.h" +#include "info.h" +#include "sc_man.h" +#include "tarray.h" +#include "w_wad.h" +#include "templates.h" +#include "r_defs.h" +#include "a_pickups.h" +#include "s_sound.h" +#include "cmdlib.h" +#include "p_lnspec.h" +#include "decallib.h" +#include "m_random.h" +#include "i_system.h" +#include "m_argv.h" +#include "p_local.h" +#include "doomerrors.h" +#include "a_artifacts.h" +#include "a_weaponpiece.h" +#include "p_conversation.h" +#include "v_text.h" +#include "thingdef.h" +#include "codegeneration/codegen.h" +#include "a_sharedglobal.h" +#include "vmbuilder.h" +#include "stats.h" + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- +void InitThingdef(); + +// STATIC FUNCTION PROTOTYPES -------------------------------------------- +PClassActor *QuestItemClasses[31]; + + +static TMap StateSourceLines; +static FScriptPosition unknownstatesource("unknown file", 0); + +//========================================================================== +// +// Saves the state's source lines for error messages during postprocessing +// +//========================================================================== + +void SaveStateSourceLines(FState *firststate, TArray &positions) +{ + for (unsigned i = 0; i < positions.Size(); i++) + { + StateSourceLines[firststate + i] = positions[i]; + } +} + +FScriptPosition & GetStateSource(FState *state) +{ + auto check = StateSourceLines.CheckKey(state); + return check ? *check : unknownstatesource; +} + +//========================================================================== +// +// SetImplicitArgs +// +// Adds the parameters implied by the function flags. +// +//========================================================================== + +void SetImplicitArgs(TArray *args, TArray *argflags, TArray *argnames, PStruct *cls, DWORD funcflags, int useflags) +{ + // Must be called before adding any other arguments. + assert(args == nullptr || args->Size() == 0); + assert(argflags == nullptr || argflags->Size() == 0); + + if (funcflags & VARF_Method) + { + // implied self pointer + if (args != nullptr) args->Push(NewPointer(cls)); + if (argflags != nullptr) argflags->Push(VARF_Implicit | VARF_ReadOnly); + if (argnames != nullptr) argnames->Push(NAME_self); + } + if (funcflags & VARF_Action) + { + // implied caller and callingstate pointers + if (args != nullptr) + { + // Special treatment for weapons and CustomInventory flagged functions: 'self' is not the defining class but the actual user of the item, so this pointer must be of type 'Actor' + if (useflags & (SUF_WEAPON|SUF_ITEM)) + { + args->Insert(0, NewPointer(RUNTIME_CLASS(AActor))); // this must go in before the real pointer to the containing class. + } + else + { + args->Push(NewPointer(cls)); + } + args->Push(NewPointer(NewStruct("FStateParamInfo", nullptr))); + } + if (argflags != nullptr) + { + argflags->Push(VARF_Implicit | VARF_ReadOnly); + argflags->Push(VARF_Implicit | VARF_ReadOnly); + } + if (argnames != nullptr) + { + argnames->Push(NAME_invoker); + argnames->Push(NAME_stateinfo); + } + } +} + +//========================================================================== +// +// CreateAnonymousFunction +// +// Creates a function symbol for an anonymous function +// This contains actual info about the implied variables which is needed +// during code generation. +// +//========================================================================== + +PFunction *CreateAnonymousFunction(PClass *containingclass, PType *returntype, int flags) +{ + TArray rets(1); + TArray args; + TArray argflags; + TArray argnames; + + // Functions that only get flagged for actors do not need the additional two context parameters. + int fflags = (flags& (SUF_OVERLAY | SUF_WEAPON | SUF_ITEM)) ? VARF_Action | VARF_Method : VARF_Method; + + rets[0] = returntype != nullptr? returntype : TypeError; // Use TypeError as placeholder if we do not know the return type yet. + SetImplicitArgs(&args, &argflags, &argnames, containingclass, fflags, flags); + + PFunction *sym = new PFunction(containingclass, NAME_None); // anonymous functions do not have names. + sym->AddVariant(NewPrototype(rets, args), argflags, argnames, nullptr, fflags, flags); + return sym; +} + +//========================================================================== +// +// FindClassMemberFunction +// +// Looks for a name in a class's symbol table and outputs appropriate messages +// +//========================================================================== + +PFunction *FindClassMemberFunction(PStruct *selfcls, PStruct *funccls, FName name, FScriptPosition &sc, bool *error) +{ + // Skip ACS_NamedExecuteWithResult. Anything calling this should use the builtin instead. + if (name == NAME_ACS_NamedExecuteWithResult) return nullptr; + + PSymbolTable *symtable; + auto symbol = selfcls->Symbols.FindSymbolInTable(name, symtable); + auto funcsym = dyn_cast(symbol); + + if (symbol != nullptr) + { + if (funcsym == nullptr) + { + sc.Message(MSG_ERROR, "%s is not a member function of %s", name.GetChars(), selfcls->TypeName.GetChars()); + } + else if (funcsym->Variants[0].Flags & VARF_Private && symtable != &funccls->Symbols) + { + // private access is only allowed if the symbol table belongs to the class in which the current function is being defined. + sc.Message(MSG_ERROR, "%s is declared private and not accessible", symbol->SymbolName.GetChars()); + } + else if (funcsym->Variants[0].Flags & VARF_Deprecated) + { + sc.Message(MSG_WARNING, "Call to deprecated function %s", symbol->SymbolName.GetChars()); + } + } + // return nullptr if the name cannot be found in the symbol table so that the calling code can do other checks. + return funcsym; +} + +//========================================================================== +// +// CreateDamageFunction +// +// creates a damage function from the given expression +// +//========================================================================== + +void CreateDamageFunction(PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate, int lumpnum) +{ + if (id == nullptr) + { + defaults->DamageFunc = nullptr; + } + else + { + auto dmg = new FxReturnStatement(new FxIntCast(id, true), id->ScriptPosition); + auto funcsym = CreateAnonymousFunction(info, TypeSInt32, 0); + defaults->DamageFunc = FunctionBuildList.AddFunction(funcsym, dmg, FStringf("%s.DamageFunction", info->TypeName.GetChars()), fromDecorate, -1, 0, lumpnum); + } +} + +//========================================================================== +// +// CheckForUnsafeStates +// +// Performs a quick analysis to find potentially bad states. +// This is not perfect because it cannot track jumps by function. +// For such cases a runtime check in the relevant places is also present. +// +//========================================================================== +static void CheckForUnsafeStates(PClassActor *obj) +{ + static ENamedName weaponstates[] = { NAME_Ready, NAME_Deselect, NAME_Select, NAME_Fire, NAME_AltFire, NAME_Hold, NAME_AltHold, NAME_Flash, NAME_AltFlash, NAME_None }; + static ENamedName pickupstates[] = { NAME_Pickup, NAME_Drop, NAME_Use, NAME_None }; + TMap checked; + ENamedName *test; + + if (obj->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + { + if (obj->Size == RUNTIME_CLASS(AWeapon)->Size) return; // This class cannot have user variables. + test = weaponstates; + } + else if (obj->IsDescendantOf(RUNTIME_CLASS(ACustomInventory))) + { + if (obj->Size == RUNTIME_CLASS(ACustomInventory)->Size) return; // This class cannot have user variables. + test = pickupstates; + } + else return; // something else derived from AStateProvider. We do not know what this may be. + + for (; *test != NAME_None; test++) + { + FState *state = obj->FindState(*test); + while (state != nullptr && checked.CheckKey(state) == nullptr) // have we checked this state already. If yes, we can stop checking the current chain. + { + checked[state] = true; + if (state->ActionFunc && state->ActionFunc->Unsafe) + { + // If an unsafe function (i.e. one that accesses user variables) is being detected, print a warning once and remove the bogus function. We may not call it because that would inevitably crash. + auto owner = FState::StaticFindStateOwner(state); + GetStateSource(state).Message(MSG_ERROR, TEXTCOLOR_RED "Unsafe state call in state %s.%d which accesses user variables, reached by %s.%s.\n", + owner->TypeName.GetChars(), state - owner->OwnedStates, obj->TypeName.GetChars(), FName(*test).GetChars()); + } + state = state->NextState; + } + } +} + +//========================================================================== +// +// CheckStates +// +// Checks if states link to ones with proper restrictions +// Checks that all base labels refer a string with proper restrictions. +// For these cases a runtime check in the relevant places is also present. +// +//========================================================================== + +static void CheckLabel(PClassActor *obj, FStateLabel *slb, int useflag, FName statename, const char *descript) +{ + auto state = slb->State; + if (state != nullptr) + { + if (!(state->UseFlags & useflag)) + { + auto owner = FState::StaticFindStateOwner(state); + GetStateSource(state).Message(MSG_ERROR, TEXTCOLOR_RED "%s references state %s.%d as %s state, but this state is not flagged for use as %s.\n", + obj->TypeName.GetChars(), owner->TypeName.GetChars(), int(state - owner->OwnedStates), statename.GetChars(), descript); + } + } + if (slb->Children != nullptr) + { + for (int i = 0; i < slb->Children->NumLabels; i++) + { + auto state = slb->Children->Labels[i].State; + CheckLabel(obj, &slb->Children->Labels[i], useflag, statename, descript); + } + } +} + +static void CheckStateLabels(PClassActor *obj, ENamedName *test, int useflag, const char *descript) +{ + FStateLabels *labels = obj->StateList; + + for (; *test != NAME_None; test++) + { + auto label = labels->FindLabel(*test); + if (label != nullptr) + { + CheckLabel(obj, label, useflag, *test, descript); + } + } +} + + +static void CheckStates(PClassActor *obj) +{ + static ENamedName actorstates[] = { NAME_Spawn, NAME_See, NAME_Melee, NAME_Missile, NAME_Pain, NAME_Death, NAME_Wound, NAME_Raise, NAME_Yes, NAME_No, NAME_Greetings, NAME_None }; + static ENamedName weaponstates[] = { NAME_Ready, NAME_Deselect, NAME_Select, NAME_Fire, NAME_AltFire, NAME_Hold, NAME_AltHold, NAME_Flash, NAME_AltFlash, NAME_None }; + static ENamedName pickupstates[] = { NAME_Pickup, NAME_Drop, NAME_Use, NAME_None }; + TMap checked; + + CheckStateLabels(obj, actorstates, SUF_ACTOR, "actor sprites"); + + if (obj->IsDescendantOf(RUNTIME_CLASS(AWeapon))) + { + CheckStateLabels(obj, weaponstates, SUF_WEAPON, "weapon sprites"); + } + else if (obj->IsDescendantOf(RUNTIME_CLASS(ACustomInventory))) + { + CheckStateLabels(obj, pickupstates, SUF_ITEM, "CustomInventory state chain"); + } + for (int i = 0; i < obj->NumOwnedStates; i++) + { + auto state = obj->OwnedStates + i; + if (state->NextState && (state->UseFlags & state->NextState->UseFlags) != state->UseFlags) + { + GetStateSource(state).Message(MSG_ERROR, TEXTCOLOR_RED "State %s.%d links to a state with incompatible restrictions.\n", + obj->TypeName.GetChars(), int(state - obj->OwnedStates)); + } + } +} + +//========================================================================== +// +// LoadActors +// +// Called from FActor::StaticInit() +// +//========================================================================== +void ParseScripts(); +void ParseAllDecorate(); + +void LoadActors() +{ + cycle_t timer; + + timer.Reset(); timer.Clock(); + FScriptPosition::ResetErrorCounter(); + + InitThingdef(); + FScriptPosition::StrictErrors = true; + ParseScripts(); + + FScriptPosition::StrictErrors = false; + ParseAllDecorate(); + + FunctionBuildList.Build(); + + if (FScriptPosition::ErrorCounter > 0) + { + I_Error("%d errors while parsing DECORATE scripts", FScriptPosition::ErrorCounter); + } + FScriptPosition::ResetErrorCounter(); + + for (int i = PClassActor::AllActorClasses.Size() - 1; i >= 0; i--) + { + auto ti = PClassActor::AllActorClasses[i]; + if (ti->Size == TentativeClass) + { + if (ti->ObjectFlags & OF_Transient) + { + Printf(TEXTCOLOR_ORANGE "Class %s referenced but not defined\n", ti->TypeName.GetChars()); + FScriptPosition::WarnCounter++; + DObject::StaticPointerSubstitution(ti, nullptr); + PClassActor::AllActorClasses.Delete(i); + } + else + { + Printf(TEXTCOLOR_RED "Class %s referenced but not defined\n", ti->TypeName.GetChars()); + FScriptPosition::ErrorCounter++; + } + continue; + } + + if (GetDefaultByType(ti) == nullptr) + { + Printf(TEXTCOLOR_RED "No ActorInfo defined for class '%s'\n", ti->TypeName.GetChars()); + FScriptPosition::ErrorCounter++; + continue; + } + + + CheckStates(ti); + + if (ti->bDecorateClass && ti->IsDescendantOf(RUNTIME_CLASS(AStateProvider))) + { + // either a DECORATE based weapon or CustomInventory. + // These are subject to relaxed rules for user variables in states. + // Although there is a runtime check for bogus states, let's do a quick analysis if any of the known entry points + // hits an unsafe state. If we can find something here it can be handled wuth a compile error rather than a runtime error. + CheckForUnsafeStates(ti); + } + + } + if (FScriptPosition::ErrorCounter > 0) + { + I_Error("%d errors during actor postprocessing", FScriptPosition::ErrorCounter); + } + + timer.Unclock(); + if (!batchrun) Printf("script parsing took %.2f ms\n", timer.TimeMS()); + + // Since these are defined in DECORATE now the table has to be initialized here. + for (int i = 0; i < 31; i++) + { + char fmt[20]; + mysnprintf(fmt, countof(fmt), "QuestItem%d", i + 1); + QuestItemClasses[i] = PClass::FindActor(fmt); + } + StateSourceLines.Clear(); +} diff --git a/src/thingdef/thingdef.h b/src/scripting/thingdef.h similarity index 68% rename from src/thingdef/thingdef.h rename to src/scripting/thingdef.h index 565da573af..9d41b5265b 100644 --- a/src/thingdef/thingdef.h +++ b/src/scripting/thingdef.h @@ -23,9 +23,10 @@ struct FFlagDef const char *name; int structoffset; int fieldsize; + int varflags; }; -FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2); +FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2, bool strict = false); void HandleDeprecatedFlags(AActor *defaults, PClassActor *info, bool set, int index); bool CheckDeprecatedFlags(const AActor *actor, PClassActor *info, int index); const char *GetFlagName(unsigned int flagnum, int flagoffset); @@ -46,18 +47,6 @@ class FxExpression; struct FStateLabels; -enum EStateDefineFlags -{ - SDF_NEXT = 0, - SDF_STATE = 1, - SDF_STOP = 2, - SDF_WAIT = 3, - SDF_LABEL = 4, - SDF_INDEX = 5, - SDF_MASK = 7, - SDF_DEHACKED = 8, // Identify a state as having been modified by a dehacked lump -}; - struct FStateDefine { FName Label; @@ -73,6 +62,7 @@ class FStateDefinitions FState *laststatebeforelabel; intptr_t lastlabel; TArray StateArray; + TArray SourceLines; static FStateDefine *FindStateLabelInList(TArray &list, FName name, bool create); static FStateLabels *CreateStateLabelList(TArray &statelist); @@ -84,7 +74,6 @@ class FStateDefinitions FState *ResolveGotoLabel(AActor *actor, PClassActor *mytype, char *name); static void FixStatePointers(PClassActor *actor, TArray & list); void ResolveGotoLabels(PClassActor *actor, AActor *defaults, TArray & list); - public: FStateDefinitions() @@ -108,28 +97,13 @@ public: bool SetStop(); bool SetWait(); bool SetLoop(); - int AddStates(FState *state, const char *framechars); + int AddStates(FState *state, const char *framechars, const FScriptPosition &sc); int GetStateCount() const { return StateArray.Size(); } }; -//========================================================================== -// -// -// -//========================================================================== -struct FStateTempCall -{ - FStateTempCall() : ActorClass(NULL), Code(NULL), FirstState(0), NumStates(0) {} - - PClassActor *ActorClass; - class FxExpression *Code; - class PPrototype *Proto; - int FirstState; - int NumStates; -}; -extern TDeletingArray StateTempCalls; -extern TDeletingArray ActorDamageFuncs; +void SaveStateSourceLines(FState *firststate, TArray &positions); +FScriptPosition & GetStateSource(FState *state); //========================================================================== // @@ -146,6 +120,7 @@ struct Baggage PClassActor *Info; bool DropItemSet; bool StateSet; + bool fromDecorate; int CurrentState; int Lumpnum; FStateDefinitions statedef; @@ -160,6 +135,7 @@ inline void ResetBaggage (Baggage *bag, PClassActor *stateclass) bag->DropItemList = NULL; bag->DropItemSet = false; bag->CurrentState = 0; + bag->fromDecorate = true; bag->StateSet = false; bag->statedef.MakeStateDefines(stateclass); } @@ -170,25 +146,21 @@ inline void ResetBaggage (Baggage *bag, PClassActor *stateclass) // //========================================================================== -struct AFuncDesc -{ - const char *Name; - actionf_p Function; - VMNativeFunction **VMPointer; -}; - -AFuncDesc *FindFunction(const char * string); +AFuncDesc *FindFunction(PStruct *cls, const char * string); +FieldDesc *FindField(PStruct *cls, const char * string); +FxExpression *ParseExpression(FScanner &sc, PClassActor *cls, bool mustresolve = false); void ParseStates(FScanner &sc, PClassActor *actor, AActor *defaults, Baggage &bag); void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray &out_params, PFunction *afd, FString statestring, FStateDefinitions *statedef); FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &endswithret); class FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, Baggage &bag); FName CheckCastKludges(FName in); -void SetImplicitArgs(TArray *args, TArray *argflags, PClassActor *cls, DWORD funcflags); - -PFunction *FindGlobalActionFunction(const char *name); +void SetImplicitArgs(TArray *args, TArray *argflags, TArray *argnames, PStruct *cls, DWORD funcflags, int useflags); +PFunction *CreateAnonymousFunction(PClass *containingclass, PType *returntype, int flags); +PFunction *FindClassMemberFunction(PStruct *cls, PStruct *funccls, FName name, FScriptPosition &sc, bool *error); +void CreateDamageFunction(PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate, int lumpnum); //========================================================================== // @@ -196,11 +168,7 @@ PFunction *FindGlobalActionFunction(const char *name); // //========================================================================== -PClassActor *CreateNewActor(const FScriptPosition &sc, FName typeName, FName parentName, bool native); -void SetReplacement(FScanner &sc, PClassActor *info, FName replaceName); - void HandleActorFlag(FScanner &sc, Baggage &bag, const char *part1, const char *part2, int mod); -void FinishActor(const FScriptPosition &sc, PClassActor *info, Baggage &bag); FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool constant); @@ -231,23 +199,13 @@ enum EDefinitionType }; #if defined(_MSC_VER) -#pragma section(".areg$u",read) #pragma section(".greg$u",read) -#pragma section(".mreg$u",read) -#define MSVC_ASEG __declspec(allocate(".areg$u")) -#define GCC_ASEG #define MSVC_PSEG __declspec(allocate(".greg$u")) #define GCC_PSEG -#define MSVC_MSEG __declspec(allocate(".mreg$u")) -#define GCC_MSEG #else -#define MSVC_ASEG -#define GCC_ASEG __attribute__((section(SECTION_AREG))) __attribute__((used)) #define MSVC_PSEG #define GCC_PSEG __attribute__((section(SECTION_GREG))) __attribute__((used)) -#define MSVC_MSEG -#define GCC_MSEG __attribute__((section(SECTION_MREG))) __attribute__((used)) #endif @@ -264,7 +222,7 @@ typedef void (*PropHandler)(AActor *defaults, PClassActor *info, Baggage &bag, F enum ECategory { CAT_PROPERTY, // Inheritable property - CAT_INFO // non-inheritable info (spawn ID, Doomednum, game filter, conversation ID) + CAT_INFO // non-inheritable info (spawn ID, Doomednum, game filter, conversation ID, not usable in ZScript) }; struct FPropertyInfo @@ -321,39 +279,4 @@ int MatchString (const char *in, const char **strings); #define PROP_COLOR_PARM(var, no) \ int var = params[(no)+1].i== 0? params[(no)+2].i : V_GetColor(NULL, params[(no)+2].s); - -// Macros to handle action functions. These are here so that I don't have to -// change every single use in case the parameters change. -#define DECLARE_ACTION(name) extern VMNativeFunction *name##_VMPtr; - -// This distinction is here so that CALL_ACTION produces errors when trying to -// access a function that requires parameters. -#define DEFINE_ACTION_FUNCTION(cls, name) \ - static int AF_##name(VM_ARGS); \ - VMNativeFunction *name##_VMPtr; \ - static const AFuncDesc cls##_##name##_Hook = { #name, AF_##name, &name##_VMPtr }; \ - extern AFuncDesc const *const cls##_##name##_HookPtr; \ - MSVC_ASEG AFuncDesc const *const cls##_##name##_HookPtr GCC_ASEG = &cls##_##name##_Hook; \ - static int AF_##name(VM_ARGS) - -#define DEFINE_ACTION_FUNCTION_PARAMS(cls, name) DEFINE_ACTION_FUNCTION(cls, name) - -//#define DECLARE_PARAMINFO AActor *self, AActor *stateowner, FState *CallingState, int ParameterIndex, StateCallData *statecall -//#define PUSH_PARAMINFO self, stateowner, CallingState, ParameterIndex, statecall - -#define CALL_ACTION(name,self) { /*AF_##name(self, self, NULL, 0, NULL)*/ \ - VMValue params[3] = { self, self, VMValue(NULL, ATAG_STATEINFO) }; \ - stack->Call(name##_VMPtr, params, countof(params), NULL, 0, NULL); \ - } - - -#define ACTION_RETURN_STATE(v) do { FState *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_STATE); return 1; } return 0; } while(0) -#define ACTION_RETURN_FLOAT(v) do { double u = v; if (numret > 0) { assert(ret != nullptr); ret->SetFloat(u); return 1; } return 0; } while(0) -#define ACTION_RETURN_INT(v) do { int u = v; if (numret > 0) { assert(ret != NULL); ret->SetInt(u); return 1; } return 0; } while(0) -#define ACTION_RETURN_BOOL(v) ACTION_RETURN_INT(v) - -// Checks to see what called the current action function -#define ACTION_CALL_FROM_ACTOR() (stateinfo == nullptr || stateinfo->mStateType == STATE_Actor) -#define ACTION_CALL_FROM_PSPRITE() (self->player && stateinfo != nullptr && stateinfo->mStateType == STATE_Psprite) -#define ACTION_CALL_FROM_INVENTORY() (stateinfo != nullptr && stateinfo->mStateType == STATE_StateChain) #endif diff --git a/src/thingdef/thingdef_data.cpp b/src/scripting/thingdef_data.cpp similarity index 68% rename from src/thingdef/thingdef_data.cpp rename to src/scripting/thingdef_data.cpp index efdd649216..18962fbca0 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -43,9 +43,16 @@ #include "d_player.h" #include "p_effect.h" #include "autosegs.h" +#include "p_maputl.h" +#include "gi.h" +#include "p_terrain.h" +#include "gstrings.h" +#include "zstring.h" +#include "d_event.h" static TArray properties; static TArray AFTable; +static TArray FieldTable; //========================================================================== // @@ -54,10 +61,43 @@ static TArray AFTable; //========================================================================== // [RH] Keep GCC quiet by not using offsetof on Actor types. -#define DEFINE_FLAG(prefix, name, type, variable) { (unsigned int)prefix##_##name, #name, (int)(size_t)&((type*)1)->variable - 1, sizeof(((type *)0)->variable) } -#define DEFINE_FLAG2(symbol, name, type, variable) { (unsigned int)symbol, #name, (int)(size_t)&((type*)1)->variable - 1, sizeof(((type *)0)->variable) } -#define DEFINE_DEPRECATED_FLAG(name) { DEPF_##name, #name, -1, 0 } -#define DEFINE_DUMMY_FLAG(name) { DEPF_UNUSED, #name, -1, 0 } +#define DEFINE_FLAG(prefix, name, type, variable) { (unsigned int)prefix##_##name, #name, (int)(size_t)&((type*)1)->variable - 1, sizeof(((type *)0)->variable), VARF_Native } +#define DEFINE_PROTECTED_FLAG(prefix, name, type, variable) { (unsigned int)prefix##_##name, #name, (int)(size_t)&((type*)1)->variable - 1, sizeof(((type *)0)->variable), VARF_Native|VARF_ReadOnly|VARF_InternalAccess } +#define DEFINE_FLAG2(symbol, name, type, variable) { (unsigned int)symbol, #name, (int)(size_t)&((type*)1)->variable - 1, sizeof(((type *)0)->variable), VARF_Native } +#define DEFINE_FLAG2_DEPRECATED(symbol, name, type, variable) { (unsigned int)symbol, #name, (int)(size_t)&((type*)1)->variable - 1, sizeof(((type *)0)->variable), VARF_Native|VARF_Deprecated } +#define DEFINE_DEPRECATED_FLAG(name) { DEPF_##name, #name, -1, 0, true } +#define DEFINE_DUMMY_FLAG(name, deprec) { DEPF_UNUSED, #name, -1, 0, deprec? VARF_Deprecated:0 } + +// internal flags. These do not get exposed to actor definitions but scripts need to be able to access them as variables. +static FFlagDef InternalActorFlagDefs[]= +{ + DEFINE_FLAG(MF, INCHASE, AActor, flags), + DEFINE_FLAG(MF, UNMORPHED, AActor, flags), + DEFINE_FLAG(MF2, FLY, AActor, flags2), + DEFINE_FLAG(MF2, ONMOBJ, AActor, flags2), + DEFINE_FLAG(MF2, ARGSDEFINED, AActor, flags2), + DEFINE_FLAG(MF3, NOSIGHTCHECK, AActor, flags3), + DEFINE_FLAG(MF3, CRASHED, AActor, flags3), + DEFINE_FLAG(MF3, WARNBOT, AActor, flags3), + DEFINE_FLAG(MF3, HUNTPLAYERS, AActor, flags3), + DEFINE_FLAG(MF4, NOHATEPLAYERS, AActor, flags4), + DEFINE_FLAG(MF4, SCROLLMOVE, AActor, flags4), + DEFINE_FLAG(MF4, VFRICTION, AActor, flags4), + DEFINE_FLAG(MF4, BOSSSPAWNED, AActor, flags4), + DEFINE_FLAG(MF5, AVOIDINGDROPOFF, AActor, flags5), + DEFINE_FLAG(MF5, CHASEGOAL, AActor, flags5), + DEFINE_FLAG(MF5, INCONVERSATION, AActor, flags5), + DEFINE_FLAG(MF6, ARMED, AActor, flags6), + DEFINE_FLAG(MF6, FALLING, AActor, flags6), + DEFINE_FLAG(MF6, LINEDONE, AActor, flags6), + DEFINE_FLAG(MF6, SHATTERING, AActor, flags6), + DEFINE_FLAG(MF6, KILLED, AActor, flags6), + DEFINE_FLAG(MF6, BOSSCUBE, AActor, flags6), + DEFINE_FLAG(MF6, INTRYMOVE, AActor, flags6), + DEFINE_FLAG(MF7, HANDLENODELAY, AActor, flags7), + DEFINE_FLAG(MF7, FLYCHEAT, AActor, flags7), +}; + static FFlagDef ActorFlagDefs[]= { @@ -65,8 +105,8 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF, SPECIAL, APlayerPawn, flags), DEFINE_FLAG(MF, SOLID, AActor, flags), DEFINE_FLAG(MF, SHOOTABLE, AActor, flags), - DEFINE_FLAG(MF, NOSECTOR, AActor, flags), - DEFINE_FLAG(MF, NOBLOCKMAP, AActor, flags), + DEFINE_PROTECTED_FLAG(MF, NOSECTOR, AActor, flags), + DEFINE_PROTECTED_FLAG(MF, NOBLOCKMAP, AActor, flags), DEFINE_FLAG(MF, AMBUSH, AActor, flags), DEFINE_FLAG(MF, JUSTHIT, AActor, flags), DEFINE_FLAG(MF, JUSTATTACKED, AActor, flags), @@ -171,7 +211,6 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF4, SYNCHRONIZED, AActor, flags4), DEFINE_FLAG(MF4, NOTARGETSWITCH, AActor, flags4), DEFINE_FLAG(MF4, DONTHARMCLASS, AActor, flags4), - DEFINE_FLAG2(MF4_DONTHARMCLASS, DONTHURTSPECIES, AActor, flags4), // Deprecated name as an alias DEFINE_FLAG(MF4, SHIELDREFLECT, AActor, flags4), DEFINE_FLAG(MF4, DEFLECT, AActor, flags4), DEFINE_FLAG(MF4, ALLOWPARTICLES, AActor, flags4), @@ -261,6 +300,8 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF7, USEKILLSCRIPTS, AActor, flags7), DEFINE_FLAG(MF7, NOKILLSCRIPTS, AActor, flags7), DEFINE_FLAG(MF7, SPRITEANGLE, AActor, flags7), + DEFINE_FLAG(MF7, SMASHABLE, AActor, flags7), + DEFINE_FLAG(MF7, NOSHIELDREFLECT, AActor, flags7), // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), @@ -294,6 +335,11 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG2(BOUNCE_MBF, MBFBOUNCER, AActor, BounceFlags), DEFINE_FLAG2(BOUNCE_AutoOffFloorOnly, BOUNCEAUTOOFFFLOORONLY, AActor, BounceFlags), DEFINE_FLAG2(BOUNCE_UseBounceState, USEBOUNCESTATE, AActor, BounceFlags), +}; + +// These won't be accessible through bitfield variables +static FFlagDef MoreFlagDefs[] = +{ // Deprecated flags. Handling must be performed in HandleDeprecatedFlags DEFINE_DEPRECATED_FLAG(FIREDAMAGE), @@ -308,15 +354,16 @@ static FFlagDef ActorFlagDefs[]= DEFINE_DEPRECATED_FLAG(DOOMBOUNCE), // Deprecated flags with no more existing functionality. - DEFINE_DUMMY_FLAG(FASTER), // obsolete, replaced by 'Fast' state flag - DEFINE_DUMMY_FLAG(FASTMELEE), // obsolete, replaced by 'Fast' state flag + DEFINE_DUMMY_FLAG(FASTER, true), // obsolete, replaced by 'Fast' state flag + DEFINE_DUMMY_FLAG(FASTMELEE, true), // obsolete, replaced by 'Fast' state flag // Various Skulltag flags that are quite irrelevant to ZDoom - DEFINE_DUMMY_FLAG(NONETID), // netcode-based - DEFINE_DUMMY_FLAG(ALLOWCLIENTSPAWN), // netcode-based - DEFINE_DUMMY_FLAG(CLIENTSIDEONLY), // netcode-based - DEFINE_DUMMY_FLAG(SERVERSIDEONLY), // netcode-based - DEFINE_DUMMY_FLAG(EXPLODEONDEATH), // seems useless + DEFINE_DUMMY_FLAG(NONETID, false), // netcode-based + DEFINE_DUMMY_FLAG(ALLOWCLIENTSPAWN, false), // netcode-based + DEFINE_DUMMY_FLAG(CLIENTSIDEONLY, false), // netcode-based + DEFINE_DUMMY_FLAG(SERVERSIDEONLY, false), // netcode-based + DEFINE_DUMMY_FLAG(EXPLODEONDEATH, true), // seems useless + DEFINE_FLAG2_DEPRECATED(MF4_DONTHARMCLASS, DONTHURTSPECIES, AActor, flags4), // Deprecated name as an alias }; static FFlagDef InventoryFlagDefs[] = @@ -371,12 +418,14 @@ static FFlagDef WeaponFlagDefs[] = DEFINE_FLAG(WIF, NOAUTOAIM, AWeapon, WeaponFlags), DEFINE_FLAG(WIF, NODEATHDESELECT, AWeapon, WeaponFlags), DEFINE_FLAG(WIF, NODEATHINPUT, AWeapon, WeaponFlags), - - DEFINE_DUMMY_FLAG(NOLMS), DEFINE_FLAG(WIF, ALT_USES_BOTH, AWeapon, WeaponFlags), - DEFINE_DUMMY_FLAG(ALLOW_WITH_RESPAWN_INVUL), + + DEFINE_DUMMY_FLAG(NOLMS, false), + DEFINE_DUMMY_FLAG(ALLOW_WITH_RESPAWN_INVUL, false), }; + + static FFlagDef PlayerPawnFlagDefs[] = { // PlayerPawn flags @@ -391,13 +440,15 @@ static FFlagDef PowerSpeedFlagDefs[] = DEFINE_FLAG(PSF, NOTRAIL, APowerSpeed, SpeedFlags), }; -static const struct FFlagList { const PClass * const *Type; FFlagDef *Defs; int NumDefs; } FlagLists[] = +static const struct FFlagList { const PClass * const *Type; FFlagDef *Defs; int NumDefs; int Use; } FlagLists[] = { - { &RUNTIME_CLASS_CASTLESS(AActor), ActorFlagDefs, countof(ActorFlagDefs) }, - { &RUNTIME_CLASS_CASTLESS(AInventory), InventoryFlagDefs, countof(InventoryFlagDefs) }, - { &RUNTIME_CLASS_CASTLESS(AWeapon), WeaponFlagDefs, countof(WeaponFlagDefs) }, - { &RUNTIME_CLASS_CASTLESS(APlayerPawn), PlayerPawnFlagDefs, countof(PlayerPawnFlagDefs) }, - { &RUNTIME_CLASS_CASTLESS(APowerSpeed), PowerSpeedFlagDefs, countof(PowerSpeedFlagDefs) }, + { &RUNTIME_CLASS_CASTLESS(AActor), ActorFlagDefs, countof(ActorFlagDefs), 3 }, // -1 to account for the terminator + { &RUNTIME_CLASS_CASTLESS(AActor), MoreFlagDefs, countof(MoreFlagDefs), 1 }, + { &RUNTIME_CLASS_CASTLESS(AActor), InternalActorFlagDefs, countof(InternalActorFlagDefs), 2 }, + { &RUNTIME_CLASS_CASTLESS(AInventory), InventoryFlagDefs, countof(InventoryFlagDefs), 3 }, + { &RUNTIME_CLASS_CASTLESS(AWeapon), WeaponFlagDefs, countof(WeaponFlagDefs), 3 }, + { &RUNTIME_CLASS_CASTLESS(APlayerPawn), PlayerPawnFlagDefs, countof(PlayerPawnFlagDefs), 3 }, + { &RUNTIME_CLASS_CASTLESS(APowerSpeed), PowerSpeedFlagDefs, countof(PowerSpeedFlagDefs), 3 }, }; #define NUM_FLAG_LISTS (countof(FlagLists)) @@ -436,16 +487,16 @@ static FFlagDef *FindFlag (FFlagDef *flags, int numflags, const char *flag) // //========================================================================== -FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2) +FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2, bool strict) { FFlagDef *def; - size_t i; if (part2 == NULL) { // Search all lists - for (i = 0; i < NUM_FLAG_LISTS; ++i) + int max = strict ? 2 : NUM_FLAG_LISTS; + for (int i = 0; i < max; ++i) { - if (type->IsDescendantOf (*FlagLists[i].Type)) + if ((FlagLists[i].Use & 1) && type->IsDescendantOf (*FlagLists[i].Type)) { def = FindFlag (FlagLists[i].Defs, FlagLists[i].NumDefs, part1); if (def != NULL) @@ -457,7 +508,7 @@ FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2) } else { // Search just the named list - for (i = 0; i < NUM_FLAG_LISTS; ++i) + for (size_t i = 0; i < NUM_FLAG_LISTS; ++i) { if (stricmp ((*FlagLists[i].Type)->TypeName.GetChars(), part1) == 0) { @@ -530,14 +581,15 @@ FPropertyInfo *FindProperty(const char * string) // //========================================================================== -AFuncDesc *FindFunction(const char * string) +AFuncDesc *FindFunction(PStruct *cls, const char * string) { - int min = 0, max = AFTable.Size()-1; + int min = 0, max = AFTable.Size() - 1; while (min <= max) { int mid = (min + max) / 2; - int lexval = stricmp (string, AFTable[mid].Name); + int lexval = stricmp(cls->TypeName.GetChars(), AFTable[mid].ClassName + 1); + if (lexval == 0) lexval = stricmp(string, AFTable[mid].FuncName); if (lexval == 0) { return &AFTable[mid]; @@ -551,7 +603,38 @@ AFuncDesc *FindFunction(const char * string) max = mid - 1; } } - return NULL; + return nullptr; +} + +//========================================================================== +// +// Find a function by name using a binary search +// +//========================================================================== + +FieldDesc *FindField(PStruct *cls, const char * string) +{ + int min = 0, max = FieldTable.Size() - 1; + + while (min <= max) + { + int mid = (min + max) / 2; + int lexval = stricmp(cls->TypeName.GetChars(), FieldTable[mid].ClassName + 1); + if (lexval == 0) lexval = stricmp(string, FieldTable[mid].FieldName); + if (lexval == 0) + { + return &FieldTable[mid]; + } + else if (lexval > 0) + { + min = mid + 1; + } + else + { + max = mid - 1; + } + } + return nullptr; } @@ -561,9 +644,10 @@ AFuncDesc *FindFunction(const char * string) // //========================================================================== -PFunction *FindGlobalActionFunction(const char *name) +VMFunction *FindVMFunction(PClass *cls, const char *name) { - return dyn_cast(RUNTIME_CLASS(AActor)->Symbols.FindSymbol(name, false)); + auto f = dyn_cast(cls->Symbols.FindSymbol(name, true)); + return f == nullptr ? nullptr : f->Variants[0].Implementation; } @@ -585,7 +669,18 @@ static int propcmp(const void * a, const void * b) static int funccmp(const void * a, const void * b) { - return stricmp( ((AFuncDesc*)a)->Name, ((AFuncDesc*)b)->Name); + // +1 to get past the prefix letter of the native class name, which gets omitted by the FName for the class. + int res = stricmp(((AFuncDesc*)a)->ClassName + 1, ((AFuncDesc*)b)->ClassName + 1); + if (res == 0) res = stricmp(((AFuncDesc*)a)->FuncName, ((AFuncDesc*)b)->FuncName); + return res; +} + +static int fieldcmp(const void * a, const void * b) +{ + // +1 to get past the prefix letter of the native class name, which gets omitted by the FName for the class. + int res = stricmp(((FieldDesc*)a)->ClassName + 1, ((FieldDesc*)b)->ClassName + 1); + if (res == 0) res = stricmp(((FieldDesc*)a)->FieldName, ((FieldDesc*)b)->FieldName); + return res; } //========================================================================== @@ -596,6 +691,87 @@ static int funccmp(const void * a, const void * b) void InitThingdef() { + PType *TypeActor = NewPointer(RUNTIME_CLASS(AActor)); + + PStruct *sstruct = NewNativeStruct("Sector", nullptr); + auto sptr = NewPointer(sstruct); + sstruct->AddNativeField("soundtarget", TypeActor, myoffsetof(sector_t, SoundTarget)); + + // expose the global validcount variable. + PField *vcf = new PField("validcount", TypeSInt32, VARF_Native | VARF_Static, (intptr_t)&validcount); + GlobalSymbols.AddSymbol(vcf); + + // expose the global Multiplayer variable. + PField *multif = new PField("multiplayer", TypeBool, VARF_Native | VARF_ReadOnly | VARF_Static, (intptr_t)&multiplayer); + GlobalSymbols.AddSymbol(multif); + + // set up a variable for the global level data structure + PStruct *lstruct = NewNativeStruct("LevelLocals", nullptr); + PField *levelf = new PField("level", lstruct, VARF_Native | VARF_Static, (intptr_t)&level); + GlobalSymbols.AddSymbol(levelf); + + // set up a variable for the DEH data + PStruct *dstruct = NewNativeStruct("DehInfo", nullptr); + PField *dehf = new PField("deh", dstruct, VARF_Native | VARF_Static, (intptr_t)&deh); + + GlobalSymbols.AddSymbol(dehf); + + // set up a variable for the global players array. + PStruct *pstruct = NewNativeStruct("PlayerInfo", nullptr); + pstruct->Size = sizeof(player_t); + pstruct->Align = alignof(player_t); + PArray *parray = NewArray(pstruct, MAXPLAYERS); + PField *playerf = new PField("players", parray, VARF_Native | VARF_Static, (intptr_t)&players); + GlobalSymbols.AddSymbol(playerf); + + // set up the lines array in the sector struct. This is a bit messy because the type system is not prepared to handle a pointer to an array of pointers to a native struct even remotely well... + // As a result, the size has to be set to something large and arbritrary because it can change between maps. This will need some serious improvement when things get cleaned up. + pstruct = NewNativeStruct("Sector", nullptr); + pstruct->AddNativeField("lines", NewPointer(NewArray(NewPointer(NewNativeStruct("line", nullptr), false), 0x40000), false), myoffsetof(sector_t, lines), VARF_Native); + + parray = NewArray(TypeBool, MAXPLAYERS); + playerf = new PField("playeringame", parray, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&playeringame); + GlobalSymbols.AddSymbol(playerf); + + playerf = new PField("gameaction", TypeUInt8, VARF_Native | VARF_Static, (intptr_t)&gameaction); + GlobalSymbols.AddSymbol(playerf); + + playerf = new PField("consoleplayer", TypeSInt32, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&consoleplayer); + GlobalSymbols.AddSymbol(playerf); + + // Argh. It sucks when bad hacks need to be supported. WP_NOCHANGE is just a bogus pointer but it used everywhere as a special flag. + // It cannot be defined as constant because constants can either be numbers or strings but nothing else, so the only 'solution' + // is to create a static variable from it and reference that in the script. Yuck!!! + static AWeapon *wpnochg = WP_NOCHANGE; + playerf = new PField("WP_NOCHANGE", NewPointer(RUNTIME_CLASS(AWeapon), false), VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&wpnochg); + GlobalSymbols.AddSymbol(playerf); + + // this needs to be done manually until it can be given a proper type. + RUNTIME_CLASS(AActor)->AddNativeField("DecalGenerator", NewPointer(TypeVoid), myoffsetof(AActor, DecalGenerator)); + + // synthesize a symbol for each flag from the flag name tables to avoid redundant declaration of them. + for (auto &fl : FlagLists) + { + if (fl.Use & 2) + { + for(int i=0;i 0) // skip the deprecated entries in this list + { + const_cast(*fl.Type)->AddNativeField(FStringf("b%s", fl.Defs[i].name), (fl.Defs[i].fieldsize == 4 ? TypeSInt32 : TypeSInt16), fl.Defs[i].structoffset, fl.Defs[i].varflags, fl.Defs[i].flagbit); + } + } + } + } + + FAutoSegIterator probe(CRegHead, CRegTail); + + while (*++probe != NULL) + { + if (((ClassReg *)*probe)->InitNatives) + ((ClassReg *)*probe)->InitNatives(); + } + // Sort the flag lists for (size_t i = 0; i < NUM_FLAG_LISTS; ++i) { @@ -625,53 +801,56 @@ void InitThingdef() { AFuncDesc *afunc = (AFuncDesc *)*probe; assert(afunc->VMPointer != NULL); - *(afunc->VMPointer) = new VMNativeFunction(afunc->Function, afunc->Name); + *(afunc->VMPointer) = new VMNativeFunction(afunc->Function, afunc->FuncName); + (*(afunc->VMPointer))->PrintableName.Format("%s.%s [Native]", afunc->ClassName+1, afunc->FuncName); AFTable.Push(*afunc); } AFTable.ShrinkToFit(); qsort(&AFTable[0], AFTable.Size(), sizeof(AFTable[0]), funccmp); } - // Define some member variables we feel like exposing to the user - PSymbolTable &symt = RUNTIME_CLASS(AActor)->Symbols; - PType *array5 = NewArray(TypeSInt32, 5); - symt.AddSymbol(new PField(NAME_Alpha, TypeFloat64, VARF_Native, myoffsetof(AActor, Alpha))); - symt.AddSymbol(new PField(NAME_Angle, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Yaw))); - symt.AddSymbol(new PField(NAME_Args, array5, VARF_Native, myoffsetof(AActor, args))); - symt.AddSymbol(new PField(NAME_CeilingZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, ceilingz))); - symt.AddSymbol(new PField(NAME_FloorZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, floorz))); - symt.AddSymbol(new PField(NAME_Health, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, health))); - symt.AddSymbol(new PField(NAME_Mass, TypeSInt32, VARF_Native, myoffsetof(AActor, Mass))); - symt.AddSymbol(new PField(NAME_Pitch, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Pitch))); - symt.AddSymbol(new PField(NAME_Roll, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Roll))); - symt.AddSymbol(new PField(NAME_Special, TypeSInt32, VARF_Native, myoffsetof(AActor, special))); - symt.AddSymbol(new PField(NAME_TID, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, tid))); - symt.AddSymbol(new PField(NAME_TIDtoHate, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, TIDtoHate))); - symt.AddSymbol(new PField(NAME_WaterLevel, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, waterlevel))); - symt.AddSymbol(new PField(NAME_X, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.X))); // must remain read-only! - symt.AddSymbol(new PField(NAME_Y, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.Y))); // must remain read-only! - symt.AddSymbol(new PField(NAME_Z, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.Z))); // must remain read-only! - symt.AddSymbol(new PField(NAME_VelX, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.X))); - symt.AddSymbol(new PField(NAME_VelY, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Y))); - symt.AddSymbol(new PField(NAME_VelZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Z))); - symt.AddSymbol(new PField(NAME_MomX, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.X))); - symt.AddSymbol(new PField(NAME_MomY, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Y))); - symt.AddSymbol(new PField(NAME_MomZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Z))); - symt.AddSymbol(new PField(NAME_ScaleX, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.X))); - symt.AddSymbol(new PField(NAME_ScaleY, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.Y))); - symt.AddSymbol(new PField(NAME_Score, TypeSInt32, VARF_Native, myoffsetof(AActor, Score))); - symt.AddSymbol(new PField(NAME_Accuracy, TypeSInt32, VARF_Native, myoffsetof(AActor, accuracy))); - symt.AddSymbol(new PField(NAME_Stamina, TypeSInt32, VARF_Native, myoffsetof(AActor, stamina))); - symt.AddSymbol(new PField(NAME_Height, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Height))); - symt.AddSymbol(new PField(NAME_Radius, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, radius))); - symt.AddSymbol(new PField(NAME_ReactionTime, TypeSInt32, VARF_Native, myoffsetof(AActor, reactiontime))); - symt.AddSymbol(new PField(NAME_MeleeRange, TypeFloat64, VARF_Native, myoffsetof(AActor, meleerange))); - symt.AddSymbol(new PField(NAME_Speed, TypeFloat64, VARF_Native, myoffsetof(AActor, Speed))); - symt.AddSymbol(new PField(NAME_Threshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, threshold))); - symt.AddSymbol(new PField(NAME_DefThreshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, DefThreshold))); - symt.AddSymbol(new PField(NAME_Damage, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, DamageVal))); - symt.AddSymbol(new PField(NAME_VisibleStartAngle, TypeFloat64, VARF_Native, myoffsetof(AActor, VisibleStartAngle))); - symt.AddSymbol(new PField(NAME_VisibleStartPitch, TypeFloat64, VARF_Native, myoffsetof(AActor, VisibleStartPitch))); - symt.AddSymbol(new PField(NAME_VisibleEndAngle, TypeFloat64, VARF_Native, myoffsetof(AActor, VisibleEndAngle))); - symt.AddSymbol(new PField(NAME_VisibleEndPitch, TypeFloat64, VARF_Native, myoffsetof(AActor, VisibleEndPitch))); + FieldTable.Clear(); + if (FieldTable.Size() == 0) + { + FAutoSegIterator probe(FRegHead, FRegTail); + + while (*++probe != NULL) + { + FieldDesc *afield = (FieldDesc *)*probe; + FieldTable.Push(*afield); + } + FieldTable.ShrinkToFit(); + qsort(&FieldTable[0], FieldTable.Size(), sizeof(FieldTable[0]), fieldcmp); + } + } + +DEFINE_ACTION_FUNCTION(DObject, GameType) +{ + PARAM_PROLOGUE; + ACTION_RETURN_INT(gameinfo.gametype); +} + +DEFINE_ACTION_FUNCTION(DObject, BAM) +{ + PARAM_PROLOGUE; + PARAM_FLOAT(ang); + ACTION_RETURN_INT(DAngle(ang).BAMs()); +} + +DEFINE_ACTION_FUNCTION(FStringTable, Localize) +{ + PARAM_PROLOGUE; + PARAM_STRING(label); + ACTION_RETURN_STRING(GStrings(label)); +} + +DEFINE_ACTION_FUNCTION(FString, Replace) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + PARAM_STRING(s1); + PARAM_STRING(s2); + self->Substitute(*s1, *s2); + return 0; +} + diff --git a/src/thingdef/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp similarity index 96% rename from src/thingdef/thingdef_properties.cpp rename to src/scripting/thingdef_properties.cpp index 6321ebfe99..9eb050a83e 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -39,17 +39,17 @@ */ #include "gi.h" -#include "actor.h" +#include "d_player.h" #include "info.h" #include "tarray.h" #include "w_wad.h" #include "templates.h" #include "r_defs.h" #include "a_pickups.h" +#include "a_armor.h" #include "s_sound.h" #include "cmdlib.h" #include "p_lnspec.h" -#include "a_action.h" #include "decallib.h" #include "m_random.h" #include "i_system.h" @@ -57,8 +57,7 @@ #include "p_effect.h" #include "v_palette.h" #include "doomerrors.h" -#include "a_hexenglobal.h" -#include "a_weaponpiece.h" +#include "a_artifacts.h" #include "p_conversation.h" #include "v_text.h" #include "thingdef.h" @@ -69,14 +68,18 @@ #include "teaminfo.h" #include "v_video.h" #include "r_data/colormaps.h" - +#include "a_weaponpiece.h" +#include "vmbuilder.h" +#include "a_ammo.h" +#include "a_health.h" +#include "a_keys.h" //========================================================================== // // Gets a class pointer and performs an error check for correct type // //========================================================================== -static PClassActor *FindClassTentative(const char *name, PClass *ancestor) +static PClassActor *FindClassTentative(const char *name, PClass *ancestor, bool optional = false) { // "" and "none" mean 'no class' if (name == NULL || *name == 0 || !stricmp(name, "none")) @@ -90,23 +93,27 @@ static PClassActor *FindClassTentative(const char *name, PClass *ancestor) { I_Error("%s does not inherit from %s\n", name, ancestor->TypeName.GetChars()); } + if (cls->Size == TentativeClass && optional) + { + cls->ObjectFlags |= OF_Transient; // since this flag has no meaning in class types, let's use it for marking the type optional. + } return static_cast(cls); } -static AAmmo::MetaClass *FindClassTentativeAmmo(const char *name) +static AAmmo::MetaClass *FindClassTentativeAmmo(const char *name, bool optional = false) { - return static_cast(FindClassTentative(name, RUNTIME_CLASS(AAmmo))); + return static_cast(FindClassTentative(name, RUNTIME_CLASS(AAmmo), optional)); } -static AWeapon::MetaClass *FindClassTentativeWeapon(const char *name) +static AWeapon::MetaClass *FindClassTentativeWeapon(const char *name, bool optional = false) { - return static_cast(FindClassTentative(name, RUNTIME_CLASS(AWeapon))); + return static_cast(FindClassTentative(name, RUNTIME_CLASS(AWeapon), optional)); } -static APowerup::MetaClass *FindClassTentativePowerup(const char *name) +static APowerup::MetaClass *FindClassTentativePowerup(const char *name, bool optional = false) { - return static_cast(FindClassTentative(name, RUNTIME_CLASS(APowerup))); + return static_cast(FindClassTentative(name, RUNTIME_CLASS(APowerup), optional)); } -static APlayerPawn::MetaClass *FindClassTentativePlayerPawn(const char *name) +static APlayerPawn::MetaClass *FindClassTentativePlayerPawn(const char *name, bool optional = false) { - return static_cast(FindClassTentative(name, RUNTIME_CLASS(APlayerPawn))); + return static_cast(FindClassTentative(name, RUNTIME_CLASS(APlayerPawn), optional)); } //========================================================================== @@ -514,10 +521,11 @@ DEFINE_INFO_PROPERTY(conversationid, IiI, Actor) //========================================================================== DEFINE_PROPERTY(skip_super, 0, Actor) { - if (info->IsDescendantOf(RUNTIME_CLASS(AInventory))) + auto actorclass = RUNTIME_CLASS(AActor); + if (info->Size != actorclass->Size) { - bag.ScriptPosition.Message(MSG_WARNING, - "'skip_super' in definition of inventory item '%s' ignored.", info->TypeName.GetChars() ); + bag.ScriptPosition.Message(MSG_OPTERROR, + "'skip_super' is only allowed in subclasses of AActor with no additional fields and will be ignored.", info->TypeName.GetChars()); return; } if (bag.StateSet) @@ -531,6 +539,15 @@ DEFINE_PROPERTY(skip_super, 0, Actor) ResetBaggage (&bag, RUNTIME_CLASS(AActor)); } +//========================================================================== +// for internal use only - please do not document! +//========================================================================== +DEFINE_PROPERTY(defaultstateusage, I, Actor) +{ + PROP_INT_PARM(use, 0); + static_cast(bag.Info)->DefaultStateUsage = use; + +} //========================================================================== // //========================================================================== @@ -645,18 +662,18 @@ DEFINE_PROPERTY(damage, X, Actor) // compatibility reasons, expressions must be enclosed within // parentheses. - // Store this expression here for now. It will be converted to a function - // later once all actors have been processed. defaults->DamageVal = dmgval; + // Only DECORATE can get here with a valid expression. + CreateDamageFunction(bag.Info, defaults, id, true, bag.Lumpnum); +} - if (id == nullptr) - { - defaults->DamageFunc = nullptr; - } - else - { - defaults->DamageFunc = (VMFunction *)(uintptr_t)(ActorDamageFuncs.Push(id) + 1); - } +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(damagemultiply, F, Actor) +{ + PROP_FLOAT_PARM(dmgm, 0); + defaults->DamageMultiply = dmgm; } //========================================================================== @@ -2288,8 +2305,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory) *pBlendColor = MakeSpecialColormap(65535); return; } - - color = V_GetColor(NULL, name); + color = V_GetColor(NULL, name, &bag.ScriptPosition); } if (PROP_PARM_COUNT > 2) { @@ -2429,11 +2445,18 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, type, S, PowerupGiver) // Yuck! What was I thinking when I decided to prepend "Power" to the name? // Now it's too late to change it... PClassActor *cls = PClass::FindActor(str); - if (cls == NULL || !cls->IsDescendantOf(RUNTIME_CLASS(APowerup))) + if (cls == nullptr || !cls->IsDescendantOf(RUNTIME_CLASS(APowerup))) { - FString st; - st.Format("%s%s", strnicmp(str, "power", 5)? "Power" : "", str); - cls = FindClassTentativePowerup(st); + if (bag.fromDecorate) + { + FString st; + st.Format("%s%s", strnicmp(str, "power", 5) ? "Power" : "", str); + cls = FindClassTentativePowerup(st); + } + else + { + I_Error("Unknown powerup type %s", str); + } } defaults->PowerupType = cls; @@ -2484,7 +2507,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, face, S, PlayerPawn) ); if (!valid) { - bag.ScriptPosition.Message(MSG_WARNING, + bag.ScriptPosition.Message(MSG_OPTERROR, "Invalid face '%s' for '%s';\nSTF replacement codes must be 3 alphanumeric characters.\n", tmp.GetChars(), info->TypeName.GetChars ()); } @@ -2551,13 +2574,13 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorset, ISIIIiiiiiiiiiiiiiiiiiiiiiiii, Pl } if (count != 0) { - bag.ScriptPosition.Message(MSG_WARNING, "Extra ranges require 4 parameters each.\n"); + bag.ScriptPosition.Message(MSG_OPTERROR, "Extra ranges require 4 parameters each.\n"); } } if (setnum < 0) { - bag.ScriptPosition.Message(MSG_WARNING, "Color set number must not be negative.\n"); + bag.ScriptPosition.Message(MSG_OPTERROR, "Color set number must not be negative.\n"); } else { @@ -2584,7 +2607,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorsetfile, ISSI, PlayerPawn) if (setnum < 0) { - bag.ScriptPosition.Message(MSG_WARNING, "Color set number must not be negative.\n"); + bag.ScriptPosition.Message(MSG_OPTERROR, "Color set number must not be negative.\n"); } else if (color.Lump >= 0) { @@ -2602,7 +2625,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, clearcolorset, I, PlayerPawn) if (setnum < 0) { - bag.ScriptPosition.Message(MSG_WARNING, "Color set number must not be negative.\n"); + bag.ScriptPosition.Message(MSG_OPTERROR, "Color set number must not be negative.\n"); } else { @@ -2777,7 +2800,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, morphweapon, S, PlayerPawn) DEFINE_CLASS_PROPERTY_PREFIX(player, flechettetype, S, PlayerPawn) { PROP_STRING_PARM(str, 0); - defaults->FlechetteType = FindClassTentative(str, RUNTIME_CLASS(AArtiPoisonBag)); + defaults->FlechetteType = FindClassTentative(str, PClass::FindActor("ArtiPoisonBag")); } //========================================================================== @@ -2966,21 +2989,21 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, viewbob, F, PlayerPawn) } //========================================================================== -// +// (non-fatal with non-existent types only in DECORATE) //========================================================================== DEFINE_CLASS_PROPERTY(playerclass, S, MorphProjectile) { PROP_STRING_PARM(str, 0); - defaults->PlayerClass = FName(str); + defaults->PlayerClass = FindClassTentativePlayerPawn(str, bag.fromDecorate); } //========================================================================== -// +// (non-fatal with non-existent types only in DECORATE) //========================================================================== DEFINE_CLASS_PROPERTY(monsterclass, S, MorphProjectile) { PROP_STRING_PARM(str, 0); - defaults->MonsterClass = FName(str); + defaults->MonsterClass = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); } //========================================================================== @@ -3002,12 +3025,12 @@ DEFINE_CLASS_PROPERTY(morphstyle, M, MorphProjectile) } //========================================================================== -// +// (non-fatal with non-existent types only in DECORATE) //========================================================================== DEFINE_CLASS_PROPERTY(morphflash, S, MorphProjectile) { PROP_STRING_PARM(str, 0); - defaults->MorphFlash = FName(str); + defaults->MorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); } //========================================================================== @@ -3016,16 +3039,16 @@ DEFINE_CLASS_PROPERTY(morphflash, S, MorphProjectile) DEFINE_CLASS_PROPERTY(unmorphflash, S, MorphProjectile) { PROP_STRING_PARM(str, 0); - defaults->UnMorphFlash = FName(str); + defaults->UnMorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); } //========================================================================== -// +// (non-fatal with non-existent types only in DECORATE) //========================================================================== DEFINE_CLASS_PROPERTY(playerclass, S, PowerMorph) { PROP_STRING_PARM(str, 0); - defaults->PlayerClass = FName(str); + defaults->PlayerClass = FindClassTentativePlayerPawn(str, bag.fromDecorate); } //========================================================================== @@ -3038,21 +3061,21 @@ DEFINE_CLASS_PROPERTY(morphstyle, M, PowerMorph) } //========================================================================== -// +// (non-fatal with non-existent types only in DECORATE) //========================================================================== DEFINE_CLASS_PROPERTY(morphflash, S, PowerMorph) { PROP_STRING_PARM(str, 0); - defaults->MorphFlash = FName(str); + defaults->MorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); } //========================================================================== -// +// (non-fatal with non-existent types only in DECORATE) //========================================================================== DEFINE_CLASS_PROPERTY(unmorphflash, S, PowerMorph) { PROP_STRING_PARM(str, 0); - defaults->UnMorphFlash = FName(str); + defaults->UnMorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate); } diff --git a/src/zscript/vm.h b/src/scripting/vm/vm.h similarity index 56% rename from src/zscript/vm.h rename to src/scripting/vm/vm.h index a000e9533f..1869c410b3 100644 --- a/src/zscript/vm.h +++ b/src/scripting/vm/vm.h @@ -2,7 +2,10 @@ #define VM_H #include "zstring.h" -#include "dobject.h" +#include "autosegs.h" +#include "vectors.h" +#include "cmdlib.h" +#include "doomerrors.h" #define MAX_RETURNS 8 // Maximum number of results a function called by script code can return #define MAX_TRY_DEPTH 8 // Maximum number of nested TRYs in a single function @@ -16,7 +19,7 @@ typedef unsigned int VM_UWORD; typedef signed int VM_SWORD; typedef VM_UBYTE VM_ATAG; -#define VM_EPSILON (1/1024.0) +#define VM_EPSILON (1/65536.0) union VMOP { @@ -110,11 +113,29 @@ enum { CAST_I2F, CAST_I2S, + CAST_U2F, + CAST_U2S, CAST_F2I, + CAST_F2U, CAST_F2S, CAST_P2S, CAST_S2I, CAST_S2F, + CAST_S2N, + CAST_N2S, + CAST_S2Co, + CAST_S2So, + CAST_Co2S, + CAST_So2S, + CAST_V22S, + CAST_V32S, + CAST_SID2S, + CAST_TID2S, + + CASTB_I, + CASTB_F, + CASTB_A, + CASTB_S }; // Register types for VMParam @@ -127,10 +148,12 @@ enum REGT_TYPE = 3, REGT_KONST = 4, - REGT_MULTIREG = 8, // (e.g. a vector) + REGT_MULTIREG2 = 8, + REGT_MULTIREG3 = 16, // (e.g. a vector) + REGT_MULTIREG = 24, REGT_ADDROF = 32, // used with PARAM: pass address of this register - REGT_NIL = 255 // parameter was omitted + REGT_NIL = 128 // parameter was omitted }; #define RET_FINAL (0x80) // Used with RET and RETI in the destination slot: this is the final return value @@ -143,17 +166,18 @@ enum ATAG_OBJECT, // pointer to an object; will be followed by GC // The following are all for documentation during debugging and are - // functionally no different than ATAG_GENERIC. + // functionally no different than ATAG_GENERIC (meaning they are useless because they trigger asserts all over the place.) + /* ATAG_FRAMEPOINTER, // pointer to extra stack frame space for this function ATAG_DREGISTER, // pointer to a data register ATAG_FREGISTER, // pointer to a float register ATAG_SREGISTER, // pointer to a string register ATAG_AREGISTER, // pointer to an address register + */ - ATAG_STATE, // pointer to FState - ATAG_STATEINFO, // FState plus some info. ATAG_RNG, // pointer to FRandom + ATAG_STATE = ATAG_GENERIC, // pointer to FState (cannot have its own type because there's no means to track inside the VM.) }; enum EVMAbortException @@ -166,18 +190,12 @@ enum EVMAbortException X_BAD_SELF, }; -class VMFunction : public DObject +class CVMAbortException : public CDoomError { - DECLARE_ABSTRACT_CLASS(VMFunction, DObject); - HAS_OBJECT_POINTERS; public: - bool Native; - FName Name; - - class PPrototype *Proto; - - VMFunction() : Native(false), Name(NAME_None), Proto(NULL) {} - VMFunction(FName name) : Native(false), Name(name), Proto(NULL) {} + static FString stacktrace; + CVMAbortException(EVMAbortException reason, const char *moreinfo, va_list ap); + void MaybePrintMessage(); }; enum EVMOpMode @@ -297,11 +315,30 @@ struct VMReturn } void SetVector(const double val[3]) { - //assert(RegType == REGT_FLOAT); + assert(RegType == (REGT_FLOAT|REGT_MULTIREG3)); ((double *)Location)[0] = val[0]; ((double *)Location)[1] = val[1]; ((double *)Location)[2] = val[2]; } + void SetVector(const DVector3 &val) + { + assert(RegType == (REGT_FLOAT | REGT_MULTIREG3)); + ((double *)Location)[0] = val[0]; + ((double *)Location)[1] = val[1]; + ((double *)Location)[2] = val[2]; + } + void SetVector2(const double val[2]) + { + assert(RegType == (REGT_FLOAT|REGT_MULTIREG2)); + ((double *)Location)[0] = val[0]; + ((double *)Location)[1] = val[1]; + } + void SetVector2(const DVector2 &val) + { + assert(RegType == (REGT_FLOAT | REGT_MULTIREG2)); + ((double *)Location)[0] = val[0]; + ((double *)Location)[1] = val[1]; + } void SetString(const FString &val) { assert(RegType == REGT_STRING); @@ -635,6 +672,25 @@ do_double: if (inexact) } }; +class VMFunction : public DObject +{ + DECLARE_ABSTRACT_CLASS(VMFunction, DObject); + HAS_OBJECT_POINTERS; +public: + bool Native; + bool Final = false; // cannot be overridden + bool Unsafe = false; // Contains references to class fields that are unsafe for psp and item state calls. + BYTE ImplicitArgs = 0; // either 0 for static, 1 for method or 3 for action + unsigned VirtualIndex = ~0u; + FName Name; + TArray DefaultArgs; + FString PrintableName; // so that the VM can print meaningful info if something in this function goes wrong. + + class PPrototype *Proto; + + VMFunction(FName name = NAME_None) : Native(false), ImplicitArgs(0), Name(name), Proto(NULL) {} +}; + // VM frame layout: // VMFrame header // parameter stack - 16 byte boundary, 16 bytes each @@ -753,6 +809,12 @@ union FVoidObj void *v; }; +struct FStatementInfo +{ + uint16_t InstructionIndex; + uint16_t LineNumber; +}; + class VMScriptFunction : public VMFunction { DECLARE_CLASS(VMScriptFunction, VMFunction); @@ -760,28 +822,37 @@ public: VMScriptFunction(FName name=NAME_None); ~VMScriptFunction(); size_t PropagateMark(); - void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta); + void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta, int numlinenumbers); VM_ATAG *KonstATags() { return (VM_UBYTE *)(KonstA + NumKonstA); } const VM_ATAG *KonstATags() const { return (VM_UBYTE *)(KonstA + NumKonstA); } VMOP *Code; + FStatementInfo *LineInfo; + FString SourceFileName; int *KonstD; double *KonstF; FString *KonstS; FVoidObj *KonstA; int ExtraSpace; int CodeSize; // Size of code in instructions (not bytes) + unsigned LineInfoCount; VM_UBYTE NumRegD; VM_UBYTE NumRegF; VM_UBYTE NumRegS; VM_UBYTE NumRegA; - VM_UBYTE NumKonstD; - VM_UBYTE NumKonstF; - VM_UBYTE NumKonstS; - VM_UBYTE NumKonstA; + VM_UHALF NumKonstD; + VM_UHALF NumKonstF; + VM_UHALF NumKonstS; + VM_UHALF NumKonstA; VM_UHALF MaxParam; // Maximum number of parameters this function has on the stack at once VM_UBYTE NumArgs; // Number of arguments this function takes + TArray SpecialInits; // list of all contents on the extra stack which require construction and destruction + + void InitExtra(void *addr); + void DestroyExtra(void *addr); + int AllocExtraStack(PType *type); + int PCToLine(const VMOP *pc); }; class VMFrameStack @@ -789,7 +860,6 @@ class VMFrameStack public: VMFrameStack(); ~VMFrameStack(); - VMFrame *AllocFrame(int numregd, int numregf, int numregs, int numrega); VMFrame *AllocFrame(VMScriptFunction *func); VMFrame *PopFrame(); VMFrame *TopFrame() @@ -821,7 +891,7 @@ class VMNativeFunction : public VMFunction { DECLARE_CLASS(VMNativeFunction, VMFunction); public: - typedef int (*NativeCallType)(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret); + typedef int (*NativeCallType)(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret); VMNativeFunction() : NativeCall(NULL) { Native = true; } VMNativeFunction(NativeCallType call) : NativeCall(call) { Native = true; } @@ -884,6 +954,9 @@ enum EVMEngine VMEngine_Checked }; +extern thread_local VMFrameStack GlobalVMStack; + + void VMSelectEngine(EVMEngine engine); extern int (*VMExec)(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret); void VMFillParams(VMValue *params, VMFrame *callee, int numparam); @@ -892,11 +965,14 @@ void VMDumpConstants(FILE *out, const VMScriptFunction *func); void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction *func); // Use this in the prototype for a native function. -#define VM_ARGS VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret -#define VM_ARGS_NAMES stack, param, numparam, ret, numret +#define VM_ARGS VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret +#define VM_ARGS_NAMES param, defaultparam, numparam, ret, numret // Use these to collect the parameters in a native function. // variable name at position

+void NullParam(const char *varname); + +#define PARAM_NULLCHECK(ptr, var) (ptr == nullptr? NullParam(#var), ptr : ptr) // For required parameters. #define PARAM_INT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); int x = param[p].i; @@ -905,30 +981,39 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction #define PARAM_SOUND_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FSoundID x = param[p].i; #define PARAM_COLOR_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); PalEntry x; x.d = param[p].i; #define PARAM_FLOAT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); double x = param[p].f; -#define PARAM_ANGLE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); DAngle x = param[p].f; +#define PARAM_ANGLE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); DAngle x = param[p].f; #define PARAM_STRING_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_STRING); FString x = param[p].s(); -#define PARAM_STATE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); FState *x = (FState *)param[p].a; +#define PARAM_STATE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FState *x = (FState *)StateLabels.GetState(param[p].i, self->GetClass()); +#define PARAM_STATE_ACTION_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FState *x = (FState *)StateLabels.GetState(param[p].i, stateowner->GetClass()); #define PARAM_POINTER_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)param[p].a; #define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); type *x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); #define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); +#define PARAM_POINTER_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x); +#define PARAM_OBJECT_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); +#define PARAM_CLASS_NOT_NULL_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); base::MetaClass *x = (base::MetaClass *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); -// For optional paramaters. These have dangling elses for you to fill in the default assignment. e.g.: -// PARAM_INT_OPT(0,myint) { myint = 55; } -// Just make sure to fill it in when using these macros, because the compiler isn't likely -// to give useful error messages if you don't. -#define PARAM_INT_OPT_AT(p,x) int x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x = param[p].i; } else -#define PARAM_BOOL_OPT_AT(p,x) bool x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x = !!param[p].i; } else -#define PARAM_NAME_OPT_AT(p,x) FName x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x = ENamedName(param[p].i); } else -#define PARAM_SOUND_OPT_AT(p,x) FSoundID x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x = FSoundID(param[p].i); } else -#define PARAM_COLOR_OPT_AT(p,x) PalEntry x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x.d = param[p].i; } else -#define PARAM_FLOAT_OPT_AT(p,x) double x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_FLOAT); x = param[p].f; } else -#define PARAM_ANGLE_OPT_AT(p,x) DAngle x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_FLOAT); x = param[p].f; } else -#define PARAM_STRING_OPT_AT(p,x) FString x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_STRING); x = param[p].s(); } else -#define PARAM_STATE_OPT_AT(p,x) FState *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); x = (FState *)param[p].a; } else -#define PARAM_STATEINFO_OPT_AT(p,x) FStateParamInfo *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATEINFO || param[p].a == NULL)); x = (FStateParamInfo *)param[p].a; } else -#define PARAM_POINTER_OPT_AT(p,x,type) type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER); x = (type *)param[p].a; } else -#define PARAM_OBJECT_OPT_AT(p,x,type) type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); } else -#define PARAM_CLASS_OPT_AT(p,x,base) base::MetaClass *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); } else +#define PARAM_EXISTS(p) ((p) < numparam) +#define ASSERTINT(p) assert((p).Type == REGT_INT) +#define ASSERTFLOAT(p) assert((p).Type == REGT_FLOAT) +#define ASSERTSTRING(p) assert((p).Type == REGT_STRING) +#define ASSERTOBJECT(p) assert((p).Type == REGT_POINTER && ((p).atag == ATAG_OBJECT || (p).a == nullptr)) +#define ASSERTPOINTER(p) assert((p).Type == REGT_POINTER && (p).atag == ATAG_GENERIC) +#define ASSERTSTATE(p) assert((p).Type == REGT_POINTER && ((p).atag == ATAG_GENERIC || (p).atag == ATAG_STATE)) + +#define PARAM_INT_DEF_AT(p,x) int x; if (PARAM_EXISTS(p)) { ASSERTINT(param[p]); x = param[p].i; } else { ASSERTINT(defaultparam[p]); x = defaultparam[p].i; } +#define PARAM_BOOL_DEF_AT(p,x) bool x; if (PARAM_EXISTS(p)) { ASSERTINT(param[p]); x = !!param[p].i; } else { ASSERTINT(defaultparam[p]); x = !!defaultparam[p].i; } +#define PARAM_NAME_DEF_AT(p,x) FName x; if (PARAM_EXISTS(p)) { ASSERTINT(param[p]); x = ENamedName(param[p].i); } else { ASSERTINT(defaultparam[p]); x = ENamedName(defaultparam[p].i); } +#define PARAM_SOUND_DEF_AT(p,x) FSoundID x; if (PARAM_EXISTS(p)) { ASSERTINT(param[p]); x = FSoundID(param[p].i); } else { ASSERTINT(defaultparam[p]); x = FSoundID(defaultparam[p].i); } +#define PARAM_COLOR_DEF_AT(p,x) PalEntry x; if (PARAM_EXISTS(p)) { ASSERTINT(param[p]); x = param[p].i; } else { ASSERTINT(defaultparam[p]); x = defaultparam[p].i; } +#define PARAM_FLOAT_DEF_AT(p,x) double x; if (PARAM_EXISTS(p)) { ASSERTFLOAT(param[p]); x = param[p].f; } else { ASSERTFLOAT(defaultparam[p]); x = defaultparam[p].f; } +#define PARAM_ANGLE_DEF_AT(p,x) DAngle x; if (PARAM_EXISTS(p)) { ASSERTFLOAT(param[p]); x = param[p].f; } else { ASSERTFLOAT(defaultparam[p]); x = defaultparam[p].f; } +#define PARAM_STRING_DEF_AT(p,x) FString x; if (PARAM_EXISTS(p)) { ASSERTSTRING(param[p]); x = param[p].s; } else { ASSERTSTRING(defaultparam[p]); x = defaultparam[p].s; } +#define PARAM_STATE_DEF_AT(p,x) FState *x; if (PARAM_EXISTS(p)) { ASSERTINT(param[p]); x = (FState*)StateLabels.GetState(param[p].i, self->GetClass()); } else { ASSERTINT(defaultparam[p]); x = (FState*)StateLabels.GetState(defaultparam[p].i, self->GetClass()); } +#define PARAM_STATE_ACTION_DEF_AT(p,x) FState *x; if (PARAM_EXISTS(p)) { ASSERTINT(param[p]); x = (FState*)StateLabels.GetState(param[p].i, stateowner->GetClass()); } else { ASSERTINT(defaultparam[p]); x = (FState*)StateLabels.GetState(defaultparam[p].i, stateowner->GetClass()); } +#define PARAM_POINTER_DEF_AT(p,x,t) t *x; if (PARAM_EXISTS(p)) { ASSERTPOINTER(param[p]); x = (t*)param[p].a; } else { ASSERTPOINTER(defaultparam[p]); x = (t*)defaultparam[p].a; } +#define PARAM_OBJECT_DEF_AT(p,x,t) t *x; if (PARAM_EXISTS(p)) { ASSERTOBJECT(param[p]); x = (t*)param[p].a; } else { ASSERTOBJECT(defaultparam[p]); x = (t*)defaultparam[p].a; } +#define PARAM_CLASS_DEF_AT(p,x,t) t::MetaClass *x; if (PARAM_EXISTS(p)) { ASSERTOBJECT(param[p]); x = (t::MetaClass*)param[p].a; } else { ASSERTOBJECT(defaultparam[p]); x = (t::MetaClass*)defaultparam[p].a; } +#define PARAM_CLASS_DEF_NOT_NULL_AT(p,x,t) t::MetaClass *x; if (PARAM_EXISTS(p)) { ASSERTOBJECT(param[p]); x = (t::MetaClass*)PARAM_NULLCHECK(param[p].a, #x); } else { ASSERTOBJECT(defaultparam[p]); x = (t::MetaClass*)PARAM_NULLCHECK(defaultparam[p].a, #x); } // The above, but with an automatically increasing position index. #define PARAM_PROLOGUE int paramnum = -1; @@ -942,22 +1027,150 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction #define PARAM_ANGLE(x) ++paramnum; PARAM_ANGLE_AT(paramnum,x) #define PARAM_STRING(x) ++paramnum; PARAM_STRING_AT(paramnum,x) #define PARAM_STATE(x) ++paramnum; PARAM_STATE_AT(paramnum,x) +#define PARAM_STATE_ACTION(x) ++paramnum; PARAM_STATE_ACTION_AT(paramnum,x) #define PARAM_POINTER(x,type) ++paramnum; PARAM_POINTER_AT(paramnum,x,type) #define PARAM_OBJECT(x,type) ++paramnum; PARAM_OBJECT_AT(paramnum,x,type) #define PARAM_CLASS(x,base) ++paramnum; PARAM_CLASS_AT(paramnum,x,base) +#define PARAM_POINTER_NOT_NULL(x,type) ++paramnum; PARAM_POINTER_NOT_NULL_AT(paramnum,x,type) +#define PARAM_OBJECT_NOT_NULL(x,type) ++paramnum; PARAM_OBJECT_NOT_NULL_AT(paramnum,x,type) +#define PARAM_CLASS_NOT_NULL(x,base) ++paramnum; PARAM_CLASS_NOT_NULL_AT(paramnum,x,base) + +#define PARAM_INT_DEF(x) ++paramnum; PARAM_INT_DEF_AT(paramnum,x) +#define PARAM_BOOL_DEF(x) ++paramnum; PARAM_BOOL_DEF_AT(paramnum,x) +#define PARAM_NAME_DEF(x) ++paramnum; PARAM_NAME_DEF_AT(paramnum,x) +#define PARAM_SOUND_DEF(x) ++paramnum; PARAM_SOUND_DEF_AT(paramnum,x) +#define PARAM_COLOR_DEF(x) ++paramnum; PARAM_COLOR_DEF_AT(paramnum,x) +#define PARAM_FLOAT_DEF(x) ++paramnum; PARAM_FLOAT_DEF_AT(paramnum,x) +#define PARAM_ANGLE_DEF(x) ++paramnum; PARAM_ANGLE_DEF_AT(paramnum,x) +#define PARAM_STRING_DEF(x) ++paramnum; PARAM_STRING_DEF_AT(paramnum,x) +#define PARAM_STATE_DEF(x) ++paramnum; PARAM_STATE_DEF_AT(paramnum,x) +#define PARAM_STATE_ACTION_DEF(x) ++paramnum; PARAM_STATE_ACTION_DEF_AT(paramnum,x) +#define PARAM_POINTER_DEF(x,type) ++paramnum; PARAM_POINTER_DEF_AT(paramnum,x,type) +#define PARAM_OBJECT_DEF(x,type) ++paramnum; PARAM_OBJECT_DEF_AT(paramnum,x,type) +#define PARAM_CLASS_DEF(x,base) ++paramnum; PARAM_CLASS_DEF_AT(paramnum,x,base) +#define PARAM_CLASS_DEF_NOT_NULL(x,base) ++paramnum; PARAM_CLASS_DEF_NOT_NULL_AT(paramnum,x,base) + +typedef int(*actionf_p)(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret);/*(VM_ARGS)*/ + +struct FieldDesc +{ + const char *ClassName; + const char *FieldName; + unsigned FieldOffset; + unsigned FieldSize; + int BitValue; +}; + +struct AFuncDesc +{ + const char *ClassName; + const char *FuncName; + actionf_p Function; + VMNativeFunction **VMPointer; +}; + +#if defined(_MSC_VER) +#pragma section(".areg$u",read) +#pragma section(".freg$u",read) + +#define MSVC_ASEG __declspec(allocate(".areg$u")) +#define MSVC_FSEG __declspec(allocate(".freg$u")) +#define GCC_ASEG +#define GCC_FSEG +#else +#define MSVC_ASEG +#define MSVC_FSEG +#define GCC_ASEG __attribute__((section(SECTION_AREG))) __attribute__((used)) +#define GCC_FSEG __attribute__((section(SECTION_FREG))) __attribute__((used)) +#endif + +// Macros to handle action functions. These are here so that I don't have to +// change every single use in case the parameters change. + +#define DEFINE_ACTION_FUNCTION(cls, name) \ + static int AF_##cls##_##name(VM_ARGS); \ + VMNativeFunction *cls##_##name##_VMPtr; \ + static const AFuncDesc cls##_##name##_Hook = { #cls, #name, AF_##cls##_##name, &cls##_##name##_VMPtr }; \ + extern AFuncDesc const *const cls##_##name##_HookPtr; \ + MSVC_ASEG AFuncDesc const *const cls##_##name##_HookPtr GCC_ASEG = &cls##_##name##_Hook; \ + static int AF_##cls##_##name(VM_ARGS) + +// cls is the scripted class name, icls the internal one (e.g. player_t vs. Player) +#define DEFINE_FIELD_X(cls, icls, name) \ + static const FieldDesc VMField_##icls##_##name = { "A" #cls, #name, (unsigned)myoffsetof(icls, name), (unsigned)sizeof(icls::name), 0 }; \ + extern FieldDesc const *const VMField_##icls##_##name##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMField_##icls##_##name##_HookPtr GCC_FSEG = &VMField_##icls##_##name; + +#define DEFINE_FIELD_NAMED_X(cls, icls, name, scriptname) \ + static const FieldDesc VMField_##icls##_##scriptname = { "A" #cls, #scriptname, (unsigned)myoffsetof(icls, name), (unsigned)sizeof(icls::name), 0 }; \ + extern FieldDesc const *const VMField_##icls##_##scriptname##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMField_##icls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##icls##_##scriptname; + +#define DEFINE_FIELD_X_BIT(cls, icls, name, bitval) \ + static const FieldDesc VMField_##icls##_##name = { "A" #cls, #name, (unsigned)myoffsetof(icls, name), (unsigned)sizeof(icls::name), bitval }; \ + extern FieldDesc const *const VMField_##icls##_##name##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMField_##icls##_##name##_HookPtr GCC_FSEG = &VMField_##cls##_##name; + +#define DEFINE_FIELD(cls, name) \ + static const FieldDesc VMField_##cls##_##name = { #cls, #name, (unsigned)myoffsetof(cls, name), (unsigned)sizeof(cls::name), 0 }; \ + extern FieldDesc const *const VMField_##cls##_##name##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMField_##cls##_##name##_HookPtr GCC_FSEG = &VMField_##cls##_##name; + +#define DEFINE_FIELD_NAMED(cls, name, scriptname) \ + static const FieldDesc VMField_##cls##_##scriptname = { #cls, #scriptname, (unsigned)myoffsetof(cls, name), (unsigned)sizeof(cls::name), 0 }; \ + extern FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##cls##_##scriptname; + +#define DEFINE_FIELD_BIT(cls, name, scriptname, bitval) \ + static const FieldDesc VMField_##cls##_##scriptname = { #cls, #scriptname, (unsigned)myoffsetof(cls, name), (unsigned)sizeof(cls::name), bitval }; \ + extern FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##cls##_##scriptname; + +class AActor; + + +#define ACTION_RETURN_STATE(v) do { FState *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_STATE); return 1; } return 0; } while(0) +#define ACTION_RETURN_POINTER(v) do { void *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_GENERIC); return 1; } return 0; } while(0) +#define ACTION_RETURN_OBJECT(v) do { auto state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_OBJECT); return 1; } return 0; } while(0) +#define ACTION_RETURN_FLOAT(v) do { double u = v; if (numret > 0) { assert(ret != nullptr); ret->SetFloat(u); return 1; } return 0; } while(0) +#define ACTION_RETURN_VEC2(v) do { DVector2 u = v; if (numret > 0) { assert(ret != nullptr); ret[0].SetVector2(u); return 1; } return 0; } while(0) +#define ACTION_RETURN_VEC3(v) do { DVector3 u = v; if (numret > 0) { assert(ret != nullptr); ret[0].SetVector(u); return 1; } return 0; } while(0) +#define ACTION_RETURN_INT(v) do { int u = v; if (numret > 0) { assert(ret != NULL); ret->SetInt(u); return 1; } return 0; } while(0) +#define ACTION_RETURN_BOOL(v) ACTION_RETURN_INT(v) +#define ACTION_RETURN_STRING(v) do { FString u = v; if (numret > 0) { assert(ret != NULL); ret->SetString(u); return 1; } return 0; } while(0) + +// Checks to see what called the current action function +#define ACTION_CALL_FROM_ACTOR() (stateinfo == nullptr || stateinfo->mStateType == STATE_Actor) +#define ACTION_CALL_FROM_PSPRITE() (self->player && stateinfo != nullptr && stateinfo->mStateType == STATE_Psprite) +#define ACTION_CALL_FROM_INVENTORY() (stateinfo != nullptr && stateinfo->mStateType == STATE_StateChain) + +// Standard parameters for all action functons +// self - Actor this action is to operate on (player if a weapon) +// stateowner - Actor this action really belongs to (may be an item) +// callingstate - State this action was called from +#define PARAM_ACTION_PROLOGUE(type) \ + PARAM_PROLOGUE; \ + PARAM_OBJECT (self, AActor); \ + PARAM_OBJECT (stateowner, type) \ + PARAM_POINTER (stateinfo, FStateParamInfo) \ + +// Number of action paramaters +#define NAP 3 + +#define PARAM_SELF_PROLOGUE(type) \ + PARAM_PROLOGUE; \ + PARAM_OBJECT(self, type); + +// for structs we need to check for ATAG_GENERIC instead of ATAG_OBJECT +#define PARAM_SELF_STRUCT_PROLOGUE(type) \ + PARAM_PROLOGUE; \ + PARAM_POINTER(self, type); + +class PFunction; + +VMFunction *FindVMFunction(PClass *cls, const char *name); +#define DECLARE_VMFUNC(cls, name) static VMFunction *name; if (name == nullptr) name = FindVMFunction(RUNTIME_CLASS(cls), #name); + -#define PARAM_INT_OPT(x) ++paramnum; PARAM_INT_OPT_AT(paramnum,x) -#define PARAM_BOOL_OPT(x) ++paramnum; PARAM_BOOL_OPT_AT(paramnum,x) -#define PARAM_NAME_OPT(x) ++paramnum; PARAM_NAME_OPT_AT(paramnum,x) -#define PARAM_SOUND_OPT(x) ++paramnum; PARAM_SOUND_OPT_AT(paramnum,x) -#define PARAM_COLOR_OPT(x) ++paramnum; PARAM_COLOR_OPT_AT(paramnum,x) -#define PARAM_FLOAT_OPT(x) ++paramnum; PARAM_FLOAT_OPT_AT(paramnum,x) -#define PARAM_ANGLE_OPT(x) ++paramnum; PARAM_ANGLE_OPT_AT(paramnum,x) -#define PARAM_STRING_OPT(x) ++paramnum; PARAM_STRING_OPT_AT(paramnum,x) -#define PARAM_STATE_OPT(x) ++paramnum; PARAM_STATE_OPT_AT(paramnum,x) -#define PARAM_STATEINFO_OPT(x) ++paramnum; PARAM_STATEINFO_OPT_AT(paramnum,x) -#define PARAM_POINTER_OPT(x,type) ++paramnum; PARAM_POINTER_OPT_AT(paramnum,x,type) -#define PARAM_OBJECT_OPT(x,type) ++paramnum; PARAM_OBJECT_OPT_AT(paramnum,x,type) -#define PARAM_CLASS_OPT(x,base) ++paramnum; PARAM_CLASS_OPT_AT(paramnum,x,base) #endif diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp new file mode 100644 index 0000000000..3e833af79c --- /dev/null +++ b/src/scripting/vm/vmbuilder.cpp @@ -0,0 +1,950 @@ +/* +** vmbuilder.cpp +** +**--------------------------------------------------------------------------- +** Copyright -2016 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include "vmbuilder.h" +#include "codegeneration/codegen.h" +#include "info.h" +#include "m_argv.h" +#include "thingdef.h" +#include "doomerrors.h" + +struct VMRemap +{ + BYTE altOp, kReg, kType; +}; + + +#define xx(op, name, mode, alt, kreg, ktype) {OP_##alt, kreg, ktype } +VMRemap opRemap[NUM_OPS] = { +#include "vmops.h" +}; +#undef xx + +//========================================================================== +// +// VMFunctionBuilder - Constructor +// +//========================================================================== + +VMFunctionBuilder::VMFunctionBuilder(int numimplicits) +{ + MaxParam = 0; + ActiveParam = 0; + NumImplicits = numimplicits; +} + +//========================================================================== +// +// VMFunctionBuilder - Destructor +// +//========================================================================== + +VMFunctionBuilder::~VMFunctionBuilder() +{ +} + +//========================================================================== +// +// VMFunctionBuilder :: BeginStatement +// +// Records the start of a new statement. +// +//========================================================================== + +void VMFunctionBuilder::BeginStatement(FxExpression *stmt) +{ + // pop empty statement records. + while (LineNumbers.Size() > 0 && LineNumbers.Last().InstructionIndex == Code.Size()) LineNumbers.Pop(); + // only add a new entry if the line number differs. + if (LineNumbers.Size() == 0 || stmt->ScriptPosition.ScriptLine != LineNumbers.Last().LineNumber) + { + FStatementInfo si = { (uint16_t)Code.Size(), (uint16_t)stmt->ScriptPosition.ScriptLine }; + LineNumbers.Push(si); + } + StatementStack.Push(stmt); +} + +void VMFunctionBuilder::EndStatement() +{ + // pop empty statement records. + while (LineNumbers.Size() > 0 && LineNumbers.Last().InstructionIndex == Code.Size()) LineNumbers.Pop(); + StatementStack.Pop(); + // Re-enter the previous statement. + if (StatementStack.Size() > 0) + { + FStatementInfo si = { (uint16_t)Code.Size(), (uint16_t)StatementStack.Last()->ScriptPosition.ScriptLine }; + LineNumbers.Push(si); + } +} + +void VMFunctionBuilder::MakeFunction(VMScriptFunction *func) +{ + func->Alloc(Code.Size(), IntConstantList.Size(), FloatConstantList.Size(), StringConstantList.Size(), AddressConstantList.Size(), LineNumbers.Size()); + + // Copy code block. + memcpy(func->Code, &Code[0], Code.Size() * sizeof(VMOP)); + memcpy(func->LineInfo, &LineNumbers[0], LineNumbers.Size() * sizeof(LineNumbers[0])); + + // Create constant tables. + if (IntConstantList.Size() > 0) + { + FillIntConstants(func->KonstD); + } + if (FloatConstantList.Size() > 0) + { + FillFloatConstants(func->KonstF); + } + if (AddressConstantList.Size() > 0) + { + FillAddressConstants(func->KonstA, func->KonstATags()); + } + if (StringConstantList.Size() > 0) + { + FillStringConstants(func->KonstS); + } + + // Assign required register space. + func->NumRegD = Registers[REGT_INT].MostUsed; + func->NumRegF = Registers[REGT_FLOAT].MostUsed; + func->NumRegA = Registers[REGT_POINTER].MostUsed; + func->NumRegS = Registers[REGT_STRING].MostUsed; + func->MaxParam = MaxParam; + + // Technically, there's no reason why we can't end the function with + // entries on the parameter stack, but it means the caller probably + // did something wrong. + assert(ActiveParam == 0); +} + +//========================================================================== +// +// VMFunctionBuilder :: FillIntConstants +// +//========================================================================== + +void VMFunctionBuilder::FillIntConstants(int *konst) +{ + memcpy(konst, &IntConstantList[0], sizeof(int) * IntConstantList.Size()); +} + +//========================================================================== +// +// VMFunctionBuilder :: FillFloatConstants +// +//========================================================================== + +void VMFunctionBuilder::FillFloatConstants(double *konst) +{ + memcpy(konst, &FloatConstantList[0], sizeof(double) * FloatConstantList.Size()); +} + +//========================================================================== +// +// VMFunctionBuilder :: FillAddressConstants +// +//========================================================================== + +void VMFunctionBuilder::FillAddressConstants(FVoidObj *konst, VM_ATAG *tags) +{ + memcpy(konst, &AddressConstantList[0], sizeof(void*) * AddressConstantList.Size()); + memcpy(tags, &AtagConstantList[0], sizeof(VM_ATAG) * AtagConstantList.Size()); +} + +//========================================================================== +// +// VMFunctionBuilder :: FillStringConstants +// +//========================================================================== + +void VMFunctionBuilder::FillStringConstants(FString *konst) +{ + for (auto &s : StringConstantList) + { + *konst++ = s; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: GetConstantInt +// +// Returns a constant register initialized with the given value. +// +//========================================================================== + +unsigned VMFunctionBuilder::GetConstantInt(int val) +{ + unsigned int *locp = IntConstantMap.CheckKey(val); + if (locp != NULL) + { + return *locp; + } + else + { + unsigned loc = IntConstantList.Push(val); + IntConstantMap.Insert(val, loc); + return loc; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: GetConstantFloat +// +// Returns a constant register initialized with the given value. +// +//========================================================================== + +unsigned VMFunctionBuilder::GetConstantFloat(double val) +{ + unsigned *locp = FloatConstantMap.CheckKey(val); + if (locp != NULL) + { + return *locp; + } + else + { + unsigned loc = FloatConstantList.Push(val); + FloatConstantMap.Insert(val, loc); + return loc; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: GetConstantString +// +// Returns a constant register initialized with the given value. +// +//========================================================================== + +unsigned VMFunctionBuilder::GetConstantString(FString val) +{ + unsigned *locp = StringConstantMap.CheckKey(val); + if (locp != NULL) + { + return *locp; + } + else + { + int loc = StringConstantList.Push(val); + StringConstantMap.Insert(val, loc); + return loc; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: GetConstantAddress +// +// Returns a constant register initialized with the given value, or -1 if +// there were no more constants free. +// +//========================================================================== + +unsigned VMFunctionBuilder::GetConstantAddress(void *ptr, VM_ATAG tag) +{ + if (ptr == NULL) + { // Make all NULL pointers generic. (Or should we allow typed NULLs?) + tag = ATAG_GENERIC; + } + AddrKonst *locp = AddressConstantMap.CheckKey(ptr); + if (locp != NULL) + { + // There should only be one tag associated with a memory location. + assert(locp->Tag == tag); + return locp->KonstNum; + } + else + { + unsigned locc = AddressConstantList.Push(ptr); + AtagConstantList.Push(tag); + + AddrKonst loc = { locc, tag }; + AddressConstantMap.Insert(ptr, loc); + return loc.KonstNum; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: AllocConstants* +// +// Returns a range of constant register initialized with the given values. +// +//========================================================================== + +unsigned VMFunctionBuilder::AllocConstantsInt(unsigned count, int *values) +{ + unsigned addr = IntConstantList.Reserve(count); + memcpy(&IntConstantList[addr], values, count * sizeof(int)); + for (unsigned i = 0; i < count; i++) + { + IntConstantMap.Insert(values[i], addr + i); + } + return addr; +} + +unsigned VMFunctionBuilder::AllocConstantsFloat(unsigned count, double *values) +{ + unsigned addr = FloatConstantList.Reserve(count); + memcpy(&FloatConstantList[addr], values, count * sizeof(double)); + for (unsigned i = 0; i < count; i++) + { + FloatConstantMap.Insert(values[i], addr + i); + } + return addr; +} + +unsigned VMFunctionBuilder::AllocConstantsAddress(unsigned count, void **ptrs, VM_ATAG tag) +{ + unsigned addr = AddressConstantList.Reserve(count); + AtagConstantList.Reserve(count); + memcpy(&AddressConstantList[addr], ptrs, count * sizeof(void *)); + for (unsigned i = 0; i < count; i++) + { + AtagConstantList[addr + i] = tag; + AddrKonst loc = { addr+i, tag }; + AddressConstantMap.Insert(ptrs[i], loc); + } + return addr; +} + +unsigned VMFunctionBuilder::AllocConstantsString(unsigned count, FString *ptrs) +{ + unsigned addr = StringConstantList.Reserve(count); + for (unsigned i = 0; i < count; i++) + { + StringConstantList[addr + i] = ptrs[i]; + StringConstantMap.Insert(ptrs[i], addr + i); + } + return addr; +} + + +//========================================================================== +// +// VMFunctionBuilder :: ParamChange +// +// Adds delta to ActiveParam and keeps track of MaxParam. +// +//========================================================================== + +void VMFunctionBuilder::ParamChange(int delta) +{ + assert(delta > 0 || -delta <= ActiveParam); + ActiveParam += delta; + if (ActiveParam > MaxParam) + { + MaxParam = ActiveParam; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: RegAvailability - Constructor +// +//========================================================================== + +VMFunctionBuilder::RegAvailability::RegAvailability() +{ + memset(Used, 0, sizeof(Used)); + MostUsed = 0; +} + +//========================================================================== +// +// VMFunctionBuilder :: RegAvailability :: Get +// +// Gets one or more unused registers. If getting multiple registers, they +// will all be consecutive. Returns -1 if there were not enough consecutive +// registers to satisfy the request. +// +// Preference is given to low-numbered registers in an attempt to keep +// the maximum register count low so as to preserve VM stack space when this +// function is executed. +// +//========================================================================== + +int VMFunctionBuilder::RegAvailability::Get(int count) +{ + VM_UWORD mask; + int i, firstbit; + + // Getting fewer than one register makes no sense, and + // the algorithm used here can only obtain ranges of up to 32 bits. + if (count < 1 || count > 32) + { + return -1; + } + + mask = count == 32 ? ~0u : (1 << count) - 1; + + for (i = 0; i < 256 / 32; ++i) + { + // Find the first word with free registers + VM_UWORD bits = Used[i]; + if (bits != ~0u) + { + // Are there enough consecutive bits to satisfy the request? + // Search by 16, then 8, then 1 bit at a time for the first + // free register. + if ((bits & 0xFFFF) == 0xFFFF) + { + firstbit = ((bits & 0xFF0000) == 0xFF0000) ? 24 : 16; + } + else + { + firstbit = ((bits & 0xFF) == 0xFF) ? 8 : 0; + } + for (; firstbit < 32; ++firstbit) + { + if (((bits >> firstbit) & mask) == 0) + { + if (firstbit + count <= 32) + { // Needed bits all fit in one word, so we got it. + if (i * 32 + firstbit + count > MostUsed) + { + MostUsed = i * 32 + firstbit + count; + } + Used[i] |= mask << firstbit; + return i * 32 + firstbit; + } + // Needed bits span two words, so check the next word. + else if (i < 256/32 - 1) + { // There is a next word. + if (((Used[i + 1]) & (mask >> (32 - firstbit))) == 0) + { // The next word has the needed open space, too. + if (i * 32 + firstbit + count > MostUsed) + { + MostUsed = i * 32 + firstbit + count; + } + Used[i] |= mask << firstbit; + Used[i + 1] |= mask >> (32 - firstbit); + return i * 32 + firstbit; + } + else + { // Skip to the next word, because we know we won't find + // what we need if we stay inside this one. All bits + // from firstbit to the end of the word are 0. If the + // next word does not start with the x amount of 0's, we + // need to satisfy the request, then it certainly won't + // have the x+1 0's we would need if we started at + // firstbit+1 in this one. + firstbit = 32; + } + } + else + { // Out of words. + break; + } + } + } + } + } + // No room! + return -1; +} + +//========================================================================== +// +// VMFunctionBuilder :: RegAvailibity :: Return +// +// Marks a range of registers as free again. +// +//========================================================================== + +void VMFunctionBuilder::RegAvailability::Return(int reg, int count) +{ + assert(count >= 1 && count <= 32); + assert(reg >= 0 && reg + count <= 256); + + VM_UWORD mask, partialmask; + int firstword, firstbit; + + mask = count == 32 ? ~0u : (1 << count) - 1; + firstword = reg / 32; + firstbit = reg & 31; + + if (firstbit + count <= 32) + { // Range is all in one word. + mask <<= firstbit; + // If we are trying to return registers that are already free, + // it probably means that the caller messed up somewhere. + assert((Used[firstword] & mask) == mask); + Used[firstword] &= ~mask; + } + else + { // Range is in two words. + partialmask = mask << firstbit; + assert((Used[firstword] & partialmask) == partialmask); + Used[firstword] &= ~partialmask; + + partialmask = mask >> (32 - firstbit); + assert((Used[firstword + 1] & partialmask) == partialmask); + Used[firstword + 1] &= ~partialmask; + } +} + +//========================================================================== +// +// VMFunctionBuilder :: RegAvailability :: Reuse +// +// Marks an unused register as in-use. Returns false if the register is +// already in use or true if it was successfully reused. +// +//========================================================================== + +bool VMFunctionBuilder::RegAvailability::Reuse(int reg) +{ + assert(reg >= 0 && reg <= 255); + assert(reg < MostUsed && "Attempt to reuse a register that was never used"); + + VM_UWORD mask = 1 << (reg & 31); + int word = reg / 32; + + if (Used[word] & mask) + { // It's already in use! + return false; + } + Used[word] |= mask; + return true; +} + +//========================================================================== +// +// VMFunctionBuilder :: GetAddress +// +//========================================================================== + +size_t VMFunctionBuilder::GetAddress() +{ + return Code.Size(); +} + +//========================================================================== +// +// VMFunctionBuilder :: Emit +// +// Just dumbly output an instruction. Returns instruction position, not +// byte position. (Because all instructions are exactly four bytes long.) +// +//========================================================================== + +size_t VMFunctionBuilder::Emit(int opcode, int opa, int opb, int opc) +{ + static BYTE opcodes[] = { OP_LK, OP_LKF, OP_LKS, OP_LKP }; + + assert(opcode >= 0 && opcode < NUM_OPS); + assert(opa >= 0); + assert(opb >= 0); + assert(opc >= 0); + + + // The following were just asserts, meaning this would silently create broken code if there was an overflow + // if this happened in a release build. Not good. + // These are critical errors that need to be reported to the user. + // In addition, the limit of 256 constants can easily be exceeded with arrays so this had to be extended to + // 65535 by adding some checks here that map byte-limited instructions to alternatives that can handle larger indices. + // (See vmops.h for the remapping info.) + + // Note: OP_CMPS also needs treatment, but I do not expect constant overflow to become an issue with strings, so for now there is no handling. + + if (opa > 255) + { + if (opRemap[opcode].kReg != 1 || opa > 32767) + { + I_Error("Register limit exceeded"); + } + int regtype = opRemap[opcode].kType; + ExpEmit emit(this, regtype); + Emit(opcodes[regtype], emit.RegNum, opa); + opcode = opRemap[opcode].altOp; + opa = emit.RegNum; + emit.Free(this); + } + if (opb > 255) + { + if (opRemap[opcode].kReg != 2 || opb > 32767) + { + I_Error("Register limit exceeded"); + } + int regtype = opRemap[opcode].kType; + ExpEmit emit(this, regtype); + Emit(opcodes[regtype], emit.RegNum, opb); + opcode = opRemap[opcode].altOp; + opb = emit.RegNum; + emit.Free(this); + } + if (opc > 255) + { + if (opcode == OP_PARAM && (opb & REGT_KONST) && opc <= 32767) + { + int regtype = opb & REGT_TYPE; + opb = regtype; + ExpEmit emit(this, regtype); + Emit(opcodes[regtype], emit.RegNum, opc); + opc = emit.RegNum; + emit.Free(this); + } + else + { + if (opRemap[opcode].kReg != 4 || opc > 32767) + { + I_Error("Register limit exceeded"); + } + int regtype = opRemap[opcode].kType; + ExpEmit emit(this, regtype); + Emit(opcodes[regtype], emit.RegNum, opc); + opcode = opRemap[opcode].altOp; + opc = emit.RegNum; + emit.Free(this); + } + } + + if (opcode == OP_PARAM) + { + int chg; + if (opb & REGT_MULTIREG2) chg = 2; + else if (opb®T_MULTIREG3) chg = 3; + else chg = 1; + ParamChange(chg); + } + else if (opcode == OP_CALL || opcode == OP_CALL_K || opcode == OP_TAIL || opcode == OP_TAIL_K) + { + ParamChange(-opb); + } + VMOP op; + op.op = opcode; + op.a = opa; + op.b = opb; + op.c = opc; + return Code.Push(op); +} + +size_t VMFunctionBuilder::Emit(int opcode, int opa, VM_SHALF opbc) +{ + assert(opcode >= 0 && opcode < NUM_OPS); + assert(opa >= 0 && opa <= 255); + //assert(opbc >= -32768 && opbc <= 32767); always true due to parameter's width + VMOP op; + op.op = opcode; + op.a = opa; + op.i16 = opbc; + return Code.Push(op); +} + +size_t VMFunctionBuilder::Emit(int opcode, int opabc) +{ + assert(opcode >= 0 && opcode < NUM_OPS); + assert(opabc >= -(1 << 23) && opabc <= (1 << 24) - 1); + if (opcode == OP_PARAMI) + { + ParamChange(1); + } + VMOP op; + op.op = opcode; + op.i24 = opabc; + return Code.Push(op); +} + +//========================================================================== +// +// VMFunctionBuilder :: EmitParamInt +// +// Passes a constant integer parameter, using either PARAMI and an immediate +// value or PARAM and a constant register, as appropriate. +// +//========================================================================== + +size_t VMFunctionBuilder::EmitParamInt(int value) +{ + // Immediates for PARAMI must fit in 24 bits. + if (((value << 8) >> 8) == value) + { + return Emit(OP_PARAMI, value); + } + else + { + return Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, GetConstantInt(value)); + } +} + +//========================================================================== +// +// VMFunctionBuilder :: EmitLoadInt +// +// Loads an integer constant into a register, using either an immediate +// value or a constant register, as appropriate. +// +//========================================================================== + +size_t VMFunctionBuilder::EmitLoadInt(int regnum, int value) +{ + assert(regnum >= 0 && regnum < Registers[REGT_INT].MostUsed); + if (value >= -32768 && value <= 32767) + { + return Emit(OP_LI, regnum, value); + } + else + { + return Emit(OP_LK, regnum, GetConstantInt(value)); + } +} + +//========================================================================== +// +// VMFunctionBuilder :: EmitRetInt +// +// Returns an integer, using either an immediate value or a constant +// register, as appropriate. +// +//========================================================================== + +size_t VMFunctionBuilder::EmitRetInt(int retnum, bool final, int value) +{ + assert(retnum >= 0 && retnum <= 127); + if (value >= -32768 && value <= 32767) + { + return Emit(OP_RETI, retnum | (final << 7), value); + } + else + { + return Emit(OP_RET, retnum | (final << 7), REGT_INT | REGT_KONST, GetConstantInt(value)); + } +} + +//========================================================================== +// +// VMFunctionBuilder :: Backpatch +// +// Store a JMP instruction at that points at . +// +//========================================================================== + +void VMFunctionBuilder::Backpatch(size_t loc, size_t target) +{ + assert(loc < Code.Size()); + int offset = int(target - loc - 1); + assert(((offset << 8) >> 8) == offset); + Code[loc].op = OP_JMP; + Code[loc].i24 = offset; +} + +void VMFunctionBuilder::BackpatchList(TArray &locs, size_t target) +{ + for (auto loc : locs) + Backpatch(loc, target); +} + + +//========================================================================== +// +// VMFunctionBuilder :: BackpatchToHere +// +// Store a JMP instruction at that points to the current code gen +// location. +// +//========================================================================== + +void VMFunctionBuilder::BackpatchToHere(size_t loc) +{ + Backpatch(loc, Code.Size()); +} + +void VMFunctionBuilder::BackpatchListToHere(TArray &locs) +{ + for (auto loc : locs) + Backpatch(loc, Code.Size()); +} + +//========================================================================== +// +// FFunctionBuildList +// +// This list contains all functions yet to build. +// All adding functions return a VMFunction - either a complete one +// for native functions or an empty VMScriptFunction for scripted ones +// This VMScriptFunction object later gets filled in with the actual +// info, but we get the pointer right after registering the function +// with the builder. +// +//========================================================================== +FFunctionBuildList FunctionBuildList; + +VMFunction *FFunctionBuildList::AddFunction(PFunction *functype, FxExpression *code, const FString &name, bool fromdecorate, int stateindex, int statecount, int lumpnum) +{ + auto func = code->GetDirectFunction(); + if (func != nullptr) + { + delete code; + return func; + } + + //Printf("Adding %s\n", name.GetChars()); + + Item it; + it.Func = functype; + it.Code = code; + it.PrintableName = name; + it.Function = new VMScriptFunction; + it.Function->Name = functype->SymbolName; + it.Function->PrintableName = name; + it.Function->ImplicitArgs = functype->GetImplicitArgs(); + it.Proto = nullptr; + it.FromDecorate = fromdecorate; + it.StateIndex = stateindex; + it.StateCount = statecount; + it.Lump = lumpnum; + assert(it.Func->Variants.Size() == 1); + it.Func->Variants[0].Implementation = it.Function; + + // set prototype for named functions. + if (it.Func->SymbolName != NAME_None) + { + it.Function->Proto = it.Func->Variants[0].Proto; + } + + mItems.Push(it); + return it.Function; +} + + +void FFunctionBuildList::Build() +{ + int errorcount = 0; + int codesize = 0; + FILE *dump = nullptr; + + if (Args->CheckParm("-dumpdisasm")) dump = fopen("disasm.txt", "w"); + + for (auto &item : mItems) + { + assert(item.Code != NULL); + + // We don't know the return type in advance for anonymous functions. + FCompileContext ctx(item.Func, item.Func->SymbolName == NAME_None ? nullptr : item.Func->Variants[0].Proto, item.FromDecorate, item.StateIndex, item.StateCount, item.Lump); + + // Allocate registers for the function's arguments and create local variable nodes before starting to resolve it. + VMFunctionBuilder buildit(item.Func->GetImplicitArgs()); + for(unsigned i=0;iVariants[0].Proto->ArgumentTypes.Size();i++) + { + auto type = item.Func->Variants[0].Proto->ArgumentTypes[i]; + auto name = item.Func->Variants[0].ArgNames[i]; + auto flags = item.Func->Variants[0].ArgFlags[i]; + // this won't get resolved and won't get emitted. It is only needed so that the code generator can retrieve the necessary info about this argument to do its work. + auto local = new FxLocalVariableDeclaration(type, name, nullptr, flags, FScriptPosition()); + local->RegNum = buildit.Registers[type->GetRegType()].Get(type->GetRegCount()); + ctx.FunctionArgs.Push(local); + } + + FScriptPosition::StrictErrors = !item.FromDecorate; + item.Code = item.Code->Resolve(ctx); + // If we need extra space, load the frame pointer into a register so that we do not have to call the wasteful LFP instruction more than once. + if (item.Function->ExtraSpace > 0) + { + buildit.FramePointer = ExpEmit(&buildit, REGT_POINTER); + buildit.FramePointer.Fixed = true; + buildit.Emit(OP_LFP, buildit.FramePointer.RegNum); + } + + // Make sure resolving it didn't obliterate it. + if (item.Code != nullptr) + { + if (!item.Code->CheckReturn()) + { + auto newcmpd = new FxCompoundStatement(item.Code->ScriptPosition); + newcmpd->Add(item.Code); + newcmpd->Add(new FxReturnStatement(nullptr, item.Code->ScriptPosition)); + item.Code = newcmpd->Resolve(ctx); + } + + item.Proto = ctx.ReturnProto; + if (item.Proto == nullptr) + { + item.Code->ScriptPosition.Message(MSG_ERROR, "Function %s without prototype", item.PrintableName.GetChars()); + continue; + } + + // Generate prototype for anonymous functions. + VMScriptFunction *sfunc = item.Function; + // create a new prototype from the now known return type and the argument list of the function's template prototype. + if (sfunc->Proto == nullptr) + { + sfunc->Proto = NewPrototype(item.Proto->ReturnTypes, item.Func->Variants[0].Proto->ArgumentTypes); + } + + // Emit code + try + { + sfunc->SourceFileName = item.Code->ScriptPosition.FileName; // remember the file name for printing error messages if something goes wrong in the VM. + buildit.BeginStatement(item.Code); + item.Code->Emit(&buildit); + buildit.EndStatement(); + buildit.MakeFunction(sfunc); + sfunc->NumArgs = 0; + // NumArgs for the VMFunction must be the amount of stack elements, which can differ from the amount of logical function arguments if vectors are in the list. + // For the VM a vector is 2 or 3 args, depending on size. + for (auto s : item.Func->Variants[0].Proto->ArgumentTypes) + { + sfunc->NumArgs += s->GetRegCount(); + } + + if (dump != nullptr) + { + DumpFunction(dump, sfunc, item.PrintableName.GetChars(), (int)item.PrintableName.Len()); + codesize += sfunc->CodeSize; + } + sfunc->Unsafe = ctx.Unsafe; + } + catch (CRecoverableError &err) + { + // catch errors from the code generator and pring something meaningful. + item.Code->ScriptPosition.Message(MSG_ERROR, "%s in %s", err.GetMessage(), item.PrintableName.GetChars()); + } + } + delete item.Code; + if (dump != nullptr) + { + fflush(dump); + } + } + if (dump != nullptr) + { + fprintf(dump, "\n*************************************************************************\n%i code bytes\n", codesize * 4); + fclose(dump); + } + FScriptPosition::StrictErrors = false; + mItems.Clear(); + FxAlloc.FreeAllBlocks(); +} \ No newline at end of file diff --git a/src/scripting/vm/vmbuilder.h b/src/scripting/vm/vmbuilder.h new file mode 100644 index 0000000000..da099256ed --- /dev/null +++ b/src/scripting/vm/vmbuilder.h @@ -0,0 +1,157 @@ +#ifndef VMUTIL_H +#define VMUTIL_H + +#include "dobject.h" + +class VMFunctionBuilder; +class FxExpression; + +struct ExpEmit +{ + ExpEmit() : RegNum(0), RegType(REGT_NIL), RegCount(1), Konst(false), Fixed(false), Final(false), Target(false) {} + ExpEmit(int reg, int type, bool konst = false, bool fixed = false) : RegNum(reg), RegType(type), RegCount(1), Konst(konst), Fixed(fixed), Final(false), Target(false) {} + ExpEmit(VMFunctionBuilder *build, int type, int count = 1); + void Free(VMFunctionBuilder *build); + void Reuse(VMFunctionBuilder *build); + + uint16_t RegNum; + uint8_t RegType, RegCount; + // We are at 8 bytes for this struct, no matter what, so it's rather pointless to squeeze these flags into bitfields. + bool Konst, Fixed, Final, Target; +}; + +class VMFunctionBuilder +{ +public: + // Keeps track of which registers are available by way of a bitmask table. + class RegAvailability + { + public: + RegAvailability(); + int GetMostUsed() { return MostUsed; } + int Get(int count); // Returns the first register in the range + void Return(int reg, int count); + bool Reuse(int regnum); + + private: + VM_UWORD Used[256/32]; // Bitmap of used registers (bit set means reg is used) + int MostUsed; + + friend class VMFunctionBuilder; + }; + + VMFunctionBuilder(int numimplicits); + ~VMFunctionBuilder(); + + void BeginStatement(FxExpression *stmt); + void EndStatement(); + void MakeFunction(VMScriptFunction *func); + + // Returns the constant register holding the value. + unsigned GetConstantInt(int val); + unsigned GetConstantFloat(double val); + unsigned GetConstantAddress(void *ptr, VM_ATAG tag); + unsigned GetConstantString(FString str); + + unsigned AllocConstantsInt(unsigned int count, int *values); + unsigned AllocConstantsFloat(unsigned int count, double *values); + unsigned AllocConstantsAddress(unsigned int count, void **ptrs, VM_ATAG tag); + unsigned AllocConstantsString(unsigned int count, FString *ptrs); + + + // Returns the address of the next instruction to be emitted. + size_t GetAddress(); + + // Returns the address of the newly-emitted instruction. + size_t Emit(int opcode, int opa, int opb, int opc); + size_t Emit(int opcode, int opa, VM_SHALF opbc); + size_t Emit(int opcode, int opabc); + size_t EmitParamInt(int value); + size_t EmitLoadInt(int regnum, int value); + size_t EmitRetInt(int retnum, bool final, int value); + + void Backpatch(size_t addr, size_t target); + void BackpatchToHere(size_t addr); + void BackpatchList(TArray &addrs, size_t target); + void BackpatchListToHere(TArray &addrs); + + // Write out complete constant tables. + void FillIntConstants(int *konst); + void FillFloatConstants(double *konst); + void FillAddressConstants(FVoidObj *konst, VM_ATAG *tags); + void FillStringConstants(FString *strings); + + // PARAM increases ActiveParam; CALL decreases it. + void ParamChange(int delta); + + // Track available registers. + RegAvailability Registers[4]; + + // amount of implicit parameters so that proper code can be emitted for method calls + int NumImplicits; + + // keep the frame pointer, if needed, in a register because the LFP opcode is hideously inefficient, requiring more than 20 instructions on x64. + ExpEmit FramePointer; + +private: + struct AddrKonst + { + unsigned KonstNum; + VM_ATAG Tag; + }; + + TArray LineNumbers; + TArray StatementStack; + + TArray IntConstantList; + TArray FloatConstantList; + TArray AddressConstantList; + TArray AtagConstantList; + TArray StringConstantList; + // These map from the constant value to its position in the constant table. + TMap IntConstantMap; + TMap FloatConstantMap; + TMap AddressConstantMap; + TMap StringConstantMap; + + int MaxParam; + int ActiveParam; + + TArray Code; + +}; + +void DumpFunction(FILE *dump, VMScriptFunction *sfunc, const char *label, int labellen); + + +//========================================================================== +// +// +// +//========================================================================== +class FxExpression; + +class FFunctionBuildList +{ + struct Item + { + PFunction *Func = nullptr; + FxExpression *Code = nullptr; + PPrototype *Proto = nullptr; + VMScriptFunction *Function = nullptr; + FString PrintableName; + int StateIndex; + int StateCount; + int Lump; + bool FromDecorate; + }; + + TArray mItems; + +public: + VMFunction *AddFunction(PFunction *func, FxExpression *code, const FString &name, bool fromdecorate, int currentstate, int statecnt, int lumpnum); + void Build(); +}; + +extern FFunctionBuildList FunctionBuildList; +#endif diff --git a/src/zscript/vmdisasm.cpp b/src/scripting/vm/vmdisasm.cpp similarity index 79% rename from src/zscript/vmdisasm.cpp rename to src/scripting/vm/vmdisasm.cpp index 4e6f33ec75..d21e38d207 100644 --- a/src/zscript/vmdisasm.cpp +++ b/src/scripting/vm/vmdisasm.cpp @@ -1,5 +1,39 @@ -#include "vm.h" +/* +** vmdisasm.cpp +** +**--------------------------------------------------------------------------- +** Copyright -2016 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include "dobject.h" #include "c_console.h" +#include "templates.h" #define NOP MODE_AUNUSED | MODE_BUNUSED | MODE_CUNUSED @@ -50,11 +84,13 @@ #define RPI8 MODE_AP | MODE_BIMMZ | MODE_CUNUSED #define KPI8 MODE_AKP | MODE_BIMMZ | MODE_CUNUSED #define RPI8I8 MODE_AP | MODE_BIMMZ | MODE_CIMMZ +#define RPRPI8 MODE_AP | MODE_BP | MODE_CIMMZ #define KPI8I8 MODE_AKP | MODE_BIMMZ | MODE_CIMMZ #define I8BCP MODE_AIMMZ | MODE_BCJOINT | MODE_BCPARAM #define THROW MODE_AIMMZ | MODE_BCTHROW #define CATCH MODE_AIMMZ | MODE_BCCATCH #define CAST MODE_AX | MODE_BX | MODE_CIMMZ | MODE_BCCAST +#define CASTB MODE_AI | MODE_BX | MODE_CIMMZ | MODE_BCCAST #define RSRSRS MODE_AS | MODE_BS | MODE_CS #define RIRS MODE_AI | MODE_BS | MODE_CUNUSED @@ -62,11 +98,13 @@ #define RIRIRI MODE_AI | MODE_BI | MODE_CI #define RIRII8 MODE_AI | MODE_BI | MODE_CIMMZ +#define RFRII8 MODE_AF | MODE_BI | MODE_CIMMZ +#define RPRII8 MODE_AP | MODE_BI | MODE_CIMMZ +#define RSRII8 MODE_AS | MODE_BI | MODE_CIMMZ #define RIRIKI MODE_AI | MODE_BI | MODE_CKI #define RIKIRI MODE_AI | MODE_BKI | MODE_CI #define RIKII8 MODE_AI | MODE_BKI | MODE_CIMMZ #define RIRIIs MODE_AI | MODE_BI | MODE_CIMMS -#define RIRI MODE_AI | MODE_BI | MODE_CUNUSED #define I8RIRI MODE_AIMMZ | MODE_BI | MODE_CI #define I8RIKI MODE_AIMMZ | MODE_BI | MODE_CKI #define I8KIRI MODE_AIMMZ | MODE_BKI | MODE_CI @@ -83,6 +121,9 @@ #define RVRVRV MODE_AV | MODE_BV | MODE_CV #define RVRVKV MODE_AV | MODE_BV | MODE_CKV #define RVKVRV MODE_AV | MODE_BKV | MODE_CV +#define RVRVRF MODE_AV | MODE_BV | MODE_CF +#define RVRVKF MODE_AV | MODE_BV | MODE_CKF +#define RVKVRF MODE_AV | MODE_BKV | MODE_CF #define RFRV MODE_AF | MODE_BV | MODE_CUNUSED #define I8RVRV MODE_AIMMZ | MODE_BV | MODE_CV #define I8RVKV MODE_AIMMZ | MODE_BV | MODE_CKV @@ -106,7 +147,7 @@ const VMOpInfo OpInfo[NUM_OPS] = { -#define xx(op, name, mode) { #name, mode } +#define xx(op, name, mode, alt, kreg, ktype) { #name, mode } #include "vmops.h" }; @@ -162,7 +203,7 @@ static int printf_wrapper(FILE *f, const char *fmt, ...) void VMDumpConstants(FILE *out, const VMScriptFunction *func) { - char tmp[21]; + char tmp[30]; int i, j, k, kk; if (func->KonstD != NULL && func->NumKonstD != 0) @@ -202,7 +243,7 @@ void VMDumpConstants(FILE *out, const VMScriptFunction *func) for (j = 0, k = i; j < 4 && k < func->NumKonstA; j++, k += kk) { mysnprintf(tmp, countof(tmp), "%3d. %p:%d", k, func->KonstA[k].v, func->KonstATags()[k]); - printf_wrapper(out, "%-20s", tmp); + printf_wrapper(out, "%-22s", tmp); } printf_wrapper(out, "\n"); } @@ -220,7 +261,6 @@ void VMDumpConstants(FILE *out, const VMScriptFunction *func) void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction *func) { VMFunction *callfunc; - const char *callname; const char *name; int col; int mode; @@ -250,6 +290,10 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction a &= CMP_CHECK | CMP_APPROX; cmp = true; } + if (code[i].op == OP_PARAM && code[i].b & REGT_ADDROF) + { + name = "parama"; + } if (cmp) { // Comparison instruction. Modify name for inverted test. if (!(a & CMP_CHECK)) @@ -285,15 +329,15 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction case OP_CALL_K: case OP_TAIL_K: + { callfunc = (VMFunction *)func->KonstA[code[i].a].o; - callname = callfunc->Name != NAME_None ? callfunc->Name : "[anonfunc]"; - col = printf_wrapper(out, "%.23s,%d", callname, code[i].b); + col = printf_wrapper(out, "[%p],%d", callfunc, code[i].b); if (code[i].op == OP_CALL_K) { col += printf_wrapper(out, ",%d", code[i].c); } break; - + } case OP_RET: if (code[i].b != REGT_NIL) { @@ -338,26 +382,47 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction break; default: + + if ((mode & MODE_BCTYPE) == MODE_BCCAST) { switch (code[i].c) { + case CASTB_I: + mode = MODE_AI | MODE_BI | MODE_CUNUSED; + break; + case CASTB_A: + mode = MODE_AI | MODE_BP | MODE_CUNUSED; + break; case CAST_I2F: + case CAST_U2F: mode = MODE_AF | MODE_BI | MODE_CUNUSED; break; + case CAST_Co2S: + case CAST_So2S: + case CAST_N2S: case CAST_I2S: + case CAST_U2S: mode = MODE_AS | MODE_BI | MODE_CUNUSED; break; case CAST_F2I: + case CAST_F2U: + case CASTB_F: mode = MODE_AI | MODE_BF | MODE_CUNUSED; break; case CAST_F2S: + case CAST_V22S: + case CAST_V32S: mode = MODE_AS | MODE_BF | MODE_CUNUSED; break; case CAST_P2S: mode = MODE_AS | MODE_BP | MODE_CUNUSED; break; + case CAST_S2Co: + case CAST_S2So: + case CAST_S2N: case CAST_S2I: + case CASTB_S: mode = MODE_AI | MODE_BS | MODE_CUNUSED; break; case CAST_S2F: @@ -445,7 +510,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction } else if (code[i].op == OP_CALL_K || code[i].op == OP_TAIL_K) { - printf_wrapper(out, " [%p]\n", callfunc); + printf_wrapper(out, " [%s]\n", callfunc->PrintableName.GetChars()); } else { @@ -535,8 +600,10 @@ static int print_reg(FILE *out, int col, int arg, int mode, int immshift, const return col+printf_wrapper(out, "s%d", regnum); case REGT_POINTER: return col+printf_wrapper(out, "a%d", regnum); - case REGT_FLOAT | REGT_MULTIREG: - return col+printf_wrapper(out, "v%d", regnum); + case REGT_FLOAT | REGT_MULTIREG2: + return col+printf_wrapper(out, "v%d.2", regnum); + case REGT_FLOAT | REGT_MULTIREG3: + return col+printf_wrapper(out, "v%d.3", regnum); case REGT_INT | REGT_KONST: return col+print_reg(out, 0, regnum, MODE_KI, 0, func); case REGT_FLOAT | REGT_KONST: @@ -565,3 +632,21 @@ static int print_reg(FILE *out, int col, int arg, int mode, int immshift, const } return col; } + +//========================================================================== +// +// Do some postprocessing after everything has been defined +// +//========================================================================== + +void DumpFunction(FILE *dump, VMScriptFunction *sfunc, const char *label, int labellen) +{ + const char *marks = "======================================================="; + fprintf(dump, "\n%.*s %s %.*s", MAX(3, 38 - labellen / 2), marks, label, MAX(3, 38 - labellen / 2), marks); + fprintf(dump, "\nInteger regs: %-3d Float regs: %-3d Address regs: %-3d String regs: %-3d\nStack size: %d\n", + sfunc->NumRegD, sfunc->NumRegF, sfunc->NumRegA, sfunc->NumRegS, sfunc->MaxParam); + VMDumpConstants(dump, sfunc); + fprintf(dump, "\nDisassembly @ %p:\n", sfunc->Code); + VMDisasm(dump, sfunc->Code, sfunc->CodeSize, sfunc); +} + diff --git a/src/zscript/vmexec.cpp b/src/scripting/vm/vmexec.cpp similarity index 58% rename from src/zscript/vmexec.cpp rename to src/scripting/vm/vmexec.cpp index 7ee89329ad..79d0b7fe6b 100644 --- a/src/zscript/vmexec.cpp +++ b/src/scripting/vm/vmexec.cpp @@ -1,8 +1,50 @@ +/* +** vmexec.cpp +** +**--------------------------------------------------------------------------- +** Copyright -2016 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + #include -#include "vm.h" +#include +#include +#include "dobject.h" #include "xs_Float.h" +#include "r_state.h" +#include "textures/textures.h" #include "math/cmath.h" +// This must be a separate function because the VC compiler would otherwise allocate memory on the stack for every separate instance of the exception object that may get thrown. +void ThrowAbortException(EVMAbortException reason, const char *moreinfo, ...); +// intentionally implemented in a different source file tp prevent inlining. +void ThrowVMException(VMException *x); + #define IMPLEMENT_VMEXEC #if !defined(COMPGOTO) && defined(__GNUC__) @@ -38,14 +80,13 @@ #define ASSERTF(x) assert((unsigned)(x) < f->NumRegF) #define ASSERTA(x) assert((unsigned)(x) < f->NumRegA) #define ASSERTS(x) assert((unsigned)(x) < f->NumRegS) +#define ASSERTO(x) assert((unsigned)(x) < f->NumRegA && reg.atag[x] == ATAG_OBJECT) #define ASSERTKD(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstD) #define ASSERTKF(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstF) #define ASSERTKA(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstA) #define ASSERTKS(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstS) -#define THROW(x) throw(EVMAbortException(x)) - #define CMPJMP(test) \ if ((test) == (a & CMP_CHECK)) { \ assert(pc[1].op == OP_JMP); \ @@ -55,7 +96,7 @@ } #define GETADDR(a,o,x) \ - if (a == NULL) { THROW(x); } \ + if (a == NULL) { ThrowAbortException(x, nullptr); } \ ptr = (VM_SBYTE *)a + o static const VM_UWORD ZapTable[16] = @@ -108,6 +149,12 @@ VMExec_Checked::Exec #endif ; +// Note: If the VM is being used in multiple threads, this should be declared as thread_local. +// ZDoom doesn't need this at the moment so this is disabled. + +thread_local VMFrameStack GlobalVMStack; + + //=========================================================================== // // VMSelectEngine @@ -153,13 +200,14 @@ void VMFillParams(VMValue *params, VMFrame *callee, int numparam) const VMRegisters calleereg(callee); assert(calleefunc != NULL && !calleefunc->Native); - assert(numparam == calleefunc->NumArgs); + assert(numparam == calleefunc->NumArgs || ((int)calleefunc->DefaultArgs.Size() == calleefunc->NumArgs)); assert(REGT_INT == 0 && REGT_FLOAT == 1 && REGT_STRING == 2 && REGT_POINTER == 3); regd = regf = regs = rega = 0; - for (int i = 0; i < numparam; ++i) + for (int i = 0; i < calleefunc->NumArgs; ++i) { - VMValue &p = params[i]; + // get all actual parameters and fill the rest from the defaults. + VMValue &p = i < numparam? params[i] : calleefunc->DefaultArgs[i]; if (p.Type < REGT_STRING) { if (p.Type == REGT_INT) @@ -183,3 +231,5 @@ void VMFillParams(VMValue *params, VMFrame *callee, int numparam) } } } + + diff --git a/src/zscript/vmexec.h b/src/scripting/vm/vmexec.h similarity index 72% rename from src/zscript/vmexec.h rename to src/scripting/vm/vmexec.h index 3637f2c1cd..76a7156cb8 100644 --- a/src/zscript/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -2,13 +2,12 @@ #error vmexec.h must not be #included outside vmexec.cpp. Use vm.h instead. #endif - static int Exec(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret) { #if COMPGOTO static const void * const ops[256] = { -#define xx(op,sym,mode) &&op +#define xx(op,sym,mode,alt,kreg,ktype) &&op #include "vmops.h" }; #endif @@ -84,10 +83,36 @@ begin: reg.a[a] = konsta[BC].v; reg.atag[a] = konstatag[BC]; NEXTOP; + + OP(LK_R) : + ASSERTD(a); ASSERTD(B); + reg.d[a] = konstd[reg.d[B] + C]; + NEXTOP; + OP(LKF_R) : + ASSERTF(a); ASSERTD(B); + reg.f[a] = konstf[reg.d[B] + C]; + NEXTOP; + OP(LKS_R) : + ASSERTS(a); ASSERTD(B); + reg.s[a] = konsts[reg.d[B] + C]; + NEXTOP; + OP(LKP_R) : + ASSERTA(a); ASSERTD(B); + b = reg.d[B] + C; + reg.a[a] = konsta[b].v; + reg.atag[a] = konstatag[b]; + NEXTOP; + OP(LFP): ASSERTA(a); assert(sfunc != NULL); assert(sfunc->ExtraSpace > 0); reg.a[a] = f->GetExtra(); - reg.atag[a] = ATAG_FRAMEPOINTER; + reg.atag[a] = ATAG_GENERIC; // using ATAG_FRAMEPOINTER will cause endless asserts. + NEXTOP; + + OP(META): + ASSERTA(a); ASSERTO(B); + reg.a[a] = ((DObject*)reg.a[B])->GetClass(); // I wish this could be done without a special opcode but there's really no good way to guarantee initialization of the Class pointer... + reg.atag[a] = ATAG_OBJECT; NEXTOP; OP(LB): @@ -175,13 +200,13 @@ begin: OP(LO): ASSERTA(a); ASSERTA(B); ASSERTKD(C); GETADDR(PB,KC,X_READ_NIL); - reg.a[a] = *(void **)ptr; + reg.a[a] = GC::ReadBarrier(*(DObject **)ptr); reg.atag[a] = ATAG_OBJECT; NEXTOP; OP(LO_R): ASSERTA(a); ASSERTA(B); ASSERTD(C); GETADDR(PB,RC,X_READ_NIL); - reg.a[a] = *(void **)ptr; + reg.a[a] = GC::ReadBarrier(*(DObject **)ptr); reg.atag[a] = ATAG_OBJECT; NEXTOP; OP(LP): @@ -196,21 +221,39 @@ begin: reg.a[a] = *(void **)ptr; reg.atag[a] = ATAG_GENERIC; NEXTOP; - OP(LV): + OP(LV2): + ASSERTF(a+1); ASSERTA(B); ASSERTKD(C); + GETADDR(PB,KC,X_READ_NIL); + { + auto v = (double *)ptr; + reg.f[a] = v[0]; + reg.f[a+1] = v[1]; + } + NEXTOP; + OP(LV2_R): + ASSERTF(a+1); ASSERTA(B); ASSERTD(C); + GETADDR(PB,RC,X_READ_NIL); + { + auto v = (double *)ptr; + reg.f[a] = v[0]; + reg.f[a+1] = v[1]; + } + NEXTOP; + OP(LV3): ASSERTF(a+2); ASSERTA(B); ASSERTKD(C); GETADDR(PB,KC,X_READ_NIL); { - float *v = (float *)ptr; + auto v = (double *)ptr; reg.f[a] = v[0]; reg.f[a+1] = v[1]; reg.f[a+2] = v[2]; } NEXTOP; - OP(LV_R): + OP(LV3_R): ASSERTF(a+2); ASSERTA(B); ASSERTD(C); GETADDR(PB,RC,X_READ_NIL); { - float *v = (float *)ptr; + auto v = (double *)ptr; reg.f[a] = v[0]; reg.f[a+1] = v[1]; reg.f[a+2] = v[2]; @@ -292,24 +335,42 @@ begin: GETADDR(PA,RC,X_WRITE_NIL); *(void **)ptr = reg.a[B]; NEXTOP; - OP(SV): + OP(SV2): + ASSERTA(a); ASSERTF(B+1); ASSERTKD(C); + GETADDR(PA,KC,X_WRITE_NIL); + { + auto v = (double *)ptr; + v[0] = reg.f[B]; + v[1] = reg.f[B+1]; + } + NEXTOP; + OP(SV2_R): + ASSERTA(a); ASSERTF(B+1); ASSERTD(C); + GETADDR(PA,RC,X_WRITE_NIL); + { + auto v = (double *)ptr; + v[0] = reg.f[B]; + v[1] = reg.f[B+1]; + } + NEXTOP; + OP(SV3): ASSERTA(a); ASSERTF(B+2); ASSERTKD(C); GETADDR(PA,KC,X_WRITE_NIL); { - float *v = (float *)ptr; - v[0] = (float)reg.f[B]; - v[1] = (float)reg.f[B+1]; - v[2] = (float)reg.f[B+2]; + auto v = (double *)ptr; + v[0] = reg.f[B]; + v[1] = reg.f[B+1]; + v[2] = reg.f[B+2]; } NEXTOP; - OP(SV_R): + OP(SV3_R): ASSERTA(a); ASSERTF(B+2); ASSERTD(C); GETADDR(PA,RC,X_WRITE_NIL); { - float *v = (float *)ptr; - v[0] = (float)reg.f[B]; - v[1] = (float)reg.f[B+1]; - v[2] = (float)reg.f[B+2]; + auto v = (double *)ptr; + v[0] = reg.f[B]; + v[1] = reg.f[B+1]; + v[2] = reg.f[B+2]; } NEXTOP; OP(SBIT): @@ -342,27 +403,67 @@ begin: reg.a[a] = reg.a[B]; reg.atag[a] = reg.atag[B]; NEXTOP; + OP(MOVEV2): + ASSERTF(a); ASSERTF(B); + reg.f[a] = reg.f[B]; + reg.f[a+1] = reg.f[B+1]; + NEXTOP; + OP(MOVEV3): + ASSERTF(a); ASSERTF(B); + reg.f[a] = reg.f[B]; + reg.f[a+1] = reg.f[B+1]; + reg.f[a+2] = reg.f[B+2]; + NEXTOP; + OP(DYNCAST_R) : + ASSERTA(a); ASSERTA(B); ASSERTA(C); + b = B; + reg.a[a] = (reg.a[b] && ((DObject*)(reg.a[b]))->IsKindOf((PClass*)(reg.a[C]))) ? reg.a[b] : nullptr; + reg.atag[a] = ATAG_OBJECT; + NEXTOP; + OP(DYNCAST_K) : + ASSERTA(a); ASSERTA(B); ASSERTKA(C); + b = B; + reg.a[a] = (reg.a[b] && ((DObject*)(reg.a[b]))->IsKindOf((PClass*)(konsta[C].o))) ? reg.a[b] : nullptr; + reg.atag[a] = ATAG_OBJECT; + NEXTOP; OP(CAST): if (C == CAST_I2F) { ASSERTF(a); ASSERTD(B); - reg.f[A] = reg.d[B]; + reg.f[a] = reg.d[B]; } else if (C == CAST_F2I) { ASSERTD(a); ASSERTF(B); - reg.d[A] = (int)reg.f[B]; + reg.d[a] = (int)reg.f[B]; } else { DoCast(reg, f, a, B, C); } NEXTOP; - OP(DYNCAST_R): - // UNDONE - NEXTOP; - OP(DYNCAST_K): - // UNDONE + + OP(CASTB): + if (C == CASTB_I) + { + ASSERTD(a); ASSERTD(B); + reg.d[a] = !!reg.d[B]; + } + else if (C == CASTB_F) + { + ASSERTD(a); ASSERTF(B); + reg.d[a] = reg.f[B] != 0; + } + else if (C == CASTB_A) + { + ASSERTD(a); ASSERTA(B); + reg.d[a] = reg.a[B] != nullptr; + } + else + { + ASSERTD(a); ASSERTS(B); + reg.d[a] = reg.s[B].Len() > 0; + } NEXTOP; OP(TEST): @@ -372,6 +473,13 @@ begin: pc++; } NEXTOP; + OP(TESTN): + ASSERTD(a); + if (-reg.d[a] != BC) + { + pc++; + } + NEXTOP; OP(JMP): pc += JMPOFS(pc); NEXTOP; @@ -399,7 +507,7 @@ begin: } else { - switch(b & (REGT_TYPE | REGT_KONST | REGT_ADDROF)) + switch(b) { case REGT_INT: assert(C < f->NumRegD); @@ -407,7 +515,7 @@ begin: break; case REGT_INT | REGT_ADDROF: assert(C < f->NumRegD); - ::new(param) VMValue(®.d[C], ATAG_DREGISTER); + ::new(param) VMValue(®.d[C], ATAG_GENERIC); break; case REGT_INT | REGT_KONST: assert(C < sfunc->NumKonstD); @@ -419,7 +527,7 @@ begin: break; case REGT_STRING | REGT_ADDROF: assert(C < f->NumRegS); - ::new(param) VMValue(®.s[C], ATAG_SREGISTER); + ::new(param) VMValue(®.s[C], ATAG_GENERIC); break; case REGT_STRING | REGT_KONST: assert(C < sfunc->NumKonstS); @@ -431,47 +539,38 @@ begin: break; case REGT_POINTER | REGT_ADDROF: assert(C < f->NumRegA); - ::new(param) VMValue(®.a[C], ATAG_AREGISTER); + ::new(param) VMValue(®.a[C], ATAG_GENERIC); break; case REGT_POINTER | REGT_KONST: assert(C < sfunc->NumKonstA); ::new(param) VMValue(konsta[C].v, konstatag[C]); break; case REGT_FLOAT: - if (b & REGT_MULTIREG) - { - assert(C < f->NumRegF - 2); - assert(f->NumParam < sfunc->MaxParam - 1); - ::new(param) VMValue(reg.f[C]); - ::new(param+1) VMValue(reg.f[C+1]); - ::new(param+2) VMValue(reg.f[C+2]); - f->NumParam += 2; - } - else - { - assert(C < f->NumRegF); - ::new(param) VMValue(reg.f[C]); - } + assert(C < f->NumRegF); + ::new(param) VMValue(reg.f[C]); + break; + case REGT_FLOAT | REGT_MULTIREG2: + assert(C < f->NumRegF - 1); + assert(f->NumParam < sfunc->MaxParam); + ::new(param) VMValue(reg.f[C]); + ::new(param + 1) VMValue(reg.f[C + 1]); + f->NumParam++; + break; + case REGT_FLOAT | REGT_MULTIREG3: + assert(C < f->NumRegF - 2); + assert(f->NumParam < sfunc->MaxParam - 1); + ::new(param) VMValue(reg.f[C]); + ::new(param + 1) VMValue(reg.f[C + 1]); + ::new(param + 2) VMValue(reg.f[C + 2]); + f->NumParam += 2; break; case REGT_FLOAT | REGT_ADDROF: assert(C < f->NumRegF); - ::new(param) VMValue(®.f[C], ATAG_FREGISTER); + ::new(param) VMValue(®.f[C], ATAG_GENERIC); break; case REGT_FLOAT | REGT_KONST: - if (b & REGT_MULTIREG) - { - assert(C < sfunc->NumKonstF - 2); - assert(f->NumParam < sfunc->MaxParam - 1); - ::new(param) VMValue(konstf[C]); - ::new(param+1) VMValue(konstf[C+1]); - ::new(param+2) VMValue(konstf[C+2]); - f->NumParam += 2; - } - else - { - assert(C < sfunc->NumKonstF); - ::new(param) VMValue(konstf[C]); - } + assert(C < sfunc->NumKonstF); + ::new(param) VMValue(konstf[C]); break; default: assert(0); @@ -480,6 +579,15 @@ begin: } } NEXTOP; + OP(VTBL): + ASSERTA(a); ASSERTA(B); + { + auto o = (DObject*)reg.a[B]; + auto p = o->GetClass(); + assert(C < p->Virtuals.Size()); + reg.a[a] = p->Virtuals[C]; + } + NEXTOP; OP(CALL_K): ASSERTKA(a); assert(konstatag[a] == ATAG_OBJECT); @@ -499,7 +607,17 @@ begin: FillReturns(reg, f, returns, pc+1, C); if (call->Native) { - numret = static_cast(call)->NativeCall(stack, reg.param + f->NumParam - B, B, returns, C); + try + { + numret = static_cast(call)->NativeCall(reg.param + f->NumParam - B, call->DefaultArgs, B, returns, C); + } + catch (CVMAbortException &err) + { + err.MaybePrintMessage(); + err.stacktrace.AppendFormat("Called from %s\n", call->PrintableName.GetChars()); + // PrintParameters(reg.param + f->NumParam - B, B); + throw; + } } else { @@ -543,7 +661,17 @@ begin: if (call->Native) { - return static_cast(call)->NativeCall(stack, reg.param + f->NumParam - B, B, ret, numret); + try + { + return static_cast(call)->NativeCall(reg.param + f->NumParam - B, call->DefaultArgs, B, ret, numret); + } + catch (CVMAbortException &err) + { + err.MaybePrintMessage(); + err.stacktrace.AppendFormat("Called from %s\n", call->PrintableName.GetChars()); + // PrintParameters(reg.param + f->NumParam - B, B); + throw; + } } else { // FIXME: Not a true tail call @@ -607,7 +735,7 @@ begin: assert(try_depth < MAX_TRY_DEPTH); if (try_depth >= MAX_TRY_DEPTH) { - THROW(X_TOO_MANY_TRIES); + ThrowAbortException(X_TOO_MANY_TRIES, nullptr); } assert((pc + JMPOFS(pc) + 1)->op == OP_CATCH); exception_frames[try_depth++] = pc + JMPOFS(pc) + 1; @@ -620,17 +748,17 @@ begin: if (a == 0) { ASSERTA(B); - throw((VMException *)reg.a[B]); + ThrowVMException((VMException *)reg.a[B]); } else if (a == 1) { ASSERTKA(B); assert(konstatag[B] == ATAG_OBJECT); - throw((VMException *)konsta[B].o); + ThrowVMException((VMException *)konsta[B].o); } else { - THROW(BC); + ThrowAbortException(EVMAbortException(BC), nullptr); } NEXTOP; OP(CATCH): @@ -642,22 +770,29 @@ begin: OP(BOUND): if (reg.d[a] >= BC) { - THROW(X_ARRAY_OUT_OF_BOUNDS); + ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", BC, reg.d[a]); + } + NEXTOP; + + OP(BOUND_K): + ASSERTKD(BC); + if (reg.d[a] >= konstd[BC]) + { + ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", konstd[BC], reg.d[a]); + } + NEXTOP; + + OP(BOUND_R): + ASSERTD(B); + if (reg.d[a] >= reg.d[B]) + { + ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Max.index = %u, current index = %u\n", reg.d[B], reg.d[a]); } NEXTOP; OP(CONCAT): ASSERTS(a); ASSERTS(B); ASSERTS(C); - { - FString *rB = ®.s[B]; - FString *rC = ®.s[C]; - FString concat(*rB); - for (++rB; rB <= rC; ++rB) - { - concat += *rB; - } - reg.s[a] = concat; - } + reg.s[a] = reg.s[B] + reg.s[C]; NEXTOP; OP(LENS): ASSERTD(a); ASSERTS(B); @@ -798,7 +933,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTD(C); if (reg.d[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = reg.d[B] / reg.d[C]; NEXTOP; @@ -806,7 +941,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTKD(C); if (konstd[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = reg.d[B] / konstd[C]; NEXTOP; @@ -814,16 +949,41 @@ begin: ASSERTD(a); ASSERTKD(B); ASSERTD(C); if (reg.d[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = konstd[B] / reg.d[C]; NEXTOP; + OP(DIVU_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + if (reg.d[C] == 0) + { + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); + } + reg.d[a] = int((unsigned)reg.d[B] / (unsigned)reg.d[C]); + NEXTOP; + OP(DIVU_RK): + ASSERTD(a); ASSERTD(B); ASSERTKD(C); + if (konstd[C] == 0) + { + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); + } + reg.d[a] = int((unsigned)reg.d[B] / (unsigned)konstd[C]); + NEXTOP; + OP(DIVU_KR): + ASSERTD(a); ASSERTKD(B); ASSERTD(C); + if (reg.d[C] == 0) + { + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); + } + reg.d[a] = int((unsigned)konstd[B] / (unsigned)reg.d[C]); + NEXTOP; + OP(MOD_RR): ASSERTD(a); ASSERTD(B); ASSERTD(C); if (reg.d[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = reg.d[B] % reg.d[C]; NEXTOP; @@ -831,7 +991,7 @@ begin: ASSERTD(a); ASSERTD(B); ASSERTKD(C); if (konstd[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = reg.d[B] % konstd[C]; NEXTOP; @@ -839,11 +999,36 @@ begin: ASSERTD(a); ASSERTKD(B); ASSERTD(C); if (reg.d[C] == 0) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.d[a] = konstd[B] % reg.d[C]; NEXTOP; + OP(MODU_RR): + ASSERTD(a); ASSERTD(B); ASSERTD(C); + if (reg.d[C] == 0) + { + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); + } + reg.d[a] = int((unsigned)reg.d[B] % (unsigned)reg.d[C]); + NEXTOP; + OP(MODU_RK): + ASSERTD(a); ASSERTD(B); ASSERTKD(C); + if (konstd[C] == 0) + { + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); + } + reg.d[a] = int((unsigned)reg.d[B] % (unsigned)konstd[C]); + NEXTOP; + OP(MODU_KR): + ASSERTD(a); ASSERTKD(B); ASSERTD(C); + if (reg.d[C] == 0) + { + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); + } + reg.d[a] = int((unsigned)konstd[B] % (unsigned)reg.d[C]); + NEXTOP; + OP(AND_RR): ASSERTD(a); ASSERTD(B); ASSERTD(C); reg.d[a] = reg.d[B] & reg.d[C]; @@ -867,7 +1052,7 @@ begin: reg.d[a] = reg.d[B] ^ reg.d[C]; NEXTOP; OP(XOR_RK): - ASSERTD(a); ASSERTD(B); ASSERTD(C); + ASSERTD(a); ASSERTD(B); ASSERTKD(C); reg.d[a] = reg.d[B] ^ konstd[C]; NEXTOP; @@ -1017,7 +1202,7 @@ begin: ASSERTF(a); ASSERTF(B); ASSERTF(C); if (reg.f[C] == 0.) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.f[a] = reg.f[B] / reg.f[C]; NEXTOP; @@ -1025,7 +1210,7 @@ begin: ASSERTF(a); ASSERTF(B); ASSERTKF(C); if (konstf[C] == 0.) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.f[a] = reg.f[B] / konstf[C]; NEXTOP; @@ -1033,7 +1218,7 @@ begin: ASSERTF(a); ASSERTKF(B); ASSERTF(C); if (reg.f[C] == 0.) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.f[a] = konstf[B] / reg.f[C]; NEXTOP; @@ -1044,7 +1229,7 @@ begin: Do_MODF: if (fc == 0.) { - THROW(X_DIVISION_BY_ZERO); + ThrowAbortException(X_DIVISION_BY_ZERO, nullptr); } reg.f[a] = luai_nummod(fb, fc); NEXTOP; @@ -1061,15 +1246,15 @@ begin: OP(POWF_RR): ASSERTF(a); ASSERTF(B); ASSERTF(C); - reg.f[a] = pow(reg.f[B], reg.f[C]); + reg.f[a] = g_pow(reg.f[B], reg.f[C]); NEXTOP; OP(POWF_RK): ASSERTF(a); ASSERTF(B); ASSERTKF(C); - reg.f[a] = pow(reg.f[B], konstf[C]); + reg.f[a] = g_pow(reg.f[B], konstf[C]); NEXTOP; OP(POWF_KR): ASSERTF(a); ASSERTKF(B); ASSERTF(C); - reg.f[a] = pow(konstf[B], reg.f[C]); + reg.f[a] = g_pow(konstf[B], reg.f[C]); NEXTOP; OP(MINF_RR): @@ -1189,60 +1374,119 @@ begin: } NEXTOP; - OP(NEGV): + OP(NEGV2): + ASSERTF(a+1); ASSERTF(B+1); + reg.f[a] = -reg.f[B]; + reg.f[a+1] = -reg.f[B+1]; + NEXTOP; + + OP(ADDV2_RR): + ASSERTF(a+1); ASSERTF(B+1); ASSERTF(C+1); + fcp = ®.f[C]; + fbp = ®.f[B]; + reg.f[a] = fbp[0] + fcp[0]; + reg.f[a+1] = fbp[1] + fcp[1]; + NEXTOP; + + OP(SUBV2_RR): + ASSERTF(a+1); ASSERTF(B+1); ASSERTF(C+1); + fbp = ®.f[B]; + fcp = ®.f[C]; + reg.f[a] = fbp[0] - fcp[0]; + reg.f[a+1] = fbp[1] - fcp[1]; + NEXTOP; + + OP(DOTV2_RR): + ASSERTF(a); ASSERTF(B+1); ASSERTF(C+1); + reg.f[a] = reg.f[B] * reg.f[C] + reg.f[B+1] * reg.f[C+1]; + NEXTOP; + + OP(MULVF2_RR): + ASSERTF(a+1); ASSERTF(B+1); ASSERTF(C); + fc = reg.f[C]; + fbp = ®.f[B]; + Do_MULV2: + reg.f[a] = fbp[0] * fc; + reg.f[a+1] = fbp[1] * fc; + NEXTOP; + OP(MULVF2_RK): + ASSERTF(a+1); ASSERTF(B+1); ASSERTKF(C); + fc = konstf[C]; + fbp = ®.f[B]; + goto Do_MULV2; + + OP(DIVVF2_RR): + ASSERTF(a+1); ASSERTF(B+1); ASSERTF(C); + fc = reg.f[C]; + fbp = ®.f[B]; + Do_DIVV2: + reg.f[a] = fbp[0] / fc; + reg.f[a+1] = fbp[1] / fc; + NEXTOP; + OP(DIVVF2_RK): + ASSERTF(a+1); ASSERTF(B+1); ASSERTKF(C); + fc = konstf[C]; + fbp = ®.f[B]; + goto Do_DIVV2; + + OP(LENV2): + ASSERTF(a); ASSERTF(B+1); + reg.f[a] = g_sqrt(reg.f[B] * reg.f[B] + reg.f[B+1] * reg.f[B+1]); + NEXTOP; + + OP(EQV2_R): + ASSERTF(B+1); ASSERTF(C+1); + fcp = ®.f[C]; + Do_EQV2: + if (a & CMP_APPROX) + { + CMPJMP(fabs(reg.f[B ] - fcp[0]) < VM_EPSILON && + fabs(reg.f[B+1] - fcp[1]) < VM_EPSILON); + } + else + { + CMPJMP(reg.f[B] == fcp[0] && reg.f[B+1] == fcp[1]); + } + NEXTOP; + OP(EQV2_K): + ASSERTF(B+1); ASSERTKF(C+1); + fcp = &konstf[C]; + goto Do_EQV2; + + OP(NEGV3): ASSERTF(a+2); ASSERTF(B+2); reg.f[a] = -reg.f[B]; reg.f[a+1] = -reg.f[B+1]; reg.f[a+2] = -reg.f[B+2]; NEXTOP; - OP(ADDV_RR): + OP(ADDV3_RR): ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C+2); fcp = ®.f[C]; - Do_ADDV: fbp = ®.f[B]; reg.f[a] = fbp[0] + fcp[0]; reg.f[a+1] = fbp[1] + fcp[1]; reg.f[a+2] = fbp[2] + fcp[2]; NEXTOP; - OP(ADDV_RK): - fcp = &konstf[C]; - goto Do_ADDV; - OP(SUBV_RR): + OP(SUBV3_RR): ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C+2); fbp = ®.f[B]; fcp = ®.f[C]; - Do_SUBV: reg.f[a] = fbp[0] - fcp[0]; reg.f[a+1] = fbp[1] - fcp[1]; reg.f[a+2] = fbp[2] - fcp[2]; NEXTOP; - OP(SUBV_RK): - ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C+2); - fbp = ®.f[B]; - fcp = &konstf[C]; - goto Do_SUBV; - OP(SUBV_KR): - ASSERTF(A+2); ASSERTKF(B+2); ASSERTF(C+2); - fbp = &konstf[B]; - fcp = ®.f[C]; - goto Do_SUBV; - OP(DOTV_RR): + OP(DOTV3_RR): ASSERTF(a); ASSERTF(B+2); ASSERTF(C+2); reg.f[a] = reg.f[B] * reg.f[C] + reg.f[B+1] * reg.f[C+1] + reg.f[B+2] * reg.f[C+2]; NEXTOP; - OP(DOTV_RK): - ASSERTF(a); ASSERTF(B+2); ASSERTKF(C+2); - reg.f[a] = reg.f[B] * konstf[C] + reg.f[B+1] * konstf[C+1] + reg.f[B+2] * konstf[C+2]; - NEXTOP; OP(CROSSV_RR): ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C+2); fbp = ®.f[B]; fcp = ®.f[C]; - Do_CROSSV: { double t[3]; t[2] = fbp[0] * fcp[1] - fbp[1] * fcp[0]; @@ -1251,46 +1495,46 @@ begin: reg.f[a] = t[0]; reg.f[a+1] = t[1]; reg.f[a+2] = t[2]; } NEXTOP; - OP(CROSSV_RK): - ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C+2); - fbp = ®.f[B]; - fcp = &konstf[C]; - goto Do_CROSSV; - OP(CROSSV_KR): - ASSERTF(a+2); ASSERTKF(B+2); ASSERTF(C+2); - fbp = ®.f[B]; - fcp = &konstf[C]; - goto Do_CROSSV; - OP(MULVF_RR): + OP(MULVF3_RR): ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C); fc = reg.f[C]; fbp = ®.f[B]; - Do_MULV: + Do_MULV3: reg.f[a] = fbp[0] * fc; reg.f[a+1] = fbp[1] * fc; reg.f[a+2] = fbp[2] * fc; NEXTOP; - OP(MULVF_RK): + OP(MULVF3_RK): ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C); fc = konstf[C]; fbp = ®.f[B]; - goto Do_MULV; - OP(MULVF_KR): - ASSERTF(a+2); ASSERTKF(B+2); ASSERTF(C); - fc = reg.f[C]; - fbp = &konstf[B]; - goto Do_MULV; + goto Do_MULV3; - OP(LENV): + OP(DIVVF3_RR): + ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C); + fc = reg.f[C]; + fbp = ®.f[B]; + Do_DIVV3: + reg.f[a] = fbp[0] / fc; + reg.f[a+1] = fbp[1] / fc; + reg.f[a+2] = fbp[2] / fc; + NEXTOP; + OP(DIVVF3_RK): + ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C); + fc = konstf[C]; + fbp = ®.f[B]; + goto Do_DIVV3; + + OP(LENV3): ASSERTF(a); ASSERTF(B+2); reg.f[a] = g_sqrt(reg.f[B] * reg.f[B] + reg.f[B+1] * reg.f[B+1] + reg.f[B+2] * reg.f[B+2]); NEXTOP; - OP(EQV_R): + OP(EQV3_R): ASSERTF(B+2); ASSERTF(C+2); fcp = ®.f[C]; - Do_EQV: + Do_EQV3: if (a & CMP_APPROX) { CMPJMP(fabs(reg.f[B ] - fcp[0]) < VM_EPSILON && @@ -1302,10 +1546,10 @@ begin: CMPJMP(reg.f[B] == fcp[0] && reg.f[B+1] == fcp[1] && reg.f[B+2] == fcp[2]); } NEXTOP; - OP(EQV_K): + OP(EQV3_K): ASSERTF(B+2); ASSERTKF(C+2); fcp = &konstf[C]; - goto Do_EQV; + goto Do_EQV3; OP(ADDA_RR): ASSERTA(a); ASSERTA(B); ASSERTD(C); @@ -1398,6 +1642,13 @@ begin: // Nothing caught it. Rethrow and let somebody else deal with it. throw; } + catch (CVMAbortException &err) + { + err.MaybePrintMessage(); + err.stacktrace.AppendFormat("Called from %s at %s, line %d\n", sfunc->PrintableName.GetChars(), sfunc->SourceFileName.GetChars(), sfunc->PCToLine(pc)); + // PrintParameters(reg.param + f->NumParam - B, B); + throw; + } return 0; } @@ -1444,23 +1695,43 @@ static void DoCast(const VMRegisters ®, const VMFrame *f, int a, int b, int c ASSERTF(a); ASSERTD(b); reg.f[a] = reg.d[b]; break; + case CAST_U2F: + ASSERTF(a); ASSERTD(b); + reg.f[a] = unsigned(reg.d[b]); + break; case CAST_I2S: ASSERTS(a); ASSERTD(b); reg.s[a].Format("%d", reg.d[b]); break; + case CAST_U2S: + ASSERTS(a); ASSERTD(b); + reg.s[a].Format("%u", reg.d[b]); + break; case CAST_F2I: ASSERTD(a); ASSERTF(b); reg.d[a] = (int)reg.f[b]; break; + case CAST_F2U: + ASSERTD(a); ASSERTF(b); + reg.d[a] = (int)(unsigned)reg.f[b]; + break; case CAST_F2S: - ASSERTS(a); ASSERTD(b); - reg.s[a].Format("%.14g", reg.f[b]); + ASSERTS(a); ASSERTF(b); + reg.s[a].Format("%.5f", reg.f[b]); // keep this small. For more precise conversion there should be a conversion function. + break; + case CAST_V22S: + ASSERTS(a); ASSERTF(b+1); + reg.s[a].Format("(%.5f, %.5f)", reg.f[b], reg.f[b + 1]); + break; + case CAST_V32S: + ASSERTS(a); ASSERTF(b + 2); + reg.s[a].Format("(%.5f, %.5f, %.5f)", reg.f[b], reg.f[b + 1], reg.f[b + 2]); break; case CAST_P2S: ASSERTS(a); ASSERTA(b); - reg.s[a].Format("%s<%p>", reg.atag[b] == ATAG_OBJECT ? "Object" : "Pointer", reg.a[b]); + reg.s[a].Format("%s<%p>", reg.atag[b] == ATAG_OBJECT ? (reg.a[b] == nullptr? "Object" : ((DObject*)reg.a[b])->GetClass()->TypeName.GetChars() ) : "Pointer", reg.a[b]); break; case CAST_S2I: @@ -1472,6 +1743,52 @@ static void DoCast(const VMRegisters ®, const VMFrame *f, int a, int b, int c reg.f[a] = reg.s[b].ToDouble(); break; + case CAST_S2N: + ASSERTD(a); ASSERTS(b); + reg.d[a] = reg.s[b].Len() == 0? FName(NAME_None) : FName(reg.s[b]); + break; + + case CAST_N2S: + { + ASSERTS(a); ASSERTD(b); + FName name = FName(ENamedName(reg.d[b])); + reg.s[a] = name.IsValidName() ? name.GetChars() : ""; + break; + } + + case CAST_S2Co: + ASSERTD(a); ASSERTS(b); + reg.d[a] = V_GetColor(NULL, reg.s[b]); + break; + + case CAST_Co2S: + ASSERTS(a); ASSERTD(b); + reg.s[a].Format("%02x %02x %02x", PalEntry(reg.d[b]).r, PalEntry(reg.d[b]).g, PalEntry(reg.d[b]).b); + break; + + case CAST_S2So: + ASSERTD(a); ASSERTS(b); + reg.d[a] = FSoundID(reg.s[b]); + break; + + case CAST_So2S: + ASSERTS(a); ASSERTD(b); + reg.s[a] = S_sfx[reg.d[b]].name; + break; + + case CAST_SID2S: + ASSERTS(a); ASSERTD(b); + reg.s[a] = unsigned(reg.d[b]) >= sprites.Size() ? "TNT1" : sprites[reg.d[b]].name; + break; + + case CAST_TID2S: + { + ASSERTS(a); ASSERTD(b); + auto tex = TexMan[*(FTextureID*)&(reg.d[b])]; + reg.s[a] = tex == nullptr ? "(null)" : tex->Name.GetChars(); + break; + } + default: assert(0); } @@ -1564,18 +1881,22 @@ static void SetReturn(const VMRegisters ®, VMFrame *frame, VMReturn *ret, VM_ case REGT_FLOAT: if (regtype & REGT_KONST) { - assert(regnum + ((regtype & REGT_KONST) ? 2u : 0u) < func->NumKonstF); + assert(regnum < func->NumKonstF); src = &func->KonstF[regnum]; } else { - assert(regnum + ((regtype & REGT_KONST) ? 2u : 0u) < frame->NumRegF); + assert(regnum < frame->NumRegF); src = ®.f[regnum]; } - if (regtype & REGT_MULTIREG) + if (regtype & REGT_MULTIREG3) { ret->SetVector((double *)src); } + else if (regtype & REGT_MULTIREG2) + { + ret->SetVector2((double *)src); + } else { ret->SetFloat(*(double *)src); diff --git a/src/zscript/vmframe.cpp b/src/scripting/vm/vmframe.cpp similarity index 58% rename from src/zscript/vmframe.cpp rename to src/scripting/vm/vmframe.cpp index 50c7d78d9e..f9f04e4258 100644 --- a/src/zscript/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -1,22 +1,62 @@ -#include -#include "vm.h" +/* +** vmframe.cpp +** +**--------------------------------------------------------------------------- +** Copyright -2016 Randy Heit +** Copyright 2016 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ -IMPLEMENT_CLASS(VMException) -IMPLEMENT_ABSTRACT_POINTY_CLASS(VMFunction) - DECLARE_POINTER(Proto) -END_POINTERS -IMPLEMENT_CLASS(VMScriptFunction) -IMPLEMENT_CLASS(VMNativeFunction) +#include +#include "dobject.h" +#include "v_text.h" + +IMPLEMENT_CLASS(VMException, false, false) +IMPLEMENT_CLASS(VMFunction, true, true) + +IMPLEMENT_POINTERS_START(VMFunction) + IMPLEMENT_POINTER(Proto) +IMPLEMENT_POINTERS_END + +IMPLEMENT_CLASS(VMScriptFunction, false, false) +IMPLEMENT_CLASS(VMNativeFunction, false, false) VMScriptFunction::VMScriptFunction(FName name) { Native = false; Name = name; + LineInfo = nullptr; Code = NULL; KonstD = NULL; KonstF = NULL; KonstS = NULL; KonstA = NULL; + LineInfoCount = 0; ExtraSpace = 0; CodeSize = 0; NumRegD = 0; @@ -46,22 +86,35 @@ VMScriptFunction::~VMScriptFunction() } } -void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta) +void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta, int numlinenumbers) { assert(Code == NULL); assert(numops > 0); - assert(numkonstd >= 0 && numkonstd <= 255); - assert(numkonstf >= 0 && numkonstf <= 255); - assert(numkonsts >= 0 && numkonsts <= 255); - assert(numkonsta >= 0 && numkonsta <= 255); + assert(numkonstd >= 0 && numkonstd <= 65535); + assert(numkonstf >= 0 && numkonstf <= 65535); + assert(numkonsts >= 0 && numkonsts <= 65535); + assert(numkonsta >= 0 && numkonsta <= 65535); + assert(numlinenumbers >= 0 && numlinenumbers <= 65535); void *mem = M_Malloc(numops * sizeof(VMOP) + numkonstd * sizeof(int) + numkonstf * sizeof(double) + numkonsts * sizeof(FString) + - numkonsta * (sizeof(FVoidObj) + 1)); + numkonsta * (sizeof(FVoidObj) + 1) + + numlinenumbers * sizeof(FStatementInfo)); Code = (VMOP *)mem; mem = (void *)((VMOP *)mem + numops); + if (numlinenumbers > 0) + { + LineInfo = (FStatementInfo*)mem; + LineInfoCount = numlinenumbers; + mem = LineInfo + numlinenumbers; + } + else + { + LineInfo = nullptr; + LineInfoCount = 0; + } if (numkonstd > 0) { KonstD = (int *)mem; @@ -126,6 +179,48 @@ size_t VMScriptFunction::PropagateMark() return NumKonstA * sizeof(void *) + Super::PropagateMark(); } +void VMScriptFunction::InitExtra(void *addr) +{ + char *caddr = (char*)addr; + + for (auto tao : SpecialInits) + { + tao.first->InitializeValue(caddr + tao.second, nullptr); + } +} + +void VMScriptFunction::DestroyExtra(void *addr) +{ + char *caddr = (char*)addr; + + for (auto tao : SpecialInits) + { + tao.first->DestroyValue(caddr + tao.second); + } +} + +int VMScriptFunction::AllocExtraStack(PType *type) +{ + int address = ((ExtraSpace + type->Align - 1) / type->Align) * type->Align; + ExtraSpace = address + type->Size; + type->SetDefaultValue(nullptr, address, &SpecialInits); + return address; +} + +int VMScriptFunction::PCToLine(const VMOP *pc) +{ + int PCIndex = int(pc - Code); + if (LineInfoCount == 1) return LineInfo[0].LineNumber; + for (unsigned i = 1; i < LineInfoCount; i++) + { + if (LineInfo[i].InstructionIndex > PCIndex) + { + return LineInfo[i - 1].LineNumber; + } + } + return -1; +} + //=========================================================================== // // VMFrame :: InitRegS @@ -187,34 +282,6 @@ VMFrameStack::~VMFrameStack() UnusedBlocks = NULL; } -//=========================================================================== -// -// VMFrameStack :: AllocFrame -// -// Allocates a frame from the stack with the desired number of registers. -// -//=========================================================================== - -VMFrame *VMFrameStack::AllocFrame(int numregd, int numregf, int numregs, int numrega) -{ - assert((unsigned)numregd < 255); - assert((unsigned)numregf < 255); - assert((unsigned)numregs < 255); - assert((unsigned)numrega < 255); - // To keep the arguments to this function simpler, it assumes that every - // register might be used as a parameter for a single call. - int numparam = numregd + numregf + numregs + numrega; - int size = VMFrame::FrameSize(numregd, numregf, numregs, numrega, numparam, 0); - VMFrame *frame = Alloc(size); - frame->NumRegD = numregd; - frame->NumRegF = numregf; - frame->NumRegS = numregs; - frame->NumRegA = numrega; - frame->MaxParam = numparam; - frame->InitRegS(); - return frame; -} - //=========================================================================== // // VMFrameStack :: AllocFrame @@ -237,6 +304,10 @@ VMFrame *VMFrameStack::AllocFrame(VMScriptFunction *func) frame->MaxParam = func->MaxParam; frame->Func = func; frame->InitRegS(); + if (func->SpecialInits.Size()) + { + func->InitExtra(frame->GetExtra()); + } return frame; } @@ -322,6 +393,11 @@ VMFrame *VMFrameStack::PopFrame() { return NULL; } + auto Func = static_cast(frame->Func); + if (Func->SpecialInits.Size()) + { + Func->DestroyExtra(frame->GetExtra()); + } // Free any string registers this frame had. FString *regs = frame->GetRegS(); for (int i = frame->NumRegS; i != 0; --i) @@ -377,12 +453,13 @@ VMFrame *VMFrameStack::PopFrame() int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults, VMException **trap) { + assert(this == &GlobalVMStack); // why would anyone even want to create a local stack? bool allocated = false; try - { + { if (func->Native) { - return static_cast(func)->NativeCall(this, params, numparams, results, numresults); + return static_cast(func)->NativeCall(params, func->DefaultArgs, numparams, results, numresults); } else { @@ -407,48 +484,6 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur } throw; } - catch (EVMAbortException exception) - { - if (allocated) - { - PopFrame(); - } - if (trap != nullptr) - { - *trap = nullptr; - } - - Printf("VM execution aborted: "); - switch (exception) - { - case X_READ_NIL: - Printf("tried to read from address zero."); - break; - - case X_WRITE_NIL: - Printf("tried to write to address zero."); - break; - - case X_TOO_MANY_TRIES: - Printf("too many try-catch blocks."); - break; - - case X_ARRAY_OUT_OF_BOUNDS: - Printf("array access out of bounds."); - break; - - case X_DIVISION_BY_ZERO: - Printf("division by zero."); - break; - - case X_BAD_SELF: - Printf("invalid self pointer."); - break; - } - Printf("\n"); - - return -1; - } catch (...) { if (allocated) @@ -458,3 +493,83 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur throw; } } + +// Exception stuff for the VM is intentionally placed there, because having this in vmexec.cpp would subject it to inlining +// which we do not want because it increases the local stack requirements of Exec which are already too high. +FString CVMAbortException::stacktrace; + +CVMAbortException::CVMAbortException(EVMAbortException reason, const char *moreinfo, va_list ap) +{ + SetMessage("VM execution aborted: "); + switch (reason) + { + case X_READ_NIL: + AppendMessage("tried to read from address zero."); + break; + + case X_WRITE_NIL: + AppendMessage("tried to write to address zero."); + break; + + case X_TOO_MANY_TRIES: + AppendMessage("too many try-catch blocks."); + break; + + case X_ARRAY_OUT_OF_BOUNDS: + AppendMessage("array access out of bounds."); + break; + + case X_DIVISION_BY_ZERO: + AppendMessage("division by zero."); + break; + + case X_BAD_SELF: + AppendMessage("invalid self pointer."); + break; + + default: + { + size_t len = strlen(m_Message); + mysnprintf(m_Message + len, MAX_ERRORTEXT - len, "Unknown reason %d", reason); + break; + } + } + if (moreinfo != nullptr) + { + AppendMessage(" "); + size_t len = strlen(m_Message); + myvsnprintf(m_Message + len, MAX_ERRORTEXT - len, moreinfo, ap); + } + stacktrace = ""; +} + +// Print this only once on the first catch block. +void CVMAbortException::MaybePrintMessage() +{ + auto m = GetMessage(); + if (m != nullptr) + { + Printf(TEXTCOLOR_RED); + Printf("%s\n", m); + SetMessage(""); + } +} + + +void ThrowAbortException(EVMAbortException reason, const char *moreinfo, ...) +{ + va_list ap; + va_start(ap, moreinfo); + throw CVMAbortException(reason, moreinfo, ap); + va_end(ap); +} + +void NullParam(const char *varname) +{ + ThrowAbortException(X_READ_NIL, "In function parameter %s", varname); +} + +void ThrowVMException(VMException *x) +{ + throw x; +} diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h new file mode 100644 index 0000000000..889706726c --- /dev/null +++ b/src/scripting/vm/vmops.h @@ -0,0 +1,253 @@ +#ifndef xx +#define xx(op, name, mode, alt, kreg, ktype) OP_##op +#endif + +// first row is the opcode +// second row is the disassembly name +// third row is the disassembly flags +// fourth row is the alternative opcode if all 256 constant registers are exhausted. +// fifth row is the constant register index in the opcode +// sixth row is the constant register type. +// OP_PARAM and OP_CMPS need special treatment because they encode this information in the instruction. + +xx(NOP, nop, NOP, NOP, 0, 0), // no operation + +// Load constants. +xx(LI, li, LI, NOP, 0, 0), // load immediate signed 16-bit constant +xx(LK, lk, LKI, NOP, 0, 0), // load integer constant +xx(LKF, lk, LKF, NOP, 0, 0), // load float constant +xx(LKS, lk, LKS, NOP, 0, 0), // load string constant +xx(LKP, lk, LKP, NOP, 0, 0), // load pointer constant +xx(LK_R, lk, RIRII8, NOP, 0, 0), // load integer constant indexed +xx(LKF_R, lk, RFRII8, NOP, 0, 0), // load float constant indexed +xx(LKS_R, lk, RSRII8, NOP, 0, 0), // load string constant indexed +xx(LKP_R, lk, RPRII8, NOP, 0, 0), // load pointer constant indexed +xx(LFP, lf, LFP, NOP, 0, 0), // load frame pointer +xx(META, meta, RPRP, NOP, 0, 0), // load a class's meta class address + +// Load from memory. rA = *(rB + rkC) +xx(LB, lb, RIRPKI, LB_R, 4, REGT_INT), // load byte +xx(LB_R, lb, RIRPRI, NOP, 0, 0), +xx(LH, lh, RIRPKI, LH_R, 4, REGT_INT), // load halfword +xx(LH_R, lh, RIRPRI, NOP, 0, 0), +xx(LW, lw, RIRPKI, LW_R, 4, REGT_INT), // load word +xx(LW_R, lw, RIRPRI, NOP, 0, 0), +xx(LBU, lbu, RIRPKI, LBU_R, 4, REGT_INT), // load byte unsigned +xx(LBU_R, lbu, RIRPRI, NOP, 0, 0), +xx(LHU, lhu, RIRPKI, LHU_R, 4, REGT_INT), // load halfword unsigned +xx(LHU_R, lhu, RIRPRI, NOP, 0, 0), +xx(LSP, lsp, RFRPKI, LSP_R, 4, REGT_INT), // load single-precision fp +xx(LSP_R, lsp, RFRPRI, NOP, 0, 0), +xx(LDP, ldp, RFRPKI, LDP_R, 4, REGT_INT), // load double-precision fp +xx(LDP_R, ldp, RFRPRI, NOP, 0, 0), +xx(LS, ls, RSRPKI, LS_R, 4, REGT_INT), // load string +xx(LS_R, ls, RSRPRI, NOP, 0, 0), +xx(LO, lo, RPRPKI, LO_R, 4, REGT_INT), // load object +xx(LO_R, lo, RPRPRI, NOP, 0, 0), +xx(LP, lp, RPRPKI, LP_R, 4, REGT_INT), // load pointer +xx(LP_R, lp, RPRPRI, NOP, 0, 0), +xx(LV2, lv2, RVRPKI, LV2_R, 4, REGT_INT), // load vector2 +xx(LV2_R, lv2, RVRPRI, NOP, 0, 0), +xx(LV3, lv3, RVRPKI, LV3_R, 4, REGT_INT), // load vector3 +xx(LV3_R, lv3, RVRPRI, NOP, 0, 0), + +xx(LBIT, lbit, RIRPI8, NOP, 0, 0), // rA = !!(*rB & C) -- *rB is a byte + +// Store instructions. *(rA + rkC) = rB +xx(SB, sb, RPRIKI, SB_R, 4, REGT_INT), // store byte +xx(SB_R, sb, RPRIRI, NOP, 0, 0), +xx(SH, sh, RPRIKI, SH_R, 4, REGT_INT), // store halfword +xx(SH_R, sh, RPRIRI, NOP, 0, 0), +xx(SW, sw, RPRIKI, SW_R, 4, REGT_INT), // store word +xx(SW_R, sw, RPRIRI, NOP, 0, 0), +xx(SSP, ssp, RPRFKI, SSP_R, 4, REGT_INT), // store single-precision fp +xx(SSP_R, ssp, RPRFRI, NOP, 0, 0), +xx(SDP, sdp, RPRFKI, SDP_R, 4, REGT_INT), // store double-precision fp +xx(SDP_R, sdp, RPRFRI, NOP, 0, 0), +xx(SS, ss, RPRSKI, SS_R, 4, REGT_INT), // store string +xx(SS_R, ss, RPRSRI, NOP, 0, 0), +xx(SP, sp, RPRPKI, SP_R, 4, REGT_INT), // store pointer +xx(SP_R, sp, RPRPRI, NOP, 0, 0), +xx(SV2, sv2, RPRVKI, SV2_R, 4, REGT_INT), // store vector2 +xx(SV2_R, sv2, RPRVRI, NOP, 0, 0), +xx(SV3, sv3, RPRVKI, SV3_R, 4, REGT_INT), // store vector3 +xx(SV3_R, sv3, RPRVRI, NOP, 0, 0), + +xx(SBIT, sbit, RPRII8, NOP, 0, 0), // *rA |= C if rB is true, *rA &= ~C otherwise + +// Move instructions. +xx(MOVE, mov, RIRI, NOP, 0, 0), // dA = dB +xx(MOVEF, mov, RFRF, NOP, 0, 0), // fA = fB +xx(MOVES, mov, RSRS, NOP, 0, 0), // sA = sB +xx(MOVEA, mov, RPRP, NOP, 0, 0), // aA = aB +xx(MOVEV2, mov2, RFRF, NOP, 0, 0), // fA = fB (2 elements) +xx(MOVEV3, mov3, RFRF, NOP, 0, 0), // fA = fB (3 elements) +xx(CAST, cast, CAST, NOP, 0, 0), // xA = xB, conversion specified by C +xx(CASTB, castb, CAST, NOP, 0, 0), // xA = !!xB, type specified by C +xx(DYNCAST_R, dyncast, RPRPRP, NOP, 0, 0), // aA = dyn_cast(aB); +xx(DYNCAST_K, dyncast, RPRPKP, NOP, 0, 0), // aA = dyn_cast(aB); + +// Control flow. +xx(TEST, test, RII16, NOP, 0, 0), // if (dA != BC) then pc++ +xx(TESTN, testn, RII16, NOP, 0, 0), // if (dA != -BC) then pc++ +xx(JMP, jmp, I24, NOP, 0, 0), // pc += ABC -- The ABC fields contain a signed 24-bit offset. +xx(IJMP, ijmp, RII16, NOP, 0, 0), // pc += dA + BC -- BC is a signed offset. The target instruction must be a JMP. +xx(PARAM, param, __BCP, NOP, 0, 0), // push parameter encoded in BC for function call (B=regtype, C=regnum) +xx(PARAMI, parami, I24, NOP, 0, 0), // push immediate, signed integer for function call +xx(CALL, call, RPI8I8, NOP, 0, 0), // Call function pkA with parameter count B and expected result count C +xx(CALL_K, call, KPI8I8, CALL, 1, REGT_POINTER), +xx(VTBL, vtbl, RPRPI8, NOP, 0, 0), // dereferences a virtual method table. +xx(TAIL, tail, RPI8, NOP, 0, 0), // Call+Ret in a single instruction +xx(TAIL_K, tail, KPI8, TAIL, 1, REGT_POINTER), +xx(RESULT, result, __BCP, NOP, 0, 0), // Result should go in register encoded in BC (in caller, after CALL) +xx(RET, ret, I8BCP, NOP, 0, 0), // Copy value from register encoded in BC to return value A, possibly returning +xx(RETI, reti, I8I16, NOP, 0, 0), // Copy immediate from BC to return value A, possibly returning +xx(TRY, try, I24, NOP, 0, 0), // When an exception is thrown, start searching for a handler at pc + ABC +xx(UNTRY, untry, I8, NOP, 0, 0), // Pop A entries off the exception stack +xx(THROW, throw, THROW, NOP, 0, 0), // A == 0: Throw exception object pB + // A == 1: Throw exception object pkB + // A >= 2: Throw VM exception of type BC +xx(CATCH, catch, CATCH, NOP, 0, 0), // A == 0: continue search on next try + // A == 1: continue execution at instruction immediately following CATCH (catches any exception) + // A == 2: (pB == ) then pc++ ; next instruction must JMP to another CATCH + // A == 3: (pkB == ) then pc++ ; next instruction must JMP to another CATCH + // for A > 0, exception is stored in pC +xx(BOUND, bound, RII16, NOP, 0, 0), // if rA >= BC, throw exception +xx(BOUND_K, bound, LKI, NOP, 0, 0), // if rA >= const[BC], throw exception +xx(BOUND_R, bound, RIRI, NOP, 0, 0), // if rA >= rB, throw exception + +// String instructions. +xx(CONCAT, concat, RSRSRS, NOP, 0, 0), // sA = sB..sC +xx(LENS, lens, RIRS, NOP, 0, 0), // dA = sB.Length +xx(CMPS, cmps, I8RXRX, NOP, 0, 0), // if ((skB op skC) != (A & 1)) then pc++ + +// Integer math. +xx(SLL_RR, sll, RIRIRI, NOP, 0, 0), // dA = dkB << diC +xx(SLL_RI, sll, RIRII8, NOP, 0, 0), +xx(SLL_KR, sll, RIKIRI, SLL_RR, 2, REGT_INT), +xx(SRL_RR, srl, RIRIRI, NOP, 0, 0), // dA = dkB >> diC -- unsigned +xx(SRL_RI, srl, RIRII8, NOP, 0, 0), +xx(SRL_KR, srl, RIKIRI, SRL_RR, 2, REGT_INT), +xx(SRA_RR, sra, RIRIRI, NOP, 0, 0), // dA = dkB >> diC -- signed +xx(SRA_RI, sra, RIRII8, NOP, 0, 0), +xx(SRA_KR, sra, RIKIRI, SRA_RR, 2, REGT_INT), +xx(ADD_RR, add, RIRIRI, NOP, 0, 0), // dA = dB + dkC +xx(ADD_RK, add, RIRIKI, ADD_RR, 4, REGT_INT), +xx(ADDI, addi, RIRIIs, NOP, 0, 0), // dA = dB + C -- C is a signed 8-bit constant +xx(SUB_RR, sub, RIRIRI, NOP, 0, 0), // dA = dkB - dkC +xx(SUB_RK, sub, RIRIKI, SUB_RR, 4, REGT_INT), +xx(SUB_KR, sub, RIKIRI, SUB_RR, 2, REGT_INT), +xx(MUL_RR, mul, RIRIRI, NOP, 0, 0), // dA = dB * dkC +xx(MUL_RK, mul, RIRIKI, MUL_RR, 4, REGT_INT), +xx(DIV_RR, div, RIRIRI, NOP, 0, 0), // dA = dkB / dkC (signed) +xx(DIV_RK, div, RIRIKI, DIV_RR, 4, REGT_INT), +xx(DIV_KR, div, RIKIRI, DIV_RR, 2, REGT_INT), +xx(DIVU_RR, divu, RIRIRI, NOP, 0, 0), // dA = dkB / dkC (unsigned) +xx(DIVU_RK, divu, RIRIKI, DIVU_RR,4, REGT_INT), +xx(DIVU_KR, divu, RIKIRI, DIVU_RR,2, REGT_INT), +xx(MOD_RR, mod, RIRIRI, NOP, 0, 0), // dA = dkB % dkC (signed) +xx(MOD_RK, mod, RIRIKI, MOD_RR, 4, REGT_INT), +xx(MOD_KR, mod, RIKIRI, MOD_RR, 2, REGT_INT), +xx(MODU_RR, modu, RIRIRI, NOP, 0, 0), // dA = dkB % dkC (unsigned) +xx(MODU_RK, modu, RIRIKI, MODU_RR,4, REGT_INT), +xx(MODU_KR, modu, RIKIRI, MODU_RR,2, REGT_INT), +xx(AND_RR, and, RIRIRI, NOP, 0, 0), // dA = dB & dkC +xx(AND_RK, and, RIRIKI, AND_RR, 4, REGT_INT), +xx(OR_RR, or, RIRIRI, NOP, 0, 0), // dA = dB | dkC +xx(OR_RK, or, RIRIKI, OR_RR, 4, REGT_INT), +xx(XOR_RR, xor, RIRIRI, NOP, 0, 0), // dA = dB ^ dkC +xx(XOR_RK, xor, RIRIKI, XOR_RR, 4, REGT_INT), +xx(MIN_RR, min, RIRIRI, NOP, 0, 0), // dA = min(dB,dkC) +xx(MIN_RK, min, RIRIKI, MIN_RR, 4, REGT_INT), +xx(MAX_RR, max, RIRIRI, NOP, 0, 0), // dA = max(dB,dkC) +xx(MAX_RK, max, RIRIKI, MAX_RR, 4, REGT_INT), +xx(ABS, abs, RIRI, NOP, 0, 0), // dA = abs(dB) +xx(NEG, neg, RIRI, NOP, 0, 0), // dA = -dB +xx(NOT, not, RIRI, NOP, 0, 0), // dA = ~dB +xx(SEXT, sext, RIRII8, NOP, 0, 0), // dA = dB, sign extended by shifting left then right by C +xx(ZAP_R, zap, RIRIRI, NOP, 0, 0), // dA = dB, with bytes zeroed where bits in C/dC are one +xx(ZAP_I, zap, RIRII8, NOP, 0, 0), +xx(ZAPNOT_R, zapnot, RIRIRI, NOP, 0, 0), // dA = dB, with bytes zeroed where bits in C/dC are zero +xx(ZAPNOT_I, zapnot, RIRII8, NOP, 0, 0), +xx(EQ_R, beq, CIRR, NOP, 0, 0), // if ((dB == dkC) != A) then pc++ +xx(EQ_K, beq, CIRK, EQ_R, 4, REGT_INT), +xx(LT_RR, blt, CIRR, NOP, 0, 0), // if ((dkB < dkC) != A) then pc++ +xx(LT_RK, blt, CIRK, LT_RR, 4, REGT_INT), +xx(LT_KR, blt, CIKR, LT_RR, 2, REGT_INT), +xx(LE_RR, ble, CIRR, NOP, 0, 0), // if ((dkB <= dkC) != A) then pc++ +xx(LE_RK, ble, CIRK, LE_RR, 4, REGT_INT), +xx(LE_KR, ble, CIKR, LE_RR, 2, REGT_INT), +xx(LTU_RR, bltu, CIRR, NOP, 0, 0), // if ((dkB < dkC) != A) then pc++ -- unsigned +xx(LTU_RK, bltu, CIRK, LTU_RR, 4, REGT_INT), +xx(LTU_KR, bltu, CIKR, LTU_RR, 2, REGT_INT), +xx(LEU_RR, bleu, CIRR, NOP, 0, 0), // if ((dkB <= dkC) != A) then pc++ -- unsigned +xx(LEU_RK, bleu, CIRK, LEU_RR, 4, REGT_INT), +xx(LEU_KR, bleu, CIKR, LEU_RR, 2, REGT_INT), + +// Double-precision floating point math. +xx(ADDF_RR, add, RFRFRF, NOP, 0, 0), // fA = fB + fkC +xx(ADDF_RK, add, RFRFKF, ADDF_RR,4, REGT_FLOAT), +xx(SUBF_RR, sub, RFRFRF, NOP, 0, 0), // fA = fkB - fkC +xx(SUBF_RK, sub, RFRFKF, SUBF_RR,4, REGT_FLOAT), +xx(SUBF_KR, sub, RFKFRF, SUBF_RR,2, REGT_FLOAT), +xx(MULF_RR, mul, RFRFRF, NOP, 0, 0), // fA = fB * fkC +xx(MULF_RK, mul, RFRFKF, MULF_RR,4, REGT_FLOAT), +xx(DIVF_RR, div, RFRFRF, NOP, 0, 0), // fA = fkB / fkC +xx(DIVF_RK, div, RFRFKF, DIVF_RR,4, REGT_FLOAT), +xx(DIVF_KR, div, RFKFRF, DIVF_RR,2, REGT_FLOAT), +xx(MODF_RR, mod, RFRFRF, NOP, 0, 0), // fA = fkB % fkC +xx(MODF_RK, mod, RFRFKF, MODF_RR,4, REGT_FLOAT), +xx(MODF_KR, mod, RFKFRF, MODF_RR,4, REGT_FLOAT), +xx(POWF_RR, pow, RFRFRF, NOP, 0, 0), // fA = fkB ** fkC +xx(POWF_RK, pow, RFRFKF, POWF_RR,4, REGT_FLOAT), +xx(POWF_KR, pow, RFKFRF, POWF_RR,2, REGT_FLOAT), +xx(MINF_RR, min, RFRFRF, NOP, 0, 0), // fA = min(fB),fkC) +xx(MINF_RK, min, RFRFKF, MINF_RR,4, REGT_FLOAT), +xx(MAXF_RR, max, RFRFRF, NOP, 0, 0), // fA = max(fB),fkC) +xx(MAXF_RK, max, RFRFKF, MAXF_RR,4, REGT_FLOAT), +xx(ATAN2, atan2, RFRFRF, NOP, 0, 0), // fA = atan2(fB,fC), result is in degrees +xx(FLOP, flop, RFRFI8, NOP, 0, 0), // fA = f(fB), where function is selected by C +xx(EQF_R, beq, CFRR, NOP, 0, 0), // if ((fB == fkC) != (A & 1)) then pc++ +xx(EQF_K, beq, CFRK, EQF_R, 4, REGT_FLOAT), +xx(LTF_RR, blt, CFRR, NOP, 0, 0), // if ((fkB < fkC) != (A & 1)) then pc++ +xx(LTF_RK, blt, CFRK, LTF_RR, 4, REGT_FLOAT), +xx(LTF_KR, blt, CFKR, LTF_RR, 2, REGT_FLOAT), +xx(LEF_RR, ble, CFRR, NOP, 0, 0), // if ((fkb <= fkC) != (A & 1)) then pc++ +xx(LEF_RK, ble, CFRK, LEF_RR, 4, REGT_FLOAT), +xx(LEF_KR, ble, CFKR, LEF_RR, 2, REGT_FLOAT), + +// Vector math. (2D) +xx(NEGV2, negv2, RVRV, NOP, 0, 0), // vA = -vB +xx(ADDV2_RR, addv2, RVRVRV, NOP, 0, 0), // vA = vB + vkC +xx(SUBV2_RR, subv2, RVRVRV, NOP, 0, 0), // vA = vkB - vkC +xx(DOTV2_RR, dotv2, RVRVRV, NOP, 0, 0), // va = vB dot vkC +xx(MULVF2_RR, mulv2, RVRVRF, NOP, 0, 0), // vA = vkB * fkC +xx(MULVF2_RK, mulv2, RVRVKF, MULVF2_RR,4, REGT_FLOAT), +xx(DIVVF2_RR, divv2, RVRVRF, NOP, 0, 0), // vA = vkB / fkC +xx(DIVVF2_RK, divv2, RVRVKF, DIVVF2_RR,4, REGT_FLOAT), +xx(LENV2, lenv2, RFRV, NOP, 0, 0), // fA = vB.Length +xx(EQV2_R, beqv2, CVRR, NOP, 0, 0), // if ((vB == vkC) != A) then pc++ (inexact if A & 32) +xx(EQV2_K, beqv2, CVRK, NOP, 0, 0), // this will never be used. + +// Vector math (3D) +xx(NEGV3, negv3, RVRV, NOP, 0, 0), // vA = -vB +xx(ADDV3_RR, addv3, RVRVRV, NOP, 0, 0), // vA = vB + vkC +xx(SUBV3_RR, subv3, RVRVRV, NOP, 0, 0), // vA = vkB - vkC +xx(DOTV3_RR, dotv3, RVRVRV, NOP, 0, 0), // va = vB dot vkC +xx(CROSSV_RR, crossv, RVRVRV, NOP, 0, 0), // vA = vkB cross vkC +xx(MULVF3_RR, mulv3, RVRVRF, NOP, 0, 0), // vA = vkB * fkC +xx(MULVF3_RK, mulv3, RVRVKF, MULVF3_RR,4, REGT_FLOAT), +xx(DIVVF3_RR, divv3, RVRVRF, NOP, 0, 0), // vA = vkB / fkC +xx(DIVVF3_RK, divv3, RVRVKF, DIVVF3_RR,4, REGT_FLOAT), +xx(LENV3, lenv3, RFRV, NOP, 0, 0), // fA = vB.Length +xx(EQV3_R, beqv3, CVRR, NOP, 0, 0), // if ((vB == vkC) != A) then pc++ (inexact if A & 33) +xx(EQV3_K, beqv3, CVRK, NOP, 0, 0), // this will never be used. + +// Pointer math. +xx(ADDA_RR, add, RPRPRI, NOP, 0, 0), // pA = pB + dkC +xx(ADDA_RK, add, RPRPKI, ADDA_RR,4, REGT_POINTER), +xx(SUBA, sub, RIRPRP, NOP, 0, 0), // dA = pB - pC +xx(EQA_R, beq, CPRR, NOP, 0, 0), // if ((pB == pkC) != A) then pc++ +xx(EQA_K, beq, CPRK, EQA_R, 4, REGT_POINTER), + +#undef xx diff --git a/src/zscript/ast.cpp b/src/scripting/zscript/ast.cpp similarity index 81% rename from src/zscript/ast.cpp rename to src/scripting/zscript/ast.cpp index a68b1c69f3..3bdc2e2440 100644 --- a/src/zscript/ast.cpp +++ b/src/scripting/zscript/ast.cpp @@ -1,3 +1,36 @@ +/* +** ast.cpp +** +**--------------------------------------------------------------------------- +** Copyright -2016 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + #include "dobject.h" #include "sc_man.h" #include "memarena.h" @@ -19,9 +52,13 @@ static const char *BuiltInTypeNames[] = "string", "vector2", "vector3", - "vector4", "name", - "usertype" + "color", + "state", + "sound", + + "usertype", + }; class FLispString @@ -32,7 +69,7 @@ public: FLispString() { NestDepth = Column = 0; - WrapWidth = 72; + WrapWidth = 200; NeedSpace = false; ConsecOpens = 0; } @@ -321,6 +358,7 @@ static void PrintStates(FLispString &out, ZCC_TreeNode *node) ZCC_States *snode = (ZCC_States *)node; out.Break(); out.Open("states"); + PrintNodes(out, snode->Flags, false, true); PrintNodes(out, snode->Body, false, true); out.Close(); } @@ -367,6 +405,7 @@ static void PrintStateGoto(FLispString &out, ZCC_TreeNode *node) { ZCC_StateGoto *snode = (ZCC_StateGoto *)node; out.Open("state-goto"); + PrintNodes(out, snode->Qualifier); PrintNodes(out, snode->Label); PrintNodes(out, snode->Offset); out.Close(); @@ -376,7 +415,8 @@ static void PrintStateLine(FLispString &out, ZCC_TreeNode *node) { ZCC_StateLine *snode = (ZCC_StateLine *)node; out.Open("state-line"); - out.Add(snode->Sprite, 4); + out.Add(*(snode->Sprite)); + PrintNodes(out, snode->Duration); if (snode->bNoDelay) out.Add("nodelay", 7); if (snode->bBright) out.Add("bright", 6); if (snode->bFast) out.Add("fast", 4); @@ -397,6 +437,17 @@ static void PrintVarName(FLispString &out, ZCC_TreeNode *node) out.Close(); } +static void PrintVarInit(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_VarInit *vnode = (ZCC_VarInit *)node; + out.Open("var-init"); + PrintNodes(out, vnode->ArraySize); + PrintNodes(out, vnode->Init); + if (vnode->InitIsArray) out.Add("array", 5); + out.AddName(vnode->Name); + out.Close(); +} + static void PrintType(FLispString &out, ZCC_TreeNode *node) { ZCC_Type *tnode = (ZCC_Type *)node; @@ -534,6 +585,26 @@ static void PrintExprFuncCall(FLispString &out, ZCC_TreeNode *node) out.Close(); } +static void PrintExprClassCast(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_ClassCast *enode = (ZCC_ClassCast *)node; + assert(enode->Operation == PEX_ClassCast); + out.Open("expr-class-cast"); + out.AddName(enode->ClassName); + PrintNodes(out, enode->Parameters, false); + out.Close(); +} + +static void PrintStaticArray(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_StaticArrayStatement *enode = (ZCC_StaticArrayStatement *)node; + out.Open("static-array-stmt"); + PrintNodes(out, enode->Type, false); + out.AddName(enode->Id); + PrintNodes(out, enode->Values, false); + out.Close(); +} + static void PrintExprMemberAccess(FLispString &out, ZCC_TreeNode *node) { ZCC_ExprMemberAccess *enode = (ZCC_ExprMemberAccess *)node; @@ -571,6 +642,16 @@ static void PrintExprTrinary(FLispString &out, ZCC_TreeNode *node) out.Close(); } +static void PrintVectorInitializer(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_VectorValue *enode = (ZCC_VectorValue *)node; + OpenExprType(out, enode->Operation); + PrintNodes(out, enode->X); + PrintNodes(out, enode->Y); + PrintNodes(out, enode->Z); + out.Close(); +} + static void PrintFuncParam(FLispString &out, ZCC_TreeNode *node) { ZCC_FuncParm *pnode = (ZCC_FuncParm *)node; @@ -596,6 +677,15 @@ static void PrintCompoundStmt(FLispString &out, ZCC_TreeNode *node) out.Close(); } +static void PrintDefault(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_Default *snode = (ZCC_Default *)node; + out.Break(); + out.Open("default"); + PrintNodes(out, snode->Content, false, true); + out.Close(); +} + static void PrintContinueStmt(FLispString &out, ZCC_TreeNode *node) { out.Break(); @@ -687,21 +777,6 @@ static void PrintAssignStmt(FLispString &out, ZCC_TreeNode *node) { ZCC_AssignStmt *snode = (ZCC_AssignStmt *)node; out.Open("assign-stmt"); - switch (snode->AssignOp) - { - case ZCC_EQ: out.AddChar('='); break; - case ZCC_MULEQ: out.Add("*=", 2); break; - case ZCC_DIVEQ: out.Add("/=", 2); break; - case ZCC_MODEQ: out.Add("%=", 2); break; - case ZCC_ADDEQ: out.Add("+=", 2); break; - case ZCC_SUBEQ: out.Add("-=", 2); break; - case ZCC_LSHEQ: out.Add("<<=", 2); break; - case ZCC_RSHEQ: out.Add(">>=", 2); break; - case ZCC_ANDEQ: out.Add("&=", 2); break; - case ZCC_OREQ: out.Add("|=", 2); break; - case ZCC_XOREQ: out.Add("^=", 2); break; - default: BadAssignOp(out, snode->AssignOp); break; - } PrintNodes(out, snode->Dests); PrintNodes(out, snode->Sources); out.Close(); @@ -713,7 +788,6 @@ static void PrintLocalVarStmt(FLispString &out, ZCC_TreeNode *node) out.Open("local-var-stmt"); PrintNodes(out, snode->Type); PrintNodes(out, snode->Vars); - PrintNodes(out, snode->Inits); out.Close(); } @@ -725,6 +799,7 @@ static void PrintFuncParamDecl(FLispString &out, ZCC_TreeNode *node) PrintNodes(out, dnode->Type); out.AddName(dnode->Name); out.AddHex(dnode->Flags); + PrintNodes(out, dnode->Default); out.Close(); } @@ -765,6 +840,7 @@ static void PrintFuncDeclarator(FLispString &out, ZCC_TreeNode *node) out.Break(); out.Open("func-declarator"); out.AddHex(dnode->Flags); + PrintNodes(out, dnode->UseFlags); PrintNodes(out, dnode->Type); out.AddName(dnode->Name); PrintNodes(out, dnode->Params); @@ -772,6 +848,36 @@ static void PrintFuncDeclarator(FLispString &out, ZCC_TreeNode *node) out.Close(); } +static void PrintDeclFlags(FLispString &out, ZCC_TreeNode *node) +{ + auto dnode = (ZCC_DeclFlags *)node; + out.Break(); + out.Open("decl-flags"); + out.AddHex(dnode->Flags); + PrintNodes(out, dnode->Id); + out.Close(); +} + +static void PrintFlagStmt(FLispString &out, ZCC_TreeNode *node) +{ + auto dnode = (ZCC_FlagStmt *)node; + out.Break(); + out.Open("flag-stmt"); + PrintNodes(out, dnode->name, false); + out.AddInt(dnode->set); + out.Close(); +} + +static void PrintPropertyStmt(FLispString &out, ZCC_TreeNode *node) +{ + auto dnode = (ZCC_PropertyStmt *)node; + out.Break(); + out.Open("property-stmt"); + PrintNodes(out, dnode->Prop, false); + PrintNodes(out, dnode->Values, false); + out.Close(); +} + void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode *) = { PrintIdentifier, @@ -789,6 +895,7 @@ void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode * PrintStateGoto, PrintStateLine, PrintVarName, + PrintVarInit, PrintType, PrintBasicType, PrintMapType, @@ -820,7 +927,13 @@ void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode * PrintConstantDef, PrintDeclarator, PrintVarDeclarator, - PrintFuncDeclarator + PrintFuncDeclarator, + PrintDefault, + PrintFlagStmt, + PrintPropertyStmt, + PrintVectorInitializer, + PrintDeclFlags, + PrintExprClassCast, }; FString ZCC_PrintAST(ZCC_TreeNode *root) diff --git a/src/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon similarity index 69% rename from src/zscript/zcc-parse.lemon rename to src/scripting/zscript/zcc-parse.lemon index 12cbb6625c..9305b9f71a 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -22,7 +22,7 @@ static void SetNodeLine(ZCC_TreeNode *name, int line) // If a is non-null, appends b to a. Otherwise, sets a to b. #define SAFE_APPEND(a,b) \ - if (a == NULL) a = b; else a->AppendSibling(b); + if (a == NULL) a = b; else AppendTreeNodeSibling(a, b); #define UNARY_EXPR(X,T) NEW_AST_NODE(ExprUnary, expr1, X); expr1->Operation = T; expr1->Operand = X; expr1->Type = NULL #define BINARY_EXPR(X,Y,T) NEW_AST_NODE(ExprBinary, expr2, X); expr2->Operation = T; expr2->Type = NULL; expr2->Left = X; expr2->Right = Y @@ -40,6 +40,7 @@ static void SetNodeLine(ZCC_TreeNode *name, int line) struct StateOpts { ZCC_Expression *Offset; + ZCC_ExprConstant *Lights; bool Bright; bool Fast; bool Slow; @@ -47,7 +48,8 @@ static void SetNodeLine(ZCC_TreeNode *name, int line) bool CanRaise; void Zero() { - Offset = NULL; + Offset = nullptr; + Lights = nullptr; Bright = false; Fast = false; Slow = false; @@ -96,12 +98,13 @@ static void SetNodeLine(ZCC_TreeNode *name, int line) } } } - stat->sc.ScriptMessage("%s\n%s\n", unexpected.GetChars(), expecting.GetChars()); + stat->sc->ScriptMessage("%s\n%s\n", unexpected.GetChars(), expecting.GetChars()); + FScriptPosition::ErrorCounter++; } -%parse_accept { stat->sc.ScriptMessage("input accepted\n"); } +%parse_accept { DPrintf(DMSG_SPAMMY, "Input accepted\n"); } %parse_failure { /**failed = true;*/ } -%nonassoc EQ MULEQ DIVEQ MODEQ ADDEQ SUBEQ LSHEQ RSHEQ ANDEQ OREQ XOREQ. +%right EQ MULEQ DIVEQ MODEQ ADDEQ SUBEQ LSHEQ RSHEQ ANDEQ OREQ XOREQ URSHEQ. %right QUESTION COLON. %left OROR. %left ANDAND. @@ -111,7 +114,7 @@ static void SetNodeLine(ZCC_TreeNode *name, int line) %left OR. /* Note that this is like the Ruby precedence for these */ %left XOR. /* three operators and not the C precedence, since */ %left AND. /* they are higher priority than the comparisons. */ -%left LSH RSH. +%left LSH RSH URSH. %left SUB ADD. %left MUL DIV MOD CROSSPROD DOTPROD. %left POW. @@ -124,7 +127,7 @@ static void SetNodeLine(ZCC_TreeNode *name, int line) %type opt_func_body {ZCC_CompoundStmt *} %type function_body {ZCC_CompoundStmt *} -main ::= translation_unit(A). { stat->TopNode = A; stat->sc.ScriptMessage("Parse complete\n"); } +main ::= translation_unit(A). { stat->TopNode = A; DPrintf(DMSG_SPAMMY, "Parse complete\n"); } %type translation_unit {ZCC_TreeNode *} translation_unit(X) ::= . { X = NULL; } @@ -137,6 +140,7 @@ external_declaration(X) ::= class_definition(A). { X = A; /*X-overwrites-A* external_declaration(X) ::= struct_def(A). { X = A; /*X-overwrites-A*/ } external_declaration(X) ::= enum_def(A). { X = A; /*X-overwrites-A*/ } external_declaration(X) ::= const_def(A). { X = A; /*X-overwrites-A*/ } +external_declaration(X) ::= include_def. { X = nullptr; } /* Optional bits. */ opt_semicolon ::= . @@ -153,6 +157,11 @@ opt_expr(X) ::= . opt_expr(X) ::= expr(X). +include_def ::= INCLUDE string_constant(A). +{ + AddInclude(A); +} + /************ Class Definition ************/ /* Can only occur at global scope. */ @@ -168,6 +177,18 @@ class_definition(X) ::= class_head(A) class_body(B). X = A; /*X-overwrites-A*/ } +class_head(X) ::= EXTEND CLASS(T) IDENTIFIER(A). +{ + NEW_AST_NODE(Class,head,T); + head->NodeName = A.Name(); + head->ParentName = nullptr; + head->Flags = ZCC_Extension; + head->Replaces = nullptr; + head->Type = nullptr; + head->Symbol = nullptr; + X = head; +} + class_head(X) ::= CLASS(T) IDENTIFIER(A) class_ancestry(B) class_flags(C). { NEW_AST_NODE(Class,head,T); @@ -175,6 +196,8 @@ class_head(X) ::= CLASS(T) IDENTIFIER(A) class_ancestry(B) class_flags(C). head->ParentName = B; head->Flags = C.Flags; head->Replaces = C.Replaces; + head->Type = nullptr; + head->Symbol = nullptr; X = head; } @@ -184,8 +207,9 @@ class_ancestry(X) ::= COLON dottable_id(A). { X = A; /*X-overwrites-A*/ } %type class_flags{ClassFlagsBlock} class_flags(X) ::= . { X.Flags = 0; X.Replaces = NULL; } -class_flags(X) ::= class_flags(A) ABSTRACT. { X.Flags = A.Flags | 0/*FIXME*/; X.Replaces = A.Replaces; } -class_flags(X) ::= class_flags(A) NATIVE. { X.Flags = A.Flags | 0/*FIXME*/; X.Replaces = A.Replaces; } +class_flags(X) ::= class_flags(A) ABSTRACT. { X.Flags = A.Flags | ZCC_Abstract; X.Replaces = A.Replaces; } +class_flags(X) ::= class_flags(A) NATIVE. { X.Flags = A.Flags | ZCC_Native; X.Replaces = A.Replaces; } +class_flags(X) ::= class_flags(A) ACTION. { X.Flags = A.Flags | ZCC_Action; X.Replaces = A.Replaces; } class_flags(X) ::= class_flags(A) REPLACES dottable_id(B). { X.Flags = A.Flags; X.Replaces = B; } /*----- Dottable Identifier -----*/ @@ -203,7 +227,25 @@ dottable_id(X) ::= dottable_id(A) DOT IDENTIFIER(B). { NEW_AST_NODE(Identifier,id2,A); id2->Id = B.Name(); - A->AppendSibling(id2); + AppendTreeNodeSibling(A, id2); + X = A; /*X-overwrites-A*/ +} +dottable_id(X) ::= dottable_id(A) DOT DEFAULT. +{ + NEW_AST_NODE(Identifier,id2,A); + id2->Id = NAME_Default; + AppendTreeNodeSibling(A, id2); + X = A; /*X-overwrites-A*/ +} + +// a bit of a hack to allow the 'color' token to be used inside default properties. +// as a variable name it is practically meaningless because it cannot defined +// as such anywhere so it will always produce an error during processing. +dottable_id(X) ::= dottable_id(A) DOT COLOR. +{ + NEW_AST_NODE(Identifier,id2,A); + id2->Id = NAME_Color; + AppendTreeNodeSibling(A, id2); X = A; /*X-overwrites-A*/ } @@ -242,22 +284,30 @@ class_member(X) ::= const_def(A). { X = A; /*X-overwrites-A*/ } %type struct_body{ZCC_TreeNode *} %type struct_member{ZCC_TreeNode *} -struct_def(X) ::= STRUCT(T) IDENTIFIER(A) LBRACE opt_struct_body(B) RBRACE opt_semicolon. +struct_def(X) ::= STRUCT(T) IDENTIFIER(A) struct_flags(S) LBRACE opt_struct_body(B) RBRACE opt_semicolon. { NEW_AST_NODE(Struct,def,T); def->NodeName = A.Name(); def->Body = B; + def->Type = nullptr; + def->Symbol = nullptr; + def->Flags = S.Flags; X = def; } +%type struct_flags{ClassFlagsBlock} +struct_flags(X) ::= . { X.Flags = 0; } +struct_flags(X) ::= NATIVE. { X.Flags = ZCC_Native; } + opt_struct_body(X) ::= . { X = NULL; } opt_struct_body(X) ::= struct_body(X). +opt_struct_body(X) ::= error. { X = NULL; } + -struct_body(X) ::= error. { X = NULL; } struct_body(X) ::= struct_member(X). -struct_body(X) ::= struct_member(A) struct_body(B). { X = A; /*X-overwrites-A*/ X->AppendSibling(B); } +struct_body(X) ::= struct_body(A) struct_member(B). { X = A; /*X-overwrites-A*/ AppendTreeNodeSibling(X, B); } -struct_member(X) ::= declarator_no_fun(A). { X = A; /*X-overwrites-A*/ } +struct_member(X) ::= declarator(A). { X = A; /*X-overwrites-A*/ } struct_member(X) ::= enum_def(A). { X = A; /*X-overwrites-A*/ } struct_member(X) ::= const_def(A). { X = A; /*X-overwrites-A*/ } @@ -286,6 +336,7 @@ enum_def(X) ::= ENUM(T) IDENTIFIER(A) enum_type(B) LBRACE opt_enum_list(C) RBRAC def->NodeName = A.Name(); def->EnumType = (EZCCBuiltinType)B.Int; def->Elements = C; + def->Symbol = nullptr; // If the first element does not have an explicit value, make it 0. if (C != NULL) @@ -330,21 +381,21 @@ enum_def(X) ::= ENUM(T) IDENTIFIER(A) enum_type(B) LBRACE opt_enum_list(C) RBRAC } // Add a new terminating node, to indicate that the ConstantDefs for this enum are done. NEW_AST_NODE(EnumTerminator,term,U); - C->AppendSibling(term); + AppendTreeNodeSibling(C, term); } if (C != NULL) { - def->AppendSibling(C); + AppendTreeNodeSibling(def, C); } X = def; } -enum_type(X) ::= . { X.Int = ZCC_IntAuto; X.SourceLoc = stat->sc.GetMessageLine(); } +enum_type(X) ::= . { X.Int = ZCC_IntAuto; X.SourceLoc = stat->sc->GetMessageLine(); } enum_type(X) ::= COLON int_type(A). { X = A; /*X-overwrites-A*/ } enum_list(X) ::= error. { X = NULL; } enum_list(X) ::= enumerator(X). -enum_list(X) ::= enum_list(A) COMMA enumerator(B). { X = A; /*X-overwrites-A*/ X->AppendSibling(B); } +enum_list(X) ::= enum_list(A) COMMA enumerator(B). { X = A; /*X-overwrites-A*/ AppendTreeNodeSibling(X, B); } opt_enum_list(X) ::= . { X = NULL; } opt_enum_list(X) ::= enum_list(X) opt_comma. @@ -379,14 +430,36 @@ enumerator(X) ::= IDENTIFIER(A) EQ expr(B). /* Expression must be constant. */ %type state_call_params {ZCC_FuncParm *} %type state_opts {StateOpts} +%type states_opts { ZCC_Identifier *} +%type states_opt { ZCC_Identifier *} -states_def(X) ::= STATES(T) scanner_mode LBRACE states_body(A) RBRACE. +states_def(X) ::= STATES(T) states_opts(B) scanner_mode LBRACE states_body(A) RBRACE. { NEW_AST_NODE(States,def,T); + def->Flags = B; def->Body = A; X = def; } +states_opts(X) ::= . { X = nullptr; } +states_opts(X) ::= LPAREN states_opt(A) RPAREN. { X = A; /*X-overwrites-A*/ } + +states_opt(X) ::= IDENTIFIER(A). +{ + NEW_AST_NODE(Identifier,id,A); + id->Id = A.Name(); + X = id; +} + +states_opt(X) ::= states_opt(A) COMMA IDENTIFIER(B). +{ + NEW_AST_NODE(Identifier,id,B); + id->Id = B.Name(); + X = A; /*X-overwrites-A*/ + AppendTreeNodeSibling(X, id); +} + + /* We use a special scanner mode to allow for sprite names and frame characters * to not be quoted even if they contain special characters. The scanner_mode * nonterminal is used to enter this mode. The scanner automatically leaves it @@ -398,7 +471,7 @@ states_def(X) ::= STATES(T) scanner_mode LBRACE states_body(A) RBRACE. * set immediately after LBRACE is consumed, rather than immediately after * STATES is consumed. */ -scanner_mode ::= . { stat->sc.SetStateMode(true); } +scanner_mode ::= . { stat->sc->SetStateMode(true); } states_body(X) ::= . { X = NULL; } states_body(X) ::= error. { X = NULL; } @@ -424,31 +497,50 @@ state_flow_type(X) ::= GOTO(T) dottable_id(A) state_goto_offset(B). NEW_AST_NODE(StateGoto, flow, T); flow->Label = A; flow->Offset = B; + flow->Qualifier = nullptr; + X = flow; +} + +state_flow_type(X) ::= GOTO(T) IDENTIFIER(C) SCOPE dottable_id(A) state_goto_offset(B). +{ + NEW_AST_NODE(StateGoto, flow, T); + flow->Label = A; + flow->Offset = B; + + NEW_AST_NODE(Identifier,id,C); + id->Id = C.Name(); + flow->Qualifier =id; + X = flow; +} + +state_flow_type(X) ::= GOTO(T) SUPER(C) SCOPE dottable_id(A) state_goto_offset(B). +{ + NEW_AST_NODE(StateGoto, flow, T); + flow->Label = A; + flow->Offset = B; + + NEW_AST_NODE(Identifier,id,C); + id->Id = NAME_Super; + flow->Qualifier =id; X = flow; } state_goto_offset(X) ::= . { X = NULL; } -state_goto_offset(X) ::= PLUS expr(A). { X = A; /*X-overwrites-A*/ } /* Must evaluate to a non-negative integer constant. */ +state_goto_offset(X) ::= ADD expr(A). { X = A; /*X-overwrites-A*/ } /* Must evaluate to a non-negative integer constant. */ -state_line(X) ::= NWS(A) NWS(B) expr state_opts(C) state_action(D). +state_line(X) ::= NWS(A) NWS(B) expr(E) state_opts(C) state_action(D). { NEW_AST_NODE(StateLine, line, A); - const char *sprite = FName(A.Name()).GetChars(); - if (strlen(sprite) != 4) - { - Printf("Sprite name '%s' must be four characters", sprite); - } - else - { - memcpy(line->Sprite, sprite, 4); - } + line->Sprite = stat->Strings.Alloc(FName(A.Name()).GetChars()); line->Frames = stat->Strings.Alloc(FName(B.Name()).GetChars()); + line->Duration = E; line->bBright = C.Bright; line->bFast = C.Fast; line->bSlow = C.Slow; line->bNoDelay = C.NoDelay; line->bCanRaise = C.CanRaise; line->Offset = C.Offset; + line->Lights = C.Lights; line->Action = D; X = line; } @@ -459,14 +551,41 @@ state_opts(X) ::= state_opts(A) FAST. { A.Fast = true; X = A; /*X-overwri state_opts(X) ::= state_opts(A) SLOW. { A.Slow = true; X = A; /*X-overwrites-A*/ } state_opts(X) ::= state_opts(A) NODELAY. { A.NoDelay = true; X = A; /*X-overwrites-A*/ } state_opts(X) ::= state_opts(A) CANRAISE. { A.CanRaise = true; X = A; /*X-overwrites-A*/ } -state_opts(X) ::= state_opts(A) OFFSET LPAREN expr(B) COMMA expr(C) RPAREN. { A.Offset = B; B->AppendSibling(C); X = A; /*X-overwrites-A*/ } -state_opts(X) ::= state_opts(A) LIGHT LPAREN light_list RPAREN. { X = A; /*X-overwrites-A*/ } ///FIXME: GZDoom would want to know this +state_opts(X) ::= state_opts(A) OFFSET LPAREN expr(B) COMMA expr(C) RPAREN. { A.Offset = B; AppendTreeNodeSibling(B, C); X = A; /*X-overwrites-A*/ } +state_opts(X) ::= state_opts(A) LIGHT LPAREN light_list(B) RPAREN. { X = A; /*X-overwrites-A*/ X.Lights = B; } -light_list ::= STRCONST. -light_list ::= light_list COMMA STRCONST. +%type light_list {ZCC_ExprConstant *} + +light_list(X) ::= STRCONST(A). +{ + NEW_AST_NODE(ExprConstant, strconst, A); + strconst->Operation = PEX_ConstValue; + strconst->Type = TypeString; + strconst->StringVal = A.String; + X = strconst; +} + +light_list(X) ::= light_list(A) COMMA STRCONST(B). +{ + NEW_AST_NODE(ExprConstant, strconst, B); + strconst->Operation = PEX_ConstValue; + strconst->Type = TypeString; + strconst->StringVal = B.String; + AppendTreeNodeSibling(A, strconst); + X = A; /*X-overwrites-A*/ +} /* A state action can be either a compound statement or a single action function call. */ -state_action(X) ::= LBRACE statement_list(A) scanner_mode RBRACE. { X = A; /*X-overwrites-A*/ } +state_action(X) ::= LBRACE(T) statement_list(A) scanner_mode RBRACE. +{ + NEW_AST_NODE(CompoundStmt,stmt,T); + stmt->Content = A; + X = stmt; +} +state_action(X) ::= LBRACE scanner_mode RBRACE. +{ + X = NULL; +} state_action(X) ::= LBRACE error scanner_mode RBRACE. { X = NULL; } state_action(X) ::= state_call(A) scanner_mode SEMICOLON. { X = A; /*X-overwrites-A*/ } @@ -488,8 +607,81 @@ state_call_params(X) ::= . { X = NULL; } state_call_params(X) ::= LPAREN func_expr_list(A) RPAREN. { X = A; /*X-overwrites-A*/ } /* Definition of a default class instance. */ -%type default_def {ZCC_CompoundStmt *} -default_def(X) ::= DEFAULT compound_statement(A). { X = A; /*X-overwrites-A*/ } +%type default_def {ZCC_Default *} +%type default_statement_list{ZCC_Statement *} +%type default_statement{ZCC_Statement *} + +default_def(X) ::= DEFAULT LBRACE(T) RBRACE. +{ + NEW_AST_NODE(Default,stmt,T); + stmt->Content = NULL; + X = stmt; +} +default_def(X) ::= DEFAULT LBRACE(T) default_statement_list(A) RBRACE. +{ + NEW_AST_NODE(Default,stmt,T); + stmt->Content = A; + X = stmt; +} +default_def(X) ::= DEFAULT LBRACE(T) error RBRACE. +{ + NEW_AST_NODE(Default,stmt,T); + stmt->Content = NULL; + X = stmt; +} + +default_statement_list(X) ::= default_statement(A). +{ + X = A; /*X-overwrites-A*/ +} +default_statement_list(X) ::= default_statement_list(X) default_statement(B). +{ + SAFE_APPEND(X,B); +} + + +default_statement(X) ::= SEMICOLON. { X = NULL; } +default_statement(X) ::= error SEMICOLON. { X = NULL; } +//default_statement(X) ::= assign_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/ } +default_statement(X) ::= property_statement(A). { X = A; /*X-overwrites-A*/ } +default_statement(X) ::= flag_statement(A). { X = A; /*X-overwrites-A*/ } + +%type flag_statement { ZCC_FlagStmt *} + +flag_statement(X) ::= ADD dottable_id(A). +{ + NEW_AST_NODE(FlagStmt, type, A); + type->set = true; + type->name = A; + X = type; +} +flag_statement(X) ::= SUB dottable_id(A). +{ + NEW_AST_NODE(FlagStmt, type, A); + type->set = false; + type->name = A; + X = type; +} + +%type property_statement{ZCC_PropertyStmt *} + +property_statement(X) ::= dottable_id(A) expr_list(B) SEMICOLON. +{ + NEW_AST_NODE(PropertyStmt,stmt,A); + stmt->Prop = A; + stmt->Values = B; + X = stmt; +} + +property_statement(X) ::= dottable_id(A) SEMICOLON. +{ + NEW_AST_NODE(PropertyStmt,stmt,A); + stmt->Prop = A; + stmt->Values = nullptr; + X = stmt; +} + + /* Type names */ %type type_name {ZCC_BasicType *} @@ -506,14 +698,20 @@ type_name1(X) ::= int_type(X). type_name1(X) ::= FLOAT(T). { X.Int = ZCC_FloatAuto; X.SourceLoc = T.SourceLoc; } type_name1(X) ::= DOUBLE(T). { X.Int = ZCC_Float64; X.SourceLoc = T.SourceLoc; } type_name1(X) ::= STRING(T). { X.Int = ZCC_String; X.SourceLoc = T.SourceLoc; } -type_name1(X) ::= VECTOR(T) vector_size(A). { X.Int = A.Int; X.SourceLoc = T.SourceLoc; } +type_name1(X) ::= VECTOR2(T). { X.Int = ZCC_Vector2; X.SourceLoc = T.SourceLoc; } +type_name1(X) ::= VECTOR3(T). { X.Int = ZCC_Vector3; X.SourceLoc = T.SourceLoc; } type_name1(X) ::= NAME(T). { X.Int = ZCC_Name; X.SourceLoc = T.SourceLoc; } +type_name1(X) ::= SOUND(T). { X.Int = ZCC_Sound; X.SourceLoc = T.SourceLoc; } +type_name1(X) ::= STATE(T). { X.Int = ZCC_State; X.SourceLoc = T.SourceLoc; } +type_name1(X) ::= COLOR(T). { X.Int = ZCC_Color; X.SourceLoc = T.SourceLoc; } +type_name1(X) ::= LET(T). { X.Int = ZCC_Let; X.SourceLoc = T.SourceLoc; } type_name(X) ::= type_name1(A). { NEW_AST_NODE(BasicType, type, A); type->Type = (EZCCBuiltinType)A.Int; type->UserType = NULL; + type->isconst = false; X = type; } type_name(X) ::= IDENTIFIER(A). /* User-defined type (struct, enum, or class) */ @@ -522,41 +720,34 @@ type_name(X) ::= IDENTIFIER(A). /* User-defined type (struct, enum, or class) NEW_AST_NODE(Identifier, id, A); type->Type = ZCC_UserType; type->UserType = id; + type->isconst = false; id->Id = A.Name(); X = type; } +type_name(X) ::= READONLY LT IDENTIFIER(A) GT. +{ + NEW_AST_NODE(BasicType, type, A); + NEW_AST_NODE(Identifier, id, A); + type->Type = ZCC_UserType; + type->UserType = id; + type->isconst = true; + id->Id = A.Name(); + X = type; +} + type_name(X) ::= DOT dottable_id(A). { NEW_AST_NODE(BasicType, type, A); type->Type = ZCC_UserType; type->UserType = A; + type->isconst = false; X = type; } -/* Vectors can be 2, 3, or 4 entries long. Default is a 3D vector. - * (Well, actually, I'm not sure if 4D ones are going to happen - * straight away.) - */ -%token_class intconst INTCONST|UINTCONST. -vector_size(X) ::= . { X.Int = ZCC_Vector3; X.SourceLoc = stat->sc.GetMessageLine(); } -vector_size(X) ::= LT intconst(A) GT. -{ - if (A.Int >= 2 && A.Int <= 4) - { - X.Int = ZCC_Vector2 + A.Int - 2; - } - else - { - X.Int = ZCC_Vector3; - stat->sc.ScriptMessage("Invalid vector size %d\n", A.Int); - } - X.SourceLoc = A.SourceLoc; -} - /* Type names can also be used as identifiers in contexts where type names * are not normally allowed. */ %fallback IDENTIFIER - SBYTE BYTE SHORT USHORT INT UINT BOOL FLOAT DOUBLE STRING VECTOR NAME MAP ARRAY VOID. + SBYTE BYTE SHORT USHORT INT UINT BOOL FLOAT DOUBLE STRING VECTOR2 VECTOR3 NAME MAP ARRAY VOID STATE COLOR SOUND UINT8 INT8 UINT16 INT16. /* Aggregate types */ %type aggregate_type {ZCC_Type *} @@ -564,7 +755,7 @@ vector_size(X) ::= LT intconst(A) GT. %type type_list {ZCC_Type *} %type type_list_or_void {ZCC_Type *} %type type_or_array {ZCC_Type *} -%type class_restrictor {ZCC_Identifier *} + %type class_restrictor {ZCC_Identifier *} %type array_size{ZCC_Expression *} %type array_size_expr{ZCC_Expression *} @@ -599,16 +790,16 @@ type_or_array(X) ::= type(X). type_or_array(X) ::= type(A) array_size(B). { X = A; /*X-overwrites-A*/ X->ArraySize = B; } type_list(X) ::= type_or_array(X). /* A comma-separated list of types */ -type_list(X) ::= type_list(A) COMMA type_or_array(B). { X = A; /*X-overwrites-A*/ X->AppendSibling(B); } +type_list(X) ::= type_list(A) COMMA type_or_array(B). { X = A; /*X-overwrites-A*/ AppendTreeNodeSibling(X, B); } type_list_or_void(X) ::= VOID. { X = NULL; } type_list_or_void(X) ::= type_list(X). -array_size_expr(X) ::= LBRACKET opt_expr(A) RBRACKET. +array_size_expr(X) ::= LBRACKET(L) opt_expr(A) RBRACKET. { if (A == NULL) { - NEW_AST_NODE(Expression,nil,A); + NEW_AST_NODE(Expression,nil,L.SourceLoc); nil->Operation = PEX_Nil; nil->Type = NULL; X = nil; @@ -621,7 +812,7 @@ array_size_expr(X) ::= LBRACKET opt_expr(A) RBRACKET. array_size(X) ::= array_size_expr(X). array_size(X) ::= array_size(A) array_size_expr(B). { - A->AppendSibling(B); + AppendTreeNodeSibling(A, B); X = A; /*X-overwrites-A*/ } @@ -636,43 +827,36 @@ declarator(X) ::= decl_flags(A) type_list_or_void(B) variables_or_function(C). } else if (C.FuncName != NAME_None) { // A function - NEW_AST_NODE(FuncDeclarator, decl, A.SourceLoc); + NEW_AST_NODE(FuncDeclarator, decl, A == nullptr? C.SourceLoc : A->SourceLoc); decl->Type = B; decl->Params = C.FuncParams; decl->Name = C.FuncName; - decl->Flags = A.Int | C.FuncFlags; + decl->UseFlags = A == nullptr? nullptr : A->Id; + decl->Flags = (A == nullptr? 0 : A->Flags) | C.FuncFlags; decl->Body = C.FuncBody; X = decl; } else if (B != NULL && B->SiblingNext == B) { // A variable - NEW_AST_NODE(VarDeclarator, decl, A.SourceLoc); + NEW_AST_NODE(VarDeclarator, decl, A == nullptr? B->SourceLoc : A->SourceLoc); decl->Type = B; decl->Names = C.VarNames; - decl->Flags = A.Int; + decl->Flags = (A == nullptr? 0 : A->Flags); X = decl; } else { // An invalid if (B == NULL) { - stat->sc.ScriptMessage("Variables may not be of type void.\n"); + stat->sc->ScriptMessage("Variables may not be of type void.\n"); } else { - stat->sc.ScriptMessage("Variables may be of only one type.\n"); + stat->sc->ScriptMessage("Variables may be of only one type.\n"); } X = NULL; } } -declarator_no_fun(X) ::= decl_flags(A) type(B) variable_list(C) SEMICOLON. -{ - NEW_AST_NODE(VarDeclarator, decl, A.SourceLoc ? A.SourceLoc : B->SourceLoc); - decl->Type = B; - decl->Names = C; - decl->Flags = A.Int; - X = decl; -} // Need to split it up like this to avoid parsing conflicts. variables_or_function(X) ::= IDENTIFIER(A) LPAREN func_params(B) RPAREN func_const(C) opt_func_body(D). /* Function */ @@ -734,23 +918,58 @@ variable_name(X) ::= IDENTIFIER(A) array_size(B). variable_list(X) ::= variable_name(X). variable_list(X) ::= variable_list(A) COMMA variable_name(B). { - A->AppendSibling(B); + AppendTreeNodeSibling(A, B); X = A; /*X-overwrites-A*/ } -decl_flags(X) ::= . { X.Int = 0; X.SourceLoc = 0; } -decl_flags(X) ::= decl_flags(A) NATIVE(T). { X.Int = A.Int | ZCC_Native; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } -decl_flags(X) ::= decl_flags(A) STATIC(T). { X.Int = A.Int | ZCC_Static; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } -decl_flags(X) ::= decl_flags(A) PRIVATE(T). { X.Int = A.Int | ZCC_Private; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } -decl_flags(X) ::= decl_flags(A) PROTECTED(T). { X.Int = A.Int | ZCC_Protected; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } -decl_flags(X) ::= decl_flags(A) LATENT(T). { X.Int = A.Int | ZCC_Latent; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } -decl_flags(X) ::= decl_flags(A) FINAL(T). { X.Int = A.Int | ZCC_Final; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } -decl_flags(X) ::= decl_flags(A) META(T). { X.Int = A.Int | ZCC_Meta; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } -decl_flags(X) ::= decl_flags(A) ACTION(T). { X.Int = A.Int | ZCC_Action; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } -decl_flags(X) ::= decl_flags(A) READONLY(T). { X.Int = A.Int | ZCC_ReadOnly; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } -decl_flags(X) ::= decl_flags(A) DEPRECATED(T). { X.Int = A.Int | ZCC_Deprecated; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +%type decl_flags { ZCC_DeclFlags * } +decl_flags(X) ::= . { X = NULL; } +decl_flags(X) ::= decl_flags(F) decl_flag(A). +{ + if (F == nullptr) + { + NEW_AST_NODE(DeclFlags,nil_f,A); + X = nil_f; + X->Id = nullptr; + X->Flags = A.Int; + } + else + { + X = F; + X->Flags |= A.Int; + } +} -func_const(X) ::= . { X.Int = 0; X.SourceLoc = stat->sc.GetMessageLine(); } + +decl_flags(X) ::= decl_flags(F) ACTION(B) states_opts(A). +{ + if (F == nullptr) + { + NEW_AST_NODE(DeclFlags,nil_f,B.SourceLoc); + X = nil_f; + X->Flags = ZCC_Action; + } + else + { + X = F; + X->Flags |= ZCC_Action; + } + X->Id = A; +} + +decl_flag(X) ::= NATIVE(T). { X.Int = ZCC_Native; X.SourceLoc = T.SourceLoc; } +decl_flag(X) ::= STATIC(T). { X.Int = ZCC_Static; X.SourceLoc = T.SourceLoc; } +decl_flag(X) ::= PRIVATE(T). { X.Int = ZCC_Private; X.SourceLoc = T.SourceLoc; } +decl_flag(X) ::= PROTECTED(T). { X.Int = ZCC_Protected; X.SourceLoc = T.SourceLoc; } +decl_flag(X) ::= LATENT(T). { X.Int = ZCC_Latent; X.SourceLoc = T.SourceLoc; } +decl_flag(X) ::= FINAL(T). { X.Int = ZCC_Final; X.SourceLoc = T.SourceLoc; } +decl_flag(X) ::= META(T). { X.Int = ZCC_Meta; X.SourceLoc = T.SourceLoc; } +decl_flag(X) ::= READONLY(T). { X.Int = ZCC_ReadOnly; X.SourceLoc = T.SourceLoc; } +decl_flag(X) ::= DEPRECATED(T). { X.Int = ZCC_Deprecated; X.SourceLoc = T.SourceLoc; } +decl_flag(X) ::= VIRTUAL(T). { X.Int = ZCC_Virtual; X.SourceLoc = T.SourceLoc; } +decl_flag(X) ::= OVERRIDE(T). { X.Int = ZCC_Override; X.SourceLoc = T.SourceLoc; } + +func_const(X) ::= . { X.Int = 0; X.SourceLoc = stat->sc->GetMessageLine(); } func_const(X) ::= CONST(T). { X.Int = ZCC_FuncConst; X.SourceLoc = T.SourceLoc; } opt_func_body(X) ::= SEMICOLON. { X = NULL; } @@ -764,8 +983,19 @@ func_params(X) ::= . /* empty */ { X = NULL; } func_params(X) ::= VOID. { X = NULL; } func_params(X) ::= func_param_list(X). +func_params(X) ::= func_param_list(A) COMMA ELLIPSIS. +{ + NEW_AST_NODE(FuncParamDecl,parm,stat->sc->GetMessageLine()); + parm->Type = nullptr; + parm->Name = NAME_None; + parm->Flags = 0; + parm->Default = nullptr; + X = A; /*X-overwrites-A*/ + AppendTreeNodeSibling(X, parm); +} + func_param_list(X) ::= func_param(X). -func_param_list(X) ::= func_param_list(A) COMMA func_param(B). { X = A; /*X-overwrites-A*/ X->AppendSibling(B); } +func_param_list(X) ::= func_param_list(A) COMMA func_param(B). { X = A; /*X-overwrites-A*/ AppendTreeNodeSibling(X, B); } func_param(X) ::= func_param_flags(A) type(B) IDENTIFIER(C). { @@ -773,13 +1003,24 @@ func_param(X) ::= func_param_flags(A) type(B) IDENTIFIER(C). parm->Type = B; parm->Name = C.Name(); parm->Flags = A.Int; + parm->Default = nullptr; + X = parm; +} + +func_param(X) ::= func_param_flags(A) type(B) IDENTIFIER(C) EQ expr(D). +{ + NEW_AST_NODE(FuncParamDecl,parm,A.SourceLoc ? A.SourceLoc : B->SourceLoc); + parm->Type = B; + parm->Name = C.Name(); + parm->Flags = A.Int; + parm->Default = D; X = parm; } func_param_flags(X) ::= . { X.Int = 0; X.SourceLoc = 0; } -func_param_flags(X) ::= func_param_flags(A) IN(T). { X.Int = A.Int | ZCC_In; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } -func_param_flags(X) ::= func_param_flags(A) OUT(T). { X.Int = A.Int | ZCC_Out; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } -func_param_flags(X) ::= func_param_flags(A) OPTIONAL(T). { X.Int = A.Int | ZCC_Optional; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; } +func_param_flags(X) ::= func_param_flags(A) IN(T). { X.Int = A.Int | ZCC_In; X.SourceLoc = T.SourceLoc; } +func_param_flags(X) ::= func_param_flags(A) OUT(T). { X.Int = A.Int | ZCC_Out; X.SourceLoc = T.SourceLoc; } +func_param_flags(X) ::= func_param_flags(A) OPTIONAL(T). { X.Int = A.Int | ZCC_Optional; X.SourceLoc = T.SourceLoc; } /************ Expressions ************/ @@ -810,12 +1051,25 @@ primary(X) ::= SUPER(T). X = expr; } primary(X) ::= constant(A). { X = A; /*X-overwrites-A*/ } -primary(X) ::= SELF(T). +primary(XX) ::= LPAREN expr(A) COMMA expr(B) COMMA expr(C) RPAREN. [DOT] { - NEW_AST_NODE(Expression, expr, T); - expr->Operation = PEX_Self; - expr->Type = NULL; - X = expr; + NEW_AST_NODE(VectorValue, expr, A); + expr->Operation = PEX_Vector; + expr->Type = TypeVector3; + expr->X = A; + expr->Y = B; + expr->Z = C; + XX = expr; +} +primary(XX) ::= LPAREN expr(A) COMMA expr(B) RPAREN. [DOT] +{ + NEW_AST_NODE(VectorValue, expr, A); + expr->Operation = PEX_Vector; + expr->Type = TypeVector2; + expr->X = A; + expr->Y = B; + expr->Z = nullptr; + XX = expr; } primary(X) ::= LPAREN expr(A) RPAREN. { @@ -831,6 +1085,14 @@ primary(X) ::= primary(A) LPAREN func_expr_list(B) RPAREN. [DOT] // Function ca expr->Parameters = B; X = expr; } +primary(X) ::= LPAREN CLASS LT IDENTIFIER(A) GT RPAREN LPAREN func_expr_list(B) RPAREN. [DOT] // class type cast +{ + NEW_AST_NODE(ClassCast, expr, A); + expr->Operation = PEX_ClassCast; + expr->ClassName = ENamedName(A.Int); + expr->Parameters = B; + X = expr; +} primary(X) ::= primary(A) LBRACKET expr(B) RBRACKET. [DOT] // Array access { NEW_AST_NODE(ExprBinary, expr, B); @@ -866,6 +1128,7 @@ primary(X) ::= SCOPE primary(B). X = expr2; } */ + /*----- Unary Expressions -----*/ unary_expr(X) ::= primary(X). @@ -994,6 +1257,11 @@ expr(X) ::= expr(A) RSH expr(B). /* a >> b */ BINARY_EXPR(A,B,PEX_RightShift); X = expr2; } +expr(X) ::= expr(A) URSH expr(B). /* a >>> b */ +{ + BINARY_EXPR(A,B,PEX_URightShift); + X = expr2; +} expr(X) ::= expr(A) DOTDOT expr(B). /* a .. b */ { BINARY_EXPR(A,B,PEX_Concat); @@ -1007,9 +1275,8 @@ expr(X) ::= expr(A) LT expr(B). /* a < b */ } expr(X) ::= expr(A) GT expr(B). /* a > b */ { - BINARY_EXPR(A,B,PEX_LTEQ); - UNARY_EXPR(expr2,PEX_BoolNot); - X = expr1; + BINARY_EXPR(A,B,PEX_GT); + X = expr2; } expr(X) ::= expr(A) LTEQ expr(B). /* a <= b */ { @@ -1018,9 +1285,8 @@ expr(X) ::= expr(A) LTEQ expr(B). /* a <= b */ } expr(X) ::= expr(A) GTEQ expr(B). /* a >= b */ { - BINARY_EXPR(A,B,PEX_LT); - UNARY_EXPR(expr1,PEX_BoolNot); - X = expr1; + BINARY_EXPR(A,B,PEX_GTEQ); + X = expr2; } expr(X) ::= expr(A) LTGTEQ expr(B). /* a <>= b */ { @@ -1040,9 +1306,8 @@ expr(X) ::= expr(A) EQEQ expr(B). /* a == b */ } expr(X) ::= expr(A) NEQ expr(B). /* a != b */ { - BINARY_EXPR(A,B,PEX_EQEQ); - UNARY_EXPR(expr2,PEX_BoolNot); - X = expr1; + BINARY_EXPR(A,B,PEX_NEQ); + X = expr2; } expr(X) ::= expr(A) APPROXEQ expr(B). /* a ~== b */ { @@ -1075,6 +1340,67 @@ expr(X) ::= expr(A) OROR expr(B). /* a || b */ BINARY_EXPR(A,B,PEX_BoolOr); X = expr2; } +expr(X) ::= expr(A) EQ expr(B). /* a = b */ +{ + BINARY_EXPR(A,B,PEX_Assign); + X = expr2; +} +expr(X) ::= expr(A) ADDEQ expr(B). /* a += b */ +{ + BINARY_EXPR(A,B,PEX_AddAssign); + X = expr2; +} +expr(X) ::= expr(A) SUBEQ expr(B). /* a -= b */ +{ + BINARY_EXPR(A,B,PEX_SubAssign); + X = expr2; +} +expr(X) ::= expr(A) MULEQ expr(B). /* a *= b */ +{ + BINARY_EXPR(A,B,PEX_MulAssign); + X = expr2; +} +expr(X) ::= expr(A) DIVEQ expr(B). /* a /= b */ +{ + BINARY_EXPR(A,B,PEX_DivAssign); + X = expr2; +} +expr(X) ::= expr(A) MODEQ expr(B). /* a %= b */ +{ + BINARY_EXPR(A,B,PEX_ModAssign); + X = expr2; +} +expr(X) ::= expr(A) LSHEQ expr(B). /* a <<= b */ +{ + BINARY_EXPR(A,B,PEX_LshAssign); + X = expr2; +} +expr(X) ::= expr(A) RSHEQ expr(B). /* a >>= b */ +{ + BINARY_EXPR(A,B,PEX_RshAssign); + X = expr2; +} +expr(X) ::= expr(A) URSHEQ expr(B). /* a >>>= b */ +{ + BINARY_EXPR(A,B,PEX_URshAssign); + X = expr2; +} +expr(X) ::= expr(A) ANDEQ expr(B). /* a &= b */ +{ + BINARY_EXPR(A,B,PEX_AndAssign); + X = expr2; +} +expr(X) ::= expr(A) OREQ expr(B). /* a |= b */ +{ + BINARY_EXPR(A,B,PEX_OrAssign); + X = expr2; +} +expr(X) ::= expr(A) XOREQ expr(B). /* a ^= b */ +{ + BINARY_EXPR(A,B,PEX_XorAssign); + X = expr2; +} + expr(X) ::= expr(A) SCOPE expr(B). { @@ -1103,7 +1429,7 @@ expr_list(X) ::= expr(X). expr_list(X) ::= expr_list(A) COMMA expr(B). { X = A; /*X-overwrites-A*/ - X->AppendSibling(B); + AppendTreeNodeSibling(X, B); } /*----- Function argument lists -----*/ @@ -1134,7 +1460,7 @@ func_expr_list(X) ::= func_expr_list(A) COMMA(T) func_expr_item(B). B = nil_b; } X = A; /*X-overwrites-A*/ - X->AppendSibling(B); + AppendTreeNodeSibling(X, B); } func_expr_item(X) ::= . @@ -1217,6 +1543,14 @@ constant(X) ::= TRUE(A). NEW_INTCONST_NODE(boolconst, TypeBool, true, A); X = boolconst; } +constant(X) ::= NULLPTR(A). +{ + NEW_AST_NODE(ExprConstant, nullptrconst, A); + nullptrconst->Operation = PEX_ConstValue; + nullptrconst->Type = TypeNullPtr; + nullptrconst->StringVal = nullptr; + X = nullptrconst; +} /************ Statements ************/ @@ -1233,6 +1567,29 @@ statement(X) ::= jump_statement(X). statement(X) ::= assign_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/ } statement(X) ::= local_var(A) SEMICOLON. { X = A; /*X-overwrites-A*/ } statement(X) ::= error SEMICOLON. { X = NULL; } +statement(X) ::= staticarray_statement(A). { X = A; /*X-overwrites-A*/ } + +/*----- Static array Statements -----*/ + +%type staticarray_statement{ZCC_StaticArrayStatement *} + +staticarray_statement(X) ::= STATIC CONST type(A) IDENTIFIER(B) LBRACKET RBRACKET EQ LBRACE expr_list(C) RBRACE. +{ + NEW_AST_NODE(StaticArrayStatement, stmt, A); + stmt->Type = A; + stmt->Id = ENamedName(B.Int); + stmt->Values = C; + X = stmt; +} + +staticarray_statement(X) ::= STATIC CONST type(A) LBRACKET RBRACKET IDENTIFIER(B) EQ LBRACE expr_list(C) RBRACE. +{ + NEW_AST_NODE(StaticArrayStatement, stmt, A); + stmt->Type = A; + stmt->Id = ENamedName(B.Int); + stmt->Values = C; + X = stmt; +} /*----- Jump Statements -----*/ @@ -1381,7 +1738,6 @@ for_init(X) ::= for_bump(A). { X = A /*X-overwrites-A*/; } %type for_bump{ZCC_Statement *} for_bump(X) ::= . { X = NULL; } for_bump(X) ::= expression_statement(A). { X = A; /*X-overwrites-A*/ } -for_bump(X) ::= assign_statement(A). { X = A; /*X-overwrites-A*/ } /*----- If Statements -----*/ @@ -1444,40 +1800,90 @@ labeled_statement(X) ::= DEFAULT(T) COLON. %type assign_statement{ZCC_AssignStmt *} -assign_statement(X) ::= expr_list(A) assign_op(OP) expr_list(B). [EQ] +// The grammar won't let this pass without some syntactic help. +// Parentheses and braces aren't accepted either so brackets are the only way to get this through the parser without a conflict. +assign_statement(X) ::= LBRACKET expr_list(A) RBRACKET EQ expr(B). [EQ] { - NEW_AST_NODE(AssignStmt,stmt,OP); - stmt->AssignOp = OP.Int; + NEW_AST_NODE(AssignStmt,stmt,A); + stmt->AssignOp = ZCC_EQ; stmt->Dests = A; stmt->Sources = B; X = stmt; } -assign_op(X) ::= EQ(T). { X.Int = ZCC_EQ; X.SourceLoc = T.SourceLoc; } -assign_op(X) ::= MULEQ(T). { X.Int = ZCC_MULEQ; X.SourceLoc = T.SourceLoc; } -assign_op(X) ::= DIVEQ(T). { X.Int = ZCC_DIVEQ; X.SourceLoc = T.SourceLoc; } -assign_op(X) ::= MODEQ(T). { X.Int = ZCC_MODEQ; X.SourceLoc = T.SourceLoc; } -assign_op(X) ::= ADDEQ(T). { X.Int = ZCC_ADDEQ; X.SourceLoc = T.SourceLoc; } -assign_op(X) ::= SUBEQ(T). { X.Int = ZCC_SUBEQ; X.SourceLoc = T.SourceLoc; } -assign_op(X) ::= LSHEQ(T). { X.Int = ZCC_LSHEQ; X.SourceLoc = T.SourceLoc; } -assign_op(X) ::= RSHEQ(T). { X.Int = ZCC_RSHEQ; X.SourceLoc = T.SourceLoc; } -assign_op(X) ::= ANDEQ(T). { X.Int = ZCC_ANDEQ; X.SourceLoc = T.SourceLoc; } -assign_op(X) ::= OREQ(T). { X.Int = ZCC_OREQ; X.SourceLoc = T.SourceLoc; } -assign_op(X) ::= XOREQ(T). { X.Int = ZCC_XOREQ; X.SourceLoc = T.SourceLoc; } - /*----- Local Variable Definition "Statements" -----*/ %type local_var{ZCC_LocalVarStmt *} -local_var(X) ::= type(A) variable_list(B) var_init(C). +local_var(X) ::= type(A) variable_list_with_init(B). { NEW_AST_NODE(LocalVarStmt,vardef,A); vardef->Type = A; vardef->Vars = B; - vardef->Inits = C; X = vardef; } -%type var_init{ZCC_Expression *} -var_init(X) ::= . { X = NULL; } -var_init(X) ::= EQ expr_list(A). { X = A; /*X-overwrites-A*/ } +%type var_init{ZCC_VarInit *} +var_init(X) ::= IDENTIFIER(A). +{ + NEW_AST_NODE(VarInit,var,A); + var->Name = ENamedName(A.Int); + var->ArraySize = NULL; + var->Init = NULL; + var->InitIsArray = false; + X = var; +} + +var_init(X) ::= IDENTIFIER(A) array_size(B). +{ + NEW_AST_NODE(VarInit,var,A); + var->Name = ENamedName(A.Int); + var->ArraySize = B; + var->Init = NULL; + var->InitIsArray = false; + X = var; +} + +var_init(X) ::= IDENTIFIER(A) EQ expr(B). +{ + NEW_AST_NODE(VarInit,var,A); + var->Name = ENamedName(A.Int); + var->ArraySize = NULL; + var->Init = B; + var->InitIsArray = false; + X = var; +} + +var_init(X) ::= IDENTIFIER(A) EQ LBRACE expr_list(C) RBRACE. // this is for arrays which declare the size with the type +{ + NEW_AST_NODE(VarInit,var,A); + var->Name = ENamedName(A.Int); + var->ArraySize = NULL; + var->Init = C; + var->InitIsArray = true; + X = var; +} + +var_init(X) ::= IDENTIFIER(A) array_size(B) EQ LBRACE expr_list(C) RBRACE. +{ + NEW_AST_NODE(VarInit,var,A); + var->Name = ENamedName(A.Int); + var->ArraySize = B; + var->Init = C; + var->InitIsArray = true; + X = var; +} + +var_init(X) ::= IDENTIFIER EQ LBRACE error RBRACE. +{ + X = NULL; +} + +%type variable_list_with_init{ZCC_VarInit *} + +variable_list_with_init(X) ::= var_init(X). +variable_list_with_init(X) ::= variable_list_with_init(A) COMMA var_init(B). +{ + AppendTreeNodeSibling(A, B); + X = A; /*X-overwrites-A*/ +} diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp new file mode 100644 index 0000000000..856802a97f --- /dev/null +++ b/src/scripting/zscript/zcc_compile.cpp @@ -0,0 +1,3274 @@ +/* +** zcc_compile.cpp +** +**--------------------------------------------------------------------------- +** Copyright -2016 Randy Heit +** Copyright 2016 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include "a_pickups.h" +#include "thingdef.h" +#include "sc_man.h" +#include "c_console.h" +#include "c_dispatch.h" +#include "doomerrors.h" +#include "w_wad.h" +#include "cmdlib.h" +#include "m_alloc.h" +#include "zcc_parser.h" +#include "zcc-parse.h" +#include "zcc_compile.h" +#include "v_text.h" +#include "p_lnspec.h" +#include "i_system.h" +#include "gdtoa.h" +#include "codegeneration/codegen.h" +#include "vmbuilder.h" +#include "version.h" + +//========================================================================== +// +// ZCCCompiler :: ProcessClass +// +//========================================================================== + +void ZCCCompiler::ProcessClass(ZCC_Class *cnode, PSymbolTreeNode *treenode) +{ + ZCC_ClassWork *cls = nullptr; + // If this is a class extension, put the new node directly into the existing class. + if (cnode->Flags == ZCC_Extension) + { + for (auto clss : Classes) + { + if (clss->NodeName() == cnode->NodeName) + { + cls = clss; + break; + } + } + if (cls == nullptr) + { + Error(cnode, "Class %s cannot be found in the current translation unit."); + return; + } + } + else + { + Classes.Push(new ZCC_ClassWork(static_cast(cnode), treenode)); + cls = Classes.Last(); + } + + auto node = cnode->Body; + PSymbolTreeNode *childnode; + ZCC_Enum *enumType = nullptr; + + // Need to check if the class actually has a body. + if (node != nullptr) do + { + switch (node->NodeType) + { + case AST_Struct: + case AST_ConstantDef: + case AST_Enum: + if ((childnode = AddTreeNode(static_cast(node)->NodeName, node, &cls->TreeNodes))) + { + switch (node->NodeType) + { + case AST_Enum: + enumType = static_cast(node); + cls->Enums.Push(enumType); + break; + + case AST_Struct: + ProcessStruct(static_cast(node), childnode, cls->cls); + break; + + case AST_ConstantDef: + cls->Constants.Push(static_cast(node)); + cls->Constants.Last()->Type = enumType; + break; + + default: + assert(0 && "Default case is just here to make GCC happy. It should never be reached"); + } + } + break; + + case AST_VarDeclarator: + cls->Fields.Push(static_cast(node)); + break; + + case AST_EnumTerminator: + enumType = nullptr; + break; + + case AST_States: + cls->States.Push(static_cast(node)); + break; + + case AST_FuncDeclarator: + cls->Functions.Push(static_cast(node)); + break; + + case AST_Default: + cls->Defaults.Push(static_cast(node)); + break; + + default: + assert(0 && "Unhandled AST node type"); + break; + } + node = node->SiblingNext; + } + while (node != cnode->Body); +} + +//========================================================================== +// +// ZCCCompiler :: ProcessStruct +// +//========================================================================== + +void ZCCCompiler::ProcessStruct(ZCC_Struct *cnode, PSymbolTreeNode *treenode, ZCC_Class *outer) +{ + Structs.Push(new ZCC_StructWork(static_cast(cnode), treenode, outer)); + ZCC_StructWork *cls = Structs.Last(); + + auto node = cnode->Body; + PSymbolTreeNode *childnode; + ZCC_Enum *enumType = nullptr; + + // Need to check if the struct actually has a body. + if (node != nullptr) do + { + switch (node->NodeType) + { + case AST_ConstantDef: + case AST_Enum: + if ((childnode = AddTreeNode(static_cast(node)->NodeName, node, &cls->TreeNodes))) + { + switch (node->NodeType) + { + case AST_Enum: + enumType = static_cast(node); + cls->Enums.Push(enumType); + break; + + case AST_ConstantDef: + cls->Constants.Push(static_cast(node)); + cls->Constants.Last()->Type = enumType; + break; + + default: + assert(0 && "Default case is just here to make GCC happy. It should never be reached"); + } + } + break; + + case AST_VarDeclarator: + cls->Fields.Push(static_cast(node)); + break; + + case AST_FuncDeclarator: + cls->Functions.Push(static_cast(node)); + break; + + case AST_EnumTerminator: + enumType = nullptr; + break; + + default: + assert(0 && "Unhandled AST node type"); + break; + } + node = node->SiblingNext; + } + while (node != cnode->Body); +} + +//========================================================================== +// +// ZCCCompiler Constructor +// +//========================================================================== + +ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols, PSymbolTable &_outsymbols, int lumpnum) + : Outer(_outer), GlobalTreeNodes(&_symbols), OutputSymbols(&_outsymbols), AST(ast), Lump(lumpnum) +{ + FScriptPosition::ResetErrorCounter(); + // Group top-level nodes by type + if (ast.TopNode != NULL) + { + ZCC_TreeNode *node = ast.TopNode; + PSymbolTreeNode *tnode; + PType *enumType = nullptr; + ZCC_Enum *zenumType = nullptr; + + do + { + switch (node->NodeType) + { + case AST_Class: + // a class extension should not check the tree node symbols. + if (static_cast(node)->Flags == ZCC_Extension) + { + ProcessClass(static_cast(node), tnode); + break; + } + case AST_Struct: + case AST_ConstantDef: + case AST_Enum: + if ((tnode = AddTreeNode(static_cast(node)->NodeName, node, GlobalTreeNodes))) + { + switch (node->NodeType) + { + case AST_Enum: + zenumType = static_cast(node); + enumType = NewEnum(zenumType->NodeName, nullptr); + GlobalSymbols.AddSymbol(new PSymbolType(zenumType->NodeName, enumType)); + break; + + case AST_Class: + ProcessClass(static_cast(node), tnode); + break; + + case AST_Struct: + ProcessStruct(static_cast(node), tnode, nullptr); + break; + + case AST_ConstantDef: + Constants.Push(static_cast(node)); + Constants.Last()->Type = zenumType; + break; + + default: + assert(0 && "Default case is just here to make GCC happy. It should never be reached"); + } + } + break; + + case AST_EnumTerminator: + zenumType = nullptr; + break; + + default: + assert(0 && "Unhandled AST node type"); + break; + } + node = node->SiblingNext; + } while (node != ast.TopNode); + } +} + +ZCCCompiler::~ZCCCompiler() +{ + for (auto s : Structs) + { + delete s; + } + for (auto c : Classes) + { + delete c; + } + Structs.Clear(); + Classes.Clear(); +} + +//========================================================================== +// +// ZCCCompiler :: AddTreeNode +// +// Keeps track of definition nodes by their names. Ensures that all names +// in this scope are unique. +// +//========================================================================== + +PSymbolTreeNode *ZCCCompiler::AddTreeNode(FName name, ZCC_TreeNode *node, PSymbolTable *treenodes, bool searchparents) +{ + PSymbol *check = treenodes->FindSymbol(name, searchparents); + if (check != NULL) + { + assert(check->IsA(RUNTIME_CLASS(PSymbolTreeNode))); + Error(node, "Attempt to redefine '%s'", name.GetChars()); + Error(static_cast(check)->Node, " Original definition is here"); + return nullptr; + } + else + { + auto sy = new PSymbolTreeNode(name, node); + FString name; + treenodes->AddSymbol(sy); + return sy; + } +} + +//========================================================================== +// +// ZCCCompiler :: Warn +// +// Prints a warning message, and increments WarnCount. +// +//========================================================================== + +void ZCCCompiler::Warn(ZCC_TreeNode *node, const char *msg, ...) +{ + va_list argptr; + va_start(argptr, msg); + MessageV(node, TEXTCOLOR_ORANGE, msg, argptr); + va_end(argptr); + + FScriptPosition::WarnCounter++; +} + +//========================================================================== +// +// ZCCCompiler :: Error +// +// Prints an error message, and increments ErrorCount. +// +//========================================================================== + +void ZCCCompiler::Error(ZCC_TreeNode *node, const char *msg, ...) +{ + va_list argptr; + va_start(argptr, msg); + MessageV(node, TEXTCOLOR_RED, msg, argptr); + va_end(argptr); + + FScriptPosition::ErrorCounter++; +} + +//========================================================================== +// +// ZCCCompiler :: MessageV +// +// Prints a message, annotated with the source location for the tree node. +// +//========================================================================== + +void ZCCCompiler::MessageV(ZCC_TreeNode *node, const char *txtcolor, const char *msg, va_list argptr) +{ + FString composed; + + composed.Format("%s%s, line %d: ", txtcolor, node->SourceName->GetChars(), node->SourceLoc); + composed.VAppendFormat(msg, argptr); + composed += '\n'; + PrintString(PRINT_HIGH, composed); +} + +//========================================================================== +// +// ZCCCompiler :: Compile +// +// Compile everything defined at this level. +// +//========================================================================== + +int ZCCCompiler::Compile() +{ + CreateClassTypes(); + CreateStructTypes(); + CompileAllConstants(); + CompileAllFields(); + InitDefaults(); + InitFunctions(); + CompileStates(); + return FScriptPosition::ErrorCounter; +} + +//========================================================================== +// +// ZCCCompiler :: CreateStructTypes +// +// Creates a PStruct for every struct. +// +//========================================================================== + +void ZCCCompiler::CreateStructTypes() +{ + for(auto s : Structs) + { + s->Outer = s->OuterDef == nullptr? nullptr : s->OuterDef->CType(); + if (s->strct->Flags & ZCC_Native) + s->strct->Type = NewNativeStruct(s->NodeName(), nullptr); + else + s->strct->Type = NewStruct(s->NodeName(), s->Outer); + s->strct->Symbol = new PSymbolType(s->NodeName(), s->Type()); + GlobalSymbols.AddSymbol(s->strct->Symbol); + + for (auto e : s->Enums) + { + auto etype = NewEnum(e->NodeName, s->Type()); + s->Type()->Symbols.AddSymbol(new PSymbolType(e->NodeName, etype)); + } + } +} + +//========================================================================== +// +// ZCCCompiler :: CreateClassTypes +// +// Creates a PClass for every class so that we get access to the symbol table +// These will be created with unknown size because for that we need to +// process all fields first, but to do that we need the PClass and some +// other info depending on the PClass. +// +//========================================================================== + +void ZCCCompiler::CreateClassTypes() +{ + // we are going to sort the classes array so that entries are sorted in order of inheritance. + + auto OrigClasses = std::move(Classes); + Classes.Clear(); + bool donesomething = true; + while (donesomething) + { + donesomething = false; + for (unsigned i = 0; icls->ParentName; + + if (ParentName != nullptr && ParentName->SiblingNext == ParentName) parent = PClass::FindClass(ParentName->Id); + else if (ParentName == nullptr) parent = RUNTIME_CLASS(DObject); + else + { + // The parent is a dotted name which the type system currently does not handle. + // Once it does this needs to be implemented here. + auto p = ParentName; + FString build; + + do + { + if (build.IsNotEmpty()) build += '.'; + build += FName(p->Id); + p = static_cast(p->SiblingNext); + } while (p != ParentName); + Error(c->cls, "Qualified name '%s' for base class not supported in '%s'", build.GetChars(), FName(c->NodeName()).GetChars()); + parent = RUNTIME_CLASS(DObject); + } + + if (parent != nullptr) + { + // The parent exists, we may create a type for this class + if (c->cls->Flags & ZCC_Native) + { + // If this is a native class, its own type must also already exist and not be a runtime class. + auto me = PClass::FindClass(c->NodeName()); + if (me == nullptr) + { + Error(c->cls, "Unknown native class %s", c->NodeName().GetChars()); + // Create a placeholder so that the compiler can continue looking for errors. + me = parent->FindClassTentative(c->NodeName()); + } + else if (me->bRuntimeClass) + { + Error(c->cls, "%s is not a native class", c->NodeName().GetChars()); + } + else + { + DPrintf(DMSG_SPAMMY, "Registered %s as native with parent %s\n", me->TypeName.GetChars(), parent->TypeName.GetChars()); + } + c->cls->Type = me; + auto ac = dyn_cast(me); + if (ac != nullptr) ac->SourceLumpName = *c->cls->SourceName; + } + else + { + // We will never get here if the name is a duplicate, so we can just do the assignment. + try + { + c->cls->Type = parent->CreateDerivedClass(c->NodeName(), TentativeClass); + if (c->Type() == nullptr) + { + Error(c->cls, "Class name %s already exists", c->NodeName().GetChars()); + } + } + catch (CRecoverableError &err) + { + Error(c->cls, "%s", err.GetMessage()); + // create a placeholder so that the compiler can continue looking for errors. + c->cls->Type = nullptr; + } + } + if (c->Type() == nullptr) c->cls->Type = parent->FindClassTentative(c->NodeName()); + c->Type()->bExported = true; // this class is accessible to script side type casts. (The reason for this flag is that types like PInt need to be skipped.) + c->cls->Symbol = new PSymbolType(c->NodeName(), c->Type()); + GlobalSymbols.AddSymbol(c->cls->Symbol); + Classes.Push(c); + OrigClasses.Delete(i--); + donesomething = true; + } + else + { + // No base class found. Now check if something in the unprocessed classes matches. + // If not, print an error. If something is found let's retry again in the next iteration. + bool found = false; + for (auto d : OrigClasses) + { + if (d->NodeName() == c->cls->ParentName->Id) + { + found = true; + break; + } + } + if (!found) + { + Error(c->cls, "Class %s has unknown base class %s", c->NodeName().GetChars(), FName(c->cls->ParentName->Id).GetChars()); + // create a placeholder so that the compiler can continue looking for errors. + c->cls->Type = RUNTIME_CLASS(DObject)->FindClassTentative(c->NodeName()); + c->cls->Symbol = new PSymbolType(c->NodeName(), c->Type()); + GlobalSymbols.AddSymbol(c->cls->Symbol); + Classes.Push(c); + OrigClasses.Delete(i--); + donesomething = true; + } + } + } + } + + // What's left refers to some other class in the list but could not be resolved. + // This normally means a circular reference. + for (auto c : OrigClasses) + { + Error(c->cls, "Class %s has circular inheritance", FName(c->NodeName()).GetChars()); + c->cls->Type = RUNTIME_CLASS(DObject)->FindClassTentative(c->NodeName()); + c->cls->Symbol = new PSymbolType(c->NodeName(), c->Type()); + GlobalSymbols.AddSymbol(c->cls->Symbol); + Classes.Push(c); + } + + // Last but not least: Now that all classes have been created, we can create the symbols for the internal enums and link the treenode symbol tables and set up replacements + for (auto cd : Classes) + { + for (auto e : cd->Enums) + { + auto etype = NewEnum(e->NodeName, cd->Type()); + cd->Type()->Symbols.AddSymbol(new PSymbolType(e->NodeName, etype)); + } + // Link the tree node tables. We only can do this after we know the class relations. + for (auto cc : Classes) + { + if (cc->Type() == cd->Type()->ParentClass) + { + cd->TreeNodes.SetParentTable(&cc->TreeNodes); + break; + } + } + + if (cd->cls->Replaces != nullptr && !static_cast(cd->Type())->SetReplacement(cd->cls->Replaces->Id)) + { + Warn(cd->cls, "Replaced type '%s' not found for %s", FName(cd->cls->Replaces->Id).GetChars(), cd->Type()->TypeName.GetChars()); + } + + } +} + +//========================================================================== +// +// ZCCCompiler :: AddConstants +// +// Helper for CompileAllConstants +// +//========================================================================== + +void ZCCCompiler::CopyConstants(TArray &dest, TArray &Constants, PSymbolTable *ot) +{ + for (auto c : Constants) + { + dest.Push({ c, ot }); + } +} + +//========================================================================== +// +// ZCCCompiler :: CompileAllConstants +// +// Make symbols from every constant defined at all levels. +// Since constants may only depend on other constants this can be done +// without any more involved processing of the AST as a first step. +// +//========================================================================== + +void ZCCCompiler::CompileAllConstants() +{ + // put all constants in one list to make resolving this easier. + TArray constantwork; + + CopyConstants(constantwork, Constants, OutputSymbols); + for (auto c : Classes) + { + CopyConstants(constantwork, c->Constants, &c->Type()->Symbols); + } + for (auto s : Structs) + { + CopyConstants(constantwork, s->Constants, &s->Type()->Symbols); + } + + // Before starting to resolve the list, let's create symbols for all already resolved ones first (i.e. all literal constants), to reduce work. + for (unsigned i = 0; iValue->NodeType == AST_ExprConstant) + { + AddConstant(constantwork[i]); + // Remove the constant from the list + constantwork.Delete(i); + i--; + } + } + bool donesomething = true; + // Now go through this list until no more constants can be resolved. The remaining ones will be non-constant values. + while (donesomething && constantwork.Size() > 0) + { + donesomething = false; + for (unsigned i = 0; i < constantwork.Size(); i++) + { + if (CompileConstant(constantwork[i].node, constantwork[i].outputtable)) + { + AddConstant(constantwork[i]); + // Remove the constant from the list + constantwork.Delete(i); + i--; + donesomething = true; + } + } + } + for (unsigned i = 0; i < constantwork.Size(); i++) + { + Error(constantwork[i].node, "%s is not a constant", FName(constantwork[i].node->NodeName).GetChars()); + } +} + +//========================================================================== +// +// ZCCCompiler :: AddConstant +// +// Adds a constant to its assigned symbol table +// +//========================================================================== + +void ZCCCompiler::AddConstant(ZCC_ConstantWork &constant) +{ + auto def = constant.node; + auto val = def->Value; + if (val->NodeType == AST_ExprConstant) + { + ZCC_ExprConstant *cval = static_cast(val); + if (cval->Type == TypeString) + { + def->Symbol = new PSymbolConstString(def->NodeName, *(cval->StringVal)); + } + else if (cval->Type->IsA(RUNTIME_CLASS(PInt))) + { + // How do we get an Enum type in here without screwing everything up??? + //auto type = def->Type != nullptr ? def->Type : cval->Type; + def->Symbol = new PSymbolConstNumeric(def->NodeName, cval->Type, cval->IntVal); + } + else if (cval->Type->IsA(RUNTIME_CLASS(PFloat))) + { + if (def->Type != nullptr) + { + Error(def, "Enum members must be integer values"); + } + def->Symbol = new PSymbolConstNumeric(def->NodeName, cval->Type, cval->DoubleVal); + } + else + { + Error(def->Value, "Bad type for constant definiton"); + def->Symbol = nullptr; + } + + if (def->Symbol == nullptr) + { + // Create a dummy constant so we don't make any undefined value warnings. + def->Symbol = new PSymbolConstNumeric(def->NodeName, TypeError, 0); + } + constant.outputtable->ReplaceSymbol(def->Symbol); + } +} + +//========================================================================== +// +// ZCCCompiler :: CompileConstant +// +// For every constant definition, evaluate its value (which should result +// in a constant), and create a symbol for it. +// +//========================================================================== + +bool ZCCCompiler::CompileConstant(ZCC_ConstantDef *def, PSymbolTable *sym) +{ + assert(def->Symbol == nullptr); + + ZCC_Expression *val = Simplify(def->Value, sym, true); + def->Value = val; + return (val->NodeType == AST_ExprConstant); +} + + +//========================================================================== +// +// ZCCCompiler :: Simplify +// +// For an expression, +// Evaluate operators whose arguments are both constants, replacing it +// with a new constant. +// For a binary operator with one constant argument, put it on the right- +// hand operand, where permitted. +// Perform automatic type promotion. +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::Simplify(ZCC_Expression *root, PSymbolTable *sym, bool wantconstant) +{ + SimplifyingConstant = wantconstant; + return DoSimplify(root, sym); +} + +ZCC_Expression *ZCCCompiler::DoSimplify(ZCC_Expression *root, PSymbolTable *sym) +{ + if (root->NodeType == AST_ExprUnary) + { + return SimplifyUnary(static_cast(root), sym); + } + else if (root->NodeType == AST_ExprBinary) + { + return SimplifyBinary(static_cast(root), sym); + } + else if (root->Operation == PEX_ID) + { + return IdentifyIdentifier(static_cast(root), sym); + } + else if (root->Operation == PEX_MemberAccess) + { + return SimplifyMemberAccess(static_cast(root), sym); + } + else if (root->Operation == PEX_FuncCall) + { + return SimplifyFunctionCall(static_cast(root), sym); + } + return root; +} + +//========================================================================== +// +// ZCCCompiler :: SimplifyUnary +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::SimplifyUnary(ZCC_ExprUnary *unary, PSymbolTable *sym) +{ + unary->Operand = DoSimplify(unary->Operand, sym); + if (unary->Operand->Type == nullptr) + { + return unary; + } + ZCC_OpProto *op = PromoteUnary(unary->Operation, unary->Operand); + if (op == NULL) + { // Oh, poo! + unary->Type = TypeError; + } + else if (unary->Operand->Operation == PEX_ConstValue) + { + return op->EvalConst1(static_cast(unary->Operand)); + } + return unary; +} + +//========================================================================== +// +// ZCCCompiler :: SimplifyBinary +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::SimplifyBinary(ZCC_ExprBinary *binary, PSymbolTable *sym) +{ + binary->Left = DoSimplify(binary->Left, sym); + binary->Right = DoSimplify(binary->Right, sym); + if (binary->Left->Type == nullptr || binary->Right->Type == nullptr) + { + // We do not know yet what this is so we cannot promote it (yet.) + return binary; + } + ZCC_OpProto *op = PromoteBinary(binary->Operation, binary->Left, binary->Right); + if (op == NULL) + { + binary->Type = TypeError; + } + else if (binary->Left->Operation == PEX_ConstValue && + binary->Right->Operation == PEX_ConstValue) + { + return op->EvalConst2(static_cast(binary->Left), + static_cast(binary->Right), AST.Strings); + } + return binary; +} + +//========================================================================== +// +// ZCCCompiler :: SimplifyMemberAccess +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::SimplifyMemberAccess(ZCC_ExprMemberAccess *dotop, PSymbolTable *symt) +{ + PSymbolTable *symtable; + + // TBD: Is it safe to simplify the left side here when not processing a constant? + dotop->Left = DoSimplify(dotop->Left, symt); + + if (dotop->Left->Operation == PEX_TypeRef) + { // Type refs can be evaluated now. + PType *ref = static_cast(dotop->Left)->RefType; + PSymbol *sym = ref->Symbols.FindSymbolInTable(dotop->Right, symtable); + if (sym != nullptr) + { + ZCC_Expression *expr = NodeFromSymbol(sym, dotop, symtable); + if (expr != nullptr) + { + return expr; + } + } + } + else if (dotop->Left->Operation == PEX_Super) + { + symt = symt->GetParentTable(); + if (symt != nullptr) + { + PSymbol *sym = symt->FindSymbolInTable(dotop->Right, symtable); + if (sym != nullptr) + { + ZCC_Expression *expr = NodeFromSymbol(sym, dotop, symtable); + if (expr != nullptr) + { + return expr; + } + } + } + } + return dotop; +} + +//========================================================================== +// +// ZCCCompiler :: SimplifyFunctionCall +// +// This may replace a function call with cast(s), since they look like the +// same thing to the parser. +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::SimplifyFunctionCall(ZCC_ExprFuncCall *callop, PSymbolTable *sym) +{ + ZCC_FuncParm *parm; + int parmcount = 0; + + parm = callop->Parameters; + if (parm != NULL) + { + do + { + parmcount++; + assert(parm->NodeType == AST_FuncParm); + parm->Value = DoSimplify(parm->Value, sym); + parm = static_cast(parm->SiblingNext); + } + while (parm != callop->Parameters); + } + // Only simplify the 'function' part if we want to retrieve a constant. + // This is necessary to evaluate the type casts, but for actual functions + // the simplification process is destructive and has to be avoided. + if (SimplifyingConstant) + { + callop->Function = DoSimplify(callop->Function, sym); + } + // If the left side is a type ref, then this is actually a cast + // and not a function call. + if (callop->Function->Operation == PEX_TypeRef) + { + if (parmcount != 1) + { + Error(callop, "Type cast requires one parameter"); + callop->ToErrorNode(); + } + else + { + PType *dest = static_cast(callop->Function)->RefType; + const PType::Conversion *route[CONVERSION_ROUTE_SIZE]; + int routelen = parm->Value->Type->FindConversion(dest, route, countof(route)); + if (routelen < 0) + { + ///FIXME: Need real type names + Error(callop, "Cannot convert %s to %s", parm->Value->Type->DescriptiveName(), dest->DescriptiveName()); + callop->ToErrorNode(); + } + else + { + ZCC_Expression *val = ApplyConversion(parm->Value, route, routelen); + assert(val->Type == dest); + return val; + } + } + } + return callop; +} + +//========================================================================== +// +// ZCCCompiler :: PromoteUnary +// +// Converts the operand into a format preferred by the operator. +// +//========================================================================== + +ZCC_OpProto *ZCCCompiler::PromoteUnary(EZCCExprType op, ZCC_Expression *&expr) +{ + if (expr->Type == TypeError) + { + return NULL; + } + const PType::Conversion *route[CONVERSION_ROUTE_SIZE]; + int routelen = countof(route); + ZCC_OpProto *proto = ZCC_OpInfo[op].FindBestProto(expr->Type, route, routelen); + + if (proto != NULL) + { + expr = ApplyConversion(expr, route, routelen); + } + return proto; +} + +//========================================================================== +// +// ZCCCompiler :: PromoteBinary +// +// Converts the operands into a format (hopefully) compatible with the +// operator. +// +//========================================================================== + +ZCC_OpProto *ZCCCompiler::PromoteBinary(EZCCExprType op, ZCC_Expression *&left, ZCC_Expression *&right) +{ + // If either operand is of type 'error', the result is also 'error' + if (left->Type == TypeError || right->Type == TypeError) + { + return NULL; + } + const PType::Conversion *route1[CONVERSION_ROUTE_SIZE], *route2[CONVERSION_ROUTE_SIZE]; + int route1len = countof(route1), route2len = countof(route2); + ZCC_OpProto *proto = ZCC_OpInfo[op].FindBestProto(left->Type, route1, route1len, right->Type, route2, route2len); + if (proto != NULL) + { + left = ApplyConversion(left, route1, route1len); + right = ApplyConversion(right, route2, route2len); + } + return proto; +} + +//========================================================================== +// +// ZCCCompiler :: ApplyConversion +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::ApplyConversion(ZCC_Expression *expr, const PType::Conversion **route, int routelen) +{ + for (int i = 0; i < routelen; ++i) + { + if (expr->Operation != PEX_ConstValue) + { + expr = AddCastNode(route[i]->TargetType, expr); + } + else + { + route[i]->ConvertConstant(static_cast(expr), AST.Strings); + } + } + return expr; +} + +//========================================================================== +// +// ZCCCompiler :: AddCastNode +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::AddCastNode(PType *type, ZCC_Expression *expr) +{ + assert(expr->Operation != PEX_ConstValue && "Expression must not be constant"); + // TODO: add a node here + return expr; +} + +//========================================================================== +// +// ZCCCompiler :: IdentifyIdentifier +// +// Returns a node that represents what the identifer stands for. +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::IdentifyIdentifier(ZCC_ExprID *idnode, PSymbolTable *symt) +{ + // Check the symbol table for the identifier. + PSymbolTable *table; + PSymbol *sym = symt->FindSymbolInTable(idnode->Identifier, table); + // GlobalSymbols cannot be the parent of a class's symbol table so we have to look for global symbols explicitly. + if (sym == nullptr && symt != &GlobalSymbols) sym = GlobalSymbols.FindSymbolInTable(idnode->Identifier, table); + if (sym != nullptr) + { + ZCC_Expression *node = NodeFromSymbol(sym, idnode, table); + if (node != NULL) + { + return node; + } + } + else if (SimplifyingConstant) // leave unknown identifiers alone when simplifying non-constants. It is impossible to know what they are here. + { + // Also handle line specials. + // To call this like a function this needs to be done differently, but for resolving constants this is ok. + int spec = P_FindLineSpecial(FName(idnode->Identifier).GetChars()); + if (spec != 0) + { + ZCC_ExprConstant *val = static_cast(AST.InitNode(sizeof(*val), AST_ExprConstant, idnode)); + val->Operation = PEX_ConstValue; + val->Type = TypeSInt32; + val->IntVal = spec; + return val; + } + + Error(idnode, "Unknown identifier '%s'", FName(idnode->Identifier).GetChars()); + idnode->ToErrorNode(); + } + return idnode; +} + +//========================================================================== +// +// ZCCCompiler :: NodeFromSymbol +// +//========================================================================== + +ZCC_Expression *ZCCCompiler::NodeFromSymbol(PSymbol *sym, ZCC_Expression *source, PSymbolTable *table) +{ + assert(sym != nullptr); + + if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) + { + return NodeFromSymbolConst(static_cast(sym), source); + } + else if (sym->IsKindOf(RUNTIME_CLASS(PSymbolType))) + { + return NodeFromSymbolType(static_cast(sym), source); + } + return NULL; +} + +//========================================================================== +// +// ZCCCompiler :: NodeFromSymbolConst +// +// Returns a new AST constant node with the symbol's content. +// +//========================================================================== + +ZCC_ExprConstant *ZCCCompiler::NodeFromSymbolConst(PSymbolConst *sym, ZCC_Expression *idnode) +{ + ZCC_ExprConstant *val = static_cast(AST.InitNode(sizeof(*val), AST_ExprConstant, idnode)); + val->Operation = PEX_ConstValue; + if (sym == NULL) + { + val->Type = TypeError; + val->IntVal = 0; + } + else if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConstString))) + { + val->StringVal = AST.Strings.Alloc(static_cast(sym)->Str); + val->Type = TypeString; + } + else + { + val->Type = sym->ValueType; + if (val->Type != TypeError) + { + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric))); + if (sym->ValueType->IsKindOf(RUNTIME_CLASS(PInt))) + { + val->IntVal = static_cast(sym)->Value; + } + else + { + assert(sym->ValueType->IsKindOf(RUNTIME_CLASS(PFloat))); + val->DoubleVal = static_cast(sym)->Float; + } + } + } + return val; +} + +//========================================================================== +// +// ZCCCompiler :: NodeFromSymbolType +// +// Returns a new AST type ref node with the symbol's content. +// +//========================================================================== + +ZCC_ExprTypeRef *ZCCCompiler::NodeFromSymbolType(PSymbolType *sym, ZCC_Expression *idnode) +{ + ZCC_ExprTypeRef *ref = static_cast(AST.InitNode(sizeof(*ref), AST_ExprTypeRef, idnode)); + ref->Operation = PEX_TypeRef; + ref->RefType = sym->Type; + ref->Type = NewClassPointer(RUNTIME_CLASS(PType)); + return ref; +} + +//========================================================================== +// +// ZCCCompiler :: CompileAllFields +// +// builds the internal structure of all classes and structs +// +//========================================================================== + +void ZCCCompiler::CompileAllFields() +{ + // Create copies of the arrays which can be altered + auto Classes = this->Classes; + auto Structs = this->Structs; + TMap HasNativeChildren; + + // first step: Look for native classes with native children. + // These may not have any variables added to them because it'd clash with the native definitions. + for (unsigned i = 0; i < Classes.Size(); i++) + { + auto c = Classes[i]; + + if (c->Type()->Size != TentativeClass && c->Fields.Size() > 0) + { + // We need to search the global class table here because not all children may have a scripted definition attached. + for (auto ac : PClass::AllClasses) + { + if (ac->ParentClass == c->Type() && ac->Size != TentativeClass) + { + // Only set a marker here, so that we can print a better message when the actual fields get added. + HasNativeChildren.Insert(ac, true); + break; + } + } + } + } + bool donesomething = true; + while (donesomething && (Structs.Size() > 0 || Classes.Size() > 0)) + { + donesomething = false; + for (unsigned i = 0; i < Structs.Size(); i++) + { + if (CompileFields(Structs[i]->Type(), Structs[i]->Fields, Structs[i]->Outer, &Structs[i]->TreeNodes, true)) + { + // Remove from the list if all fields got compiled. + Structs.Delete(i--); + donesomething = true; + } + } + for (unsigned i = 0; i < Classes.Size(); i++) + { + auto type = Classes[i]->Type(); + if (type->Size == TentativeClass) + { + if (type->ParentClass->Size == TentativeClass) + { + // we do not know the parent class's size yet, so skip this class for now. + continue; + } + else + { + // Inherit the size of the parent class + type->Size = Classes[i]->Type()->ParentClass->Size; + } + } + if (CompileFields(type, Classes[i]->Fields, nullptr, &Classes[i]->TreeNodes, false, !!HasNativeChildren.CheckKey(type))) + { + // Remove from the list if all fields got compiled. + Classes.Delete(i--); + donesomething = true; + } + } + } + // This really should never happen, but if it does, let's better print an error. + for (auto s : Structs) + { + Error(s->strct, "Unable to resolve all fields for struct %s", FName(s->NodeName()).GetChars()); + } + for (auto s : Classes) + { + Error(s->cls, "Unable to resolve all fields for class %s", FName(s->NodeName()).GetChars()); + } +} + +//========================================================================== +// +// ZCCCompiler :: CompileFields +// +// builds the internal structure of a single class or struct +// +//========================================================================== + +bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren) +{ + while (Fields.Size() > 0) + { + auto field = Fields[0]; + FieldDesc *fd = nullptr; + + PType *fieldtype = DetermineType(type, field, field->Names->Name, field->Type, true, true); + + // For structs only allow 'deprecated', for classes exclude function qualifiers. + int notallowed = forstruct? + ZCC_Latent | ZCC_Final | ZCC_Action | ZCC_Static | ZCC_FuncConst | ZCC_Abstract | ZCC_Virtual | ZCC_Override | ZCC_Meta | ZCC_Extension : + ZCC_Latent | ZCC_Final | ZCC_Action | ZCC_Static | ZCC_FuncConst | ZCC_Abstract | ZCC_Virtual | ZCC_Override | ZCC_Extension; + + if (field->Flags & notallowed) + { + Error(field, "Invalid qualifiers for %s (%s not allowed)", FName(field->Names->Name).GetChars(), FlagsToString(field->Flags & notallowed).GetChars()); + field->Flags &= notallowed; + } + uint32_t varflags = 0; + + // These map directly to implementation flags. + if (field->Flags & ZCC_Private) varflags |= VARF_Private; + if (field->Flags & ZCC_Protected) varflags |= VARF_Protected; + if (field->Flags & ZCC_Deprecated) varflags |= VARF_Deprecated; + if (field->Flags & ZCC_ReadOnly) varflags |= VARF_ReadOnly; + + if (field->Flags & ZCC_Native) + { + varflags |= VARF_Native | VARF_Transient; + } + + if (field->Flags & ZCC_Meta) + { + varflags |= VARF_Static|VARF_ReadOnly; // metadata implies readonly + if (!(field->Flags & ZCC_Native)) + { + // Non-native meta data is not implemented yet and requires some groundwork in the class copy code. + Error(field, "Metadata member %s must be native", FName(field->Names->Name).GetChars()); + } + } + + if (field->Type->ArraySize != nullptr) + { + fieldtype = ResolveArraySize(fieldtype, field->Type->ArraySize, &type->Symbols); + } + + auto name = field->Names; + do + { + if (AddTreeNode(name->Name, name, TreeNodes, !forstruct)) + { + auto thisfieldtype = fieldtype; + if (name->ArraySize != nullptr) + { + thisfieldtype = ResolveArraySize(thisfieldtype, name->ArraySize, &type->Symbols); + } + + if (varflags & VARF_Native) + { + auto querytype = (varflags & VARF_Static) ? type->GetClass() : type; + fd = FindField(querytype, FName(name->Name).GetChars()); + if (fd == nullptr) + { + Error(field, "The member variable '%s.%s' has not been exported from the executable.", type->TypeName.GetChars(), FName(name->Name).GetChars()); + } + else if (thisfieldtype->Size != fd->FieldSize && fd->BitValue == 0) + { + Error(field, "The member variable '%s.%s' has mismatching sizes in internal and external declaration. (Internal = %d, External = %d)", type->TypeName.GetChars(), FName(name->Name).GetChars(), fd->FieldSize, thisfieldtype->Size); + } + // Q: Should we check alignment, too? A mismatch may be an indicator for bad assumptions. + else + { + // for bit fields the type must point to the source variable. + if (fd->BitValue != 0) thisfieldtype = fd->FieldSize == 1 ? TypeUInt8 : fd->FieldSize == 2 ? TypeUInt16 : TypeUInt32; + type->AddNativeField(name->Name, thisfieldtype, fd->FieldOffset, varflags, fd->BitValue); + } + } + else if (hasnativechildren) + { + Error(field, "Cannot add field %s to %s. %s has native children which means it size may not change.", type->TypeName.GetChars(), fd->FieldSize, FName(name->Name).GetChars()); + } + else + { + type->AddField(name->Name, thisfieldtype, varflags); + } + } + name = static_cast(name->SiblingNext); + } while (name != field->Names); + Fields.Delete(0); + } + return Fields.Size() == 0; +} + +//========================================================================== +// +// ZCCCompiler :: FieldFlagsToString +// +// creates a string for a field's flags +// +//========================================================================== + +FString ZCCCompiler::FlagsToString(uint32_t flags) +{ + const char *flagnames[] = { "native", "static", "private", "protected", "latent", "final", "meta", "action", "deprecated", "readonly", "funcconst", "abstract" }; + FString build; + + for (int i = 0; i < 12; i++) + { + if (flags & (1 << i)) + { + if (build.IsNotEmpty()) build += ", "; + build += flagnames[i]; + } + } + return build; +} + +//========================================================================== +// +// ZCCCompiler :: DetermineType +// +// retrieves the type for this field, for arrays the type of a single entry. +// +//========================================================================== + +PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName name, ZCC_Type *ztype, bool allowarraytypes, bool formember) +{ + PType *retval = TypeError; + if (!allowarraytypes && ztype->ArraySize != nullptr) + { + Error(field, "%s: Array type not allowed", name.GetChars()); + return TypeError; + } + switch (ztype->NodeType) + { + case AST_BasicType: + { + auto btype = static_cast(ztype); + switch (btype->Type) + { + case ZCC_SInt8: + retval = formember? TypeSInt8 : (PType*)TypeError; + break; + + case ZCC_UInt8: + retval = formember ? TypeUInt8 : (PType*)TypeError; + break; + + case ZCC_SInt16: + retval = formember ? TypeSInt16 : (PType*)TypeError; + break; + + case ZCC_UInt16: + retval = formember ? TypeUInt16 : (PType*)TypeError; + break; + + case ZCC_SInt32: + case ZCC_IntAuto: // todo: for enums, autoselect appropriately sized int + retval = TypeSInt32; + break; + + case ZCC_UInt32: + retval = TypeUInt32; + break; + + case ZCC_Bool: + retval = TypeBool; + break; + + case ZCC_FloatAuto: + retval = formember ? TypeFloat32 : TypeFloat64; + break; + + case ZCC_Float64: + retval = TypeFloat64; + break; + + case ZCC_String: + retval = TypeString; + break; + + case ZCC_Name: + retval = TypeName; + break; + + case ZCC_Vector2: + retval = TypeVector2; + break; + + case ZCC_Vector3: + retval = TypeVector3; + break; + + case ZCC_State: + retval = TypeState; + break; + + case ZCC_Color: + retval = TypeColor; + break; + + case ZCC_Sound: + retval = TypeSound; + break; + + case ZCC_Let: + retval = TypeAuto; + break; + + case ZCC_UserType: + // statelabel et.al. are not tokens - there really is no need to, it works just as well as an identifier. Maybe the same should be done for some other types, too? + switch (btype->UserType->Id) + { + case NAME_StateLabel: + retval = TypeStateLabel; + break; + + case NAME_SpriteID: + retval = TypeSpriteID; + break; + + case NAME_TextureID: + retval = TypeTextureID; + break; + + default: + retval = ResolveUserType(btype, &outertype->Symbols); + break; + } + break; + + default: + break; + } + break; + } + + case AST_MapType: + if (allowarraytypes) + { + Error(field, "%s: Map types not implemented yet", name.GetChars()); + // Todo: Decide what we allow here and if it makes sense to allow more complex constructs. + auto mtype = static_cast(ztype); + retval = NewMap(DetermineType(outertype, field, name, mtype->KeyType, false, false), DetermineType(outertype, field, name, mtype->ValueType, false, false)); + break; + } + break; + + case AST_DynArrayType: + if (allowarraytypes) + { + Error(field, "%s: Dynamic array types not implemented yet", name.GetChars()); + auto atype = static_cast(ztype); + retval = NewDynArray(DetermineType(outertype, field, name, atype->ElementType, false, false)); + break; + } + break; + + case AST_ClassType: + { + auto ctype = static_cast(ztype); + if (ctype->Restriction == nullptr) + { + retval = NewClassPointer(RUNTIME_CLASS(DObject)); + } + else + { + auto sym = outertype->Symbols.FindSymbol(ctype->Restriction->Id, true); + if (sym == nullptr) sym = GlobalSymbols.FindSymbol(ctype->Restriction->Id, false); + if (sym == nullptr) + { + Error(field, "%s: Unknown identifier", FName(ctype->Restriction->Id).GetChars()); + return TypeError; + } + auto typesym = dyn_cast(sym); + if (typesym == nullptr || !typesym->Type->IsKindOf(RUNTIME_CLASS(PClass))) + { + Error(field, "%s does not represent a class type", FName(ctype->Restriction->Id).GetChars()); + return TypeError; + } + retval = NewClassPointer(static_cast(typesym->Type)); + } + break; + } + + default: + break; + } + if (retval != TypeError && retval->MemberOnly && !formember) + { + Error(field, "Invalid type %s", retval->DescriptiveName()); + return TypeError; + } + return retval; +} + +//========================================================================== +// +// ZCCCompiler :: ResolveUserType +// +// resolves a user type and returns a matching PType +// +//========================================================================== + +PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt) +{ + // Check the symbol table for the identifier. + PSymbolTable *table; + PSymbol *sym = symt->FindSymbolInTable(type->UserType->Id, table); + // GlobalSymbols cannot be the parent of a class's symbol table so we have to look for global symbols explicitly. + if (sym == nullptr && symt != &GlobalSymbols) sym = GlobalSymbols.FindSymbolInTable(type->UserType->Id, table); + if (sym != nullptr && sym->IsKindOf(RUNTIME_CLASS(PSymbolType))) + { + auto ptype = static_cast(sym)->Type; + if (ptype->IsKindOf(RUNTIME_CLASS(PEnum))) + { + return TypeSInt32; // hack this to an integer until we can resolve the enum mess. + } + if (ptype->IsKindOf(RUNTIME_CLASS(PNativeStruct))) // native structs and classes cannot be instantiated, they always get used as reference. + { + return NewPointer(ptype, type->isconst); + } + return ptype; + } + Error(type, "Unable to resolve %s as type.", FName(type->UserType->Id).GetChars()); + return TypeError; +} + + +//========================================================================== +// +// ZCCCompiler :: ResolveArraySize +// +// resolves the array size and returns a matching type. +// +//========================================================================== + +PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PSymbolTable *sym) +{ + // The duplicate Simplify call is necessary because if the head node gets replaced there is no way to detect the end of the list otherwise. + arraysize = Simplify(arraysize, sym, true); + ZCC_Expression *val; + do + { + val = Simplify(arraysize, sym, true); + if (val->Operation != PEX_ConstValue || !val->Type->IsA(RUNTIME_CLASS(PInt))) + { + Error(arraysize, "Array index must be an integer constant"); + return TypeError; + } + int size = static_cast(val)->IntVal; + if (size < 1) + { + Error(arraysize, "Array size must be positive"); + return TypeError; + } + baseType = NewArray(baseType, size); + val = static_cast(val->SiblingNext); + } while (val != arraysize); + return baseType; +} + +//========================================================================== +// +// ZCCCompiler :: GetInt - Input must be a constant expression +// +//========================================================================== + +int ZCCCompiler::GetInt(ZCC_Expression *expr) +{ + if (expr->Type == TypeError) + { + return 0; + } + const PType::Conversion *route[CONVERSION_ROUTE_SIZE]; + int routelen = expr->Type->FindConversion(TypeSInt32, route, countof(route)); + if (routelen < 0) + { + Error(expr, "Cannot convert to integer"); + return 0; + } + else + { + if (expr->Type->IsKindOf(RUNTIME_CLASS(PFloat))) + { + Warn(expr, "Truncation of floating point value"); + } + auto ex = static_cast(ApplyConversion(expr, route, routelen)); + return ex->IntVal; + } +} + +double ZCCCompiler::GetDouble(ZCC_Expression *expr) +{ + if (expr->Type == TypeError) + { + return 0; + } + const PType::Conversion *route[CONVERSION_ROUTE_SIZE]; + int routelen = expr->Type->FindConversion(TypeFloat64, route, countof(route)); + if (routelen < 0) + { + Error(expr, "Cannot convert to float"); + return 0; + } + else + { + auto ex = static_cast(ApplyConversion(expr, route, routelen)); + return ex->DoubleVal; + } +} + +const char *ZCCCompiler::GetString(ZCC_Expression *expr, bool silent) +{ + if (expr->Type == TypeError) + { + return nullptr; + } + else if (expr->Type->IsKindOf(RUNTIME_CLASS(PString))) + { + return static_cast(expr)->StringVal->GetChars(); + } + else if (expr->Type->IsKindOf(RUNTIME_CLASS(PName))) + { + // Ugh... What a mess... + return FName(ENamedName(static_cast(expr)->IntVal)).GetChars(); + } + else + { + if (!silent) Error(expr, "Cannot convert to string"); + return nullptr; + } +} + +//========================================================================== +// +// Parses an actor property's parameters and calls the handler +// +//========================================================================== + +void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *property, AActor *defaults, Baggage &bag) +{ + static TArray params; + static TArray strings; + + params.Clear(); + strings.Clear(); + params.Reserve(1); + params[0].i = 0; + if (prop->params[0] != '0') + { + if (property->Values == nullptr) + { + Error(property, "%s: arguments missing", prop->name); + return; + } + property->Values = Simplify(property->Values, &bag.Info->Symbols, true); // need to do this before the loop so that we can find the head node again. + const char * p = prop->params; + auto exp = property->Values; + + while (true) + { + FPropParam conv; + FPropParam pref; + + if (exp->NodeType != AST_ExprConstant) + { + // If we get TypeError, there has already been a message from deeper down so do not print another one. + if (exp->Type != TypeError) Error(exp, "%s: non-constant parameter", prop->name); + return; + } + conv.s = nullptr; + pref.s = nullptr; + pref.i = -1; + switch ((*p) & 223) + { + + case 'X': // Expression in parentheses or number. We only support the constant here. The function will have to be handled by a separate property to get past the parser. + conv.i = GetInt(exp); + params.Push(conv); + conv.exp = nullptr; + break; + + case 'I': + case 'M': // special case for morph styles in DECORATE . This expression-aware parser will not need this. + case 'N': // special case for thing activations in DECORATE. This expression-aware parser will not need this. + conv.i = GetInt(exp); + break; + + case 'F': + conv.d = GetDouble(exp); + break; + + case 'Z': // an optional string. Does not allow any numeric value. + if (!GetString(exp, true)) + { + // apply this expression to the next argument on the list. + params.Push(conv); + params[0].i++; + p++; + continue; + } + conv.s = GetString(exp); + break; + + case 'C': // this parser accepts colors only in string form. + pref.i = 1; + case 'S': + case 'T': // a filtered string (ZScript only parses filtered strings so there's nothing to do here.) + conv.s = GetString(exp); + break; + + case 'L': // Either a number or a list of strings + if (!GetString(exp, true)) + { + pref.i = 0; + conv.i = GetInt(exp); + } + else + { + pref.i = 1; + params.Push(pref); + params[0].i++; + + do + { + conv.s = GetString(exp); + if (conv.s != nullptr) + { + params.Push(conv); + params[0].i++; + } + exp = Simplify(static_cast(exp->SiblingNext), &bag.Info->Symbols, true); + } while (exp != property->Values); + goto endofparm; + } + break; + + default: + assert(false); + break; + + } + if (pref.i != -1) + { + params.Push(pref); + params[0].i++; + } + params.Push(conv); + params[0].i++; + exp = Simplify(static_cast(exp->SiblingNext), &bag.Info->Symbols, true); + endofparm: + p++; + // Skip the DECORATE 'no comma' marker + if (*p == '_') p++; + + if (*p == 0) + { + if (exp != property->Values) + { + Error(property, "Too many values for '%s'", prop->name); + return; + } + break; + } + else if (exp == property->Values) + { + if (*p < 'a') + { + Error(property, "Insufficient parameters for %s", prop->name); + return; + } + break; + } + } + } + // call the handler + try + { + prop->Handler(defaults, bag.Info, bag, ¶ms[0]); + } + catch (CRecoverableError &error) + { + Error(property, "%s", error.GetMessage()); + } +} + +//========================================================================== +// +// Parses an actor property +// +//========================================================================== + +void ZCCCompiler::ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *prop, Baggage &bag) +{ + auto namenode = prop->Prop; + FString propname; + + if (namenode->SiblingNext == namenode) + { + if (namenode->Id == NAME_DamageFunction) + { + auto x = ConvertNode(prop->Values); + CreateDamageFunction(cls, (AActor *)bag.Info->Defaults, x, false, Lump); + ((AActor *)bag.Info->Defaults)->DamageVal = -1; + return; + } + + // a one-name property + propname = FName(namenode->Id); + + } + else if (namenode->SiblingNext->SiblingNext == namenode) + { + // a two-name property + propname << FName(namenode->Id) << "." << FName(static_cast(namenode->SiblingNext)->Id); + } + else + { + Error(prop, "Property name may at most contain two parts"); + return; + } + + + FPropertyInfo *property = FindProperty(propname); + + if (property != nullptr && property->category != CAT_INFO) + { + if (cls->IsDescendantOf(*property->cls)) + { + DispatchProperty(property, prop, (AActor *)bag.Info->Defaults, bag); + } + else + { + Error(prop, "'%s' requires an actor of type '%s'\n", propname.GetChars(), (*property->cls)->TypeName.GetChars()); + } + } + else + { + Error(prop, "'%s' is an unknown actor property\n", propname.GetChars()); + } +} + +//========================================================================== +// +// Finds a flag and sets or clears it +// +//========================================================================== + +void ZCCCompiler::ProcessDefaultFlag(PClassActor *cls, ZCC_FlagStmt *flg) +{ + auto namenode = flg->name; + const char *n1 = FName(namenode->Id).GetChars(), *n2; + + if (namenode->SiblingNext == namenode) + { + // a one-name flag + n2 = nullptr; + } + else if (namenode->SiblingNext->SiblingNext == namenode) + { + // a two-name flag + n2 = FName(static_cast(namenode->SiblingNext)->Id).GetChars(); + } + else + { + Error(flg, "Flag name may at most contain two parts"); + return; + } + + auto fd = FindFlag(cls, n1, n2, true); + if (fd != nullptr) + { + if (fd->varflags & VARF_Deprecated) + { + Warn(flg, "Deprecated flag '%s%s%s' used", n1, n2 ? "." : "", n2 ? n2 : ""); + } + if (fd->structoffset == -1) + { + HandleDeprecatedFlags((AActor*)cls->Defaults, cls, flg->set, fd->flagbit); + } + else + { + ModActorFlag((AActor*)cls->Defaults, fd, flg->set); + } + } + else + { + Error(flg, "Unknown flag '%s%s%s'", n1, n2 ? "." : "", n2 ? n2 : ""); + } +} + +//========================================================================== +// +// Parses the default list +// +//========================================================================== + +void ZCCCompiler::InitDefaults() +{ + for (auto c : Classes) + { + // This may be removed if the conditions change, but right now only subclasses of Actor can define a Default block. + if (!c->Type()->IsDescendantOf(RUNTIME_CLASS(AActor))) + { + if (c->Defaults.Size()) Error(c->cls, "%s: Non-actor classes may not have defaults", c->Type()->TypeName.GetChars()); + if (c->Type()->ParentClass) c->Type()->ParentClass->DeriveData(c->Type()); + } + else + { + // This should never happen. + if (c->Type()->Defaults != nullptr) + { + Error(c->cls, "%s already has defaults", c->Type()->TypeName.GetChars()); + } + // This can only occur if a native parent is not initialized. In all other cases the sorting of the class list should prevent this from ever happening. + else if (c->Type()->ParentClass->Defaults == nullptr && c->Type() != RUNTIME_CLASS(AActor)) + { + Error(c->cls, "Parent class %s of %s is not initialized", c->Type()->ParentClass->TypeName.GetChars(), c->Type()->TypeName.GetChars()); + } + else + { + // Copy the parent's defaults and meta data. + auto ti = static_cast(c->Type()); + + ti->InitializeDefaults(); + ti->ParentClass->DeriveData(ti); + + // We need special treatment for this one field in AActor's defaults which cannot be made visible to DECORATE as a property. + // It's better to do this here under controlled conditions than deeper down in the class type classes. + if (ti == RUNTIME_CLASS(AActor)) + { + ((AActor*)ti->Defaults)->ConversationRoot = 1; + } + + Baggage bag; + #ifdef _DEBUG + bag.ClassName = c->Type()->TypeName; + #endif + bag.Info = ti; + bag.DropItemSet = false; + bag.StateSet = false; + bag.fromDecorate = false; + bag.CurrentState = 0; + bag.Lumpnum = c->cls->SourceLump; + bag.DropItemList = nullptr; + // The actual script position needs to be set per property. + + for (auto d : c->Defaults) + { + auto content = d->Content; + if (content != nullptr) do + { + switch (content->NodeType) + { + case AST_PropertyStmt: + bag.ScriptPosition.FileName = *content->SourceName; + bag.ScriptPosition.ScriptLine = content->SourceLoc; + ProcessDefaultProperty(ti, static_cast(content), bag); + break; + + case AST_FlagStmt: + ProcessDefaultFlag(ti, static_cast(content)); + break; + + default: + break; + } + content = static_cast(content->SiblingNext); + } while (content != d->Content); + } + if (bag.DropItemSet) + { + bag.Info->SetDropItems(bag.DropItemList); + } + } + } + } +} + + +void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool forclass) +{ + TArray rets(1); + TArray args; + TArray argflags; + TArray argdefaults; + TArray argnames; + + rets.Clear(); + args.Clear(); + argflags.Clear(); + bool hasdefault = false; + // For the time being, let's not allow overloading. This may be reconsidered later but really just adds an unnecessary amount of complexity here. + if (AddTreeNode(f->Name, f, &c->TreeNodes, false)) + { + auto t = f->Type; + if (t != nullptr) + { + do + { + auto type = DetermineType(c->Type(), f, f->Name, t, false, false); + if (type->IsKindOf(RUNTIME_CLASS(PStruct)) && type != TypeVector2 && type != TypeVector3) + { + // structs and classes only get passed by pointer. + type = NewPointer(type); + } + // TBD: disallow certain types? For now, let everything pass that isn't an array. + rets.Push(type); + t = static_cast(t->SiblingNext); + } while (t != f->Type); + } + + int notallowed = ZCC_Latent | ZCC_Meta | ZCC_ReadOnly | ZCC_FuncConst | ZCC_Abstract; + + if (f->Flags & notallowed) + { + Error(f, "Invalid qualifiers for %s (%s not allowed)", FName(f->Name).GetChars(), FlagsToString(f->Flags & notallowed).GetChars()); + f->Flags &= notallowed; + } + uint32_t varflags = VARF_Method; + int implicitargs = 1; + AFuncDesc *afd = nullptr; + int useflags = SUF_ACTOR | SUF_OVERLAY | SUF_WEAPON | SUF_ITEM; + if (f->UseFlags != nullptr) + { + useflags = 0; + auto p = f->UseFlags; + do + { + switch (p->Id) + { + case NAME_Actor: + useflags |= SUF_ACTOR; + break; + case NAME_Overlay: + useflags |= SUF_OVERLAY; + break; + case NAME_Weapon: + useflags |= SUF_WEAPON; + break; + case NAME_Item: + useflags |= SUF_ITEM; + break; + default: + Error(p, "Unknown Action qualifier %s", FName(p->Id).GetChars()); + break; + } + + p = static_cast(p->SiblingNext); + } while (p != f->UseFlags); + } + + // map to implementation flags. + if (f->Flags & ZCC_Private) varflags |= VARF_Private; + if (f->Flags & ZCC_Protected) varflags |= VARF_Protected; + if (f->Flags & ZCC_Deprecated) varflags |= VARF_Deprecated; + if (f->Flags & ZCC_Virtual) varflags |= VARF_Virtual; + if (f->Flags & ZCC_Override) varflags |= VARF_Override; + if (f->Flags & ZCC_Action) + { + // Non-Actors cannot have action functions. + if (!c->Type()->IsKindOf(RUNTIME_CLASS(PClassActor))) + { + Error(f, "'Action' can only be used in child classes of Actor"); + } + + varflags |= VARF_Final; // Action implies Final. + if (useflags & (SUF_OVERLAY | SUF_WEAPON | SUF_ITEM)) + { + varflags |= VARF_Action; + implicitargs = 3; + } + else + { + implicitargs = 1; + } + } + if (f->Flags & ZCC_Static) varflags = (varflags & ~VARF_Method) | VARF_Final, implicitargs = 0; // Static implies Final. + + + if (varflags & VARF_Override) varflags &= ~VARF_Virtual; // allow 'virtual override'. + // Only one of these flags may be used. + static int exclude[] = { ZCC_Virtual, ZCC_Override, ZCC_Action, ZCC_Static }; + static const char * print[] = { "virtual", "override", "action", "static" }; + int fc = 0; + FString build; + for (int i = 0; i < 4; i++) + { + if (f->Flags & exclude[i]) + { + fc++; + if (build.Len() > 0) build += ", "; + build += print[i]; + } + } + if (fc > 1) + { + Error(f, "Invalid combination of qualifiers %s on function %s.", FName(f->Name).GetChars(), build.GetChars()); + varflags |= VARF_Method; + } + if (varflags & VARF_Override) varflags |= VARF_Virtual; // Now that the flags are checked, make all override functions virtual as well. + + if (f->Flags & ZCC_Native) + { + varflags |= VARF_Native; + afd = FindFunction(c->Type(), FName(f->Name).GetChars()); + if (afd == nullptr) + { + Error(f, "The function '%s.%s' has not been exported from the executable.", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()); + } + else + { + (*afd->VMPointer)->ImplicitArgs = BYTE(implicitargs); + } + } + SetImplicitArgs(&args, &argflags, &argnames, c->Type(), varflags, useflags); + argdefaults.Resize(argnames.Size()); + auto p = f->Params; + bool hasoptionals = false; + if (p != nullptr) + { + do + { + int elementcount = 1; + VMValue vmval[3]; // default is REGT_NIL which means 'no default value' here. + if (p->Type != nullptr) + { + auto type = DetermineType(c->Type(), p, f->Name, p->Type, false, false); + int flags = 0; + if (type->IsA(RUNTIME_CLASS(PStruct)) && type != TypeVector2 && type != TypeVector3) + { + // Structs are being passed by pointer, but unless marked 'out' that pointer must be readonly. + type = NewPointer(type /*, !(p->Flags & ZCC_Out)*/); + flags |= VARF_Ref; + } + else if (type->GetRegType() != REGT_NIL) + { + if (p->Flags & ZCC_Out) flags |= VARF_Out; + if (type == TypeVector2) + { + elementcount = 2; + } + else if (type == TypeVector3) + { + elementcount = 3; + } + } + if (type->GetRegType() == REGT_NIL && type != TypeVector2 && type != TypeVector3) + { + Error(p, "Invalid type %s for function parameter", type->DescriptiveName()); + } + else if (p->Default != nullptr) + { + flags |= VARF_Optional; + hasoptionals = true; + // The simplifier is not suited to convert the constant into something usable. + // All it does is reduce the expression to a constant but we still got to do proper type checking and conversion. + // It will also lose important type info about enums, once these get implemented + // The code generator can do this properly for us. + FxExpression *x = new FxTypeCast(ConvertNode(p->Default), type, false); + FCompileContext ctx(c->Type(), false); + x = x->Resolve(ctx); + + if (x != nullptr) + { + // Vectors need special treatment because they use more than one entry in the Defaults and do not report as actual constants + if (type == TypeVector2 && x->ExprType == EFX_VectorValue && static_cast(x)->isConstVector(2)) + { + auto vx = static_cast(x); + vmval[0] = static_cast(vx->xyz[0])->GetValue().GetFloat(); + vmval[1] = static_cast(vx->xyz[1])->GetValue().GetFloat(); + } + else if (type == TypeVector3 && x->ExprType == EFX_VectorValue && static_cast(x)->isConstVector(3)) + { + auto vx = static_cast(x); + vmval[0] = static_cast(vx->xyz[0])->GetValue().GetFloat(); + vmval[1] = static_cast(vx->xyz[1])->GetValue().GetFloat(); + vmval[2] = static_cast(vx->xyz[2])->GetValue().GetFloat(); + } + else if (!x->isConstant()) + { + Error(p, "Default parameter %s is not constant in %s", FName(p->Name).GetChars(), FName(f->Name).GetChars()); + } + else if (x->ValueType != type) + { + Error(p, "Default parameter %s could not be converted to target type %s", FName(p->Name).GetChars(), c->Type()->TypeName.GetChars()); + } + else + { + auto cnst = static_cast(x); + hasdefault = true; + switch (type->GetRegType()) + { + case REGT_INT: + vmval[0] = cnst->GetValue().GetInt(); + break; + + case REGT_FLOAT: + vmval[0] = cnst->GetValue().GetFloat(); + break; + + case REGT_POINTER: + if (type->IsKindOf(RUNTIME_CLASS(PClassPointer))) + vmval[0] = (DObject*)cnst->GetValue().GetPointer(); + else + vmval[0] = cnst->GetValue().GetPointer(); + break; + + case REGT_STRING: + vmval[0] = cnst->GetValue().GetString(); + break; + + default: + assert(0 && "no valid type for constant"); + break; + } + } + } + if (x != nullptr) delete x; + } + else if (hasoptionals) + { + Error(p, "All arguments after the first optional one need also be optional."); + } + // TBD: disallow certain types? For now, let everything pass that isn't an array. + args.Push(type); + argflags.Push(flags); + argnames.Push(p->Name); + + } + else + { + args.Push(nullptr); + argflags.Push(0); + argnames.Push(NAME_None); + } + for (int i = 0; i(p->SiblingNext); + } while (p != f->Params); + } + + PFunction *sym = new PFunction(c->Type(), f->Name); + sym->AddVariant(NewPrototype(rets, args), argflags, argnames, afd == nullptr ? nullptr : *(afd->VMPointer), varflags, useflags); + c->Type()->Symbols.ReplaceSymbol(sym); + + auto cls = dyn_cast(c->Type()); + PFunction *virtsym = nullptr; + if (cls != nullptr && cls->ParentClass != nullptr) virtsym = dyn_cast(cls->ParentClass->Symbols.FindSymbol(FName(f->Name), true)); + unsigned vindex = ~0u; + if (virtsym != nullptr) vindex = virtsym->Variants[0].Implementation->VirtualIndex; + + if (vindex != ~0u || (varflags & VARF_Virtual)) + { + // Todo: Check if the declaration is legal. + + // First step: compare prototypes - if they do not match the virtual base method does not apply. + + // Second step: Check flags. Possible cases: + // 1. Base method is final: Error. + // 2. This method is override: Base virtual method must exist + // 3. This method is virtual but not override: Base may not have a virtual method with the same prototype. + } + + + if (!(f->Flags & ZCC_Native)) + { + if (f->Body == nullptr) + { + Error(f, "Empty function %s", FName(f->Name).GetChars()); + return; + } + else + { + auto code = ConvertAST(c->Type(), f->Body); + if (code != nullptr) + { + FunctionBuildList.AddFunction(sym, code, FStringf("%s.%s", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()), false, -1, 0, Lump); + } + } + } + if (sym->Variants[0].Implementation != nullptr && hasdefault) // do not copy empty default lists, they only waste space and processing time. + { + sym->Variants[0].Implementation->DefaultArgs = std::move(argdefaults); + } + + if (varflags & VARF_Virtual) + { + if (sym->Variants[0].Implementation == nullptr) + { + Error(f, "Virtual function %s.%s not present.", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()); + return; + } + if (varflags & VARF_Final) + { + sym->Variants[0].Implementation->Final = true; + } + if (forclass) + { + PClass *clstype = static_cast(c->Type()); + int vindex = clstype->FindVirtualIndex(sym->SymbolName, sym->Variants[0].Proto); + // specifying 'override' is necessary to prevent one of the biggest problem spots with virtual inheritance: Mismatching argument types. + if (varflags & VARF_Override) + { + if (vindex == -1) + { + Error(f, "Attempt to override non-existent virtual function %s", FName(f->Name).GetChars()); + } + else + { + auto oldfunc = clstype->Virtuals[vindex]; + if (oldfunc->Final) + { + Error(f, "Attempt to override final function %s", FName(f->Name).GetChars()); + } + clstype->Virtuals[vindex] = sym->Variants[0].Implementation; + sym->Variants[0].Implementation->VirtualIndex = vindex; + } + } + else + { + if (vindex != -1) + { + Error(f, "Function %s attempts to override parent function without 'override' qualifier", FName(f->Name).GetChars()); + } + sym->Variants[0].Implementation->VirtualIndex = clstype->Virtuals.Push(sym->Variants[0].Implementation); + } + } + else + { + Error(p, "Virtual functions can only be defined for classes"); + } + } + } +} + +//========================================================================== +// +// Parses the functions list +// +//========================================================================== + +void ZCCCompiler::InitFunctions() +{ + for (auto s : Structs) + { + for (auto f : s->Functions) + { + CompileFunction(s, f, false); + } + } + + for (auto c : Classes) + { + // cannot be done earlier because it requires the parent class to be processed by this code, too. + if (c->Type()->ParentClass != nullptr) + { + c->Type()->Virtuals = c->Type()->ParentClass->Virtuals; + } + for (auto f : c->Functions) + { + CompileFunction(c, f, true); + } + } +} + +//========================================================================== +// +// very complicated check for random duration. +// +//========================================================================== + +static bool CheckRandom(ZCC_Expression *duration) +{ + if (duration->NodeType != AST_ExprFuncCall) return false; + auto func = static_cast(duration); + if (func->Function == nullptr) return false; + if (func->Function->NodeType != AST_ExprID) return false; + auto f2 = static_cast(func->Function); + return f2->Identifier == NAME_Random; +} + +//========================================================================== +// +// Sets up the action function call +// +//========================================================================== +FxExpression *ZCCCompiler::SetupActionFunction(PClass *cls, ZCC_TreeNode *af, int StateFlags) +{ + // We have 3 cases to consider here: + // 1. A function without parameters. This can be called directly + // 2. A functon with parameters. This needs to be wrapped into a helper function to set everything up. + // 3. An anonymous function. + + // 1. and 2. are exposed through AST_ExprFunctionCall + if (af->NodeType == AST_ExprFuncCall) + { + auto fc = static_cast(af); + assert(fc->Function->NodeType == AST_ExprID); + auto id = static_cast(fc->Function); + + // We must skip ACS_NamedExecuteWithResult here, because this name both exists as an action function and as a builtin. + // The code which gets called from here can easily make use of the builtin, so let's just pass this name without any checks. + // The actual action function is still needed by DECORATE: + if (id->Identifier != NAME_ACS_NamedExecuteWithResult) + { + PFunction *afd = dyn_cast(cls->Symbols.FindSymbol(id->Identifier, true)); + if (afd != nullptr) + { + if (fc->Parameters == nullptr && !(afd->Variants[0].Flags & VARF_Virtual)) + { + FArgumentList argumentlist; + // We can use this function directly without wrapping it in a caller. + auto selfclass = dyn_cast(afd->Variants[0].SelfClass); + assert(selfclass != nullptr); // non classes are not supposed to get here. + + int comboflags = afd->Variants[0].UseFlags & StateFlags; + if (comboflags == StateFlags) // the function must satisfy all the flags the state requires + { + return new FxVMFunctionCall(new FxSelf(*af), afd, argumentlist, *af, false); + } + else + { + Error(af, "Cannot use non-action function %s here.", FName(id->Identifier).GetChars()); + } + } + } + else + { + // it may also be an action special so check that first before printing an error. + if (!P_FindLineSpecial(FName(id->Identifier).GetChars())) + { + Error(af, "%s: action function not found in %s", FName(id->Identifier).GetChars(), cls->TypeName.GetChars()); + return nullptr; + } + // Action specials fall through to the code generator. + } + } + } + return ConvertAST(cls, af); +} + +//========================================================================== +// +// Compile the states +// +//========================================================================== + +void ZCCCompiler::CompileStates() +{ + for (auto c : Classes) + { + + if (!c->Type()->IsDescendantOf(RUNTIME_CLASS(AActor))) + { + if (c->States.Size()) Error(c->cls, "%s: States can only be defined for actors.", c->Type()->TypeName.GetChars()); + continue; + } + + // Same here, hack in the DVMObject as they weren't in the list originally + // TODO: process them in a non hackish way obviously + if (c->Type()->bRuntimeClass == true && c->Type()->ParentClass->bRuntimeClass == false) + { + auto vmtype = static_cast(c->Type()->ParentClass); + if (vmtype->StateList == nullptr) + { + FStateDefinitions vmstates; + vmstates.MakeStateDefines(dyn_cast(vmtype->ParentClass)); + vmtype->Finalize(vmstates); + } + } + + FString statename; // The state builder wants the label as one complete string, not separated into tokens. + FStateDefinitions statedef; + statedef.MakeStateDefines(dyn_cast(c->Type()->ParentClass)); + int numframes = 0; + + for (auto s : c->States) + { + int flags; + if (s->Flags != nullptr) + { + flags = 0; + auto p = s->Flags; + do + { + switch (p->Id) + { + case NAME_Actor: + flags |= SUF_ACTOR; + break; + case NAME_Overlay: + flags |= SUF_OVERLAY; + break; + case NAME_Weapon: + flags |= SUF_WEAPON; + break; + case NAME_Item: + flags |= SUF_ITEM; + break; + default: + Error(p, "Unknown States qualifier %s", FName(p->Id).GetChars()); + break; + } + + p = static_cast(p->SiblingNext); + } while (p != s->Flags); + } + else + { + flags = static_cast(c->Type())->DefaultStateUsage; + } + auto st = s->Body; + if (st != nullptr) do + { + switch (st->NodeType) + { + case AST_StateLabel: + { + auto sl = static_cast(st); + statename = FName(sl->Label); + statedef.AddStateLabel(statename); + break; + } + case AST_StateLine: + { + auto sl = static_cast(st); + FState state; + memset(&state, 0, sizeof(state)); + state.UseFlags = flags; + if (sl->Sprite->Len() != 4) + { + Error(sl, "Sprite name must be exactly 4 characters. Found '%s'", sl->Sprite->GetChars()); + } + else + { + state.sprite = GetSpriteIndex(sl->Sprite->GetChars()); + } + // It is important to call CheckRandom before Simplify, because Simplify will resolve the function's name to nonsense + if (CheckRandom(sl->Duration)) + { + auto func = static_cast(sl->Duration); + if (func->Parameters == func->Parameters->SiblingNext || func->Parameters != func->Parameters->SiblingNext->SiblingNext) + { + Error(sl, "Random duration requires exactly 2 parameters"); + } + auto p1 = Simplify(func->Parameters->Value, &c->Type()->Symbols, true); + auto p2 = Simplify(static_cast(func->Parameters->SiblingNext)->Value, &c->Type()->Symbols, true); + int v1 = GetInt(p1); + int v2 = GetInt(p2); + if (v1 > v2) std::swap(v1, v2); + state.Tics = (int16_t)clamp(v1, 0, INT16_MAX); + state.TicRange = (uint16_t)clamp(v2 - v1, 0, UINT16_MAX); + } + else + { + auto duration = Simplify(sl->Duration, &c->Type()->Symbols, true); + if (duration->Operation == PEX_ConstValue) + { + state.Tics = (int16_t)clamp(GetInt(duration), -1, INT16_MAX); + state.TicRange = 0; + } + else + { + Error(sl, "Duration is not a constant"); + } + } + if (sl->bBright) state.StateFlags |= STF_FULLBRIGHT; + if (sl->bFast) state.StateFlags |= STF_FAST; + if (sl->bSlow) state.StateFlags |= STF_SLOW; + if (sl->bCanRaise) state.StateFlags |= STF_CANRAISE; + if (sl->bNoDelay) state.StateFlags |= STF_NODELAY; + if (sl->bNoDelay) + { + if (statedef.GetStateLabelIndex(NAME_Spawn) != statedef.GetStateCount()) + { + Warn(sl, "NODELAY only has an effect on the first state after 'Spawn:'"); + } + } + if (sl->Offset != nullptr) + { + auto o1 = static_cast(Simplify(sl->Offset, &c->Type()->Symbols, true)); + auto o2 = static_cast(Simplify(static_cast(o1->SiblingNext), &c->Type()->Symbols, true)); + + if (o1->Operation != PEX_ConstValue || o2->Operation != PEX_ConstValue) + { + Error(o1, "State offsets must be constant"); + } + else + { + state.Misc1 = GetInt(o1); + state.Misc2 = GetInt(o2); + } + } +#ifdef DYNLIGHT + if (sl->Lights != nullptr) + { + auto l = sl->Lights; + do + { + AddStateLight(&state, GetString(l)); + l = static_cast(l->SiblingNext); + } while (l != sl->Lights); + } +#endif + + if (sl->Action != nullptr) + { + auto code = SetupActionFunction(static_cast(c->Type()), sl->Action, state.UseFlags); + if (code != nullptr) + { + auto funcsym = CreateAnonymousFunction(c->Type(), nullptr, state.UseFlags); + state.ActionFunc = FunctionBuildList.AddFunction(funcsym, code, FStringf("%s.StateFunction.%d", c->Type()->TypeName.GetChars(), statedef.GetStateCount()), false, statedef.GetStateCount(), (int)sl->Frames->Len(), Lump); + } + } + + int count = statedef.AddStates(&state, sl->Frames->GetChars(), *sl); + if (count < 0) + { + Error(sl, "Invalid frame character string '%s'", sl->Frames->GetChars()); + count = -count; + } + break; + } + case AST_StateGoto: + { + auto sg = static_cast(st); + statename = ""; + if (sg->Qualifier != nullptr) + { + statename << FName(sg->Qualifier->Id) << "::"; + } + auto part = sg->Label; + do + { + statename << FName(part->Id) << '.'; + part = static_cast(part->SiblingNext); + } while (part != sg->Label); + statename.Truncate((long)statename.Len() - 1); // remove the last '.' in the label name + if (sg->Offset != nullptr) + { + auto ofs = Simplify(sg->Offset, &c->Type()->Symbols, true); + if (ofs->Operation != PEX_ConstValue) + { + Error(sg, "Constant offset expected for GOTO"); + } + else + { + int offset = GetInt(ofs); + if (offset < 0) + { + Error(sg, "GOTO offset must be positive"); + offset = 0; + } + if (offset > 0) + { + statename.AppendFormat("+%d", offset); + } + } + } + if (!statedef.SetGotoLabel(statename)) + { + Error(sg, "GOTO before first state"); + } + break; + } + case AST_StateFail: + case AST_StateWait: + if (!statedef.SetWait()) + { + Error(st, "%s before first state", st->NodeType == AST_StateFail ? "Fail" : "Wait"); + continue; + } + break; + + case AST_StateLoop: + if (!statedef.SetLoop()) + { + Error(st, "LOOP before first state"); + continue; + } + break; + + case AST_StateStop: + if (!statedef.SetStop()) + { + Error(st, "STOP before first state"); + } + break; + + default: + assert(0 && "Bad AST node in state"); + } + st = static_cast(st->SiblingNext); + } while (st != s->Body); + } + try + { + static_cast(c->Type())->Finalize(statedef); + } + catch (CRecoverableError &err) + { + Error(c->cls, "%s", err.GetMessage()); + } + } +} + +//========================================================================== +// +// Convert the AST data for the code generator. +// +//========================================================================== + +FxExpression *ZCCCompiler::ConvertAST(PStruct *cls, ZCC_TreeNode *ast) +{ + ConvertClass = cls; + // there are two possibilities here: either a single function call or a compound statement. For a compound statement we also need to check if the last thing added was a return. + if (ast->NodeType == AST_ExprFuncCall) + { + auto cp = new FxCompoundStatement(*ast); + cp->Add(new FxReturnStatement(ConvertNode(ast), *ast)); + return cp; + } + else + { + // This must be done here so that we can check for a trailing return statement. + auto x = new FxCompoundStatement(*ast); + auto compound = static_cast(ast); + //bool isreturn = false; + auto node = compound->Content; + if (node != nullptr) do + { + x->Add(ConvertNode(node)); + //isreturn = node->NodeType == AST_ReturnStmt; + node = static_cast(node->SiblingNext); + } while (node != compound->Content); + //if (!isreturn) x->Add(new FxReturnStatement(nullptr, *ast)); + return x; + } +} + + +#define xx(a,z) z, +static int Pex2Tok[] = { +#include "zcc_exprlist.h" +}; + +//========================================================================== +// +// Helper for modify/assign operators +// +//========================================================================== + +static FxExpression *ModifyAssign(FxBinary *operation, FxExpression *left) +{ + auto assignself = static_cast(operation->left); + auto assignment = new FxAssign(left, operation, true); + assignself->Assignment = assignment; + return assignment; +} + + +//========================================================================== +// +// Convert an AST node and its children +// +//========================================================================== + +FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) +{ + if (ast == nullptr) return nullptr; + + // Note: Do not call 'Simplify' here because that function tends to destroy identifiers due to lack of context in which to resolve them. + // The Fx nodes created here will be better suited for that. + switch (ast->NodeType) + { + case AST_ExprFuncCall: + { + auto fcall = static_cast(ast); + + // function names can either be + // - plain identifiers + // - class members + // - array syntax for random() calls. + // Everything else coming here is a syntax error. + FArgumentList args; + switch (fcall->Function->NodeType) + { + case AST_ExprID: + // The function name is a simple identifier. + return new FxFunctionCall(static_cast(fcall->Function)->Identifier, NAME_None, ConvertNodeList(args, fcall->Parameters), *ast); + + case AST_ExprMemberAccess: + { + auto ema = static_cast(fcall->Function); + return new FxMemberFunctionCall(ConvertNode(ema->Left), ema->Right, ConvertNodeList(args, fcall->Parameters), *ast); + } + + case AST_ExprBinary: + // Array syntax for randoms. They are internally stored as ExprBinary with both an identifier on the left and right side. + if (fcall->Function->Operation == PEX_ArrayAccess) + { + auto binary = static_cast(fcall->Function); + if (binary->Left->NodeType == AST_ExprID && binary->Right->NodeType == AST_ExprID) + { + return new FxFunctionCall(static_cast(binary->Left)->Identifier, static_cast(binary->Right)->Identifier, ConvertNodeList(args, fcall->Parameters), *ast); + } + } + // fall through if this isn't an array access node. + + default: + Error(fcall, "Invalid function identifier"); + return new FxNop(*ast); // return something so that the compiler can continue. + } + break; + } + + case AST_ClassCast: + { + auto cc = static_cast(ast); + if (cc->Parameters == nullptr || cc->Parameters->SiblingNext != cc->Parameters) + { + Error(cc, "Class type cast requires exactly one parameter"); + return new FxNop(*ast); // return something so that the compiler can continue. + } + auto cls = PClass::FindClass(cc->ClassName); + if (cls == nullptr) + { + Error(cc, "Unknown class %s", FName(cc->ClassName).GetChars()); + return new FxNop(*ast); // return something so that the compiler can continue. + } + return new FxClassPtrCast(cls, ConvertNode(cc->Parameters)); + } + + case AST_StaticArrayStatement: + { + auto sas = static_cast(ast); + PType *ztype = DetermineType(ConvertClass, sas, sas->Id, sas->Type, false, false); + FArgumentList args; + ConvertNodeList(args, sas->Values); + // This has to let the code generator resolve the constants, not the Simplifier, which lacks all the necessary type info. + return new FxStaticArray(ztype, sas->Id, args, *ast); + } + + case AST_ExprMemberAccess: + { + auto memaccess = static_cast(ast); + return new FxMemberIdentifier(ConvertNode(memaccess->Left), memaccess->Right, *ast); + } + + case AST_FuncParm: + { + auto fparm = static_cast(ast); + auto node = ConvertNode(fparm->Value); + if (fparm->Label != NAME_None) node = new FxNamedNode(fparm->Label, node, *ast); + return node; + } + + case AST_ExprID: + { + auto id = static_cast(ast); + return new FxIdentifier(id->Identifier, *ast); + } + + case AST_ExprConstant: + { + auto cnst = static_cast(ast); + if (cnst->Type->IsA(RUNTIME_CLASS(PName))) + { + return new FxConstant(FName(ENamedName(cnst->IntVal)), *ast); + } + else if (cnst->Type->IsA(RUNTIME_CLASS(PInt))) + { + return new FxConstant(cnst->IntVal, *ast); + } + else if (cnst->Type->IsA(RUNTIME_CLASS(PBool))) + { + return new FxConstant(!!cnst->IntVal, *ast); + } + else if (cnst->Type->IsA(RUNTIME_CLASS(PFloat))) + { + return new FxConstant(cnst->DoubleVal, *ast); + } + else if (cnst->Type->IsA(RUNTIME_CLASS(PString))) + { + return new FxConstant(*cnst->StringVal, *ast); + } + else if (cnst->Type == TypeNullPtr) + { + return new FxConstant(*ast); + } + else + { + // can there be other types? + Error(cnst, "Unknown constant type %s", cnst->Type->DescriptiveName()); + return new FxConstant(0, *ast); + } + } + + case AST_ExprUnary: + { + auto unary = static_cast(ast); + auto operand = ConvertNode(unary->Operand); + auto op = unary->Operation; + switch (op) + { + case PEX_PostDec: + case PEX_PostInc: + return new FxPostIncrDecr(operand, Pex2Tok[op]); + + case PEX_PreDec: + case PEX_PreInc: + return new FxPreIncrDecr(operand, Pex2Tok[op]); + + case PEX_Negate: + return new FxMinusSign(operand); + + case PEX_AntiNegate: + return new FxPlusSign(operand); + + case PEX_BitNot: + return new FxUnaryNotBitwise(operand); + + case PEX_BoolNot: + return new FxUnaryNotBoolean(operand); + + case PEX_SizeOf: + case PEX_AlignOf: + return new FxSizeAlign(operand, Pex2Tok[op]); + + default: + assert(0 && "Unknown unary operator."); // should never happen + Error(unary, "Unknown unary operator ID #%d", op); + return new FxNop(*ast); + } + break; + } + + + case AST_ExprBinary: + { + auto binary = static_cast(ast); + auto left = ConvertNode(binary->Left); + auto right = ConvertNode(binary->Right); + auto op = binary->Operation; + auto tok = Pex2Tok[op]; + switch (op) + { + case PEX_Add: + case PEX_Sub: + return new FxAddSub(tok, left, right); + + case PEX_Mul: + case PEX_Div: + case PEX_Mod: + return new FxMulDiv(tok, left, right); + + case PEX_Pow: + return new FxPow(left, right); + + case PEX_LeftShift: + case PEX_RightShift: + case PEX_URightShift: + return new FxShift(tok, left, right); + + case PEX_BitAnd: + case PEX_BitOr: + case PEX_BitXor: + return new FxBitOp(tok, left, right); + + case PEX_BoolOr: + case PEX_BoolAnd: + return new FxBinaryLogical(tok, left, right); + + case PEX_LT: + case PEX_LTEQ: + case PEX_GT: + case PEX_GTEQ: + return new FxCompareRel(tok, left, right); + + case PEX_EQEQ: + case PEX_NEQ: + case PEX_APREQ: + return new FxCompareEq(tok, left, right); + + case PEX_Assign: + return new FxAssign(left, right); + + case PEX_AddAssign: + case PEX_SubAssign: + return ModifyAssign(new FxAddSub(tok, new FxAssignSelf(*ast), right), left); + + case PEX_MulAssign: + case PEX_DivAssign: + case PEX_ModAssign: + return ModifyAssign(new FxMulDiv(tok, new FxAssignSelf(*ast), right), left); + + case PEX_LshAssign: + case PEX_RshAssign: + case PEX_URshAssign: + return ModifyAssign(new FxShift(tok, new FxAssignSelf(*ast), right), left); + + case PEX_AndAssign: + case PEX_OrAssign: + case PEX_XorAssign: + return ModifyAssign(new FxBitOp(tok, new FxAssignSelf(*ast), right), left); + + case PEX_LTGTEQ: + return new FxLtGtEq(left, right); + + case PEX_ArrayAccess: + return new FxArrayElement(left, right); + + case PEX_CrossProduct: + case PEX_DotProduct: + return new FxDotCross(tok, left, right); + + case PEX_Is: + return new FxTypeCheck(left, right); + + case PEX_Concat: + return new FxConcat(left, right); + + default: + I_Error("Binary operator %d not implemented yet", op); + } + break; + } + + case AST_ExprTrinary: + { + auto trinary = static_cast(ast); + auto condition = ConvertNode(trinary->Test); + auto left = ConvertNode(trinary->Left); + auto right = ConvertNode(trinary->Right); + + return new FxConditional(condition, left, right); + } + + case AST_VectorValue: + { + auto vecini = static_cast(ast); + auto xx = ConvertNode(vecini->X); + auto yy = ConvertNode(vecini->Y); + auto zz = ConvertNode(vecini->Z); + return new FxVectorValue(xx, yy, zz, *ast); + } + + case AST_LocalVarStmt: + { + auto loc = static_cast(ast); + auto node = loc->Vars; + FxSequence *list = new FxSequence(*ast); + + PType *ztype = DetermineType(ConvertClass, node, node->Name, loc->Type, true, false); + + if (loc->Type->ArraySize != nullptr) + { + ztype = ResolveArraySize(ztype, loc->Type->ArraySize, &ConvertClass->Symbols); + } + + do + { + PType *type; + + if (node->ArraySize != nullptr) + { + type = ResolveArraySize(ztype, node->ArraySize, &ConvertClass->Symbols); + } + else + { + type = ztype; + } + + FxExpression *val; + if (node->InitIsArray) + { + Error(node, "Compound initializer not implemented yet"); + val = nullptr; + } + else + { + val = node->Init ? ConvertNode(node->Init) : nullptr; + } + list->Add(new FxLocalVariableDeclaration(type, node->Name, val, 0, *node)); // todo: Handle flags in the grammar. + + node = static_cast(node->SiblingNext); + } while (node != loc->Vars); + return list; + } + + case AST_Expression: + { + auto ret = static_cast(ast); + if (ret->Operation == PEX_Super) + { + return new FxSuper(*ast); + } + break; + } + + case AST_ExpressionStmt: + return ConvertNode(static_cast(ast)->Expression); + + case AST_ReturnStmt: + { + auto ret = static_cast(ast); + FArgumentList args; + ConvertNodeList(args, ret->Values); + if (args.Size() == 0) + { + return new FxReturnStatement(nullptr, *ast); + } + else if (args.Size() == 1) + { + auto arg = args[0]; + args[0] = nullptr; + return new FxReturnStatement(arg, *ast); + } + else + { + Error(ast, "Return with multiple values not implemented yet."); + return new FxReturnStatement(nullptr, *ast); + } + } + + case AST_BreakStmt: + case AST_ContinueStmt: + return new FxJumpStatement(ast->NodeType == AST_BreakStmt ? TK_Break : TK_Continue, *ast); + + case AST_IfStmt: + { + auto iff = static_cast(ast); + return new FxIfStatement(ConvertNode(iff->Condition), ConvertNode(iff->TruePath), ConvertNode(iff->FalsePath), *ast); + } + + case AST_IterationStmt: + { + auto iter = static_cast(ast); + if (iter->CheckAt == ZCC_IterationStmt::End) + { + assert(iter->LoopBumper == nullptr); + return new FxDoWhileLoop(ConvertNode(iter->LoopCondition), ConvertNode(iter->LoopStatement), *ast); + } + else if (iter->LoopBumper != nullptr) + { + return new FxForLoop(nullptr, ConvertNode(iter->LoopCondition), ConvertNode(iter->LoopBumper), ConvertNode(iter->LoopStatement), *ast); + } + else + { + return new FxWhileLoop(ConvertNode(iter->LoopCondition), ConvertNode(iter->LoopStatement), *ast); + } + } + + // not yet done + case AST_SwitchStmt: + { + auto swtch = static_cast(ast); + if (swtch->Content->NodeType != AST_CompoundStmt) + { + Error(ast, "Expecting { after 'switch'"); + return new FxNop(*ast); // allow compiler to continue looking for errors. + } + else + { + // The switch content is wrapped into a compound statement which needs to be unraveled here. + auto cmpnd = static_cast(swtch->Content); + FArgumentList args; + return new FxSwitchStatement(ConvertNode(swtch->Condition), ConvertNodeList(args, cmpnd->Content), *ast); + } + } + + case AST_CaseStmt: + { + auto cases = static_cast(ast); + return new FxCaseStatement(ConvertNode(cases->Condition), *ast); + } + + case AST_CompoundStmt: + { + auto x = new FxCompoundStatement(*ast); + auto compound = static_cast(ast); + auto node = compound->Content; + if (node != nullptr) do + { + x->Add(ConvertNode(node)); + node = static_cast(node->SiblingNext); + } while (node != compound->Content); + return x; + } + + case AST_AssignStmt: + { + auto ass = static_cast(ast); + FArgumentList args; + ConvertNodeList(args, ass->Dests); + assert(ass->Sources->SiblingNext == ass->Sources); // right side should be a single function call - nothing else + if (ass->Sources->NodeType != AST_ExprFuncCall) + { + // don't let this through to the code generator. This node is only used to assign multiple returns of a function to more than one variable. + Error(ass, "Right side of multi-assignment must be a function call"); + return new FxNop(*ast); // allow compiler to continue looking for errors. + } + return new FxMultiAssign(args, ConvertNode(ass->Sources), *ast); + } + + default: + break; + } + // only for development. I_Error is more convenient here than a normal error. + I_Error("ConvertNode encountered unsupported node of type %d", ast->NodeType); + return nullptr; +} + + +FArgumentList &ZCCCompiler::ConvertNodeList(FArgumentList &args, ZCC_TreeNode *head) +{ + if (head != nullptr) + { + auto node = head; + do + { + args.Push(ConvertNode(node)); + node = node->SiblingNext; + } while (node != head); + } + return args; +} diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h new file mode 100644 index 0000000000..8b3a9f5f12 --- /dev/null +++ b/src/scripting/zscript/zcc_compile.h @@ -0,0 +1,156 @@ +#ifndef ZCC_COMPILE_H +#define ZCC_COMPILE_H + +#include + +struct Baggage; +struct FPropertyInfo; +class AActor; +class FxExpression; +typedef TDeletingArray FArgumentList; + + +struct ZCC_StructWork +{ + PSymbolTable TreeNodes; + ZCC_Struct *strct; + ZCC_Class *OuterDef; + PClass *Outer; + PSymbolTreeNode *node; + TArray Enums; + TArray Constants; + TArray Fields; + TArray Functions; + + ZCC_StructWork() + { + } + + ZCC_StructWork(ZCC_Struct * s, PSymbolTreeNode *n, ZCC_Class *outer) + { + strct = s; + node = n; + OuterDef = outer; + Outer = nullptr; + }; + + FName NodeName() const + { + return strct->NodeName; + } + + PStruct *Type() + { + return strct->Type; + } + +}; + +struct ZCC_ClassWork : public ZCC_StructWork +{ + ZCC_Class *cls; + TArray Defaults; + TArray States; + + ZCC_ClassWork(ZCC_Class * s, PSymbolTreeNode *n) + { + strct = s; + cls = s; + node = n; + OuterDef = nullptr; + Outer = nullptr; + } + + PClass *Type() + { + return static_cast(strct->Type); + } +}; + +struct ZCC_ConstantWork +{ + ZCC_ConstantDef *node; + PSymbolTable *outputtable; +}; + +class ZCCCompiler +{ +public: + ZCCCompiler(ZCC_AST &tree, DObject *outer, PSymbolTable &symbols, PSymbolTable &outsymbols, int lumpnum); + ~ZCCCompiler(); + int Compile(); + +private: + void ProcessClass(ZCC_Class *node, PSymbolTreeNode *tnode); + void ProcessStruct(ZCC_Struct *node, PSymbolTreeNode *tnode, ZCC_Class *outer); + void CreateStructTypes(); + void CreateClassTypes(); + void CopyConstants(TArray &dest, TArray &Constants, PSymbolTable *ot); + void CompileAllConstants(); + void AddConstant(ZCC_ConstantWork &constant); + bool CompileConstant(ZCC_ConstantDef *def, PSymbolTable *Symbols); + + void CompileAllFields(); + bool CompileFields(PStruct *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren = false); + FString FlagsToString(uint32_t flags); + PType *DetermineType(PType *outertype, ZCC_TreeNode *field, FName name, ZCC_Type *ztype, bool allowarraytypes, bool formember); + PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PSymbolTable *sym); + PType *ResolveUserType(ZCC_BasicType *type, PSymbolTable *sym); + + void InitDefaults(); + void ProcessDefaultFlag(PClassActor *cls, ZCC_FlagStmt *flg); + void ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *flg, Baggage &bag); + void DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *pex, AActor *defaults, Baggage &bag); + int GetInt(ZCC_Expression *expr); + double GetDouble(ZCC_Expression *expr); + const char *GetString(ZCC_Expression *expr, bool silent = false); + void CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool forclass); + + void InitFunctions(); + void CompileStates(); + FxExpression *SetupActionFunction(PClass *cls, ZCC_TreeNode *sl, int stateflags); + + bool SimplifyingConstant; + TArray Constants; + TArray Structs; + TArray Classes; + + PSymbolTreeNode *AddTreeNode(FName name, ZCC_TreeNode *node, PSymbolTable *treenodes, bool searchparents = false); + + ZCC_Expression *Simplify(ZCC_Expression *root, PSymbolTable *Symbols, bool wantconstant); + ZCC_Expression *DoSimplify(ZCC_Expression *root, PSymbolTable *Symbols); + ZCC_Expression *SimplifyUnary(ZCC_ExprUnary *unary, PSymbolTable *Symbols); + ZCC_Expression *SimplifyBinary(ZCC_ExprBinary *binary, PSymbolTable *Symbols); + ZCC_Expression *SimplifyMemberAccess(ZCC_ExprMemberAccess *dotop, PSymbolTable *Symbols); + ZCC_Expression *SimplifyFunctionCall(ZCC_ExprFuncCall *callop, PSymbolTable *Symbols); + ZCC_OpProto *PromoteUnary(EZCCExprType op, ZCC_Expression *&expr); + ZCC_OpProto *PromoteBinary(EZCCExprType op, ZCC_Expression *&left, ZCC_Expression *&right); + + ZCC_Expression *ApplyConversion(ZCC_Expression *expr, const PType::Conversion **route, int routelen); + ZCC_Expression *AddCastNode(PType *type, ZCC_Expression *expr); + + ZCC_Expression *IdentifyIdentifier(ZCC_ExprID *idnode, PSymbolTable *sym); + ZCC_Expression *NodeFromSymbol(PSymbol *sym, ZCC_Expression *source, PSymbolTable *table); + ZCC_ExprConstant *NodeFromSymbolConst(PSymbolConst *sym, ZCC_Expression *idnode); + ZCC_ExprTypeRef *NodeFromSymbolType(PSymbolType *sym, ZCC_Expression *idnode); + + + void Warn(ZCC_TreeNode *node, const char *msg, ...); + void Error(ZCC_TreeNode *node, const char *msg, ...); + void MessageV(ZCC_TreeNode *node, const char *txtcolor, const char *msg, va_list argptr); + + FxExpression *ConvertAST(PStruct *cclass, ZCC_TreeNode *ast); + FxExpression *ConvertNode(ZCC_TreeNode *node); + FArgumentList &ConvertNodeList(FArgumentList &, ZCC_TreeNode *head); + + DObject *Outer; + PStruct *ConvertClass; // class type to be used when resoving symbols while converting an AST + PSymbolTable *GlobalTreeNodes; + PSymbolTable *OutputSymbols; + ZCC_AST &AST; + int Lump; +}; + +void ZCC_InitConversions(); + +#endif diff --git a/src/zscript/zcc_expr.cpp b/src/scripting/zscript/zcc_expr.cpp similarity index 85% rename from src/zscript/zcc_expr.cpp rename to src/scripting/zscript/zcc_expr.cpp index e1a091b180..0c2c6baee5 100644 --- a/src/zscript/zcc_expr.cpp +++ b/src/scripting/zscript/zcc_expr.cpp @@ -1,3 +1,36 @@ +/* +** zcc_expr.cpp +** +**--------------------------------------------------------------------------- +** Copyright -2016 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + #include #include "dobject.h" #include "sc_man.h" @@ -8,6 +41,7 @@ #include "m_alloc.h" #include "zcc_parser.h" #include "templates.h" +#include "math/cmath.h" #define luai_nummod(a,b) ((a) - floor((a)/(b))*(b)) @@ -299,7 +333,7 @@ void ZCC_InitOperators() { PEX_Mod , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal %= r->UIntVal; return l; } }, { PEX_Mod , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal = luai_nummod(l->DoubleVal, r->DoubleVal); return l; } }, - { PEX_Pow , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal = pow(l->DoubleVal, r->DoubleVal); return l; } }, + { PEX_Pow , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal = g_pow(l->DoubleVal, r->DoubleVal); return l; } }, { PEX_Concat , (PType **)&TypeString, (PType **)&TypeString, (PType **)&TypeString, EvalConcat }, @@ -332,6 +366,18 @@ void ZCC_InitOperators() { PEX_LTEQ , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal <= r->UIntVal; l->Type = TypeBool; return l; } }, { PEX_LTEQ , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->IntVal = l->DoubleVal <= r->DoubleVal; l->Type = TypeBool; return l; } }, + { PEX_GT , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal > r->IntVal; l->Type = TypeBool; return l; } }, + { PEX_GT , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal > r->UIntVal; l->Type = TypeBool; return l; } }, + { PEX_GT , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->IntVal = l->DoubleVal > r->DoubleVal; l->Type = TypeBool; return l; } }, + + { PEX_GTEQ , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal >= r->IntVal; l->Type = TypeBool; return l; } }, + { PEX_GTEQ , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal >= r->UIntVal; l->Type = TypeBool; return l; } }, + { PEX_GTEQ , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->IntVal = l->DoubleVal >= r->DoubleVal; l->Type = TypeBool; return l; } }, + + { PEX_NEQ , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal != r->IntVal; l->Type = TypeBool; return l; } }, + { PEX_NEQ , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal != r->UIntVal; l->Type = TypeBool; return l; } }, + { PEX_NEQ , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->IntVal = l->DoubleVal != r->DoubleVal; l->Type = TypeBool; return l; } }, + { PEX_EQEQ , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal == r->IntVal; l->Type = TypeBool; return l; } }, { PEX_EQEQ , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal == r->UIntVal; l->Type = TypeBool; return l; } }, { PEX_EQEQ , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->IntVal = l->DoubleVal == r->DoubleVal; l->Type = TypeBool; return l; } }, diff --git a/src/scripting/zscript/zcc_exprlist.h b/src/scripting/zscript/zcc_exprlist.h new file mode 100644 index 0000000000..faf6af6a43 --- /dev/null +++ b/src/scripting/zscript/zcc_exprlist.h @@ -0,0 +1,76 @@ +// Name Token used in the code generator +xx(Nil, TK_None) + +xx(ID, TK_Identifier) +xx(Super, TK_Super) +xx(Null, TK_Null) +xx(ConstValue, TK_Const) +xx(FuncCall, '(') +xx(ArrayAccess, TK_Array) +xx(MemberAccess, '.') +xx(ClassCast, TK_Class) +xx(TypeRef, TK_Class) +xx(Vector, TK_Vector2) + +xx(PostInc, TK_Incr) +xx(PostDec, TK_Decr) + +xx(PreInc, TK_Incr) +xx(PreDec, TK_Decr) +xx(Negate, '-') +xx(AntiNegate, '+') +xx(BitNot, '~') +xx(BoolNot, '!') +xx(SizeOf, TK_SizeOf) +xx(AlignOf, TK_AlignOf) + +xx(Add, '+') +xx(Sub, '-') +xx(Mul, '*') +xx(Div, '/') +xx(Mod, '%') +xx(Pow, TK_MulMul) +xx(CrossProduct, TK_Cross) +xx(DotProduct, TK_Dot) +xx(LeftShift, TK_LShift) +xx(RightShift, TK_RShift) +xx(URightShift, TK_URShift) +xx(Concat, TK_DotDot) + +xx(LT, '<') +xx(LTEQ, TK_Leq) +xx(GT, '>') +xx(GTEQ, TK_Geq) +xx(LTGTEQ, TK_LtGtEq) +xx(Is, TK_Is) + +xx(EQEQ, TK_Eq) +xx(NEQ, TK_Neq) +xx(APREQ, TK_ApproxEq) + +xx(BitAnd, '&') +xx(BitOr, '|') +xx(BitXor, '^') +xx(BoolAnd, TK_AndAnd) +xx(BoolOr, TK_OrOr) + +xx(Assign, '=') +xx(AddAssign, '+') // these are what the code generator needs, not what they represent. +xx(SubAssign, '-') +xx(MulAssign, '*') +xx(DivAssign, '/') +xx(ModAssign, '%') +xx(LshAssign, TK_LShift) +xx(RshAssign, TK_RShift) +xx(URshAssign, TK_URShift) +xx(AndAssign, '&') +xx(OrAssign, '|') +xx(XorAssign, '^') + +xx(Scope, TK_ColonColon) + +xx(Trinary, '?') + +xx(Cast, TK_Coerce) + +#undef xx diff --git a/src/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp similarity index 53% rename from src/zscript/zcc_parser.cpp rename to src/scripting/zscript/zcc_parser.cpp index 1f1fa45411..44f72da283 100644 --- a/src/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -1,3 +1,36 @@ +/* +** zcc_expr.cpp +** +**--------------------------------------------------------------------------- +** Copyright -2016 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + #include "dobject.h" #include "sc_man.h" #include "c_console.h" @@ -5,10 +38,25 @@ #include "w_wad.h" #include "cmdlib.h" #include "m_alloc.h" +#include "i_system.h" +#include "m_argv.h" +#include "v_text.h" #include "zcc_parser.h" #include "zcc_compile.h" +TArray Includes; +TArray IncludeLocs; + static FString ZCCTokenName(int terminal); +void AddInclude(ZCC_ExprConstant *node) +{ + assert(node->Type == TypeString); + if (Includes.Find(*node->StringVal) >= Includes.Size()) + { + Includes.Push(*node->StringVal); + IncludeLocs.Push(*node); + } +} #include "zcc-parse.h" #include "zcc-parse.c" @@ -37,6 +85,7 @@ static void InitTokenMap() TOKENDEF (TK_SubEq, ZCC_SUBEQ); TOKENDEF (TK_LShiftEq, ZCC_LSHEQ); TOKENDEF (TK_RShiftEq, ZCC_RSHEQ); + TOKENDEF (TK_URShiftEq, ZCC_URSHEQ); TOKENDEF (TK_AndEq, ZCC_ANDEQ); TOKENDEF (TK_OrEq, ZCC_OREQ); TOKENDEF (TK_XorEq, ZCC_XOREQ); @@ -54,11 +103,13 @@ static void InitTokenMap() TOKENDEF (TK_LtGtEq, ZCC_LTGTEQ); TOKENDEF (TK_Is, ZCC_IS); TOKENDEF (TK_DotDot, ZCC_DOTDOT); + TOKENDEF (TK_Ellipsis, ZCC_ELLIPSIS); TOKENDEF ('|', ZCC_OR); TOKENDEF ('^', ZCC_XOR); TOKENDEF ('&', ZCC_AND); TOKENDEF (TK_LShift, ZCC_LSH); TOKENDEF (TK_RShift, ZCC_RSH); + TOKENDEF (TK_URShift, ZCC_URSH); TOKENDEF ('-', ZCC_SUB); TOKENDEF ('+', ZCC_ADD); TOKENDEF ('*', ZCC_MUL); @@ -78,11 +129,14 @@ static void InitTokenMap() TOKENDEF (TK_Class, ZCC_CLASS); TOKENDEF (TK_Abstract, ZCC_ABSTRACT); TOKENDEF (TK_Native, ZCC_NATIVE); + TOKENDEF (TK_Action, ZCC_ACTION); TOKENDEF (TK_Replaces, ZCC_REPLACES); TOKENDEF (TK_Static, ZCC_STATIC); TOKENDEF (TK_Private, ZCC_PRIVATE); TOKENDEF (TK_Protected, ZCC_PROTECTED); TOKENDEF (TK_Latent, ZCC_LATENT); + TOKENDEF (TK_Virtual, ZCC_VIRTUAL); + TOKENDEF (TK_Override, ZCC_OVERRIDE); TOKENDEF (TK_Final, ZCC_FINAL); TOKENDEF (TK_Meta, ZCC_META); TOKENDEF (TK_Deprecated, ZCC_DEPRECATED); @@ -95,16 +149,22 @@ static void InitTokenMap() TOKENDEF2(TK_Byte, ZCC_BYTE, NAME_Byte); TOKENDEF2(TK_Short, ZCC_SHORT, NAME_Short); TOKENDEF2(TK_UShort, ZCC_USHORT, NAME_uShort); + TOKENDEF2(TK_Int8, ZCC_SBYTE, NAME_int8); + TOKENDEF2(TK_UInt8, ZCC_BYTE, NAME_uint8); + TOKENDEF2(TK_Int16, ZCC_SHORT, NAME_int16); + TOKENDEF2(TK_UInt16, ZCC_USHORT, NAME_uint16); TOKENDEF2(TK_Int, ZCC_INT, NAME_Int); TOKENDEF2(TK_UInt, ZCC_UINT, NAME_uInt); TOKENDEF2(TK_Bool, ZCC_BOOL, NAME_Bool); TOKENDEF2(TK_Float, ZCC_FLOAT, NAME_Float); TOKENDEF2(TK_Double, ZCC_DOUBLE, NAME_Double); TOKENDEF2(TK_String, ZCC_STRING, NAME_String); - TOKENDEF2(TK_Vector, ZCC_VECTOR, NAME_Vector); + TOKENDEF2(TK_Vector2, ZCC_VECTOR2, NAME_Vector2); + TOKENDEF2(TK_Vector3, ZCC_VECTOR3, NAME_Vector3); TOKENDEF2(TK_Name, ZCC_NAME, NAME_Name); TOKENDEF2(TK_Map, ZCC_MAP, NAME_Map); TOKENDEF2(TK_Array, ZCC_ARRAY, NAME_Array); + TOKENDEF2(TK_Include, ZCC_INCLUDE, NAME_Include); TOKENDEF (TK_Void, ZCC_VOID); TOKENDEF (TK_True, ZCC_TRUE); TOKENDEF (TK_False, ZCC_FALSE); @@ -114,7 +174,7 @@ static void InitTokenMap() TOKENDEF (TK_Out, ZCC_OUT); TOKENDEF (TK_Optional, ZCC_OPTIONAL); TOKENDEF (TK_Super, ZCC_SUPER); - TOKENDEF (TK_Self, ZCC_SELF); + TOKENDEF (TK_Null, ZCC_NULLPTR); TOKENDEF ('~', ZCC_TILDE); TOKENDEF ('!', ZCC_BANG); TOKENDEF (TK_SizeOf, ZCC_SIZEOF); @@ -138,6 +198,10 @@ static void InitTokenMap() TOKENDEF (TK_Loop, ZCC_LOOP); TOKENDEF (TK_Goto, ZCC_GOTO); TOKENDEF (TK_States, ZCC_STATES); + TOKENDEF2(TK_State, ZCC_STATE, NAME_State); + TOKENDEF2(TK_Color, ZCC_COLOR, NAME_Color); + TOKENDEF2(TK_Sound, ZCC_SOUND, NAME_Sound); + TOKENDEF2(TK_Let, ZCC_LET, NAME_let); TOKENDEF (TK_Identifier, ZCC_IDENTIFIER); TOKENDEF (TK_StringConst, ZCC_STRCONST); @@ -154,51 +218,34 @@ static void InitTokenMap() TOKENDEF (TK_Offset, ZCC_OFFSET); TOKENDEF (TK_CanRaise, ZCC_CANRAISE); TOKENDEF (TK_Light, ZCC_LIGHT); - - ZCC_InitOperators(); - ZCC_InitConversions(); + TOKENDEF (TK_Extend, ZCC_EXTEND); } #undef TOKENDEF #undef TOKENDEF2 -static void DoParse(const char *filename) +static void ParseSingleFile(const char *filename, int lump, void *parser, ZCCParseState &state) { - if (TokenMap.CountUsed() == 0) - { - InitTokenMap(); - } - - FScanner sc; - void *parser; int tokentype; - int lump; - bool failed; + //bool failed; ZCCToken value; + FScanner sc; - lump = Wads.CheckNumForFullName(filename, true); - if (lump >= 0) + if (filename != nullptr) { - sc.OpenLumpNum(lump); + lump = Wads.CheckNumForFullName(filename, true); + if (lump >= 0) + { + sc.OpenLumpNum(lump); + } + else + { + Printf("Could not find script lump '%s'\n", filename); + return; + } } - else if (FileExists(filename)) - { - sc.OpenFile(filename); - } - else - { - Printf("Could not find script lump '%s'\n", filename); - return; - } - - parser = ZCCParseAlloc(malloc); - failed = false; -#ifdef _DEBUG - FILE *f = fopen("trace.txt", "w"); - char prompt = '\0'; - ZCCParseTrace(f, &prompt); -#endif - ZCCParseState state(sc); + else sc.OpenLumpNum(lump); + state.sc = ≻ while (sc.GetToken()) { value.SourceLoc = sc.GetMessageLine(); @@ -241,7 +288,7 @@ static void DoParse(const char *filename) default: TokenMapEntry *zcctoken = TokenMap.CheckKey(sc.TokenType); - if (zcctoken != NULL) + if (zcctoken != nullptr) { tokentype = zcctoken->TokenType; value.Int = zcctoken->TokenName; @@ -254,38 +301,124 @@ static void DoParse(const char *filename) break; } ZCCParse(parser, tokentype, value, &state); - if (failed) - { - sc.ScriptMessage("Parse failed\n"); - goto parse_end; - } } parse_end: value.Int = -1; ZCCParse(parser, ZCC_EOF, value, &state); + state.sc = nullptr; +} + +static void DoParse(int lumpnum) +{ + FScanner sc; + void *parser; + ZCCToken value; + + parser = ZCCParseAlloc(malloc); + ZCCParseState state; + +#ifndef NDEBUG + FILE *f = nullptr; + const char *tracefile = Args->CheckValue("-tracefile"); + if (tracefile != nullptr) + { + f = fopen(tracefile, "w"); + char prompt = '\0'; + ZCCParseTrace(f, &prompt); + } +#endif + + sc.OpenLumpNum(lumpnum); + auto saved = sc.SavePos(); + + ParseSingleFile(nullptr, lumpnum, parser, state); + for (unsigned i = 0; i < Includes.Size(); i++) + { + lumpnum = Wads.CheckNumForFullName(Includes[i], true); + if (lumpnum == -1) + { + IncludeLocs[i].Message(MSG_ERROR, "Include script lump %s not found", Includes[i].GetChars()); + } + else + { + ParseSingleFile(nullptr, lumpnum, parser, state); + } + } + Includes.Clear(); + Includes.ShrinkToFit(); + IncludeLocs.Clear(); + IncludeLocs.ShrinkToFit(); + + value.Int = -1; + value.SourceLoc = sc.GetMessageLine(); ZCCParse(parser, 0, value, &state); ZCCParseFree(parser, free); - PSymbolTable symbols(&GlobalSymbols); - ZCCCompiler cc(state, NULL, symbols); - cc.Compile(); -#ifdef _DEBUG - if (f != NULL) + // If the parser fails, there is no point starting the compiler, because it'd only flood the output with endless errors. + if (FScriptPosition::ErrorCounter > 0) { - fclose(f); + I_Error("%d errors while parsing %s", FScriptPosition::ErrorCounter, Wads.GetLumpFullPath(lumpnum).GetChars()); } - FString ast = ZCC_PrintAST(state.TopNode); - FString astfile = ExtractFileBase(filename, false); - astfile << ".ast"; - f = fopen(astfile, "w"); - if (f != NULL) + +#ifndef NDEBUG + if (f != nullptr) { - fputs(ast.GetChars(), f); fclose(f); } #endif + + // Make a dump of the AST before running the compiler for diagnostic purposes. + if (Args->CheckParm("-dumpast")) + { + FString ast = ZCC_PrintAST(state.TopNode); + FString filename = Wads.GetLumpFullPath(lumpnum); + filename.ReplaceChars(":\\/?|", '.'); + filename << ".ast"; + FILE *ff = fopen(filename, "w"); + if (ff != NULL) + { + fputs(ast.GetChars(), ff); + fclose(ff); + } + } + + PSymbolTable symtable; + ZCCCompiler cc(state, NULL, symtable, GlobalSymbols, lumpnum); + cc.Compile(); + + if (FScriptPosition::ErrorCounter > 0) + { + // Abort if the compiler produced any errors. Also do not compile further lumps, because they very likely miss some stuff. + I_Error("%d errors, %d warnings while compiling %s", FScriptPosition::ErrorCounter, FScriptPosition::WarnCounter, Wads.GetLumpFullPath(lumpnum).GetChars()); + } + else if (FScriptPosition::WarnCounter > 0) + { + // If we got warnings, but no errors, print the information but continue. + Printf(TEXTCOLOR_ORANGE "%d warnings while compiling %s", FScriptPosition::WarnCounter, Wads.GetLumpFullPath(lumpnum).GetChars()); + } + } +void ParseScripts() +{ + if (TokenMap.CountUsed() == 0) + { + InitTokenMap(); + } + ZCC_InitOperators(); + ZCC_InitConversions(); + + int lump, lastlump = 0; + FScriptPosition::ResetErrorCounter(); + + while ((lump = Wads.FindLump("ZSCRIPT", &lastlump)) != -1) + { + DoParse(lump); + } + +} + +/* CCMD(parse) { if (argv.argc() == 2) @@ -293,6 +426,7 @@ CCMD(parse) DoParse(argv[1]); } } +*/ static FString ZCCTokenName(int terminal) { @@ -325,6 +459,7 @@ ZCC_TreeNode *ZCC_AST::InitNode(size_t size, EZCCTreeNodeType type, ZCC_TreeNode if (basis != NULL) { node->SourceName = basis->SourceName; + node->SourceLump = basis->SourceLump; node->SourceLoc = basis->SourceLoc; } return node; @@ -333,6 +468,38 @@ ZCC_TreeNode *ZCC_AST::InitNode(size_t size, EZCCTreeNodeType type, ZCC_TreeNode ZCC_TreeNode *ZCCParseState::InitNode(size_t size, EZCCTreeNodeType type) { ZCC_TreeNode *node = ZCC_AST::InitNode(size, type, NULL); - node->SourceName = Strings.Alloc(sc.ScriptName); + node->SourceName = Strings.Alloc(sc->ScriptName); + node->SourceLump = sc->LumpNum; return node; } + +// Appends a sibling to this node's sibling list. +void AppendTreeNodeSibling(ZCC_TreeNode *thisnode, ZCC_TreeNode *sibling) +{ + if (thisnode == nullptr) + { + // Some bad syntax can actually get here, so better abort so that the user can see the error which caused this. + I_FatalError("Internal script compiler error. Execution aborted."); + } + if (sibling == nullptr) + { + return; + } + + ZCC_TreeNode *&SiblingPrev = thisnode->SiblingPrev; + ZCC_TreeNode *&SiblingNext = thisnode->SiblingNext; + + // Check integrity of our sibling list. + assert(SiblingPrev->SiblingNext == thisnode); + assert(SiblingNext->SiblingPrev == thisnode); + + // Check integrity of new sibling list. + assert(sibling->SiblingPrev->SiblingNext == sibling); + assert(sibling->SiblingNext->SiblingPrev == sibling); + + ZCC_TreeNode *siblingend = sibling->SiblingPrev; + SiblingPrev->SiblingNext = sibling; + sibling->SiblingPrev = SiblingPrev; + SiblingPrev = siblingend; + siblingend->SiblingNext = thisnode; +} diff --git a/src/zscript/zcc_parser.h b/src/scripting/zscript/zcc_parser.h similarity index 81% rename from src/zscript/zcc_parser.h rename to src/scripting/zscript/zcc_parser.h index e74b5263ec..d02b1a12f2 100644 --- a/src/zscript/zcc_parser.h +++ b/src/scripting/zscript/zcc_parser.h @@ -2,6 +2,7 @@ #define ZCC_PARSER_H #include "memarena.h" +#include "sc_man.h" struct ZCCToken { @@ -16,7 +17,7 @@ struct ZCCToken ENamedName Name() { return ENamedName(Int); } }; -// Variable / Function modifiers +// Variable / Function / Class modifiers enum { ZCC_Native = 1 << 0, @@ -30,6 +31,10 @@ enum ZCC_Deprecated = 1 << 8, ZCC_ReadOnly = 1 << 9, ZCC_FuncConst = 1 << 10, + ZCC_Abstract = 1 << 11, + ZCC_Extension = 1 << 12, + ZCC_Virtual = 1 << 13, + ZCC_Override = 1 << 14, }; // Function parameter modifiers @@ -41,7 +46,6 @@ enum }; - // Syntax tree structures. enum EZCCTreeNodeType { @@ -60,6 +64,7 @@ enum EZCCTreeNodeType AST_StateGoto, AST_StateLine, AST_VarName, + AST_VarInit, AST_Type, AST_BasicType, AST_MapType, @@ -92,6 +97,13 @@ enum EZCCTreeNodeType AST_Declarator, AST_VarDeclarator, AST_FuncDeclarator, + AST_Default, + AST_FlagStmt, + AST_PropertyStmt, + AST_VectorValue, + AST_DeclFlags, + AST_ClassCast, + AST_StaticArrayStatement, NUM_AST_NODE_TYPES }; @@ -101,21 +113,25 @@ enum EZCCBuiltinType ZCC_SInt8, ZCC_UInt8, ZCC_SInt16, - ZCC_UInt16, + ZCC_UInt16, // smaller than 32 bit types are only valid in structs, classes and arrays. ZCC_SInt32, ZCC_UInt32, ZCC_IntAuto, // for enums, autoselect appropriately sized int ZCC_Bool, - ZCC_Float32, ZCC_Float64, ZCC_FloatAuto, // 32-bit in structs/classes, 64-bit everywhere else ZCC_String, ZCC_Vector2, ZCC_Vector3, - ZCC_Vector4, ZCC_Name, + + ZCC_Color, // special types for ZDoom. + ZCC_State, + ZCC_Sound, + ZCC_UserType, + ZCC_Let, ZCC_NUM_BUILT_IN_TYPES }; @@ -139,36 +155,22 @@ struct ZCC_TreeNode // can't use FScriptPosition, because the string wouldn't have a chance to // destruct if we did that. FString *SourceName; + int SourceLump; int SourceLoc; // Node type is one of the node types above, which corresponds with // one of the structures below. EZCCTreeNodeType NodeType; - // Appends a sibling to this node's sibling list. - void AppendSibling(ZCC_TreeNode *sibling) + operator FScriptPosition() { - if (sibling == NULL) - { - return; - } - - // Check integrity of our sibling list. - assert(SiblingPrev->SiblingNext == this); - assert(SiblingNext->SiblingPrev == this); - - // Check integrity of new sibling list. - assert(sibling->SiblingPrev->SiblingNext == sibling); - assert(sibling->SiblingNext->SiblingPrev == sibling); - - ZCC_TreeNode *siblingend = sibling->SiblingPrev; - SiblingPrev->SiblingNext = sibling; - sibling->SiblingPrev = SiblingPrev; - SiblingPrev = siblingend; - siblingend->SiblingNext = this; + return FScriptPosition(*SourceName, SourceLoc); } + }; +void AppendTreeNodeSibling(ZCC_TreeNode *thisnode, ZCC_TreeNode *sibling); + struct ZCC_Identifier : ZCC_TreeNode { ENamedName Id; @@ -177,19 +179,22 @@ struct ZCC_Identifier : ZCC_TreeNode struct ZCC_NamedNode : ZCC_TreeNode { ENamedName NodeName; -}; - -struct ZCC_Class : ZCC_NamedNode -{ - ZCC_Identifier *ParentName; - ZCC_Identifier *Replaces; - VM_UWORD Flags; - ZCC_TreeNode *Body; + PSymbolType *Symbol; }; struct ZCC_Struct : ZCC_NamedNode { + VM_UWORD Flags; ZCC_TreeNode *Body; + PStruct *Type; +}; + +struct ZCC_Class : ZCC_Struct +{ + ZCC_Identifier *ParentName; + ZCC_Identifier *Replaces; + + PClass *CType() { return static_cast(Type); } }; struct ZCC_Enum : ZCC_NamedNode @@ -205,6 +210,7 @@ struct ZCC_EnumTerminator : ZCC_TreeNode struct ZCC_States : ZCC_TreeNode { struct ZCC_StatePart *Body; + ZCC_Identifier *Flags; }; struct ZCC_StatePart : ZCC_TreeNode @@ -248,20 +254,23 @@ struct ZCC_Expression : ZCC_TreeNode struct ZCC_StateGoto : ZCC_StatePart { + ZCC_Identifier *Qualifier; ZCC_Identifier *Label; ZCC_Expression *Offset; }; struct ZCC_StateLine : ZCC_StatePart { - char Sprite[4]; + FString *Sprite; BITFIELD bBright : 1; BITFIELD bFast : 1; BITFIELD bSlow : 1; BITFIELD bNoDelay : 1; BITFIELD bCanRaise : 1; FString *Frames; + ZCC_Expression *Duration; ZCC_Expression *Offset; + ZCC_ExprConstant *Lights; ZCC_TreeNode *Action; }; @@ -271,6 +280,12 @@ struct ZCC_VarName : ZCC_TreeNode ZCC_Expression *ArraySize; // NULL if not an array }; +struct ZCC_VarInit : ZCC_VarName +{ + ZCC_Expression *Init; + bool InitIsArray; // this is needed to distinguish one-element arrays from raw elements. +}; + struct ZCC_Type : ZCC_TreeNode { ZCC_Expression *ArraySize; // NULL if not an array @@ -280,6 +295,7 @@ struct ZCC_BasicType : ZCC_Type { EZCCBuiltinType Type; ZCC_Identifier *UserType; + bool isconst; }; struct ZCC_MapType : ZCC_Type @@ -331,6 +347,12 @@ struct ZCC_ExprFuncCall : ZCC_Expression ZCC_FuncParm *Parameters; }; +struct ZCC_ClassCast : ZCC_Expression +{ + ENamedName ClassName; + ZCC_FuncParm *Parameters; +}; + struct ZCC_ExprMemberAccess : ZCC_Expression { ZCC_Expression *Left; @@ -355,10 +377,22 @@ struct ZCC_ExprTrinary : ZCC_Expression ZCC_Expression *Right; }; +struct ZCC_VectorValue : ZCC_Expression +{ + ZCC_Expression *X, *Y, *Z; +}; + struct ZCC_Statement : ZCC_TreeNode { }; +struct ZCC_StaticArrayStatement : ZCC_Statement +{ + ZCC_Type *Type; + ENamedName Id; + ZCC_Expression *Values; +}; + struct ZCC_CompoundStmt : ZCC_Statement { ZCC_Statement *Content; @@ -423,21 +457,28 @@ struct ZCC_AssignStmt : ZCC_Statement struct ZCC_LocalVarStmt : ZCC_Statement { ZCC_Type *Type; - ZCC_VarName *Vars; - ZCC_Expression *Inits; + ZCC_VarInit *Vars; }; struct ZCC_FuncParamDecl : ZCC_TreeNode { ZCC_Type *Type; + ZCC_Expression *Default; ENamedName Name; int Flags; }; +struct ZCC_DeclFlags : ZCC_TreeNode +{ + ZCC_Identifier *Id; + int Flags; +}; + struct ZCC_ConstantDef : ZCC_NamedNode { ZCC_Expression *Value; PSymbolConst *Symbol; + ZCC_Enum *Type; // gets set when the constant originates from an enum. }; struct ZCC_Declarator : ZCC_TreeNode @@ -458,6 +499,24 @@ struct ZCC_FuncDeclarator : ZCC_Declarator ZCC_FuncParamDecl *Params; ENamedName Name; ZCC_Statement *Body; + ZCC_Identifier *UseFlags; +}; + +struct ZCC_Default : ZCC_CompoundStmt +{ +}; + +struct ZCC_PropertyStmt : ZCC_Statement +{ + ZCC_Identifier *Prop; + ZCC_Expression *Values; +}; + + +struct ZCC_FlagStmt : ZCC_Statement +{ + ZCC_Identifier *name; + bool set; }; typedef ZCC_ExprConstant *(*EvalConst1op)(ZCC_ExprConstant *); @@ -514,10 +573,10 @@ struct ZCC_AST struct ZCCParseState : public ZCC_AST { - ZCCParseState(FScanner &scanner) : sc(scanner) {} + ZCCParseState(FScanner *scanner = nullptr) : sc(scanner) {} ZCC_TreeNode *InitNode(size_t size, EZCCTreeNodeType type); - FScanner ≻ + FScanner *sc; }; #endif diff --git a/src/serializer.cpp b/src/serializer.cpp index 8875b61f99..5f0e6dfce5 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -63,6 +63,7 @@ #include "w_zip.h" #include "doomerrors.h" #include "v_text.h" +#include "cmdlib.h" char nulspace[1024 * 1024 * 4]; bool save_full = false; // for testing. Should be removed afterward. diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index c1973780b4..53c471a316 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -59,6 +59,7 @@ #include "i_music.h" #include "i_musicinterns.h" #include "tempfiles.h" +#include "cmdlib.h" FModule OpenALModule{"OpenAL"}; diff --git a/src/teaminfo.cpp b/src/teaminfo.cpp index bf0ef8a40b..38ba56f4cd 100644 --- a/src/teaminfo.cpp +++ b/src/teaminfo.cpp @@ -182,7 +182,7 @@ void FTeam::ParseTeamDefinition (FScanner &Scan) case TEAMINFO_PlayerColor: Scan.MustGetString (); - Team.m_iPlayerColor = V_GetColor (NULL, Scan.String); + Team.m_iPlayerColor = V_GetColor (NULL, Scan); break; case TEAMINFO_TextColor: diff --git a/src/textures/multipatchtexture.cpp b/src/textures/multipatchtexture.cpp index 653d2a7988..c0bd6807a2 100644 --- a/src/textures/multipatchtexture.cpp +++ b/src/textures/multipatchtexture.cpp @@ -1098,7 +1098,7 @@ void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part, TexInit &init) if (!sc.CheckNumber()) { sc.MustGetString(); - part.Blend = V_GetColor(NULL, sc.String); + part.Blend = V_GetColor(NULL, sc); } else { diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp deleted file mode 100644 index 9af031b04f..0000000000 --- a/src/thingdef/thingdef.cpp +++ /dev/null @@ -1,482 +0,0 @@ -/* -** thingdef.cpp -** -** Actor definitions -** -**--------------------------------------------------------------------------- -** Copyright 2002-2008 Christoph Oelckers -** Copyright 2004-2008 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be -** covered by the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or (at -** your option) any later version. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ - -#include "gi.h" -#include "actor.h" -#include "info.h" -#include "sc_man.h" -#include "tarray.h" -#include "w_wad.h" -#include "templates.h" -#include "r_defs.h" -#include "a_pickups.h" -#include "s_sound.h" -#include "cmdlib.h" -#include "p_lnspec.h" -#include "a_action.h" -#include "decallib.h" -#include "m_random.h" -#include "i_system.h" -#include "m_argv.h" -#include "p_local.h" -#include "doomerrors.h" -#include "a_weaponpiece.h" -#include "p_conversation.h" -#include "v_text.h" -#include "thingdef.h" -#include "thingdef_exp.h" -#include "a_sharedglobal.h" -#include "vmbuilder.h" -#include "stats.h" - -TDeletingArray ActorDamageFuncs; - - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- -void InitThingdef(); -void ParseDecorate(FScanner &ctx); - -// STATIC FUNCTION PROTOTYPES -------------------------------------------- -PClassActor *QuestItemClasses[31]; - -EXTERN_CVAR(Bool, strictdecorate); - -PClassActor *DecoDerivedClass(const FScriptPosition &sc, PClassActor *parent, FName typeName) -{ - PClassActor *type = static_cast(parent->CreateDerivedClass(typeName, parent->Size)); - if (type == nullptr) - { - FString newname = typeName.GetChars(); - FString sourcefile = sc.FileName; - - sourcefile.Substitute(":", "@"); - newname << '@' << sourcefile; - if (strictdecorate) - { - sc.Message(MSG_ERROR, "Tried to define class '%s' more than once.", typeName.GetChars()); - } - else - { - // Due to backwards compatibility issues this cannot be an unconditional error. - sc.Message(MSG_WARNING, "Tried to define class '%s' more than once. Renaming class to '%s'", typeName.GetChars(), newname.GetChars()); - } - type = static_cast(parent->CreateDerivedClass(newname, parent->Size)); - if (type == nullptr) - { - // This we cannot handle cleanly anymore. Let's just abort and forget about the odd mod out that was this careless. - sc.Message(MSG_FATAL, "Tried to define class '%s' more than twice in the same file.", typeName.GetChars()); - } - } - return type; -} -//========================================================================== -// -// Starts a new actor definition -// -//========================================================================== -PClassActor *CreateNewActor(const FScriptPosition &sc, FName typeName, FName parentName, bool native) -{ - PClassActor *replacee = NULL; - PClassActor *ti = NULL; - - PClassActor *parent = RUNTIME_CLASS(AActor); - - if (parentName != NAME_None) - { - parent = PClass::FindActor(parentName); - - PClassActor *p = parent; - while (p != NULL) - { - if (p->TypeName == typeName) - { - sc.Message(MSG_ERROR, "'%s' inherits from a class with the same name", typeName.GetChars()); - break; - } - p = dyn_cast(p->ParentClass); - } - - if (parent == NULL) - { - sc.Message(MSG_ERROR, "Parent type '%s' not found in %s", parentName.GetChars(), typeName.GetChars()); - parent = RUNTIME_CLASS(AActor); - } - else if (!parent->IsDescendantOf(RUNTIME_CLASS(AActor))) - { - sc.Message(MSG_ERROR, "Parent type '%s' is not an actor in %s", parentName.GetChars(), typeName.GetChars()); - parent = RUNTIME_CLASS(AActor); - } - } - - if (native) - { - ti = PClass::FindActor(typeName); - if (ti == NULL) - { - extern void DumpTypeTable(); - DumpTypeTable(); - sc.Message(MSG_ERROR, "Unknown native actor '%s'", typeName.GetChars()); - goto create; - } - else if (ti != RUNTIME_CLASS(AActor) && ti->ParentClass->NativeClass() != parent->NativeClass()) - { - sc.Message(MSG_ERROR, "Native class '%s' does not inherit from '%s'", typeName.GetChars(), parentName.GetChars()); - parent = RUNTIME_CLASS(AActor); - goto create; - } - else if (ti->Defaults != NULL) - { - sc.Message(MSG_ERROR, "Redefinition of internal class '%s'", typeName.GetChars()); - goto create; - } - ti->InitializeNativeDefaults(); - ti->ParentClass->DeriveData(ti); - } - else - { - create: - ti = DecoDerivedClass(sc, parent, typeName); - } - - ti->Replacee = ti->Replacement = NULL; - ti->DoomEdNum = -1; - return ti; -} - -//========================================================================== -// -// -// -//========================================================================== - -void SetReplacement(FScanner &sc, PClassActor *info, FName replaceName) -{ - // Check for "replaces" - if (replaceName != NAME_None) - { - // Get actor name - PClassActor *replacee = PClass::FindActor(replaceName); - - if (replacee == NULL) - { - sc.ScriptMessage("Replaced type '%s' not found for %s", replaceName.GetChars(), info->TypeName.GetChars()); - return; - } - if (replacee != NULL) - { - replacee->Replacement = info; - info->Replacee = replacee; - } - } - -} - -//========================================================================== -// -// Finalizes an actor definition -// -//========================================================================== - -void FinishActor(const FScriptPosition &sc, PClassActor *info, Baggage &bag) -{ - AActor *defaults = (AActor*)info->Defaults; - - try - { - bag.statedef.FinishStates (info, defaults); - } - catch (CRecoverableError &err) - { - sc.Message(MSG_ERROR, "%s", err.GetMessage()); - bag.statedef.MakeStateDefines(NULL); - return; - } - bag.statedef.InstallStates (info, defaults); - bag.statedef.MakeStateDefines(NULL); - if (bag.DropItemSet) - { - info->DropItems = bag.DropItemList; - GC::WriteBarrier(info, info->DropItems); - } - if (info->IsDescendantOf (RUNTIME_CLASS(AInventory))) - { - defaults->flags |= MF_SPECIAL; - } - - // Weapons must be checked for all relevant states. They may crash the game otherwise. - if (info->IsDescendantOf(RUNTIME_CLASS(AWeapon))) - { - FState *ready = info->FindState(NAME_Ready); - FState *select = info->FindState(NAME_Select); - FState *deselect = info->FindState(NAME_Deselect); - FState *fire = info->FindState(NAME_Fire); - - // Consider any weapon without any valid state abstract and don't output a warning - // This is for creating base classes for weapon groups that only set up some properties. - if (ready || select || deselect || fire) - { - if (!ready) - { - sc.Message(MSG_ERROR, "Weapon %s doesn't define a ready state.\n", info->TypeName.GetChars()); - } - if (!select) - { - sc.Message(MSG_ERROR, "Weapon %s doesn't define a select state.\n", info->TypeName.GetChars()); - } - if (!deselect) - { - sc.Message(MSG_ERROR, "Weapon %s doesn't define a deselect state.\n", info->TypeName.GetChars()); - } - if (!fire) - { - sc.Message(MSG_ERROR, "Weapon %s doesn't define a fire state.\n", info->TypeName.GetChars()); - } - } - } -} - -//========================================================================== -// -// Do some postprocessing after everything has been defined -// -//========================================================================== - -static void DumpFunction(FILE *dump, VMScriptFunction *sfunc, const char *label, int labellen) -{ - const char *marks = "======================================================="; - fprintf(dump, "\n%.*s %s %.*s", MAX(3, 38 - labellen / 2), marks, label, MAX(3, 38 - labellen / 2), marks); - fprintf(dump, "\nInteger regs: %-3d Float regs: %-3d Address regs: %-3d String regs: %-3d\nStack size: %d\n", - sfunc->NumRegD, sfunc->NumRegF, sfunc->NumRegA, sfunc->NumRegS, sfunc->MaxParam); - VMDumpConstants(dump, sfunc); - fprintf(dump, "\nDisassembly @ %p:\n", sfunc->Code); - VMDisasm(dump, sfunc->Code, sfunc->CodeSize, sfunc); -} - -static void FinishThingdef() -{ - int errorcount = 0; - unsigned i; - int codesize = 0; - FILE *dump = NULL; - - if (Args->CheckParm("-dumpdisasm")) dump = fopen("disasm.txt", "w"); - - for (i = 0; i < StateTempCalls.Size(); ++i) - { - FStateTempCall *tcall = StateTempCalls[i]; - VMFunction *func = nullptr; - - assert(tcall->Code != NULL); - - // We don't know the return type in advance for anonymous functions. - FCompileContext ctx(tcall->ActorClass, nullptr); - tcall->Code = tcall->Code->Resolve(ctx); - tcall->Proto = ctx.ReturnProto; - - // Make sure resolving it didn't obliterate it. - if (tcall->Code != nullptr) - { - // Can we call this function directly without wrapping it in an - // anonymous function? e.g. Are we passing any parameters to it? - func = tcall->Code->GetDirectFunction(); - - if (func == nullptr) - { - VMFunctionBuilder buildit(true); - - assert(tcall->Proto != nullptr); - - // Allocate registers used to pass parameters in. - // self, stateowner, state (all are pointers) - buildit.Registers[REGT_POINTER].Get(3); - - // Emit code - tcall->Code->Emit(&buildit); - - VMScriptFunction *sfunc = buildit.MakeFunction(); - sfunc->NumArgs = NAP; - - // Generate prototype for this anonymous function - TArray args(3); - SetImplicitArgs(&args, NULL, tcall->ActorClass, VARF_Method | VARF_Action); - sfunc->Proto = NewPrototype(tcall->Proto->ReturnTypes, args); - - func = sfunc; - - if (dump != NULL) - { - char label[64]; - int labellen = mysnprintf(label, countof(label), "Function %s.States[%d] (*%d)", - tcall->ActorClass->TypeName.GetChars(), tcall->FirstState, tcall->NumStates); - DumpFunction(dump, sfunc, label, labellen); - codesize += sfunc->CodeSize; - } - } - - delete tcall->Code; - tcall->Code = nullptr; - for (int k = 0; k < tcall->NumStates; ++k) - { - tcall->ActorClass->OwnedStates[tcall->FirstState + k].SetAction(func); - } - } - } - - for (i = 0; i < PClassActor::AllActorClasses.Size(); i++) - { - PClassActor *ti = PClassActor::AllActorClasses[i]; - - if (ti->Size == TentativeClass) - { - Printf(TEXTCOLOR_RED "Class %s referenced but not defined\n", ti->TypeName.GetChars()); - errorcount++; - continue; - } - - AActor *def = GetDefaultByType(ti); - - if (!def) - { - Printf(TEXTCOLOR_RED "No ActorInfo defined for class '%s'\n", ti->TypeName.GetChars()); - errorcount++; - continue; - } - - if (def->DamageFunc != nullptr) - { - FxDamageValue *dmg = (FxDamageValue *)ActorDamageFuncs[(uintptr_t)def->DamageFunc - 1]; - VMScriptFunction *sfunc; - sfunc = dmg->GetFunction(); - if (sfunc == nullptr) - { - FCompileContext ctx(ti); - dmg = static_cast(dmg->Resolve(ctx)); - - if (dmg != nullptr) - { - VMFunctionBuilder buildit; - buildit.Registers[REGT_POINTER].Get(1); // The self pointer - dmg->Emit(&buildit); - sfunc = buildit.MakeFunction(); - sfunc->NumArgs = 1; - sfunc->Proto = nullptr; ///FIXME: Need a proper prototype here - // Save this function in case this damage value was reused - // (which happens quite easily with inheritance). - dmg->SetFunction(sfunc); - } - } - def->DamageFunc = sfunc; - - if (dump != nullptr && sfunc != nullptr) - { - char label[64]; - int labellen = mysnprintf(label, countof(label), "Function %s.Damage", - ti->TypeName.GetChars()); - DumpFunction(dump, sfunc, label, labellen); - codesize += sfunc->CodeSize; - } - } - } - if (dump != NULL) - { - fprintf(dump, "\n*************************************************************************\n%i code bytes\n", codesize * 4); - fclose(dump); - } - if (errorcount > 0) - { - I_Error("%d errors during actor postprocessing", errorcount); - } - - ActorDamageFuncs.DeleteAndClear(); - StateTempCalls.DeleteAndClear(); - - // Since these are defined in DECORATE now the table has to be initialized here. - for(int i = 0; i < 31; i++) - { - char fmt[20]; - mysnprintf(fmt, countof(fmt), "QuestItem%d", i+1); - QuestItemClasses[i] = PClass::FindActor(fmt); - } -} - - - -//========================================================================== -// -// LoadActors -// -// Called from FActor::StaticInit() -// -//========================================================================== - -void LoadActors () -{ - int lastlump, lump; - cycle_t timer; - - timer.Reset(); timer.Clock(); - ActorDamageFuncs.Clear(); - FScriptPosition::ResetErrorCounter(); - InitThingdef(); - lastlump = 0; - while ((lump = Wads.FindLump ("DECORATE", &lastlump)) != -1) - { - FScanner sc(lump); - - if (Wads.GetLumpFile(lump) == 0) - { - // define namespace 'zdoom' - } - else - { - // use namespace 'zdoom' - } - - ParseDecorate (sc); - } - FinishThingdef(); - if (FScriptPosition::ErrorCounter > 0) - { - I_Error("%d errors while parsing DECORATE scripts", FScriptPosition::ErrorCounter); - } - timer.Unclock(); - if (!batchrun) Printf("DECORATE parsing took %.2f ms\n", timer.TimeMS()); - // Base time: ~52 ms -} diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp deleted file mode 100644 index 7c55e52864..0000000000 --- a/src/thingdef/thingdef_expression.cpp +++ /dev/null @@ -1,5259 +0,0 @@ -/* -** thingdef_expression.cpp -** -** Expression evaluation -** -**--------------------------------------------------------------------------- -** Copyright 2008 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be -** covered by the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or (at -** your option) any later version. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ - -#include -#include "actor.h" -#include "sc_man.h" -#include "tarray.h" -#include "templates.h" -#include "cmdlib.h" -#include "i_system.h" -#include "m_random.h" -#include "a_pickups.h" -#include "thingdef.h" -#include "p_lnspec.h" -#include "doomstat.h" -#include "thingdef_exp.h" -#include "m_fixed.h" -#include "vmbuilder.h" -#include "v_text.h" -#include "math/cmath.h" - -struct FLOP -{ - ENamedName Name; - int Flop; - double (*Evaluate)(double); -}; - -// Decorate operates on degrees, so the evaluate functions need to convert -// degrees to radians for those that work with angles. -static const FLOP FxFlops[] = -{ - { NAME_Exp, FLOP_EXP, [](double v) { return g_exp(v); } }, - { NAME_Log, FLOP_LOG, [](double v) { return g_log(v); } }, - { NAME_Log10, FLOP_LOG10, [](double v) { return g_log10(v); } }, - { NAME_Sqrt, FLOP_SQRT, [](double v) { return g_sqrt(v); } }, - { NAME_Ceil, FLOP_CEIL, [](double v) { return ceil(v); } }, - { NAME_Floor, FLOP_FLOOR, [](double v) { return floor(v); } }, - - { NAME_ACos, FLOP_ACOS_DEG, [](double v) { return g_acos(v) * (180.0 / M_PI); } }, - { NAME_ASin, FLOP_ASIN_DEG, [](double v) { return g_asin(v) * (180.0 / M_PI); } }, - { NAME_ATan, FLOP_ATAN_DEG, [](double v) { return g_atan(v) * (180.0 / M_PI); } }, - { NAME_Cos, FLOP_COS_DEG, [](double v) { return g_cosdeg(v); } }, - { NAME_Sin, FLOP_SIN_DEG, [](double v) { return g_sindeg(v); } }, - { NAME_Tan, FLOP_TAN_DEG, [](double v) { return g_tan(v * (M_PI / 180.0)); } }, - - { NAME_CosH, FLOP_COSH, [](double v) { return g_cosh(v); } }, - { NAME_SinH, FLOP_SINH, [](double v) { return g_sinh(v); } }, - { NAME_TanH, FLOP_TANH, [](double v) { return g_tanh(v); } }, -}; - -//========================================================================== -// -// FCompileContext -// -//========================================================================== - -FCompileContext::FCompileContext(PClassActor *cls, PPrototype *ret) : ReturnProto(ret), Class(cls) -{ -} - -PSymbol *FCompileContext::FindInClass(FName identifier) -{ - return Class ? Class->Symbols.FindSymbol(identifier, true) : nullptr; -} -PSymbol *FCompileContext::FindGlobal(FName identifier) -{ - return GlobalSymbols.FindSymbol(identifier, true); -} - -void FCompileContext::HandleJumps(int token, FxExpression *handler) -{ - for (unsigned int i = 0; i < Jumps.Size(); i++) - { - if (Jumps[i]->Token == token) - { - Jumps[i]->AddressResolver = handler; - handler->JumpAddresses.Push(Jumps[i]); - Jumps.Delete(i); - i--; - } - } -} - -void FCompileContext::CheckReturn(PPrototype *proto, FScriptPosition &pos) -{ - assert(proto != nullptr); - bool fail = false; - - if (ReturnProto == nullptr) - { - ReturnProto = proto; - return; - } - - // A prototype that defines fewer return types can be compatible with - // one that defines more if the shorter one matches the initial types - // for the longer one. - if (ReturnProto->ReturnTypes.Size() < proto->ReturnTypes.Size()) - { // Make proto the shorter one to avoid code duplication below. - swapvalues(proto, ReturnProto); - } - // If one prototype returns nothing, they both must. - if (proto->ReturnTypes.Size() == 0) - { - if (ReturnProto->ReturnTypes.Size() != 0) - { - fail = true; - } - } - else - { - for (unsigned i = 0; i < proto->ReturnTypes.Size(); i++) - { - if (ReturnProto->ReturnTypes[i] != proto->ReturnTypes[i]) - { // Incompatible - fail = true; - break; - } - } - } - - if (fail) - { - pos.Message(MSG_ERROR, "All return expressions must deduce to the same type"); - } -} - -//========================================================================== -// -// ExpEmit -// -//========================================================================== - -ExpEmit::ExpEmit(VMFunctionBuilder *build, int type) -: RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false), Fixed(false), Final(false) -{ -} - -void ExpEmit::Free(VMFunctionBuilder *build) -{ - if (!Fixed && !Konst && RegType <= REGT_TYPE) - { - build->Registers[RegType].Return(RegNum, 1); - } -} - -void ExpEmit::Reuse(VMFunctionBuilder *build) -{ - if (!Fixed && !Konst) - { - bool success = build->Registers[RegType].Reuse(RegNum); - assert(success && "Attempt to reuse a register that is already in use"); - } -} - -//========================================================================== -// -// FindDecorateBuiltinFunction -// -// Returns the symbol for a decorate utility function. If not found, create -// it and install it in Actor. -// -//========================================================================== - -static PSymbol *FindDecorateBuiltinFunction(FName funcname, VMNativeFunction::NativeCallType func) -{ - PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol(funcname, false); - if (sym == NULL) - { - PSymbolVMFunction *symfunc = new PSymbolVMFunction(funcname); - VMNativeFunction *calldec = new VMNativeFunction(func, funcname); - symfunc->Function = calldec; - sym = symfunc; - RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym); - } - return sym; -} - -//========================================================================== -// -// -// -//========================================================================== - -ExpEmit FxExpression::Emit (VMFunctionBuilder *build) -{ - ScriptPosition.Message(MSG_ERROR, "Unemitted expression found"); - return ExpEmit(); -} - - -//========================================================================== -// -// -// -//========================================================================== - -bool FxExpression::isConstant() const -{ - return false; -} - -//========================================================================== -// -// -// -//========================================================================== - -VMFunction *FxExpression::GetDirectFunction() -{ - return NULL; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxExpression::Resolve(FCompileContext &ctx) -{ - isresolved = true; - return this; -} - -//========================================================================== -// -// Returns true if we can write to the address. -// -//========================================================================== - -bool FxExpression::RequestAddress() -{ - ScriptPosition.Message(MSG_ERROR, "invalid dereference\n"); - return false; -} - -//========================================================================== -// -// Called by return statements. -// -//========================================================================== - -PPrototype *FxExpression::ReturnProto() -{ - assert(ValueType != nullptr); - - TArray ret(0); - TArray none(0); - if (ValueType != TypeVoid) - { - ret.Push(ValueType); - } - - return NewPrototype(ret, none); -} - -//========================================================================== -// -// -// -//========================================================================== - -static void EmitParameter(VMFunctionBuilder *build, FxExpression *operand, const FScriptPosition &pos) -{ - ExpEmit where = operand->Emit(build); - - if (where.RegType == REGT_NIL) - { - pos.Message(MSG_ERROR, "Attempted to pass a non-value"); - build->Emit(OP_PARAM, 0, where.RegType, where.RegNum); - } - else - { - int regtype = where.RegType; - if (where.Konst) - { - regtype |= REGT_KONST; - } - build->Emit(OP_PARAM, 0, regtype, where.RegNum); - where.Free(build); - } -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxConstant::MakeConstant(PSymbol *sym, const FScriptPosition &pos) -{ - FxExpression *x; - PSymbolConstNumeric *csym = dyn_cast(sym); - if (csym != NULL) - { - if (csym->ValueType->IsA(RUNTIME_CLASS(PInt))) - { - x = new FxConstant(csym->Value, pos); - } - else if (csym->ValueType->IsA(RUNTIME_CLASS(PFloat))) - { - x = new FxConstant(csym->Float, pos); - } - else - { - pos.Message(MSG_ERROR, "Invalid constant '%s'\n", csym->SymbolName.GetChars()); - return NULL; - } - } - else - { - pos.Message(MSG_ERROR, "'%s' is not a constant\n", sym->SymbolName.GetChars()); - x = NULL; - } - return x; -} - -ExpEmit FxConstant::Emit(VMFunctionBuilder *build) -{ - ExpEmit out; - - out.Konst = true; - int regtype = value.Type->GetRegType(); - out.RegType = regtype; - if (regtype == REGT_INT) - { - out.RegNum = build->GetConstantInt(value.Int); - } - else if (regtype == REGT_FLOAT) - { - out.RegNum = build->GetConstantFloat(value.Float); - } - else if (regtype == REGT_POINTER) - { - VM_ATAG tag = ATAG_GENERIC; - if (value.Type == TypeState) - { - tag = ATAG_STATE; - } - else if (value.Type->GetLoadOp() == OP_LO) - { - tag = ATAG_OBJECT; - } - out.RegNum = build->GetConstantAddress(value.pointer, tag); - } - else if (regtype == REGT_STRING) - { - out.RegNum = build->GetConstantString(value.GetString()); - } - else - { - ScriptPosition.Message(MSG_ERROR, "Cannot emit needed constant"); - out.RegNum = 0; - } - return out; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxBoolCast::FxBoolCast(FxExpression *x) - : FxExpression(x->ScriptPosition) -{ - basex = x; - ValueType = TypeBool; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxBoolCast::~FxBoolCast() -{ - SAFE_DELETE(basex); -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxBoolCast::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE(basex, ctx); - - if (basex->ValueType == TypeBool) - { - FxExpression *x = basex; - basex = nullptr; - delete this; - return x; - } - else if (basex->ValueType->GetRegType() == REGT_INT || basex->ValueType->GetRegType() == REGT_FLOAT || basex->ValueType->GetRegType() == REGT_POINTER) - { - if (basex->isConstant()) - { - assert(basex->ValueType != TypeState && "We shouldn't be able to generate a constant state ref"); - - ExpVal constval = static_cast(basex)->GetValue(); - FxExpression *x = new FxConstant(constval.GetBool(), ScriptPosition); - delete this; - return x; - } - return this; - } - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); - delete this; - return nullptr; -} - -//========================================================================== -// -// -// -//========================================================================== - -ExpEmit FxBoolCast::Emit(VMFunctionBuilder *build) -{ - ExpEmit from = basex->Emit(build); - assert(!from.Konst); - assert(basex->ValueType->GetRegType() == REGT_INT || basex->ValueType->GetRegType() == REGT_FLOAT || basex->ValueType->GetRegType() == REGT_POINTER); - ExpEmit to(build, REGT_INT); - from.Free(build); - - // Preload result with 0. - build->Emit(OP_LI, to.RegNum, 0); - - // Check source against 0. - if (from.RegType == REGT_INT) - { - build->Emit(OP_EQ_R, 1, from.RegNum, to.RegNum); - } - else if (from.RegType == REGT_FLOAT) - { - build->Emit(OP_EQF_K, 1, from.RegNum, build->GetConstantFloat(0.)); - } - else if (from.RegType == REGT_POINTER) - { - build->Emit(OP_EQA_K, 1, from.RegNum, build->GetConstantAddress(nullptr, ATAG_GENERIC)); - } - build->Emit(OP_JMP, 1); - - // Reload result with 1 if the comparison fell through. - build->Emit(OP_LI, to.RegNum, 1); - - return to; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxIntCast::FxIntCast(FxExpression *x) -: FxExpression(x->ScriptPosition) -{ - basex=x; - ValueType = TypeSInt32; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxIntCast::~FxIntCast() -{ - SAFE_DELETE(basex); -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxIntCast::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE(basex, ctx); - - if (basex->ValueType->GetRegType() == REGT_INT) - { - if (basex->ValueType != TypeName) - { - FxExpression *x = basex; - basex = NULL; - delete this; - return x; - } - else - { - // Ugh. This should abort, but too many mods fell into this logic hole somewhere, so this seroious error needs to be reduced to a warning. :( - if (!basex->isConstant()) ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got a name"); - else ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got \"%s\"", static_cast(basex)->GetValue().GetName().GetChars()); - FxExpression * x = new FxConstant(0, ScriptPosition); - delete this; - return x; - } - } - else if (basex->ValueType->GetRegType() == REGT_FLOAT) - { - if (basex->isConstant()) - { - ExpVal constval = static_cast(basex)->GetValue(); - FxExpression *x = new FxConstant(constval.GetInt(), ScriptPosition); - delete this; - return x; - } - return this; - } - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); - delete this; - return NULL; -} - -//========================================================================== -// -// -// -//========================================================================== - -ExpEmit FxIntCast::Emit(VMFunctionBuilder *build) -{ - ExpEmit from = basex->Emit(build); - assert(!from.Konst); - assert(basex->ValueType->GetRegType() == REGT_FLOAT); - from.Free(build); - ExpEmit to(build, REGT_INT); - build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_F2I); - return to; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxFloatCast::FxFloatCast(FxExpression *x) -: FxExpression(x->ScriptPosition) -{ - basex=x; - ValueType = TypeFloat64; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxFloatCast::~FxFloatCast() -{ - SAFE_DELETE(basex); -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxFloatCast::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE(basex, ctx); - - if (basex->ValueType->GetRegType() == REGT_FLOAT) - { - FxExpression *x = basex; - basex = NULL; - delete this; - return x; - } - else if (basex->ValueType->GetRegType() == REGT_INT) - { - if (basex->ValueType != TypeName) - { - if (basex->isConstant()) - { - ExpVal constval = static_cast(basex)->GetValue(); - FxExpression *x = new FxConstant(constval.GetFloat(), ScriptPosition); - delete this; - return x; - } - return this; - } - else - { - // Ugh. This should abort, but too many mods fell into this logic hole somewhere, so this seroious error needs to be reduced to a warning. :( - if (!basex->isConstant()) ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got a name"); - else ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got \"%s\"", static_cast(basex)->GetValue().GetName().GetChars()); - FxExpression *x = new FxConstant(0.0, ScriptPosition); - delete this; - return x; - } - } - else - { - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); - delete this; - return NULL; - } -} - -//========================================================================== -// -// -// -//========================================================================== - -ExpEmit FxFloatCast::Emit(VMFunctionBuilder *build) -{ - ExpEmit from = basex->Emit(build); - assert(!from.Konst); - assert(basex->ValueType->GetRegType() == REGT_INT); - from.Free(build); - ExpEmit to(build, REGT_FLOAT); - build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_I2F); - return to; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxPlusSign::FxPlusSign(FxExpression *operand) -: FxExpression(operand->ScriptPosition) -{ - Operand=operand; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxPlusSign::~FxPlusSign() -{ - SAFE_DELETE(Operand); -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxPlusSign::Resolve(FCompileContext& ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE(Operand, ctx); - - if (Operand->IsNumeric()) - { - FxExpression *e = Operand; - Operand = NULL; - delete this; - return e; - } - else - { - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); - delete this; - return NULL; - } -} - -ExpEmit FxPlusSign::Emit(VMFunctionBuilder *build) -{ - return Operand->Emit(build); -} - -//========================================================================== -// -// -// -//========================================================================== - -FxMinusSign::FxMinusSign(FxExpression *operand) -: FxExpression(operand->ScriptPosition) -{ - Operand=operand; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxMinusSign::~FxMinusSign() -{ - SAFE_DELETE(Operand); -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxMinusSign::Resolve(FCompileContext& ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE(Operand, ctx); - - if (Operand->IsNumeric()) - { - if (Operand->isConstant()) - { - ExpVal val = static_cast(Operand)->GetValue(); - FxExpression *e = val.Type->GetRegType() == REGT_INT ? - new FxConstant(-val.Int, ScriptPosition) : - new FxConstant(-val.Float, ScriptPosition); - delete this; - return e; - } - ValueType = Operand->ValueType; - return this; - } - else - { - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); - delete this; - return NULL; - } -} - -//========================================================================== -// -// -// -//========================================================================== - -ExpEmit FxMinusSign::Emit(VMFunctionBuilder *build) -{ - assert(ValueType == Operand->ValueType); - ExpEmit from = Operand->Emit(build); - assert(from.Konst == 0); - // Do it in-place. - if (ValueType->GetRegType() == REGT_INT) - { - build->Emit(OP_NEG, from.RegNum, from.RegNum, 0); - } - else - { - assert(ValueType->GetRegType() == REGT_FLOAT); - build->Emit(OP_FLOP, from.RegNum, from.RegNum, FLOP_NEG); - } - return from; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxUnaryNotBitwise::FxUnaryNotBitwise(FxExpression *operand) -: FxExpression(operand->ScriptPosition) -{ - Operand=operand; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxUnaryNotBitwise::~FxUnaryNotBitwise() -{ - SAFE_DELETE(Operand); -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE(Operand, ctx); - - if (Operand->ValueType->GetRegType() == REGT_FLOAT /* lax */) - { - // DECORATE allows floats here so cast them to int. - Operand = new FxIntCast(Operand); - Operand = Operand->Resolve(ctx); - if (Operand == NULL) - { - delete this; - return NULL; - } - } - - if (Operand->ValueType->GetRegType() != REGT_INT) - { - ScriptPosition.Message(MSG_ERROR, "Integer type expected"); - delete this; - return NULL; - } - - if (Operand->isConstant()) - { - int result = ~static_cast(Operand)->GetValue().GetInt(); - FxExpression *e = new FxConstant(result, ScriptPosition); - delete this; - return e; - } - ValueType = TypeSInt32; - return this; -} - -//========================================================================== -// -// -// -//========================================================================== - -ExpEmit FxUnaryNotBitwise::Emit(VMFunctionBuilder *build) -{ - assert(Operand->ValueType->GetRegType() == REGT_INT); - ExpEmit from = Operand->Emit(build); - assert(!from.Konst); - // Do it in-place. - build->Emit(OP_NOT, from.RegNum, from.RegNum, 0); - return from; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxUnaryNotBoolean::FxUnaryNotBoolean(FxExpression *operand) -: FxExpression(operand->ScriptPosition) -{ - Operand=operand; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxUnaryNotBoolean::~FxUnaryNotBoolean() -{ - SAFE_DELETE(Operand); -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE(Operand, ctx); - - if (Operand->ValueType != TypeBool) - { - Operand = new FxBoolCast(Operand); - SAFE_RESOLVE(Operand, ctx); - } - - if (Operand->isConstant()) - { - bool result = !static_cast(Operand)->GetValue().GetBool(); - FxExpression *e = new FxConstant(result, ScriptPosition); - delete this; - return e; - } - - ValueType = TypeBool; - return this; -} - -//========================================================================== -// -// -// -//========================================================================== - -ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build) -{ - assert(Operand->ValueType == ValueType); - assert(ValueType == TypeBool); - ExpEmit from = Operand->Emit(build); - assert(!from.Konst); - // ~x & 1 - build->Emit(OP_NOT, from.RegNum, from.RegNum, 0); - build->Emit(OP_AND_RK, from.RegNum, from.RegNum, build->GetConstantInt(1)); - return from; -} - -//========================================================================== -// -// FxPreIncrDecr -// -//========================================================================== - -FxPreIncrDecr::FxPreIncrDecr(FxExpression *base, int token) -: FxExpression(base->ScriptPosition), Token(token), Base(base) -{ - AddressRequested = false; - AddressWritable = false; -} - -FxPreIncrDecr::~FxPreIncrDecr() -{ - SAFE_DELETE(Base); -} - -bool FxPreIncrDecr::RequestAddress() -{ - AddressRequested = true; - return AddressWritable; -} - -FxExpression *FxPreIncrDecr::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE(Base, ctx); - - ValueType = Base->ValueType; - - if (!Base->IsNumeric()) - { - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); - delete this; - return nullptr; - } - else if (Base->ValueType == TypeBool) - { - ScriptPosition.Message(MSG_ERROR, "%s is not allowed on type bool", FScanner::TokenName(Token).GetChars()); - delete this; - return nullptr; - } - if (!(AddressWritable = Base->RequestAddress())) - { - ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value"); - delete this; - return nullptr; - } - - return this; -} - -ExpEmit FxPreIncrDecr::Emit(VMFunctionBuilder *build) -{ - assert(Token == TK_Incr || Token == TK_Decr); - assert(ValueType == Base->ValueType && IsNumeric()); - - int zero = build->GetConstantInt(0); - int regtype = ValueType->GetRegType(); - ExpEmit pointer = Base->Emit(build); - - ExpEmit value(build, regtype); - build->Emit(ValueType->GetLoadOp(), value.RegNum, pointer.RegNum, zero); - - if (regtype == REGT_INT) - { - build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, value.RegNum, value.RegNum, build->GetConstantInt(1)); - } - else - { - build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, value.RegNum, value.RegNum, build->GetConstantFloat(1.)); - } - - build->Emit(ValueType->GetStoreOp(), pointer.RegNum, value.RegNum, zero); - - if (AddressRequested) - { - value.Free(build); - return pointer; - } - - pointer.Free(build); - return value; -} - -//========================================================================== -// -// FxPostIncrDecr -// -//========================================================================== - -FxPostIncrDecr::FxPostIncrDecr(FxExpression *base, int token) -: FxExpression(base->ScriptPosition), Token(token), Base(base) -{ -} - -FxPostIncrDecr::~FxPostIncrDecr() -{ - SAFE_DELETE(Base); -} - -FxExpression *FxPostIncrDecr::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE(Base, ctx); - - ValueType = Base->ValueType; - - if (!Base->IsNumeric()) - { - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); - delete this; - return nullptr; - } - else if (Base->ValueType == TypeBool) - { - ScriptPosition.Message(MSG_ERROR, "%s is not allowed on type bool", FScanner::TokenName(Token).GetChars()); - delete this; - return nullptr; - } - if (!Base->RequestAddress()) - { - ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value"); - delete this; - return nullptr; - } - - return this; -} - -ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build) -{ - assert(Token == TK_Incr || Token == TK_Decr); - assert(ValueType == Base->ValueType && IsNumeric()); - - int zero = build->GetConstantInt(0); - int regtype = ValueType->GetRegType(); - ExpEmit pointer = Base->Emit(build); - - ExpEmit out(build, regtype); - build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, zero); - - ExpEmit assign(build, regtype); - if (regtype == REGT_INT) - { - build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, assign.RegNum, out.RegNum, build->GetConstantInt(1)); - } - else - { - build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, assign.RegNum, out.RegNum, build->GetConstantFloat(1.)); - } - - build->Emit(ValueType->GetStoreOp(), pointer.RegNum, assign.RegNum, zero); - - pointer.Free(build); - assign.Free(build); - return out; -} - -//========================================================================== -// -// FxAssign -// -//========================================================================== - -FxAssign::FxAssign(FxExpression *base, FxExpression *right) -: FxExpression(base->ScriptPosition), Base(base), Right(right) -{ - AddressRequested = false; - AddressWritable = false; -} - -FxAssign::~FxAssign() -{ - SAFE_DELETE(Base); - SAFE_DELETE(Right); -} - -bool FxAssign::RequestAddress() -{ - AddressRequested = true; - return AddressWritable; -} - -FxExpression *FxAssign::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE(Base, ctx); - - ValueType = Base->ValueType; - - SAFE_RESOLVE(Right, ctx); - - if (!Base->IsNumeric() || !Right->IsNumeric()) - { - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); - delete this; - return nullptr; - } - if (!(AddressWritable = Base->RequestAddress())) - { - ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value"); - delete this; - return nullptr; - } - - if (Right->ValueType != ValueType) - { - if (ValueType == TypeBool) - { - Right = new FxBoolCast(Right); - } - else if (ValueType->GetRegType() == REGT_INT) - { - Right = new FxIntCast(Right); - } - else - { - Right = new FxFloatCast(Right); - } - SAFE_RESOLVE(Right, ctx); - } - - return this; -} - -ExpEmit FxAssign::Emit(VMFunctionBuilder *build) -{ - assert(ValueType == Base->ValueType && IsNumeric()); - assert(ValueType->GetRegType() == Right->ValueType->GetRegType()); - - ExpEmit pointer = Base->Emit(build); - Address = pointer; - - ExpEmit result = Right->Emit(build); - - if (result.Konst) - { - ExpEmit temp(build, result.RegType); - build->Emit(result.RegType == REGT_FLOAT ? OP_LKF : OP_LK, temp.RegNum, result.RegNum); - result.Free(build); - result = temp; - } - - build->Emit(ValueType->GetStoreOp(), pointer.RegNum, result.RegNum, build->GetConstantInt(0)); - - if (AddressRequested) - { - result.Free(build); - return pointer; - } - - pointer.Free(build); - return result; -} - -//========================================================================== -// -// FxAssignSelf -// -//========================================================================== - -FxAssignSelf::FxAssignSelf(const FScriptPosition &pos) -: FxExpression(pos) -{ - Assignment = nullptr; -} - -FxExpression *FxAssignSelf::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - - // This should never happen if FxAssignSelf is used correctly - assert(Assignment != nullptr); - - ValueType = Assignment->ValueType; - - return this; -} - -ExpEmit FxAssignSelf::Emit(VMFunctionBuilder *build) -{ - assert(ValueType = Assignment->ValueType); - ExpEmit pointer = Assignment->Address; // FxAssign should have already emitted it - ExpEmit out(build, ValueType->GetRegType()); - build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, build->GetConstantInt(0)); - return out; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxBinary::FxBinary(int o, FxExpression *l, FxExpression *r) -: FxExpression(l->ScriptPosition) -{ - Operator=o; - left=l; - right=r; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxBinary::~FxBinary() -{ - SAFE_DELETE(left); - SAFE_DELETE(right); -} - -//========================================================================== -// -// -// -//========================================================================== - -bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric) -{ - RESOLVE(left, ctx); - RESOLVE(right, ctx); - if (!left || !right) - { - delete this; - return false; - } - - if (left->ValueType == TypeBool && right->ValueType == TypeBool) - { - ValueType = TypeBool; - } - if (left->ValueType->GetRegType() == REGT_INT && right->ValueType->GetRegType() == REGT_INT) - { - ValueType = TypeSInt32; - } - else if (left->IsNumeric() && right->IsNumeric()) - { - ValueType = TypeFloat64; - } - else if (left->ValueType->GetRegType() == REGT_POINTER && left->ValueType == right->ValueType) - { - ValueType = left->ValueType; - } - else - { - ValueType = TypeVoid; - } - - if (castnumeric) - { - // later! - } - return true; -} - -void FxBinary::Promote(FCompileContext &ctx) -{ - if (left->ValueType->GetRegType() == REGT_FLOAT && right->ValueType->GetRegType() == REGT_INT) - { - right = (new FxFloatCast(right))->Resolve(ctx); - } - else if (left->ValueType->GetRegType() == REGT_INT && right->ValueType->GetRegType() == REGT_FLOAT) - { - left = (new FxFloatCast(left))->Resolve(ctx); - } -} - -//========================================================================== -// -// -// -//========================================================================== - -FxAddSub::FxAddSub(int o, FxExpression *l, FxExpression *r) -: FxBinary(o, l, r) -{ -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxAddSub::Resolve(FCompileContext& ctx) -{ - CHECKRESOLVED(); - if (!ResolveLR(ctx, true)) return NULL; - - if (!IsNumeric()) - { - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); - delete this; - return NULL; - } - else if (left->isConstant() && right->isConstant()) - { - if (ValueType->GetRegType() == REGT_FLOAT) - { - double v; - double v1 = static_cast(left)->GetValue().GetFloat(); - double v2 = static_cast(right)->GetValue().GetFloat(); - - v = Operator == '+'? v1 + v2 : - Operator == '-'? v1 - v2 : 0; - - FxExpression *e = new FxConstant(v, ScriptPosition); - delete this; - return e; - } - else - { - int v; - int v1 = static_cast(left)->GetValue().GetInt(); - int v2 = static_cast(right)->GetValue().GetInt(); - - v = Operator == '+'? v1 + v2 : - Operator == '-'? v1 - v2 : 0; - - FxExpression *e = new FxConstant(v, ScriptPosition); - delete this; - return e; - - } - } - Promote(ctx); - return this; -} - -//========================================================================== -// -// -// -//========================================================================== - -ExpEmit FxAddSub::Emit(VMFunctionBuilder *build) -{ - assert(Operator == '+' || Operator == '-'); - ExpEmit op1 = left->Emit(build); - ExpEmit op2 = right->Emit(build); - if (Operator == '+') - { - // Since addition is commutative, only the second operand may be a constant. - if (op1.Konst) - { - swapvalues(op1, op2); - } - assert(!op1.Konst); - op1.Free(build); - op2.Free(build); - if (ValueType->GetRegType() == REGT_FLOAT) - { - assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); - ExpEmit to(build, REGT_FLOAT); - build->Emit(op2.Konst ? OP_ADDF_RK : OP_ADDF_RR, to.RegNum, op1.RegNum, op2.RegNum); - return to; - } - else - { - assert(ValueType->GetRegType() == REGT_INT); - assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT); - ExpEmit to(build, REGT_INT); - build->Emit(op2.Konst ? OP_ADD_RK : OP_ADD_RR, to.RegNum, op1.RegNum, op2.RegNum); - return to; - } - } - else - { - // Subtraction is not commutative, so either side may be constant (but not both). - assert(!op1.Konst || !op2.Konst); - op1.Free(build); - op2.Free(build); - if (ValueType->GetRegType() == REGT_FLOAT) - { - assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); - ExpEmit to(build, REGT_FLOAT); - build->Emit(op1.Konst ? OP_SUBF_KR : op2.Konst ? OP_SUBF_RK : OP_SUBF_RR, - to.RegNum, op1.RegNum, op2.RegNum); - return to; - } - else - { - assert(ValueType->GetRegType() == REGT_INT); - assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT); - ExpEmit to(build, REGT_INT); - build->Emit(op1.Konst ? OP_SUB_KR : op2.Konst ? OP_SUB_RK : OP_SUB_RR, - to.RegNum, op1.RegNum, op2.RegNum); - return to; - } - } -} - -//========================================================================== -// -// -// -//========================================================================== - -FxMulDiv::FxMulDiv(int o, FxExpression *l, FxExpression *r) -: FxBinary(o, l, r) -{ -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxMulDiv::Resolve(FCompileContext& ctx) -{ - CHECKRESOLVED(); - - if (!ResolveLR(ctx, true)) return NULL; - - if (!IsNumeric()) - { - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); - delete this; - return NULL; - } - else if (left->isConstant() && right->isConstant()) - { - if (ValueType->GetRegType() == REGT_FLOAT) - { - double v; - double v1 = static_cast(left)->GetValue().GetFloat(); - double v2 = static_cast(right)->GetValue().GetFloat(); - - if (Operator != '*' && v2 == 0) - { - ScriptPosition.Message(MSG_ERROR, "Division by 0"); - delete this; - return NULL; - } - - v = Operator == '*'? v1 * v2 : - Operator == '/'? v1 / v2 : - Operator == '%'? fmod(v1, v2) : 0; - - FxExpression *e = new FxConstant(v, ScriptPosition); - delete this; - return e; - } - else - { - int v; - int v1 = static_cast(left)->GetValue().GetInt(); - int v2 = static_cast(right)->GetValue().GetInt(); - - if (Operator != '*' && v2 == 0) - { - ScriptPosition.Message(MSG_ERROR, "Division by 0"); - delete this; - return NULL; - } - - v = Operator == '*'? v1 * v2 : - Operator == '/'? v1 / v2 : - Operator == '%'? v1 % v2 : 0; - - FxExpression *e = new FxConstant(v, ScriptPosition); - delete this; - return e; - - } - } - Promote(ctx); - return this; -} - - -//========================================================================== -// -// -// -//========================================================================== - -ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build) -{ - ExpEmit op1 = left->Emit(build); - ExpEmit op2 = right->Emit(build); - - if (Operator == '*') - { - // Multiplication is commutative, so only the second operand may be constant. - if (op1.Konst) - { - swapvalues(op1, op2); - } - assert(!op1.Konst); - op1.Free(build); - op2.Free(build); - if (ValueType->GetRegType() == REGT_FLOAT) - { - assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); - ExpEmit to(build, REGT_FLOAT); - build->Emit(op2.Konst ? OP_MULF_RK : OP_MULF_RR, to.RegNum, op1.RegNum, op2.RegNum); - return to; - } - else - { - assert(ValueType->GetRegType() == REGT_INT); - assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT); - ExpEmit to(build, REGT_INT); - build->Emit(op2.Konst ? OP_MUL_RK : OP_MUL_RR, to.RegNum, op1.RegNum, op2.RegNum); - return to; - } - } - else - { - // Division is not commutative, so either side may be constant (but not both). - assert(!op1.Konst || !op2.Konst); - assert(Operator == '%' || Operator == '/'); - op1.Free(build); - op2.Free(build); - if (ValueType->GetRegType() == REGT_FLOAT) - { - assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); - ExpEmit to(build, REGT_FLOAT); - build->Emit(Operator == '/' ? (op1.Konst ? OP_DIVF_KR : op2.Konst ? OP_DIVF_RK : OP_DIVF_RR) - : (op1.Konst ? OP_MODF_KR : op2.Konst ? OP_MODF_RK : OP_MODF_RR), - to.RegNum, op1.RegNum, op2.RegNum); - return to; - } - else - { - assert(ValueType->GetRegType() == REGT_INT); - assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT); - ExpEmit to(build, REGT_INT); - build->Emit(Operator == '/' ? (op1.Konst ? OP_DIV_KR : op2.Konst ? OP_DIV_RK : OP_DIV_RR) - : (op1.Konst ? OP_MOD_KR : op2.Konst ? OP_MOD_RK : OP_MOD_RR), - to.RegNum, op1.RegNum, op2.RegNum); - return to; - } - } -} - -//========================================================================== -// -// -// -//========================================================================== - -FxCompareRel::FxCompareRel(int o, FxExpression *l, FxExpression *r) -: FxBinary(o, l, r) -{ -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxCompareRel::Resolve(FCompileContext& ctx) -{ - CHECKRESOLVED(); - if (!ResolveLR(ctx, true)) return NULL; - - if (!IsNumeric()) - { - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); - delete this; - return NULL; - } - else if (left->isConstant() && right->isConstant()) - { - int v; - - if (ValueType->GetRegType() == REGT_FLOAT) - { - double v1 = static_cast(left)->GetValue().GetFloat(); - double v2 = static_cast(right)->GetValue().GetFloat(); - v = Operator == '<'? v1 < v2 : - Operator == '>'? v1 > v2 : - Operator == TK_Geq? v1 >= v2 : - Operator == TK_Leq? v1 <= v2 : 0; - } - else - { - int v1 = static_cast(left)->GetValue().GetInt(); - int v2 = static_cast(right)->GetValue().GetInt(); - v = Operator == '<'? v1 < v2 : - Operator == '>'? v1 > v2 : - Operator == TK_Geq? v1 >= v2 : - Operator == TK_Leq? v1 <= v2 : 0; - } - FxExpression *e = new FxConstant(v, ScriptPosition); - delete this; - return e; - } - Promote(ctx); - ValueType = TypeBool; - return this; -} - - -//========================================================================== -// -// -// -//========================================================================== - -ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build) -{ - ExpEmit op1 = left->Emit(build); - ExpEmit op2 = right->Emit(build); - assert(op1.RegType == op2.RegType); - assert(op1.RegType == REGT_INT || op1.RegType == REGT_FLOAT); - assert(!op1.Konst || !op2.Konst); - assert(Operator == '<' || Operator == '>' || Operator == TK_Geq || Operator == TK_Leq); - static const VM_UBYTE InstrMap[][4] = - { - { OP_LT_RR, OP_LTF_RR, 0 }, // < - { OP_LE_RR, OP_LEF_RR, 1 }, // > - { OP_LT_RR, OP_LTF_RR, 1 }, // >= - { OP_LE_RR, OP_LEF_RR, 0 } // <= - }; - int instr, check, index; - ExpEmit to(build, REGT_INT); - - index = Operator == '<' ? 0 : - Operator == '>' ? 1 : - Operator == TK_Geq ? 2 : 3; - instr = InstrMap[index][op1.RegType == REGT_INT ? 0 : 1]; - check = InstrMap[index][2]; - if (op2.Konst) - { - instr += 1; - } - else - { - op2.Free(build); - } - if (op1.Konst) - { - instr += 2; - } - else - { - op1.Free(build); - } - - // See FxBoolCast for comments, since it's the same thing. - build->Emit(OP_LI, to.RegNum, 0, 0); - build->Emit(instr, check, op1.RegNum, op2.RegNum); - build->Emit(OP_JMP, 1); - build->Emit(OP_LI, to.RegNum, 1); - return to; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxCompareEq::FxCompareEq(int o, FxExpression *l, FxExpression *r) -: FxBinary(o, l, r) -{ -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxCompareEq::Resolve(FCompileContext& ctx) -{ - CHECKRESOLVED(); - - if (!ResolveLR(ctx, true)) return NULL; - - if (!left || !right) - { - delete this; - return NULL; - } - - if (!IsNumeric() && !IsPointer()) - { - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); - delete this; - return NULL; - } - - if (left->isConstant() && right->isConstant()) - { - int v; - - if (ValueType->GetRegType() == REGT_FLOAT) - { - double v1 = static_cast(left)->GetValue().GetFloat(); - double v2 = static_cast(right)->GetValue().GetFloat(); - v = Operator == TK_Eq? v1 == v2 : v1 != v2; - } - else - { - int v1 = static_cast(left)->GetValue().GetInt(); - int v2 = static_cast(right)->GetValue().GetInt(); - v = Operator == TK_Eq? v1 == v2 : v1 != v2; - } - FxExpression *e = new FxConstant(v, ScriptPosition); - delete this; - return e; - } - Promote(ctx); - ValueType = TypeBool; - return this; -} - -//========================================================================== -// -// -// -//========================================================================== - -ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build) -{ - ExpEmit op1 = left->Emit(build); - ExpEmit op2 = right->Emit(build); - assert(op1.RegType == op2.RegType); - assert(op1.RegType == REGT_INT || op1.RegType == REGT_FLOAT || op1.RegType == REGT_POINTER); - int instr; - - // Only the second operand may be constant. - if (op1.Konst) - { - swapvalues(op1, op2); - } - assert(!op1.Konst); - - ExpEmit to(build, REGT_INT); - - instr = op1.RegType == REGT_INT ? OP_EQ_R : - op1.RegType == REGT_FLOAT ? OP_EQF_R : - OP_EQA_R; - op1.Free(build); - if (!op2.Konst) - { - op2.Free(build); - } - else - { - instr += 1; - } - - // See FxUnaryNotBoolean for comments, since it's the same thing. - build->Emit(OP_LI, to.RegNum, 0, 0); - build->Emit(instr, Operator != TK_Eq, op1.RegNum, op2.RegNum); - build->Emit(OP_JMP, 1); - build->Emit(OP_LI, to.RegNum, 1); - return to; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxBinaryInt::FxBinaryInt(int o, FxExpression *l, FxExpression *r) -: FxBinary(o, l, r) -{ - ValueType = TypeSInt32; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx) -{ - CHECKRESOLVED(); - if (!ResolveLR(ctx, false)) return NULL; - - if (ValueType->GetRegType() == REGT_FLOAT /* lax */) - { - // For DECORATE which allows floats here. - if (left->ValueType->GetRegType() != REGT_INT) - { - left = new FxIntCast(left); - left = left->Resolve(ctx); - } - if (right->ValueType->GetRegType() != REGT_INT) - { - right = new FxIntCast(right); - right = right->Resolve(ctx); - } - if (left == NULL || right == NULL) - { - delete this; - return NULL; - } - ValueType = TypeSInt32; - } - - if (ValueType->GetRegType() != REGT_INT) - { - ScriptPosition.Message(MSG_ERROR, "Integer type expected"); - delete this; - return NULL; - } - else if (left->isConstant() && right->isConstant()) - { - int v1 = static_cast(left)->GetValue().GetInt(); - int v2 = static_cast(right)->GetValue().GetInt(); - - FxExpression *e = new FxConstant( - Operator == TK_LShift? v1 << v2 : - Operator == TK_RShift? v1 >> v2 : - Operator == TK_URShift? int((unsigned int)(v1) >> v2) : - Operator == '&'? v1 & v2 : - Operator == '|'? v1 | v2 : - Operator == '^'? v1 ^ v2 : 0, ScriptPosition); - - delete this; - return e; - } - return this; -} - -//========================================================================== -// -// -// -//========================================================================== - -ExpEmit FxBinaryInt::Emit(VMFunctionBuilder *build) -{ - assert(left->ValueType->GetRegType() == REGT_INT); - assert(right->ValueType->GetRegType() == REGT_INT); - static const VM_UBYTE InstrMap[][4] = - { - { OP_SLL_RR, OP_SLL_KR, OP_SLL_RI }, // TK_LShift - { OP_SRA_RR, OP_SRA_KR, OP_SRA_RI }, // TK_RShift - { OP_SRL_RR, OP_SRL_KR, OP_SRL_RI }, // TK_URShift - { OP_AND_RR, 0, OP_AND_RK }, // '&' - { OP_OR_RR, 0, OP_OR_RK }, // '|' - { OP_XOR_RR, 0, OP_XOR_RK }, // '^' - }; - int index, instr, rop; - ExpEmit op1, op2; - - index = Operator == TK_LShift ? 0 : - Operator == TK_RShift ? 1 : - Operator == TK_URShift ? 2 : - Operator == '&' ? 3 : - Operator == '|' ? 4 : - Operator == '^' ? 5 : -1; - assert(index >= 0); - op1 = left->Emit(build); - if (index < 3) - { // Shift instructions use right-hand immediates instead of constant registers. - if (right->isConstant()) - { - rop = static_cast(right)->GetValue().GetInt(); - op2.Konst = true; - } - else - { - op2 = right->Emit(build); - assert(!op2.Konst); - op2.Free(build); - rop = op2.RegNum; - } - } - else - { // The other operators only take a constant on the right-hand side. - op2 = right->Emit(build); - if (op1.Konst) - { - swapvalues(op1, op2); - } - assert(!op1.Konst); - rop = op2.RegNum; - op2.Free(build); - } - if (!op1.Konst) - { - op1.Free(build); - if (!op2.Konst) - { - instr = InstrMap[index][0]; - } - else - { - instr = InstrMap[index][2]; - } - } - else - { - assert(!op2.Konst); - instr = InstrMap[index][1]; - } - assert(instr != 0); - ExpEmit to(build, REGT_INT); - build->Emit(instr, to.RegNum, op1.RegNum, rop); - return to; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxBinaryLogical::FxBinaryLogical(int o, FxExpression *l, FxExpression *r) -: FxExpression(l->ScriptPosition) -{ - Operator=o; - left=l; - right=r; - ValueType = TypeBool; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxBinaryLogical::~FxBinaryLogical() -{ - SAFE_DELETE(left); - SAFE_DELETE(right); -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx) -{ - CHECKRESOLVED(); - RESOLVE(left, ctx); - RESOLVE(right, ctx); - ABORT(right && left); - - if (left->ValueType != TypeBool) - { - left = new FxBoolCast(left); - SAFE_RESOLVE(left, ctx); - } - if (right->ValueType != TypeBool) - { - right = new FxBoolCast(right); - SAFE_RESOLVE(right, ctx); - } - - int b_left=-1, b_right=-1; - if (left->isConstant()) b_left = static_cast(left)->GetValue().GetBool(); - if (right->isConstant()) b_right = static_cast(right)->GetValue().GetBool(); - - // Do some optimizations. This will throw out all sub-expressions that are not - // needed to retrieve the final result. - if (Operator == TK_AndAnd) - { - if (b_left==0 || b_right==0) - { - FxExpression *x = new FxConstant(true, ScriptPosition); - delete this; - return x; - } - else if (b_left==1 && b_right==1) - { - FxExpression *x = new FxConstant(false, ScriptPosition); - delete this; - return x; - } - else if (b_left==1) - { - FxExpression *x = right; - right=NULL; - delete this; - return x; - } - else if (b_right==1) - { - FxExpression *x = left; - left=NULL; - delete this; - return x; - } - } - else if (Operator == TK_OrOr) - { - if (b_left==1 || b_right==1) - { - FxExpression *x = new FxConstant(true, ScriptPosition); - delete this; - return x; - } - if (b_left==0 && b_right==0) - { - FxExpression *x = new FxConstant(false, ScriptPosition); - delete this; - return x; - } - else if (b_left==0) - { - FxExpression *x = right; - right=NULL; - delete this; - return x; - } - else if (b_right==0) - { - FxExpression *x = left; - left=NULL; - delete this; - return x; - } - } - return this; -} - -//========================================================================== -// -// -// -//========================================================================== - -ExpEmit FxBinaryLogical::Emit(VMFunctionBuilder *build) -{ - // This is not the "right" way to do these, but it works for now. - // (Problem: No information sharing is done between nodes to reduce the - // code size if you have something like a1 && a2 && a3 && ... && an.) - assert(left->ValueType->GetRegType() == REGT_INT && right->ValueType->GetRegType() == REGT_INT); - ExpEmit op1 = left->Emit(build); - assert(!op1.Konst); - int zero = build->GetConstantInt(0); - op1.Free(build); - - if (Operator == TK_AndAnd) - { - build->Emit(OP_EQ_K, 1, op1.RegNum, zero); - // If op1 is 0, skip evaluation of op2. - size_t patchspot = build->Emit(OP_JMP, 0, 0, 0); - - // Evaluate op2. - ExpEmit op2 = right->Emit(build); - assert(!op2.Konst); - op2.Free(build); - - ExpEmit to(build, REGT_INT); - build->Emit(OP_EQ_K, 1, op2.RegNum, zero); - build->Emit(OP_JMP, 2); - build->Emit(OP_LI, to.RegNum, 1); - build->Emit(OP_JMP, 1); - size_t target = build->Emit(OP_LI, to.RegNum, 0); - build->Backpatch(patchspot, target); - return to; - } - else - { - assert(Operator == TK_OrOr); - build->Emit(OP_EQ_K, 0, op1.RegNum, zero); - // If op1 is not 0, skip evaluation of op2. - size_t patchspot = build->Emit(OP_JMP, 0, 0, 0); - - // Evaluate op2. - ExpEmit op2 = right->Emit(build); - assert(!op2.Konst); - op2.Free(build); - - ExpEmit to(build, REGT_INT); - build->Emit(OP_EQ_K, 0, op2.RegNum, zero); - build->Emit(OP_JMP, 2); - build->Emit(OP_LI, to.RegNum, 0); - build->Emit(OP_JMP, 1); - size_t target = build->Emit(OP_LI, to.RegNum, 1); - build->Backpatch(patchspot, target); - return to; - } -} - -//========================================================================== -// -// -// -//========================================================================== - -FxConditional::FxConditional(FxExpression *c, FxExpression *t, FxExpression *f) -: FxExpression(c->ScriptPosition) -{ - condition = c; - truex=t; - falsex=f; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxConditional::~FxConditional() -{ - SAFE_DELETE(condition); - SAFE_DELETE(truex); - SAFE_DELETE(falsex); -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxConditional::Resolve(FCompileContext& ctx) -{ - CHECKRESOLVED(); - RESOLVE(condition, ctx); - RESOLVE(truex, ctx); - RESOLVE(falsex, ctx); - ABORT(condition && truex && falsex); - - if (truex->ValueType == TypeBool && falsex->ValueType == TypeBool) - ValueType = TypeBool; - else if (truex->ValueType->GetRegType() == REGT_INT && falsex->ValueType->GetRegType() == REGT_INT) - ValueType = TypeSInt32; - else if (truex->IsNumeric() && falsex->IsNumeric()) - ValueType = TypeFloat64; - //else if (truex->ValueType != falsex->ValueType) - - if (condition->ValueType != TypeBool) - { - condition = new FxBoolCast(condition); - SAFE_RESOLVE(condition, ctx); - } - - if (condition->isConstant()) - { - ExpVal condval = static_cast(condition)->GetValue(); - bool result = condval.GetBool(); - - FxExpression *e = result? truex:falsex; - delete (result? falsex:truex); - falsex = truex = NULL; - delete this; - return e; - } - - if (ValueType->GetRegType() == REGT_FLOAT) - { - if (truex->ValueType->GetRegType() != REGT_FLOAT) - { - truex = new FxFloatCast(truex); - RESOLVE(truex, ctx); - } - if (falsex->ValueType->GetRegType() != REGT_FLOAT) - { - falsex = new FxFloatCast(falsex); - RESOLVE(falsex, ctx); - } - } - - return this; -} - -//========================================================================== -// -// -// -//========================================================================== - -ExpEmit FxConditional::Emit(VMFunctionBuilder *build) -{ - size_t truejump, falsejump; - ExpEmit out; - - // The true and false expressions ought to be assigned to the - // same temporary instead of being copied to it. Oh well; good enough - // for now. - ExpEmit cond = condition->Emit(build); - assert(cond.RegType == REGT_INT && !cond.Konst); - - // Test condition. - build->Emit(OP_EQ_K, 1, cond.RegNum, build->GetConstantInt(0)); - falsejump = build->Emit(OP_JMP, 0); - - // Evaluate true expression. - if (truex->isConstant() && truex->ValueType->GetRegType() == REGT_INT) - { - out = ExpEmit(build, REGT_INT); - build->EmitLoadInt(out.RegNum, static_cast(truex)->GetValue().GetInt()); - } - else - { - ExpEmit trueop = truex->Emit(build); - if (trueop.Konst) - { - assert(trueop.RegType == REGT_FLOAT); - out = ExpEmit(build, REGT_FLOAT); - build->Emit(OP_LKF, out.RegNum, trueop.RegNum); - } - else - { - // Use the register returned by the true condition as the - // target for the false condition. - out = trueop; - } - } - // Make sure to skip the false path. - truejump = build->Emit(OP_JMP, 0); - - // Evaluate false expression. - build->BackpatchToHere(falsejump); - if (falsex->isConstant() && falsex->ValueType->GetRegType() == REGT_INT) - { - build->EmitLoadInt(out.RegNum, static_cast(falsex)->GetValue().GetInt()); - } - else - { - ExpEmit falseop = falsex->Emit(build); - if (falseop.Konst) - { - assert(falseop.RegType == REGT_FLOAT); - build->Emit(OP_LKF, out.RegNum, falseop.RegNum); - } - else - { - // Move result from the register returned by "false" to the one - // returned by "true" so that only one register is returned by - // this tree. - falseop.Free(build); - if (falseop.RegType == REGT_INT) - { - build->Emit(OP_MOVE, out.RegNum, falseop.RegNum, 0); - } - else - { - assert(falseop.RegType == REGT_FLOAT); - build->Emit(OP_MOVEF, out.RegNum, falseop.RegNum, 0); - } - } - } - build->BackpatchToHere(truejump); - - return out; -} - -//========================================================================== -// -// -// -//========================================================================== -FxAbs::FxAbs(FxExpression *v) -: FxExpression(v->ScriptPosition) -{ - val = v; - ValueType = v->ValueType; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxAbs::~FxAbs() -{ - SAFE_DELETE(val); -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxAbs::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE(val, ctx); - - - if (!val->IsNumeric()) - { - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); - delete this; - return NULL; - } - else if (val->isConstant()) - { - ExpVal value = static_cast(val)->GetValue(); - switch (value.Type->GetRegType()) - { - case REGT_INT: - value.Int = abs(value.Int); - break; - - case REGT_FLOAT: - value.Float = fabs(value.Float); - break; - - default: - // shouldn't happen - delete this; - return NULL; - } - FxExpression *x = new FxConstant(value, ScriptPosition); - delete this; - return x; - } - ValueType = val->ValueType; - return this; -} - -//========================================================================== -// -// -// -//========================================================================== - -ExpEmit FxAbs::Emit(VMFunctionBuilder *build) -{ - ExpEmit absofsteal = val->Emit(build); - assert(!absofsteal.Konst); - ExpEmit out(build, absofsteal.RegType); - if (absofsteal.RegType == REGT_INT) - { - build->Emit(OP_ABS, out.RegNum, absofsteal.RegNum, 0); - } - else - { - assert(absofsteal.RegType == REGT_FLOAT); - build->Emit(OP_FLOP, out.RegNum, absofsteal.RegNum, FLOP_ABS); - } - return out; -} - -//========================================================================== -// -// -// -//========================================================================== -FxATan2::FxATan2(FxExpression *y, FxExpression *x, const FScriptPosition &pos) -: FxExpression(pos) -{ - yval = y; - xval = x; -} - -//========================================================================== -// -// -// -//========================================================================== -FxATan2::~FxATan2() -{ - SAFE_DELETE(yval); - SAFE_DELETE(xval); -} - -//========================================================================== -// -// -// -//========================================================================== -FxExpression *FxATan2::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE(yval, ctx); - SAFE_RESOLVE(xval, ctx); - - if (!yval->IsNumeric() || !xval->IsNumeric()) - { - ScriptPosition.Message(MSG_ERROR, "numeric value expected for parameter"); - delete this; - return NULL; - } - if (yval->isConstant() && xval->isConstant()) - { - double y = static_cast(yval)->GetValue().GetFloat(); - double x = static_cast(xval)->GetValue().GetFloat(); - FxExpression *z = new FxConstant(g_atan2(y, x) * (180 / M_PI), ScriptPosition); - delete this; - return z; - } - if (yval->ValueType->GetRegType() != REGT_FLOAT && !yval->isConstant()) - { - yval = new FxFloatCast(yval); - } - if (xval->ValueType->GetRegType() != REGT_FLOAT && !xval->isConstant()) - { - xval = new FxFloatCast(xval); - } - ValueType = TypeFloat64; - return this; -} - -//========================================================================== -// -// -// -//========================================================================== -ExpEmit FxATan2::Emit(VMFunctionBuilder *build) -{ - ExpEmit yreg = ToReg(build, yval); - ExpEmit xreg = ToReg(build, xval); - yreg.Free(build); - xreg.Free(build); - ExpEmit out(build, REGT_FLOAT); - build->Emit(OP_ATAN2, out.RegNum, yreg.RegNum, xreg.RegNum); - return out; -} - -//========================================================================== -// -// The atan2 opcode only takes registers as parameters, so any constants -// must be loaded into registers first. -// -//========================================================================== -ExpEmit FxATan2::ToReg(VMFunctionBuilder *build, FxExpression *val) -{ - if (val->isConstant()) - { - ExpEmit reg(build, REGT_FLOAT); - build->Emit(OP_LKF, reg.RegNum, build->GetConstantFloat(static_cast(val)->GetValue().GetFloat())); - return reg; - } - return val->Emit(build); -} - -//========================================================================== -// -// -// -//========================================================================== -FxMinMax::FxMinMax(TArray &expr, FName type, const FScriptPosition &pos) -: FxExpression(pos), Type(type) -{ - assert(expr.Size() > 0); - assert(type == NAME_Min || type == NAME_Max); - - choices.Resize(expr.Size()); - for (unsigned i = 0; i < expr.Size(); ++i) - { - choices[i] = expr[i]; - } -} - -//========================================================================== -// -// -// -//========================================================================== -FxExpression *FxMinMax::Resolve(FCompileContext &ctx) -{ - unsigned int i; - int intcount, floatcount; - - CHECKRESOLVED(); - - // Determine if float or int - intcount = floatcount = 0; - for (i = 0; i < choices.Size(); ++i) - { - RESOLVE(choices[i], ctx); - ABORT(choices[i]); - - if (choices[i]->ValueType->GetRegType() == REGT_FLOAT) - { - floatcount++; - } - else if (choices[i]->ValueType->GetRegType() == REGT_INT) - { - intcount++; - } - else - { - ScriptPosition.Message(MSG_ERROR, "Arguments must be of type int or float"); - delete this; - return NULL; - } - } - if (floatcount != 0) - { - ValueType = TypeFloat64; - if (intcount != 0) - { // There are some ints that need to be cast to floats - for (i = 0; i < choices.Size(); ++i) - { - if (choices[i]->ValueType->GetRegType() == REGT_INT) - { - choices[i] = new FxFloatCast(choices[i]); - RESOLVE(choices[i], ctx); - ABORT(choices[i]); - } - } - } - } - else - { - ValueType = TypeSInt32; - } - - // If at least two arguments are constants, they can be solved now. - - // Look for first constant - for (i = 0; i < choices.Size(); ++i) - { - if (choices[i]->isConstant()) - { - ExpVal best = static_cast(choices[i])->GetValue(); - // Compare against remaining constants, which are removed. - // The best value gets stored in this one. - for (unsigned j = i + 1; j < choices.Size(); ) - { - if (!choices[j]->isConstant()) - { - j++; - } - else - { - ExpVal value = static_cast(choices[j])->GetValue(); - assert(value.Type == ValueType); - if (Type == NAME_Min) - { - if (value.Type->GetRegType() == REGT_FLOAT) - { - if (value.Float < best.Float) - { - best.Float = value.Float; - } - } - else - { - if (value.Int < best.Int) - { - best.Int = value.Int; - } - } - } - else - { - if (value.Type->GetRegType() == REGT_FLOAT) - { - if (value.Float > best.Float) - { - best.Float = value.Float; - } - } - else - { - if (value.Int > best.Int) - { - best.Int = value.Int; - } - } - } - delete choices[j]; - choices[j] = NULL; - choices.Delete(j); - } - } - FxExpression *x = new FxConstant(best, ScriptPosition); - if (i == 0 && choices.Size() == 1) - { // Every choice was constant - delete this; - return x; - } - delete choices[i]; - choices[i] = x; - break; - } - } - return this; -} - -//========================================================================== -// -// -// -//========================================================================== -static void EmitLoad(VMFunctionBuilder *build, const ExpEmit resultreg, const ExpVal &value) -{ - if (resultreg.RegType == REGT_FLOAT) - { - build->Emit(OP_LKF, resultreg.RegNum, build->GetConstantFloat(value.GetFloat())); - } - else - { - build->EmitLoadInt(resultreg.RegNum, value.GetInt()); - } -} - -ExpEmit FxMinMax::Emit(VMFunctionBuilder *build) -{ - unsigned i; - int opcode, opA; - - assert(choices.Size() > 0); - assert(OP_LTF_RK == OP_LTF_RR+1); - assert(OP_LT_RK == OP_LT_RR+1); - assert(OP_LEF_RK == OP_LEF_RR+1); - assert(OP_LE_RK == OP_LE_RR+1); - - if (Type == NAME_Min) - { - opcode = ValueType->GetRegType() == REGT_FLOAT ? OP_LEF_RR : OP_LE_RR; - opA = 1; - } - else - { - opcode = ValueType->GetRegType() == REGT_FLOAT ? OP_LTF_RR : OP_LT_RR; - opA = 0; - } - - ExpEmit bestreg; - - // Get first value into a register. This will also be the result register. - if (choices[0]->isConstant()) - { - bestreg = ExpEmit(build, ValueType->GetRegType()); - EmitLoad(build, bestreg, static_cast(choices[0])->GetValue()); - } - else - { - bestreg = choices[0]->Emit(build); - } - - // Compare every choice. Better matches get copied to the bestreg. - for (i = 1; i < choices.Size(); ++i) - { - ExpEmit checkreg = choices[i]->Emit(build); - assert(checkreg.RegType == bestreg.RegType); - build->Emit(opcode + checkreg.Konst, opA, bestreg.RegNum, checkreg.RegNum); - build->Emit(OP_JMP, 1); - if (checkreg.Konst) - { - build->Emit(bestreg.RegType == REGT_FLOAT ? OP_LKF : OP_LK, bestreg.RegNum, checkreg.RegNum); - } - else - { - build->Emit(bestreg.RegType == REGT_FLOAT ? OP_MOVEF : OP_MOVE, bestreg.RegNum, checkreg.RegNum, 0); - checkreg.Free(build); - } - } - return bestreg; -} - -//========================================================================== -// -// -// -//========================================================================== -FxRandom::FxRandom(FRandom * r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos) -: FxExpression(pos) -{ - EmitTail = false; - if (mi != NULL && ma != NULL) - { - min = new FxIntCast(mi); - max = new FxIntCast(ma); - } - else min = max = NULL; - rng = r; - ValueType = TypeSInt32; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxRandom::~FxRandom() -{ - SAFE_DELETE(min); - SAFE_DELETE(max); -} - -//========================================================================== -// -// -// -//========================================================================== - -PPrototype *FxRandom::ReturnProto() -{ - EmitTail = true; - return FxExpression::ReturnProto(); -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxRandom::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - if (min && max) - { - RESOLVE(min, ctx); - RESOLVE(max, ctx); - ABORT(min && max); - assert(min->ValueType == ValueType); - assert(max->ValueType == ValueType); - } - return this; -}; - - -//========================================================================== -// -// -// -//========================================================================== - -int DecoRandom(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) -{ - assert(numparam >= 1 && numparam <= 3); - FRandom *rng = reinterpret_cast(param[0].a); - if (numparam == 1) - { - ACTION_RETURN_INT((*rng)()); - } - else if (numparam == 2) - { - int maskval = param[1].i; - ACTION_RETURN_INT(rng->Random2(maskval)); - } - else if (numparam == 3) - { - int min = param[1].i, max = param[2].i; - if (max < min) - { - swapvalues(max, min); - } - ACTION_RETURN_INT((*rng)(max - min + 1) + min); - } - - // Shouldn't happen - return 0; -} - -ExpEmit FxRandom::Emit(VMFunctionBuilder *build) -{ - // Call DecoRandom to generate a random number. - VMFunction *callfunc; - PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoRandom, DecoRandom); - - assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); - assert(((PSymbolVMFunction *)sym)->Function != NULL); - callfunc = ((PSymbolVMFunction *)sym)->Function; - - int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); - - build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); - if (min != NULL && max != NULL) - { - EmitParameter(build, min, ScriptPosition); - EmitParameter(build, max, ScriptPosition); - build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); - } - else - { - build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 1, 1); - } - - if (EmitTail) - { - ExpEmit call; - call.Final = true; - return call; - } - - ExpEmit out(build, REGT_INT); - build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum); - return out; -} - -//========================================================================== -// -// -// -//========================================================================== -FxRandomPick::FxRandomPick(FRandom *r, TArray &expr, bool floaty, const FScriptPosition &pos) -: FxExpression(pos) -{ - assert(expr.Size() > 0); - choices.Resize(expr.Size()); - for (unsigned int index = 0; index < expr.Size(); index++) - { - if (floaty) - { - choices[index] = new FxFloatCast(expr[index]); - } - else - { - choices[index] = new FxIntCast(expr[index]); - } - - } - rng = r; - if (floaty) - { - ValueType = TypeFloat64; - } - else - { - ValueType = TypeSInt32; - } -} - -//========================================================================== -// -// -// -//========================================================================== - -FxRandomPick::~FxRandomPick() -{ -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxRandomPick::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - for (unsigned int index = 0; index < choices.Size(); index++) - { - RESOLVE(choices[index], ctx); - ABORT(choices[index]); - assert(choices[index]->ValueType == ValueType); - } - return this; -}; - - -//========================================================================== -// -// FxPick :: Emit -// -// The expression: -// a = pick[rng](i_0, i_1, i_2, ..., i_n) -// [where i_x is a complete expression and not just a value] -// is syntactic sugar for: -// -// switch(random[rng](0, n)) { -// case 0: a = i_0; -// case 1: a = i_1; -// case 2: a = i_2; -// ... -// case n: a = i_n; -// } -// -//========================================================================== - -ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build) -{ - unsigned i; - - assert(choices.Size() > 0); - - // Call DecoRandom to generate a random number. - VMFunction *callfunc; - PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoRandom, DecoRandom); - - assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); - assert(((PSymbolVMFunction *)sym)->Function != NULL); - callfunc = ((PSymbolVMFunction *)sym)->Function; - - build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); - build->EmitParamInt(0); - build->EmitParamInt(choices.Size() - 1); - build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); - - ExpEmit resultreg(build, REGT_INT); - build->Emit(OP_RESULT, 0, REGT_INT, resultreg.RegNum); - build->Emit(OP_IJMP, resultreg.RegNum, 0); - - // Free the result register now. The simple code generation algorithm should - // automatically pick it as the destination register for each case. - resultreg.Free(build); - - // For floating point results, we need to get a new register, since we can't - // reuse the integer one used to store the random result. - if (ValueType->GetRegType() == REGT_FLOAT) - { - resultreg = ExpEmit(build, REGT_FLOAT); - resultreg.Free(build); - } - - // Allocate space for the jump table. - size_t jumptable = build->Emit(OP_JMP, 0); - for (i = 1; i < choices.Size(); ++i) - { - build->Emit(OP_JMP, 0); - } - - // Emit each case - TArray finishes(choices.Size() - 1); - for (unsigned i = 0; i < choices.Size(); ++i) - { - build->BackpatchToHere(jumptable + i); - if (choices[i]->isConstant()) - { - EmitLoad(build, resultreg, static_cast(choices[i])->GetValue()); - } - else - { - ExpEmit casereg = choices[i]->Emit(build); - if (casereg.RegNum != resultreg.RegNum) - { // The result of the case is in a different register from what - // was expected. Copy it to the one we wanted. - - resultreg.Reuse(build); // This is really just for the assert in Reuse() - build->Emit(ValueType->GetRegType() == REGT_INT ? OP_MOVE : OP_MOVEF, resultreg.RegNum, casereg.RegNum, 0); - resultreg.Free(build); - } - // Free this register so the remaining cases can use it. - casereg.Free(build); - } - // All but the final case needs a jump to the end of the expression's code. - if (i + 1 < choices.Size()) - { - size_t loc = build->Emit(OP_JMP, 0); - finishes.Push(loc); - } - } - // Backpatch each case (except the last, since it ends here) to jump to here. - for (i = 0; i < choices.Size() - 1; ++i) - { - build->BackpatchToHere(finishes[i]); - } - // The result register needs to be in-use when we return. - // It should have been freed earlier, so restore its in-use flag. - resultreg.Reuse(build); - return resultreg; -} - -//========================================================================== -// -// -// -//========================================================================== -FxFRandom::FxFRandom(FRandom *r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos) -: FxRandom(r, NULL, NULL, pos) -{ - if (mi != NULL && ma != NULL) - { - min = new FxFloatCast(mi); - max = new FxFloatCast(ma); - } - ValueType = TypeFloat64; -} - -//========================================================================== -// -// -// -//========================================================================== - -int DecoFRandom(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) -{ - assert(numparam == 1 || numparam == 3); - FRandom *rng = reinterpret_cast(param[0].a); - - int random = (*rng)(0x40000000); - double frandom = random / double(0x40000000); - - if (numparam == 3) - { - double min = param[1].f, max = param[2].f; - if (max < min) - { - swapvalues(max, min); - } - ACTION_RETURN_FLOAT(frandom * (max - min) + min); - } - else - { - ACTION_RETURN_FLOAT(frandom); - } -} - -ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) -{ - // Call the DecoFRandom function to generate a floating point random number.. - VMFunction *callfunc; - PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoFRandom, DecoFRandom); - - assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); - assert(((PSymbolVMFunction *)sym)->Function != NULL); - callfunc = ((PSymbolVMFunction *)sym)->Function; - - int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); - - build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); - if (min != NULL && max != NULL) - { - EmitParameter(build, min, ScriptPosition); - EmitParameter(build, max, ScriptPosition); - build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); - } - else - { - build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 1, 1); - } - - if (EmitTail) - { - ExpEmit call; - call.Final = true; - return call; - } - - ExpEmit out(build, REGT_FLOAT); - build->Emit(OP_RESULT, 0, REGT_FLOAT, out.RegNum); - return out; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxRandom2::FxRandom2(FRandom *r, FxExpression *m, const FScriptPosition &pos) -: FxExpression(pos) -{ - EmitTail = false; - rng = r; - if (m) mask = new FxIntCast(m); - else mask = new FxConstant(-1, pos); - ValueType = TypeSInt32; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxRandom2::~FxRandom2() -{ - SAFE_DELETE(mask); -} - -//========================================================================== -// -// -// -//========================================================================== - -PPrototype *FxRandom2::ReturnProto() -{ - EmitTail = true; - return FxExpression::ReturnProto(); -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxRandom2::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE(mask, ctx); - return this; -} - -//========================================================================== -// -// -// -//========================================================================== - -ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) -{ - // Call the DecoRandom function to generate the random number. - VMFunction *callfunc; - PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoRandom, DecoRandom); - - assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); - assert(((PSymbolVMFunction *)sym)->Function != NULL); - callfunc = ((PSymbolVMFunction *)sym)->Function; - - int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); - - build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); - EmitParameter(build, mask, ScriptPosition); - build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1); - - if (EmitTail) - { - ExpEmit call; - call.Final = true; - return call; - } - - ExpEmit out(build, REGT_INT); - build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum); - return out; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxIdentifier::FxIdentifier(FName name, const FScriptPosition &pos) -: FxExpression(pos) -{ - Identifier = name; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) -{ - PSymbol * sym; - FxExpression *newex = NULL; - //FBaseCVar * cv = NULL; - //FString s; - int num; - //const PClass *Class; - - CHECKRESOLVED(); - // see if the current class (if valid) defines something with this name. - if ((sym = ctx.FindInClass(Identifier)) != NULL) - { - if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) - { - ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as class constant\n", Identifier.GetChars()); - newex = FxConstant::MakeConstant(sym, ScriptPosition); - } - else if (sym->IsKindOf(RUNTIME_CLASS(PField))) - { - PField *vsym = static_cast(sym); - ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as member variable, index %d\n", Identifier.GetChars(), vsym->Offset); - newex = new FxClassMember((new FxSelf(ScriptPosition))->Resolve(ctx), vsym, ScriptPosition); - } - else - { - ScriptPosition.Message(MSG_ERROR, "Invalid member identifier '%s'\n", Identifier.GetChars()); - } - } - // now check the global identifiers. - else if ((sym = ctx.FindGlobal(Identifier)) != NULL) - { - if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) - { - ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as global constant\n", Identifier.GetChars()); - newex = FxConstant::MakeConstant(sym, ScriptPosition); - } - else - { - ScriptPosition.Message(MSG_ERROR, "Invalid global identifier '%s'\n", Identifier.GetChars()); - } - } - /* - else if ((Class = PClass::FindClass(Identifier))) - { - pos.Message(MSG_DEBUGLOG, "Resolving name '%s' as class name\n", Identifier.GetChars()); - newex = new FxClassType(Class, ScriptPosition); - } - } - */ - - // also check for CVars - /* - else if ((cv = FindCVar(Identifier, NULL)) != NULL) - { - CLOG(CL_RESOLVE, LPrintf("Resolving name '%s' as cvar\n", Identifier.GetChars())); - newex = new FxCVar(cv, ScriptPosition); - } - */ - // and line specials - else if ((num = P_FindLineSpecial(Identifier, NULL, NULL))) - { - ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as line special %d\n", Identifier.GetChars(), num); - newex = new FxConstant(num, ScriptPosition); - } - else - { - ScriptPosition.Message(MSG_ERROR, "Unknown identifier '%s'", Identifier.GetChars()); - newex = new FxConstant(0, ScriptPosition); - } - delete this; - return newex? newex->Resolve(ctx) : NULL; -} - - -//========================================================================== -// -// -// -//========================================================================== - -FxSelf::FxSelf(const FScriptPosition &pos) -: FxExpression(pos) -{ -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxSelf::Resolve(FCompileContext& ctx) -{ - CHECKRESOLVED(); - if (!ctx.Class) - { - // can't really happen with DECORATE's expression evaluator. - ScriptPosition.Message(MSG_ERROR, "self used outside of a member function"); - delete this; - return NULL; - } - ValueType = ctx.Class; - ValueType = NewPointer(RUNTIME_CLASS(DObject)); - return this; -} - -//========================================================================== -// -// -// -//========================================================================== - -ExpEmit FxSelf::Emit(VMFunctionBuilder *build) -{ - // self is always the first pointer passed to the function - ExpEmit me(0, REGT_POINTER); - me.Fixed = true; - return me; -} - - -//========================================================================== -// -// -// -//========================================================================== - -FxClassMember::FxClassMember(FxExpression *x, PField* mem, const FScriptPosition &pos) -: FxExpression(pos) -{ - classx = x; - membervar = mem; - AddressRequested = false; - //if (classx->IsDefaultObject()) Readonly=true; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxClassMember::~FxClassMember() -{ - SAFE_DELETE(classx); -} - -//========================================================================== -// -// -// -//========================================================================== - -bool FxClassMember::RequestAddress() -{ - AddressRequested = true; - return !!(~membervar->Flags & VARF_ReadOnly); -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxClassMember::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE(classx, ctx); - - PPointer *ptrtype = dyn_cast(classx->ValueType); - if (ptrtype == NULL || !ptrtype->IsKindOf(RUNTIME_CLASS(DObject))) - { - ScriptPosition.Message(MSG_ERROR, "Member variable requires a class or object"); - delete this; - return NULL; - } - ValueType = membervar->Type; - return this; -} - -ExpEmit FxClassMember::Emit(VMFunctionBuilder *build) -{ - if (build->IsActionFunc && ~membervar->Flags & VARF_Native) - { // Check if this is a user-defined variable. - // As of right now, FxClassMember is only ever used with FxSelf. - // This very user variable was defined in stateowner so if - // self (a0) != stateowner (a1) then the offset is most likely - // going to end up being totally wrong even if the variable was - // redefined in self which means we have to abort to avoid reading - // or writing to a random address and possibly crash. - build->Emit(OP_EQA_R, 1, 0, 1); - build->Emit(OP_JMP, 1); - build->Emit(OP_THROW, 2, X_BAD_SELF); - } - - ExpEmit obj = classx->Emit(build); - assert(obj.RegType == REGT_POINTER); - - if (obj.Konst) - { - // If the situation where we are dereferencing a constant - // pointer is common, then it would probably be worthwhile - // to add new opcodes for those. But as of right now, I - // don't expect it to be a particularly common case. - ExpEmit newobj(build, REGT_POINTER); - build->Emit(OP_LKP, newobj.RegNum, obj.RegNum); - obj = newobj; - } - - if (AddressRequested) - { - if (membervar->Offset == 0) - { - return obj; - } - obj.Free(build); - ExpEmit out(build, REGT_POINTER); - build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, build->GetConstantInt((int)membervar->Offset)); - return out; - } - - int offsetreg = build->GetConstantInt((int)membervar->Offset); - ExpEmit loc(build, membervar->Type->GetRegType()); - - build->Emit(membervar->Type->GetLoadOp(), loc.RegNum, obj.RegNum, offsetreg); - obj.Free(build); - return loc; -} - - -//========================================================================== -// -// -// -//========================================================================== - -FxArrayElement::FxArrayElement(FxExpression *base, FxExpression *_index) -:FxExpression(base->ScriptPosition) -{ - Array=base; - index = _index; - AddressRequested = false; - AddressWritable = false; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxArrayElement::~FxArrayElement() -{ - SAFE_DELETE(Array); - SAFE_DELETE(index); -} - -//========================================================================== -// -// -// -//========================================================================== - -bool FxArrayElement::RequestAddress() -{ - AddressRequested = true; - return AddressWritable; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE(Array,ctx); - SAFE_RESOLVE(index,ctx); - - if (index->ValueType->GetRegType() == REGT_FLOAT /* lax */) - { - // DECORATE allows floats here so cast them to int. - index = new FxIntCast(index); - index = index->Resolve(ctx); - if (index == NULL) - { - delete this; - return NULL; - } - } - if (index->ValueType->GetRegType() != REGT_INT) - { - ScriptPosition.Message(MSG_ERROR, "Array index must be integer"); - delete this; - return NULL; - } - - PArray *arraytype = dyn_cast(Array->ValueType); - if (arraytype == NULL) - { - ScriptPosition.Message(MSG_ERROR, "'[]' can only be used with arrays."); - delete this; - return NULL; - } - if (index->isConstant()) - { - unsigned indexval = static_cast(index)->GetValue().GetInt(); - if (indexval >= arraytype->ElementCount) - { - ScriptPosition.Message(MSG_ERROR, "Array index out of bounds"); - delete this; - return NULL; - } - } - - ValueType = arraytype->ElementType; - if (ValueType->GetRegType() != REGT_INT && ValueType->GetRegType() != REGT_FLOAT) - { - // int arrays only for now - ScriptPosition.Message(MSG_ERROR, "Only numeric arrays are supported."); - delete this; - return NULL; - } - AddressWritable = Array->RequestAddress(); - return this; -} - -//========================================================================== -// -// in its current state this won't be able to do more than handle the args array. -// -//========================================================================== - -ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) -{ - ExpEmit start = Array->Emit(build); - PArray *const arraytype = static_cast(Array->ValueType); - ExpEmit dest(build, arraytype->ElementType->GetRegType()); - - if (start.Konst) - { - ExpEmit tmpstart(build, REGT_POINTER); - build->Emit(OP_LKP, tmpstart.RegNum, start.RegNum); - start.Free(build); - start = tmpstart; - } - if (index->isConstant()) - { - unsigned indexval = static_cast(index)->GetValue().GetInt(); - assert(indexval < arraytype->ElementCount && "Array index out of bounds"); - indexval *= arraytype->ElementSize; - - if (AddressRequested) - { - if (indexval != 0) - { - build->Emit(OP_ADDA_RK, start.RegNum, start.RegNum, build->GetConstantInt(indexval)); - } - } - else - { - build->Emit(arraytype->ElementType->GetLoadOp(), dest.RegNum, - start.RegNum, build->GetConstantInt(indexval)); - } - } - else - { - ExpEmit indexv(index->Emit(build)); - int shiftbits = 0; - while (1u << shiftbits < arraytype->ElementSize) - { - shiftbits++; - } - assert(1u << shiftbits == arraytype->ElementSize && "Element sizes other than power of 2 are not implemented"); - build->Emit(OP_BOUND, indexv.RegNum, arraytype->ElementCount); - if (shiftbits > 0) - { - build->Emit(OP_SLL_RI, indexv.RegNum, indexv.RegNum, shiftbits); - } - - if (AddressRequested) - { - build->Emit(OP_ADDA_RR, start.RegNum, start.RegNum, indexv.RegNum); - } - else - { - build->Emit(arraytype->ElementType->GetLoadOp() + 1, // added 1 to use the *_R version that - dest.RegNum, start.RegNum, indexv.RegNum); // takes the offset from a register - } - indexv.Free(build); - } - if (AddressRequested) - { - dest.Free(build); - return start; - } - - start.Free(build); - return dest; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxFunctionCall::FxFunctionCall(FxExpression *self, FName methodname, FArgumentList *args, const FScriptPosition &pos) -: FxExpression(pos) -{ - Self = self; - MethodName = methodname; - ArgList = args; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxFunctionCall::~FxFunctionCall() -{ - SAFE_DELETE(Self); - SAFE_DELETE(ArgList); -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) -{ - for (size_t i = 0; i < countof(FxFlops); ++i) - { - if (MethodName == FxFlops[i].Name) - { - if (Self != NULL) - { - ScriptPosition.Message(MSG_ERROR, "Global functions cannot have a self pointer"); - delete this; - return NULL; - } - FxExpression *x = new FxFlopFunctionCall(i, ArgList, ScriptPosition); - ArgList = NULL; - delete this; - return x->Resolve(ctx); - } - } - - int min, max, special; - if (MethodName == NAME_ACS_NamedExecuteWithResult || MethodName == NAME_CallACS) - { - special = -ACS_ExecuteWithResult; - min = 1; - max = 5; - } - else - { - special = P_FindLineSpecial(MethodName.GetChars(), &min, &max); - } - if (special != 0 && min >= 0) - { - int paramcount = ArgList? ArgList->Size() : 0; - if (paramcount < min) - { - ScriptPosition.Message(MSG_ERROR, "Not enough parameters for '%s' (expected %d, got %d)", - MethodName.GetChars(), min, paramcount); - delete this; - return NULL; - } - else if (paramcount > max) - { - ScriptPosition.Message(MSG_ERROR, "too many parameters for '%s' (expected %d, got %d)", - MethodName.GetChars(), max, paramcount); - delete this; - return NULL; - } - FxExpression *x = new FxActionSpecialCall(Self, special, ArgList, ScriptPosition); - ArgList = NULL; - delete this; - return x->Resolve(ctx); - } - - ScriptPosition.Message(MSG_ERROR, "Call to unknown function '%s'", MethodName.GetChars()); - delete this; - return NULL; -} - - -//========================================================================== -// -// FxActionSpecialCall -// -// If special is negative, then the first argument will be treated as a -// name for ACS_NamedExecuteWithResult. -// -//========================================================================== - -FxActionSpecialCall::FxActionSpecialCall(FxExpression *self, int special, FArgumentList *args, const FScriptPosition &pos) -: FxExpression(pos) -{ - Self = self; - Special = special; - ArgList = args; - EmitTail = false; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxActionSpecialCall::~FxActionSpecialCall() -{ - SAFE_DELETE(Self); - SAFE_DELETE(ArgList); -} - -//========================================================================== -// -// -// -//========================================================================== - -PPrototype *FxActionSpecialCall::ReturnProto() -{ - EmitTail = true; - return FxExpression::ReturnProto(); -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx) -{ - CHECKRESOLVED(); - bool failed = false; - - if (ArgList != NULL) - { - for (unsigned i = 0; i < ArgList->Size(); i++) - { - (*ArgList)[i] = (*ArgList)[i]->Resolve(ctx); - if ((*ArgList)[i] == NULL) failed = true; - if (Special < 0 && i == 0) - { - if ((*ArgList)[i]->ValueType != TypeName) - { - ScriptPosition.Message(MSG_ERROR, "Name expected for parameter %d", i); - failed = true; - } - } - else if ((*ArgList)[i]->ValueType->GetRegType() != REGT_INT) - { - if ((*ArgList)[i]->ValueType->GetRegType() == REGT_FLOAT /* lax */) - { - (*ArgList)[i] = new FxIntCast((*ArgList)[i]); - } - else - { - ScriptPosition.Message(MSG_ERROR, "Integer expected for parameter %d", i); - failed = true; - } - } - } - if (failed) - { - delete this; - return NULL; - } - } - ValueType = TypeSInt32; - return this; -} - - -//========================================================================== -// -// -// -//========================================================================== - -int DecoCallLineSpecial(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) -{ - assert(numparam > 2 && numparam < 8); - assert(param[0].Type == REGT_INT); - assert(param[1].Type == REGT_POINTER); - int v[5] = { 0 }; - - for (int i = 2; i < numparam; ++i) - { - v[i - 2] = param[i].i; - } - ACTION_RETURN_INT(P_ExecuteSpecial(param[0].i, NULL, reinterpret_cast(param[1].a), false, v[0], v[1], v[2], v[3], v[4])); -} - -ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) -{ - assert(Self == NULL); - unsigned i = 0; - - build->Emit(OP_PARAMI, abs(Special)); // pass special number - build->Emit(OP_PARAM, 0, REGT_POINTER, 0); // pass self - if (ArgList != NULL) - { - for (; i < ArgList->Size(); ++i) - { - FxExpression *argex = (*ArgList)[i]; - if (Special < 0 && i == 0) - { - assert(argex->ValueType == TypeName); - assert(argex->isConstant()); - build->EmitParamInt(-static_cast(argex)->GetValue().GetName()); - } - else - { - assert(argex->ValueType->GetRegType() == REGT_INT); - if (argex->isConstant()) - { - build->EmitParamInt(static_cast(argex)->GetValue().GetInt()); - } - else - { - ExpEmit arg(argex->Emit(build)); - build->Emit(OP_PARAM, 0, arg.RegType, arg.RegNum); - arg.Free(build); - } - } - } - } - // Call the DecoCallLineSpecial function to perform the desired special. - VMFunction *callfunc; - PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoCallLineSpecial, DecoCallLineSpecial); - - assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); - assert(((PSymbolVMFunction *)sym)->Function != NULL); - callfunc = ((PSymbolVMFunction *)sym)->Function; - - if (EmitTail) - { - build->Emit(OP_TAIL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2 + i, 0); - ExpEmit call; - call.Final = true; - return call; - } - - ExpEmit dest(build, REGT_INT); - build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2 + i, 1); - build->Emit(OP_RESULT, 0, REGT_INT, dest.RegNum); - return dest; -} - -//========================================================================== -// -// FxVMFunctionCall -// -//========================================================================== - -FxVMFunctionCall::FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos) -: FxExpression(pos) -{ - Function = func; - ArgList = args; - EmitTail = false; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxVMFunctionCall::~FxVMFunctionCall() -{ - SAFE_DELETE(ArgList); -} - -//========================================================================== -// -// -// -//========================================================================== - -PPrototype *FxVMFunctionCall::ReturnProto() -{ - EmitTail = true; - return Function->Variants[0].Implementation->Proto; -} - -//========================================================================== -// -// -// -//========================================================================== - -VMFunction *FxVMFunctionCall::GetDirectFunction() -{ - // If this return statement calls a function with no arguments, - // then it can be a "direct" function. That is, the DECORATE - // definition can call that function directly without wrapping - // it inside VM code. - if (EmitTail && (ArgList ? ArgList->Size() : 0) == 0 && (Function->Flags & VARF_Action)) - { - return Function->Variants[0].Implementation; - } - - return nullptr; -} - -//========================================================================== -// -// FxVMFunctionCall :: Resolve -// -//========================================================================== - -FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) -{ - CHECKRESOLVED(); - bool failed = false; - - if (ArgList != NULL) - { - for (unsigned i = 0; i < ArgList->Size(); i++) - { - (*ArgList)[i] = (*ArgList)[i]->Resolve(ctx); - if ((*ArgList)[i] == NULL) failed = true; - } - } - if (failed) - { - delete this; - return NULL; - } - TArray &rets = Function->Variants[0].Implementation->Proto->ReturnTypes; - if (rets.Size() > 0) - { - ValueType = rets[0]; - } - else - { - ValueType = TypeVoid; - } - - return this; -} - -//========================================================================== -// -// Assumption: This call is being generated inside a function whose a0 -// register is a self pointer. For action functions, a1 maps to stateowner -// and a2 maps to callingstate. (self, stateowner, callingstate) -// -//========================================================================== - -ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) -{ - assert((build->IsActionFunc && build->Registers[REGT_POINTER].GetMostUsed() >= NAP) || - (!build->IsActionFunc && build->Registers[REGT_POINTER].GetMostUsed() >= 1)); - int count = (ArgList ? ArgList->Size() : 0); - - if (count == 1) - { - ExpEmit reg; - if (CheckEmitCast(build, EmitTail, reg)) - { - return reg; - } - } - // Emit code to pass implied parameters - if (Function->Flags & VARF_Method) - { - build->Emit(OP_PARAM, 0, REGT_POINTER, 0); - count += 1; - } - if (Function->Flags & VARF_Action) - { - static_assert(NAP == 3, "This code needs to be updated if NAP changes"); - if (build->IsActionFunc) - { - build->Emit(OP_PARAM, 0, REGT_POINTER, 1); - build->Emit(OP_PARAM, 0, REGT_POINTER, 2); - } - else - { - int null = build->GetConstantAddress(nullptr, ATAG_GENERIC); - build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, null); - build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, null); - } - count += 2; - } - // Emit code to pass explicit parameters - if (ArgList != NULL) - { - for (unsigned i = 0; i < ArgList->Size(); ++i) - { - EmitParameter(build, (*ArgList)[i], ScriptPosition); - } - } - // Get a constant register for this function - VMFunction *vmfunc = Function->Variants[0].Implementation; - int funcaddr = build->GetConstantAddress(vmfunc, ATAG_OBJECT); - // Emit the call - if (EmitTail) - { // Tail call - build->Emit(OP_TAIL_K, funcaddr, count, 0); - ExpEmit call; - call.Final = true; - return call; - } - else if (vmfunc->Proto->ReturnTypes.Size() > 0) - { // Call, expecting one result - ExpEmit reg(build, vmfunc->Proto->ReturnTypes[0]->GetRegType()); - build->Emit(OP_CALL_K, funcaddr, count, 1); - build->Emit(OP_RESULT, 0, reg.RegType, reg.RegNum); - return reg; - } - else - { // Call, expecting no results - build->Emit(OP_CALL_K, funcaddr, count, 0); - return ExpEmit(); - } -} - -//========================================================================== -// -// If calling one of the casting kludge functions, don't bother calling the -// function; just use the parameter directly. Returns true if this was a -// kludge function, false otherwise. -// -//========================================================================== - -bool FxVMFunctionCall::CheckEmitCast(VMFunctionBuilder *build, bool returnit, ExpEmit ®) -{ - FName funcname = Function->SymbolName; - if (funcname == NAME___decorate_internal_int__ || - funcname == NAME___decorate_internal_bool__ || - funcname == NAME___decorate_internal_state__ || - funcname == NAME___decorate_internal_float__) - { - FxExpression *arg = (*ArgList)[0]; - if (returnit) - { - if (arg->isConstant() && - (funcname == NAME___decorate_internal_int__ || - funcname == NAME___decorate_internal_bool__)) - { // Use immediate version for integers in range - build->EmitRetInt(0, true, static_cast(arg)->GetValue().Int); - } - else - { - ExpEmit where = arg->Emit(build); - build->Emit(OP_RET, RET_FINAL, where.RegType | (where.Konst ? REGT_KONST : 0), where.RegNum); - where.Free(build); - } - reg = ExpEmit(); - reg.Final = true; - } - else - { - reg = arg->Emit(build); - } - return true; - } - return false; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxFlopFunctionCall::FxFlopFunctionCall(size_t index, FArgumentList *args, const FScriptPosition &pos) -: FxExpression(pos) -{ - assert(index < countof(FxFlops) && "FLOP index out of range"); - Index = (int)index; - ArgList = args; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxFlopFunctionCall::~FxFlopFunctionCall() -{ - SAFE_DELETE(ArgList); -} - -FxExpression *FxFlopFunctionCall::Resolve(FCompileContext& ctx) -{ - CHECKRESOLVED(); - - if (ArgList == NULL || ArgList->Size() != 1) - { - ScriptPosition.Message(MSG_ERROR, "%s only has one parameter", FName(FxFlops[Index].Name).GetChars()); - delete this; - return NULL; - } - - (*ArgList)[0] = (*ArgList)[0]->Resolve(ctx); - if ((*ArgList)[0] == NULL) - { - delete this; - return NULL; - } - - if (!(*ArgList)[0]->IsNumeric()) - { - ScriptPosition.Message(MSG_ERROR, "numeric value expected for parameter"); - delete this; - return NULL; - } - if ((*ArgList)[0]->isConstant()) - { - double v = static_cast((*ArgList)[0])->GetValue().GetFloat(); - v = FxFlops[Index].Evaluate(v); - FxExpression *x = new FxConstant(v, ScriptPosition); - delete this; - return x; - } - if ((*ArgList)[0]->ValueType->GetRegType() == REGT_INT) - { - (*ArgList)[0] = new FxFloatCast((*ArgList)[0]); - } - ValueType = TypeFloat64; - return this; -} - -//========================================================================== -// -// -//========================================================================== - -ExpEmit FxFlopFunctionCall::Emit(VMFunctionBuilder *build) -{ - ExpEmit v = (*ArgList)[0]->Emit(build); - assert(!v.Konst && v.RegType == REGT_FLOAT); - - build->Emit(OP_FLOP, v.RegNum, v.RegNum, FxFlops[Index].Flop); - return v; -} - -//========================================================================== -// -// FxSequence :: Resolve -// -//========================================================================== - -FxExpression *FxSequence::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - for (unsigned i = 0; i < Expressions.Size(); ++i) - { - if (NULL == (Expressions[i] = Expressions[i]->Resolve(ctx))) - { - delete this; - return NULL; - } - } - return this; -} - -//========================================================================== -// -// FxSequence :: Emit -// -//========================================================================== - -ExpEmit FxSequence::Emit(VMFunctionBuilder *build) -{ - for (unsigned i = 0; i < Expressions.Size(); ++i) - { - ExpEmit v = Expressions[i]->Emit(build); - // Throw away any result. We don't care about it. - v.Free(build); - } - return ExpEmit(); -} - -//========================================================================== -// -// FxSequence :: GetDirectFunction -// -//========================================================================== - -VMFunction *FxSequence::GetDirectFunction() -{ - if (Expressions.Size() == 1) - { - return Expressions[0]->GetDirectFunction(); - } - return NULL; -} - -//========================================================================== -// -// FxIfStatement -// -//========================================================================== - -FxIfStatement::FxIfStatement(FxExpression *cond, FxExpression *true_part, - FxExpression *false_part, const FScriptPosition &pos) -: FxExpression(pos) -{ - Condition = cond; - WhenTrue = true_part; - WhenFalse = false_part; - assert(cond != NULL); -} - -FxIfStatement::~FxIfStatement() -{ - SAFE_DELETE(Condition); - SAFE_DELETE(WhenTrue); - SAFE_DELETE(WhenFalse); -} - -FxExpression *FxIfStatement::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - - if (WhenTrue == nullptr && WhenFalse == nullptr) - { // We don't do anything either way, so disappear - delete this; - return nullptr; - } - - SAFE_RESOLVE(Condition, ctx); - - if (Condition->ValueType != TypeBool) - { - Condition = new FxBoolCast(Condition); - SAFE_RESOLVE(Condition, ctx); - } - - if (WhenTrue != nullptr) - { - WhenTrue = WhenTrue->Resolve(ctx); - ABORT(WhenTrue); - } - if (WhenFalse != nullptr) - { - WhenFalse = WhenFalse->Resolve(ctx); - ABORT(WhenFalse); - } - - ValueType = TypeVoid; - - if (Condition->isConstant()) - { - ExpVal condval = static_cast(Condition)->GetValue(); - bool result = condval.GetBool(); - - FxExpression *e = result ? WhenTrue : WhenFalse; - delete (result ? WhenFalse : WhenTrue); - WhenTrue = WhenFalse = NULL; - if (e == NULL) e = new FxNop(ScriptPosition); // create a dummy if this statement gets completely removed by optimizing out the constant parts. - delete this; - return e; - } - - return this; -} - -ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build) -{ - ExpEmit v; - size_t jumpspot; - FxExpression *path1, *path2; - int condcheck; - - // This is pretty much copied from FxConditional, except we don't - // keep any results. - ExpEmit cond = Condition->Emit(build); - assert(cond.RegType == REGT_INT && !cond.Konst); - - if (WhenTrue != NULL) - { - path1 = WhenTrue; - path2 = WhenFalse; - condcheck = 1; - } - else - { - // When there is only a false path, reverse the condition so we can - // treat it as a true path. - assert(WhenFalse != NULL); - path1 = WhenFalse; - path2 = NULL; - condcheck = 0; - } - - // Test condition. - build->Emit(OP_EQ_K, condcheck, cond.RegNum, build->GetConstantInt(0)); - jumpspot = build->Emit(OP_JMP, 0); - cond.Free(build); - - // Evaluate first path - v = path1->Emit(build); - v.Free(build); - if (path2 != NULL) - { - size_t path1jump = build->Emit(OP_JMP, 0); - // Evaluate second path - build->BackpatchToHere(jumpspot); - v = path2->Emit(build); - v.Free(build); - jumpspot = path1jump; - } - build->BackpatchToHere(jumpspot); - return ExpEmit(); -} - -//========================================================================== -// -// FxWhileLoop -// -//========================================================================== - -FxWhileLoop::FxWhileLoop(FxExpression *condition, FxExpression *code, const FScriptPosition &pos) -: FxExpression(pos), Condition(condition), Code(code) -{ - ValueType = TypeVoid; -} - -FxWhileLoop::~FxWhileLoop() -{ - SAFE_DELETE(Condition); - SAFE_DELETE(Code); -} - -FxExpression *FxWhileLoop::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE(Condition, ctx); - SAFE_RESOLVE_OPT(Code, ctx); - - ctx.HandleJumps(TK_Break, this); - ctx.HandleJumps(TK_Continue, this); - - if (Condition->ValueType != TypeBool) - { - Condition = new FxBoolCast(Condition); - SAFE_RESOLVE(Condition, ctx); - } - - if (Condition->isConstant()) - { - if (static_cast(Condition)->GetValue().GetBool() == false) - { // Nothing happens - FxExpression *nop = new FxNop(ScriptPosition); - delete this; - return nop; - } - else if (Code == nullptr) - { // "while (true) { }" - // Someone could be using this for testing. - ScriptPosition.Message(MSG_WARNING, "Infinite empty loop"); - } - } - - return this; -} - -ExpEmit FxWhileLoop::Emit(VMFunctionBuilder *build) -{ - assert(Condition->ValueType == TypeBool); - - size_t loopstart, loopend; - size_t jumpspot; - - // Evaluate the condition and execute/break out of the loop. - loopstart = build->GetAddress(); - if (!Condition->isConstant()) - { - ExpEmit cond = Condition->Emit(build); - build->Emit(OP_TEST, cond.RegNum, 0); - jumpspot = build->Emit(OP_JMP, 0); - cond.Free(build); - } - else assert(static_cast(Condition)->GetValue().GetBool() == true); - - // Execute the loop's content. - if (Code != nullptr) - { - ExpEmit code = Code->Emit(build); - code.Free(build); - } - - // Loop back. - build->Backpatch(build->Emit(OP_JMP, 0), loopstart); - loopend = build->GetAddress(); - - if (!Condition->isConstant()) - { - build->Backpatch(jumpspot, loopend); - } - - // Give a proper address to any break/continue statement within this loop. - for (unsigned int i = 0; i < JumpAddresses.Size(); i++) - { - if (JumpAddresses[i]->Token == TK_Break) - { - build->Backpatch(JumpAddresses[i]->Address, loopend); - } - else - { // Continue statement. - build->Backpatch(JumpAddresses[i]->Address, loopstart); - } - } - - return ExpEmit(); -} - -//========================================================================== -// -// FxDoWhileLoop -// -//========================================================================== - -FxDoWhileLoop::FxDoWhileLoop(FxExpression *condition, FxExpression *code, const FScriptPosition &pos) -: FxExpression(pos), Condition(condition), Code(code) -{ - ValueType = TypeVoid; -} - -FxDoWhileLoop::~FxDoWhileLoop() -{ - SAFE_DELETE(Condition); - SAFE_DELETE(Code); -} - -FxExpression *FxDoWhileLoop::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE(Condition, ctx); - SAFE_RESOLVE_OPT(Code, ctx); - - ctx.HandleJumps(TK_Break, this); - ctx.HandleJumps(TK_Continue, this); - - if (Condition->ValueType != TypeBool) - { - Condition = new FxBoolCast(Condition); - SAFE_RESOLVE(Condition, ctx); - } - - if (Condition->isConstant()) - { - if (static_cast(Condition)->GetValue().GetBool() == false) - { // The code executes once, if any. - if (JumpAddresses.Size() == 0) - { // We would still have to handle the jumps however. - FxExpression *e = Code; - if (e == nullptr) e = new FxNop(ScriptPosition); - Code = nullptr; - delete this; - return e; - } - } - else if (Code == nullptr) - { // "do { } while (true);" - // Someone could be using this for testing. - ScriptPosition.Message(MSG_WARNING, "Infinite empty loop"); - } - } - - return this; -} - -ExpEmit FxDoWhileLoop::Emit(VMFunctionBuilder *build) -{ - assert(Condition->ValueType == TypeBool); - - size_t loopstart, loopend; - size_t codestart; - - // Execute the loop's content. - codestart = build->GetAddress(); - if (Code != nullptr) - { - ExpEmit code = Code->Emit(build); - code.Free(build); - } - - // Evaluate the condition and execute/break out of the loop. - loopstart = build->GetAddress(); - if (!Condition->isConstant()) - { - ExpEmit cond = Condition->Emit(build); - build->Emit(OP_TEST, cond.RegNum, 1); - cond.Free(build); - build->Backpatch(build->Emit(OP_JMP, 0), codestart); - } - else if (static_cast(Condition)->GetValue().GetBool() == true) - { // Always looping - build->Backpatch(build->Emit(OP_JMP, 0), codestart); - } - loopend = build->GetAddress(); - - // Give a proper address to any break/continue statement within this loop. - for (unsigned int i = 0; i < JumpAddresses.Size(); i++) - { - if (JumpAddresses[i]->Token == TK_Break) - { - build->Backpatch(JumpAddresses[i]->Address, loopend); - } - else - { // Continue statement. - build->Backpatch(JumpAddresses[i]->Address, loopstart); - } - } - - return ExpEmit(); -} - -//========================================================================== -// -// FxForLoop -// -//========================================================================== - -FxForLoop::FxForLoop(FxExpression *init, FxExpression *condition, FxExpression *iteration, FxExpression *code, const FScriptPosition &pos) -: FxExpression(pos), Init(init), Condition(condition), Iteration(iteration), Code(code) -{ - ValueType = TypeVoid; -} - -FxForLoop::~FxForLoop() -{ - SAFE_DELETE(Init); - SAFE_DELETE(Condition); - SAFE_DELETE(Iteration); - SAFE_DELETE(Code); -} - -FxExpression *FxForLoop::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE_OPT(Init, ctx); - SAFE_RESOLVE_OPT(Condition, ctx); - SAFE_RESOLVE_OPT(Iteration, ctx); - SAFE_RESOLVE_OPT(Code, ctx); - - ctx.HandleJumps(TK_Break, this); - ctx.HandleJumps(TK_Continue, this); - - if (Condition != nullptr) - { - if (Condition->ValueType != TypeBool) - { - Condition = new FxBoolCast(Condition); - SAFE_RESOLVE(Condition, ctx); - } - - if (Condition->isConstant()) - { - if (static_cast(Condition)->GetValue().GetBool() == false) - { // Nothing happens - FxExpression *nop = new FxNop(ScriptPosition); - delete this; - return nop; - } - else - { // "for (..; true; ..)" - delete Condition; - Condition = nullptr; - } - } - } - if (Condition == nullptr && Code == nullptr) - { // "for (..; ; ..) { }" - // Someone could be using this for testing. - ScriptPosition.Message(MSG_WARNING, "Infinite empty loop"); - } - - return this; -} - -ExpEmit FxForLoop::Emit(VMFunctionBuilder *build) -{ - assert((Condition && Condition->ValueType == TypeBool && !Condition->isConstant()) || Condition == nullptr); - - size_t loopstart, loopend; - size_t codestart; - size_t jumpspot; - - // Init statement. - if (Init != nullptr) - { - ExpEmit init = Init->Emit(build); - init.Free(build); - } - - // Evaluate the condition and execute/break out of the loop. - codestart = build->GetAddress(); - if (Condition != nullptr) - { - ExpEmit cond = Condition->Emit(build); - build->Emit(OP_TEST, cond.RegNum, 0); - cond.Free(build); - jumpspot = build->Emit(OP_JMP, 0); - } - - // Execute the loop's content. - if (Code != nullptr) - { - ExpEmit code = Code->Emit(build); - code.Free(build); - } - - // Iteration statement. - loopstart = build->GetAddress(); - if (Iteration != nullptr) - { - ExpEmit iter = Iteration->Emit(build); - iter.Free(build); - } - build->Backpatch(build->Emit(OP_JMP, 0), codestart); - - // End of loop. - loopend = build->GetAddress(); - if (Condition != nullptr) - { - build->Backpatch(jumpspot, loopend); - } - - // Give a proper address to any break/continue statement within this loop. - for (unsigned int i = 0; i < JumpAddresses.Size(); i++) - { - if (JumpAddresses[i]->Token == TK_Break) - { - build->Backpatch(JumpAddresses[i]->Address, loopend); - } - else - { // Continue statement. - build->Backpatch(JumpAddresses[i]->Address, loopstart); - } - } - - return ExpEmit(); -} - -//========================================================================== -// -// FxJumpStatement -// -//========================================================================== - -FxJumpStatement::FxJumpStatement(int token, const FScriptPosition &pos) -: FxExpression(pos), Token(token), AddressResolver(nullptr) -{ - ValueType = TypeVoid; -} - -FxExpression *FxJumpStatement::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - - ctx.Jumps.Push(this); - - return this; -} - -ExpEmit FxJumpStatement::Emit(VMFunctionBuilder *build) -{ - if (AddressResolver == nullptr) - { - ScriptPosition.Message(MSG_ERROR, "Jump statement %s has nowhere to go!", FScanner::TokenName(Token).GetChars()); - } - - Address = build->Emit(OP_JMP, 0); - - return ExpEmit(); -} - -//========================================================================== -// -//========================================================================== - -FxReturnStatement::FxReturnStatement(FxExpression *value, const FScriptPosition &pos) -: FxExpression(pos), Value(value) -{ - ValueType = TypeVoid; -} - -FxReturnStatement::~FxReturnStatement() -{ - SAFE_DELETE(Value); -} - -FxExpression *FxReturnStatement::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE_OPT(Value, ctx); - - PPrototype *retproto; - if (Value == nullptr) - { - TArray none(0); - retproto = NewPrototype(none, none); - } - else - { - retproto = Value->ReturnProto(); - } - - ctx.CheckReturn(retproto, ScriptPosition); - - return this; -} - -ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build) -{ - ExpEmit out(0, REGT_NIL); - - // If we return nothing, use a regular RET opcode. - // Otherwise just return the value we're given. - if (Value == nullptr) - { - build->Emit(OP_RET, RET_FINAL, REGT_NIL, 0); - } - else - { - out = Value->Emit(build); - - // Check if it is a function call that simplified itself - // into a tail call in which case we don't emit anything. - if (!out.Final) - { - if (Value->ValueType == TypeVoid) - { // Nothing is returned. - build->Emit(OP_RET, RET_FINAL, REGT_NIL, 0); - } - else - { - build->Emit(OP_RET, RET_FINAL, out.RegType | (out.Konst ? REGT_KONST : 0), out.RegNum); - } - } - } - - out.Final = true; - return out; -} - -VMFunction *FxReturnStatement::GetDirectFunction() -{ - if (Value != nullptr) - { - return Value->GetDirectFunction(); - } - return nullptr; -} - -//========================================================================== -// -//========================================================================== - -FxClassTypeCast::FxClassTypeCast(PClass *dtype, FxExpression *x) -: FxExpression(x->ScriptPosition) -{ - desttype = dtype; - basex=x; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxClassTypeCast::~FxClassTypeCast() -{ - SAFE_DELETE(basex); -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE(basex, ctx); - - if (basex->ValueType != TypeName) - { - ScriptPosition.Message(MSG_ERROR, "Cannot convert to class type"); - delete this; - return NULL; - } - - if (basex->isConstant()) - { - FName clsname = static_cast(basex)->GetValue().GetName(); - PClass *cls = NULL; - - if (clsname != NAME_None) - { - cls = PClass::FindClass(clsname); - if (cls == NULL) - { - /* lax */ - // Since this happens in released WADs it must pass without a terminal error... :( - ScriptPosition.Message(MSG_OPTERROR, - "Unknown class name '%s'", - clsname.GetChars(), desttype->TypeName.GetChars()); - } - else - { - if (!cls->IsDescendantOf(desttype)) - { - ScriptPosition.Message(MSG_ERROR, "class '%s' is not compatible with '%s'", clsname.GetChars(), desttype->TypeName.GetChars()); - delete this; - return NULL; - } - ScriptPosition.Message(MSG_DEBUG, "resolving '%s' as class name", clsname.GetChars()); - } - } - FxExpression *x = new FxConstant(cls, ScriptPosition); - delete this; - return x; - } - return this; -} - -//========================================================================== -// -// -// -//========================================================================== - -int DecoNameToClass(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) -{ - assert(numparam == 2); - assert(numret == 1); - assert(param[0].Type == REGT_INT); - assert(param[1].Type == REGT_POINTER); - assert(ret->RegType == REGT_POINTER); - - FName clsname = ENamedName(param[0].i); - const PClass *cls = PClass::FindClass(clsname); - const PClass *desttype = reinterpret_cast(param[0].a); - - if (!cls->IsDescendantOf(desttype)) - { - Printf("class '%s' is not compatible with '%s'", clsname.GetChars(), desttype->TypeName.GetChars()); - cls = NULL; - } - ret->SetPointer(const_cast(cls), ATAG_OBJECT); - return 1; -} - -ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build) -{ - if (basex->ValueType != TypeName) - { - return ExpEmit(build->GetConstantAddress(NULL, ATAG_OBJECT), REGT_POINTER, true); - } - ExpEmit clsname = basex->Emit(build); - assert(!clsname.Konst); - ExpEmit dest(build, REGT_POINTER); - build->Emit(OP_PARAM, 0, clsname.RegType, clsname.RegNum); - build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(const_cast(desttype), ATAG_OBJECT)); - - // Call the DecoNameToClass function to convert from 'name' to class. - VMFunction *callfunc; - PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoNameToClass, DecoNameToClass); - - assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); - assert(((PSymbolVMFunction *)sym)->Function != NULL); - callfunc = ((PSymbolVMFunction *)sym)->Function; - - build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1); - build->Emit(OP_RESULT, 0, REGT_POINTER, dest.RegNum); - clsname.Free(build); - return dest; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - ABORT(ctx.Class); - - if (ctx.Class->NumOwnedStates == 0) - { - // This can't really happen - assert(false); - } - if (ctx.Class->NumOwnedStates <= index) - { - ScriptPosition.Message(MSG_ERROR, "%s: Attempt to jump to non existing state index %d", - ctx.Class->TypeName.GetChars(), index); - delete this; - return NULL; - } - FxExpression *x = new FxConstant(ctx.Class->OwnedStates + index, ScriptPosition); - delete this; - return x; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxRuntimeStateIndex::FxRuntimeStateIndex(FxExpression *index) -: FxExpression(index->ScriptPosition), Index(index) -{ - EmitTail = false; - ValueType = TypeState; -} - -FxRuntimeStateIndex::~FxRuntimeStateIndex() -{ - SAFE_DELETE(Index); -} - -PPrototype *FxRuntimeStateIndex::ReturnProto() -{ - EmitTail = true; - return FxExpression::ReturnProto(); -} - -FxExpression *FxRuntimeStateIndex::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE(Index, ctx); - - if (!Index->IsNumeric()) - { - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); - delete this; - return nullptr; - } - else if (Index->ValueType->GetRegType() != REGT_INT) - { // Float. - Index = new FxIntCast(Index); - SAFE_RESOLVE(Index, ctx); - } - - return this; -} - -static bool VerifyJumpTarget(AActor *stateowner, FStateParamInfo *stateinfo, int index) -{ - PClassActor *cls = stateowner->GetClass(); - - while (cls != RUNTIME_CLASS(AActor)) - { - // both calling and target state need to belong to the same class. - if (cls->OwnsState(stateinfo->mCallingState)) - { - return cls->OwnsState(stateinfo->mCallingState + index); - } - - // We can safely assume the ParentClass is of type PClassActor - // since we stop when we see the Actor base class. - cls = static_cast(cls->ParentClass); - } - return false; -} - -static int DecoHandleRuntimeState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) -{ - PARAM_PROLOGUE; - PARAM_OBJECT(stateowner, AActor); - PARAM_POINTER(stateinfo, FStateParamInfo); - PARAM_INT(index); - - if (index == 0 || !VerifyJumpTarget(stateowner, stateinfo, index)) - { - // Null is returned if the location was invalid which means that no jump will be performed - // if used as return value - // 0 always meant the same thing so we handle it here for compatibility - ACTION_RETURN_STATE(nullptr); - } - else - { - ACTION_RETURN_STATE(stateinfo->mCallingState + index); - } -} - -ExpEmit FxRuntimeStateIndex::Emit(VMFunctionBuilder *build) -{ - assert(build->IsActionFunc && build->Registers[REGT_POINTER].GetMostUsed() >= 3 && - "FxRuntimeStateIndex is only valid inside action functions"); - - ExpEmit out(build, REGT_POINTER); - - build->Emit(OP_PARAM, 0, REGT_POINTER, 1); // stateowner - build->Emit(OP_PARAM, 0, REGT_POINTER, 2); // stateinfo - ExpEmit id = Index->Emit(build); - build->Emit(OP_PARAM, 0, REGT_INT | (id.Konst ? REGT_KONST : 0), id.RegNum); // index - - VMFunction *callfunc; - PSymbol *sym; - - sym = FindDecorateBuiltinFunction(NAME_DecoHandleRuntimeState, DecoHandleRuntimeState); - assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); - assert(((PSymbolVMFunction *)sym)->Function != nullptr); - callfunc = ((PSymbolVMFunction *)sym)->Function; - - if (EmitTail) - { - build->Emit(OP_TAIL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); - out.Final = true; - } - else - { - build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); - build->Emit(OP_RESULT, 0, REGT_POINTER, out.RegNum); - } - - return out; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxMultiNameState::FxMultiNameState(const char *_statestring, const FScriptPosition &pos) - :FxExpression(pos) -{ - FName scopename; - FString statestring = _statestring; - int scopeindex = statestring.IndexOf("::"); - - if (scopeindex >= 0) - { - scopename = FName(statestring, scopeindex, false); - statestring = statestring.Right(statestring.Len() - scopeindex - 2); - } - else - { - scopename = NULL; - } - names = MakeStateNameList(statestring); - names.Insert(0, scopename); - scope = NULL; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - ABORT(ctx.Class); - - if (names[0] == NAME_None) - { - scope = NULL; - } - else if (names[0] == NAME_Super) - { - scope = dyn_cast(ctx.Class->ParentClass); - } - else - { - scope = PClass::FindActor(names[0]); - if (scope == NULL) - { - ScriptPosition.Message(MSG_ERROR, "Unknown class '%s' in state label", names[0].GetChars()); - delete this; - return NULL; - } - else if (!scope->IsDescendantOf(ctx.Class)) - { - ScriptPosition.Message(MSG_ERROR, "'%s' is not an ancestor of '%s'", names[0].GetChars(),ctx.Class->TypeName.GetChars()); - delete this; - return NULL; - } - } - if (scope != NULL) - { - FState *destination = NULL; - // If the label is class specific we can resolve it right here - if (names[1] != NAME_None) - { - destination = scope->FindState(names.Size()-1, &names[1], false); - if (destination == NULL) - { - ScriptPosition.Message(MSG_OPTERROR, "Unknown state jump destination"); - /* lax */ - return this; - } - } - FxExpression *x = new FxConstant(destination, ScriptPosition); - delete this; - return x; - } - names.Delete(0); - names.ShrinkToFit(); - ValueType = TypeState; - return this; -} - -//========================================================================== -// -// -// -//========================================================================== - -static int DoFindState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, FName *names, int numnames) -{ - PARAM_OBJECT_AT(0, self, AActor); - FState *state = self->GetClass()->FindState(numparam - 1, names); - if (state == NULL) - { - const char *dot = ""; - Printf("Jump target '"); - for (int i = 0; i < numparam - 1; i++) - { - Printf("%s%s", dot, names[i].GetChars()); - dot = "."; - } - Printf("' not found in %s\n", self->GetClass()->TypeName.GetChars()); - } - ret->SetPointer(state, ATAG_STATE); - return 1; -} - -// Find a state with any number of dots in its name. -int DecoFindMultiNameState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) -{ - assert(numparam > 1); - assert(numret == 1); - assert(ret->RegType == REGT_POINTER); - - FName *names = (FName *)alloca((numparam - 1) * sizeof(FName)); - for (int i = 1; i < numparam; ++i) - { - PARAM_NAME_AT(i, zaname); - names[i - 1] = zaname; - } - return DoFindState(stack, param, numparam, ret, names, numparam - 1); -} - -// Find a state without any dots in its name. -int DecoFindSingleNameState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) -{ - assert(numparam == 2); - assert(numret == 1); - assert(ret->RegType == REGT_POINTER); - - PARAM_NAME_AT(1, zaname); - return DoFindState(stack, param, numparam, ret, &zaname, 1); -} - -ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build) -{ - ExpEmit dest(build, REGT_POINTER); - if (build->IsActionFunc) - { - build->Emit(OP_PARAM, 0, REGT_POINTER, 1); // pass stateowner - } - else - { - build->Emit(OP_PARAM, 0, REGT_POINTER, 0); // pass self - } - for (unsigned i = 0; i < names.Size(); ++i) - { - build->EmitParamInt(names[i]); - } - - // For one name, use the DecoFindSingleNameState function. For more than - // one name, use the DecoFindMultiNameState function. - VMFunction *callfunc; - PSymbol *sym; - - if (names.Size() == 1) - { - sym = FindDecorateBuiltinFunction(NAME_DecoFindSingleNameState, DecoFindSingleNameState); - } - else - { - sym = FindDecorateBuiltinFunction(NAME_DecoFindMultiNameState, DecoFindMultiNameState); - } - - assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); - assert(((PSymbolVMFunction *)sym)->Function != NULL); - callfunc = ((PSymbolVMFunction *)sym)->Function; - - build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), names.Size() + 1, 1); - build->Emit(OP_RESULT, 0, REGT_POINTER, dest.RegNum); - return dest; -} - -//========================================================================== -// -// -// -//========================================================================== - -FxDamageValue::FxDamageValue(FxExpression *v) -: FxExpression(v->ScriptPosition) -{ - val = v; - ValueType = TypeVoid; - MyFunction = NULL; -} - -FxDamageValue::~FxDamageValue() -{ - SAFE_DELETE(val); - -} - -FxExpression *FxDamageValue::Resolve(FCompileContext &ctx) -{ - CHECKRESOLVED(); - SAFE_RESOLVE(val, ctx) - - if (!val->IsNumeric()) - { - ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); - delete this; - return NULL; - } - return this; -} - -// This is a highly-specialized "expression" type that emits a complete function. -ExpEmit FxDamageValue::Emit(VMFunctionBuilder *build) -{ - if (val->isConstant()) - { - build->EmitRetInt(0, false, static_cast(val)->GetValue().Int); - } - else - { - ExpEmit emitval = val->Emit(build); - assert(emitval.RegType == REGT_INT); - build->Emit(OP_RET, 0, REGT_INT | (emitval.Konst ? REGT_KONST : 0), emitval.RegNum); - } - build->Emit(OP_RETI, 1 | RET_FINAL, true); - - return ExpEmit(); -} diff --git a/src/v_blend.cpp b/src/v_blend.cpp index c13ed547c2..ffc16cd5ce 100644 --- a/src/v_blend.cpp +++ b/src/v_blend.cpp @@ -104,7 +104,7 @@ void V_AddPlayerBlend (player_t *CPlayer, float blend[4], float maxinvalpha, int // [RH] All powerups can affect the screen blending now for (AInventory *item = CPlayer->mo->Inventory; item != NULL; item = item->Inventory) { - PalEntry color = item->GetBlend (); + PalEntry color = item->CallGetBlend (); if (color.a != 0) { V_AddBlend (color.r/255.f, color.g/255.f, color.b/255.f, color.a/255.f, blend); diff --git a/src/v_font.cpp b/src/v_font.cpp index 0eb28a67c3..f024e2d2ba 100644 --- a/src/v_font.cpp +++ b/src/v_font.cpp @@ -2300,19 +2300,19 @@ void V_InitFontColors () else if (sc.Compare ("Flat:")) { sc.MustGetString(); - logcolor = V_GetColor (NULL, sc.String); + logcolor = V_GetColor (NULL, sc); } else { // Get first color - c = V_GetColor (NULL, sc.String); + c = V_GetColor (NULL, sc); tparm.Start[0] = RPART(c); tparm.Start[1] = GPART(c); tparm.Start[2] = BPART(c); // Get second color sc.MustGetString(); - c = V_GetColor (NULL, sc.String); + c = V_GetColor (NULL, sc); tparm.End[0] = RPART(c); tparm.End[1] = GPART(c); tparm.End[2] = BPART(c); diff --git a/src/v_video.cpp b/src/v_video.cpp index 32e1a54d39..efe93aa04a 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -44,6 +44,7 @@ #include "i_video.h" #include "v_video.h" #include "v_text.h" +#include "sc_man.h" #include "w_wad.h" @@ -69,8 +70,8 @@ int active_con_scale(); FRenderer *Renderer; -IMPLEMENT_ABSTRACT_CLASS (DCanvas) -IMPLEMENT_ABSTRACT_CLASS (DFrameBuffer) +IMPLEMENT_CLASS(DCanvas, true, false) +IMPLEMENT_CLASS(DFrameBuffer, true, false) #if defined(_DEBUG) && defined(_M_IX86) && !defined(__MINGW32__) #define DBGBREAK { __asm int 3 } @@ -106,11 +107,11 @@ public: float Gamma; }; -IMPLEMENT_ABSTRACT_CLASS (DDummyFrameBuffer) +IMPLEMENT_CLASS(DDummyFrameBuffer, true, false) // SimpleCanvas is not really abstract, but this macro does not // try to generate a CreateNew() function. -IMPLEMENT_ABSTRACT_CLASS (DSimpleCanvas) +IMPLEMENT_CLASS(DSimpleCanvas, true, false) class FPaletteTester : public FTexture { @@ -437,7 +438,7 @@ void DCanvas::ReleaseScreenshotBuffer() // //========================================================================== -int V_GetColorFromString (const DWORD *palette, const char *cstr) +int V_GetColorFromString (const DWORD *palette, const char *cstr, FScriptPosition *sc) { int c[3], i, p; char val[3]; @@ -456,7 +457,7 @@ int V_GetColorFromString (const DWORD *palette, const char *cstr) { val[0] = cstr[1 + i*2]; val[1] = cstr[2 + i*2]; - c[i] = ParseHex (val); + c[i] = ParseHex (val, sc); } } else if (len == 4) @@ -465,7 +466,7 @@ int V_GetColorFromString (const DWORD *palette, const char *cstr) for (i = 0; i < 3; ++i) { val[1] = val[0] = cstr[1 + i]; - c[i] = ParseHex (val); + c[i] = ParseHex (val, sc); } } else @@ -518,7 +519,7 @@ normal: { val[1] = val[0]; } - c[i] = ParseHex (val); + c[i] = ParseHex (val, sc); } } } @@ -538,7 +539,7 @@ normal: // //========================================================================== -FString V_GetColorStringByName (const char *name) +FString V_GetColorStringByName (const char *name, FScriptPosition *sc) { FMemLump rgbNames; char *rgbEnd; @@ -552,7 +553,8 @@ FString V_GetColorStringByName (const char *name) rgblump = Wads.CheckNumForName ("X11R6RGB"); if (rgblump == -1) { - Printf ("X11R6RGB lump not found\n"); + if (!sc) Printf ("X11R6RGB lump not found\n"); + else sc->Message(MSG_WARNING, "X11R6RGB lump not found"); return FString(); } @@ -614,7 +616,8 @@ FString V_GetColorStringByName (const char *name) } if (rgb < rgbEnd) { - Printf ("X11R6RGB lump is corrupt\n"); + if (!sc) Printf ("X11R6RGB lump is corrupt\n"); + else sc->Message(MSG_WARNING, "X11R6RGB lump is corrupt"); } return FString(); } @@ -627,22 +630,28 @@ FString V_GetColorStringByName (const char *name) // //========================================================================== -int V_GetColor (const DWORD *palette, const char *str) +int V_GetColor (const DWORD *palette, const char *str, FScriptPosition *sc) { - FString string = V_GetColorStringByName (str); + FString string = V_GetColorStringByName (str, sc); int res; if (!string.IsEmpty()) { - res = V_GetColorFromString (palette, string); + res = V_GetColorFromString (palette, string, sc); } else { - res = V_GetColorFromString (palette, str); + res = V_GetColorFromString (palette, str, sc); } return res; } +int V_GetColor(const DWORD *palette, FScanner &sc) +{ + FScriptPosition scc = sc; + return V_GetColor(palette, sc.String, &scc); +} + //========================================================================== // // BuildTransTable diff --git a/src/v_video.h b/src/v_video.h index 890ab6d638..971aa6c13d 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -497,15 +497,17 @@ void V_Shutdown (); void V_MarkRect (int x, int y, int width, int height); +class FScanner; // Returns the closest color to the one desired. String // should be of the form "rr gg bb". -int V_GetColorFromString (const DWORD *palette, const char *colorstring); +int V_GetColorFromString (const DWORD *palette, const char *colorstring, FScriptPosition *sc = nullptr); // Scans through the X11R6RGB lump for a matching color // and returns a color string suitable for V_GetColorFromString. -FString V_GetColorStringByName (const char *name); +FString V_GetColorStringByName (const char *name, FScriptPosition *sc = nullptr); // Tries to get color by name, then by string -int V_GetColor (const DWORD *palette, const char *str); +int V_GetColor (const DWORD *palette, const char *str, FScriptPosition *sc = nullptr); +int V_GetColor(const DWORD *palette, FScanner &sc); void V_DrawFrame (int left, int top, int width, int height); // If the view size is not full screen, draws a border around it. diff --git a/src/virtual.h b/src/virtual.h new file mode 100644 index 0000000000..844c51d381 --- /dev/null +++ b/src/virtual.h @@ -0,0 +1,20 @@ +inline unsigned GetVirtualIndex(PClass *cls, const char *funcname) +{ + // Look up the virtual function index in the defining class because this may have gotten overloaded in subclasses with something different than a virtual override. + auto sym = dyn_cast(cls->Symbols.FindSymbol(funcname, false)); + assert(sym != nullptr); + auto VIndex = sym->Variants[0].Implementation->VirtualIndex; + return VIndex; +} + +#define IFVIRTUALPTR(self, cls, funcname) \ + static unsigned VIndex = ~0u; \ + if (VIndex == ~0u) { \ + VIndex = GetVirtualIndex(RUNTIME_CLASS(cls), #funcname); \ + assert(VIndex != ~0u); \ + } \ + auto clss = self->GetClass(); \ + VMFunction *func = clss->Virtuals.Size() > VIndex? clss->Virtuals[VIndex] : nullptr; \ + if (func != nullptr) + +#define IFVIRTUAL(cls, funcname) IFVIRTUALPTR(this, cls, funcname) diff --git a/src/w_wad.cpp b/src/w_wad.cpp index da369144a4..41833fc245 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -501,6 +501,15 @@ int FWadCollection::CheckNumForName (const char *name, int space, int wadnum, bo return i != NULL_INDEX ? i : -1; } +DEFINE_ACTION_FUNCTION(_Wads, CheckNumForName) +{ + PARAM_PROLOGUE; + PARAM_STRING(name); + PARAM_INT(ns); + PARAM_INT_DEF(wadnum); + PARAM_BOOL_DEF(exact); + ACTION_RETURN_INT(Wads.CheckNumForName(name, ns, wadnum, exact)); +} //========================================================================== // // W_GetNumForName diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index 108edff3b6..12ca10e320 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -51,6 +51,7 @@ #include "r_data/r_translate.h" #include "templates.h" #include "gstrings.h" +#include "cmdlib.h" // States for the intermission typedef enum diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 10ab11c729..0e8dd3dec9 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -91,7 +91,7 @@ // TYPES ------------------------------------------------------------------- -IMPLEMENT_CLASS(D3DFB) +IMPLEMENT_CLASS(D3DFB, false, false) struct D3DFB::PackedTexture { diff --git a/src/win32/fb_ddraw.cpp b/src/win32/fb_ddraw.cpp index 7cc6037865..85f0c47685 100644 --- a/src/win32/fb_ddraw.cpp +++ b/src/win32/fb_ddraw.cpp @@ -61,7 +61,7 @@ // TYPES ------------------------------------------------------------------- -IMPLEMENT_CLASS(DDrawFB) +IMPLEMENT_CLASS(DDrawFB, false, false) // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- diff --git a/src/win32/win32gliface.cpp b/src/win32/win32gliface.cpp index 5d68d84278..aa4755e483 100644 --- a/src/win32/win32gliface.cpp +++ b/src/win32/win32gliface.cpp @@ -854,7 +854,7 @@ bool Win32GLVideo::SetFullscreen(const char *devicename, int w, int h, int bits, // //========================================================================== -IMPLEMENT_ABSTRACT_CLASS(Win32GLFrameBuffer) +IMPLEMENT_CLASS(Win32GLFrameBuffer, true, false) //========================================================================== // diff --git a/src/win32/win32video.cpp b/src/win32/win32video.cpp index 18c66f5d31..0d91ed1d04 100644 --- a/src/win32/win32video.cpp +++ b/src/win32/win32video.cpp @@ -80,7 +80,7 @@ // TYPES ------------------------------------------------------------------- -IMPLEMENT_ABSTRACT_CLASS(BaseWinFB) +IMPLEMENT_CLASS(BaseWinFB, true, false) typedef IDirect3D9 *(WINAPI *DIRECT3DCREATE9FUNC)(UINT SDKVersion); typedef HRESULT (WINAPI *DIRECTDRAWCREATEFUNC)(GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter); diff --git a/src/zscript/vmbuilder.cpp b/src/zscript/vmbuilder.cpp deleted file mode 100644 index 8d7b5a8c12..0000000000 --- a/src/zscript/vmbuilder.cpp +++ /dev/null @@ -1,603 +0,0 @@ -#include "vmbuilder.h" - -//========================================================================== -// -// VMFunctionBuilder - Constructor -// -//========================================================================== - -VMFunctionBuilder::VMFunctionBuilder(bool selfcheck) -{ - NumIntConstants = 0; - NumFloatConstants = 0; - NumAddressConstants = 0; - NumStringConstants = 0; - MaxParam = 0; - ActiveParam = 0; - IsActionFunc = selfcheck; -} - -//========================================================================== -// -// VMFunctionBuilder - Destructor -// -//========================================================================== - -VMFunctionBuilder::~VMFunctionBuilder() -{ -} - -//========================================================================== -// -// VMFunctionBuilder :: MakeFunction -// -// Creates a new VMScriptFunction out of the data passed to this class. -// -//========================================================================== - -VMScriptFunction *VMFunctionBuilder::MakeFunction() -{ - VMScriptFunction *func = new VMScriptFunction; - - func->Alloc(Code.Size(), NumIntConstants, NumFloatConstants, NumStringConstants, NumAddressConstants); - - // Copy code block. - memcpy(func->Code, &Code[0], Code.Size() * sizeof(VMOP)); - - // Create constant tables. - if (NumIntConstants > 0) - { - FillIntConstants(func->KonstD); - } - if (NumFloatConstants > 0) - { - FillFloatConstants(func->KonstF); - } - if (NumAddressConstants > 0) - { - FillAddressConstants(func->KonstA, func->KonstATags()); - } - if (NumStringConstants > 0) - { - FillStringConstants(func->KonstS); - } - - // Assign required register space. - func->NumRegD = Registers[REGT_INT].MostUsed; - func->NumRegF = Registers[REGT_FLOAT].MostUsed; - func->NumRegA = Registers[REGT_POINTER].MostUsed; - func->NumRegS = Registers[REGT_STRING].MostUsed; - func->MaxParam = MaxParam; - - // Technically, there's no reason why we can't end the function with - // entries on the parameter stack, but it means the caller probably - // did something wrong. - assert(ActiveParam == 0); - - return func; -} - -//========================================================================== -// -// VMFunctionBuilder :: FillIntConstants -// -//========================================================================== - -void VMFunctionBuilder::FillIntConstants(int *konst) -{ - TMapIterator it(IntConstants); - TMap::Pair *pair; - - while (it.NextPair(pair)) - { - konst[pair->Value] = pair->Key; - } -} - -//========================================================================== -// -// VMFunctionBuilder :: FillFloatConstants -// -//========================================================================== - -void VMFunctionBuilder::FillFloatConstants(double *konst) -{ - TMapIterator it(FloatConstants); - TMap::Pair *pair; - - while (it.NextPair(pair)) - { - konst[pair->Value] = pair->Key; - } -} - -//========================================================================== -// -// VMFunctionBuilder :: FillAddressConstants -// -//========================================================================== - -void VMFunctionBuilder::FillAddressConstants(FVoidObj *konst, VM_ATAG *tags) -{ - TMapIterator it(AddressConstants); - TMap::Pair *pair; - - while (it.NextPair(pair)) - { - konst[pair->Value.KonstNum].v = pair->Key; - tags[pair->Value.KonstNum] = pair->Value.Tag; - } -} - -//========================================================================== -// -// VMFunctionBuilder :: FillStringConstants -// -//========================================================================== - -void VMFunctionBuilder::FillStringConstants(FString *konst) -{ - TMapIterator it(StringConstants); - TMap::Pair *pair; - - while (it.NextPair(pair)) - { - konst[pair->Value] = pair->Key; - } -} - -//========================================================================== -// -// VMFunctionBuilder :: GetConstantInt -// -// Returns a constant register initialized with the given value, or -1 if -// there were no more constants free. -// -//========================================================================== - -int VMFunctionBuilder::GetConstantInt(int val) -{ - int *locp = IntConstants.CheckKey(val); - if (locp != NULL) - { - return *locp; - } - else - { - int loc = NumIntConstants++; - IntConstants.Insert(val, loc); - return loc; - } -} - -//========================================================================== -// -// VMFunctionBuilder :: GetConstantFloat -// -// Returns a constant register initialized with the given value, or -1 if -// there were no more constants free. -// -//========================================================================== - -int VMFunctionBuilder::GetConstantFloat(double val) -{ - int *locp = FloatConstants.CheckKey(val); - if (locp != NULL) - { - return *locp; - } - else - { - int loc = NumFloatConstants++; - FloatConstants.Insert(val, loc); - return loc; - } -} - -//========================================================================== -// -// VMFunctionBuilder :: GetConstantString -// -// Returns a constant register initialized with the given value, or -1 if -// there were no more constants free. -// -//========================================================================== - -int VMFunctionBuilder::GetConstantString(FString val) -{ - int *locp = StringConstants.CheckKey(val); - if (locp != NULL) - { - return *locp; - } - else - { - int loc = NumStringConstants++; - StringConstants.Insert(val, loc); - return loc; - } -} - -//========================================================================== -// -// VMFunctionBuilder :: GetConstantAddress -// -// Returns a constant register initialized with the given value, or -1 if -// there were no more constants free. -// -//========================================================================== - -int VMFunctionBuilder::GetConstantAddress(void *ptr, VM_ATAG tag) -{ - if (ptr == NULL) - { // Make all NULL pointers generic. (Or should we allow typed NULLs?) - tag = ATAG_GENERIC; - } - AddrKonst *locp = AddressConstants.CheckKey(ptr); - if (locp != NULL) - { - // There should only be one tag associated with a memory location. - assert(locp->Tag == tag); - return locp->KonstNum; - } - else - { - AddrKonst loc = { NumAddressConstants++, tag }; - AddressConstants.Insert(ptr, loc); - return loc.KonstNum; - } -} - -//========================================================================== -// -// VMFunctionBuilder :: ParamChange -// -// Adds delta to ActiveParam and keeps track of MaxParam. -// -//========================================================================== - -void VMFunctionBuilder::ParamChange(int delta) -{ - assert(delta > 0 || -delta <= ActiveParam); - ActiveParam += delta; - if (ActiveParam > MaxParam) - { - MaxParam = ActiveParam; - } -} - -//========================================================================== -// -// VMFunctionBuilder :: RegAvailability - Constructor -// -//========================================================================== - -VMFunctionBuilder::RegAvailability::RegAvailability() -{ - memset(Used, 0, sizeof(Used)); - MostUsed = 0; -} - -//========================================================================== -// -// VMFunctionBuilder :: RegAvailability :: Get -// -// Gets one or more unused registers. If getting multiple registers, they -// will all be consecutive. Returns -1 if there were not enough consecutive -// registers to satisfy the request. -// -// Preference is given to low-numbered registers in an attempt to keep -// the maximum register count low so as to preserve VM stack space when this -// function is executed. -// -//========================================================================== - -int VMFunctionBuilder::RegAvailability::Get(int count) -{ - VM_UWORD mask; - int i, firstbit; - - // Getting fewer than one register makes no sense, and - // the algorithm used here can only obtain ranges of up to 32 bits. - if (count < 1 || count > 32) - { - return -1; - } - - mask = count == 32 ? ~0u : (1 << count) - 1; - - for (i = 0; i < 256/32; ++i) - { - // Find the first word with free registers - VM_UWORD bits = Used[i]; - if (bits != ~0u) - { - // Are there enough consecutive bits to satisfy the request? - // Search by 16, then 8, then 1 bit at a time for the first - // free register. - if ((bits & 0xFFFF) == 0xFFFF) - { - firstbit = ((bits & 0xFF0000) == 0xFF0000) ? 24 : 16; - } - else - { - firstbit = ((bits & 0xFF) == 0xFF) ? 8 : 0; - } - for (; firstbit < 32; ++firstbit) - { - if (((bits >> firstbit) & mask) == 0) - { - if (firstbit + count <= 32) - { // Needed bits all fit in one word, so we got it. - if (firstbit + count > MostUsed) - { - MostUsed = firstbit + count; - } - Used[i] |= mask << firstbit; - return i * 32 + firstbit; - } - // Needed bits span two words, so check the next word. - else if (i < 256/32 - 1) - { // There is a next word. - if (((Used[i + 1]) & (mask >> (32 - firstbit))) == 0) - { // The next word has the needed open space, too. - if (firstbit + count > MostUsed) - { - MostUsed = firstbit + count; - } - Used[i] |= mask << firstbit; - Used[i + 1] |= mask >> (32 - firstbit); - return i * 32 + firstbit; - } - else - { // Skip to the next word, because we know we won't find - // what we need if we stay inside this one. All bits - // from firstbit to the end of the word are 0. If the - // next word does not start with the x amount of 0's, we - // need to satisfy the request, then it certainly won't - // have the x+1 0's we would need if we started at - // firstbit+1 in this one. - firstbit = 32; - } - } - else - { // Out of words. - break; - } - } - } - } - } - // No room! - return -1; -} - -//========================================================================== -// -// VMFunctionBuilder :: RegAvailibity :: Return -// -// Marks a range of registers as free again. -// -//========================================================================== - -void VMFunctionBuilder::RegAvailability::Return(int reg, int count) -{ - assert(count >= 1 && count <= 32); - assert(reg >= 0 && reg + count <= 256); - - VM_UWORD mask, partialmask; - int firstword, firstbit; - - mask = count == 32 ? ~0u : (1 << count) - 1; - firstword = reg / 32; - firstbit = reg & 31; - - if (firstbit + count <= 32) - { // Range is all in one word. - mask <<= firstbit; - // If we are trying to return registers that are already free, - // it probably means that the caller messed up somewhere. - assert((Used[firstword] & mask) == mask); - Used[firstword] &= ~mask; - } - else - { // Range is in two words. - partialmask = mask << firstbit; - assert((Used[firstword] & partialmask) == partialmask); - Used[firstword] &= ~partialmask; - - partialmask = mask >> (32 - firstbit); - assert((Used[firstword + 1] & partialmask) == partialmask); - Used[firstword + 1] &= ~partialmask; - } -} - -//========================================================================== -// -// VMFunctionBuilder :: RegAvailability :: Reuse -// -// Marks an unused register as in-use. Returns false if the register is -// already in use or true if it was successfully reused. -// -//========================================================================== - -bool VMFunctionBuilder::RegAvailability::Reuse(int reg) -{ - assert(reg >= 0 && reg <= 255); - assert(reg < MostUsed && "Attempt to reuse a register that was never used"); - - VM_UWORD mask = 1 << (reg & 31); - int word = reg / 32; - - if (Used[word] & mask) - { // It's already in use! - return false; - } - Used[word] |= mask; - return true; -} - -//========================================================================== -// -// VMFunctionBuilder :: GetAddress -// -//========================================================================== - -size_t VMFunctionBuilder::GetAddress() -{ - return Code.Size(); -} - -//========================================================================== -// -// VMFunctionBuilder :: Emit -// -// Just dumbly output an instruction. Returns instruction position, not -// byte position. (Because all instructions are exactly four bytes long.) -// -//========================================================================== - -size_t VMFunctionBuilder::Emit(int opcode, int opa, int opb, int opc) -{ - assert(opcode >= 0 && opcode < NUM_OPS); - assert(opa >= 0 && opa <= 255); - assert(opb >= 0 && opb <= 255); - assert(opc >= 0 && opc <= 255); - if (opcode == OP_PARAM) - { - ParamChange(1); - } - else if (opcode == OP_CALL || opcode == OP_CALL_K || opcode == OP_TAIL || opcode == OP_TAIL_K) - { - ParamChange(-opb); - } - VMOP op; - op.op = opcode; - op.a = opa; - op.b = opb; - op.c = opc; - return Code.Push(op); -} - -size_t VMFunctionBuilder::Emit(int opcode, int opa, VM_SHALF opbc) -{ - assert(opcode >= 0 && opcode < NUM_OPS); - assert(opa >= 0 && opa <= 255); - //assert(opbc >= -32768 && opbc <= 32767); always true due to parameter's width - VMOP op; - op.op = opcode; - op.a = opa; - op.i16 = opbc; - return Code.Push(op); -} - -size_t VMFunctionBuilder::Emit(int opcode, int opabc) -{ - assert(opcode >= 0 && opcode < NUM_OPS); - assert(opabc >= -(1 << 23) && opabc <= (1 << 24) - 1); - if (opcode == OP_PARAMI) - { - ParamChange(1); - } - VMOP op; - op.op = opcode; - op.i24 = opabc; - return Code.Push(op); -} - -//========================================================================== -// -// VMFunctionBuilder :: EmitParamInt -// -// Passes a constant integer parameter, using either PARAMI and an immediate -// value or PARAM and a constant register, as appropriate. -// -//========================================================================== - -size_t VMFunctionBuilder::EmitParamInt(int value) -{ - // Immediates for PARAMI must fit in 24 bits. - if (((value << 8) >> 8) == value) - { - return Emit(OP_PARAMI, value); - } - else - { - return Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, GetConstantInt(value)); - } -} - -//========================================================================== -// -// VMFunctionBuilder :: EmitLoadInt -// -// Loads an integer constant into a register, using either an immediate -// value or a constant register, as appropriate. -// -//========================================================================== - -size_t VMFunctionBuilder::EmitLoadInt(int regnum, int value) -{ - assert(regnum >= 0 && regnum < Registers[REGT_INT].MostUsed); - if (value >= -32768 && value <= 32767) - { - return Emit(OP_LI, regnum, value); - } - else - { - return Emit(OP_LK, regnum, GetConstantInt(value)); - } -} - -//========================================================================== -// -// VMFunctionBuilder :: EmitRetInt -// -// Returns an integer, using either an immediate value or a constant -// register, as appropriate. -// -//========================================================================== - -size_t VMFunctionBuilder::EmitRetInt(int retnum, bool final, int value) -{ - assert(retnum >= 0 && retnum <= 127); - if (value >= -32768 && value <= 32767) - { - return Emit(OP_RETI, retnum | (final << 7), value); - } - else - { - return Emit(OP_RET, retnum | (final << 7), REGT_INT | REGT_KONST, GetConstantInt(value)); - } -} - -//========================================================================== -// -// VMFunctionBuilder :: Backpatch -// -// Store a JMP instruction at that points at . -// -//========================================================================== - -void VMFunctionBuilder::Backpatch(size_t loc, size_t target) -{ - assert(loc < Code.Size()); - int offset = int(target - loc - 1); - assert(((offset << 8) >> 8) == offset); - Code[loc].op = OP_JMP; - Code[loc].i24 = offset; -} - -//========================================================================== -// -// VMFunctionBuilder :: BackpatchToHere -// -// Store a JMP instruction at that points to the current code gen -// location. -// -//========================================================================== - -void VMFunctionBuilder::BackpatchToHere(size_t loc) -{ - Backpatch(loc, Code.Size()); -} diff --git a/src/zscript/vmbuilder.h b/src/zscript/vmbuilder.h deleted file mode 100644 index ed2516c2ae..0000000000 --- a/src/zscript/vmbuilder.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef VMUTIL_H -#define VMUTIL_H - -#include "vm.h" - -class VMFunctionBuilder -{ -public: - // Keeps track of which registers are available by way of a bitmask table. - class RegAvailability - { - public: - RegAvailability(); - int GetMostUsed() { return MostUsed; } - int Get(int count); // Returns the first register in the range - void Return(int reg, int count); - bool Reuse(int regnum); - - private: - VM_UWORD Used[256/32]; // Bitmap of used registers (bit set means reg is used) - int MostUsed; - - friend class VMFunctionBuilder; - }; - - VMFunctionBuilder(bool checkself = false); - ~VMFunctionBuilder(); - - VMScriptFunction *MakeFunction(); - - // Returns the constant register holding the value. - int GetConstantInt(int val); - int GetConstantFloat(double val); - int GetConstantAddress(void *ptr, VM_ATAG tag); - int GetConstantString(FString str); - - // Returns the address of the next instruction to be emitted. - size_t GetAddress(); - - // Returns the address of the newly-emitted instruction. - size_t Emit(int opcode, int opa, int opb, int opc); - size_t Emit(int opcode, int opa, VM_SHALF opbc); - size_t Emit(int opcode, int opabc); - size_t EmitParamInt(int value); - size_t EmitLoadInt(int regnum, int value); - size_t EmitRetInt(int retnum, bool final, int value); - - void Backpatch(size_t addr, size_t target); - void BackpatchToHere(size_t addr); - - // Write out complete constant tables. - void FillIntConstants(int *konst); - void FillFloatConstants(double *konst); - void FillAddressConstants(FVoidObj *konst, VM_ATAG *tags); - void FillStringConstants(FString *strings); - - // PARAM increases ActiveParam; CALL decreases it. - void ParamChange(int delta); - - // Track available registers. - RegAvailability Registers[4]; - - // For use by DECORATE's self/stateowner sanitizer. - bool IsActionFunc; - -private: - struct AddrKonst - { - int KonstNum; - VM_ATAG Tag; - }; - // These map from the constant value to its position in the constant table. - TMap IntConstants; - TMap FloatConstants; - TMap AddressConstants; - TMap StringConstants; - - int NumIntConstants; - int NumFloatConstants; - int NumAddressConstants; - int NumStringConstants; - - int MaxParam; - int ActiveParam; - - TArray Code; - -}; - -#endif diff --git a/src/zscript/vmops.h b/src/zscript/vmops.h deleted file mode 100644 index 39d224f5c9..0000000000 --- a/src/zscript/vmops.h +++ /dev/null @@ -1,215 +0,0 @@ -#ifndef xx -#define xx(op, name, mode) OP_##op -#endif - -xx(NOP, nop, NOP), // no operation - -// Load constants. -xx(LI, li, LI), // load immediate signed 16-bit constant -xx(LK, lk, LKI), // load integer constant -xx(LKF, lk, LKF), // load float constant -xx(LKS, lk, LKS), // load string constant -xx(LKP, lk, LKP), // load pointer constant -xx(LFP, lf, LFP), // load frame pointer - -// Load from memory. rA = *(rB + rkC) -xx(LB, lb, RIRPKI), // load byte -xx(LB_R, lb, RIRPRI), -xx(LH, lh, RIRPKI), // load halfword -xx(LH_R, lh, RIRPRI), -xx(LW, lw, RIRPKI), // load word -xx(LW_R, lw, RIRPRI), -xx(LBU, lbu, RIRPKI), // load byte unsigned -xx(LBU_R, lbu, RIRPRI), -xx(LHU, lhu, RIRPKI), // load halfword unsigned -xx(LHU_R, lhu, RIRPRI), -xx(LSP, lsp, RFRPKI), // load single-precision fp -xx(LSP_R, lsp, RFRPRI), -xx(LDP, ldp, RFRPKI), // load double-precision fp -xx(LDP_R, ldp, RFRPRI), -xx(LS, ls, RSRPKI), // load string -xx(LS_R, ls, RSRPRI), -xx(LO, lo, RPRPKI), // load object -xx(LO_R, lo, RPRPRI), -xx(LP, lp, RPRPKI), // load pointer -xx(LP_R, lp, RPRPRI), -xx(LV, lv, RVRPKI), // load vector -xx(LV_R, lv, RVRPRI), - -xx(LBIT, lbit, RIRPI8), // rA = !!(*rB & C) -- *rB is a byte - -// Store instructions. *(rA + rkC) = rB -xx(SB, sb, RPRIKI), // store byte -xx(SB_R, sb, RPRIRI), -xx(SH, sh, RPRIKI), // store halfword -xx(SH_R, sh, RPRIRI), -xx(SW, sw, RPRIKI), // store word -xx(SW_R, sw, RPRIRI), -xx(SSP, ssp, RPRFKI), // store single-precision fp -xx(SSP_R, ssp, RPRFRI), -xx(SDP, sdp, RPRFKI), // store double-precision fp -xx(SDP_R, sdp, RPRFRI), -xx(SS, ss, RPRSKI), // store string -xx(SS_R, ss, RPRSRI), -xx(SP, sp, RPRPKI), // store pointer -xx(SP_R, sp, RPRPRI), -xx(SV, sv, RPRVKI), // store vector -xx(SV_R, sv, RPRVRI), - -xx(SBIT, sbit, RPRII8), // *rA |= C if rB is true, *rA &= ~C otherwise - -// Move instructions. -xx(MOVE, mov, RIRI), // dA = dB -xx(MOVEF, mov, RFRF), // fA = fB -xx(MOVES, mov, RSRS), // sA = sB -xx(MOVEA, mov, RPRP), // aA = aB -xx(CAST, cast, CAST), // xA = xB, conversion specified by C -xx(DYNCAST_R, dyncast,RPRPRP), // aA = aB after casting to rkC (specifying a class) -xx(DYNCAST_K, dyncast,RPRPKP), - -// Control flow. -xx(TEST, test, RII16), // if (dA != BC) then pc++ -xx(JMP, jmp, I24), // pc += ABC -- The ABC fields contain a signed 24-bit offset. -xx(IJMP, ijmp, RII16), // pc += dA + BC -- BC is a signed offset. The target instruction must be a JMP. -xx(PARAM, param, __BCP), // push parameter encoded in BC for function call (B=regtype, C=regnum) -xx(PARAMI, parami, I24), // push immediate, signed integer for function call -xx(CALL, call, RPI8I8), // Call function pkA with parameter count B and expected result count C -xx(CALL_K, call, KPI8I8), -xx(TAIL, tail, RPI8), // Call+Ret in a single instruction -xx(TAIL_K, tail, KPI8), -xx(RESULT, result, __BCP), // Result should go in register encoded in BC (in caller, after CALL) -xx(RET, ret, I8BCP), // Copy value from register encoded in BC to return value A, possibly returning -xx(RETI, reti, I8I16), // Copy immediate from BC to return value A, possibly returning -xx(TRY, try, I24), // When an exception is thrown, start searching for a handler at pc + ABC -xx(UNTRY, untry, I8), // Pop A entries off the exception stack -xx(THROW, throw, THROW), // A == 0: Throw exception object pB - // A == 1: Throw exception object pkB - // A >= 2: Throw VM exception of type BC -xx(CATCH, catch, CATCH), // A == 0: continue search on next try - // A == 1: continue execution at instruction immediately following CATCH (catches any exception) - // A == 2: (pB == ) then pc++ ; next instruction must JMP to another CATCH - // A == 3: (pkB == ) then pc++ ; next instruction must JMP to another CATCH - // for A > 0, exception is stored in pC -xx(BOUND, bound, RII16), // if rA >= BC, throw exception - -// String instructions. -xx(CONCAT, concat, RSRSRS), // sA = sB.. ... ..sC -xx(LENS, lens, RIRS), // dA = sB.Length -xx(CMPS, cmps, I8RXRX), // if ((skB op skC) != (A & 1)) then pc++ - -// Integer math. -xx(SLL_RR, sll, RIRIRI), // dA = dkB << diC -xx(SLL_RI, sll, RIRII8), -xx(SLL_KR, sll, RIKIRI), -xx(SRL_RR, srl, RIRIRI), // dA = dkB >> diC -- unsigned -xx(SRL_RI, srl, RIRII8), -xx(SRL_KR, srl, RIKIRI), -xx(SRA_RR, sra, RIRIRI), // dA = dkB >> diC -- signed -xx(SRA_RI, sra, RIRII8), -xx(SRA_KR, sra, RIKIRI), -xx(ADD_RR, add, RIRIRI), // dA = dB + dkC -xx(ADD_RK, add, RIRIKI), -xx(ADDI, addi, RIRIIs), // dA = dB + C -- C is a signed 8-bit constant -xx(SUB_RR, sub, RIRIRI), // dA = dkB - dkC -xx(SUB_RK, sub, RIRIKI), -xx(SUB_KR, sub, RIKIRI), -xx(MUL_RR, mul, RIRIRI), // dA = dB * dkC -xx(MUL_RK, mul, RIRIKI), -xx(DIV_RR, div, RIRIRI), // dA = dkB / dkC -xx(DIV_RK, div, RIRIKI), -xx(DIV_KR, div, RIKIRI), -xx(MOD_RR, mod, RIRIRI), // dA = dkB % dkC -xx(MOD_RK, mod, RIRIKI), -xx(MOD_KR, mod, RIKIRI), -xx(AND_RR, and, RIRIRI), // dA = dB & dkC -xx(AND_RK, and, RIRIKI), -xx(OR_RR, or, RIRIRI), // dA = dB | dkC -xx(OR_RK, or, RIRIKI), -xx(XOR_RR, xor, RIRIRI), // dA = dB ^ dkC -xx(XOR_RK, xor, RIRIKI), -xx(MIN_RR, min, RIRIRI), // dA = min(dB,dkC) -xx(MIN_RK, min, RIRIKI), -xx(MAX_RR, max, RIRIRI), // dA = max(dB,dkC) -xx(MAX_RK, max, RIRIKI), -xx(ABS, abs, RIRI), // dA = abs(dB) -xx(NEG, neg, RIRI), // dA = -dB -xx(NOT, not, RIRI), // dA = ~dB -xx(SEXT, sext, RIRII8), // dA = dB, sign extended by shifting left then right by C -xx(ZAP_R, zap, RIRIRI), // dA = dB, with bytes zeroed where bits in C/dC are one -xx(ZAP_I, zap, RIRII8), -xx(ZAPNOT_R, zapnot, RIRIRI), // dA = dB, with bytes zeroed where bits in C/dC are zero -xx(ZAPNOT_I, zapnot, RIRII8), -xx(EQ_R, beq, CIRR), // if ((dB == dkC) != A) then pc++ -xx(EQ_K, beq, CIRK), -xx(LT_RR, blt, CIRR), // if ((dkB < dkC) != A) then pc++ -xx(LT_RK, blt, CIRK), -xx(LT_KR, blt, CIKR), -xx(LE_RR, ble, CIRR), // if ((dkB <= dkC) != A) then pc++ -xx(LE_RK, ble, CIRK), -xx(LE_KR, ble, CIKR), -xx(LTU_RR, bltu, CIRR), // if ((dkB < dkC) != A) then pc++ -- unsigned -xx(LTU_RK, bltu, CIRK), -xx(LTU_KR, bltu, CIKR), -xx(LEU_RR, bleu, CIRR), // if ((dkB <= dkC) != A) then pc++ -- unsigned -xx(LEU_RK, bleu, CIRK), -xx(LEU_KR, bleu, CIKR), - -// Double-precision floating point math. -xx(ADDF_RR, add, RFRFRF), // fA = fB + fkC -xx(ADDF_RK, add, RFRFKF), -xx(SUBF_RR, sub, RFRFRF), // fA = fkB - fkC -xx(SUBF_RK, sub, RFRFKF), -xx(SUBF_KR, sub, RFKFRF), -xx(MULF_RR, mul, RFRFRF), // fA = fB * fkC -xx(MULF_RK, mul, RFRFKF), -xx(DIVF_RR, div, RFRFRF), // fA = fkB / fkC -xx(DIVF_RK, div, RFRFKF), -xx(DIVF_KR, div, RFKFRF), -xx(MODF_RR, mod, RFRFRF), // fA = fkB % fkC -xx(MODF_RK, mod, RFRFKF), -xx(MODF_KR, mod, RFKFRF), -xx(POWF_RR, pow, RFRFRF), // fA = fkB ** fkC -xx(POWF_RK, pow, RFRFKF), -xx(POWF_KR, pow, RFKFRF), -xx(MINF_RR, min, RFRFRF), // fA = min(fB),fkC) -xx(MINF_RK, min, RFRFKF), -xx(MAXF_RR, max, RFRFRF), // fA = max(fB),fkC) -xx(MAXF_RK, max, RFRFKF), -xx(ATAN2, atan2, RFRFRF), // fA = atan2(fB,fC), result is in degrees -xx(FLOP, flop, RFRFI8), // fA = f(fB), where function is selected by C -xx(EQF_R, beq, CFRR), // if ((fB == fkC) != (A & 1)) then pc++ -xx(EQF_K, beq, CFRK), -xx(LTF_RR, blt, CFRR), // if ((fkB < fkC) != (A & 1)) then pc++ -xx(LTF_RK, blt, CFRK), -xx(LTF_KR, blt, CFKR), -xx(LEF_RR, ble, CFRR), // if ((fkb <= fkC) != (A & 1)) then pc++ -xx(LEF_RK, ble, CFRK), -xx(LEF_KR, ble, CFKR), - -// Vector math. -xx(NEGV, negv, RVRV), // vA = -vB -xx(ADDV_RR, addv, RVRVRV), // vA = vB + vkC -xx(ADDV_RK, addv, RVRVKV), -xx(SUBV_RR, subv, RVRVRV), // vA = vkB - vkC -xx(SUBV_RK, subv, RVRVKV), -xx(SUBV_KR, subv, RVKVRV), -xx(DOTV_RR, dotv, RVRVRV), // va = vB dot vkC -xx(DOTV_RK, dotv, RVRVKV), -xx(CROSSV_RR, crossv, RVRVRV), // vA = vkB cross vkC -xx(CROSSV_RK, crossv, RVRVKV), -xx(CROSSV_KR, crossv, RVKVRV), -xx(MULVF_RR, mulv, RVRVRV), // vA = vkB * fkC -xx(MULVF_RK, mulv, RVRVKV), -xx(MULVF_KR, mulv, RVKVRV), -xx(LENV, lenv, RFRV), // fA = vB.Length -xx(EQV_R, beqv, CVRR), // if ((vB == vkC) != A) then pc++ (inexact if A & 32) -xx(EQV_K, beqv, CVRK), - -// Pointer math. -xx(ADDA_RR, add, RPRPRI), // pA = pB + dkC -xx(ADDA_RK, add, RPRPKI), -xx(SUBA, sub, RIRPRP), // dA = pB - pC -xx(EQA_R, beq, CPRR), // if ((pB == pkC) != A) then pc++ -xx(EQA_K, beq, CPRK), - -#undef xx diff --git a/src/zscript/zcc_compile.cpp b/src/zscript/zcc_compile.cpp deleted file mode 100644 index b7bfe81ba1..0000000000 --- a/src/zscript/zcc_compile.cpp +++ /dev/null @@ -1,642 +0,0 @@ -#include "dobject.h" -#include "sc_man.h" -#include "c_console.h" -#include "c_dispatch.h" -#include "w_wad.h" -#include "cmdlib.h" -#include "m_alloc.h" -#include "zcc_parser.h" -#include "zcc_compile.h" -#include "v_text.h" -#include "gdtoa.h" - -#define DEFINING_CONST ((PSymbolConst *)(void *)1) - -//========================================================================== -// -// ZCCCompiler Constructor -// -//========================================================================== - -ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols) -: Outer(_outer), Symbols(&_symbols), AST(ast), ErrorCount(0), WarnCount(0) -{ - // Group top-level nodes by type - if (ast.TopNode != NULL) - { - ZCC_TreeNode *node = ast.TopNode; - do - { - switch (node->NodeType) - { - case AST_Class: - case AST_Struct: - case AST_ConstantDef: - if (AddNamedNode(static_cast(node))) - { - switch (node->NodeType) - { - case AST_Class: Classes.Push(static_cast(node)); break; - case AST_Struct: Structs.Push(static_cast(node)); break; - case AST_ConstantDef: Constants.Push(static_cast(node)); break; - default: assert(0 && "Default case is just here to make GCC happy. It should never be reached"); - } - } - break; - - case AST_Enum: break; - case AST_EnumTerminator:break; - - default: - assert(0 && "Unhandled AST node type"); - break; - } - node = node->SiblingNext; - } - while (node != ast.TopNode); - } -} - -//========================================================================== -// -// ZCCCompiler :: AddNamedNode -// -// Keeps track of definition nodes by their names. Ensures that all names -// in this scope are unique. -// -//========================================================================== - -bool ZCCCompiler::AddNamedNode(ZCC_NamedNode *node) -{ - FName name = node->NodeName; - PSymbol *check = Symbols->FindSymbol(name, false); - if (check != NULL) - { - assert(check->IsA(RUNTIME_CLASS(PSymbolTreeNode))); - Error(node, "Attempt to redefine '%s'", name.GetChars()); - Error(static_cast(check)->Node, " Original definition is here"); - return false; - } - else - { - Symbols->AddSymbol(new PSymbolTreeNode(name, node)); - return true; - } -} - -//========================================================================== -// -// ZCCCompiler :: Warn -// -// Prints a warning message, and increments WarnCount. -// -//========================================================================== - -void ZCCCompiler::Warn(ZCC_TreeNode *node, const char *msg, ...) -{ - va_list argptr; - va_start(argptr, msg); - MessageV(node, TEXTCOLOR_ORANGE, msg, argptr); - va_end(argptr); - - WarnCount++; -} - -//========================================================================== -// -// ZCCCompiler :: Error -// -// Prints an error message, and increments ErrorCount. -// -//========================================================================== - -void ZCCCompiler::Error(ZCC_TreeNode *node, const char *msg, ...) -{ - va_list argptr; - va_start(argptr, msg); - MessageV(node, TEXTCOLOR_RED, msg, argptr); - va_end(argptr); - - ErrorCount++; -} - -//========================================================================== -// -// ZCCCompiler :: MessageV -// -// Prints a message, annotated with the source location for the tree node. -// -//========================================================================== - -void ZCCCompiler::MessageV(ZCC_TreeNode *node, const char *txtcolor, const char *msg, va_list argptr) -{ - FString composed; - - composed.Format("%s%s, line %d: ", txtcolor, node->SourceName->GetChars(), node->SourceLoc); - composed.VAppendFormat(msg, argptr); - composed += '\n'; - PrintString(PRINT_HIGH, composed); -} - -//========================================================================== -// -// ZCCCompiler :: Compile -// -// Compile everything defined at this level. -// -//========================================================================== - -int ZCCCompiler::Compile() -{ - CompileConstants(Constants); - return ErrorCount; -} - -//========================================================================== -// -// ZCCCompiler :: CompileConstants -// -// Make symbols from every constant defined at this level. -// -//========================================================================== - -void ZCCCompiler::CompileConstants(const TArray &defs) -{ - for (unsigned i = 0; i < defs.Size(); ++i) - { - ZCC_ConstantDef *def = defs[i]; - if (def->Symbol == NULL) - { - PSymbolConst *sym = CompileConstant(def); - } - } -} - -//========================================================================== -// -// ZCCCompiler :: CompileConstant -// -// For every constant definition, evaluate its value (which should result -// in a constant), and create a symbol for it. Simplify() uses recursion -// to resolve constants used before their declarations. -// -//========================================================================== - -PSymbolConst *ZCCCompiler::CompileConstant(ZCC_ConstantDef *def) -{ - assert(def->Symbol == NULL); - - def->Symbol = DEFINING_CONST; // avoid recursion - ZCC_Expression *val = Simplify(def->Value); - def->Value = val; - PSymbolConst *sym = NULL; - if (val->NodeType == AST_ExprConstant) - { - ZCC_ExprConstant *cval = static_cast(val); - if (cval->Type == TypeString) - { - sym = new PSymbolConstString(def->NodeName, *(cval->StringVal)); - } - else if (cval->Type->IsA(RUNTIME_CLASS(PInt))) - { - sym = new PSymbolConstNumeric(def->NodeName, cval->Type, cval->IntVal); - } - else if (cval->Type->IsA(RUNTIME_CLASS(PFloat))) - { - sym = new PSymbolConstNumeric(def->NodeName, cval->Type, cval->DoubleVal); - } - else - { - Error(def->Value, "Bad type for constant definiton"); - } - } - else - { - Error(def->Value, "Constant definition requires a constant value"); - } - if (sym == NULL) - { - // Create a dummy constant so we don't make any undefined value warnings. - sym = new PSymbolConstNumeric(def->NodeName, TypeError, 0); - } - def->Symbol = sym; - Symbols->ReplaceSymbol(sym); - return sym; -} - - -//========================================================================== -// -// ZCCCompiler :: Simplify -// -// For an expression, -// Evaluate operators whose arguments are both constants, replacing it -// with a new constant. -// For a binary operator with one constant argument, put it on the right- -// hand operand, where permitted. -// Perform automatic type promotion. -// -//========================================================================== - -ZCC_Expression *ZCCCompiler::Simplify(ZCC_Expression *root) -{ - if (root->NodeType == AST_ExprUnary) - { - return SimplifyUnary(static_cast(root)); - } - else if (root->NodeType == AST_ExprBinary) - { - return SimplifyBinary(static_cast(root)); - } - else if (root->Operation == PEX_ID) - { - return IdentifyIdentifier(static_cast(root)); - } - else if (root->Operation == PEX_MemberAccess) - { - return SimplifyMemberAccess(static_cast(root)); - } - else if (root->Operation == PEX_FuncCall) - { - return SimplifyFunctionCall(static_cast(root)); - } - return root; -} - -//========================================================================== -// -// ZCCCompiler :: SimplifyUnary -// -//========================================================================== - -ZCC_Expression *ZCCCompiler::SimplifyUnary(ZCC_ExprUnary *unary) -{ - unary->Operand = Simplify(unary->Operand); - ZCC_OpProto *op = PromoteUnary(unary->Operation, unary->Operand); - if (op == NULL) - { // Oh, poo! - unary->Type = TypeError; - } - else if (unary->Operand->Operation == PEX_ConstValue) - { - return op->EvalConst1(static_cast(unary->Operand)); - } - return unary; -} - -//========================================================================== -// -// ZCCCompiler :: SimplifyBinary -// -//========================================================================== - -ZCC_Expression *ZCCCompiler::SimplifyBinary(ZCC_ExprBinary *binary) -{ - binary->Left = Simplify(binary->Left); - binary->Right = Simplify(binary->Right); - ZCC_OpProto *op = PromoteBinary(binary->Operation, binary->Left, binary->Right); - if (op == NULL) - { - binary->Type = TypeError; - } - else if (binary->Left->Operation == PEX_ConstValue && - binary->Right->Operation == PEX_ConstValue) - { - return op->EvalConst2(static_cast(binary->Left), - static_cast(binary->Right), AST.Strings); - } - return binary; -} - -//========================================================================== -// -// ZCCCompiler :: SimplifyMemberAccess -// -//========================================================================== - -ZCC_Expression *ZCCCompiler::SimplifyMemberAccess(ZCC_ExprMemberAccess *dotop) -{ - dotop->Left = Simplify(dotop->Left); - - if (dotop->Left->Operation == PEX_TypeRef) - { // Type refs can be evaluated now. - PType *ref = static_cast(dotop->Left)->RefType; - PSymbolTable *symtable; - PSymbol *sym = ref->Symbols.FindSymbolInTable(dotop->Right, symtable); - if (sym == NULL) - { - Error(dotop, "'%s' is not a valid member", FName(dotop->Right).GetChars()); - } - else - { - ZCC_Expression *expr = NodeFromSymbol(sym, dotop, symtable); - if (expr == NULL) - { - Error(dotop, "Unhandled symbol type encountered"); - } - else - { - return expr; - } - } - } - return dotop; -} - -//========================================================================== -// -// ZCCCompiler :: SimplifyFunctionCall -// -// This may replace a function call with cast(s), since they look like the -// same thing to the parser. -// -//========================================================================== - -ZCC_Expression *ZCCCompiler::SimplifyFunctionCall(ZCC_ExprFuncCall *callop) -{ - ZCC_FuncParm *parm; - int parmcount = 0; - - callop->Function = Simplify(callop->Function); - parm = callop->Parameters; - if (parm != NULL) - { - do - { - parmcount++; - assert(parm->NodeType == AST_FuncParm); - parm->Value = Simplify(parm->Value); - parm = static_cast(parm->SiblingNext); - } - while (parm != callop->Parameters); - } - // If the left side is a type ref, then this is actually a cast - // and not a function call. - if (callop->Function->Operation == PEX_TypeRef) - { - if (parmcount != 1) - { - Error(callop, "Type cast requires one parameter"); - callop->ToErrorNode(); - } - else - { - PType *dest = static_cast(callop->Function)->RefType; - const PType::Conversion *route[CONVERSION_ROUTE_SIZE]; - int routelen = parm->Value->Type->FindConversion(dest, route, countof(route)); - if (routelen < 0) - { - ///FIXME: Need real type names - Error(callop, "Cannot convert type 1 to type 2"); - callop->ToErrorNode(); - } - else - { - ZCC_Expression *val = ApplyConversion(parm->Value, route, routelen); - assert(val->Type == dest); - return val; - } - } - } - return callop; -} - -//========================================================================== -// -// ZCCCompiler :: PromoteUnary -// -// Converts the operand into a format preferred by the operator. -// -//========================================================================== - -ZCC_OpProto *ZCCCompiler::PromoteUnary(EZCCExprType op, ZCC_Expression *&expr) -{ - if (expr->Type == TypeError) - { - return NULL; - } - const PType::Conversion *route[CONVERSION_ROUTE_SIZE]; - int routelen = countof(route); - ZCC_OpProto *proto = ZCC_OpInfo[op].FindBestProto(expr->Type, route, routelen); - - if (proto != NULL) - { - expr = ApplyConversion(expr, route, routelen); - } - return proto; -} - -//========================================================================== -// -// ZCCCompiler :: PromoteBinary -// -// Converts the operands into a format (hopefully) compatible with the -// operator. -// -//========================================================================== - -ZCC_OpProto *ZCCCompiler::PromoteBinary(EZCCExprType op, ZCC_Expression *&left, ZCC_Expression *&right) -{ - // If either operand is of type 'error', the result is also 'error' - if (left->Type == TypeError || right->Type == TypeError) - { - return NULL; - } - const PType::Conversion *route1[CONVERSION_ROUTE_SIZE], *route2[CONVERSION_ROUTE_SIZE]; - int route1len = countof(route1), route2len = countof(route2); - ZCC_OpProto *proto = ZCC_OpInfo[op].FindBestProto(left->Type, route1, route1len, right->Type, route2, route2len); - if (proto != NULL) - { - left = ApplyConversion(left, route1, route1len); - right = ApplyConversion(right, route2, route2len); - } - return proto; -} - -//========================================================================== -// -// ZCCCompiler :: ApplyConversion -// -//========================================================================== - -ZCC_Expression *ZCCCompiler::ApplyConversion(ZCC_Expression *expr, const PType::Conversion **route, int routelen) -{ - for (int i = 0; i < routelen; ++i) - { - if (expr->Operation != PEX_ConstValue) - { - expr = AddCastNode(route[i]->TargetType, expr); - } - else - { - route[i]->ConvertConstant(static_cast(expr), AST.Strings); - } - } - return expr; -} - -//========================================================================== -// -// ZCCCompiler :: AddCastNode -// -//========================================================================== - -ZCC_Expression *ZCCCompiler::AddCastNode(PType *type, ZCC_Expression *expr) -{ - assert(expr->Operation != PEX_ConstValue && "Expression must not be constant"); - // TODO: add a node here - return expr; -} - -//========================================================================== -// -// ZCCCompiler :: IdentifyIdentifier -// -// Returns a node that represents what the identifer stands for. -// -//========================================================================== - -ZCC_Expression *ZCCCompiler::IdentifyIdentifier(ZCC_ExprID *idnode) -{ - // Check the symbol table for the identifier. - PSymbolTable *table; - PSymbol *sym = Symbols->FindSymbolInTable(idnode->Identifier, table); - if (sym != NULL) - { - ZCC_Expression *node = NodeFromSymbol(sym, idnode, table); - if (node != NULL) - { - return node; - } - } - else - { - Error(idnode, "Unknown identifier '%s'", FName(idnode->Identifier).GetChars()); - } - // Identifier didn't refer to anything good, so type error it. - idnode->ToErrorNode(); - return idnode; -} - -//========================================================================== -// -// ZCCCompiler :: CompileNode -// -//========================================================================== - -PSymbol *ZCCCompiler::CompileNode(ZCC_NamedNode *node) -{ - assert(node != NULL); - if (node->NodeType == AST_ConstantDef) - { - ZCC_ConstantDef *def = static_cast(node); - PSymbolConst *sym = def->Symbol; - - if (sym == DEFINING_CONST) - { - Error(node, "Definition of '%s' is infinitely recursive", FName(node->NodeName).GetChars()); - sym = NULL; - } - else - { - assert(sym == NULL); - sym = CompileConstant(def); - } - return sym; - } - else if (node->NodeType == AST_Struct) - { - - } - return NULL; -} - -//========================================================================== -// -// ZCCCompiler :: NodeFromSymbol -// -//========================================================================== - -ZCC_Expression *ZCCCompiler::NodeFromSymbol(PSymbol *sym, ZCC_Expression *source, PSymbolTable *table) -{ - assert(sym != NULL); - if (sym->IsA(RUNTIME_CLASS(PSymbolTreeNode))) - { - PSymbolTable *prevtable = Symbols; - Symbols = table; - sym = CompileNode(static_cast(sym)->Node); - Symbols = prevtable; - if (sym == NULL) - { - return NULL; - } - } - if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) - { - return NodeFromSymbolConst(static_cast(sym), source); - } - else if (sym->IsKindOf(RUNTIME_CLASS(PSymbolType))) - { - return NodeFromSymbolType(static_cast(sym), source); - } - return NULL; -} - -//========================================================================== -// -// ZCCCompiler :: NodeFromSymbolConst -// -// Returns a new AST constant node with the symbol's content. -// -//========================================================================== - -ZCC_ExprConstant *ZCCCompiler::NodeFromSymbolConst(PSymbolConst *sym, ZCC_Expression *idnode) -{ - ZCC_ExprConstant *val = static_cast(AST.InitNode(sizeof(*val), AST_ExprConstant, idnode)); - val->Operation = PEX_ConstValue; - if (sym == NULL) - { - val->Type = TypeError; - val->IntVal = 0; - } - else if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConstString))) - { - val->StringVal = AST.Strings.Alloc(static_cast(sym)->Str); - val->Type = TypeString; - } - else - { - val->Type = sym->ValueType; - if (val->Type != TypeError) - { - assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric))); - if (sym->ValueType->IsKindOf(RUNTIME_CLASS(PInt))) - { - val->IntVal = static_cast(sym)->Value; - } - else - { - assert(sym->ValueType->IsKindOf(RUNTIME_CLASS(PFloat))); - val->DoubleVal = static_cast(sym)->Float; - } - } - } - return val; -} - -//========================================================================== -// -// ZCCCompiler :: NodeFromSymbolType -// -// Returns a new AST type ref node with the symbol's content. -// -//========================================================================== - -ZCC_ExprTypeRef *ZCCCompiler::NodeFromSymbolType(PSymbolType *sym, ZCC_Expression *idnode) -{ - ZCC_ExprTypeRef *ref = static_cast(AST.InitNode(sizeof(*ref), AST_ExprTypeRef, idnode)); - ref->Operation = PEX_TypeRef; - ref->RefType = sym->Type; - ref->Type = NewClassPointer(RUNTIME_CLASS(PType)); - return ref; -} diff --git a/src/zscript/zcc_compile.h b/src/zscript/zcc_compile.h deleted file mode 100644 index d034464b77..0000000000 --- a/src/zscript/zcc_compile.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef ZCC_COMPILE_H -#define ZCC_COMPILE_H - -class ZCCCompiler -{ -public: - ZCCCompiler(ZCC_AST &tree, DObject *outer, PSymbolTable &symbols); - int Compile(); - -private: - void CompileConstants(const TArray &defs); - PSymbolConst *CompileConstant(ZCC_ConstantDef *def); - - TArray Constants; - TArray Structs; - TArray Classes; - - bool AddNamedNode(ZCC_NamedNode *node); - - ZCC_Expression *Simplify(ZCC_Expression *root); - ZCC_Expression *SimplifyUnary(ZCC_ExprUnary *unary); - ZCC_Expression *SimplifyBinary(ZCC_ExprBinary *binary); - ZCC_Expression *SimplifyMemberAccess(ZCC_ExprMemberAccess *dotop); - ZCC_Expression *SimplifyFunctionCall(ZCC_ExprFuncCall *callop); - ZCC_OpProto *PromoteUnary(EZCCExprType op, ZCC_Expression *&expr); - ZCC_OpProto *PromoteBinary(EZCCExprType op, ZCC_Expression *&left, ZCC_Expression *&right); - - void PromoteToInt(ZCC_Expression *&expr); - void PromoteToUInt(ZCC_Expression *&expr); - void PromoteToDouble(ZCC_Expression *&expr); - void PromoteToString(ZCC_Expression *&expr); - - ZCC_Expression *ApplyConversion(ZCC_Expression *expr, const PType::Conversion **route, int routelen); - ZCC_Expression *AddCastNode(PType *type, ZCC_Expression *expr); - - ZCC_Expression *IdentifyIdentifier(ZCC_ExprID *idnode); - ZCC_Expression *NodeFromSymbol(PSymbol *sym, ZCC_Expression *source, PSymbolTable *table); - ZCC_ExprConstant *NodeFromSymbolConst(PSymbolConst *sym, ZCC_Expression *idnode); - ZCC_ExprTypeRef *NodeFromSymbolType(PSymbolType *sym, ZCC_Expression *idnode); - PSymbol *CompileNode(ZCC_NamedNode *node); - - - void Warn(ZCC_TreeNode *node, const char *msg, ...); - void Error(ZCC_TreeNode *node, const char *msg, ...); - void MessageV(ZCC_TreeNode *node, const char *txtcolor, const char *msg, va_list argptr); - - DObject *Outer; - PSymbolTable *Symbols; - ZCC_AST &AST; - int ErrorCount; - int WarnCount; -}; - -void ZCC_InitConversions(); - -#endif diff --git a/src/zscript/zcc_exprlist.h b/src/zscript/zcc_exprlist.h deleted file mode 100644 index e36aedea63..0000000000 --- a/src/zscript/zcc_exprlist.h +++ /dev/null @@ -1,57 +0,0 @@ -// Name n-ary -xx(Nil, ) - -xx(ID, ) -xx(Super, ) -xx(Self, ) -xx(ConstValue, ) -xx(FuncCall, ) -xx(ArrayAccess, ) -xx(MemberAccess, ) -xx(TypeRef, ) - -xx(PostInc, ) -xx(PostDec, ) - -xx(PreInc, ) -xx(PreDec, ) -xx(Negate, ) -xx(AntiNegate, ) -xx(BitNot, ) -xx(BoolNot, ) -xx(SizeOf, ) -xx(AlignOf, ) - -xx(Add, ) -xx(Sub, ) -xx(Mul, ) -xx(Div, ) -xx(Mod, ) -xx(Pow, ) -xx(CrossProduct, ) -xx(DotProduct, ) -xx(LeftShift, ) -xx(RightShift, ) -xx(Concat, ) - -xx(LT, ) -xx(LTEQ, ) -xx(LTGTEQ, ) -xx(Is, ) - -xx(EQEQ, ) -xx(APREQ, ) - -xx(BitAnd, ) -xx(BitOr, ) -xx(BitXor, ) -xx(BoolAnd, ) -xx(BoolOr, ) - -xx(Scope, ) - -xx(Trinary, ) - -xx(Cast, ) - -#undef xx diff --git a/src/zstring.cpp b/src/zstring.cpp index 70ce9dc687..aed599cd6c 100644 --- a/src/zstring.cpp +++ b/src/zstring.cpp @@ -1231,3 +1231,11 @@ FStringData *FStringData::MakeCopy () FString::StrCopy (copy->Chars(), Chars(), Len); return copy; } + +FStringf::FStringf(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + VFormat(fmt, ap); + va_end(ap); +} diff --git a/src/zstring.h b/src/zstring.h index 6138f38aa9..c696f7fd6a 100644 --- a/src/zstring.h +++ b/src/zstring.h @@ -332,17 +332,75 @@ protected: friend struct FStringData; +public: + bool operator == (const FString &other) const + { + return Compare(other) == 0; + } + + bool operator != (const FString &other) const + { + return Compare(other) != 0; + } + + bool operator < (const FString &other) const + { + return Compare(other) < 0; + } + + bool operator > (const FString &other) const + { + return Compare(other) > 0; + } + + bool operator <= (const FString &other) const + { + return Compare(other) <= 0; + } + + bool operator >= (const FString &other) const + { + return Compare(other) >= 0; + } + + bool operator == (const char *) const = delete; + bool operator != (const char *) const = delete; + bool operator < (const char *) const = delete; + bool operator > (const char *) const = delete; + bool operator <= (const char *) const = delete; + bool operator >= (const char *) const = delete; + + bool operator == (FName) const = delete; + bool operator != (FName) const = delete; + bool operator < (FName) const = delete; + bool operator > (FName) const = delete; + bool operator <= (FName) const = delete; + bool operator >= (FName) const = delete; + private: - // Prevent these from being called as current practices are to use Compare. - // Without this FStrings will be accidentally compared against char* ptrs. - bool operator == (const FString &illegal) const; - bool operator != (const FString &illegal) const; - bool operator < (const FString &illegal) const; - bool operator > (const FString &illegal) const; - bool operator <= (const FString &illegal) const; - bool operator >= (const FString &illegal) const; }; +bool operator == (const char *, const FString &) = delete; +bool operator != (const char *, const FString &) = delete; +bool operator < (const char *, const FString &) = delete; +bool operator > (const char *, const FString &) = delete; +bool operator <= (const char *, const FString &) = delete; +bool operator >= (const char *, const FString &) = delete; + +bool operator == (FName, const FString &) = delete; +bool operator != (FName, const FString &) = delete; +bool operator < (FName, const FString &) = delete; +bool operator > (FName, const FString &) = delete; +bool operator <= (FName, const FString &) = delete; +bool operator >= (FName, const FString &) = delete; + +class FStringf : public FString +{ +public: + FStringf(const char *fmt, ...); +}; + + namespace StringFormat { enum diff --git a/src/zzautozend.cpp b/src/zzautozend.cpp index 5567b1ddda..18c020310c 100644 --- a/src/zzautozend.cpp +++ b/src/zzautozend.cpp @@ -43,6 +43,9 @@ __declspec(allocate(".areg$z")) void *const ARegTail = 0; #pragma section(".creg$z",read) __declspec(allocate(".creg$z")) void *const CRegTail = 0; +#pragma section(".freg$z",read) +__declspec(allocate(".freg$z")) void *const FRegTail = 0; + #pragma section(".greg$z",read) __declspec(allocate(".greg$z")) void *const GRegTail = 0; @@ -56,6 +59,7 @@ __declspec(allocate(".yreg$z")) void *const YRegTail = 0; void *const ARegTail __attribute__((section(SECTION_AREG))) = 0; void *const CRegTail __attribute__((section(SECTION_CREG))) = 0; +void *const FRegTail __attribute__((section(SECTION_FREG))) = 0; void *const GRegTail __attribute__((section(SECTION_GREG))) = 0; void *const YRegTail __attribute__((section(SECTION_YREG))) = 0; diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt deleted file mode 100644 index 71e82f613d..0000000000 --- a/wadsrc/static/actors/actor.txt +++ /dev/null @@ -1,393 +0,0 @@ -ACTOR Actor native //: Thinker -{ - Scale 1 - Health 1000 - Reactiontime 8 - Radius 20 - Height 16 - Mass 100 - RenderStyle Normal - Alpha 1 - MinMissileChance 200 - MeleeRange 44 - MaxDropoffHeight 24 - MaxStepHeight 24 - BounceFactor 0.7 - WallBounceFactor 0.75 - BounceCount -1 - FloatSpeed 4 - FloatBobPhase -1 // randomly initialize by default - Gravity 1 - Friction 1 - DamageFactor 1.0 - PushFactor 0.25 - WeaveIndexXY 0 - WeaveIndexZ 16 - DesignatedTeam 255 - PainType Normal - DeathType Normal - TeleFogSourceType "TeleportFog" - TeleFogDestType "TeleportFog" - RipperLevel 0 - RipLevelMin 0 - RipLevelMax 0 - DefThreshold 100 - BloodType "Blood", "BloodSplatter", "AxeBlood" - ExplosionDamage 128 - MissileHeight 32 - SpriteAngle 0 - SpriteRotation 0 - StencilColor "00 00 00" - VisibleAngles 0, 0 - VisiblePitch 0, 0 - - // Functions - native bool CheckClass(class checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false); - native bool IsPointerEqual(int ptr_select1, int ptr_select2); - native int CountInv(class itemtype, int ptr_select = AAPTR_DEFAULT); - native float GetDistance(bool checkz, int ptr = AAPTR_DEFAULT); - native float GetAngle(int flags, int ptr = AAPTR_DEFAULT); - native float GetZAt(float px = 0, float py = 0, float angle = 0, int flags = 0, int pick_pointer = AAPTR_DEFAULT); - native int GetSpawnHealth(); - native int GetGibHealth(); - native float GetCrouchFactor(int ptr = AAPTR_PLAYER1); - native float GetCVar(string cvar); - native int GetPlayerInput(int inputnum, int ptr = AAPTR_DEFAULT); - native int CountProximity(class classname, float distance, int flags = 0, int ptr = AAPTR_DEFAULT); - native float GetSpriteAngle(int ptr = AAPTR_DEFAULT); - native float GetSpriteRotation(int ptr = AAPTR_DEFAULT); - native int GetMissileDamage(int mask, int add, int ptr = AAPTR_DEFAULT); - action native int OverlayID(); - action native float OverlayX(int layer = 0); - action native float OverlayY(int layer = 0); - - // Action functions - // Meh, MBF redundant functions. Only for DeHackEd support. - action native A_Turn(float angle = 0); - action native bool A_LineEffect(int boomspecial = 0, int tag = 0); - // End of MBF redundant functions. - - action native A_MonsterRail(); - action native A_BFGSpray(class spraytype = "BFGExtra", int numrays = 40, int damagecount = 15, float/*angle*/ angle = 90, float distance = 16*64, float/*angle*/ vrange = 32, int damage = 0, int flags = 0); - action native A_Pain(); - action native A_NoBlocking(); - action native A_XScream(); - action native A_Look(); - action native A_Chase(state melee = "*", state missile = "none", int flags = 0); - action native A_FaceTarget(float max_turn = 0, float max_pitch = 270, float ang_offset = 0, float pitch_offset = 0, int flags = 0, float z_ofs = 0); - action native A_FaceTracer(float max_turn = 0, float max_pitch = 270, float ang_offset = 0, float pitch_offset = 0, int flags = 0, float z_ofs = 0); - action native A_FaceMaster(float max_turn = 0, float max_pitch = 270, float ang_offset = 0, float pitch_offset = 0, int flags = 0, float z_ofs = 0); - action native A_PosAttack(); - action native A_Scream(); - action native A_SPosAttack(); - action native A_SPosAttackUseAtkSound(); - action native A_VileChase(); - action native A_VileStart(); - action native A_VileTarget(class fire = "ArchvileFire"); - action native A_VileAttack(sound snd = "vile/stop", int initialdmg = 20, int blastdmg = 70, int blastradius = 70, float thrustfac = 1.0, name damagetype = "Fire", int flags = 0); - action native A_StartFire(); - action native A_Fire(float spawnheight = 0); - action native A_FireCrackle(); - action native A_Tracer(); - action native A_SkelWhoosh(); - action native A_SkelFist(); - action native A_SkelMissile(); - action native A_FatRaise(); - action native A_FatAttack1(class spawntype = "FatShot"); - action native A_FatAttack2(class spawntype = "FatShot"); - action native A_FatAttack3(class spawntype = "FatShot"); - action native A_BossDeath(); - action native A_CPosAttack(); - action native A_CPosRefire(); - action native A_TroopAttack(); - action native A_SargAttack(); - action native A_HeadAttack(); - action native A_BruisAttack(); - action native A_SkullAttack(float speed = 20); - action native A_BetaSkullAttack(); - action native A_Metal(); - action native A_SpidRefire(); - action native A_BabyMetal(); - action native A_BspiAttack(); - action native A_Hoof(); - action native A_CyberAttack(); - action native A_PainAttack(class spawntype = "LostSoul", float angle = 0, int flags = 0, int limit = -1); - action native A_DualPainAttack(class spawntype = "LostSoul"); - action native A_PainDie(class spawntype = "LostSoul"); - action native A_KeenDie(int doortag = 666); - action native A_BrainPain(); - action native A_BrainScream(); - action native A_BrainDie(); - action native A_BrainAwake(); - action native A_BrainSpit(class spawntype = "none"); // needs special treatment for default - action native A_SpawnSound(); - action native A_SpawnFly(class spawntype = "none"); // needs special treatment for default - action native A_BrainExplode(); - action native A_Die(name damagetype = "none"); - action native A_Detonate(); - action native A_Mushroom(class spawntype = "FatShot", int numspawns = 0, int flags = 0, float vrange = 4.0, float hrange = 0.5); - native bool A_CallSpecial(int special, int arg1=0, int arg2=0, int arg3=0, int arg4=0, int arg5=0); - - action native A_SetFloorClip(); - action native A_UnSetFloorClip(); - action native A_HideThing(); - action native A_UnHideThing(); - action native A_SetInvulnerable(); - action native A_UnSetInvulnerable(); - action native A_SetReflective(); - action native A_UnSetReflective(); - action native A_SetReflectiveInvulnerable(); - action native A_UnSetReflectiveInvulnerable(); - action native A_SetShootable(); - action native A_UnSetShootable(); - action native A_NoGravity(); - action native A_Gravity(); - action native A_LowGravity(); - native void A_SetGravity(float gravity); - action native A_Fall(); - action native A_SetSolid(); - action native A_UnsetSolid(); - action native A_SetFloat(); - action native A_UnsetFloat(); - - action native A_M_Saw(sound fullsound = "weapons/sawfull", sound hitsound = "weapons/sawhit", int damage = 2, class pufftype = "BulletPuff"); - - action native A_ScreamAndUnblock(); - action native A_ActiveAndUnblock(); - action native A_ActiveSound(); - - action native A_FastChase(); - action native A_FreezeDeath(); - action native A_FreezeDeathChunks(); - action native A_GenericFreezeDeath(); - action native A_IceGuyDie(); - action native A_CentaurDefend(); - action native A_BishopMissileWeave(); - action native A_CStaffMissileSlither(); - action native A_PlayerScream(); - action native A_SkullPop(class skulltype = "BloodySkull"); - action native A_CheckPlayerDone(); - - action native A_Wander(int flags = 0); - action native A_Look2(); - action native A_TossGib(); - action native A_SentinelBob(); - action native A_SentinelRefire(); - action native A_Tracer2(); - action native A_SetShadow(); - action native A_ClearShadow(); - action native A_GetHurt(); - action native A_TurretLook(); - action native A_KlaxonBlare(); - action native A_Countdown(); - action native A_AlertMonsters(float maxdist = 0, int flags = 0); - action native A_ClearSoundTarget(); - action native A_FireAssaultGun(); - action native A_CheckTerrain(); - action native A_FaceConsolePlayer(float MaxTurnAngle = 0); // [TP] no-op - - action native A_MissileAttack(); - action native A_MeleeAttack(); - action native A_ComboAttack(); - action native A_BulletAttack(); - action native A_WolfAttack(int flags = 0, sound whattoplay = "weapons/pistol", float snipe = 1.0, int maxdamage = 64, int blocksize = 128, int pointblank = 2, int longrange = 4, float runspeed = 160.0, class pufftype = "BulletPuff"); - action native A_PlaySound(sound whattoplay = "weapons/pistol", int slot = CHAN_BODY, float volume = 1.0, bool looping = false, float attenuation = ATTN_NORM, bool local = false); - native void A_PlayWeaponSound(sound whattoplay); - action native A_FLoopActiveSound(); - action native A_LoopActiveSound(); - action native A_StopSound(int slot = CHAN_VOICE); // Bad default but that's what is originally was... - native void A_PlaySoundEx(sound whattoplay, coerce name slot, bool looping = false, int attenuation = 0); - native void A_StopSoundEx(coerce name slot); - native void A_SeekerMissile(int threshold, int turnmax, int flags = 0, int chance = 50, int distance = 10); - native state A_Jump(int chance = 256, state label, ...); - native void A_CustomMissile(class missiletype, float spawnheight = 32, float spawnofs_xy = 0, float angle = 0, int flags = 0, float pitch = 0, int ptr = AAPTR_TARGET); - native void A_CustomBulletAttack(float/*angle*/ spread_xy, float/*angle*/ spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", float range = 0, int flags = 0, int ptr = AAPTR_TARGET, class missile = "", float Spawnheight = 32, float Spawnofs_xy = 0); - native void A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = "", color color2 = "", int flags = 0, int aim = 0, float maxdiff = 0, class pufftype = "BulletPuff", float/*angle*/ spread_xy = 0, float/*angle*/ spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class spawnclass = "none", float spawnofs_z = 0, int spiraloffset = 270, int limit = 0); - native state A_JumpIfHealthLower(int health, state label, int ptr_selector = AAPTR_DEFAULT); - native state A_JumpIfCloser(float distance, state label, bool noz = false); - native state A_JumpIfTracerCloser(float distance, state label, bool noz = false); - native state A_JumpIfMasterCloser(float distance, state label, bool noz = false); - native state A_JumpIfTargetOutsideMeleeRange(state label); - native state A_JumpIfTargetInsideMeleeRange(state label); - native state A_JumpIfInventory(class itemtype, int itemamount, state label, int owner = AAPTR_DEFAULT); - native state A_JumpIfArmorType(name Type, state label, int amount = 1); - action native bool A_SetInventory(class itemtype, int amount, int ptr = AAPTR_DEFAULT, bool beyondMax = false); - native bool A_GiveInventory(class itemtype, int amount = 0, int giveto = AAPTR_DEFAULT); - native bool A_TakeInventory(class itemtype, int amount = 0, int flags = 0, int giveto = AAPTR_DEFAULT); - action native bool A_SpawnItem(class itemtype = "Unknown", float distance = 0, float zheight = 0, bool useammo = true, bool transfer_translation = false); - native bool A_SpawnItemEx(class itemtype, float xofs = 0, float yofs = 0, float zofs = 0, float xvel = 0, float yvel = 0, float zvel = 0, float angle = 0, int flags = 0, int failchance = 0, int tid=0); - native void A_Print(string whattoprint, float time = 0, name fontname = ""); - native void A_PrintBold(string whattoprint, float time = 0, name fontname = ""); - native void A_Log(string whattoprint); - native void A_LogInt(int whattoprint); - native void A_LogFloat(float whattoprint); - native void A_SetTranslucent(float alpha, int style = 0); - native void A_SetRenderStyle(float alpha, int style); - action native A_FadeIn(float reduce = 0.1, int flags = 0); - action native A_FadeOut(float reduce = 0.1, int flags = 1); //bool remove == true - native void A_FadeTo(float target, float amount = 0.1, int flags = 0); - native void A_SetScale(float scalex, float scaley = 0, int ptr = AAPTR_DEFAULT, bool usezero = false); - native void A_SetMass(int mass); - native void A_SpawnDebris(class spawntype, bool transfer_translation = false, float mult_h = 1, float mult_v = 1); - native void A_SpawnParticle(color color1, int flags = 0, int lifetime = 35, float size = 1, float angle = 0, float xoff = 0, float yoff = 0, float zoff = 0, float velx = 0, float vely = 0, float velz = 0, float accelx = 0, float accely = 0, float accelz = 0, float startalphaf = 1, float fadestepf = -1, float sizestep = 0); - native state A_CheckSight(state label); - native void A_ExtChase(bool usemelee, bool usemissile, bool playactive = true, bool nightmarefast = false); - native void A_DropInventory(class itemtype); - native void A_SetBlend(color color1, float alpha, int tics, color color2 = ""); - native void A_ChangeFlag(string flagname, bool value); - native state A_CheckFlag(string flagname, state label, int check_pointer = AAPTR_DEFAULT); - native state A_JumpIf(bool expression, state label); - action native A_RaiseMaster(bool copy = 0); - action native A_RaiseChildren(bool copy = 0); - action native A_RaiseSiblings(bool copy = 0); - native state A_CheckFloor(state label); - native state A_CheckCeiling(state label); - native state A_PlayerSkinCheck(state label); - native void A_BasicAttack(int meleedamage, sound meleesound, class missiletype, float missileheight); - action native state, bool A_Teleport(state teleportstate = "", class targettype = "BossSpot", class fogtype = "TeleportFog", int flags = 0, float mindist = 0, float maxdist = 0, int ptr = AAPTR_DEFAULT); - action native state, bool A_Warp(int ptr_destination, float xofs = 0, float yofs = 0, float zofs = 0, float angle = 0, int flags = 0, state success_state = "", float heightoffset = 0, float radiusoffset = 0, float pitch = 0); - action native bool A_ThrowGrenade(class itemtype, float zheight = 0, float xyvel = 0, float zvel = 0, bool useammo = true); - native void A_Weave(int xspeed, int yspeed, float xdist, float ydist); - - native void A_Recoil(float xyvel); - native state A_JumpIfInTargetInventory(class itemtype, int amount, state label, int forward_ptr = AAPTR_DEFAULT); - native bool A_GiveToTarget(class itemtype, int amount = 0, int forward_ptr = AAPTR_DEFAULT); - native bool A_TakeFromTarget(class itemtype, int amount = 0, int flags = 0, int forward_ptr = AAPTR_DEFAULT); - native int A_RadiusGive(class itemtype, float distance, int flags, int amount = 0, class filter = "None", name species = "None", float mindist = 0, int limit = 0); - native state A_CheckSpecies(state jump, name species = "", int ptr = AAPTR_DEFAULT); - native void A_CountdownArg(int argnum, state targstate = ""); - action native A_CustomMeleeAttack(int damage = 0, sound meleesound = "", sound misssound = "", name damagetype = "none", bool bleed = true); - native void A_CustomComboAttack(class missiletype, float spawnheight, int damage, sound meleesound = "", name damagetype = "none", bool bleed = true); - native void A_Burst(class chunktype); - action native A_Blast(int flags = 0, float strength = 255, float radius = 255, float speed = 20, class blasteffect = "BlastEffect", sound blastsound = "BlastRadius"); - action native A_RadiusThrust(int force = 128, int distance = -1, int flags = RTF_AFFECTSOURCE, int fullthrustdistance = 0); - action native A_RadiusDamageSelf(int damage = 128, float distance = 128, int flags = 0, class flashtype = "None"); - action native int A_Explode(int damage = -1, int distance = -1, int flags = XF_HURTSOURCE, bool alert = false, int fulldamagedistance = 0, int nails = 0, int naildamage = 10, class pufftype = "BulletPuff", name damagetype = "none"); - action native A_Stop(); - action native A_Respawn(int flags = 1); - action native A_BarrelDestroy(); - action native A_QueueCorpse(); - action native A_DeQueueCorpse(); - action native A_LookEx(int flags = 0, float minseedist = 0, float maxseedist = 0, float maxheardist = 0, float fov = 0, state label = ""); - action native A_ClearLastHeard(); - action native A_ClearTarget(); - native state A_CheckLOF(state jump, int flags = 0, float range = 0, float minrange = 0, float angle = 0, float pitch = 0, float offsetheight = 0, float offsetwidth = 0, int ptr_target = AAPTR_DEFAULT, float offsetforward = 0); - native state A_JumpIfTargetInLOS (state label, float/*angle*/ fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0); - native state A_JumpIfInTargetLOS (state label, float/*angle*/ fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0); - native bool A_SelectWeapon(class whichweapon, int flags = 0); - action native A_Punch(); - action native A_Feathers(); - action native A_ClassBossHealth(); - action native A_ShootGun(); - action native A_RocketInFlight(); - action native A_Bang4Cloud(); - action native A_DropFire(); - native void A_GiveQuestItem(int itemno); - action native A_RemoveForcefield(); - native void A_DropWeaponPieces(class p1, class p2, class p3); - action native A_PigPain (); - native state A_MonsterRefire(int chance, state label); - action native A_SetAngle(float angle = 0, int flags = 0, int ptr = AAPTR_DEFAULT); - native void A_SetPitch(float pitch, int flags = 0, int ptr = AAPTR_DEFAULT); - native void A_SetRoll(float/*angle*/ roll, int flags = 0, int ptr = AAPTR_DEFAULT); - native void A_ScaleVelocity(float scale, int ptr = AAPTR_DEFAULT); - action native A_ChangeVelocity(float x = 0, float y = 0, float z = 0, int flags = 0, int ptr = AAPTR_DEFAULT); - native void A_SetArg(int pos, int value); - native void A_SetUserVar(name varname, int value); - native void A_SetUserArray(name varname, int index, int value); - native void A_SetUserVarFloat(name varname, float value); - native void A_SetUserArrayFloat(name varname, int index, float value); - native void A_SetSpecial(int spec, int arg0 = 0, int arg1 = 0, int arg2 = 0, int arg3 = 0, int arg4 = 0); - native void A_Quake(int intensity, int duration, int damrad, int tremrad, sound sfx = "world/quake"); - native void A_QuakeEx(int intensityX, int intensityY, int intensityZ, int duration, int damrad, int tremrad, sound sfx = "world/quake", int flags = 0, float mulWaveX = 1, float mulWaveY = 1, float mulWaveZ = 1, int falloff = 0, int highpoint = 0, float rollIntensity = 0, float rollWave = 0); - action native A_SetTics(int tics); - native void A_SetDamageType(name damagetype); - native void A_DropItem(class item, int dropamount = -1, int chance = 256); - native void A_SetSpeed(float speed, int ptr = AAPTR_DEFAULT); - native void A_SetFloatSpeed(float speed, int ptr = AAPTR_DEFAULT); - native void A_SetPainThreshold(int threshold, int ptr = AAPTR_DEFAULT); - native void A_DamageSelf(int amount, name damagetype = "none", int flags = 0, class filter = "None", name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); - native void A_DamageTarget(int amount, name damagetype = "none", int flags = 0, class filter = "None", name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); - native void A_DamageMaster(int amount, name damagetype = "none", int flags = 0, class filter = "None", name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); - native void A_DamageTracer(int amount, name damagetype = "none", int flags = 0, class filter = "None", name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); - native void A_DamageChildren(int amount, name damagetype = "none", int flags = 0, class filter = "None", name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); - native void A_DamageSiblings(int amount, name damagetype = "none", int flags = 0, class filter = "None", name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); - action native A_KillTarget(name damagetype = "none", int flags = 0, class filter = "None", name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); - action native A_KillMaster(name damagetype = "none", int flags = 0, class filter = "None", name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); - action native A_KillTracer(name damagetype = "none", int flags = 0, class filter = "None", name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); - action native A_KillChildren(name damagetype = "none", int flags = 0, class filter = "None", name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); - action native A_KillSiblings(name damagetype = "none", int flags = 0, class filter = "None", name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); - action native A_RemoveTarget(int flags = 0, class filter = "None", name species = "None"); - action native A_RemoveMaster(int flags = 0, class filter = "None", name species = "None"); - action native A_RemoveTracer(int flags = 0, class filter = "None", name species = "None"); - action native A_RemoveChildren(bool removeall = false, int flags = 0, class filter = "None", name species = "None"); - action native A_RemoveSiblings(bool removeall = false, int flags = 0, class filter = "None", name species = "None"); - native void A_Remove(int removee, int flags = 0, class filter = "None", name species = "None"); - native int A_GiveToChildren(class itemtype, int amount = 0); - native int A_GiveToSiblings(class itemtype, int amount = 0); - native int A_TakeFromChildren(class itemtype, int amount = 0); - native int A_TakeFromSiblings(class itemtype, int amount = 0); - native void A_SetTeleFog(class oldpos, class newpos); - action native A_SwapTeleFog(); - native void A_SetFloatBobPhase(int bob); - native void A_SetHealth(int health, int ptr = AAPTR_DEFAULT); - action native A_ResetHealth(int ptr = AAPTR_DEFAULT); - native state A_JumpIfHigherOrLower(state high, state low, float offsethigh = 0, float offsetlow = 0, bool includeHeight = true, int ptr = AAPTR_TARGET); - native void A_SetSpecies(name species, int ptr = AAPTR_DEFAULT); - native void A_SetRipperLevel(int level); - native void A_SetRipMin(int mininum); - native void A_SetRipMax(int maximum); - native void A_SetChaseThreshold(int threshold, bool def = false, int ptr = AAPTR_DEFAULT); - native state A_CheckProximity(state jump, class classname, float distance, int count = 1, int flags = 0, int ptr = AAPTR_DEFAULT); - native state A_CheckBlock(state block, int flags = 0, int ptr = AAPTR_DEFAULT, float xofs = 0, float yofs = 0, float zofs = 0, float angle = 0); - native state A_CheckSightOrRange(float distance, state label, bool two_dimension = false); - native state A_CheckRange(float distance, state label, bool two_dimension = false); - action native bool A_FaceMovementDirection(float offset = 0, float anglelimit = 0, float pitchlimit = 0, int flags = 0, int ptr = AAPTR_DEFAULT); - action native int A_ClearOverlays(int sstart = 0, int sstop = 0, bool safety = true); - action native bool A_CopySpriteFrame(int from, int to, int flags = 0); - action native bool A_SetSpriteAngle(float angle = 0, int ptr = AAPTR_DEFAULT); - action native bool A_SetSpriteRotation(float angle = 0, int ptr = AAPTR_DEFAULT); - action native bool A_SetVisibleRotation(float anglestart = 0, float angleend = 0, float pitchstart = 0, float pitchend = 0, int flags = 0, int ptr = AAPTR_DEFAULT); - native void A_SetTranslation(string transname); - - native void A_RearrangePointers(int newtarget, int newmaster = AAPTR_DEFAULT, int newtracer = AAPTR_DEFAULT, int flags=0); - native void A_TransferPointer(int ptr_source, int ptr_recepient, int sourcefield, int recepientfield=AAPTR_DEFAULT, int flags=0); - action native A_CopyFriendliness(int ptr_source = AAPTR_MASTER); - - action native bool A_Overlay(int layer, state start = "", bool nooverride = false); - action native A_WeaponOffset(float wx = 0, float wy = 32, int flags = 0); - action native A_OverlayOffset(int layer = PSP_WEAPON, float wx = 0, float wy = 32, int flags = 0); - action native A_OverlayFlags(int layer, int flags, bool set); - - native int ACS_NamedExecute(name script, int mapnum=0, int arg1=0, int arg2=0, int arg3=0); - native int ACS_NamedSuspend(name script, int mapnum=0); - native int ACS_NamedTerminate(name script, int mapnum=0); - native int ACS_NamedLockedExecute(name script, int mapnum=0, int arg1=0, int arg2=0, int lock=0); - native int ACS_NamedLockedExecuteDoor(name script, int mapnum=0, int arg1=0, int arg2=0, int lock=0); - native int ACS_NamedExecuteWithResult(name script, int arg1=0, int arg2=0, int arg3=0, int arg4=0); - native void ACS_NamedExecuteAlways(name script, int mapnum=0, int arg1=0, int arg2=0, int arg3=0); - - States - { - Spawn: - TNT1 A -1 - Stop - Null: - TNT1 A 1 - Stop - GenericFreezeDeath: - // Generic freeze death frames. Woo! - "####" "#" 5 A_GenericFreezeDeath - "----" A 1 A_FreezeDeathChunks - Wait - GenericCrush: - POL5 A -1 - Stop - } - - // Internal functions - native state __decorate_internal_state__(state); - native int __decorate_internal_int__(int); - native bool __decorate_internal_bool__(bool); - native float __decorate_internal_float__(float); -} diff --git a/wadsrc/static/actors/chex/chexammo.txt b/wadsrc/static/actors/chex/chexammo.txt deleted file mode 100644 index 27c5d419b4..0000000000 --- a/wadsrc/static/actors/chex/chexammo.txt +++ /dev/null @@ -1,77 +0,0 @@ -// Renaming and changing messages - -// Mini Zorch ----------------------------------------------------------------- - -actor MiniZorchRecharge : Clip -{ - inventory.pickupmessage "$GOTZORCHRECHARGE" -} - -actor MiniZorchPack : Clip -{ - Inventory.PickupMessage "$GOTMINIZORCHPACK" - Inventory.Amount 50 - States - { - Spawn: - AMMO A -1 - Stop - } -} - -// Large Zorch ---------------------------------------------------------------- - -actor LargeZorchRecharge : Shell -{ - inventory.pickupmessage "$GOTLARGEZORCHERRECHARGE" -} - -actor LargeZorchPack : Shell -{ - Inventory.PickupMessage "$GOTLARGEZORCHERPACK" - Inventory.Amount 20 - States - { - Spawn: - SBOX A -1 - Stop - } -} - -// Zorch Propulsor ------------------------------------------------------------ - -actor PropulsorZorch : RocketAmmo -{ - inventory.pickupmessage "$GOTPROPULSORRECHARGE" -} - -actor PropulsorZorchPack : RocketAmmo -{ - Inventory.PickupMessage "$GOTPROPULSORPACK" - Inventory.Amount 5 - States - { - Spawn: - BROK A -1 - Stop - } -} - -// Phasing Zorch -------------------------------------------------------------- - -actor PhasingZorch : Cell -{ - inventory.pickupmessage "$GOTPHASINGZORCHERRECHARGE" -} - -actor PhasingZorchPack : Cell -{ - Inventory.PickupMessage "$GOTPHASINGZORCHERPACK" - Inventory.Amount 100 - States - { - Spawn: - CELP A -1 - Stop - } -} diff --git a/wadsrc/static/actors/chex/chexdecorations.txt b/wadsrc/static/actors/chex/chexdecorations.txt deleted file mode 100644 index 6515061c5f..0000000000 --- a/wadsrc/static/actors/chex/chexdecorations.txt +++ /dev/null @@ -1,120 +0,0 @@ -// Doom items renamed with height changes - -// Civilians ------------------------------------------------------------------ - -actor ChexCivilian1 : GreenTorch -{ - height 54 -} - -actor ChexCivilian2 : ShortGreenTorch -{ - height 54 -} - -actor ChexCivilian3 : ShortRedTorch -{ - height 48 -} - -// Landing Zone --------------------------------------------------------------- - -actor ChexLandingLight : Column -{ - height 35 -} - -actor ChexSpaceship : TechPillar -{ - height 52 -} - -// Trees and Plants ----------------------------------------------------------- - -actor ChexAppleTree : Stalagtite -{ - height 92 -} - -actor ChexBananaTree : BigTree -{ - height 108 -} - -actor ChexOrangeTree : TorchTree -{ - height 92 -} - -actor ChexSubmergedPlant : ShortGreenColumn -{ - height 42 -} - -actor ChexTallFlower : HeadsOnAStick -{ - height 25 -} - -actor ChexTallFlower2 : DeadStick -{ - height 25 -} - -// Slime Fountain ------------------------------------------------------------- - -actor ChexSlimeFountain : BlueTorch -{ - height 48 - States - { - Spawn: - TBLU ABCD 4 - Loop - } -} - -// Cavern Decorations --------------------------------------------------------- - -actor ChexCavernColumn : TallRedColumn -{ - height 128 -} - -actor ChexCavernStalagmite : TallGreenColumn -{ - height 60 -} - -// Misc. Props ---------------------------------------------------------------- - -actor ChexChemicalBurner : EvilEye -{ - height 25 -} - -actor ChexChemicalFlask : Candlestick -{ - renderstyle translucent - alpha 0.75 -} - -actor ChexFlagOnPole : SkullColumn -{ - height 128 -} - -actor ChexGasTank : Candelabra -{ - height 36 -} - -actor ChexLightColumn : ShortBlueTorch -{ - height 86 -} - -actor ChexMineCart : ShortRedColumn -{ - height 30 -} diff --git a/wadsrc/static/actors/chex/chexitems.txt b/wadsrc/static/actors/chex/chexitems.txt deleted file mode 100644 index 431728e073..0000000000 --- a/wadsrc/static/actors/chex/chexitems.txt +++ /dev/null @@ -1,59 +0,0 @@ - -// General Pickups ============================================================ - -// Health --------------------------------------------------------------------- - -actor GlassOfWater : HealthBonus -{ - inventory.pickupmessage "$GOTWATER" -} - -actor BowlOfFruit : Stimpack -{ - inventory.pickupmessage "$GOTFRUIT" -} - -actor BowlOfVegetables : Medikit -{ - inventory.pickupmessage "$GOTVEGETABLES" - health.lowmessage 25, "$GOTVEGETABLESNEED" -} - -actor SuperchargeBreakfast : Soulsphere -{ - inventory.pickupmessage "$GOTBREAKFAST" -} - -// Armor ---------------------------------------------------------------------- - -actor SlimeRepellent : ArmorBonus -{ - inventory.pickupmessage "$GOTREPELLENT" -} - -actor ChexArmor : GreenArmor -{ - inventory.pickupmessage "$GOTCHEXARMOR" -} - -actor SuperChexArmor : BlueArmor -{ - inventory.pickupmessage "$GOTSUPERCHEXARMOR" -} - -// Powerups =================================================================== - -actor ComputerAreaMap : Allmap -{ - inventory.pickupmessage "$GOTCHEXMAP" -} - -actor SlimeProofSuit : RadSuit -{ - inventory.pickupmessage "$GOTSLIMESUIT" -} - -actor Zorchpack : Backpack -{ - inventory.pickupmessage "$GOTZORCHPACK" -} diff --git a/wadsrc/static/actors/chex/chexkeys.txt b/wadsrc/static/actors/chex/chexkeys.txt deleted file mode 100644 index 0d5156392e..0000000000 --- a/wadsrc/static/actors/chex/chexkeys.txt +++ /dev/null @@ -1,16 +0,0 @@ -// These are merely renames of the Doom cards - -actor ChexBlueCard : BlueCard -{ - inventory.pickupmessage "$GOTCBLUEKEY" -} - -actor ChexYellowCard : YellowCard -{ - inventory.pickupmessage "$GOTCYELLOWKEY" -} - -actor ChexRedCard : RedCard -{ - inventory.pickupmessage "$GOTCREDKEY" -} diff --git a/wadsrc/static/actors/chex/chexplayer.txt b/wadsrc/static/actors/chex/chexplayer.txt deleted file mode 100644 index 210a684707..0000000000 --- a/wadsrc/static/actors/chex/chexplayer.txt +++ /dev/null @@ -1,29 +0,0 @@ -// Chex Warrior - -actor ChexPlayer : DoomPlayer -{ - player.displayname "Chex Warrior" - player.crouchsprite "" - player.colorrange 192, 207 //Not perfect, but its better than everyone being blue. - player.startitem "MiniZorcher" - player.startitem "Bootspoon" - player.startitem "MiniZorchRecharge", 50 - player.damagescreencolor "60 b0 58" - player.WeaponSlot 1, Bootspoon, SuperBootspork - player.WeaponSlot 2, MiniZorcher - player.WeaponSlot 3, LargeZorcher, SuperLargeZorcher - player.WeaponSlot 4, RapidZorcher - player.WeaponSlot 5, ZorchPropulsor - player.WeaponSlot 6, PhasingZorcher - player.WeaponSlot 7, LAZDevice - - Player.Colorset 0, "Light Blue", 0xC0, 0xCF, 0xC2 - Player.Colorset 1, "Green", 0x70, 0x7F, 0x72 - Player.Colorset 2, "Gray", 0x60, 0x6F, 0x62 - Player.Colorset 3, "Brown", 0x40, 0x4F, 0x42 - Player.Colorset 4, "Red", 0x20, 0x2F, 0x22 - Player.Colorset 5, "Light Gray", 0x58, 0x67, 0x5A - Player.Colorset 6, "Light Brown", 0x38, 0x47, 0x3A - Player.Colorset 7, "Light Red", 0xB0, 0xBF, 0xB2 - -} diff --git a/wadsrc/static/actors/chex/chexweapons.txt b/wadsrc/static/actors/chex/chexweapons.txt deleted file mode 100644 index 0cdb968491..0000000000 --- a/wadsrc/static/actors/chex/chexweapons.txt +++ /dev/null @@ -1,124 +0,0 @@ -// Same as Doom weapons, but the obituaries are removed. - -actor Bootspoon : Fist -{ - obituary "$OB_MPSPOON" - Tag "$TAG_SPOON" -} - -actor SuperBootspork : Chainsaw -{ - obituary "$OB_MPBOOTSPORK" - Inventory.PickupMessage "$GOTSUPERBOOTSPORK" - Tag "$TAG_SPORK" -} - -actor MiniZorcher : Pistol -{ - obituary "$OB_MPZORCH" - inventory.pickupmessage "$GOTMINIZORCHER" - Tag "$TAG_MINIZORCHER" - states - { - Spawn: - MINZ A -1 - stop - } -} - -actor LargeZorcher : Shotgun -{ - obituary "$OB_MPZORCH" - inventory.pickupmessage "$GOTLARGEZORCHER" - Tag "$TAG_LARGEZORCHER" -} - -actor SuperLargeZorcher : SuperShotgun -{ - obituary "$OB_MPMEGAZORCH" - inventory.pickupmessage "$GOTSUPERLARGEZORCHER" - Tag "$TAG_SUPERLARGEZORCHER" -} - -actor RapidZorcher : Chaingun -{ - obituary "$OB_MPRAPIDZORCH" - inventory.pickupmessage "$GOTRAPIDZORCHER" - Tag "$TAG_RAPIDZORCHER" -} - -actor ZorchPropulsor : RocketLauncher -{ - obituary "" - inventory.pickupmessage "$GOTZORCHPROPULSOR" - Tag "$TAG_ZORCHPROPULSOR" - States - { - Fire: - MISG B 8 A_GunFlash - MISG B 12 A_FireCustomMissile("PropulsorMissile") - MISG B 0 A_ReFire - Goto Ready - } -} - -actor PropulsorMissile : Rocket -{ - -ROCKETTRAIL - -DEHEXPLOSION - RenderStyle Translucent - Obituary "$OB_MPPROPULSOR" - Alpha 0.75 -} - -actor PhasingZorcher : PlasmaRifle -{ - obituary "" - inventory.pickupmessage "$GOTPHASINGZORCHER" - Tag "$TAG_PHASINGZORCHER" - states - { - Fire: - PLSG A 0 A_GunFlash - PLSG A 3 A_FireCustomMissile("PhaseZorchMissile") - PLSG B 20 A_ReFire - Goto Ready - Flash: - PLSF A 0 A_Jump(128, "Flash2") - PLSF A 3 Bright A_Light1 - Goto LightDone - Flash2: - PLSF B 3 Bright A_Light1 - Goto LightDone - } -} - -actor PhaseZorchMissile : PlasmaBall -{ - RenderStyle Translucent - Obituary "$OB_MPPHASEZORCH" - Alpha 0.75 -} - -actor LAZDevice : BFG9000 -{ - obituary "" - inventory.pickupmessage "$GOTLAZDEVICE" - Tag "$TAG_LAZDEVICE" - states - { - Fire: - BFGG A 20 A_BFGsound - BFGG B 10 A_GunFlash - BFGG B 10 A_FireCustomMissile("LAZBall") - BFGG B 20 A_ReFire - Goto Ready - } -} - -actor LAZBall : BFGBall -{ - RenderStyle Translucent - Obituary "$OB_MPLAZ_BOOM" - Alpha 0.75 -} diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt deleted file mode 100644 index df3bb860bb..0000000000 --- a/wadsrc/static/actors/constants.txt +++ /dev/null @@ -1,711 +0,0 @@ - -// Flags for A_PainAttack -const int PAF_NOSKULLATTACK = 1; -const int PAF_AIMFACING = 2; -const int PAF_NOTARGET = 4; - -// Flags for A_VileAttack -const int VAF_DMGTYPEAPPLYTODIRECT = 1; - -// Flags for A_Saw -const int SF_NORANDOM = 1; -const int SF_RANDOMLIGHTMISS = 2; -const int SF_RANDOMLIGHTHIT = 4; -const int SF_RANDOMLIGHTBOTH = 6; -const int SF_NOUSEAMMOMISS = 8; -const int SF_NOUSEAMMO = 16; -const int SF_NOPULLIN = 32; -const int SF_NOTURN = 64; -const int SF_STEALARMOR = 128; - -// Flags for A_BFGSpray -const int BFGF_HURTSOURCE = 1; -const int BFGF_MISSILEORIGIN = 2; - -// Flags for A_CustomMissile -const int CMF_AIMOFFSET = 1; -const int CMF_AIMDIRECTION = 2; -const int CMF_TRACKOWNER = 4; -const int CMF_CHECKTARGETDEAD = 8; -const int CMF_ABSOLUTEPITCH = 16; -const int CMF_OFFSETPITCH = 32; -const int CMF_SAVEPITCH = 64; -const int CMF_ABSOLUTEANGLE = 128; - -// Flags for A_CustomBulletAttack -const int CBAF_AIMFACING = 1; -const int CBAF_NORANDOM = 2; -const int CBAF_EXPLICITANGLE = 4; -const int CBAF_NOPITCH = 8; -const int CBAF_NORANDOMPUFFZ = 16; -const int CBAF_PUFFTARGET = 32; -const int CBAF_PUFFMASTER = 64; -const int CBAF_PUFFTRACER = 128; - -// Flags for A_GunFlash -const int GFF_NOEXTCHANGE = 1; - -// Flags for A_FireBullets -const int FBF_USEAMMO = 1; -const int FBF_NORANDOM = 2; -const int FBF_EXPLICITANGLE = 4; -const int FBF_NOPITCH = 8; -const int FBF_NOFLASH = 16; -const int FBF_NORANDOMPUFFZ = 32; - -// Flags for A_SpawnItemEx -const int SXF_TRANSFERTRANSLATION = 1 << 0; -const int SXF_ABSOLUTEPOSITION = 1 << 1; -const int SXF_ABSOLUTEANGLE = 1 << 2; -const int SXF_ABSOLUTEMOMENTUM = 1 << 3; //Since "momentum" is declared to be deprecated in the expressions, for compatibility -const int SXF_ABSOLUTEVELOCITY = 1 << 3; //purposes, this was made. It does the same thing though. Do not change the value. -const int SXF_SETMASTER = 1 << 4; -const int SXF_NOCHECKPOSITION = 1 << 5; -const int SXF_TELEFRAG = 1 << 6; -const int SXF_CLIENTSIDE = 1 << 7; // only used by Skulltag -const int SXF_TRANSFERAMBUSHFLAG = 1 << 8; -const int SXF_TRANSFERPITCH = 1 << 9; -const int SXF_TRANSFERPOINTERS = 1 << 10; -const int SXF_USEBLOODCOLOR = 1 << 11; -const int SXF_CLEARCALLERTID = 1 << 12; -const int SXF_MULTIPLYSPEED = 1 << 13; -const int SXF_TRANSFERSCALE = 1 << 14; -const int SXF_TRANSFERSPECIAL = 1 << 15; -const int SXF_CLEARCALLERSPECIAL = 1 << 16; -const int SXF_TRANSFERSTENCILCOL = 1 << 17; -const int SXF_TRANSFERALPHA = 1 << 18; -const int SXF_TRANSFERRENDERSTYLE = 1 << 19; -const int SXF_SETTARGET = 1 << 20; -const int SXF_SETTRACER = 1 << 21; -const int SXF_NOPOINTERS = 1 << 22; -const int SXF_ORIGINATOR = 1 << 23; -const int SXF_TRANSFERSPRITEFRAME = 1 << 24; -const int SXF_TRANSFERROLL = 1 << 25; -const int SXF_ISTARGET = 1 << 26; -const int SXF_ISMASTER = 1 << 27; -const int SXF_ISTRACER = 1 << 28; - -// Flags for A_Chase -enum -{ - CHF_FASTCHASE = 1, - CHF_NOPLAYACTIVE = 2, - CHF_NIGHTMAREFAST = 4, - CHF_RESURRECT = 8, - CHF_DONTMOVE = 16, - CHF_NORANDOMTURN = 32, - CHF_NODIRECTIONTURN = 64, - CHF_NOPOSTATTACKTURN = 128, - CHF_STOPIFBLOCKED = 256, - - CHF_DONTTURN = CHF_NORANDOMTURN | CHF_NOPOSTATTACKTURN | CHF_STOPIFBLOCKED -}; - -// Flags for A_LookEx -const int LOF_NOSIGHTCHECK = 1; -const int LOF_NOSOUNDCHECK = 2; -const int LOF_DONTCHASEGOAL = 4; -const int LOF_NOSEESOUND = 8; -const int LOF_FULLVOLSEESOUND = 16; -const int LOF_NOJUMP = 32; - -// Flags for A_Respawn -const int RSF_FOG = 1; -const int RSF_KEEPTARGET = 2; -const int RSF_TELEFRAG = 4; - -// Flags for A_JumpIfTargetInLOS and A_JumpIfInTargetLOS -enum -{ - JLOSF_PROJECTILE = 1, - JLOSF_NOSIGHT = 1 << 1, - JLOSF_CLOSENOFOV = 1 << 2, - JLOSF_CLOSENOSIGHT = 1 << 3, - JLOSF_CLOSENOJUMP = 1 << 4, - JLOSF_DEADNOJUMP = 1 << 5, - JLOSF_CHECKMASTER = 1 << 6, - JLOSF_TARGETLOS = 1 << 7, - JLOSF_FLIPFOV = 1 << 8, - JLOSF_ALLYNOJUMP = 1 << 9, - JLOSF_COMBATANTONLY = 1 << 10, - JLOSF_NOAUTOAIM = 1 << 11, - JLOSF_CHECKTRACER = 1 << 12, -}; - -// Flags for A_ChangeVelocity -const int CVF_RELATIVE = 1; -const int CVF_REPLACE = 2; - -// Flags for A_WeaponReady -const int WRF_NOBOB = 1; -const int WRF_NOSWITCH = 2; -const int WRF_NOPRIMARY = 4; -const int WRF_NOSECONDARY = 8; -const int WRF_NOFIRE = WRF_NOPRIMARY | WRF_NOSECONDARY; -const int WRF_ALLOWRELOAD = 16; -const int WRF_ALLOWZOOM = 32; -const int WRF_DISABLESWITCH = 64; -const int WRF_ALLOWUSER1 = 128; -const int WRF_ALLOWUSER2 = 256; -const int WRF_ALLOWUSER3 = 512; -const int WRF_ALLOWUSER4 = 1024; - -// Flags for A_SelectWeapon -const int SWF_SELECTPRIORITY = 1; - -// Morph constants -const int MRF_ADDSTAMINA = 1; -const int MRF_FULLHEALTH = 2; -const int MRF_UNDOBYTOMEOFPOWER = 4; -const int MRF_UNDOBYCHAOSDEVICE = 8; -const int MRF_FAILNOTELEFRAG = 16; -const int MRF_FAILNOLAUGH = 32; -const int MRF_WHENINVULNERABLE = 64; -const int MRF_LOSEACTUALWEAPON = 128; -const int MRF_NEWTIDBEHAVIOUR = 256; -const int MRF_UNDOBYDEATH = 512; -const int MRF_UNDOBYDEATHFORCED = 1024; -const int MRF_UNDOBYDEATHSAVES = 2048; -const int MRF_UNDOALWAYS = 4096; -const int MRF_TRANSFERTRANSLATION = 8192; - -// Flags for A_RailAttack and A_CustomRailgun -const int RGF_SILENT = 1; -const int RGF_NOPIERCING = 2; -const int RGF_EXPLICITANGLE = 4; -const int RGF_FULLBRIGHT = 8; -const int RGF_CENTERZ = 16; -const int RGF_NORANDOMPUFFZ = 32; - -// Flags for A_Mushroom -const int MSF_Standard = 0; -const int MSF_Classic = 1; -const int MSF_DontHurt = 2; - -// Flags for A_Explode -const int XF_HURTSOURCE = 1; -const int XF_NOTMISSILE = 4; -const int XF_EXPLICITDAMAGETYPE = 1 << 3; - -// Flags for A_RadiusThrust -const int RTF_AFFECTSOURCE = 1; -const int RTF_NOIMPACTDAMAGE = 2; -const int RTF_NOTMISSILE = 4; -const int RTF_THRUSTZ = 16; - -// Flags for A_RadiusDamageSelf -const int RDSF_BFGDAMAGE = 1; - -// Flags for A_Blast -const int BF_USEAMMO = 1; -const int BF_DONTWARN = 2; -const int BF_AFFECTBOSSES = 4; -const int BF_NOIMPACTDAMAGE = 8; - -// Flags for A_SeekerMissile -const int SMF_LOOK = 1; -const int SMF_PRECISE = 2; -const int SMF_CURSPEED = 4; - -// Flags for A_CustomPunch -const int CPF_USEAMMO = 1; -const int CPF_DAGGER = 2; -const int CPF_PULLIN = 4; -const int CPF_NORANDOMPUFFZ = 8; -const int CPF_NOTURN = 16; -const int CPF_STEALARMOR = 32; - -// Flags for A_CustomMissile -const int FPF_AIMATANGLE = 1; -const int FPF_TRANSFERTRANSLATION = 2; -const int FPF_NOAUTOAIM = 4; -const int FBF_PUFFTARGET = 64; -const int FBF_PUFFMASTER = 128; -const int FBF_PUFFTRACER = 256; - -// Flags for A_Teleport -enum -{ - TF_TELEFRAG = 0x00000001, // Allow telefrag in order to teleport. - TF_RANDOMDECIDE = 0x00000002, // Randomly fail based on health. (A_Srcr2Decide) - TF_FORCED = 0x00000004, // Forget what's in the way. TF_Telefrag takes precedence though. - TF_KEEPVELOCITY = 0x00000008, // Preserve velocity. - TF_KEEPANGLE = 0x00000010, // Keep angle. - TF_USESPOTZ = 0x00000020, // Set the z to the spot's z, instead of the floor. - TF_NOSRCFOG = 0x00000040, // Don't leave any fog behind when teleporting. - TF_NODESTFOG = 0x00000080, // Don't spawn any fog at the arrival position. - TF_USEACTORFOG = 0x00000100, // Use the actor's TeleFogSourceType and TeleFogDestType fogs. - TF_NOJUMP = 0x00000200, // Don't jump after teleporting. - TF_OVERRIDE = 0x00000400, // Ignore NOTELEPORT. - TF_SENSITIVEZ = 0x00000800, // Fail if the actor wouldn't fit in the position (for Z). - - TF_KEEPORIENTATION = TF_KEEPVELOCITY|TF_KEEPANGLE, - TF_NOFOG = TF_NOSRCFOG|TF_NODESTFOG, -}; - -// Flags for A_WolfAttack -const int WAF_NORANDOM = 1; -const int WAF_USEPUFF = 2; - -// Flags for A_RadiusGive -enum -{ - RGF_GIVESELF = 1, - RGF_PLAYERS = 1 << 1, - RGF_MONSTERS = 1 << 2, - RGF_OBJECTS = 1 << 3, - RGF_VOODOO = 1 << 4, - RGF_CORPSES = 1 << 5, - RGF_NOTARGET = 1 << 6, - RGF_NOTRACER = 1 << 7, - RGF_NOMASTER = 1 << 8, - RGF_CUBE = 1 << 9, - RGF_NOSIGHT = 1 << 10, - RGF_MISSILES = 1 << 11, - RGF_INCLUSIVE = 1 << 12, - RGF_ITEMS = 1 << 13, - RGF_KILLED = 1 << 14, - RGF_EXFILTER = 1 << 15, - RGF_EXSPECIES = 1 << 16, - RGF_EITHER = 1 << 17, -}; - -// Activation flags -enum -{ - THINGSPEC_Default = 0, - THINGSPEC_ThingActs = 1, - THINGSPEC_ThingTargets = 2, - THINGSPEC_TriggerTargets = 4, - THINGSPEC_MonsterTrigger = 8, - THINGSPEC_MissileTrigger = 16, - THINGSPEC_ClearSpecial = 32, - THINGSPEC_NoDeathSpecial = 64, - THINGSPEC_TriggerActs = 128, -}; -// Shorter aliases for same -const int AF_Default = 0; -const int AF_ThingActs = 1; -const int AF_ThingTargets = 2; -const int AF_TriggerTargets = 4; -const int AF_MonsterTrigger = 8; -const int AF_MissileTrigger = 16; -const int AF_ClearSpecial = 32; -const int AF_NoDeathSpecial = 64; -const int AF_TriggerActs = 128; - -// Flags for A_TakeInventory and A_TakeFromTarget -const int TIF_NOTAKEINFINITE = 1; - -// constants for A_PlaySound -enum -{ - CHAN_AUTO = 0, - CHAN_WEAPON = 1, - CHAN_VOICE = 2, - CHAN_ITEM = 3, - CHAN_BODY = 4, - CHAN_5 = 5, - CHAN_6 = 6, - CHAN_7 = 7, - - // modifier flags - CHAN_LISTENERZ = 8, - CHAN_MAYBE_LOCAL = 16, - CHAN_UI = 32, - CHAN_NOPAUSE = 64 -}; - -// sound attenuation values -const float ATTN_NONE = 0; -const float ATTN_NORM = 1; -const float ATTN_IDLE = 1.001; -const float ATTN_STATIC = 3; - -// For SetPlayerProprty action special -Const Int PROP_FROZEN = 0; -Const Int PROP_NOTARGET = 1; -Const Int PROP_INSTANTWEAPONSWITCH = 2; -Const Int PROP_FLY = 3; -Const Int PROP_TOTALLYFROZEN = 4; -Const Int PROP_INVULNERABILITY = 5; // (Deprecated) -Const Int PROP_STRENGTH = 6; // (Deprecated) -Const Int PROP_INVISIBILITY = 7; // (Deprecated) -Const Int PROP_RADIATIONSUIT = 8; // (Deprecated) -Const Int PROP_ALLMAP = 9; // (Deprecated) -Const Int PROP_INFRARED = 10; // (Deprecated) -Const Int PROP_WEAPONLEVEL2 = 11; // (Deprecated) -Const Int PROP_FLIGHT = 12; // (Deprecated) -Const Int PROP_SPEED = 15; // (Deprecated) -Const Int PROP_BUDDHA = 16; - -// Line_SetBlocking -Const Int BLOCKF_CREATURES = 1; -Const Int BLOCKF_MONSTERS = 2; -Const Int BLOCKF_PLAYERS = 4; -Const Int BLOCKF_FLOATERS = 8; -Const Int BLOCKF_PROJECTILES = 16; -Const Int BLOCKF_EVERYTHING = 32; -Const Int BLOCKF_RAILING = 64; -Const Int BLOCKF_USE = 128; - -// Pointer constants, bitfield-enabled - -Const Int AAPTR_DEFAULT = 0; -Const Int AAPTR_NULL = 0x1; -Const Int AAPTR_TARGET = 0x2; -Const Int AAPTR_MASTER = 0x4; -Const Int AAPTR_TRACER = 0x8; - -Const Int AAPTR_PLAYER_GETTARGET = 0x10; -Const Int AAPTR_PLAYER_GETCONVERSATION = 0x20; - -Const Int AAPTR_PLAYER1 = 0x40; -Const Int AAPTR_PLAYER2 = 0x80; -Const Int AAPTR_PLAYER3 = 0x100; -Const Int AAPTR_PLAYER4 = 0x200; -Const Int AAPTR_PLAYER5 = 0x400; -Const Int AAPTR_PLAYER6 = 0x800; -Const Int AAPTR_PLAYER7 = 0x1000; -Const Int AAPTR_PLAYER8 = 0x2000; - -Const Int AAPTR_FRIENDPLAYER = 0x4000; -Const Int AAPTR_LINETARGET = 0x8000; - -// Pointer operation flags - -Const Int PTROP_UNSAFETARGET = 1; -Const Int PTROP_UNSAFEMASTER = 2; -Const Int PTROP_NOSAFEGUARDS = PTROP_UNSAFETARGET|PTROP_UNSAFEMASTER; - - -// Flags for A_Warp - -Const Int WARPF_ABSOLUTEOFFSET = 0x1; -Const Int WARPF_ABSOLUTEANGLE = 0x2; -Const Int WARPF_USECALLERANGLE = 0x4; -Const Int WARPF_NOCHECKPOSITION = 0x8; -Const Int WARPF_INTERPOLATE = 0x10; -Const Int WARPF_WARPINTERPOLATION = 0x20; -Const Int WARPF_COPYINTERPOLATION = 0x40; -Const Int WARPF_STOP = 0x80; -Const Int WARPF_TOFLOOR = 0x100; -Const Int WARPF_TESTONLY = 0x200; -Const Int WAPRF_ABSOLUTEPOSITION = 0x400; -Const Int WARPF_ABSOLUTEPOSITION = 0x400; -Const Int WARPF_BOB = 0x800; -Const Int WARPF_MOVEPTR = 0x1000; -Const Int WARPF_USETID = 0x2000; -Const Int WARPF_COPYVELOCITY = 0x4000; -Const Int WARPF_COPYPITCH = 0x8000; - -// flags for A_SetPitch/SetAngle/SetRoll -const int SPF_FORCECLAMP = 1; -const int SPF_INTERPOLATE = 2; - - -// flags for A_CheckLOF - -enum -{ - CLOFF_NOAIM_VERT = 0x1, - CLOFF_NOAIM_HORZ = 0x2, - - CLOFF_JUMPENEMY = 0x4, - CLOFF_JUMPFRIEND = 0x8, - CLOFF_JUMPOBJECT = 0x10, - CLOFF_JUMPNONHOSTILE = 0x20, - - CLOFF_SKIPENEMY = 0x40, - CLOFF_SKIPFRIEND = 0x80, - CLOFF_SKIPOBJECT = 0x100, - CLOFF_SKIPNONHOSTILE = 0x200, - - CLOFF_MUSTBESHOOTABLE = 0x400, - - CLOFF_SKIPTARGET = 0x800, - CLOFF_ALLOWNULL = 0x1000, - CLOFF_CHECKPARTIAL = 0x2000, - - CLOFF_MUSTBEGHOST = 0x4000, - CLOFF_IGNOREGHOST = 0x8000, - - CLOFF_MUSTBESOLID = 0x10000, - CLOFF_BEYONDTARGET = 0x20000, - - CLOFF_FROMBASE = 0x40000, - CLOFF_MUL_HEIGHT = 0x80000, - CLOFF_MUL_WIDTH = 0x100000, - - CLOFF_JUMP_ON_MISS = 0x200000, - CLOFF_AIM_VERT_NOOFFSET = 0x400000, - - CLOFF_SETTARGET = 0x800000, - CLOFF_SETMASTER = 0x1000000, - CLOFF_SETTRACER = 0x2000000, - - CLOFF_SKIPOBSTACLES = CLOFF_SKIPENEMY|CLOFF_SKIPFRIEND|CLOFF_SKIPOBJECT|CLOFF_SKIPNONHOSTILE, - CLOFF_NOAIM = CLOFF_NOAIM_VERT|CLOFF_NOAIM_HORZ -}; - -// Flags for A_Kill (Master/Target/Tracer/Children/Siblings) series -enum -{ - KILS_FOILINVUL = 0x00000001, - KILS_KILLMISSILES = 0x00000002, - KILS_NOMONSTERS = 0x00000004, - KILS_FOILBUDDHA = 0x00000008, - KILS_EXFILTER = 0x00000010, - KILS_EXSPECIES = 0x00000020, - KILS_EITHER = 0x00000040, -}; - -// Flags for A_Damage (Master/Target/Tracer/Children/Siblings/Self) series -enum -{ - DMSS_FOILINVUL = 0x00000001, - DMSS_AFFECTARMOR = 0x00000002, - DMSS_KILL = 0x00000004, - DMSS_NOFACTOR = 0x00000008, - DMSS_FOILBUDDHA = 0x00000010, - DMSS_NOPROTECT = 0x00000020, - DMSS_EXFILTER = 0x00000040, - DMSS_EXSPECIES = 0x00000080, - DMSS_EITHER = 0x00000100, - DMSS_INFLICTORDMGTYPE = 0x00000200, -}; - -// Flags for A_AlertMonsters -const int AMF_TARGETEMITTER = 1; -const int AMF_TARGETNONPLAYER = 2; -const int AMF_EMITFROMTARGET = 4; - -// Flags for A_Remove* -enum -{ - RMVF_MISSILES = 0x00000001, - RMVF_NOMONSTERS = 0x00000002, - RMVF_MISC = 0x00000004, - RMVF_EVERYTHING = 0x00000008, - RMVF_EXFILTER = 0x00000010, - RMVF_EXSPECIES = 0x00000020, - RMVF_EITHER = 0x00000040, -}; - -// Flags for A_Fade* -enum -{ - FTF_REMOVE = 1 << 0, - FTF_CLAMP = 1 << 1, -}; - -// Flags for A_Face* -enum -{ - FAF_BOTTOM = 1, - FAF_MIDDLE = 2, - FAF_TOP = 4, - FAF_NODISTFACTOR = 8, -}; - -// Flags for A_QuakeEx -enum -{ - QF_RELATIVE = 1, - QF_SCALEDOWN = 1 << 1, - QF_SCALEUP = 1 << 2, - QF_MAX = 1 << 3, - QF_FULLINTENSITY = 1 << 4, - QF_WAVE = 1 << 5, -}; - -// A_CheckProximity flags -enum -{ - CPXF_ANCESTOR = 1, - CPXF_LESSOREQUAL = 1 << 1, - CPXF_NOZ = 1 << 2, - CPXF_COUNTDEAD = 1 << 3, - CPXF_DEADONLY = 1 << 4, - CPXF_EXACT = 1 << 5, - CPXF_SETTARGET = 1 << 6, - CPXF_SETMASTER = 1 << 7, - CPXF_SETTRACER = 1 << 8, - CPXF_FARTHEST = 1 << 9, - CPXF_CLOSEST = 1 << 10, - CPXF_SETONPTR = 1 << 11, - CPXF_CHECKSIGHT = 1 << 12, -}; - -// Flags for A_CheckBlock -// These flags only affect the calling actor('s pointer), not the ones being searched. -enum -{ - CBF_NOLINES = 1 << 0, //Don't check actors. - CBF_SETTARGET = 1 << 1, //Sets the caller/pointer's target to the actor blocking it. Actors only. - CBF_SETMASTER = 1 << 2, //^ but with master. - CBF_SETTRACER = 1 << 3, //^ but with tracer. - CBF_SETONPTR = 1 << 4, //Sets the pointer change on the actor doing the checking instead of self. - CBF_DROPOFF = 1 << 5, //Check for dropoffs. - CBF_NOACTORS = 1 << 6, //Don't check actors. - CBF_ABSOLUTEPOS = 1 << 7, //Absolute position for offsets. - CBF_ABSOLUTEANGLE = 1 << 8, //Absolute angle for offsets. -}; - -enum -{ - SPF_FULLBRIGHT = 1, - SPF_RELPOS = 1 << 1, - SPF_RELVEL = 1 << 2, - SPF_RELACCEL = 1 << 3, - SPF_RELANG = 1 << 4, - SPF_NOTIMEFREEZE = 1 << 5, - - SPF_RELATIVE = SPF_RELPOS|SPF_RELVEL|SPF_RELACCEL|SPF_RELANG -}; - -//Flags for A_FaceMovementDirection -enum -{ - FMDF_NOPITCH = 1 << 0, - FMDF_INTERPOLATE = 1 << 1, - FMDF_NOANGLE = 1 << 2, -}; - -// Flags for GetZAt -enum -{ - GZF_ABSOLUTEPOS = 1, // Use the absolute position instead of an offsetted one. - GZF_ABSOLUTEANG = 1 << 1, // Don't add the actor's angle to the parameter. - GZF_CEILING = 1 << 2, // Check the ceiling instead of the floor. - GZF_3DRESTRICT = 1 << 3, // Ignore midtextures and 3D floors above the pointer's z. - GZF_NOPORTALS = 1 << 4, // Don't pass through any portals. - GZF_NO3DFLOOR = 1 << 5, // Pass all 3D floors. -}; - -// Flags for A_WeaponOffset -enum -{ - WOF_KEEPX = 1, - WOF_KEEPY = 1 << 1, - WOF_ADD = 1 << 2, -}; - -// Flags for psprite layers -enum -{ - PSPF_ADDWEAPON = 1 << 0, - PSPF_ADDBOB = 1 << 1, - PSPF_POWDOUBLE = 1 << 2, - PSPF_CVARFAST = 1 << 3, - PSPF_FLIP = 1 << 6, -}; - -// Default psprite layers -enum -{ - PSP_WEAPON = 1, - PSP_FLASH = 1000, -}; - -enum -{ - // These are the original inputs sent by the player. - INPUT_OLDBUTTONS, - INPUT_BUTTONS, - INPUT_PITCH, - INPUT_YAW, - INPUT_ROLL, - INPUT_FORWARDMOVE, - INPUT_SIDEMOVE, - INPUT_UPMOVE, - - // These are the inputs, as modified by P_PlayerThink(). - // Most of the time, these will match the original inputs, but - // they can be different if a player is frozen or using a - // chainsaw. - MODINPUT_OLDBUTTONS, - MODINPUT_BUTTONS, - MODINPUT_PITCH, - MODINPUT_YAW, - MODINPUT_ROLL, - MODINPUT_FORWARDMOVE, - MODINPUT_SIDEMOVE, - MODINPUT_UPMOVE -}; - -enum -{ - BT_ATTACK = 1<<0, // Press "Fire". - BT_USE = 1<<1, // Use button, to open doors, activate switches. - BT_JUMP = 1<<2, - BT_CROUCH = 1<<3, - BT_TURN180 = 1<<4, - BT_ALTATTACK = 1<<5, // Press your other "Fire". - BT_RELOAD = 1<<6, // [XA] Reload key. Causes state jump in A_WeaponReady. - BT_ZOOM = 1<<7, // [XA] Zoom key. Ditto. - - // The rest are all ignored by the play simulation and are for scripts. - BT_SPEED = 1<<8, - BT_STRAFE = 1<<9, - - BT_MOVERIGHT = 1<<10, - BT_MOVELEFT = 1<<11, - BT_BACK = 1<<12, - BT_FORWARD = 1<<13, - BT_RIGHT = 1<<14, - BT_LEFT = 1<<15, - BT_LOOKUP = 1<<16, - BT_LOOKDOWN = 1<<17, - BT_MOVEUP = 1<<18, - BT_MOVEDOWN = 1<<19, - BT_SHOWSCORES = 1<<20, - - BT_USER1 = 1<<21, - BT_USER2 = 1<<22, - BT_USER3 = 1<<23, - BT_USER4 = 1<<24, -}; -// Flags for GetAngle -enum -{ - GAF_RELATIVE = 1, - GAF_SWITCH = 1 << 1, -}; - -//Flags for A_CopySpriteFrame -enum -{ - CPSF_NOSPRITE = 1, - CPSF_NOFRAME = 1 << 1, -}; - -//Flags for A_SetMaskRotation -enum -{ - VRF_NOANGLESTART = 1, - VRF_NOANGLEEND = 1 << 1, - VRF_NOPITCHSTART = 1 << 2, - VRF_NOPITCHEND = 1 << 3, - - VRF_NOANGLE = VRF_NOANGLESTART|VRF_NOANGLEEND, - VRF_NOPITCH = VRF_NOPITCHSTART|VRF_NOPITCHEND, -}; - -enum -{ - STYLE_None, - STYLE_Normal, - STYLE_Fuzzy, - STYLE_SoulTrans, - STYLE_OptFuzzy, - STYLE_Stencil, - STYLE_Translucent, - STYLE_Add, - STYLE_Shaded, - STYLE_TranslucentStencil, - STYLE_Shadow, - STYLE_Subtract, - STYLE_AddStencil, - STYLE_AddShaded, -}; diff --git a/wadsrc/static/actors/doom/arachnotron.txt b/wadsrc/static/actors/doom/arachnotron.txt deleted file mode 100644 index 1a70a11d13..0000000000 --- a/wadsrc/static/actors/doom/arachnotron.txt +++ /dev/null @@ -1,85 +0,0 @@ -//=========================================================================== -// -// Arachnotron -// -//=========================================================================== -ACTOR Arachnotron -{ - Health 500 - Radius 64 - Height 64 - Mass 600 - Speed 12 - PainChance 128 - Monster - +FLOORCLIP - +BOSSDEATH - SeeSound "baby/sight" - PainSound "baby/pain" - DeathSound "baby/death" - ActiveSound "baby/active" - Obituary "$OB_BABY" - States - { - Spawn: - BSPI AB 10 A_Look - Loop - See: - BSPI A 20 - BSPI A 3 A_BabyMetal - BSPI ABBCC 3 A_Chase - BSPI D 3 A_BabyMetal - BSPI DEEFF 3 A_Chase - Goto See+1 - Missile: - BSPI A 20 BRIGHT A_FaceTarget - BSPI G 4 BRIGHT A_BspiAttack - BSPI H 4 BRIGHT - BSPI H 1 BRIGHT A_SpidRefire - Goto Missile+1 - Pain: - BSPI I 3 - BSPI I 3 A_Pain - Goto See+1 - Death: - BSPI J 20 A_Scream - BSPI K 7 A_NoBlocking - BSPI LMNO 7 - BSPI P -1 A_BossDeath - Stop - Raise: - BSPI P 5 - BSPI ONMLKJ 5 - Goto See+1 - } -} - -//=========================================================================== -// -// Arachnotron plasma -// -//=========================================================================== -ACTOR ArachnotronPlasma -{ - Radius 13 - Height 8 - Speed 25 - Damage 5 - Projectile - +RANDOMIZE - RenderStyle Add - Alpha 0.75 - SeeSound "baby/attack" - DeathSound "baby/shotx" - States - { - Spawn: - APLS AB 5 BRIGHT - Loop - Death: - APBX ABCDE 5 BRIGHT - Stop - } -} - - diff --git a/wadsrc/static/actors/doom/archvile.txt b/wadsrc/static/actors/doom/archvile.txt deleted file mode 100644 index f2c5d6ab47..0000000000 --- a/wadsrc/static/actors/doom/archvile.txt +++ /dev/null @@ -1,83 +0,0 @@ -//=========================================================================== -// -// Arch Vile -// -//=========================================================================== - -ACTOR Archvile -{ - Health 700 - Radius 20 - Height 56 - Mass 500 - Speed 15 - PainChance 10 - Monster - MaxTargetRange 896 - +QUICKTORETALIATE - +FLOORCLIP - +NOTARGET - SeeSound "vile/sight" - PainSound "vile/pain" - DeathSound "vile/death" - ActiveSound "vile/active" - MeleeSound "vile/stop" - Obituary "$OB_VILE" - States - { - Spawn: - VILE AB 10 A_Look - Loop - See: - VILE AABBCCDDEEFF 2 A_VileChase - Loop - Missile: - VILE G 0 BRIGHT A_VileStart - VILE G 10 BRIGHT A_FaceTarget - VILE H 8 BRIGHT A_VileTarget - VILE IJKLMN 8 BRIGHT A_FaceTarget - VILE O 8 BRIGHT A_VileAttack - VILE P 20 BRIGHT - Goto See - Heal: - VILE "[\]" 10 BRIGHT - Goto See - Pain: - VILE Q 5 - VILE Q 5 A_Pain - Goto See - Death: - VILE Q 7 - VILE R 7 A_Scream - VILE S 7 A_NoBlocking - VILE TUVWXY 7 - VILE Z -1 - Stop - } -} - - -//=========================================================================== -// -// Arch Vile Fire -// -//=========================================================================== - -ACTOR ArchvileFire -{ - +NOBLOCKMAP +NOGRAVITY - RenderStyle Add - Alpha 1 - States - { - Spawn: - FIRE A 2 BRIGHT A_StartFire - FIRE BAB 2 BRIGHT A_Fire - FIRE C 2 BRIGHT A_FireCrackle - FIRE BCBCDCDCDEDED 2 BRIGHT A_Fire - FIRE E 2 BRIGHT A_FireCrackle - FIRE FEFEFGHGHGH 2 BRIGHT A_Fire - Stop - } -} - diff --git a/wadsrc/static/actors/doom/bossbrain.txt b/wadsrc/static/actors/doom/bossbrain.txt deleted file mode 100644 index 67b6da7d61..0000000000 --- a/wadsrc/static/actors/doom/bossbrain.txt +++ /dev/null @@ -1,120 +0,0 @@ - -//=========================================================================== -// -// Boss Brain -// -//=========================================================================== - -ACTOR BossBrain -{ - Health 250 - Mass 10000000 - PainChance 255 - +SOLID +SHOOTABLE - +NOICEDEATH - +OLDRADIUSDMG - PainSound "brain/pain" - DeathSound "brain/death" - States - { - BrainExplode: - MISL BC 10 Bright - MISL D 10 A_BrainExplode - Stop - Spawn: - BBRN A -1 - Stop - Pain: - BBRN B 36 A_BrainPain - Goto Spawn - Death: - BBRN A 100 A_BrainScream - BBRN AA 10 - BBRN A -1 A_BrainDie - Stop - } -} - - -//=========================================================================== -// -// Boss Eye -// -//=========================================================================== - -ACTOR BossEye -{ - Height 32 - +NOBLOCKMAP - +NOSECTOR - States - { - Spawn: - SSWV A 10 A_Look - Loop - See: - SSWV A 181 A_BrainAwake - SSWV A 150 A_BrainSpit - Wait - } -} - -//=========================================================================== -// -// Boss Target -// -//=========================================================================== - -ACTOR BossTarget : SpecialSpot -{ - Height 32 - +NOBLOCKMAP - +NOSECTOR -} - -//=========================================================================== -// -// Spawn shot -// -//=========================================================================== - -ACTOR SpawnShot -{ - Radius 6 - Height 32 - Speed 10 - Damage 3 - Projectile - +NOCLIP - -ACTIVATEPCROSS - +RANDOMIZE - SeeSound "brain/spit" - DeathSound "brain/cubeboom" - States - { - Spawn: - BOSF A 3 BRIGHT A_SpawnSound - BOSF BCD 3 BRIGHT A_SpawnFly - Loop - } -} - -//=========================================================================== -// -// Spawn fire -// -//=========================================================================== - -ACTOR SpawnFire -{ - Height 78 - +NOBLOCKMAP - +NOGRAVITY - RenderStyle Add - States - { - Spawn: - FIRE ABCDEFGH 4 Bright A_Fire - Stop - } -} diff --git a/wadsrc/static/actors/doom/bruiser.txt b/wadsrc/static/actors/doom/bruiser.txt deleted file mode 100644 index 0a2bdcff64..0000000000 --- a/wadsrc/static/actors/doom/bruiser.txt +++ /dev/null @@ -1,131 +0,0 @@ -//=========================================================================== -// -// Baron of Hell -// -//=========================================================================== -ACTOR BaronOfHell -{ - Health 1000 - Radius 24 - Height 64 - Mass 1000 - Speed 8 - PainChance 50 - Monster - +FLOORCLIP - +BOSSDEATH - SeeSound "baron/sight" - PainSound "baron/pain" - DeathSound "baron/death" - ActiveSound "baron/active" - Obituary "$OB_BARON" - HitObituary "$OB_BARONHIT" - States - { - Spawn: - BOSS AB 10 A_Look - Loop - See: - BOSS AABBCCDD 3 A_Chase - Loop - Melee: - Missile: - BOSS EF 8 A_FaceTarget - BOSS G 8 A_BruisAttack - Goto See - Pain: - BOSS H 2 - BOSS H 2 A_Pain - Goto See - Death: - BOSS I 8 - BOSS J 8 A_Scream - BOSS K 8 - BOSS L 8 A_NoBlocking - BOSS MN 8 - BOSS O -1 A_BossDeath - Stop - Raise: - BOSS O 8 - BOSS NMLKJI 8 - Goto See - } -} - -//=========================================================================== -// -// Hell Knight -// -//=========================================================================== -ACTOR HellKnight : BaronOfHell -{ - Health 500 - -BOSSDEATH - SeeSound "knight/sight" - ActiveSound "knight/active" - PainSound "knight/pain" - DeathSound "knight/death" - HitObituary "$OB_KNIGHTHIT" - Obituary "$OB_KNIGHT" - States - { - Spawn: - BOS2 AB 10 A_Look - Loop - See: - BOS2 AABBCCDD 3 A_Chase - Loop - Melee: - Missile: - BOS2 EF 8 A_FaceTarget - BOS2 G 8 A_BruisAttack - Goto See - Pain: - BOS2 H 2 - BOS2 H 2 A_Pain - Goto See - Death: - BOS2 I 8 - BOS2 J 8 A_Scream - BOS2 K 8 - BOS2 L 8 A_NoBlocking - BOS2 MN 8 - BOS2 O -1 - Stop - Raise: - BOS2 O 8 - BOS2 NMLKJI 8 - Goto See - } -} - -//=========================================================================== -// -// Baron slime ball -// -//=========================================================================== -ACTOR BaronBall -{ - Radius 6 - Height 16 - Speed 15 - FastSpeed 20 - Damage 8 - Projectile - +RANDOMIZE - RenderStyle Add - Alpha 1 - SeeSound "baron/attack" - DeathSound "baron/shotx" - Decal "BaronScorch" - States - { - Spawn: - BAL7 AB 4 BRIGHT - Loop - Death: - BAL7 CDE 6 BRIGHT - Stop - } -} - diff --git a/wadsrc/static/actors/doom/cacodemon.txt b/wadsrc/static/actors/doom/cacodemon.txt deleted file mode 100644 index db2ee76571..0000000000 --- a/wadsrc/static/actors/doom/cacodemon.txt +++ /dev/null @@ -1,82 +0,0 @@ -//=========================================================================== -// -// Cacodemon -// -//=========================================================================== -ACTOR Cacodemon -{ - Health 400 - Radius 31 - Height 56 - Mass 400 - Speed 8 - PainChance 128 - Monster - +FLOAT +NOGRAVITY - SeeSound "caco/sight" - PainSound "caco/pain" - DeathSound "caco/death" - ActiveSound "caco/active" - Obituary "$OB_CACO" - HitObituary "$OB_CACOHIT" - States - { - Spawn: - HEAD A 10 A_Look - Loop - See: - HEAD A 3 A_Chase - Loop - Missile: - HEAD B 5 A_FaceTarget - HEAD C 5 A_FaceTarget - HEAD D 5 BRIGHT A_HeadAttack - Goto See - Pain: - HEAD E 3 - HEAD E 3 A_Pain - HEAD F 6 - Goto See - Death: - HEAD G 8 - HEAD H 8 A_Scream - HEAD I 8 - HEAD J 8 - HEAD K 8 A_NoBlocking - HEAD L -1 A_SetFloorClip - Stop - Raise: - HEAD L 8 A_UnSetFloorClip - HEAD KJIHG 8 - Goto See - } -} - -//=========================================================================== -// -// Cacodemon plasma ball -// -//=========================================================================== -ACTOR CacodemonBall -{ - Radius 6 - Height 8 - Speed 10 - FastSpeed 20 - Damage 5 - Projectile - +RANDOMIZE - RenderStyle Add - Alpha 1 - SeeSound "caco/attack" - DeathSound "caco/shotx" - States - { - Spawn: - BAL2 AB 4 BRIGHT - Loop - Death: - BAL2 CDE 6 BRIGHT - Stop - } -} diff --git a/wadsrc/static/actors/doom/cyberdemon.txt b/wadsrc/static/actors/doom/cyberdemon.txt deleted file mode 100644 index 9f9c986f4a..0000000000 --- a/wadsrc/static/actors/doom/cyberdemon.txt +++ /dev/null @@ -1,61 +0,0 @@ - -//=========================================================================== -// -// Cyberdemon -// -//=========================================================================== -ACTOR Cyberdemon -{ - Health 4000 - Radius 40 - Height 110 - Mass 1000 - Speed 16 - PainChance 20 - Monster - MinMissileChance 160 - +BOSS - +MISSILEMORE - +FLOORCLIP - +NORADIUSDMG - +DONTMORPH - +BOSSDEATH - SeeSound "cyber/sight" - PainSound "cyber/pain" - DeathSound "cyber/death" - ActiveSound "cyber/active" - Obituary "$OB_CYBORG" - States - { - Spawn: - CYBR AB 10 A_Look - Loop - See: - CYBR A 3 A_Hoof - CYBR ABBCC 3 A_Chase - CYBR D 3 A_Metal - CYBR D 3 A_Chase - Loop - Missile: - CYBR E 6 A_FaceTarget - CYBR F 12 A_CyberAttack - CYBR E 12 A_FaceTarget - CYBR F 12 A_CyberAttack - CYBR E 12 A_FaceTarget - CYBR F 12 A_CyberAttack - Goto See - Pain: - CYBR G 10 A_Pain - Goto See - Death: - CYBR H 10 - CYBR I 10 A_Scream - CYBR JKL 10 - CYBR M 10 A_NoBlocking - CYBR NO 10 - CYBR P 30 - CYBR P -1 A_BossDeath - Stop - } -} - diff --git a/wadsrc/static/actors/doom/demon.txt b/wadsrc/static/actors/doom/demon.txt deleted file mode 100644 index 3680b24e96..0000000000 --- a/wadsrc/static/actors/doom/demon.txt +++ /dev/null @@ -1,71 +0,0 @@ -//=========================================================================== -// -// Pink Demon -// -//=========================================================================== -ACTOR Demon -{ - Health 150 - PainChance 180 - Speed 10 - Radius 30 - Height 56 - Mass 400 - Monster - +FLOORCLIP - SeeSound "demon/sight" - AttackSound "demon/melee" - PainSound "demon/pain" - DeathSound "demon/death" - ActiveSound "demon/active" - Obituary "$OB_DEMONHIT" - States - { - Spawn: - SARG AB 10 A_Look - Loop - See: - SARG AABBCCDD 2 Fast A_Chase - Loop - Melee: - SARG EF 8 Fast A_FaceTarget - SARG G 8 Fast A_SargAttack - Goto See - Pain: - SARG H 2 Fast - SARG H 2 Fast A_Pain - Goto See - Death: - SARG I 8 - SARG J 8 A_Scream - SARG K 4 - SARG L 4 A_NoBlocking - SARG M 4 - SARG N -1 - Stop - Raise: - SARG N 5 - SARG MLKJI 5 - Goto See - } -} - -//=========================================================================== -// -// Spectre -// -//=========================================================================== -ACTOR Spectre : Demon -{ - +SHADOW - RenderStyle OptFuzzy - Alpha 0.5 - SeeSound "spectre/sight" - AttackSound "spectre/melee" - PainSound "spectre/pain" - DeathSound "spectre/death" - ActiveSound "spectre/active" - HitObituary "$OB_SPECTREHIT" -} - - diff --git a/wadsrc/static/actors/doom/doomammo.txt b/wadsrc/static/actors/doom/doomammo.txt deleted file mode 100644 index bc931c08fb..0000000000 --- a/wadsrc/static/actors/doom/doomammo.txt +++ /dev/null @@ -1,142 +0,0 @@ -// Clip -------------------------------------------------------------------- - -ACTOR Clip : Ammo -{ - Inventory.PickupMessage "$GOTCLIP" - Inventory.Amount 10 - Inventory.MaxAmount 200 - Ammo.BackpackAmount 10 - Ammo.BackpackMaxAmount 400 - Inventory.Icon "CLIPA0" - States - { - Spawn: - CLIP A -1 - Stop - } -} - -// Clip box ---------------------------------------------------------------- - -ACTOR ClipBox : Clip -{ - Inventory.PickupMessage "$GOTCLIPBOX" - Inventory.Amount 50 - States - { - Spawn: - AMMO A -1 - Stop - } -} - -// Rocket ------------------------------------------------------------------ - -ACTOR RocketAmmo : Ammo -{ - Inventory.PickupMessage "$GOTROCKET" - Inventory.Amount 1 - Inventory.MaxAmount 50 - Ammo.BackpackAmount 1 - Ammo.BackpackMaxAmount 100 - Inventory.Icon "ROCKA0" - States - { - Spawn: - ROCK A -1 - Stop - } -} - -// Rocket box -------------------------------------------------------------- - -ACTOR RocketBox : RocketAmmo -{ - Inventory.PickupMessage "$GOTROCKBOX" - Inventory.Amount 5 - States - { - Spawn: - BROK A -1 - Stop - } -} - -// Cell -------------------------------------------------------------------- - -ACTOR Cell : Ammo -{ - Inventory.PickupMessage "$GOTCELL" - Inventory.Amount 20 - Inventory.MaxAmount 300 - Ammo.BackpackAmount 20 - Ammo.BackpackMaxAmount 600 - Inventory.Icon "CELLA0" - States - { - Spawn: - CELL A -1 - Stop - } -} - -// Cell pack --------------------------------------------------------------- - -ACTOR CellPack : Cell -{ - Inventory.PickupMessage "$GOTCELLBOX" - Inventory.Amount 100 - States - { - Spawn: - CELP A -1 - Stop - } -} - -// Shells ------------------------------------------------------------------ - -ACTOR Shell : Ammo -{ - Inventory.PickupMessage "$GOTSHELLS" - Inventory.Amount 4 - Inventory.MaxAmount 50 - Ammo.BackpackAmount 4 - Ammo.BackpackMaxAmount 100 - Inventory.Icon "SHELA0" - States - { - Spawn: - SHEL A -1 - Stop - } -} - -// Shell box --------------------------------------------------------------- - -ACTOR ShellBox : Shell -{ - Inventory.PickupMessage "$GOTSHELLBOX" - Inventory.Amount 20 - States - { - Spawn: - SBOX A -1 - Stop - } -} - -// Backpack --------------------------------------------------------------- - -ACTOR Backpack : BackpackItem -{ - Height 26 - Inventory.PickupMessage "$GOTBACKPACK" - States - { - Spawn: - BPAK A -1 - Stop - } -} - diff --git a/wadsrc/static/actors/doom/doomarmor.txt b/wadsrc/static/actors/doom/doomarmor.txt deleted file mode 100644 index 578c4f0fe9..0000000000 --- a/wadsrc/static/actors/doom/doomarmor.txt +++ /dev/null @@ -1,60 +0,0 @@ - -// Armor bonus -------------------------------------------------------------- - -Actor ArmorBonus : BasicArmorBonus -{ - Radius 20 - Height 16 - Inventory.Pickupmessage "$GOTARMBONUS" - Inventory.Icon "BON2A0" - Armor.Savepercent 33.335 - Armor.Saveamount 1 - Armor.Maxsaveamount 200 - +COUNTITEM - +INVENTORY.ALWAYSPICKUP - States - { - Spawn: - BON2 ABCDCB 6 - loop - } -} - -// Green armor -------------------------------------------------------------- - -Actor GreenArmor : BasicArmorPickup -{ - Radius 20 - Height 16 - Inventory.Pickupmessage "$GOTARMOR" - Inventory.Icon "ARM1A0" - Armor.SavePercent 33.335 - Armor.SaveAmount 100 - States - { - Spawn: - ARM1 A 6 - ARM1 B 7 bright - loop - } -} - -// Blue armor --------------------------------------------------------------- - -Actor BlueArmor : BasicArmorPickup -{ - Radius 20 - Height 16 - Inventory.Pickupmessage "$GOTMEGA" - Inventory.Icon "ARM2A0" - Armor.Savepercent 50 - Armor.Saveamount 200 - States - { - Spawn: - ARM2 A 6 - ARM2 B 6 bright - loop - } -} - diff --git a/wadsrc/static/actors/doom/doomartifacts.txt b/wadsrc/static/actors/doom/doomartifacts.txt deleted file mode 100644 index e9caa5f113..0000000000 --- a/wadsrc/static/actors/doom/doomartifacts.txt +++ /dev/null @@ -1,171 +0,0 @@ -// Invulnerability Sphere --------------------------------------------------- - -ACTOR InvulnerabilitySphere : PowerupGiver -{ - +COUNTITEM - +INVENTORY.AUTOACTIVATE - +INVENTORY.ALWAYSPICKUP - +INVENTORY.BIGPOWERUP - Inventory.MaxAmount 0 - Powerup.Type Invulnerable - Powerup.Color InverseMap - Inventory.PickupMessage "$GOTINVUL" - States - { - Spawn: - PINV ABCD 6 Bright - Loop - } -} - -// Soulsphere -------------------------------------------------------------- - -ACTOR Soulsphere : Health -{ - +COUNTITEM - +INVENTORY.AUTOACTIVATE - +INVENTORY.ALWAYSPICKUP - +INVENTORY.FANCYPICKUPSOUND - Inventory.Amount 100 - Inventory.MaxAmount 200 - Inventory.PickupMessage "$GOTSUPER" - Inventory.PickupSound "misc/p_pkup" - States - { - Spawn: - SOUL ABCDCB 6 Bright - Loop - } -} - -// Mega sphere -------------------------------------------------------------- - -ACTOR MegasphereHealth : Health // for manipulation by Dehacked -{ - Inventory.Amount 200 - Inventory.MaxAmount 200 - +INVENTORY.ALWAYSPICKUP -} - -// DeHackEd can only modify the blue armor's type, not the megasphere's. -actor BlueArmorForMegasphere : BlueArmor -{ - Armor.SavePercent 50 - Armor.SaveAmount 200 -} - -ACTOR Megasphere : CustomInventory -{ - +COUNTITEM - +INVENTORY.ALWAYSPICKUP - Inventory.PickupMessage "$GOTMSPHERE" - Inventory.PickupSound "misc/p_pkup" - States - { - Spawn: - MEGA ABCD 6 BRIGHT - Loop - Pickup: - TNT1 A 0 A_GiveInventory("BlueArmorForMegasphere", 1) - TNT1 A 0 A_GiveInventory("MegasphereHealth", 1) - Stop - } -} - -// Invisibility ------------------------------------------------------------- - -ACTOR BlurSphere : PowerupGiver -{ - +COUNTITEM - +VISIBILITYPULSE - +INVENTORY.AUTOACTIVATE - +INVENTORY.ALWAYSPICKUP - +INVENTORY.BIGPOWERUP - Inventory.MaxAmount 0 - Powerup.Type Invisibility - RenderStyle Translucent - Inventory.PickupMessage "$GOTINVIS" - States - { - Spawn: - PINS ABCD 6 Bright - Loop - } -} - -// Radiation suit (aka iron feet) ------------------------------------------- - -ACTOR RadSuit : PowerupGiver -{ - Height 46 - +INVENTORY.AUTOACTIVATE - +INVENTORY.ALWAYSPICKUP - Inventory.MaxAmount 0 - Inventory.PickupMessage "$GOTSUIT" - Powerup.Type IronFeet - States - { - Spawn: - SUIT A -1 Bright - Stop - } -} - -// infrared ----------------------------------------------------------------- - -ACTOR Infrared : PowerupGiver -{ - +COUNTITEM - +INVENTORY.AUTOACTIVATE - +INVENTORY.ALWAYSPICKUP - Inventory.MaxAmount 0 - Powerup.Type LightAmp - Inventory.PickupMessage "$GOTVISOR" - States - { - Spawn: - PVIS A 6 Bright - PVIS B 6 - Loop - } -} - -// Allmap ------------------------------------------------------------------- - -ACTOR Allmap : MapRevealer -{ - +COUNTITEM - +INVENTORY.FANCYPICKUPSOUND - +INVENTORY.ALWAYSPICKUP - Inventory.MaxAmount 0 - Inventory.PickupSound "misc/p_pkup" - Inventory.PickupMessage "$GOTMAP" - States - { - Spawn: - PMAP ABCDCB 6 Bright - Loop - } -} - -// Berserk ------------------------------------------------------------------ - -ACTOR Berserk : CustomInventory -{ - +COUNTITEM - +INVENTORY.ALWAYSPICKUP - Inventory.PickupMessage "$GOTBERSERK" - Inventory.PickupSound "misc/p_pkup" - States - { - Spawn: - PSTR A -1 - Stop - Pickup: - TNT1 A 0 A_GiveInventory("PowerStrength") - TNT1 A 0 HealThing(100, 0) - TNT1 A 0 A_SelectWeapon("Fist") - Stop - } -} - diff --git a/wadsrc/static/actors/doom/doomdecorations.txt b/wadsrc/static/actors/doom/doomdecorations.txt deleted file mode 100644 index 4206c09ed7..0000000000 --- a/wadsrc/static/actors/doom/doomdecorations.txt +++ /dev/null @@ -1,753 +0,0 @@ - -// Tech lamp --------------------------------------------------------------- - -ACTOR TechLamp -{ - Radius 16 - Height 80 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - TLMP ABCD 4 BRIGHT - Loop - } -} - -// Tech lamp 2 ------------------------------------------------------------- - -ACTOR TechLamp2 -{ - Radius 16 - Height 60 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - TLP2 ABCD 4 BRIGHT - Loop - } -} - -// Column ------------------------------------------------------------------ - -ACTOR Column -{ - Radius 16 - Height 48 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - COLU A -1 BRIGHT - Stop - } -} - -// Tall green column ------------------------------------------------------- - -ACTOR TallGreenColumn -{ - Radius 16 - Height 52 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - COL1 A -1 - Stop - } -} - -// Short green column ------------------------------------------------------ - -ACTOR ShortGreenColumn -{ - Radius 16 - Height 40 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - COL2 A -1 - Stop - } -} - -// Tall red column --------------------------------------------------------- - -ACTOR TallRedColumn -{ - Radius 16 - Height 52 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - COL3 A -1 - Stop - } -} - -// Short red column -------------------------------------------------------- - -ACTOR ShortRedColumn -{ - Radius 16 - Height 40 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - COL4 A -1 - Stop - } -} - -// Skull column ------------------------------------------------------------ - -ACTOR SkullColumn -{ - Radius 16 - Height 40 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - COL6 A -1 - Stop - } -} - -// Heart column ------------------------------------------------------------ - -ACTOR HeartColumn -{ - Radius 16 - Height 40 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - COL5 AB 14 - Loop - } -} - -// Evil eye ---------------------------------------------------------------- - -ACTOR EvilEye -{ - Radius 16 - Height 54 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - CEYE ABCB 6 BRIGHT - Loop - } -} - -// Floating skull ---------------------------------------------------------- - -ACTOR FloatingSkull -{ - Radius 16 - Height 26 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - FSKU ABC 6 BRIGHT - Loop - } -} - -// Torch tree -------------------------------------------------------------- - -ACTOR TorchTree -{ - Radius 16 - Height 56 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - TRE1 A -1 - Stop - } -} - -// Blue torch -------------------------------------------------------------- - -ACTOR BlueTorch -{ - Radius 16 - Height 68 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - TBLU ABCD 4 BRIGHT - Loop - } -} - -// Green torch ------------------------------------------------------------- - -ACTOR GreenTorch -{ - Radius 16 - Height 68 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - TGRN ABCD 4 BRIGHT - Loop - } -} - -// Red torch --------------------------------------------------------------- - -ACTOR RedTorch -{ - Radius 16 - Height 68 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - TRED ABCD 4 BRIGHT - Loop - } -} - -// Short blue torch -------------------------------------------------------- - -ACTOR ShortBlueTorch -{ - Radius 16 - Height 37 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - SMBT ABCD 4 BRIGHT - Loop - } -} - -// Short green torch ------------------------------------------------------- - -ACTOR ShortGreenTorch -{ - Radius 16 - Height 37 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - SMGT ABCD 4 BRIGHT - Loop - } -} - -// Short red torch --------------------------------------------------------- - -ACTOR ShortRedTorch -{ - Radius 16 - Height 37 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - SMRT ABCD 4 BRIGHT - Loop - } -} - -// Stalagtite -------------------------------------------------------------- - -ACTOR Stalagtite -{ - Radius 16 - Height 40 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - SMIT A -1 - Stop - } -} - -// Tech pillar ------------------------------------------------------------- - -ACTOR TechPillar -{ - Radius 16 - Height 128 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - ELEC A -1 - Stop - } -} - -// Candle stick ------------------------------------------------------------ - -ACTOR Candlestick -{ - Radius 20 - Height 14 - ProjectilePassHeight -16 - States - { - Spawn: - CAND A -1 BRIGHT - Stop - } -} - -// Candelabra -------------------------------------------------------------- - -ACTOR Candelabra -{ - Radius 16 - Height 60 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - CBRA A -1 BRIGHT - Stop - } -} - -// Bloody twitch ----------------------------------------------------------- - -ACTOR BloodyTwitch -{ - Radius 16 - Height 68 - +SOLID - +NOGRAVITY - +SPAWNCEILING - States - { - Spawn: - GOR1 A 10 - GOR1 B 15 - GOR1 C 8 - GOR1 B 6 - Loop - } -} - -// Meat 2 ------------------------------------------------------------------ - -ACTOR Meat2 -{ - Radius 16 - Height 84 - +SOLID - +NOGRAVITY - +SPAWNCEILING - States - { - Spawn: - GOR2 A -1 - Stop - } -} - -// Meat 3 ------------------------------------------------------------------ - -ACTOR Meat3 -{ - Radius 16 - Height 84 - +SOLID - +NOGRAVITY - +SPAWNCEILING - States - { - Spawn: - GOR3 A -1 - Stop - } -} - -// Meat 4 ------------------------------------------------------------------ - -ACTOR Meat4 -{ - Radius 16 - Height 68 - +SOLID - +NOGRAVITY - +SPAWNCEILING - States - { - Spawn: - GOR4 A -1 - Stop - } -} - -// Meat 5 ------------------------------------------------------------------ - -ACTOR Meat5 -{ - Radius 16 - Height 52 - +SOLID - +NOGRAVITY - +SPAWNCEILING - States - { - Spawn: - GOR5 A -1 - Stop - } -} - -// Nonsolid meat ----------------------------------------------------------- - -ACTOR NonsolidMeat2 : Meat2 -{ - -SOLID - Radius 20 -} - -ACTOR NonsolidMeat3 : Meat3 -{ - -SOLID - Radius 20 -} - -ACTOR NonsolidMeat4 : Meat4 -{ - -SOLID - Radius 20 -} - -ACTOR NonsolidMeat5 : Meat5 -{ - -SOLID - Radius 20 -} - -// Nonsolid bloody twitch -------------------------------------------------- - -ACTOR NonsolidTwitch : BloodyTwitch -{ - -SOLID - Radius 20 -} - -// Head on a stick --------------------------------------------------------- - -ACTOR HeadOnAStick -{ - Radius 16 - Height 56 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - POL4 A -1 - Stop - } -} - -// Heads (plural!) on a stick ---------------------------------------------- - -ACTOR HeadsOnAStick -{ - Radius 16 - Height 64 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - POL2 A -1 - Stop - } -} - -// Head candles ------------------------------------------------------------ - -ACTOR HeadCandles -{ - Radius 16 - Height 42 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - POL3 AB 6 BRIGHT - Loop - } -} - -// Dead on a stick --------------------------------------------------------- - -ACTOR DeadStick -{ - Radius 16 - Height 64 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - POL1 A -1 - Stop - } -} - -// Still alive on a stick -------------------------------------------------- - -ACTOR LiveStick -{ - Radius 16 - Height 64 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - POL6 A 6 - POL6 B 8 - Loop - } -} - -// Big tree ---------------------------------------------------------------- - -ACTOR BigTree -{ - Radius 32 - Height 108 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - TRE2 A -1 - Stop - } -} - -// Burning barrel ---------------------------------------------------------- - -ACTOR BurningBarrel -{ - Radius 16 - Height 32 - ProjectilePassHeight -16 - +SOLID - States - { - Spawn: - FCAN ABC 4 BRIGHT - Loop - } -} - -// Hanging with no guts ---------------------------------------------------- - -ACTOR HangNoGuts -{ - Radius 16 - Height 88 - +SOLID - +NOGRAVITY - +SPAWNCEILING - States - { - Spawn: - HDB1 A -1 - Stop - } -} - -// Hanging from bottom with no brain --------------------------------------- - -ACTOR HangBNoBrain -{ - Radius 16 - Height 88 - +SOLID - +NOGRAVITY - +SPAWNCEILING - States - { - Spawn: - HDB2 A -1 - Stop - } -} - -// Hanging from top, looking down ------------------------------------------ - -ACTOR HangTLookingDown -{ - Radius 16 - Height 64 - +SOLID - +NOGRAVITY - +SPAWNCEILING - States - { - Spawn: - HDB3 A -1 - Stop - } -} - -// Hanging from top, looking up -------------------------------------------- - -ACTOR HangTLookingUp -{ - Radius 16 - Height 64 - +SOLID - +NOGRAVITY - +SPAWNCEILING - States - { - Spawn: - HDB5 A -1 - Stop - } -} - -// Hanging from top, skully ------------------------------------------------ - -ACTOR HangTSkull -{ - Radius 16 - Height 64 - +SOLID - +NOGRAVITY - +SPAWNCEILING - States - { - Spawn: - HDB4 A -1 - Stop - } -} - -// Hanging from top without a brain ---------------------------------------- - -ACTOR HangTNoBrain -{ - Radius 16 - Height 64 - +SOLID - +NOGRAVITY - +SPAWNCEILING - States - { - Spawn: - HDB6 A -1 - Stop - } -} - -// Colon gibs -------------------------------------------------------------- - -ACTOR ColonGibs -{ - Radius 20 - Height 4 - +NOBLOCKMAP - +MOVEWITHSECTOR - States - { - Spawn: - POB1 A -1 - Stop - } -} - -// Small pool o' blood ----------------------------------------------------- - -ACTOR SmallBloodPool -{ - Radius 20 - Height 1 - +NOBLOCKMAP - +MOVEWITHSECTOR - States - { - Spawn: - POB2 A -1 - Stop - } -} - -// brain stem lying on the ground ------------------------------------------ - -ACTOR BrainStem -{ - Radius 20 - Height 4 - +NOBLOCKMAP - +MOVEWITHSECTOR - States - { - Spawn: - BRS1 A -1 - Stop - } -} - - -// Grey stalagmite (unused Doom sprite, definition taken from Skulltag ----- - -ACTOR Stalagmite -{ - Radius 16 - Height 48 - +SOLID - States - { - Spawn: - SMT2 A -1 - Stop - } -} - diff --git a/wadsrc/static/actors/doom/doomhealth.txt b/wadsrc/static/actors/doom/doomhealth.txt deleted file mode 100644 index c1a8d96ffa..0000000000 --- a/wadsrc/static/actors/doom/doomhealth.txt +++ /dev/null @@ -1,45 +0,0 @@ -// Health bonus ------------------------------------------------------------- - -ACTOR HealthBonus : Health -{ - +COUNTITEM - +INVENTORY.ALWAYSPICKUP - Inventory.Amount 1 - Inventory.MaxAmount 200 - Inventory.PickupMessage "$GOTHTHBONUS" - States - { - Spawn: - BON1 ABCDCB 6 - Loop - } -} - -// Stimpack ----------------------------------------------------------------- - -ACTOR Stimpack : Health -{ - Inventory.Amount 10 - Inventory.PickupMessage "$GOTSTIM" - States - { - Spawn: - STIM A -1 - Stop - } -} - -// Medikit ----------------------------------------------------------------- - -ACTOR Medikit : Health -{ - Inventory.Amount 25 - Inventory.PickupMessage "$GOTMEDIKIT" - Health.LowMessage 25, "$GOTMEDINEED" - States - { - Spawn: - MEDI A -1 - Stop - } -} diff --git a/wadsrc/static/actors/doom/doomimp.txt b/wadsrc/static/actors/doom/doomimp.txt deleted file mode 100644 index 008cc5229d..0000000000 --- a/wadsrc/static/actors/doom/doomimp.txt +++ /dev/null @@ -1,88 +0,0 @@ -//=========================================================================== -// -// Imp -// -//=========================================================================== -ACTOR DoomImp -{ - Health 60 - Radius 20 - Height 56 - Mass 100 - Speed 8 - PainChance 200 - Monster - +FLOORCLIP - SeeSound "imp/sight" - PainSound "imp/pain" - DeathSound "imp/death" - ActiveSound "imp/active" - HitObituary "$OB_IMPHIT" - Obituary "$OB_IMP" - States - { - Spawn: - TROO AB 10 A_Look - Loop - See: - TROO AABBCCDD 3 A_Chase - Loop - Melee: - Missile: - TROO EF 8 A_FaceTarget - TROO G 6 A_TroopAttack - Goto See - Pain: - TROO H 2 - TROO H 2 A_Pain - Goto See - Death: - TROO I 8 - TROO J 8 A_Scream - TROO K 6 - TROO L 6 A_NoBlocking - TROO M -1 - Stop - XDeath: - TROO N 5 - TROO O 5 A_XScream - TROO P 5 - TROO Q 5 A_NoBlocking - TROO RST 5 - TROO U -1 - Stop - Raise: - TROO ML 8 - TROO KJI 6 - Goto See - } -} - -//=========================================================================== -// -// Imp fireball -// -//=========================================================================== -ACTOR DoomImpBall -{ - Radius 6 - Height 8 - Speed 10 - FastSpeed 20 - Damage 3 - Projectile - +RANDOMIZE - RenderStyle Add - Alpha 1 - SeeSound "imp/attack" - DeathSound "imp/shotx" - States - { - Spawn: - BAL1 AB 4 BRIGHT - Loop - Death: - BAL1 CDE 6 BRIGHT - Stop - } -} diff --git a/wadsrc/static/actors/doom/doomkeys.txt b/wadsrc/static/actors/doom/doomkeys.txt deleted file mode 100644 index d243925599..0000000000 --- a/wadsrc/static/actors/doom/doomkeys.txt +++ /dev/null @@ -1,98 +0,0 @@ - -Actor DoomKey : Key -{ - Radius 20 - Height 16 - +NOTDMATCH -} - -// Blue key card ------------------------------------------------------------ - -Actor BlueCard : DoomKey -{ - Inventory.Pickupmessage "$GOTBLUECARD" - Inventory.Icon "STKEYS0" - States - { - Spawn: - BKEY A 10 - BKEY B 10 bright - loop - } -} - -// Yellow key card ---------------------------------------------------------- - -Actor YellowCard : DoomKey -{ - Inventory.Pickupmessage "$GOTYELWCARD" - Inventory.Icon "STKEYS1" - States - { - Spawn: - YKEY A 10 - YKEY B 10 bright - loop - } -} - -// Red key card ------------------------------------------------------------- - -Actor RedCard : DoomKey -{ - Inventory.Pickupmessage "$GOTREDCARD" - Inventory.Icon "STKEYS2" - States - { - Spawn: - RKEY A 10 - RKEY B 10 bright - loop - } -} - -// Blue skull key ----------------------------------------------------------- - -Actor BlueSkull : DoomKey -{ - Inventory.Pickupmessage "$GOTBLUESKUL" - Inventory.Icon "STKEYS3" - States - { - Spawn: - BSKU A 10 - BSKU B 10 bright - loop - } -} - -// Yellow skull key --------------------------------------------------------- - -Actor YellowSkull : DoomKey -{ - Inventory.Pickupmessage "$GOTYELWSKUL" - Inventory.Icon "STKEYS4" - States - { - Spawn: - YSKU A 10 - YSKU B 10 bright - loop - } -} - -// Red skull key ------------------------------------------------------------ - -Actor RedSkull : DoomKey -{ - Inventory.Pickupmessage "$GOTREDSKUL" - Inventory.Icon "STKEYS5" - States - { - Spawn: - RSKU A 10 - RSKU B 10 bright - loop - } -} - diff --git a/wadsrc/static/actors/doom/doommisc.txt b/wadsrc/static/actors/doom/doommisc.txt deleted file mode 100644 index cb22474b93..0000000000 --- a/wadsrc/static/actors/doom/doommisc.txt +++ /dev/null @@ -1,104 +0,0 @@ -// The barrel of green goop ------------------------------------------------ - -ACTOR ExplosiveBarrel -{ - Health 20 - Radius 10 - Height 42 - +SOLID - +SHOOTABLE - +NOBLOOD - +ACTIVATEMCROSS - +DONTGIB - +NOICEDEATH - +OLDRADIUSDMG - DeathSound "world/barrelx" - Obituary "$OB_BARREL" - States - { - Spawn: - BAR1 AB 6 - Loop - Death: - BEXP A 5 BRIGHT - BEXP B 5 BRIGHT A_Scream - BEXP C 5 BRIGHT - BEXP D 5 BRIGHT A_Explode - BEXP E 10 BRIGHT - TNT1 A 1050 BRIGHT A_BarrelDestroy - TNT1 A 5 A_Respawn - Wait - } -} - -// Bullet puff ------------------------------------------------------------- - -ACTOR BulletPuff -{ - +NOBLOCKMAP - +NOGRAVITY - +ALLOWPARTICLES - +RANDOMIZE - RenderStyle Translucent - Alpha 0.5 - VSpeed 1 - Mass 5 - States - { - Spawn: - PUFF A 4 Bright - PUFF B 4 - Melee: - PUFF CD 4 - Stop - } -} - -// Container for an unused state ------------------------------------------- - -/* Doom defined the states S_STALAG, S_DEADTORSO, and S_DEADBOTTOM but never - * actually used them. For compatibility with DeHackEd patches, they still - * need to be kept around. This actor serves that purpose. - */ - -ACTOR DoomUnusedStates -{ - States - { - Label1: - SMT2 A -1 - stop - Label2: - PLAY N -1 - stop - PLAY S -1 - stop - TNT: // MBF compatibility - TNT1 A -1 - Loop - } -} - -// MBF Beta emulation items - -Actor EvilSceptre : ScoreItem -{ - Inventory.PickupMessage "$BETA_BONUS3" - States - { - Spawn: - BON3 A 6 - Loop - } -} - -Actor UnholyBible : ScoreItem -{ - Inventory.PickupMessage "$BETA_BONUS4" - States - { - Spawn: - BON4 A 6 - Loop - } -} diff --git a/wadsrc/static/actors/doom/doomplayer.txt b/wadsrc/static/actors/doom/doomplayer.txt deleted file mode 100644 index e31c10ea77..0000000000 --- a/wadsrc/static/actors/doom/doomplayer.txt +++ /dev/null @@ -1,90 +0,0 @@ -//=========================================================================== -// -// Player -// -//=========================================================================== -ACTOR DoomPlayer : PlayerPawn -{ - Speed 1 - Health 100 - Radius 16 - Height 56 - Mass 100 - PainChance 255 - Player.DisplayName "Marine" - Player.CrouchSprite "PLYC" - Player.StartItem "Pistol" - Player.StartItem "Fist" - Player.StartItem "Clip", 50 - Player.WeaponSlot 1, Fist, Chainsaw - Player.WeaponSlot 2, Pistol - Player.WeaponSlot 3, Shotgun, SuperShotgun - Player.WeaponSlot 4, Chaingun - Player.WeaponSlot 5, RocketLauncher - Player.WeaponSlot 6, PlasmaRifle - Player.WeaponSlot 7, BFG9000 - - Player.ColorRange 112, 127 - Player.Colorset 0, "Green", 0x70, 0x7F, 0x72 - Player.Colorset 1, "Gray", 0x60, 0x6F, 0x62 - Player.Colorset 2, "Brown", 0x40, 0x4F, 0x42 - Player.Colorset 3, "Red", 0x20, 0x2F, 0x22 - // Doom Legacy additions - Player.Colorset 4, "Light Gray", 0x58, 0x67, 0x5A - Player.Colorset 5, "Light Brown", 0x38, 0x47, 0x3A - Player.Colorset 6, "Light Red", 0xB0, 0xBF, 0xB2 - Player.Colorset 7, "Light Blue", 0xC0, 0xCF, 0xC2 - - States - { - Spawn: - PLAY A -1 - Loop - See: - PLAY ABCD 4 - Loop - Missile: - PLAY E 12 - Goto Spawn - Melee: - PLAY F 6 BRIGHT - Goto Missile - Pain: - PLAY G 4 - PLAY G 4 A_Pain - Goto Spawn - Death: - PLAY H 0 A_PlayerSkinCheck("AltSkinDeath") - Death1: - PLAY H 10 - PLAY I 10 A_PlayerScream - PLAY J 10 A_NoBlocking - PLAY KLM 10 - PLAY N -1 - Stop - XDeath: - PLAY O 0 A_PlayerSkinCheck("AltSkinXDeath") - XDeath1: - PLAY O 5 - PLAY P 5 A_XScream - PLAY Q 5 A_NoBlocking - PLAY RSTUV 5 - PLAY W -1 - Stop - AltSkinDeath: - PLAY H 6 - PLAY I 6 A_PlayerScream - PLAY JK 6 - PLAY L 6 A_NoBlocking - PLAY MNO 6 - PLAY P -1 - Stop - AltSkinXDeath: - PLAY Q 5 A_PlayerScream - PLAY R 0 A_NoBlocking - PLAY R 5 A_SkullPop - PLAY STUVWX 5 - PLAY Y -1 - Stop - } -} diff --git a/wadsrc/static/actors/doom/doomweapons.txt b/wadsrc/static/actors/doom/doomweapons.txt deleted file mode 100644 index 16369572bd..0000000000 --- a/wadsrc/static/actors/doom/doomweapons.txt +++ /dev/null @@ -1,574 +0,0 @@ -// -------------------------------------------------------------------------- -// -// Doom weapon base class -// -// -------------------------------------------------------------------------- - -ACTOR DoomWeapon : Weapon -{ - Weapon.Kickback 100 -} - -// -------------------------------------------------------------------------- -// -// Fist -// -// -------------------------------------------------------------------------- - -ACTOR Fist : Weapon -{ - Weapon.SelectionOrder 3700 - Weapon.Kickback 100 - Obituary "$OB_MPFIST" - Tag "$TAG_FIST" - +WEAPON.WIMPY_WEAPON - +WEAPON.MELEEWEAPON - States - { - Ready: - PUNG A 1 A_WeaponReady - Loop - Deselect: - PUNG A 1 A_Lower - Loop - Select: - PUNG A 1 A_Raise - Loop - Fire: - PUNG B 4 - PUNG C 4 A_Punch - PUNG D 5 - PUNG C 4 - PUNG B 5 A_ReFire - Goto Ready - } -} - - -// -------------------------------------------------------------------------- -// -// Pistol -// -// -------------------------------------------------------------------------- - -ACTOR Pistol : DoomWeapon -{ - Weapon.SelectionOrder 1900 - Weapon.AmmoUse 1 - Weapon.AmmoGive 20 - Weapon.AmmoType "Clip" - Obituary "$OB_MPPISTOL" - +WEAPON.WIMPY_WEAPON - Inventory.Pickupmessage "$PICKUP_PISTOL_DROPPED" - Tag "$TAG_PISTOL" - States - { - Ready: - PISG A 1 A_WeaponReady - Loop - Deselect: - PISG A 1 A_Lower - Loop - Select: - PISG A 1 A_Raise - Loop - Fire: - PISG A 4 - PISG B 6 A_FirePistol - PISG C 4 - PISG B 5 A_ReFire - Goto Ready - Flash: - PISF A 7 Bright A_Light1 - Goto LightDone - PISF A 7 Bright A_Light1 - Goto LightDone - Spawn: - PIST A -1 - Stop - } -} - -// -------------------------------------------------------------------------- -// -// Chainsaw -// -// -------------------------------------------------------------------------- - -ACTOR Chainsaw : Weapon -{ - Weapon.Kickback 0 - Weapon.SelectionOrder 2200 - Weapon.UpSound "weapons/sawup" - Weapon.ReadySound "weapons/sawidle" - Inventory.PickupMessage "$GOTCHAINSAW" - Obituary "$OB_MPCHAINSAW" - Tag "$TAG_CHAINSAW" - +WEAPON.MELEEWEAPON - States - { - Ready: - SAWG CD 4 A_WeaponReady - Loop - Deselect: - SAWG C 1 A_Lower - Loop - Select: - SAWG C 1 A_Raise - Loop - Fire: - SAWG AB 4 A_Saw - SAWG B 0 A_ReFire - Goto Ready - Spawn: - CSAW A -1 - Stop - } -} - - -// -------------------------------------------------------------------------- -// -// Shotgun -// -// -------------------------------------------------------------------------- - -ACTOR Shotgun : DoomWeapon -{ - Weapon.SelectionOrder 1300 - Weapon.AmmoUse 1 - Weapon.AmmoGive 8 - Weapon.AmmoType "Shell" - Inventory.PickupMessage "$GOTSHOTGUN" - Obituary "$OB_MPSHOTGUN" - Tag "$TAG_SHOTGUN" - States - { - Ready: - SHTG A 1 A_WeaponReady - Loop - Deselect: - SHTG A 1 A_Lower - Loop - Select: - SHTG A 1 A_Raise - Loop - Fire: - SHTG A 3 - SHTG A 7 A_FireShotgun - SHTG BC 5 - SHTG D 4 - SHTG CB 5 - SHTG A 3 - SHTG A 7 A_ReFire - Goto Ready - Flash: - SHTF A 4 Bright A_Light1 - SHTF B 3 Bright A_Light2 - Goto LightDone - Spawn: - SHOT A -1 - Stop - } -} - -// -------------------------------------------------------------------------- -// -// Shotgun -// -// -------------------------------------------------------------------------- - -ACTOR SuperShotgun : DoomWeapon -{ - Weapon.SelectionOrder 400 - Weapon.AmmoUse 2 - Weapon.AmmoGive 8 - Weapon.AmmoType "Shell" - Inventory.PickupMessage "$GOTSHOTGUN2" - Obituary "$OB_MPSSHOTGUN" - Tag "$TAG_SUPERSHOTGUN" - States - { - Ready: - SHT2 A 1 A_WeaponReady - Loop - Deselect: - SHT2 A 1 A_Lower - Loop - Select: - SHT2 A 1 A_Raise - Loop - Fire: - SHT2 A 3 - SHT2 A 7 A_FireShotgun2 - SHT2 B 7 - SHT2 C 7 A_CheckReload - SHT2 D 7 A_OpenShotgun2 - SHT2 E 7 - SHT2 F 7 A_LoadShotgun2 - SHT2 G 6 - SHT2 H 6 A_CloseShotgun2 - SHT2 A 5 A_ReFire - Goto Ready - // unused states - SHT2 B 7 - SHT2 A 3 - Goto Deselect - Flash: - SHT2 I 4 Bright A_Light1 - SHT2 J 3 Bright A_Light2 - Goto LightDone - Spawn: - SGN2 A -1 - Stop - } -} - -// -------------------------------------------------------------------------- -// -// Chaingun -// -// -------------------------------------------------------------------------- - -ACTOR Chaingun : DoomWeapon -{ - Weapon.SelectionOrder 700 - Weapon.AmmoUse 1 - Weapon.AmmoGive 20 - Weapon.AmmoType "Clip" - Inventory.PickupMessage "$GOTCHAINGUN" - Obituary "$OB_MPCHAINGUN" - Tag "$TAG_CHAINGUN" - States - { - Ready: - CHGG A 1 A_WeaponReady - Loop - Deselect: - CHGG A 1 A_Lower - Loop - Select: - CHGG A 1 A_Raise - Loop - Fire: - CHGG AB 4 A_FireCGun - CHGG B 0 A_ReFire - Goto Ready - Flash: - CHGF A 5 Bright A_Light1 - Goto LightDone - CHGF B 5 Bright A_Light2 - Goto LightDone - Spawn: - MGUN A -1 - Stop - } -} - -// -------------------------------------------------------------------------- -// -// Rocket launcher -// -// -------------------------------------------------------------------------- - -ACTOR RocketLauncher : DoomWeapon -{ - Weapon.SelectionOrder 2500 - Weapon.AmmoUse 1 - Weapon.AmmoGive 2 - Weapon.AmmoType "RocketAmmo" - +WEAPON.NOAUTOFIRE - Inventory.PickupMessage "$GOTLAUNCHER" - Tag "$TAG_ROCKETLAUNCHER" - States - { - Ready: - MISG A 1 A_WeaponReady - Loop - Deselect: - MISG A 1 A_Lower - Loop - Select: - MISG A 1 A_Raise - Loop - Fire: - MISG B 8 A_GunFlash - MISG B 12 A_FireMissile - MISG B 0 A_ReFire - Goto Ready - Flash: - MISF A 3 Bright A_Light1 - MISF B 4 Bright - MISF CD 4 Bright A_Light2 - Goto LightDone - Spawn: - LAUN A -1 - Stop - } -} - -ACTOR Rocket -{ - Radius 11 - Height 8 - Speed 20 - Damage 20 - Projectile - +RANDOMIZE - +DEHEXPLOSION - +ROCKETTRAIL - SeeSound "weapons/rocklf" - DeathSound "weapons/rocklx" - Obituary "$OB_MPROCKET" - States - { - Spawn: - MISL A 1 Bright - Loop - Death: - MISL B 8 Bright A_Explode - MISL C 6 Bright - MISL D 4 Bright - Stop - } -} - -// -------------------------------------------------------------------------- -// -// Grenade -- Taken and adapted from Skulltag, with MBF stuff added to it -// -// -------------------------------------------------------------------------- - -ACTOR Grenade -{ - Radius 8 - Height 8 - Speed 25 - Damage 20 - Projectile - -NOGRAVITY - +RANDOMIZE - +DEHEXPLOSION - +GRENADETRAIL - BounceType "Doom" - Gravity 0.25 - SeeSound "weapons/grenlf" - DeathSound "weapons/grenlx" - BounceSound "weapons/grbnce" - Obituary "$OB_GRENADE" - DamageType Grenade - - States - { - Spawn: - SGRN A 1 Bright - Loop - Death: - MISL B 8 Bright A_Explode - MISL C 6 Bright - MISL D 4 Bright - Stop - Grenade: - MISL A 1000 A_Die - Wait - Detonate: - MISL B 4 A_Scream - MISL C 6 A_Detonate - MISL D 10 - Stop - Mushroom: - MISL B 8 A_Mushroom - Goto Death+1 - } -} - -// -------------------------------------------------------------------------- -// -// Plasma rifle -// -// -------------------------------------------------------------------------- - -ACTOR PlasmaRifle : DoomWeapon -{ - Weapon.SelectionOrder 100 - Weapon.AmmoUse 1 - Weapon.AmmoGive 40 - Weapon.AmmoType "Cell" - Inventory.PickupMessage "$GOTPLASMA" - Tag "$TAG_PLASMARIFLE" - States - { - Ready: - PLSG A 1 A_WeaponReady - Loop - Deselect: - PLSG A 1 A_Lower - Loop - Select: - PLSG A 1 A_Raise - Loop - Fire: - PLSG A 3 A_FirePlasma - PLSG B 20 A_ReFire - Goto Ready - Flash: - PLSF A 4 Bright A_Light1 - Goto LightDone - PLSF B 4 Bright A_Light1 - Goto LightDone - Spawn: - PLAS A -1 - Stop - } -} - -ACTOR PlasmaBall -{ - Radius 13 - Height 8 - Speed 25 - Damage 5 - Projectile - +RANDOMIZE - RenderStyle Add - Alpha 0.75 - SeeSound "weapons/plasmaf" - DeathSound "weapons/plasmax" - Obituary "$OB_MPPLASMARIFLE" - States - { - Spawn: - PLSS AB 6 Bright - Loop - Death: - PLSE ABCDE 4 Bright - Stop - } -} - -// -------------------------------------------------------------------------- -// -// BFG 2704 -// -// -------------------------------------------------------------------------- - -ACTOR PlasmaBall1 : PlasmaBall -{ - Damage 4 - BounceType "Classic" - BounceFactor 1.0 - Obituary "$OB_MPBFG_MBF" - States - { - Spawn: - PLS1 AB 6 Bright - Loop - Death: - PLS1 CDEFG 4 Bright - Stop - } -} - -ACTOR PlasmaBall2 : PlasmaBall1 -{ - States - { - Spawn: - PLS2 AB 6 Bright - Loop - Death: - PLS2 CDE 4 Bright - Stop - } -} - -// -------------------------------------------------------------------------- -// -// BFG 9000 -// -// -------------------------------------------------------------------------- - -ACTOR BFG9000 : DoomWeapon -{ - Height 20 - Weapon.SelectionOrder 2800 - Weapon.AmmoUse 40 - Weapon.AmmoGive 40 - Weapon.AmmoType "Cell" - +WEAPON.NOAUTOFIRE - Inventory.PickupMessage "$GOTBFG9000" - Tag "$TAG_BFG9000" - States - { - Ready: - BFGG A 1 A_WeaponReady - Loop - Deselect: - BFGG A 1 A_Lower - Loop - Select: - BFGG A 1 A_Raise - Loop - Fire: - BFGG A 20 A_BFGsound - BFGG B 10 A_GunFlash - BFGG B 10 A_FireBFG - BFGG B 20 A_ReFire - Goto Ready - Flash: - BFGF A 11 Bright A_Light1 - BFGF B 6 Bright A_Light2 - Goto LightDone - Spawn: - BFUG A -1 - Stop - OldFire: - BFGG A 10 A_BFGsound - BFGG BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB 1 A_FireOldBFG - BFGG B 0 A_Light0 - BFGG B 20 A_ReFire - Goto Ready - } -} - - -ACTOR BFGBall -{ - Radius 13 - Height 8 - Speed 25 - Damage 100 - Projectile - +RANDOMIZE - RenderStyle Add - Alpha 0.75 - DeathSound "weapons/bfgx" - Obituary "$OB_MPBFG_BOOM" - States - { - Spawn: - BFS1 AB 4 Bright - Loop - Death: - BFE1 AB 8 Bright - BFE1 C 8 Bright A_BFGSpray - BFE1 DEF 8 Bright - Stop - } -} - -ACTOR BFGExtra -{ - +NOBLOCKMAP - +NOGRAVITY - RenderStyle Add - Alpha 0.75 - DamageType "BFGSplash" - States - { - Spawn: - BFE2 ABCD 8 Bright - Stop - } -} - diff --git a/wadsrc/static/actors/doom/fatso.txt b/wadsrc/static/actors/doom/fatso.txt deleted file mode 100644 index 9b3a7d26a2..0000000000 --- a/wadsrc/static/actors/doom/fatso.txt +++ /dev/null @@ -1,89 +0,0 @@ -//=========================================================================== -// -// Mancubus -// -//=========================================================================== -ACTOR Fatso -{ - Health 600 - Radius 48 - Height 64 - Mass 1000 - Speed 8 - PainChance 80 - Monster - +FLOORCLIP - +BOSSDEATH - SeeSound "fatso/sight" - PainSound "fatso/pain" - DeathSound "fatso/death" - ActiveSound "fatso/active" - Obituary "$OB_FATSO" - States - { - Spawn: - FATT AB 15 A_Look - Loop - See: - FATT AABBCCDDEEFF 4 A_Chase - Loop - Missile: - FATT G 20 A_FatRaise - FATT H 10 BRIGHT A_FatAttack1 - FATT IG 5 A_FaceTarget - FATT H 10 BRIGHT A_FatAttack2 - FATT IG 5 A_FaceTarget - FATT H 10 BRIGHT A_FatAttack3 - FATT IG 5 A_FaceTarget - Goto See - Pain: - FATT J 3 - FATT J 3 A_Pain - Goto See - Death: - FATT K 6 - FATT L 6 A_Scream - FATT M 6 A_NoBlocking - FATT NOPQRS 6 - FATT T -1 A_BossDeath - Stop - Raise: - FATT R 5 - FATT QPONMLK 5 - Goto See - } -} - - - -//=========================================================================== -// -// Mancubus fireball -// -//=========================================================================== -ACTOR FatShot -{ - Radius 6 - Height 8 - Speed 20 - Damage 8 - Projectile - +RANDOMIZE - RenderStyle Add - Alpha 1 - SeeSound "fatso/attack" - DeathSound "fatso/shotx" - States - { - Spawn: - MANF AB 4 BRIGHT - Loop - Death: - MISL B 8 BRIGHT - MISL C 6 BRIGHT - MISL D 4 BRIGHT - Stop - } -} - - diff --git a/wadsrc/static/actors/doom/keen.txt b/wadsrc/static/actors/doom/keen.txt deleted file mode 100644 index 7ad41d2cee..0000000000 --- a/wadsrc/static/actors/doom/keen.txt +++ /dev/null @@ -1,41 +0,0 @@ -//=========================================================================== -// -// Commander Keen -// -//=========================================================================== -ACTOR CommanderKeen -{ - Health 100 - Radius 16 - Height 72 - Mass 10000000 - PainChance 256 - +SOLID - +SPAWNCEILING - +NOGRAVITY - +SHOOTABLE - +COUNTKILL - +NOICEDEATH - +ISMONSTER - PainSound "keen/pain" - DeathSound "keen/death" - States - { - Spawn: - KEEN A -1 - Loop - Death: - KEEN AB 6 - KEEN C 6 A_Scream - KEEN DEFGH 6 - KEEN I 6 - KEEN J 6 - KEEN K 6 A_KeenDie - KEEN L -1 - Stop - Pain: - KEEN M 4 - KEEN M 8 A_Pain - Goto Spawn - } -} diff --git a/wadsrc/static/actors/doom/lostsoul.txt b/wadsrc/static/actors/doom/lostsoul.txt deleted file mode 100644 index bd6212cf27..0000000000 --- a/wadsrc/static/actors/doom/lostsoul.txt +++ /dev/null @@ -1,80 +0,0 @@ -//=========================================================================== -// -// Lost Soul -// -//=========================================================================== -ACTOR LostSoul -{ - Health 100 - Radius 16 - Height 56 - Mass 50 - Speed 8 - Damage 3 - PainChance 256 - Monster - +FLOAT +NOGRAVITY +MISSILEMORE +DONTFALL +NOICEDEATH - AttackSound "skull/melee" - PainSound "skull/pain" - DeathSound "skull/death" - ActiveSound "skull/active" - RenderStyle SoulTrans - Obituary "$OB_SKULL" - States - { - Spawn: - SKUL AB 10 BRIGHT A_Look - Loop - See: - SKUL AB 6 BRIGHT A_Chase - Loop - Missile: - SKUL C 10 BRIGHT A_FaceTarget - SKUL D 4 BRIGHT A_SkullAttack - SKUL CD 4 BRIGHT - Goto Missile+2 - Pain: - SKUL E 3 BRIGHT - SKUL E 3 BRIGHT A_Pain - Goto See - Death: - SKUL F 6 BRIGHT - SKUL G 6 BRIGHT A_Scream - SKUL H 6 BRIGHT - SKUL I 6 BRIGHT A_NoBlocking - SKUL J 6 - SKUL K 6 - Stop - } -} - -Actor BetaSkull : LostSoul -{ - States - { - Spawn: - SKUL A 10 A_Look - Loop - See: - SKUL BCDA 5 A_Chase - Loop - Missile: - SKUL E 4 A_FaceTarget - SKUL F 5 A_BetaSkullAttack - SKUL F 4 - Goto See - Pain: - SKUL G 4 - SKUL H 2 A_Pain - Goto See - SKUL I 4 - Goto See - Death: - SKUL JKLM 5 - SKUL N 5 A_Scream - SKUL O 5 - SKUL P 5 A_Fall - SKUL Q 5 A_Stop - Wait - } -} diff --git a/wadsrc/static/actors/doom/painelemental.txt b/wadsrc/static/actors/doom/painelemental.txt deleted file mode 100644 index bba4756502..0000000000 --- a/wadsrc/static/actors/doom/painelemental.txt +++ /dev/null @@ -1,50 +0,0 @@ -//=========================================================================== -// -// Pain Elemental -// -//=========================================================================== -ACTOR PainElemental -{ - Health 400 - Radius 31 - Height 56 - Mass 400 - Speed 8 - PainChance 128 - Monster - +FLOAT - +NOGRAVITY - SeeSound "pain/sight" - PainSound "pain/pain" - DeathSound "pain/death" - ActiveSound "pain/active" - States - { - Spawn: - PAIN A 10 A_Look - Loop - See: - PAIN AABBCC 3 A_Chase - Loop - Missile: - PAIN D 5 A_FaceTarget - PAIN E 5 A_FaceTarget - PAIN F 5 BRIGHT A_FaceTarget - PAIN F 0 BRIGHT A_PainAttack - Goto See - Pain: - PAIN G 6 - PAIN G 6 A_Pain - Goto See - Death: - PAIN H 8 BRIGHT - PAIN I 8 BRIGHT A_Scream - PAIN JK 8 BRIGHT - PAIN L 8 BRIGHT A_PainDie - PAIN M 8 BRIGHT - Stop - Raise: - PAIN MLKJIH 8 - Goto See - } -} diff --git a/wadsrc/static/actors/doom/possessed.txt b/wadsrc/static/actors/doom/possessed.txt deleted file mode 100644 index 6961cc8a50..0000000000 --- a/wadsrc/static/actors/doom/possessed.txt +++ /dev/null @@ -1,241 +0,0 @@ - -//=========================================================================== -// -// Zombie man -// -//=========================================================================== -ACTOR ZombieMan -{ - Health 20 - Radius 20 - Height 56 - Speed 8 - PainChance 200 - Monster - +FLOORCLIP - SeeSound "grunt/sight" - AttackSound "grunt/attack" - PainSound "grunt/pain" - DeathSound "grunt/death" - ActiveSound "grunt/active" - Obituary "$OB_ZOMBIE" - DropItem "Clip" - States - { - Spawn: - POSS AB 10 A_Look - Loop - See: - POSS AABBCCDD 4 A_Chase - Loop - Missile: - POSS E 10 A_FaceTarget - POSS F 8 A_PosAttack - POSS E 8 - Goto See - Pain: - POSS G 3 - POSS G 3 A_Pain - Goto See - Death: - POSS H 5 - POSS I 5 A_Scream - POSS J 5 A_NoBlocking - POSS K 5 - POSS L -1 - Stop - XDeath: - POSS M 5 - POSS N 5 A_XScream - POSS O 5 A_NoBlocking - POSS PQRST 5 - POSS U -1 - Stop - Raise: - POSS K 5 - POSS JIH 5 - Goto See - } -} - -//=========================================================================== -// -// Sergeant / Shotgun guy -// -//=========================================================================== -ACTOR ShotgunGuy -{ - Health 30 - Radius 20 - Height 56 - Mass 100 - Speed 8 - PainChance 170 - Monster - +FLOORCLIP - SeeSound "shotguy/sight" - AttackSound "shotguy/attack" - PainSound "shotguy/pain" - DeathSound "shotguy/death" - ActiveSound "shotguy/active" - Obituary "$OB_SHOTGUY" - DropItem "Shotgun" - States - { - Spawn: - SPOS AB 10 A_Look - Loop - See: - SPOS AABBCCDD 3 A_Chase - Loop - Missile: - SPOS E 10 A_FaceTarget - SPOS F 10 BRIGHT A_SposAttackUseAtkSound - SPOS E 10 - Goto See - Pain: - SPOS G 3 - SPOS G 3 A_Pain - Goto See - Death: - SPOS H 5 - SPOS I 5 A_Scream - SPOS J 5 A_NoBlocking - SPOS K 5 - SPOS L -1 - Stop - XDeath: - SPOS M 5 - SPOS N 5 A_XScream - SPOS O 5 A_NoBlocking - SPOS PQRST 5 - SPOS U -1 - Stop - Raise: - SPOS L 5 - SPOS KJIH 5 - Goto See - } -} - -//=========================================================================== -// -// Chaingunner -// -//=========================================================================== -ACTOR ChaingunGuy -{ - Health 70 - Radius 20 - Height 56 - Mass 100 - Speed 8 - PainChance 170 - Monster - +FLOORCLIP - SeeSound "chainguy/sight" - PainSound "chainguy/pain" - DeathSound "chainguy/death" - ActiveSound "chainguy/active" - AttackSound "chainguy/attack" - Obituary "$OB_CHAINGUY" - Dropitem "Chaingun" - States - { - Spawn: - CPOS AB 10 A_Look - Loop - See: - CPOS AABBCCDD 3 A_Chase - Loop - Missile: - CPOS E 10 A_FaceTarget - CPOS FE 4 BRIGHT A_CPosAttack - CPOS F 1 A_CPosRefire - Goto Missile+1 - Pain: - CPOS G 3 - CPOS G 3 A_Pain - Goto See - Death: - CPOS H 5 - CPOS I 5 A_Scream - CPOS J 5 A_NoBlocking - CPOS KLM 5 - CPOS N -1 - Stop - XDeath: - CPOS O 5 - CPOS P 5 A_XScream - CPOS Q 5 A_NoBlocking - CPOS RS 5 - CPOS T -1 - Stop - Raise: - CPOS N 5 - CPOS MLKJIH 5 - Goto See - } -} - -//=========================================================================== -// -// SS Nazi -// -//=========================================================================== -ACTOR WolfensteinSS -{ - Health 50 - Radius 20 - Height 56 - Speed 8 - PainChance 170 - Monster - +FLOORCLIP - SeeSound "wolfss/sight" - PainSound "wolfss/pain" - DeathSound "wolfss/death" - ActiveSound "wolfss/active" - AttackSound "wolfss/attack" - Obituary "$OB_WOLFSS" - Dropitem "Clip" - States - { - Spawn: - SSWV AB 10 A_Look - Loop - See: - SSWV AABBCCDD 3 A_Chase - Loop - Missile: - SSWV E 10 A_FaceTarget - SSWV F 10 A_FaceTarget - SSWV G 4 BRIGHT A_CPosAttack - SSWV F 6 A_FaceTarget - SSWV G 4 BRIGHT A_CPosAttack - SSWV F 1 A_CPosRefire - Goto Missile+1 - Pain: - SSWV H 3 - SSWV H 3 A_Pain - Goto See - Death: - SSWV I 5 - SSWV J 5 A_Scream - SSWV K 5 A_NoBlocking - SSWV L 5 - SSWV M -1 - Stop - XDeath: - SSWV N 5 - SSWV O 5 A_XScream - SSWV P 5 A_NoBlocking - SSWV QRSTU 5 - SSWV V -1 - Stop - Raise: - SSWV M 5 - SSWV LKJI 5 - Goto See - } -} diff --git a/wadsrc/static/actors/doom/revenant.txt b/wadsrc/static/actors/doom/revenant.txt deleted file mode 100644 index 4062647f48..0000000000 --- a/wadsrc/static/actors/doom/revenant.txt +++ /dev/null @@ -1,113 +0,0 @@ -//=========================================================================== -// -// Revenant -// -//=========================================================================== -ACTOR Revenant -{ - Health 300 - Radius 20 - Height 56 - Mass 500 - Speed 10 - PainChance 100 - Monster - MeleeThreshold 196 - +MISSILEMORE - +FLOORCLIP - SeeSound "skeleton/sight" - PainSound "skeleton/pain" - DeathSound "skeleton/death" - ActiveSound "skeleton/active" - MeleeSound "skeleton/melee" - HitObituary "$OB_UNDEADHIT" - Obituary "$OB_UNDEAD" - States - { - Spawn: - SKEL AB 10 A_Look - Loop - See: - SKEL AABBCCDDEEFF 2 A_Chase - Loop - Melee: - SKEL G 0 A_FaceTarget - SKEL G 6 A_SkelWhoosh - SKEL H 6 A_FaceTarget - SKEL I 6 A_SkelFist - Goto See - Missile: - SKEL J 0 BRIGHT A_FaceTarget - SKEL J 10 BRIGHT A_FaceTarget - SKEL K 10 A_SkelMissile - SKEL K 10 A_FaceTarget - Goto See - Pain: - SKEL L 5 - SKEL L 5 A_Pain - Goto See - Death: - SKEL LM 7 - SKEL N 7 A_Scream - SKEL O 7 A_NoBlocking - SKEL P 7 - SKEL Q -1 - Stop - Raise: - SKEL Q 5 - SKEL PONML 5 - Goto See - } -} - - -//=========================================================================== -// -// Revenant Tracer -// -//=========================================================================== -ACTOR RevenantTracer -{ - Radius 11 - Height 8 - Speed 10 - Damage 10 - Projectile - +SEEKERMISSILE - +RANDOMIZE - SeeSound "skeleton/attack" - DeathSound "skeleton/tracex" - RenderStyle Add - States - { - Spawn: - FATB AB 2 BRIGHT A_Tracer - Loop - Death: - FBXP A 8 BRIGHT - FBXP B 6 BRIGHT - FBXP C 4 BRIGHT - Stop - } -} - - -//=========================================================================== -// -// Revenant Tracer Smoke -// -//=========================================================================== -ACTOR RevenantTracerSmoke -{ - +NOBLOCKMAP - +NOGRAVITY - +NOTELEPORT - RenderStyle Translucent - Alpha 0.5 - States - { - Spawn: - PUFF ABABC 4 - Stop - } -} diff --git a/wadsrc/static/actors/doom/scriptedmarine.txt b/wadsrc/static/actors/doom/scriptedmarine.txt deleted file mode 100644 index 73de9a49d2..0000000000 --- a/wadsrc/static/actors/doom/scriptedmarine.txt +++ /dev/null @@ -1,306 +0,0 @@ - -// Scriptable marine ------------------------------------------------------- - -ACTOR ScriptedMarine native -{ - Health 100 - Radius 16 - Height 56 - Mass 100 - Speed 8 - Painchance 160 - MONSTER - -COUNTKILL - Translation 0 - Damage 100 - DeathSound "*death" - PainSound "*pain50" - - action native A_M_Refire (bool ignoremissile=false); - action native A_M_CheckAttack (); - action native A_MarineChase (); - action native A_MarineLook (); - action native A_MarineNoise (); - action native A_M_Punch (int force); - action native A_M_SawRefire (); - action native A_M_FirePistol (bool accurate); - action native A_M_FireShotgun (); - action native A_M_FireShotgun2 (); - action native A_M_FireCGun(bool accurate); - action native A_M_FireMissile (); - action native A_M_FirePlasma (); - action native A_M_FireRailgun (); - action native A_M_BFGsound (); - action native A_M_FireBFG (); - - States - { - Spawn: - PLAY A 4 A_MarineLook - PLAY A 4 A_MarineNoise - Loop - Idle: - PLAY A 4 A_MarineLook - PLAY A 4 A_MarineNoise - PLAY A 4 A_MarineLook - PLAY B 4 A_MarineNoise - PLAY B 4 A_MarineLook - PLAY B 4 A_MarineNoise - Loop - See: - PLAY ABCD 4 A_MarineChase - Loop - - Melee.Fist: - PLAY E 4 A_FaceTarget - PLAY E 4 A_M_Punch(1) - PLAY A 9 - PLAY A 0 A_M_Refire(1) - Loop - PLAY A 5 A_FaceTarget - Goto See - Melee.Berserk: - PLAY E 4 A_FaceTarget - PLAY E 4 A_M_Punch(10) - PLAY A 9 - PLAY A 0 A_M_Refire(1) - Loop - PLAY A 5 A_FaceTarget - Goto See - Melee.Chainsaw: - PLAY E 4 A_MarineNoise - PLAY E 4 A_M_Saw - PLAY E 0 A_M_SawRefire - goto Melee.Chainsaw+1 - PLAY A 0 - Goto See - - Missile: - Missile.None: - PLAY E 12 A_FaceTarget - Goto Idle - PLAY F 6 BRIGHT - Loop - Missile.Pistol: - PLAY E 4 A_FaceTarget - PLAY F 6 BRIGHT A_M_FirePistol(1) - PLAY A 4 A_FaceTarget - PLAY A 0 A_M_Refire - PLAY A 5 - Goto See - Fireloop.Pistol: - PLAY F 6 BRIGHT A_M_FirePistol(0) - PLAY A 4 A_FaceTarget - PLAY A 0 A_M_Refire - Goto Fireloop.Pistol - PLAY A 5 - Goto See - Missile.Shotgun: - PLAY E 3 A_M_CheckAttack - PLAY F 7 BRIGHT A_M_FireShotgun - Goto See - Missile.SSG: - PLAY E 3 A_M_CheckAttack - PLAY F 7 BRIGHT A_M_FireShotgun2 - Goto See - Missile.Chaingun: - PLAY E 4 A_FaceTarget - PLAY FF 4 BRIGHT A_M_FireCGun(1) - PLAY FF 4 BRIGHT A_M_FireCGun(0) - PLAY A 0 A_M_Refire - Goto Missile.Chaingun+3 - PLAY A 0 - Goto See - Missile.Rocket: - PLAY E 8 - PLAY F 6 BRIGHT A_M_FireMissile - PLAY E 6 - PLAY A 0 A_M_Refire - Loop - PLAY A 0 - Goto See - Missile.Plasma: - PLAY E 2 A_FaceTarget - PLAY E 0 A_FaceTarget - PLAY F 3 BRIGHT A_M_FirePlasma - PLAY A 0 A_M_Refire - Goto Missile.Plasma+1 - PLAY A 0 - Goto See - Missile.Railgun: - PLAY E 4 A_M_CheckAttack - PLAY F 6 BRIGHT A_M_FireRailgun - Goto See - Missile.BFG: - PLAY E 5 A_M_BFGSound - PLAY EEEEE 5 A_FaceTarget - PLAY F 6 BRIGHT A_M_FireBFG - PLAY A 4 A_FaceTarget - PLAY A 0 A_M_Refire - Loop - PLAY A 0 - Goto See - - SkipAttack: - PLAY A 1 - Goto See - Pain: - PLAY G 4 - PLAY G 4 A_Pain - Goto Idle - Death: - PLAY H 10 - PLAY I 10 A_Scream - PLAY J 10 A_NoBlocking - PLAY KLM 10 - PLAY N -1 - Stop - XDeath: - PLAY O 5 - PLAY P 5 A_XScream - PLAY Q 5 A_NoBlocking - PLAY RSTUV 5 - PLAY W -1 - Stop - Raise: - PLAY MLKJIH 5 - Goto See - } -} - -//--------------------------------------------------------------------------- - -ACTOR MarineFist : ScriptedMarine -{ - States - { - Melee: - Goto Super::Melee.Fist - Missile: - Stop - } -} - - -//--------------------------------------------------------------------------- - -ACTOR MarineBerserk : MarineFist -{ - States - { - Melee: - Goto Super::Melee.Berserk - Missile: - Stop - } -} -//--------------------------------------------------------------------------- - -ACTOR MarineChainsaw : ScriptedMarine -{ - States - { - Melee: - Goto Super::Melee.Chainsaw - Missile: - Stop - } -} - - - -//--------------------------------------------------------------------------- - -ACTOR MarinePistol : ScriptedMarine -{ - States - { - Missile: - Goto Super::Missile.Pistol - } - -} - -//--------------------------------------------------------------------------- - -ACTOR MarineShotgun : ScriptedMarine -{ - States - { - Missile: - Goto Super::Missile.Shotgun - } - -} - - - -//--------------------------------------------------------------------------- - -ACTOR MarineSSG : ScriptedMarine -{ - States - { - Missile: - Goto Super::Missile.SSG - } -} - -//--------------------------------------------------------------------------- - -ACTOR MarineChaingun : ScriptedMarine -{ - States - { - Missile: - Goto Super::Missile.Chaingun - } -} - - -//--------------------------------------------------------------------------- - -ACTOR MarineRocket : MarineFist -{ - States - { - Missile: - Goto Super::Missile.Rocket - } - -} - -//--------------------------------------------------------------------------- - -ACTOR MarinePlasma : ScriptedMarine -{ - States - { - Missile: - Goto Super::Missile.Plasma - } - -} - -//--------------------------------------------------------------------------- - -ACTOR MarineRailgun : ScriptedMarine -{ - States - { - Missile: - Goto Super::Missile.Railgun - } - -} - -//--------------------------------------------------------------------------- - -ACTOR MarineBFG : ScriptedMarine -{ - States - { - Missile: - Goto Super::Missile.BFG - } -} diff --git a/wadsrc/static/actors/doom/spidermaster.txt b/wadsrc/static/actors/doom/spidermaster.txt deleted file mode 100644 index e087b3fb38..0000000000 --- a/wadsrc/static/actors/doom/spidermaster.txt +++ /dev/null @@ -1,59 +0,0 @@ -//=========================================================================== -// -// Spider boss -// -//=========================================================================== -ACTOR SpiderMastermind -{ - Health 3000 - Radius 128 - Height 100 - Mass 1000 - Speed 12 - PainChance 40 - Monster - MinMissileChance 160 - +BOSS - +MISSILEMORE - +FLOORCLIP - +NORADIUSDMG - +DONTMORPH - +BOSSDEATH - SeeSound "spider/sight" - AttackSound "spider/attack" - PainSound "spider/pain" - DeathSound "spider/death" - ActiveSound "spider/active" - Obituary "$OB_SPIDER" - States - { - Spawn: - SPID AB 10 A_Look - Loop - See: - SPID A 3 A_Metal - SPID ABB 3 A_Chase - SPID C 3 A_Metal - SPID CDD 3 A_Chase - SPID E 3 A_Metal - SPID EFF 3 A_Chase - Loop - Missile: - SPID A 20 BRIGHT A_FaceTarget - SPID G 4 BRIGHT A_SPosAttackUseAtkSound - SPID H 4 BRIGHT A_SposAttackUseAtkSound - SPID H 1 BRIGHT A_SpidRefire - Goto Missile+1 - Pain: - SPID I 3 - SPID I 3 A_Pain - Goto See - Death: - SPID J 20 A_Scream - SPID K 10 A_NoBlocking - SPID LMNOPQR 10 - SPID S 30 - SPID S -1 A_BossDeath - Stop - } -} diff --git a/wadsrc/static/actors/doom/stealthmonsters.txt b/wadsrc/static/actors/doom/stealthmonsters.txt deleted file mode 100644 index 2755374858..0000000000 --- a/wadsrc/static/actors/doom/stealthmonsters.txt +++ /dev/null @@ -1,103 +0,0 @@ - -ACTOR StealthArachnotron : Arachnotron -{ - +STEALTH - RenderStyle Translucent - Alpha 0 - Obituary "$OB_STEALTHBABY" -} - -ACTOR StealthArchvile : Archvile -{ - +STEALTH - RenderStyle Translucent - Alpha 0 - Obituary "$OB_STEALTHVILE" -} - -ACTOR StealthBaron : BaronOfHell -{ - +STEALTH - RenderStyle Translucent - Alpha 0 - Obituary "$OB_STEALTHBARON" - HitObituary "$OB_STEALTHBARON" -} - -ACTOR StealthCacodemon : Cacodemon -{ - +STEALTH - RenderStyle Translucent - Alpha 0 - Obituary "$OB_STEALTHCACO" - HitObituary "$OB_STEALTHCACO" -} - -ACTOR StealthChaingunGuy : ChaingunGuy -{ - +STEALTH - RenderStyle Translucent - Alpha 0 - Obituary "$OB_STEALTHCHAINGUY" -} - -ACTOR StealthDemon : Demon -{ - +STEALTH - RenderStyle Translucent - Alpha 0 - Obituary "$OB_STEALTHDEMON" - HitObituary "$OB_STEALTHDEMON" -} - -ACTOR StealthHellKnight : HellKnight -{ - +STEALTH - RenderStyle Translucent - Alpha 0 - Obituary "$OB_STEALTHKNIGHT" - HitObituary "$OB_STEALTHKNIGHT" -} - -ACTOR StealthDoomImp : DoomImp -{ - +STEALTH - RenderStyle Translucent - Alpha 0 - Obituary "$OB_STEALTHIMP" - HitObituary "$OB_STEALTHIMP" -} - -ACTOR StealthFatso : Fatso -{ - +STEALTH - RenderStyle Translucent - Alpha 0 - Obituary "$OB_STEALTHFATSO" -} - -ACTOR StealthRevenant : Revenant -{ - +STEALTH - RenderStyle Translucent - Alpha 0 - Obituary "$OB_STEALTHUNDEAD" - HitObituary "$OB_STEALTHUNDEAD" -} - -ACTOR StealthShotgunGuy : ShotgunGuy -{ - +STEALTH - RenderStyle Translucent - Alpha 0 - Obituary "$OB_STEALTHSHOTGUNGUY" -} - -ACTOR StealthZombieMan : ZombieMan -{ - +STEALTH - RenderStyle Translucent - Alpha 0 - Obituary "$OB_STEALTHZOMBIE" -} - diff --git a/wadsrc/static/actors/heretic/beast.txt b/wadsrc/static/actors/heretic/beast.txt deleted file mode 100644 index 73eb630ec2..0000000000 --- a/wadsrc/static/actors/heretic/beast.txt +++ /dev/null @@ -1,109 +0,0 @@ - -// Beast -------------------------------------------------------------------- - -ACTOR Beast -{ - Health 220 - Radius 32 - Height 74 - Mass 200 - Speed 14 - Painchance 100 - Monster - +FLOORCLIP - SeeSound "beast/sight" - AttackSound "beast/attack" - PainSound "beast/pain" - DeathSound "beast/death" - ActiveSound "beast/active" - Obituary "$OB_BEAST" - DropItem "CrossbowAmmo", 84, 10 - States - { - Spawn: - BEAS AB 10 A_Look - Loop - See: - BEAS ABCDEF 3 A_Chase - Loop - Missile: - BEAS H 10 A_FaceTarget - BEAS I 10 A_CustomComboAttack("BeastBall", 32, random[BeastAttack](1,8)*3, "beast/attack") - Goto See - Pain: - BEAS G 3 - BEAS G 3 A_Pain - Goto See - Death: - BEAS R 6 - BEAS S 6 A_Scream - BEAS TUV 6 - BEAS W 6 A_NoBlocking - BEAS XY 6 - BEAS Z -1 - Stop - XDeath: - BEAS J 5 - BEAS K 6 A_Scream - BEAS L 5 - BEAS M 6 - BEAS N 5 - BEAS O 6 A_NoBlocking - BEAS P 5 - BEAS Q -1 - Stop - } -} - -// Beast ball --------------------------------------------------------------- - -ACTOR BeastBall -{ - Radius 9 - Height 8 - Speed 12 - FastSpeed 20 - Damage 4 - Projectile - -ACTIVATEIMPACT - -ACTIVATEPCROSS - -NOBLOCKMAP - +WINDTHRUST - +SPAWNSOUNDSOURCE - RenderStyle Add - SeeSound "beast/attack" - States - { - Spawn: - FRB1 AABBCC 2 A_SpawnItemEx("Puffy", random2[BeastPuff]()*0.015625, random2[BeastPuff]()*0.015625, random2[BeastPuff]()*0.015625, - 0,0,0,0,SXF_ABSOLUTEPOSITION, 64) - Loop - Death: - FRB1 DEFGH 4 - Stop - } -} - -// Puffy -------------------------------------------------------------------- - -ACTOR Puffy -{ - Radius 6 - Height 8 - Speed 10 - +NOBLOCKMAP - +NOGRAVITY - +MISSILE - +NOTELEPORT - +DONTSPLASH - RenderStyle Add - States - { - Spawn: - FRB1 DEFGH 4 - Stop - } -} - - - diff --git a/wadsrc/static/actors/heretic/chicken.txt b/wadsrc/static/actors/heretic/chicken.txt deleted file mode 100644 index 8d3b1e71d8..0000000000 --- a/wadsrc/static/actors/heretic/chicken.txt +++ /dev/null @@ -1,181 +0,0 @@ - -// Beak puff ---------------------------------------------------------------- - -ACTOR BeakPuff : StaffPuff -{ - Mass 5 - Renderstyle Translucent - Alpha 0.4 - AttackSound "chicken/attack" - VSpeed 1 -} - -// Beak --------------------------------------------------------------------- - -ACTOR Beak : Weapon -{ - Weapon.SelectionOrder 10000 - +WEAPON.DONTBOB - +WEAPON.MELEEWEAPON - Weapon.YAdjust 15 - Weapon.SisterWeapon "BeakPowered" - - action native A_BeakRaise (); - action native A_BeakAttackPL1(); - - States - { - Ready: - BEAK A 1 A_WeaponReady - Loop - Deselect: - BEAK A 1 A_Lower - Loop - Select: - BEAK A 1 A_BeakRaise - Loop - Fire: - BEAK A 18 A_BeakAttackPL1 - Goto Ready - } -} - - -ACTOR BeakPowered : Beak -{ - +WEAPON.POWERED_UP - Weapon.SisterWeapon "Beak" - - action native A_BeakAttackPL2(); - - States - { - Fire: - BEAK A 12 A_BeakAttackPL2 - Goto Ready - } -} - -// Chicken player ----------------------------------------------------------- - -ACTOR ChickenPlayer : PlayerPawn native -{ - Health 30 - ReactionTime 0 - PainChance 255 - Radius 16 - Height 24 - Speed 1 - Gravity 0.125 - +NOSKIN - +CANSUPERMORPH - PainSound "chicken/pain" - DeathSound "chicken/death" - Player.JumpZ 1 - Player.Viewheight 21 - Player.ForwardMove 1.22, 1.22 - Player.SideMove 1.22, 1.22 - Player.SpawnClass "Chicken" - Player.SoundClass "Chicken" - Player.DisplayName "Chicken" - Player.MorphWeapon "Beak" - -PICKUP - States - { - Spawn: - CHKN A -1 - Stop - See: - CHKN ABAB 3 - Loop - Melee: - Missile: - CHKN C 12 - Goto Spawn - Pain: - CHKN D 4 A_Feathers - CHKN C 4 A_Pain - Goto Spawn - Death: - CHKN E 6 A_Scream - CHKN F 6 A_Feathers - CHKN G 6 - CHKN H 6 A_NoBlocking - CHKN IJK 6 - CHKN L -1 - Stop - } -} - - - -// Chicken (non-player) ----------------------------------------------------- - -ACTOR Chicken : MorphedMonster -{ - Health 10 - Radius 9 - Height 22 - Mass 40 - Speed 4 - Painchance 200 - Monster - -COUNTKILL - +WINDTHRUST - +DONTMORPH - +FLOORCLIP - SeeSound "chicken/pain" - AttackSound "chicken/attack" - PainSound "chicken/pain" - DeathSound "chicken/death" - ActiveSound "chicken/active" - Obituary "$OB_CHICKEN" - States - { - Spawn: - CHKN AB 10 A_Look - Loop - See: - CHKN AB 3 A_Chase - Loop - Pain: - CHKN D 5 A_Feathers - CHKN C 5 A_Pain - Goto See - Melee: - CHKN A 8 A_FaceTarget - CHKN C 10 A_CustomMeleeAttack(random[ChicAttack](1,2)) - Goto See - Death: - CHKN E 6 A_Scream - CHKN F 6 A_Feathers - CHKN G 6 - CHKN H 6 A_NoBlocking - CHKN IJK 6 - CHKN L -1 - Stop - } -} - - -// Feather ------------------------------------------------------------------ - -ACTOR Feather -{ - Radius 2 - Height 4 - +MISSILE +DROPOFF - +NOTELEPORT +CANNOTPUSH - +WINDTHRUST +DONTSPLASH - Gravity 0.125 - States - { - Spawn: - CHKN MNOPQPON 3 - Loop - Death: - CHKN N 6 - Stop - } -} - diff --git a/wadsrc/static/actors/heretic/clink.txt b/wadsrc/static/actors/heretic/clink.txt deleted file mode 100644 index 7f3e4370d3..0000000000 --- a/wadsrc/static/actors/heretic/clink.txt +++ /dev/null @@ -1,46 +0,0 @@ - -ACTOR Clink -{ - Health 150 - Radius 20 - Height 64 - Mass 75 - Speed 14 - Painchance 32 - Monster - +NOBLOOD - +FLOORCLIP - SeeSound "clink/sight" - AttackSound "clink/attack" - PainSound "clink/pain" - DeathSound "clink/death" - ActiveSound "clink/active" - Obituary "$OB_CLINK" - DropItem "SkullRodAmmo", 84, 20 - States - { - Spawn: - CLNK AB 10 A_Look - Loop - See: - CLNK ABCD 3 A_Chase - Loop - Melee: - CLNK E 5 A_FaceTarget - CLNK F 4 A_FaceTarget - CLNK G 7 A_CustomMeleeAttack(random[ClinkAttack](3,9), "clink/attack", "clink/attack") - Goto See - Pain: - CLNK H 3 - CLNK H 3 A_Pain - Goto See - Death: - CLNK IJ 6 - CLNK K 5 A_Scream - CLNK L 5 A_NoBlocking - CLNK MN 5 - CLNK O -1 - Stop - } -} - diff --git a/wadsrc/static/actors/heretic/dsparil.txt b/wadsrc/static/actors/heretic/dsparil.txt deleted file mode 100644 index 8b2f4dc5c1..0000000000 --- a/wadsrc/static/actors/heretic/dsparil.txt +++ /dev/null @@ -1,270 +0,0 @@ - -// Boss spot ---------------------------------------------------------------- - -ACTOR BossSpot : SpecialSpot -{ - +INVISIBLE -} - -// Sorcerer (D'Sparil on his serpent) --------------------------------------- - -ACTOR Sorcerer1 -{ - Health 2000 - Radius 28 - Height 100 - Mass 800 - Speed 16 - PainChance 56 - Monster - +BOSS - +DONTMORPH - +NORADIUSDMG - +NOTARGET - +NOICEDEATH - +FLOORCLIP - +DONTGIB - SeeSound "dsparilserpent/sight" - AttackSound "dsparilserpent/attack" - PainSound "dsparilserpent/pain" - DeathSound "dsparilserpent/death" - ActiveSound "dsparilserpent/active" - Obituary "$OB_DSPARIL1" - HitObituary "$OB_DSPARIL1HIT" - - action native A_Sor1Pain (); - action native A_Sor1Chase (); - action native A_Srcr1Attack (); - action native A_SorcererRise (); - - States - { - Spawn: - SRCR AB 10 A_Look - Loop - See: - SRCR ABCD 5 A_Sor1Chase - Loop - Pain: - SRCR Q 6 A_Sor1Pain - Goto See - Missile: - SRCR Q 7 A_FaceTarget - SRCR R 6 A_FaceTarget - SRCR S 10 A_Srcr1Attack - Goto See - Missile2: - SRCR S 10 A_FaceTarget - SRCR Q 7 A_FaceTarget - SRCR R 6 A_FaceTarget - SRCR S 10 A_Srcr1Attack - Goto See - Death: - SRCR E 7 - SRCR F 7 A_Scream - SRCR G 7 - SRCR HIJK 6 - SRCR L 25 A_PlaySound("dsparil/zap", CHAN_BODY, 1, false, ATTN_NONE) - SRCR MN 5 - SRCR O 4 - SRCR L 20 A_PlaySound("dsparil/zap", CHAN_BODY, 1, false, ATTN_NONE) - SRCR MN 5 - SRCR O 4 - SRCR L 12 - SRCR P -1 A_SorcererRise - } -} - - -// Sorcerer FX 1 ------------------------------------------------------------ - -ACTOR SorcererFX1 -{ - Radius 10 - Height 10 - Speed 20 - FastSpeed 28 - Damage 10 - DamageType Fire - Projectile - -ACTIVATEIMPACT - -ACTIVATEPCROSS - RenderStyle Add - States - { - Spawn: - FX14 ABC 6 BRIGHT - Loop - Death: - FX14 DEFGH 5 BRIGHT - Stop - } -} - - -// Sorcerer 2 (D'Sparil without his serpent) -------------------------------- - -ACTOR Sorcerer2 -{ - Health 3500 - Radius 16 - Height 70 - Mass 300 - Speed 14 - Painchance 32 - Monster - +DROPOFF - +BOSS - +DONTMORPH - +FULLVOLACTIVE - +NORADIUSDMG - +NOTARGET - +NOICEDEATH - +FLOORCLIP - +BOSSDEATH - SeeSound "dsparil/sight" - AttackSound "dsparil/attack" - PainSound "dsparil/pain" - ActiveSound "dsparil/active" - Obituary "$OB_DSPARIL2" - HitObituary "$OB_DSPARIL2HIT" - - action native A_Srcr2Decide (); - action native A_Srcr2Attack (); - action native A_Sor2DthInit (); - action native A_Sor2DthLoop (); - - States - { - Spawn: - SOR2 MN 10 A_Look - Loop - See: - SOR2 MNOP 4 A_Chase - Loop - Rise: - SOR2 AB 4 - SOR2 C 4 A_PlaySound("dsparil/rise", CHAN_BODY, 1, false, ATTN_NONE) - SOR2 DEF 4 - SOR2 G 12 A_PlaySound("dsparil/sight", CHAN_BODY, 1, false, ATTN_NONE) - Goto See - Pain: - SOR2 Q 3 - SOR2 Q 6 A_Pain - Goto See - Missile: - SOR2 R 9 A_Srcr2Decide - SOR2 S 9 A_FaceTarget - SOR2 T 20 A_Srcr2Attack - Goto See - Teleport: - SOR2 LKJIHG 6 - Goto See - Death: - SDTH A 8 A_Sor2DthInit - SDTH B 8 - SDTH C 8 A_PlaySound("dsparil/scream", CHAN_BODY, 1, false, ATTN_NONE) - DeathLoop: - SDTH DE 7 - SDTH F 7 A_Sor2DthLoop - SDTH G 6 A_PlaySound("dsparil/explode", CHAN_BODY, 1, false, ATTN_NONE) - SDTH H 6 - SDTH I 18 - SDTH J 6 A_NoBlocking - SDTH K 6 A_PlaySound("dsparil/bones", CHAN_BODY, 1, false, ATTN_NONE) - SDTH LMN 6 - SDTH O -1 A_BossDeath - Stop - } -} - - - -// Sorcerer 2 FX 1 ---------------------------------------------------------- - -ACTOR Sorcerer2FX1 -{ - Radius 10 - Height 6 - Speed 20 - FastSpeed 28 - Damage 1 - Projectile - -ACTIVATEIMPACT - -ACTIVATEPCROSS - RenderStyle Add - - action native A_BlueSpark (); - - States - { - Spawn: - FX16 ABC 3 BRIGHT A_BlueSpark - Loop - Death: - FX16 G 5 BRIGHT A_Explode(random[S2FX1](80,111)) - FX16 HIJKL 5 BRIGHT - Stop - } -} - -// Sorcerer 2 FX Spark ------------------------------------------------------ - -ACTOR Sorcerer2FXSpark -{ - Radius 20 - Height 16 - +NOBLOCKMAP - +NOGRAVITY - +NOTELEPORT - +CANNOTPUSH - RenderStyle Add - States - { - Spawn: - FX16 DEF 12 BRIGHT - Stop - } -} - -// Sorcerer 2 FX 2 ---------------------------------------------------------- - -ACTOR Sorcerer2FX2 -{ - Radius 10 - Height 6 - Speed 6 - Damage 10 - Projectile - -ACTIVATEIMPACT - -ACTIVATEPCROSS - RenderStyle Add - - action native A_GenWizard (); - - States - { - Spawn: - FX11 A 35 BRIGHT - FX11 A 5 BRIGHT A_GenWizard - FX11 B 5 BRIGHT - Goto Spawn+1 - Death: - FX11 CDEFG 5 BRIGHT - Stop - - } -} -// Sorcerer 2 Telefade ------------------------------------------------------ - -ACTOR Sorcerer2Telefade -{ - +NOBLOCKMAP - States - { - Spawn: - SOR2 GHIJKL 6 - Stop - } -} - diff --git a/wadsrc/static/actors/heretic/hereticammo.txt b/wadsrc/static/actors/heretic/hereticammo.txt deleted file mode 100644 index 35f404274e..0000000000 --- a/wadsrc/static/actors/heretic/hereticammo.txt +++ /dev/null @@ -1,204 +0,0 @@ - -// Wimpy ammo --------------------------------------------------------------- - -ACTOR GoldWandAmmo : Ammo -{ - Inventory.PickupMessage "$TXT_AMMOGOLDWAND1" - Inventory.Amount 10 - Inventory.MaxAmount 100 - Ammo.BackpackAmount 10 - Ammo.BackpackMaxAmount 200 - Inventory.Icon "INAMGLD" - States - { - Spawn: - AMG1 A -1 - Stop - } -} - -// Hefty ammo --------------------------------------------------------------- - -ACTOR GoldWandHefty : GoldWandAmmo -{ - Inventory.PickupMessage "$TXT_AMMOGOLDWAND2" - Inventory.Amount 50 - States - { - Spawn: - AMG2 ABC 4 - Loop - } -} -// Wimpy ammo --------------------------------------------------------------- - -ACTOR CrossbowAmmo : Ammo -{ - Inventory.PickupMessage "$TXT_AMMOCROSSBOW1" - Inventory.Amount 5 - Inventory.MaxAmount 50 - Ammo.BackpackAmount 5 - Ammo.BackpackMaxAmount 100 - Inventory.Icon "INAMBOW" - States - { - Spawn: - AMC1 A -1 - Stop - } -} - -// Hefty ammo --------------------------------------------------------------- - -ACTOR CrossbowHefty : CrossbowAmmo -{ - Inventory.PickupMessage "$TXT_AMMOCROSSBOW2" - Inventory.Amount 20 - States - { - Spawn: - AMC2 ABC 5 - Loop - } -} -// Wimpy ammo --------------------------------------------------------------- - -ACTOR MaceAmmo : Ammo -{ - Inventory.PickupMessage "$TXT_AMMOMACE1" - Inventory.Amount 20 - Inventory.MaxAmount 150 - Ammo.BackpackAmount 20 - Ammo.BackpackMaxAmount 300 - Inventory.Icon "INAMLOB" - States - { - Spawn: - AMM1 A -1 - Stop - } -} - -// Hefty ammo --------------------------------------------------------------- - -ACTOR MaceHefty : MaceAmmo -{ - Inventory.PickupMessage "$TXT_AMMOMACE2" - Inventory.Amount 100 - States - { - Spawn: - AMM2 A -1 - Stop - } -} - -// Wimpy ammo --------------------------------------------------------------- - -ACTOR BlasterAmmo : Ammo -{ - Inventory.PickupMessage "$TXT_AMMOBLASTER1" - Inventory.Amount 10 - Inventory.MaxAmount 200 - Ammo.BackpackAmount 10 - Ammo.BackpackMaxAmount 400 - Inventory.Icon "INAMBST" - States - { - Spawn: - AMB1 ABC 4 - Loop - } -} - -// Hefty ammo --------------------------------------------------------------- - -ACTOR BlasterHefty : BlasterAmmo -{ - Inventory.PickupMessage "$TXT_AMMOBLASTER2" - Inventory.Amount 25 - States - { - Spawn: - AMB2 ABC 4 - Loop - } -} - -// Wimpy ammo --------------------------------------------------------------- - -ACTOR SkullRodAmmo : Ammo -{ - Inventory.PickupMessage "$TXT_AMMOSKULLROD1" - Inventory.Amount 20 - Inventory.MaxAmount 200 - Ammo.BackpackAmount 20 - Ammo.BackpackMaxAmount 400 - Inventory.Icon "INAMRAM" - States - { - Spawn: - AMS1 AB 5 - Loop - } -} - -// Hefty ammo --------------------------------------------------------------- - -ACTOR SkullRodHefty : SkullRodAmmo -{ - Inventory.PickupMessage "$TXT_AMMOSKULLROD2" - Inventory.Amount 100 - States - { - Spawn: - AMS2 AB 5 - Loop - } -} - -// Wimpy ammo --------------------------------------------------------------- - -ACTOR PhoenixRodAmmo : Ammo -{ - Inventory.PickupMessage "$TXT_AMMOPHOENIXROD1" - Inventory.Amount 1 - Inventory.MaxAmount 20 - Ammo.BackpackAmount 1 - Ammo.BackpackMaxAmount 40 - Inventory.Icon "INAMPNX" - States - { - Spawn: - AMP1 ABC 4 - Loop - } -} -// Hefty ammo --------------------------------------------------------------- - -ACTOR PhoenixRodHefty : PhoenixRodAmmo -{ - Inventory.PickupMessage "$TXT_AMMOPHOENIXROD2" - Inventory.Amount 10 - States - { - Spawn: - AMP2 ABC 4 - Loop - } -} - -// --- Bag of holding ------------------------------------------------------- - -ACTOR BagOfHolding : BackpackItem -{ - Inventory.PickupMessage "$TXT_ITEMBAGOFHOLDING" - +COUNTITEM - +FLOATBOB - States - { - Spawn: - BAGH A -1 - Stop - } -} diff --git a/wadsrc/static/actors/heretic/hereticarmor.txt b/wadsrc/static/actors/heretic/hereticarmor.txt deleted file mode 100644 index 91684cc0e4..0000000000 --- a/wadsrc/static/actors/heretic/hereticarmor.txt +++ /dev/null @@ -1,35 +0,0 @@ - -// Silver Shield (Shield1) -------------------------------------------------- - -Actor SilverShield : BasicArmorPickup -{ - +FLOATBOB - Inventory.Pickupmessage "$TXT_ITEMSHIELD1" - Inventory.Icon "SHLDA0" - Armor.Savepercent 50 - Armor.Saveamount 100 - States - { - Spawn: - SHLD A -1 - stop - } -} - -// Enchanted shield (Shield2) ----------------------------------------------- - -Actor EnchantedShield : BasicArmorPickup -{ - +FLOATBOB - Inventory.Pickupmessage "$TXT_ITEMSHIELD2" - Inventory.Icon "SHD2A0" - Armor.Savepercent 75 - Armor.Saveamount 200 - States - { - Spawn: - SHD2 A -1 - stop - } -} - diff --git a/wadsrc/static/actors/heretic/hereticartifacts.txt b/wadsrc/static/actors/heretic/hereticartifacts.txt deleted file mode 100644 index 9555415fda..0000000000 --- a/wadsrc/static/actors/heretic/hereticartifacts.txt +++ /dev/null @@ -1,103 +0,0 @@ -// Super map ---------------------------------------------------------------- - -ACTOR SuperMap : MapRevealer -{ - +COUNTITEM - +INVENTORY.ALWAYSPICKUP - +FLOATBOB - Inventory.MaxAmount 0 - Inventory.PickupMessage "$TXT_ITEMSUPERMAP" - States - { - Spawn: - SPMP A -1 - Stop - } -} - - -// Invisibility ------------------------------------------------------------- - -ACTOR ArtiInvisibility : PowerupGiver -{ - +COUNTITEM - +FLOATBOB - +INVENTORY.PICKUPFLASH - RenderStyle Translucent - Alpha 0.4 - Inventory.RespawnTics 4230 - Inventory.Icon ARTIINVS - Powerup.Type Ghost - Inventory.PickupMessage "$TXT_ARTIINVISIBILITY" - Tag "$TAG_ARTIINVISIBILITY" - States - { - Spawn: - INVS A 350 Bright - Loop - } -} - - -// Tome of power ------------------------------------------------------------ - -ACTOR ArtiTomeOfPower : PowerupGiver native -{ - +COUNTITEM - +FLOATBOB - +INVENTORY.PICKUPFLASH - Inventory.Icon "ARTIPWBK" - Powerup.Type Weaponlevel2 - Inventory.PickupMessage "$TXT_ARTITOMEOFPOWER" - Tag "$TAG_ARTITOMEOFPOWER" - States - { - Spawn: - PWBK A 350 - Loop - } -} - - -// Time bomb ---------------------------------------------------------------- - -ACTOR ActivatedTimeBomb -{ - +NOGRAVITY - RenderStyle Translucent - Alpha 0.4 - DeathSound "misc/timebomb" - - action native A_Timebomb(); - - States - { - Spawn: - FBMB ABCD 10 - FBMB E 6 A_Scream - XPL1 A 4 BRIGHT A_Timebomb - XPL1 BCDEF 4 BRIGHT - Stop - } -} - - -ACTOR ArtiTimeBomb : Inventory native -{ - +COUNTITEM - +FLOATBOB - +INVENTORY.PICKUPFLASH - +INVENTORY.INVBAR - +INVENTORY.FANCYPICKUPSOUND - Inventory.Icon "ARTIFBMB" - Inventory.PickupSound "misc/p_pkup" - Inventory.PickupMessage "$TXT_ARTIFIREBOMB" - Tag "$TAG_ARTIFIREBOMB" - Inventory.DefMaxAmount - States - { - Spawn: - FBMB E 350 - Loop - } -} diff --git a/wadsrc/static/actors/heretic/hereticdecorations.txt b/wadsrc/static/actors/heretic/hereticdecorations.txt deleted file mode 100644 index 032ee33a1d..0000000000 --- a/wadsrc/static/actors/heretic/hereticdecorations.txt +++ /dev/null @@ -1,248 +0,0 @@ -ACTOR SkullHang70 -{ - Radius 20 - Height 70 - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - SKH1 A -1 - Stop - } -} - -ACTOR SkullHang60 -{ - Radius 20 - Height 60 - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - SKH2 A -1 - Stop - } -} - -ACTOR SkullHang45 -{ - Radius 20 - Height 45 - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - SKH3 A -1 - Stop - } -} - -ACTOR SkullHang35 -{ - Radius 20 - Height 35 - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - SKH4 A -1 - Stop - } -} - -ACTOR Chandelier -{ - Radius 20 - Height 60 - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - CHDL ABC 4 - Loop - } -} - -ACTOR SerpentTorch -{ - Radius 12 - Height 54 - +SOLID - States - { - Spawn: - SRTC ABC 4 - Loop - } -} - -ACTOR SmallPillar -{ - Radius 16 - Height 34 - +SOLID - States - { - Spawn: - SMPL A -1 - Stop - } -} - -ACTOR StalagmiteSmall -{ - Radius 8 - Height 32 - +SOLID - States - { - Spawn: - STGS A -1 - Stop - } -} - -ACTOR StalagmiteLarge -{ - Radius 12 - Height 64 - +SOLID - States - { - Spawn: - STGL A -1 - Stop - } -} - -ACTOR StalactiteSmall -{ - Radius 8 - Height 36 - +SOLID - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - STCS A -1 - Stop - } -} - -ACTOR StalactiteLarge -{ - Radius 12 - Height 68 - +SOLID - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - STCL A -1 - Stop - } -} - -ACTOR FireBrazier -{ - Radius 16 - Height 44 - +SOLID - States - { - Spawn: - KFR1 ABCDEFGH 3 Bright - Loop - } -} - -ACTOR Barrel -{ - Radius 12 - Height 32 - +SOLID - States - { - Spawn: - BARL A -1 - Stop - } -} - -ACTOR BrownPillar -{ - Radius 14 - Height 128 - +SOLID - States - { - Spawn: - BRPL A -1 - Stop - } -} - -ACTOR Moss1 -{ - Radius 20 - Height 23 - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - MOS1 A -1 - Stop - } -} - -ACTOR Moss2 -{ - Radius 20 - Height 27 - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - MOS2 A -1 - Stop - } -} - -ACTOR WallTorch -{ - Radius 6 - Height 16 - +NOGRAVITY - +FIXMAPTHINGPOS - States - { - Spawn: - WTRH ABC 6 Bright - Loop - } -} - -ACTOR HangingCorpse -{ - Radius 8 - Height 104 - +SOLID - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - HCOR A -1 - Stop - } -} - diff --git a/wadsrc/static/actors/heretic/hereticimp.txt b/wadsrc/static/actors/heretic/hereticimp.txt deleted file mode 100644 index fdbdeb9b7d..0000000000 --- a/wadsrc/static/actors/heretic/hereticimp.txt +++ /dev/null @@ -1,156 +0,0 @@ - -// Heretic imp (as opposed to the Doom variety) ----------------------------- - -ACTOR HereticImp -{ - Health 40 - Radius 16 - Height 36 - Mass 50 - Speed 10 - Painchance 200 - Monster - +FLOAT - +NOGRAVITY - +SPAWNFLOAT - +DONTOVERLAP - +MISSILEMORE - SeeSound "himp/sight" - AttackSound "himp/attack" - PainSound "himp/pain" - DeathSound "himp/death" - ActiveSound "himp/active" - Obituary "$OB_HERETICIMP" - HitObituary "$OB_HERETICIMPHIT" - - action native A_ImpMsAttack(); - action native A_ImpDeath(); - action native A_ImpXDeath1(); - action native A_ImpExplode(); - - - States - { - Spawn: - IMPX ABCB 10 A_Look - Loop - See: - IMPX AABBCCBB 3 A_Chase - Loop - Melee: - IMPX DE 6 A_FaceTarget - IMPX F 6 A_CustomMeleeAttack(random[ImpMeAttack](5,12), "himp/attack", "himp/attack") - Goto See - Missile: - IMPX A 10 A_FaceTarget - IMPX B 6 A_ImpMsAttack - IMPX CBAB 6 - Goto Missile+2 - Pain: - IMPX G 3 - IMPX G 3 A_Pain - Goto See - Death: - IMPX G 4 A_ImpDeath - IMPX H 5 - Wait - XDeath: - IMPX S 5 A_ImpXDeath1 - IMPX TU 5 - IMPX V 5 A_Gravity - IMPX W 5 - Wait - Crash: - IMPX I 7 A_ImpExplode - IMPX J 7 A_Scream - IMPX K 7 - IMPX L -1 - Stop - XCrash: - IMPX X 7 - IMPX Y 7 - IMPX Z -1 - Stop - } -} - -// Heretic imp leader ------------------------------------------------------- - -ACTOR HereticImpLeader : HereticImp -{ - Species "HereticImpLeader" - Health 80 - -MISSILEMORE - AttackSound "himp/leaderattack" - States - { - Melee: - Stop - Missile: - IMPX DE 6 A_FaceTarget - IMPX F 6 A_CustomComboAttack("HereticImpBall", 32, random[ImpMsAttack2](5,12), "himp/leaderattack") - Goto See - } -} - -// Heretic imp chunk 1 ------------------------------------------------------ - -ACTOR HereticImpChunk1 -{ - Mass 5 - Radius 4 - +NOBLOCKMAP - +MOVEWITHSECTOR - States - { - Spawn: - IMPX M 5 - IMPX NO 700 - Stop - } -} - -// Heretic imp chunk 2 ------------------------------------------------------ - -ACTOR HereticImpChunk2 -{ - Mass 5 - Radius 4 - +NOBLOCKMAP - +MOVEWITHSECTOR - States - { - Spawn: - IMPX P 5 - IMPX QR 700 - Stop - } -} - -// Heretic imp ball --------------------------------------------------------- - -ACTOR HereticImpBall -{ - Radius 8 - Height 8 - Speed 10 - FastSpeed 20 - Damage 1 - Projectile - SeeSound "himp/leaderattack" - +SPAWNSOUNDSOURCE - -ACTIVATEPCROSS - -ACTIVATEIMPACT - RenderStyle Add - States - { - Spawn: - FX10 ABC 6 Bright - Loop - Death: - FX10 DEFG 5 Bright - Stop - } -} - - diff --git a/wadsrc/static/actors/heretic/heretickeys.txt b/wadsrc/static/actors/heretic/heretickeys.txt deleted file mode 100644 index 1bda24dcc5..0000000000 --- a/wadsrc/static/actors/heretic/heretickeys.txt +++ /dev/null @@ -1,144 +0,0 @@ - -ACTOR HereticKey : Key -{ - +NOTDMATCH - Radius 20 - Height 16 -} - -// Green key ------------------------------------------------------------ - -ACTOR KeyGreen : HereticKey -{ - Inventory.PickupMessage "$TXT_GOTGREENKEY" - Inventory.Icon "GKEYICON" - States - { - Spawn: - AKYY ABCDEFGHIJ 3 Bright - Loop - } -} - -// Blue key ----------------------------------------------------------------- - -ACTOR KeyBlue : HereticKey -{ - Inventory.PickupMessage "$TXT_GOTBLUEKEY" - Inventory.Icon "BKEYICON" - States - { - Spawn: - BKYY ABCDEFGHIJ 3 Bright - Loop - } -} - -// Yellow key --------------------------------------------------------------- - -ACTOR KeyYellow : HereticKey -{ - Inventory.PickupMessage "$TXT_GOTYELLOWKEY" - Inventory.Icon "YKEYICON" - States - { - Spawn: - CKYY ABCDEFGHI 3 Bright - Loop - } -} - - -// --- Blue Key gizmo ----------------------------------------------------------- - -ACTOR KeyGizmoBlue -{ - Radius 16 - Height 50 - +SOLID - States - { - Spawn: - KGZ1 A 1 - KGZ1 A 1 A_SpawnItemEx("KeyGizmoFloatBlue", 0, 0, 60) - KGZ1 A -1 - Stop - } -} - -ACTOR KeyGizmoFloatBlue -{ - Radius 16 - Height 16 - +SOLID - +NOGRAVITY - States - { - Spawn: - KGZB A -1 Bright - Stop - } -} - -// --- Green Key gizmo ----------------------------------------------------------- - -ACTOR KeyGizmoGreen -{ - Radius 16 - Height 50 - +SOLID - States - { - Spawn: - KGZ1 A 1 - KGZ1 A 1 A_SpawnItemEx("KeyGizmoFloatGreen", 0, 0, 60) - KGZ1 A -1 - Stop - } -} - -ACTOR KeyGizmoFloatGreen -{ - Radius 16 - Height 16 - +SOLID - +NOGRAVITY - States - { - Spawn: - KGZG A -1 Bright - Stop - } -} - -// --- Yellow Key gizmo ----------------------------------------------------------- - -ACTOR KeyGizmoYellow -{ - Radius 16 - Height 50 - +SOLID - States - { - Spawn: - KGZ1 A 1 - KGZ1 A 1 A_SpawnItemEx("KeyGizmoFloatYellow", 0, 0, 60) - KGZ1 A -1 - Stop - } -} - -ACTOR KeyGizmoFloatYellow -{ - Radius 16 - Height 16 - +SOLID - +NOGRAVITY - States - { - Spawn: - KGZY A -1 Bright - Stop - } -} - diff --git a/wadsrc/static/actors/heretic/hereticmisc.txt b/wadsrc/static/actors/heretic/hereticmisc.txt deleted file mode 100644 index 9b000ede32..0000000000 --- a/wadsrc/static/actors/heretic/hereticmisc.txt +++ /dev/null @@ -1,229 +0,0 @@ - -// Pod ---------------------------------------------------------------------- - -ACTOR Pod -{ - Health 45 - Radius 16 - Height 54 - Painchance 255 - +SOLID +NOBLOOD +SHOOTABLE +DROPOFF - +WINDTHRUST +PUSHABLE +SLIDESONWALLS - +CANPASS +TELESTOMP +DONTMORPH - +NOBLOCKMONST +DONTGIB +OLDRADIUSDMG - DeathSound "world/podexplode" - PushFactor 0.5 - - action native A_PodPain (class podtype = "PodGoo"); - action native A_RemovePod (); - - States - { - Spawn: - PPOD A 10 - Loop - Pain: - PPOD B 14 A_PodPain - Goto Spawn - Death: - PPOD C 5 BRIGHT A_RemovePod - PPOD D 5 BRIGHT A_Scream - PPOD E 5 BRIGHT A_Explode - PPOD F 10 BRIGHT - Stop - Grow: - PPOD IJKLMNOP 3 - Goto Spawn - } -} - - -// Pod goo (falls from pod when damaged) ------------------------------------ - -ACTOR PodGoo -{ - Radius 2 - Height 4 - Gravity 0.125 - +NOBLOCKMAP +MISSILE +DROPOFF - +NOTELEPORT +CANNOTPUSH - States - { - Spawn: - PPOD GH 8 - Loop - Death: - PPOD G 10 - Stop - } -} - -// Pod generator ------------------------------------------------------------ - -ACTOR PodGenerator -{ - +NOBLOCKMAP - +NOSECTOR - +DONTSPLASH - AttackSound "world/podgrow" - - action native A_MakePod (class podtype = "Pod"); - - States - { - Spawn: - TNT1 A 35 A_MakePod - Loop - } -} - - -// Teleglitter generator 1 -------------------------------------------------- - -ACTOR TeleGlitterGenerator1 -{ - +NOBLOCKMAP - +NOGRAVITY - +DONTSPLASH - +MOVEWITHSECTOR - States - { - Spawn: - TNT1 A 8 A_SpawnItemEx("TeleGlitter1", random[TeleGlitter](0,31)-16, random[TeleGlitter](0,31)-16, 0, 0,0,0.25) - Loop - } -} - -// Teleglitter generator 2 -------------------------------------------------- - -ACTOR TeleGlitterGenerator2 -{ - +NOBLOCKMAP - +NOGRAVITY - +DONTSPLASH - +MOVEWITHSECTOR - States - { - Spawn: - TNT1 A 8 A_SpawnItemEx("TeleGlitter2", random[TeleGlitter2](0,31)-16, random[TeleGlitter2](0,31)-16, 0, 0,0,0.25) - Loop - } -} - - -// Teleglitter 1 ------------------------------------------------------------ - -ACTOR TeleGlitter1 -{ - +NOBLOCKMAP +NOGRAVITY +MISSILE - RenderStyle Add - Damage 0 - - action native A_AccTeleGlitter (); - - States - { - Spawn: - TGLT A 2 BRIGHT - TGLT B 2 BRIGHT A_AccTeleGlitter - TGLT C 2 BRIGHT - TGLT D 2 BRIGHT A_AccTeleGlitter - TGLT E 2 BRIGHT - Loop - } -} - -// Teleglitter 2 ------------------------------------------------------------ - -ACTOR TeleGlitter2 : TeleGlitter1 -{ - States - { - Spawn: - TGLT F 2 BRIGHT - TGLT G 2 BRIGHT A_AccTeleGlitter - TGLT H 2 BRIGHT - TGLT I 2 BRIGHT A_AccTeleGlitter - TGLT J 2 BRIGHT - Loop - } -} - - -// --- Volcano -------------------------------------------------------------- - -ACTOR Volcano -{ - Radius 12 - Height 20 - +SOLID - - action native A_VolcanoSet (); - action native A_VolcanoBlast (); - - States - { - Spawn: - VLCO A 350 - VLCO A 35 A_VolcanoSet - VLCO BCDBCD 3 - VLCO E 10 A_VolcanoBlast - Goto Spawn+1 - } - -} - -// Volcano blast ------------------------------------------------------------ - -ACTOR VolcanoBlast -{ - Radius 8 - Height 8 - Speed 2 - Damage 2 - DamageType Fire - Gravity 0.125 - +NOBLOCKMAP +MISSILE +DROPOFF - +NOTELEPORT - DeathSound "world/volcano/blast" - - action native A_VolcBallImpact (); - - States - { - Spawn: - VFBL AB 4 BRIGHT A_SpawnItemEx("Puffy", random2[BeastPuff]()*0.015625, random2[BeastPuff]()*0.015625, random2[BeastPuff]()*0.015625, - 0,0,0,0,SXF_ABSOLUTEPOSITION, 64) - Loop - - Death: - XPL1 A 4 BRIGHT A_VolcBallImpact - XPL1 BCDEF 4 BRIGHT - Stop - } -} - -// Volcano T Blast ---------------------------------------------------------- - -ACTOR VolcanoTBlast -{ - Radius 8 - Height 6 - Speed 2 - Damage 1 - DamageType Fire - Gravity 0.125 - +NOBLOCKMAP +MISSILE +DROPOFF - +NOTELEPORT - States - { - Spawn: - VTFB AB 4 BRIGHT - Loop - Death: - SFFI CBABCDE 4 BRIGHT - Stop - } -} - - diff --git a/wadsrc/static/actors/heretic/hereticplayer.txt b/wadsrc/static/actors/heretic/hereticplayer.txt deleted file mode 100644 index 5a3e437729..0000000000 --- a/wadsrc/static/actors/heretic/hereticplayer.txt +++ /dev/null @@ -1,129 +0,0 @@ -ACTOR HereticPlayer : PlayerPawn -{ - Health 100 - Radius 16 - Height 56 - Mass 100 - Painchance 255 - Speed 1 - Player.DisplayName "Corvus" - Player.StartItem "GoldWand" - Player.StartItem "Staff" - Player.StartItem "GoldWandAmmo", 50 - Player.WeaponSlot 1, Staff, Gauntlets - Player.WeaponSlot 2, GoldWand - Player.WeaponSlot 3, Crossbow - Player.WeaponSlot 4, Blaster - Player.WeaponSlot 5, SkullRod - Player.WeaponSlot 6, PhoenixRod - Player.WeaponSlot 7, Mace - - Player.ColorRange 225, 240 - Player.Colorset 0, "Green", 225, 240, 238 - Player.Colorset 1, "Yellow", 114, 129, 127 - Player.Colorset 2, "Red", 145, 160, 158 - Player.Colorset 3, "Blue", 190, 205, 203 - // Doom Legacy additions - Player.Colorset 4, "Brown", 67, 82, 80 - Player.Colorset 5, "Light Gray", 9, 24, 22 - Player.Colorset 6, "Light Brown", 74, 89, 87 - Player.Colorset 7, "Light Red", 150, 165, 163 - Player.Colorset 8, "Light Blue", 192, 207, 205 - Player.Colorset 9, "Beige", 95, 110, 108 - - States - { - Spawn: - PLAY A -1 - Stop - See: - PLAY ABCD 4 - Loop - Melee: - Missile: - PLAY F 6 BRIGHT - PLAY E 12 - Goto Spawn - Pain: - PLAY G 4 - PLAY G 4 A_Pain - Goto Spawn - Death: - PLAY H 6 A_PlayerSkinCheck("AltSkinDeath") - PLAY I 6 A_PlayerScream - PLAY JK 6 - PLAY L 6 A_NoBlocking - PLAY MNO 6 - PLAY P -1 - Stop - XDeath: - PLAY Q 0 A_PlayerSkinCheck("AltSkinXDeath") - PLAY Q 5 A_PlayerScream - PLAY R 0 A_NoBlocking - PLAY R 5 A_SkullPop - PLAY STUVWX 5 - PLAY Y -1 - Stop - Burn: - FDTH A 5 BRIGHT A_PlaySound("*burndeath") - FDTH B 4 BRIGHT - FDTH C 5 BRIGHT - FDTH D 4 BRIGHT A_PlayerScream - FDTH E 5 BRIGHT - FDTH F 4 BRIGHT - FDTH G 5 BRIGHT A_PlaySound("*burndeath") - FDTH H 4 BRIGHT - FDTH I 5 BRIGHT - FDTH J 4 BRIGHT - FDTH K 5 BRIGHT - FDTH L 4 BRIGHT - FDTH M 5 BRIGHT - FDTH N 4 BRIGHT - FDTH O 5 BRIGHT A_NoBlocking - FDTH P 4 BRIGHT - FDTH Q 5 BRIGHT - FDTH R 4 BRIGHT - ACLO E 35 A_CheckPlayerDone - Wait - AltSkinDeath: - PLAY H 10 - PLAY I 10 A_PlayerScream - PLAY J 10 A_NoBlocking - PLAY KLM 10 - PLAY N -1 - Stop - AltSkinXDeath: - PLAY O 5 - PLAY P 5 A_XScream - PLAY Q 5 A_NoBlocking - PLAY RSTUV 5 - PLAY W -1 - Stop - } -} - -// The player's skull ------------------------------------------------------- - -ACTOR BloodySkull : PlayerChunk -{ - Radius 4 - Height 4 - +NOBLOCKMAP - +DROPOFF - +LOWGRAVITY - +CANNOTPUSH - +SKYEXPLODE - +NOBLOCKMONST - +NOSKIN - States - { - Spawn: - BSKL A 0 - BSKL ABCDE 5 A_CheckFloor("Hit") - Goto Spawn+1 - Hit: - BSKL F 16 A_CheckPlayerDone - Wait - } -} - diff --git a/wadsrc/static/actors/heretic/hereticweaps.txt b/wadsrc/static/actors/heretic/hereticweaps.txt deleted file mode 100644 index 41461379af..0000000000 --- a/wadsrc/static/actors/heretic/hereticweaps.txt +++ /dev/null @@ -1,1133 +0,0 @@ - -ACTOR HereticWeapon : Weapon -{ - Weapon.Kickback 150 -} - - -// Staff -------------------------------------------------------------------- - -ACTOR Staff : HereticWeapon -{ - Weapon.SelectionOrder 3800 - +THRUGHOST - +WIMPY_WEAPON - +MELEEWEAPON - Weapon.sisterweapon "StaffPowered" - Obituary "$OB_MPSTAFF" - Tag "$TAG_STAFF" - - action native A_StaffAttack (int damage, class puff); - - States - { - Ready: - STFF A 1 A_WeaponReady - Loop - Deselect: - STFF A 1 A_Lower - Loop - Select: - STFF A 1 A_Raise - Loop - Fire: - STFF B 6 - STFF C 8 A_StaffAttack(random[StaffAttack](5, 20), "StaffPuff") - STFF B 8 A_ReFire - Goto Ready - } -} - -ACTOR StaffPowered : Staff -{ - Weapon.sisterweapon "Staff" - Weapon.ReadySound "weapons/staffcrackle" - +WEAPON.POWERED_UP - +WEAPON.READYSNDHALF - +WEAPON.STAFF2_KICKBACK - Obituary "$OB_MPPSTAFF" - Tag "$TAG_STAFFP" - States - { - Ready: - STFF DEF 4 A_WeaponReady - Loop - Deselect: - STFF D 1 A_Lower - Loop - Select: - STFF D 1 A_Raise - Loop - Fire: - STFF G 6 - STFF H 8 A_StaffAttack(random[StaffAttack](18, 81), "StaffPuff2") - STFF G 8 A_ReFire - Goto Ready - } -} - - -// Staff puff --------------------------------------------------------------- - -ACTOR StaffPuff -{ - RenderStyle Translucent - Alpha 0.4 - VSpeed 1 - +NOBLOCKMAP - +NOGRAVITY - +PUFFONACTORS - AttackSound "weapons/staffhit" - States - { - Spawn: - PUF3 A 4 BRIGHT - PUF3 BCD 4 - Stop - } -} - -// Staff puff 2 ------------------------------------------------------------- - -ACTOR StaffPuff2 -{ - RenderStyle Add - +NOBLOCKMAP - +NOGRAVITY - +PUFFONACTORS - AttackSound "weapons/staffpowerhit" - States - { - Spawn: - PUF4 ABCDEF 4 BRIGHT - Stop - } -} - - - -// Gold wand ---------------------------------------------------------------- - -ACTOR GoldWand : HereticWeapon -{ - +BLOODSPLATTER - Weapon.SelectionOrder 2000 - Weapon.AmmoGive 25 - Weapon.AmmoUse 1 - Weapon.AmmoType "GoldWandAmmo" - Weapon.SisterWeapon "GoldWandPowered" - Weapon.YAdjust 5 - Inventory.PickupMessage "$TXT_WPNGOLDWAND" - Obituary "$OB_MPGOLDWAND" - Tag "$TAG_GOLDWAND" - - action native A_FireGoldWandPL1 (); - - States - { - Spawn: - GWAN A -1 - Stop - Ready: - GWND A 1 A_WeaponReady - Loop - Deselect: - GWND A 1 A_Lower - Loop - Select: - GWND A 1 A_Raise - Loop - Fire: - GWND B 3 - GWND C 5 A_FireGoldWandPL1 - GWND D 3 - GWND D 0 A_ReFire - Goto Ready - } -} - -ACTOR GoldWandPowered : GoldWand -{ - +WEAPON.POWERED_UP - Weapon.AmmoGive 0 - Weapon.SisterWeapon "GoldWand" - Obituary "$OB_MPPGOLDWAND" - Tag "$TAG_GOLDWANDP" - - action native A_FireGoldWandPL2 (); - - States - { - Fire: - GWND B 3 - GWND C 4 A_FireGoldWandPL2 - GWND D 3 - GWND D 0 A_ReFire - Goto Ready - } -} - - -// Gold wand FX1 ------------------------------------------------------------ - -ACTOR GoldWandFX1 -{ - Radius 10 - Height 6 - Speed 22 - Damage 2 - Projectile - RenderStyle Add - DeathSound "weapons/wandhit" - Obituary "$OB_MPPGOLDWAND" - States - { - Spawn: - FX01 AB 6 BRIGHT - Loop - Death: - FX01 EFGH 3 BRIGHT - Stop - } -} - -// Gold wand FX2 ------------------------------------------------------------ - -ACTOR GoldWandFX2 : GoldWandFX1 -{ - Speed 18 - Damage 1 - DeathSound "" - States - { - Spawn: - FX01 CD 6 BRIGHT - Loop - } -} - -// Gold wand puff 1 --------------------------------------------------------- - -ACTOR GoldWandPuff1 -{ - +NOBLOCKMAP - +NOGRAVITY - +PUFFONACTORS - RenderStyle Add - States - { - Spawn: - PUF2 ABCDE 3 BRIGHT - Stop - } -} - -// Gold wand puff 2 --------------------------------------------------------- - -ACTOR GoldWandPuff2 : GoldWandFX1 -{ - Skip_Super - +NOBLOCKMAP - +NOGRAVITY - +PUFFONACTORS - States - { - Spawn: - Goto Super::Death - } -} - - -// Crossbow ----------------------------------------------------------------- - -ACTOR Crossbow : HereticWeapon -{ - Weapon.SelectionOrder 800 - Weapon.AmmoUse 1 - Weapon.AmmoGive 10 - Weapon.AmmoType "CrossbowAmmo" - Weapon.SisterWeapon "CrossbowPowered" - Weapon.YAdjust 15 - Inventory.PickupMessage "$TXT_WPNCROSSBOW" - Tag "$TAG_CROSSBOW" - - action native A_FireCrossbowPL1 (); - - States - { - Spawn: - WBOW A -1 - Stop - Ready: - CRBW AAAAAABBBBBBCCCCCC 1 A_WeaponReady - Loop - Deselect: - CRBW A 1 A_Lower - Loop - Select: - CRBW A 1 A_Raise - Loop - Fire: - CRBW D 6 A_FireCrossbowPL1 - CRBW EFGH 3 - CRBW AB 4 - CRBW C 5 A_ReFire - Goto Ready - } -} - - -ACTOR CrossbowPowered : Crossbow -{ - +WEAPON.POWERED_UP - Weapon.AmmoGive 0 - Weapon.SisterWeapon "Crossbow" - Tag "$TAG_CROSSBOWP" - - action native A_FireCrossbowPL2(); - - States - { - Fire: - CRBW D 5 A_FireCrossbowPL2 - CRBW E 3 - CRBW F 2 - CRBW G 3 - CRBW H 2 - CRBW A 3 - CRBW B 3 - CRBW C 4 A_ReFire - Goto Ready - } -} - - -// Crossbow FX1 ------------------------------------------------------------- - -ACTOR CrossbowFX1 -{ - Radius 11 - Height 8 - Speed 30 - Damage 10 - Projectile - RenderStyle Add - SeeSound "weapons/bowshoot" - DeathSound "weapons/bowhit" - Obituary "$OB_MPCROSSBOW" - States - { - Spawn: - FX03 B 1 BRIGHT - Loop - Death: - FX03 HIJ 8 BRIGHT - Stop - } -} - - -// Crossbow FX2 ------------------------------------------------------------- - -ACTOR CrossbowFX2 : CrossbowFX1 -{ - Speed 32 - Damage 6 - Obituary "$OB_MPPCROSSBOW" - States - { - Spawn: - FX03 B 1 BRIGHT A_SpawnItemEx("CrossbowFX4", random2[BoltSpark]()*0.015625, random2[BoltSpark]()*0.015625, 0, 0,0,0,0,SXF_ABSOLUTEPOSITION, 50) - Loop - } -} - -// Crossbow FX3 ------------------------------------------------------------- - -ACTOR CrossbowFX3 : CrossbowFX1 -{ - Speed 20 - Damage 2 - SeeSound "" - -NOBLOCKMAP - +WINDTHRUST - +THRUGHOST - States - { - Spawn: - FX03 A 1 BRIGHT - Loop - Death: - FX03 CDE 8 BRIGHT - Stop - } -} - -// Crossbow FX4 ------------------------------------------------------------- - -ACTOR CrossbowFX4 -{ - +NOBLOCKMAP - Gravity 0.125 - RenderStyle Add - States - { - Spawn: - FX03 FG 8 BRIGHT - Stop - } -} - - - - -// Gauntlets ---------------------------------------------------------------- - -ACTOR Gauntlets : Weapon -{ - +BLOODSPLATTER - Weapon.SelectionOrder 2300 - +WEAPON.WIMPY_WEAPON - +WEAPON.MELEEWEAPON - Weapon.Kickback 0 - Weapon.YAdjust 15 - Weapon.UpSound "weapons/gauntletsactivate" - Weapon.SisterWeapon "GauntletsPowered" - Inventory.PickupMessage "$TXT_WPNGAUNTLETS" - Tag "$TAG_GAUNTLETS" - Obituary "$OB_MPGAUNTLETS" - - action native A_GauntletAttack (int power); - - States - { - Spawn: - WGNT A -1 - Stop - Ready: - GAUN A 1 A_WeaponReady - Loop - Deselect: - GAUN A 1 A_Lower - Loop - Select: - GAUN A 1 A_Raise - Loop - Fire: - GAUN B 4 A_PlayWeaponSound("weapons/gauntletsuse") - GAUN C 4 - Hold: - GAUN DEF 4 BRIGHT A_GauntletAttack(0) - GAUN C 4 A_ReFire - GAUN B 4 A_Light0 - Goto Ready - } -} - - -ACTOR GauntletsPowered : Gauntlets -{ - +POWERED_UP - Tag "$TAG_GAUNTLETSP" - Obituary "$OB_MPPGAUNTLETS" - Weapon.SisterWeapon "Gauntlets" - States - { - Ready: - GAUN GHI 4 A_WeaponReady - Loop - Deselect: - GAUN G 1 A_Lower - Loop - Select: - GAUN G 1 A_Raise - Loop - Fire: - GAUN J 4 A_PlayWeaponSound("weapons/gauntletsuse") - GAUN K 4 - Hold: - GAUN LMN 4 BRIGHT A_GauntletAttack(1) - GAUN K 4 A_ReFire - GAUN J 4 A_Light0 - Goto Ready - } -} - - -// Gauntlet puff 1 ---------------------------------------------------------- - -ACTOR GauntletPuff1 -{ - +NOBLOCKMAP - +NOGRAVITY - +PUFFONACTORS - RenderStyle Translucent - Alpha 0.4 - VSpeed 0.8 - States - { - Spawn: - PUF1 ABCD 4 BRIGHT - Stop - } -} - -// Gauntlet puff 2 --------------------------------------------------------- - -ACTOR GauntletPuff2 : GauntletPuff1 -{ - States - { - Spawn: - PUF1 EFGH 4 BRIGHT - Stop - } -} - - -// The mace itself ---------------------------------------------------------- - -ACTOR Mace : HereticWeapon -{ - Weapon.SelectionOrder 1400 - Weapon.AmmoUse 1 - Weapon.AmmoGive1 50 - Weapon.YAdjust 15 - Weapon.AmmoType "MaceAmmo" - Weapon.SisterWeapon "MacePowered" - Inventory.PickupMessage "$TXT_WPNMACE" - Tag "$TAG_MACE" - - action native A_FireMacePL1(); - - States - { - Spawn: - WMCE A -1 - Stop - Ready: - MACE A 1 A_WeaponReady - Loop - Deselect: - MACE A 1 A_Lower - Loop - Select: - MACE A 1 A_Raise - Loop - Fire: - MACE B 4 - Hold: - MACE CDEF 3 A_FireMacePL1 - MACE C 4 A_ReFire - MACE DEFB 4 - Goto Ready - } -} - -ACTOR MacePowered : Mace -{ - +WEAPON.POWERED_UP - Weapon.AmmoUse 5 - Weapon.AmmoGive 0 - Weapon.SisterWeapon "Mace" - Tag "$TAG_MACEP" - - action native A_FireMacePL2(); - - States - { - Fire: - Hold: - MACE B 4 - MACE D 4 A_FireMacePL2 - MACE B 4 - MACE A 8 A_ReFire - Goto Ready - } -} - -// Mace FX1 ----------------------------------------------------------------- - -ACTOR MaceFX1 -{ - Radius 8 - Height 6 - Speed 20 - Damage 2 - Projectile - +THRUGHOST - BounceType "HereticCompat" - SeeSound "weapons/maceshoot" - Obituary "$OB_MPMACE" - - action native A_MacePL1Check(); - action native A_MaceBallImpact(); - - States - { - Spawn: - FX02 AB 4 A_MacePL1Check - Loop - Death: - FX02 F 4 BRIGHT A_MaceBallImpact - FX02 GHIJ 4 BRIGHT - Stop - } -} - -// Mace FX2 ----------------------------------------------------------------- - -ACTOR MaceFX2 : MaceFX1 -{ - Speed 10 - Damage 6 - Gravity 0.125 - -NOGRAVITY - SeeSound "" - - action native A_MaceBallImpact2(); - - States - { - Spawn: - FX02 CD 4 - Loop - Death: - FX02 F 4 A_MaceBallImpact2 - goto Super::Death+1 - } -} - -// Mace FX3 ----------------------------------------------------------------- - -ACTOR MaceFX3 : MaceFX1 -{ - Speed 7 - Damage 4 - -NOGRAVITY - Gravity 0.125 - States - { - Spawn: - FX02 AB 4 - Loop - } -} - - -// Mace FX4 ----------------------------------------------------------------- - -ACTOR MaceFX4 native -{ - Radius 8 - Height 6 - Speed 7 - Damage 18 - Gravity 0.125 - Projectile - -NOGRAVITY - +TELESTOMP - +THRUGHOST - -NOTELEPORT - BounceType "HereticCompat" - SeeSound "" - Obituary "$OB_MPPMACE" - - action native A_DeathBallImpact(); - - States - { - Spawn: - FX02 E 99 - Loop - Death: - FX02 C 4 A_DeathBallImpact - FX02 GHIJ 4 BRIGHT - Stop - } -} - - -// Mace spawn spot ---------------------------------------------------------- - -ACTOR MaceSpawner : SpecialSpot -{ - +NOSECTOR - +NOBLOCKMAP - States - { - Spawn: - TNT1 A 1 - TNT1 A -1 A_SpawnSingleItem("Mace", 64, 64, 0) - Stop - } -} - - -// Blaster ------------------------------------------------------------------ - -ACTOR Blaster : HereticWeapon -{ - +BLOODSPLATTER - Weapon.SelectionOrder 500 - Weapon.AmmoUse 1 - Weapon.AmmoGive 30 - Weapon.YAdjust 15 - Weapon.AmmoType "BlasterAmmo" - Weapon.SisterWeapon "BlasterPowered" - Inventory.PickupMessage "$TXT_WPNBLASTER" - Tag "$TAG_BLASTER" - Obituary "$OB_MPBLASTER" - - action native A_FireBlasterPL1(); - - States - { - Spawn: - WBLS A -1 - Stop - Ready: - BLSR A 1 A_WeaponReady - Loop - Deselect: - BLSR A 1 A_Lower - Loop - Select: - BLSR A 1 A_Raise - Loop - Fire: - BLSR BC 3 - Hold: - BLSR D 2 A_FireBlasterPL1 - BLSR CB 2 - BLSR A 0 A_ReFire - Goto Ready - } -} - -ACTOR BlasterPowered : Blaster -{ - +WEAPON.POWERED_UP - Weapon.AmmoUse 5 - Weapon.AmmoGive 0 - Weapon.SisterWeapon "Blaster" - Tag "$TAG_BLASTERP" - States - { - Fire: - BLSR BC 0 - Hold: - BLSR D 3 A_FireCustomMissile("BlasterFX1") - BLSR CB 4 - BLSR A 0 A_ReFire - Goto Ready - } -} - -// Blaster FX 1 ------------------------------------------------------------- - -ACTOR BlasterFX1 : FastProjectile native -{ - Radius 12 - Height 8 - Speed 184 - Damage 2 - SeeSound "weapons/blastershoot" - DeathSound "weapons/blasterhit" - +SPAWNSOUNDSOURCE - Obituary "$OB_MPPBLASTER" - - action native A_SpawnRippers(); - - States - { - Spawn: - ACLO E 200 - Loop - Death: - FX18 A 3 BRIGHT A_SpawnRippers - FX18 B 3 BRIGHT - FX18 CDEFG 4 BRIGHT - Stop - } -} - -// Blaster smoke ------------------------------------------------------------ - -ACTOR BlasterSmoke -{ - +NOBLOCKMAP - +NOGRAVITY - +NOTELEPORT - +CANNOTPUSH - RenderStyle Translucent - Alpha 0.4 - States - { - Spawn: - FX18 HIJKL 4 - Stop - } -} - -// Ripper ------------------------------------------------------------------- - -ACTOR Ripper native -{ - Radius 8 - Height 6 - Speed 14 - Damage 1 - Projectile - +RIPPER - DeathSound "weapons/blasterpowhit" - Obituary "$OB_MPPBLASTER" - States - { - Spawn: - FX18 M 4 - FX18 N 5 - Loop - Death: - FX18 OPQRS 4 BRIGHT - Stop - } -} - -// Blaster Puff ------------------------------------------------------------- - -ACTOR BlasterPuff -{ - +NOBLOCKMAP - +NOGRAVITY - +PUFFONACTORS - RenderStyle Add - SeeSound "weapons/blasterhit" - States - { - Crash: - FX17 ABCDE 4 BRIGHT - Stop - Spawn: - FX17 FG 3 BRIGHT - FX17 HIJKL 4 BRIGHT - Stop - } -} - - -// Skull (Horn) Rod --------------------------------------------------------- - -ACTOR SkullRod : HereticWeapon -{ - Weapon.SelectionOrder 200 - Weapon.AmmoUse1 1 - Weapon.AmmoGive1 50 - Weapon.YAdjust 15 - Weapon.AmmoType1 "SkullRodAmmo" - Weapon.SisterWeapon "SkullRodPowered" - Inventory.PickupMessage "$TXT_WPNSKULLROD" - Tag "$TAG_SKULLROD" - - action native A_FireSkullRodPL1(); - - States - { - Spawn: - WSKL A -1 - Stop - Ready: - HROD A 1 A_WeaponReady - Loop - Deselect: - HROD A 1 A_Lower - Loop - Select: - HROD A 1 A_Raise - Loop - Fire: - HROD AB 4 A_FireSkullRodPL1 - HROD B 0 A_ReFire - Goto Ready - } -} - -ACTOR SkullRodPowered : SkullRod -{ - +WEAPON.POWERED_UP - Weapon.AmmoUse1 5 - Weapon.AmmoGive1 0 - Weapon.SisterWeapon "SkullRod" - Tag "$TAG_SKULLRODP" - - action native A_FireSkullRodPL2(); - - States - { - Fire: - HROD C 2 - HROD D 3 - HROD E 2 - HROD F 3 - HROD G 4 A_FireSkullRodPL2 - HROD F 2 - HROD E 3 - HROD D 2 - HROD C 2 A_ReFire - Goto Ready - } -} - -// Horn Rod FX 1 ------------------------------------------------------------ - -ACTOR HornRodFX1 -{ - Radius 12 - Height 8 - Speed 22 - Damage 3 - Projectile - +WINDTHRUST - -NOBLOCKMAP - RenderStyle Add - SeeSound "weapons/hornrodshoot" - DeathSound "weapons/hornrodhit" - Obituary "$OB_MPSKULLROD" - States - { - Spawn: - FX00 AB 6 BRIGHT - Loop - Death: - FX00 HI 5 BRIGHT - FX00 JK 4 BRIGHT - FX00 LM 3 BRIGHT - Stop - } -} - - -// Horn Rod FX 2 ------------------------------------------------------------ - -ACTOR HornRodFX2 native -{ - Radius 12 - Height 8 - Speed 22 - Damage 10 - Health 140 - Projectile - RenderStyle Add - SeeSound "weapons/hornrodpowshoot" - DeathSound "weapons/hornrodpowhit" - Obituary "$OB_MPPSKULLROD" - - action native A_AddPlayerRain(); - action native A_HideInCeiling(); - action native A_SkullRodStorm(); - - States - { - Spawn: - FX00 C 3 BRIGHT - FX00 D 3 BRIGHT A_SeekerMissile(10, 30) - FX00 E 3 BRIGHT - FX00 F 3 BRIGHT A_SeekerMissile(10, 30) - Loop - Death: - FX00 H 5 BRIGHT A_AddPlayerRain - FX00 I 5 BRIGHT - FX00 J 4 BRIGHT - FX00 KLM 3 BRIGHT - FX00 G 1 A_HideInCeiling - FX00 G 1 A_SkullRodStorm - Wait - } -} - -// Rain pillar 1 ------------------------------------------------------------ - -ACTOR RainPillar native -{ - Radius 5 - Height 12 - Speed 12 - Damage 5 - Mass 5 - Projectile - -ACTIVATEPCROSS - -ACTIVATEIMPACT - RenderStyle Add - Obituary "$OB_MPPSKULLROD" - - action native A_RainImpact(); - - States - { - Spawn: - FX22 A -1 BRIGHT - Stop - Death: - FX22 B 4 BRIGHT A_RainImpact - FX22 CDEF 4 BRIGHT - Stop - NotFloor: - FX22 GHI 4 BRIGHT - Stop - } -} - -// Rain tracker "inventory" item -------------------------------------------- - -ACTOR RainTracker : Inventory native -{ - +INVENTORY.UNDROPPABLE -} - - -// Phoenix Rod -------------------------------------------------------------- - -ACTOR PhoenixRod : Weapon native -{ - +WEAPON.NOAUTOFIRE - Weapon.SelectionOrder 2600 - Weapon.Kickback 150 - Weapon.YAdjust 15 - Weapon.AmmoUse 1 - Weapon.AmmoGive 2 - Weapon.AmmoType "PhoenixRodAmmo" - Weapon.Sisterweapon "PhoenixRodPowered" - Inventory.PickupMessage "$TXT_WPNPHOENIxROD" - Tag "$TAG_PHOENIxROD" - - action native A_FirePhoenixPL1(); - - States - { - Spawn: - WPHX A -1 - Stop - Ready: - PHNX A 1 A_WeaponReady - Loop - Deselect: - PHNX A 1 A_Lower - Loop - Select: - PHNX A 1 A_Raise - Loop - Fire: - PHNX B 5 - PHNX C 7 A_FirePhoenixPL1 - PHNX DB 4 - PHNX B 0 A_ReFire - Goto Ready - } -} - -ACTOR PhoenixRodPowered : PhoenixRod native -{ - +WEAPON.POWERED_UP - +WEAPON.MELEEWEAPON - Weapon.SisterWeapon "PhoenixRod" - Weapon.AmmoGive 0 - Tag "$TAG_PHOENIxRODP" - - action native A_InitPhoenixPL2(); - action native A_FirePhoenixPL2(); - action native A_ShutdownPhoenixPL2(); - - States - { - Fire: - PHNX B 3 A_InitPhoenixPL2 - Hold: - PHNX C 1 A_FirePhoenixPL2 - PHNX B 4 A_ReFire - Powerdown: - PHNX B 4 A_ShutdownPhoenixPL2 - Goto Ready - } -} - -// Phoenix FX 1 ------------------------------------------------------------- - -ACTOR PhoenixFX1 native -{ - Radius 11 - Height 8 - Speed 20 - Damage 20 - DamageType Fire - Projectile - +THRUGHOST - +SPECIALFIREDAMAGE - SeeSound "weapons/phoenixshoot" - DeathSound "weapons/phoenixhit" - Obituary "$OB_MPPHOENIXROD" - - action native A_PhoenixPuff(); - - States - { - Spawn: - FX04 A 4 BRIGHT A_PhoenixPuff - Loop - Death: - FX08 A 6 BRIGHT A_Explode - FX08 BC 5 BRIGHT - FX08 DEFGH 4 BRIGHT - Stop - } -} - -// Phoenix puff ------------------------------------------------------------- - -ACTOR PhoenixPuff -{ - +NOBLOCKMAP - +NOGRAVITY - +NOTELEPORT - +CANNOTPUSH - RenderStyle Translucent - Alpha 0.4 - States - { - Spawn: - FX04 BCDEF 4 - Stop - } -} - -// Phoenix FX 2 ------------------------------------------------------------- - -ACTOR PhoenixFX2 native -{ - Radius 6 - Height 8 - Speed 10 - Damage 2 - DamageType Fire - Projectile - RenderStyle Add - Obituary "$OB_MPPPHOENIXROD" - - action native A_FlameEnd(); - action native A_FloatPuff(); - - States - { - Spawn: - FX09 ABABA 2 BRIGHT - FX09 B 2 BRIGHT A_FlameEnd - FX09 CDEF 2 BRIGHT - Stop - Death: - FX09 G 3 BRIGHT - FX09 H 3 BRIGHT A_FloatPuff - FX09 I 4 BRIGHT - FX09 JK 5 BRIGHT - Stop - } -} - diff --git a/wadsrc/static/actors/heretic/ironlich.txt b/wadsrc/static/actors/heretic/ironlich.txt deleted file mode 100644 index 43d7c16c58..0000000000 --- a/wadsrc/static/actors/heretic/ironlich.txt +++ /dev/null @@ -1,175 +0,0 @@ - -// Ironlich ----------------------------------------------------------------- - -ACTOR Ironlich -{ - Health 700 - Radius 40 - Height 72 - Mass 325 - Speed 6 - Painchance 32 - Monster - +NOBLOOD - +DONTMORPH - +DONTSQUASH - +BOSSDEATH - SeeSound "ironlich/sight" - AttackSound "ironlich/attack" - PainSound "ironlich/pain" - DeathSound "ironlich/death" - ActiveSound "ironlich/active" - Obituary "$OB_IRONLICH" - HitObituary "$OB_IRONLICHHIT" - DropItem "BlasterAmmo", 84, 10 - DropItem "ArtiEgg", 51, 0 - - action native A_LichAttack (); - - States - { - Spawn: - LICH A 10 A_Look - Loop - See: - LICH A 4 A_Chase - Loop - Missile: - LICH A 5 A_FaceTarget - LICH B 20 A_LichAttack - Goto See - Pain: - LICH A 4 - LICH A 4 A_Pain - Goto See - Death: - LICH C 7 - LICH D 7 A_Scream - LICH EF 7 - LICH G 7 A_NoBlocking - LICH H 7 - LICH I -1 A_BossDeath - Stop - } -} - -// Head FX 1 ---------------------------------------------------------------- - -ACTOR HeadFX1 -{ - Radius 12 - Height 6 - Speed 13 - FastSpeed 20 - Damage 1 - Projectile - -ACTIVATEIMPACT - -ACTIVATEPCROSS - +THRUGHOST - RenderStyle Add - - action native A_LichIceImpact(); - - States - { - Spawn: - FX05 ABC 6 BRIGHT - Loop - Death: - FX05 D 5 BRIGHT A_LichIceImpact - FX05 EFG 5 BRIGHT - Stop - } -} - -// Head FX 2 ---------------------------------------------------------------- - -ACTOR HeadFX2 -{ - Radius 12 - Height 6 - Speed 8 - Damage 3 - Projectile - -ACTIVATEIMPACT - -ACTIVATEPCROSS - RenderStyle Add - States - { - Spawn: - FX05 HIJ 6 BRIGHT - Loop - Death: - FX05 DEFG 5 BRIGHT - Stop - } -} - - -// Head FX 3 ---------------------------------------------------------------- - -ACTOR HeadFX3 -{ - Radius 14 - Height 12 - Speed 10 - FastSpeed 18 - Damage 5 - Projectile - +WINDTHRUST - -ACTIVATEIMPACT - -ACTIVATEPCROSS - -NOBLOCKMAP - RenderStyle Add - - action native A_LichFireGrow (); - - States - { - Spawn: - FX06 ABC 4 BRIGHT A_LichFireGrow - Loop - NoGrow: - FX06 ABC 5 BRIGHT - Loop - Death: - FX06 DEFG 5 BRIGHT - Stop - } -} - - -// Whirlwind ---------------------------------------------------------------- - -ACTOR Whirlwind native -{ - Radius 16 - Height 74 - Speed 10 - Damage 1 - Projectile - -ACTIVATEIMPACT - -ACTIVATEMCROSS - +SEEKERMISSILE - +EXPLOCOUNT - +StepMissile - RenderStyle Translucent - DefThreshold 60 - Threshold 50 - Alpha 0.4 - - action native A_WhirlwindSeek(); - - States - { - Spawn: - FX07 DEFG 3 - FX07 ABC 3 A_WhirlwindSeek - Goto Spawn+4 - Death: - FX07 GFED 4 - Stop - } -} - - diff --git a/wadsrc/static/actors/heretic/knight.txt b/wadsrc/static/actors/heretic/knight.txt deleted file mode 100644 index 863c67b75d..0000000000 --- a/wadsrc/static/actors/heretic/knight.txt +++ /dev/null @@ -1,118 +0,0 @@ - -// Knight ------------------------------------------------------------------- - -ACTOR Knight -{ - Health 200 - Radius 24 - Height 78 - Mass 150 - Speed 12 - Painchance 100 - Monster - +FLOORCLIP - SeeSound "hknight/sight" - AttackSound "hknight/attack" - PainSound "hknight/pain" - DeathSound "hknight/death" - ActiveSound "hknight/active" - Obituary "$OB_BONEKNIGHT" - HitObituary "$OB_BONEKNIGHTHIT" - DropItem "CrossbowAmmo", 84, 5 - - action native A_KnightAttack (); - - States - { - Spawn: - KNIG AB 10 A_Look - Loop - See: - KNIG ABCD 4 A_Chase - Loop - Melee: - Missile: - KNIG E 10 A_FaceTarget - KNIG F 8 A_FaceTarget - KNIG G 8 A_KnightAttack - KNIG E 10 A_FaceTarget - KNIG F 8 A_FaceTarget - KNIG G 8 A_KnightAttack - Goto See - Pain: - KNIG H 3 - KNIG H 3 A_Pain - Goto See - Death: - KNIG I 6 - KNIG J 6 A_Scream - KNIG K 6 - KNIG L 6 A_NoBlocking - KNIG MN 6 - KNIG O -1 - Stop - } - -} - - -// Knight ghost ------------------------------------------------------------- - -ACTOR KnightGhost : Knight -{ - +SHADOW - +GHOST - RenderStyle Translucent - Alpha 0.4 -} - -// Knight axe --------------------------------------------------------------- - -ACTOR KnightAxe -{ - Radius 10 - Height 8 - Speed 9 - FastSpeed 18 - Damage 2 - Projectile - -NOBLOCKMAP - -ACTIVATEIMPACT - -ACTIVATEPCROSS - +WINDTHRUST - +THRUGHOST - DeathSound "hknight/hit" - States - { - Spawn: - SPAX A 3 BRIGHT A_PlaySound("hknight/axewhoosh") - SPAX BC 3 BRIGHT - Loop - Death: - SPAX DEF 6 BRIGHT - Stop - } -} - - -// Red axe ------------------------------------------------------------------ - -ACTOR RedAxe : KnightAxe -{ - +NOBLOCKMAP - -WINDTHRUST - Damage 7 - - action native A_DripBlood (); - - States - { - Spawn: - RAXE AB 5 BRIGHT A_DripBlood - Loop - Death: - RAXE CDE 6 BRIGHT - Stop - } -} - diff --git a/wadsrc/static/actors/heretic/mummy.txt b/wadsrc/static/actors/heretic/mummy.txt deleted file mode 100644 index 331f315cd5..0000000000 --- a/wadsrc/static/actors/heretic/mummy.txt +++ /dev/null @@ -1,133 +0,0 @@ - -// Mummy -------------------------------------------------------------------- - -ACTOR Mummy -{ - Health 80 - Radius 22 - Height 62 - Mass 75 - Speed 12 - Painchance 128 - Monster - +FLOORCLIP - SeeSound "mummy/sight" - AttackSound "mummy/attack1" - PainSound "mummy/pain" - DeathSound "mummy/death" - ActiveSound "mummy/active" - HitObituary "$OB_MUMMY" - DropItem "GoldWandAmmo", 84, 3 - States - { - Spawn: - MUMM AB 10 A_Look - Loop - See: - MUMM ABCD 4 A_Chase - Loop - Melee: - MUMM E 6 A_FaceTarget - MUMM F 6 A_CustomMeleeAttack(random[MummyAttack](1,8)*2, "mummy/attack2", "mummy/attack") - MUMM G 6 - Goto See - Pain: - MUMM H 4 - MUMM H 4 A_Pain - Goto See - Death: - MUMM I 5 - MUMM J 5 A_Scream - MUMM K 5 A_SpawnItemEx("MummySoul", 0,0,10, 0,0,1) - MUMM L 5 - MUMM M 5 A_NoBlocking - MUMM NO 5 - MUMM P -1 - Stop - } -} - -// Mummy leader ------------------------------------------------------------- - -ACTOR MummyLeader : Mummy -{ - Species "MummyLeader" - Health 100 - Painchance 64 - Obituary "$OB_MUMMYLEADER" - States - { - Missile: - MUMM X 5 A_FaceTarget - MUMM Y 5 Bright A_FaceTarget - MUMM X 5 A_FaceTarget - MUMM Y 5 Bright A_FaceTarget - MUMM X 5 A_FaceTarget - MUMM Y 5 Bright A_CustomComboAttack("MummyFX1", 32, random[MummyAttack2](1,8)*2, "mummy/attack2") - Goto See - } -} - -// Mummy ghost -------------------------------------------------------------- - -ACTOR MummyGhost : Mummy -{ - +SHADOW - +GHOST - RenderStyle Translucent - Alpha 0.4 -} - -// Mummy leader ghost ------------------------------------------------------- - -ACTOR MummyLeaderGhost : MummyLeader -{ - Species "MummyLeaderGhost" - +SHADOW - +GHOST - RenderStyle Translucent - Alpha 0.4 -} - -// Mummy soul --------------------------------------------------------------- - -ACTOR MummySoul -{ - +NOBLOCKMAP - +NOGRAVITY - States - { - Spawn: - MUMM QRS 5 - MUMM TUVW 9 - Stop - } -} - -// Mummy FX 1 (flying head) ------------------------------------------------- - -ACTOR MummyFX1 -{ - Radius 8 - Height 14 - Speed 9 - FastSpeed 18 - Damage 4 - RenderStyle Add - Projectile - -ACTIVATEPCROSS - -ACTIVATEIMPACT - +SEEKERMISSILE - States - { - Spawn: - FX15 A 5 Bright A_PlaySound("mummy/head") - FX15 B 5 Bright A_SeekerMissile(10,20) - FX15 C 5 Bright - FX15 B 5 Bright A_SeekerMissile(10,20) - Loop - Death: - FX15 DEFG 5 Bright - Stop - } -} diff --git a/wadsrc/static/actors/heretic/snake.txt b/wadsrc/static/actors/heretic/snake.txt deleted file mode 100644 index bb9beb3dd0..0000000000 --- a/wadsrc/static/actors/heretic/snake.txt +++ /dev/null @@ -1,95 +0,0 @@ - -ACTOR Snake -{ - Health 280 - Radius 22 - Height 70 - Speed 10 - Painchance 48 - Monster - +FLOORCLIP - AttackSound "snake/attack" - SeeSound "snake/sight" - PainSound "snake/pain" - DeathSound "snake/death" - ActiveSound "snake/active" - Obituary "$OB_SNAKE" - DropItem "PhoenixRodAmmo", 84, 5 - States - { - Spawn: - SNKE AB 10 A_Look - Loop - See: - SNKE ABCD 4 A_Chase - Loop - Missile: - SNKE FF 5 A_FaceTarget - SNKE FFF 4 A_CustomMissile("SnakeProjA", 32, 0, 0, CMF_CHECKTARGETDEAD) - SNKE FFF 5 A_FaceTarget - SNKE F 4 A_CustomMissile("SnakeProjB", 32, 0, 0, CMF_CHECKTARGETDEAD) - Goto See - Pain: - SNKE E 3 - SNKE E 3 A_Pain - Goto See - Death: - SNKE G 5 - SNKE H 5 A_Scream - SNKE IJKL 5 - SNKE M 5 A_NoBlocking - SNKE NO 5 - SNKE P -1 - Stop - } -} - -// Snake projectile A ------------------------------------------------------- - -ACTOR SnakeProjA -{ - Radius 12 - Height 8 - Speed 14 - FastSpeed 20 - Damage 1 - Projectile - -NOBLOCKMAP - -ACTIVATEIMPACT - -ACTIVATEPCROSS - +WINDTHRUST - +SPAWNSOUNDSOURCE - RenderStyle Add - SeeSound "snake/attack" - States - { - Spawn: - SNFX ABCD 5 Bright - Loop - Death: - SNFX EF 5 Bright - SNFX G 4 Bright - SNFX HI 3 Bright - Stop - } -} - -// Snake projectile B ------------------------------------------------------- - -ACTOR SnakeProjB : SnakeProjA -{ - Damage 3 - +NOBLOCKMAP - -WINDTHRUST - States - { - Spawn: - SNFX JK 6 Bright - Loop - Death: - SNFX LM 5 Bright - SNFX N 4 Bright - SNFX O 3 Bright - Stop - } -} diff --git a/wadsrc/static/actors/heretic/wizard.txt b/wadsrc/static/actors/heretic/wizard.txt deleted file mode 100644 index 11ef0ad675..0000000000 --- a/wadsrc/static/actors/heretic/wizard.txt +++ /dev/null @@ -1,96 +0,0 @@ - -// Wizard -------------------------------------------------------- - -ACTOR Wizard -{ - Health 180 - Radius 16 - Height 68 - Mass 100 - Speed 12 - Painchance 64 - Monster - +FLOAT - +NOGRAVITY - +DONTOVERLAP - SeeSound "wizard/sight" - AttackSound "wizard/attack" - PainSound "wizard/pain" - DeathSound "wizard/death" - ActiveSound "wizard/active" - Obituary "$OB_WIZARD" - HitObituary "$OB_WIZARDHIT" - DropItem "BlasterAmmo", 84, 10 - DropItem "ArtiTomeOfPower", 4, 0 - - action native A_GhostOff (); - action native A_WizAtk1 (); - action native A_WizAtk2 (); - action native A_WizAtk3 (); - - States - { - Spawn: - WZRD AB 10 A_Look - Loop - See: - WZRD A 3 A_Chase - WZRD A 4 A_Chase - WZRD A 3 A_Chase - WZRD A 4 A_Chase - WZRD B 3 A_Chase - WZRD B 4 A_Chase - WZRD B 3 A_Chase - WZRD B 4 A_Chase - Loop - Missile: - WZRD C 4 A_WizAtk1 - WZRD C 4 A_WizAtk2 - WZRD C 4 A_WizAtk1 - WZRD C 4 A_WizAtk2 - WZRD C 4 A_WizAtk1 - WZRD C 4 A_WizAtk2 - WZRD C 4 A_WizAtk1 - WZRD C 4 A_WizAtk2 - WZRD D 12 A_WizAtk3 - Goto See - Pain: - WZRD E 3 A_GhostOff - WZRD E 3 A_Pain - Goto See - Death: - WZRD F 6 A_GhostOff - WZRD G 6 A_Scream - WZRD HI 6 - WZRD J 6 A_NoBlocking - WZRD KL 6 - WZRD M -1 A_SetFloorClip - Stop - } -} - -// Projectile -------------------------------------------------------- - -ACTOR WizardFX1 -{ - Radius 10 - Height 6 - Speed 18 - FastSpeed 24 - Damage 3 - Projectile - -ACTIVATEIMPACT - -ACTIVATEPCROSS - RenderStyle Add - States - { - Spawn: - FX11 AB 6 BRIGHT - Loop - Death: - FX11 CDEFG 5 BRIGHT - Stop - } -} - - diff --git a/wadsrc/static/actors/hexen/baseweapons.txt b/wadsrc/static/actors/hexen/baseweapons.txt deleted file mode 100644 index d40536316f..0000000000 --- a/wadsrc/static/actors/hexen/baseweapons.txt +++ /dev/null @@ -1,20 +0,0 @@ -// The Doom and Heretic players are not excluded from pickup in case -// somebody wants to use these weapons with either of those games. - -ACTOR FighterWeapon : Weapon native -{ - Weapon.Kickback 150 - Inventory.ForbiddenTo ClericPlayer, MagePlayer -} - -ACTOR ClericWeapon : Weapon native -{ - Weapon.Kickback 150 - Inventory.ForbiddenTo FighterPlayer, MagePlayer -} - -ACTOR MageWeapon : Weapon native -{ - Weapon.Kickback 150 - Inventory.ForbiddenTo FighterPlayer, ClericPlayer -} diff --git a/wadsrc/static/actors/hexen/bats.txt b/wadsrc/static/actors/hexen/bats.txt deleted file mode 100644 index 521d46e6ef..0000000000 --- a/wadsrc/static/actors/hexen/bats.txt +++ /dev/null @@ -1,47 +0,0 @@ - -// Bat Spawner -------------------------------------------------------------- - -ACTOR BatSpawner : SwitchableDecoration -{ - +NOBLOCKMAP +NOSECTOR +NOGRAVITY - RenderStyle None - - action native A_BatSpawnInit(); - action native A_BatSpawn(); - - States - { - Spawn: - Active: - TNT1 A 2 - TNT1 A 2 A_BatSpawnInit - TNT1 A 2 A_BatSpawn - Wait - Inactive: - TNT1 A -1 - Stop - } -} - -// Bat ---------------------------------------------------------------------- - -ACTOR Bat -{ - Speed 5 - Radius 3 - Height 3 - +NOBLOCKMAP +NOGRAVITY +MISSILE - +NOTELEPORT +CANPASS - - action native A_BatMove(); - - States - { - Spawn: - ABAT ABC 2 A_BatMove - Loop - Death: - ABAT A 2 - Stop - } -} diff --git a/wadsrc/static/actors/hexen/bishop.txt b/wadsrc/static/actors/hexen/bishop.txt deleted file mode 100644 index 435420ddd8..0000000000 --- a/wadsrc/static/actors/hexen/bishop.txt +++ /dev/null @@ -1,151 +0,0 @@ - -// Bishop ------------------------------------------------------------------- - -ACTOR Bishop -{ - Health 130 - Radius 22 - Height 65 - Speed 10 - PainChance 110 - Monster - +FLOAT +NOGRAVITY +NOBLOOD - +TELESTOMP - +DONTOVERLAP - +NOTARGETSWITCH - SeeSound "BishopSight" - AttackSound "BishopAttack" - PainSound "BishopPain" - DeathSound "BishopDeath" - ActiveSound "BishopActiveSounds" - Obituary"$OB_BISHOP" - - action native A_BishopChase(); - action native A_BishopDecide(); - action native A_BishopDoBlur(); - action native A_BishopSpawnBlur(); - action native A_BishopPainBlur(); - action native A_BishopAttack(); - action native A_BishopAttack2(); - - States - { - Spawn: - BISH A 10 A_Look - Loop - See: - BISH A 2 A_Chase - BISH A 2 A_BishopChase - BISH A 2 - BISH B 2 A_BishopChase - BISH B 2 A_Chase - BISH B 2 A_BishopChase - BISH A 1 A_BishopDecide - Loop - Blur: - BISH A 2 A_BishopDoBlur - BISH A 4 A_BishopSpawnBlur - Wait - Pain: - BISH C 6 A_Pain - BISH CCC 6 A_BishopPainBlur - BISH C 0 - Goto See - Missile: - BISH A 3 A_FaceTarget - BISH DE 3 A_FaceTarget - BISH F 3 A_BishopAttack - BISH F 5 A_BishopAttack2 - Wait - Death: - BISH G 6 - BISH H 6 Bright A_Scream - BISH I 5 Bright A_NoBlocking - BISH J 5 BRIGHT A_Explode(random[BishopBoom](25,40)) - BISH K 5 Bright - BISH LM 4 Bright - BISH N 4 A_SpawnItemEx("BishopPuff", 0,0,40, 0,0,0.5) - BISH O 4 A_QueueCorpse - BISH P -1 - Stop - Ice: - BISH X 5 A_FreezeDeath - BISH X 1 A_FreezeDeathChunks - Wait - } -} - -// Bishop puff -------------------------------------------------------------- - -ACTOR BishopPuff -{ - +NOBLOCKMAP +NOGRAVITY - RenderStyle Translucent - Alpha 0.6 - States - { - Spawn: - BISH QRST 5 - BISH UV 6 - BISH W 5 - Stop - } -} - -// Bishop pain blur --------------------------------------------------------- - -ACTOR BishopPainBlur -{ - +NOBLOCKMAP +NOGRAVITY - RenderStyle Translucent - Alpha 0.6 - States - { - Spawn: - BISH C 8 - Stop - } -} - -// Bishop FX ---------------------------------------------------------------- - -ACTOR BishopFX -{ - Radius 10 - Height 6 - Speed 10 - Damage 1 - Projectile - +SEEKERMISSILE - -ACTIVATEIMPACT -ACTIVATEPCROSS - +STRIFEDAMAGE - RenderStyle Add - DeathSound "BishopMissileExplode" - States - { - Spawn: - BPFX ABAB 1 Bright A_BishopMissileWeave - BPFX B 0 Bright A_SeekerMissile(2,3) - Loop - Death: - BPFX CDEF 4 Bright - BPFX GH 3 Bright - Stop - } -} - -// Bishop blur -------------------------------------------------------------- - -ACTOR BishopBlur -{ - +NOBLOCKMAP +NOGRAVITY - RenderStyle Translucent - Alpha 0.6 - States - { - Spawn: - BISH A 16 - BISH A 8 A_SetTranslucent(0.4) - Stop - } -} diff --git a/wadsrc/static/actors/hexen/blastradius.txt b/wadsrc/static/actors/hexen/blastradius.txt deleted file mode 100644 index 5612404380..0000000000 --- a/wadsrc/static/actors/hexen/blastradius.txt +++ /dev/null @@ -1,36 +0,0 @@ - -ACTOR ArtiBlastRadius : CustomInventory -{ - +FLOATBOB - Inventory.DefMaxAmount - Inventory.PickupFlash "PickupFlash" - +INVBAR +FANCYPICKUPSOUND - Inventory.Icon "ARTIBLST" - Inventory.PickupSound "misc/p_pkup" - Inventory.PickupMessage "$TXT_ARTIBLASTRADIUS" - Tag "$TAG_ARTIBLASTRADIUS" - States - { - Spawn: - BLST ABCDEFGH 4 Bright - Loop - Use: - TNT1 A 0 A_Blast - } -} - -// Blast Effect ------------------------------------------------------------- - -ACTOR BlastEffect -{ - +NOBLOCKMAP +NOGRAVITY +NOCLIP - +NOTELEPORT - RenderStyle Translucent - Alpha 0.666 - States - { - Spawn: - RADE ABCDEFGHI 4 - Stop - } -} diff --git a/wadsrc/static/actors/hexen/boostarmor.txt b/wadsrc/static/actors/hexen/boostarmor.txt deleted file mode 100644 index b55c29f881..0000000000 --- a/wadsrc/static/actors/hexen/boostarmor.txt +++ /dev/null @@ -1,21 +0,0 @@ - -// Boost Armor Artifact (Dragonskin Bracers) -------------------------------- - -ACTOR ArtiBoostArmor : Inventory native -{ - +COUNTITEM - +FLOATBOB - Inventory.DefMaxAmount - Inventory.PickupFlash "PickupFlash" - +INVBAR +FANCYPICKUPSOUND - Inventory.Icon "ARTIBRAC" - Inventory.PickupSound "misc/p_pkup" - Inventory.PickupMessage "$TXT_ARTIBOOSTARMOR" - Tag "$TAG_ARTIBOOSTARMOR" - States - { - Spawn: - BRAC ABCDEFGH 4 Bright - Loop - } -} diff --git a/wadsrc/static/actors/hexen/centaur.txt b/wadsrc/static/actors/hexen/centaur.txt deleted file mode 100644 index d036566bd6..0000000000 --- a/wadsrc/static/actors/hexen/centaur.txt +++ /dev/null @@ -1,186 +0,0 @@ -// Centaur ------------------------------------------------------------------ - -ACTOR Centaur -{ - Health 200 - Painchance 135 - Speed 13 - Height 64 - Mass 120 - Monster - +FLOORCLIP - +TELESTOMP - +SHIELDREFLECT - SeeSound "CentaurSight" - AttackSound "CentaurAttack" - PainSound "CentaurPain" - DeathSound "CentaurDeath" - ActiveSound "CentaurActive" - HowlSound "PuppyBeat" - Obituary "$OB_CENTAUR" - DamageFactor "Electric", 3 - States - { - Spawn: - CENT AB 10 A_Look - Loop - See: - CENT ABCD 4 A_Chase - Loop - Pain: - CENT G 6 A_Pain - CENT G 6 A_SetReflectiveInvulnerable - CENT EEE 15 A_CentaurDefend - CENT E 1 A_UnsetReflectiveInvulnerable - Goto See - Melee: - CENT H 5 A_FaceTarget - CENT I 4 A_FaceTarget - CENT J 7 A_CustomMeleeAttack(random[CentaurAttack](3,9)) - Goto See - Death: - CENT K 4 - CENT L 4 A_Scream - CENT MN 4 - CENT O 4 A_NoBlocking - CENT PQ 4 - CENT R 4 A_QueueCorpse - CENT S 4 - CENT T -1 - Stop - XDeath: - CTXD A 4 - CTXD B 4 A_NoBlocking - CTXD C 0 A_SpawnItemEx("CentaurSword", 0, 0, 45, - 1 + random[CentaurDrop](-128,127)*0.03125, - 1 + random[CentaurDrop](-128,127)*0.03125, - 8 + random[CentaurDrop](0,255)*0.015625, 270) - CTXD C 4 A_SpawnItemEx("CentaurShield", 0, 0, 45, - 1 + random[CentaurDrop](-128,127)*0.03125, - 1 + random[CentaurDrop](-128,127)*0.03125, - 8 + random[CentaurDrop](0,255)*0.015625, 90) - CTXD D 3 A_Scream - CTXD E 4 A_QueueCorpse - CTXD F 3 - CTXD G 4 - CTXD H 3 - CTXD I 4 - CTXD J 3 - CTXD K -1 - Ice: - CENT U 5 A_FreezeDeath - CENT U 1 A_FreezeDeathChunks - Wait - } -} - -// Centaur Leader ----------------------------------------------------------- - -ACTOR CentaurLeader : Centaur -{ - Health 250 - PainChance 96 - Speed 10 - Obituary "$OB_SLAUGHTAUR" - HitObituary "$OB_SLAUGHTAURHIT" - States - { - Missile: - CENT E 10 A_FaceTarget - CENT F 8 Bright A_CustomMissile("CentaurFX", 45, 0, 0, CMF_AIMOFFSET) - CENT E 10 A_FaceTarget - CENT F 8 Bright A_CustomMissile("CentaurFX", 45, 0, 0, CMF_AIMOFFSET) - Goto See - } -} - -// Mashed centaur ----------------------------------------------------------- -// -// The mashed centaur is only placed through ACS. Nowhere in the game source -// is it ever referenced. - -ACTOR CentaurMash : Centaur -{ - +NOBLOOD - +BLASTED - -TELESTOMP - +NOICEDEATH - RenderStyle Translucent - Alpha 0.4 - States - { - Death: - XDeath: - Ice: - Stop - } -} - -// Centaur projectile ------------------------------------------------------- - -ACTOR CentaurFX -{ - Speed 20 - Damage 4 - Projectile - +SPAWNSOUNDSOURCE - RenderStyle Add - SeeSound "CentaurLeaderAttack" - DeathSound "CentaurMissileExplode" - States - { - Spawn: - CTFX A -1 Bright - Stop - Death: - CTFX B 4 Bright - CTFX C 3 Bright - CTFX D 4 Bright - CTFX E 3 Bright - CTFX F 2 Bright - Stop - } -} - -// Centaur shield (debris) -------------------------------------------------- - -ACTOR CentaurShield -{ - +DROPOFF - +CORPSE - +NOTELEPORT - States - { - Spawn: - CTDP ABCDEF 3 - Goto Spawn+2 - Crash: - CTDP G 4 - CTDP H 4 A_QueueCorpse - CTDP I 4 - CTDP J -1 - Stop - } -} - -// Centaur sword (debris) --------------------------------------------------- - -ACTOR CentaurSword -{ - +DROPOFF - +CORPSE - +NOTELEPORT - States - { - Spawn: - CTDP KLMNOPQ 3 - Goto Spawn+2 - Crash: - CTDP R 4 - CTDP S 4 A_QueueCorpse - CTDP T -1 - Stop - } -} - - diff --git a/wadsrc/static/actors/hexen/clericboss.txt b/wadsrc/static/actors/hexen/clericboss.txt deleted file mode 100644 index dac0f741cd..0000000000 --- a/wadsrc/static/actors/hexen/clericboss.txt +++ /dev/null @@ -1,79 +0,0 @@ - -// Cleric Boss (Traductus) -------------------------------------------------- - -ACTOR ClericBoss -{ - Health 800 - PainChance 50 - Speed 25 - Radius 16 - Height 64 - Monster - +FLOORCLIP +TELESTOMP - +DONTMORPH - PainSound "PlayerClericPain" - DeathSound "PlayerClericCrazyDeath" - Obituary "$OBCBOSS" - - action native A_ClericAttack(); - - States - { - Spawn: - CLER A 2 - CLER A 3 A_ClassBossHealth - CLER A 5 A_Look - Wait - See: - CLER ABCD 4 A_FastChase - Loop - Pain: - CLER H 4 - CLER H 4 A_Pain - Goto See - Melee: - Missile: - CLER EF 8 A_FaceTarget - CLER G 10 A_ClericAttack - Goto See - Death: - CLER I 6 - CLER K 6 A_Scream - CLER LL 6 - CLER M 6 A_NoBlocking - CLER NOP 6 - CLER Q -1 - Stop - XDeath: - CLER R 5 A_Scream - CLER S 5 - CLER T 5 A_NoBlocking - CLER UVWXYZ 5 - CLER "[" -1 - Stop - Ice: - CLER "\" 5 A_FreezeDeath - CLER "\" 1 A_FreezeDeathChunks - Wait - Burn: - CLER C 5 Bright A_PlaySound("PlayerClericBurnDeath") - FDTH D 4 Bright - FDTH G 5 Bright - FDTH H 4 Bright A_Scream - FDTH I 5 Bright - FDTH J 4 Bright - FDTH K 5 Bright - FDTH L 4 Bright - FDTH M 5 Bright - FDTH N 4 Bright - FDTH O 5 Bright - FDTH P 4 Bright - FDTH Q 5 Bright - FDTH R 4 Bright - FDTH S 5 Bright A_NoBlocking - FDTH T 4 Bright - FDTH U 5 Bright - FDTH V 4 Bright - Stop - } -} diff --git a/wadsrc/static/actors/hexen/clericflame.txt b/wadsrc/static/actors/hexen/clericflame.txt deleted file mode 100644 index b6688a6edd..0000000000 --- a/wadsrc/static/actors/hexen/clericflame.txt +++ /dev/null @@ -1,196 +0,0 @@ - -// The Cleric's Flame Strike ------------------------------------------------ - -ACTOR CWeapFlame : ClericWeapon -{ - +NOGRAVITY - Weapon.SelectionOrder 1000 - Weapon.AmmoUse 4 - Weapon.AmmoGive 25 - Weapon.KickBack 150 - Weapon.YAdjust 10 - Weapon.AmmoType1 "Mana2" - Inventory.PickupMessage "$TXT_WEAPON_C3" - Tag "$TAG_CWEAPFLAME" - - action native A_CFlameAttack(); - - States - { - Spawn: - WCFM ABCDEFGH 4 Bright - Loop - Select: - CFLM A 1 A_Raise - Loop - Deselect: - CFLM A 1 A_Lower - Loop - Ready: - CFLM AAAABBBBCCCC 1 A_WeaponReady - Loop - Fire: - CFLM A 2 Offset (0, 40) - CFLM D 2 Offset (0, 50) - CFLM D 2 Offset (0, 36) - CFLM E 4 Bright - CFLM F 4 Bright A_CFlameAttack - CFLM E 4 Bright - CFLM G 2 Offset (0, 40) - CFLM G 2 - Goto Ready - } -} - -// Floor Flame -------------------------------------------------------------- - -ACTOR CFlameFloor -{ - +NOBLOCKMAP +NOGRAVITY - RenderStyle Add - States - { - Spawn: - CFFX N 5 Bright - CFFX O 4 Bright - CFFX P 3 Bright - Stop - } -} - -// Flame Puff --------------------------------------------------------------- - -ACTOR FlamePuff -{ - Radius 1 - Height 1 - +NOBLOCKMAP +NOGRAVITY - RenderStyle Add - SeeSound "ClericFlameExplode" - AttackSound "ClericFlameExplode" - States - { - Spawn: - CFFX ABC 3 Bright - CFFX D 4 Bright - CFFX E 3 Bright - CFFX F 4 Bright - CFFX G 3 Bright - CFFX H 4 Bright - CFFX I 3 Bright - CFFX J 4 Bright - CFFX K 3 Bright - CFFX L 4 Bright - CFFX M 3 Bright - Stop - } -} - -// Flame Puff 2 ------------------------------------------------------------- - -ACTOR FlamePuff2 : FlamePuff -{ - States - { - Spawn: - CFFX ABC 3 Bright - CFFX D 4 Bright - CFFX E 3 Bright - CFFX F 4 Bright - CFFX G 3 Bright - CFFX H 4 Bright - CFFX IC 3 Bright - CFFX D 4 Bright - CFFX E 3 Bright - CFFX F 4 Bright - CFFX G 3 Bright - CFFX H 4 Bright - CFFX I 3 Bright - CFFX J 4 Bright - CFFX K 3 Bright - CFFX L 4 Bright - CFFX M 3 Bright - Stop - } -} - -// Circle Flame ------------------------------------------------------------- - -ACTOR CircleFlame -{ - Radius 6 - Damage 2 - DamageType "Fire" - Projectile - -ACTIVATEIMPACT - -ACTIVATEPCROSS - RenderStyle Add - DeathSound "ClericFlameCircle" - Obituary "$OB_MPCWEAPFLAME" - - action native A_CFlameRotate(); - - States - { - Spawn: - CFCF A 4 Bright - CFCF B 2 Bright A_CFlameRotate - CFCF C 2 Bright - CFCF D 1 Bright - CFCF E 2 Bright - CFCF F 2 Bright A_CFlameRotate - CFCF G 1 Bright - CFCF HI 2 Bright - CFCF J 1 Bright A_CFlameRotate - CFCF K 2 Bright - CFCF LM 3 Bright - CFCF N 2 Bright A_CFlameRotate - CFCF O 3 Bright - CFCF P 2 Bright - Stop - Death: - CFCF QR 3 Bright - CFCF S 3 Bright A_Explode(20, 20, 0) - CFCF TUVWXYZ 3 Bright - Stop - } -} - -// Flame Missile ------------------------------------------------------------ - -ACTOR CFlameMissile : FastProjectile native -{ - Speed 200 - Radius 14 - Height 8 - Damage 8 - DamageType "Fire" - +INVISIBLE - RenderStyle Add - Obituary "$OB_MPCWEAPFLAME" - - action native A_CFlamePuff(); - action native A_CFlameMissile(); - - States - { - Spawn: - CFFX A 4 Bright - CFFX A 1 A_CFlamePuff - Goto Death + 1 - Death: - CFFX A 1 Bright A_CFlameMissile - CFFX ABC 3 Bright - CFFX D 4 Bright - CFFX E 3 Bright - CFFX F 4 Bright - CFFX G 3 Bright - CFFX H 4 Bright - CFFX I 3 Bright - CFFX J 4 Bright - CFFX K 3 Bright - CFFX L 4 Bright - CFFX M 3 Bright - Stop - } -} diff --git a/wadsrc/static/actors/hexen/clericholy.txt b/wadsrc/static/actors/hexen/clericholy.txt deleted file mode 100644 index f24a846b39..0000000000 --- a/wadsrc/static/actors/hexen/clericholy.txt +++ /dev/null @@ -1,237 +0,0 @@ - -// Cleric Weapon Piece ------------------------------------------------------ - -ACTOR ClericWeaponPiece : WeaponPiece -{ - Inventory.PickupSound "misc/w_pkup" - Inventory.PickupMessage "$TXT_WRAITHVERGE_PIECE" - Inventory.ForbiddenTo FighterPlayer, MagePlayer - WeaponPiece.Weapon CWeapWraithverge - +FLOATBOB -} - -// Cleric Weapon Piece 1 ---------------------------------------------------- - -ACTOR CWeaponPiece1 : ClericWeaponPiece -{ - WeaponPiece.Number 1 - States - { - Spawn: - WCH1 A -1 - Stop - } -} - -// Cleric Weapon Piece 2 ---------------------------------------------------- - -ACTOR CWeaponPiece2 : ClericWeaponPiece -{ - WeaponPiece.Number 2 - States - { - Spawn: - WCH2 A -1 - Stop - } -} - -// Cleric Weapon Piece 3 ---------------------------------------------------- - -ACTOR CWeaponPiece3 : ClericWeaponPiece -{ - WeaponPiece.Number 3 - States - { - Spawn: - WCH3 A -1 - Stop - } -} - -// Wraithverge Drop --------------------------------------------------------- - -ACTOR WraithvergeDrop -{ - States - { - Spawn: - TNT1 A 1 - TNT1 A 1 A_DropWeaponPieces("CWeaponPiece1", "CWeaponPiece2", "CWeaponPiece3") - Stop - } -} - -// Cleric's Wraithverge (Holy Symbol?) -------------------------------------- - -ACTOR CWeapWraithverge : ClericWeapon native -{ - Health 3 - Weapon.SelectionOrder 3000 - +WEAPON.PRIMARY_USES_BOTH - +Inventory.NoAttenPickupSound - Weapon.AmmoUse1 18 - Weapon.AmmoUse2 18 - Weapon.AmmoGive1 20 - Weapon.AmmoGive2 20 - Weapon.KickBack 150 - Weapon.AmmoType1 "Mana1" - Weapon.AmmoType2 "Mana2" - Inventory.PickupMessage "$TXT_WEAPON_C4" - Tag "$TAG_CWEAPWRAITHVERGE" - Inventory.PickupSound "WeaponBuild" - - action native A_CHolyAttack(); - action native A_CHolyPalette(); - - States - { - Spawn: - TNT1 A -1 - Stop - Ready: - CHLY A 1 A_WeaponReady - Loop - Select: - CHLY A 1 A_Raise - Loop - Deselect: - CHLY A 1 A_Lower - Loop - Fire: - CHLY AB 1 Bright Offset (0, 40) - CHLY CD 2 Bright Offset (0, 43) - CHLY E 2 Bright Offset (0, 45) - CHLY F 6 Bright Offset (0, 48) A_CHolyAttack - CHLY GG 2 Bright Offset (0, 40) A_CHolyPalette - CHLY G 2 Offset (0, 36) A_CHolyPalette - Goto Ready - } -} - -// Holy Missile ------------------------------------------------------------- - -ACTOR HolyMissile -{ - Speed 30 - Radius 15 - Height 8 - Damage 4 - Projectile - -ACTIVATEIMPACT -ACTIVATEPCROSS - +EXTREMEDEATH - - action native A_CHolyAttack2(); - - States - { - Spawn: - SPIR PPPP 3 Bright A_SpawnItemEx("HolyMissilePuff") - Death: - SPIR P 1 Bright A_CHolyAttack2 - Stop - } -} - -// Holy Missile Puff -------------------------------------------------------- - -ACTOR HolyMissilePuff -{ - Radius 4 - Height 8 - +NOBLOCKMAP +NOGRAVITY +DROPOFF - +NOTELEPORT - RenderStyle "Translucent" - Alpha 0.4 - States - { - Spawn: - SPIR QRSTU 3 - Stop - } -} - -// Holy Puff ---------------------------------------------------------------- - -ACTOR HolyPuff -{ - +NOBLOCKMAP +NOGRAVITY - RenderStyle Translucent - Alpha 0.6 - States - { - Spawn: - SPIR KLMNO 3 - Stop - } -} - -// Holy Spirit -------------------------------------------------------------- - -ACTOR HolySpirit native -{ - Health 105 - Speed 12 - Radius 10 - Height 6 - Damage 3 - Projectile - +RIPPER +SEEKERMISSILE - +FOILINVUL +SKYEXPLODE +NOEXPLODEFLOOR +CANBLAST - +EXTREMEDEATH - RenderStyle Translucent - Alpha 0.4 - DeathSound "SpiritDie" - Obituary "$OB_MPCWEAPWRAITHVERGE" - - action native A_CHolySeek(); - action native A_CHolyCheckScream(); - - States - { - Spawn: - SPIR AAB 2 A_CHolySeek - SPIR B 2 A_CHolyCheckScream - Loop - Death: - SPIR D 4 - SPIR E 4 A_Scream - SPIR FGHI 4 - Stop - } -} - -// Holy Tail ---------------------------------------------------------------- - -ACTOR HolyTail -{ - Radius 1 - Height 1 - +NOBLOCKMAP +NOGRAVITY +DROPOFF +NOCLIP - +NOTELEPORT - RenderStyle Translucent - Alpha 0.6 - - action native A_CHolyTail(); - - States - { - Spawn: - SPIR C 1 A_CHolyTail - Loop - TailTrail: - SPIR D -1 - Stop - } -} - -// Holy Tail Trail --------------------------------------------------------- - -ACTOR HolyTailTrail : HolyTail -{ - States - { - Spawn: - Goto TailTrail - } -} diff --git a/wadsrc/static/actors/hexen/clericmace.txt b/wadsrc/static/actors/hexen/clericmace.txt deleted file mode 100644 index dfb06d9585..0000000000 --- a/wadsrc/static/actors/hexen/clericmace.txt +++ /dev/null @@ -1,46 +0,0 @@ - -// The Cleric's Mace -------------------------------------------------------- - -ACTOR CWeapMace : ClericWeapon -{ - Weapon.SelectionOrder 3500 - Weapon.KickBack 150 - Weapon.YAdjust -8 - +BLOODSPLATTER - Obituary "$OB_MPCWEAPMACE" - Tag "$TAG_CWEAPMACE" - - action native A_CMaceAttack(); - - States - { - Select: - CMCE A 1 A_Raise - Loop - Deselect: - CMCE A 1 A_Lower - Loop - Ready: - CMCE A 1 A_WeaponReady - Loop - Fire: - CMCE B 2 Offset (60, 20) - CMCE B 1 Offset (30, 33) - CMCE B 2 Offset (8, 45) - CMCE C 1 Offset (8, 45) - CMCE D 1 Offset (8, 45) - CMCE E 1 Offset (8, 45) - CMCE E 1 Offset (-11, 58) A_CMaceAttack - CMCE F 1 Offset (8, 45) - CMCE F 2 Offset (-8, 74) - CMCE F 1 Offset (-20, 96) - CMCE F 8 Offset (-33, 160) - CMCE A 2 Offset (8, 75) A_ReFire - CMCE A 1 Offset (8, 65) - CMCE A 2 Offset (8, 60) - CMCE A 1 Offset (8, 55) - CMCE A 2 Offset (8, 50) - CMCE A 1 Offset (8, 45) - Goto Ready - } -} diff --git a/wadsrc/static/actors/hexen/clericplayer.txt b/wadsrc/static/actors/hexen/clericplayer.txt deleted file mode 100644 index 4b762af5da..0000000000 --- a/wadsrc/static/actors/hexen/clericplayer.txt +++ /dev/null @@ -1,103 +0,0 @@ -// The cleric --------------------------------------------------------------- - -ACTOR ClericPlayer : PlayerPawn -{ - Health 100 - ReactionTime 0 - PainChance 255 - Radius 16 - Height 64 - Speed 1 - +NOSKIN - +NODAMAGETHRUST - +NOTHRUSTWHENINVUL - PainSound "PlayerClericPain" - RadiusDamageFactor 0.25 - Player.JumpZ 9 - Player.Viewheight 48 - Player.SpawnClass "Cleric" - Player.DisplayName "Cleric" - Player.SoundClass "cleric" - Player.ScoreIcon "CLERFACE" - Player.InvulnerabilityMode "Ghost" - Player.HealRadiusType "Health" - Player.Hexenarmor 10, 10, 25, 5, 20 - Player.StartItem "CWeapMace" - Player.Portrait "P_CWALK1" - Player.WeaponSlot 1, CWeapMace - Player.WeaponSlot 2, CWeapStaff - Player.WeaponSlot 3, CWeapFlame - Player.WeaponSlot 4, CWeapWraithverge - Player.FlechetteType "ArtiPoisonBag1" - - Player.ColorRange 146, 163 - Player.Colorset 0, "Blue", 146, 163, 161 - Player.ColorsetFile 1, "Red", "TRANTBL7", 0xB3 - Player.ColorsetFile 2, "Gold", "TRANTBL8", 0x8C - Player.ColorsetFile 3, "Dull Green", "TRANTBL9", 0x41 - Player.ColorsetFile 4, "Green", "TRANTBLA", 0xC9 - Player.ColorsetFile 5, "Gray", "TRANTBLB", 0x30 - Player.ColorsetFile 6, "Brown", "TRANTBLC", 0x72 - Player.ColorsetFile 7, "Purple", "TRANTBLD", 0xEE - - States - { - Spawn: - CLER A -1 - Stop - See: - CLER ABCD 4 - Loop - Pain: - CLER H 4 - CLER H 4 A_Pain - Goto Spawn - Missile: - Melee: - CLER EFG 6 - Goto Spawn - Death: - CLER I 6 - CLER J 6 A_PlayerScream - CLER KL 6 - CLER M 6 A_NoBlocking - CLER NOP 6 - CLER Q -1 - Stop - XDeath: - CLER R 5 A_PlayerScream - CLER S 5 - CLER T 5 A_NoBlocking - CLER UVWXYZ 5 - CLER [ -1 - Stop - Ice: - CLER "\" 5 A_FreezeDeath - CLER "\" 1 A_FreezeDeathChunks - Wait - Burn: - FDTH C 5 BRIGHT A_PlaySound("*burndeath") - FDTH D 4 BRIGHT - FDTH G 5 BRIGHT - FDTH H 4 BRIGHT A_PlayerScream - FDTH I 5 BRIGHT - FDTH J 4 BRIGHT - FDTH K 5 BRIGHT - FDTH L 4 BRIGHT - FDTH M 5 BRIGHT - FDTH N 4 BRIGHT - FDTH O 5 BRIGHT - FDTH P 4 BRIGHT - FDTH Q 5 BRIGHT - FDTH R 4 BRIGHT - FDTH S 5 BRIGHT A_NoBlocking - FDTH T 4 BRIGHT - FDTH U 5 BRIGHT - FDTH V 4 BRIGHT - ACLO E 35 A_CheckPlayerDone - Wait - ACLO E 8 - Stop - } -} - diff --git a/wadsrc/static/actors/hexen/clericstaff.txt b/wadsrc/static/actors/hexen/clericstaff.txt deleted file mode 100644 index bd848b5c6a..0000000000 --- a/wadsrc/static/actors/hexen/clericstaff.txt +++ /dev/null @@ -1,96 +0,0 @@ - -// The Cleric's Serpent Staff ----------------------------------------------- - -ACTOR CWeapStaff : ClericWeapon -{ - Weapon.SelectionOrder 1600 - Weapon.AmmoUse1 1 - Weapon.AmmoGive1 25 - Weapon.KickBack 150 - Weapon.YAdjust 10 - Weapon.AmmoType1 "Mana1" - Inventory.PickupMessage "$TXT_WEAPON_C2" - Obituary "$OB_MPCWEAPSTAFFM" - Tag "$TAG_CWEAPSTAFF" - - action native A_CStaffInitBlink(); - action native A_CStaffCheckBlink(); - action native A_CStaffCheck(); - action native A_CStaffAttack(); - - States - { - Spawn: - WCSS A -1 - Stop - Select: - CSSF C 1 A_Raise - Loop - Deselect: - CSSF B 3 - CSSF C 4 - CSSF C 1 A_Lower - Wait - Ready: - CSSF C 4 - CSSF B 3 A_CStaffInitBlink - CSSF AAAAAAA 1 A_WeaponReady - CSSF A 1 A_CStaffCheckBlink - Goto Ready + 2 - Fire: - CSSF A 1 Offset (0, 45) A_CStaffCheck - CSSF J 1 Offset (0, 50) A_CStaffAttack - CSSF J 2 Offset (0, 50) - CSSF J 2 Offset (0, 45) - CSSF A 2 Offset (0, 40) - CSSF A 2 Offset (0, 36) - Goto Ready + 2 - Blink: - CSSF BBBCCCCCBBB 1 A_WeaponReady - Goto Ready + 2 - Drain: - CSSF K 10 Offset (0, 36) - Goto Ready + 2 - } -} - -// Serpent Staff Missile ---------------------------------------------------- - -ACTOR CStaffMissile native -{ - Speed 22 - Radius 12 - Height 10 - Damage 5 - RenderStyle Add - Projectile - DeathSound "ClericCStaffExplode" - Obituary "$OB_MPCWEAPSTAFFR" - States - { - Spawn: - CSSF DDEE 1 Bright A_CStaffMissileSlither - Loop - Death: - CSSF FG 4 Bright - CSSF HI 3 Bright - Stop - } -} - -// Serpent Staff Puff ------------------------------------------------------- - -ACTOR CStaffPuff -{ - +NOBLOCKMAP +NOGRAVITY - +PUFFONACTORS - RenderStyle Translucent - Alpha 0.6 - SeeSound "ClericCStaffHitThing" - States - { - Spawn: - FHFX STUVW 4 - Stop - } -} diff --git a/wadsrc/static/actors/hexen/demons.txt b/wadsrc/static/actors/hexen/demons.txt deleted file mode 100644 index 39da26e1de..0000000000 --- a/wadsrc/static/actors/hexen/demons.txt +++ /dev/null @@ -1,385 +0,0 @@ - -// Demon, type 1 (green, like D'Sparil's) ----------------------------------- - -ACTOR Demon1 -{ - Health 250 - Painchance 50 - Speed 13 - Radius 32 - Height 64 - Mass 220 - Monster - +TELESTOMP - +FLOORCLIP - SeeSound "DemonSight" - AttackSound "DemonAttack" - PainSound "DemonPain" - DeathSound "DemonDeath" - ActiveSound "DemonActive" - Obituary "$OB_DEMON1" - const int ChunkFlags = SXF_TRANSFERTRANSLATION | SXF_ABSOLUTEVELOCITY; - States - { - Spawn: - DEMN AA 10 A_Look - Loop - See: - DEMN ABCD 4 A_Chase - Loop - Pain: - DEMN E 4 - DEMN E 4 A_Pain - Goto See - Melee: - DEMN E 6 A_FaceTarget - DEMN F 8 A_FaceTarget - DEMN G 6 A_CustomMeleeAttack(random[DemonAttack1](1,8)*2) - Goto See - Missile: - DEMN E 5 A_FaceTarget - DEMN F 6 A_FaceTarget - DEMN G 5 A_CustomMissile("Demon1FX1", 62, 0) - Goto See - Death: - DEMN HI 6 - DEMN J 6 A_Scream - DEMN K 6 A_NoBlocking - DEMN L 6 A_QueueCorpse - DEMN MNO 6 - DEMN P -1 - Stop - XDeath: - DEMN H 6 - DEMN I 0 A_SpawnItemEx("Demon1Chunk1", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle+90), frandom[DemonChunks](1,4.984375)*sin(Angle+90), 8, 90, ChunkFlags) - DEMN I 0 A_SpawnItemEx("Demon1Chunk2", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags) - DEMN I 0 A_SpawnItemEx("Demon1Chunk3", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags) - DEMN I 0 A_SpawnItemEx("Demon1Chunk4", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags) - DEMN I 6 A_SpawnItemEx("Demon1Chunk5", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags) - Goto Death+2 - Ice: - DEMN Q 5 A_FreezeDeath - DEMN Q 1 A_FreezeDeathChunks - Wait - } -} - -// Demon, type 1, mashed ---------------------------------------------------- - -ACTOR Demon1Mash : Demon1 -{ - +NOBLOOD - +BLASTED - -TELESTOMP - +NOICEDEATH - RenderStyle Translucent - Alpha 0.4 - States - { - Death: - XDeath: - Ice: - Stop - } -} - -// Demon chunk, base class -------------------------------------------------- - -ACTOR DemonChunk -{ - Radius 5 - Height 5 - +NOBLOCKMAP - +DROPOFF - +MISSILE - +CORPSE - +FLOORCLIP - +NOTELEPORT -} - -// Demon, type 1, chunk 1 --------------------------------------------------- - -ACTOR Demon1Chunk1 : DemonChunk -{ - States - { - Spawn: - DEMA A 4 - DEMA A 10 A_QueueCorpse - DEMA A 20 - Wait - Death: - DEMA A -1 - Stop - } -} - -// Demon, type 1, chunk 2 --------------------------------------------------- - -ACTOR Demon1Chunk2 : DemonChunk -{ - States - { - Spawn: - DEMB A 4 - DEMB A 10 A_QueueCorpse - DEMB A 20 - Wait - Death: - DEMB A -1 - Stop - } -} - -ACTOR Demon1Chunk3 : DemonChunk -{ - States - { - Spawn: - DEMC A 4 - DEMC A 10 A_QueueCorpse - DEMC A 20 - Wait - Death: - DEMC A -1 - Stop - } -} - -// Demon, type 1, chunk 4 --------------------------------------------------- - -ACTOR Demon1Chunk4 : DemonChunk -{ - States - { - Spawn: - DEMD A 4 - DEMD A 10 A_QueueCorpse - DEMD A 20 - Wait - Death: - DEMD A -1 - Stop - } -} - -// Demon, type 1, chunk 5 --------------------------------------------------- - -ACTOR Demon1Chunk5 : DemonChunk -{ - States - { - Spawn: - DEME A 4 - DEME A 10 A_QueueCorpse - DEME A 20 - Wait - Death: - DEME A -1 - Stop - } -} - -// Demon, type 1, projectile ------------------------------------------------ - -ACTOR Demon1FX1 -{ - Speed 15 - Radius 10 - Height 6 - Damage 5 - DamageType Fire - Projectile - +SPAWNSOUNDSOURCE - RenderStyle Add - SeeSound "DemonMissileFire" - DeathSound "DemonMissileExplode" - States - { - Spawn: - DMFX ABC 4 Bright - Loop - Death: - DMFX DE 4 Bright - DMFX FGH 3 Bright - Stop - } -} - -// Demon, type 2 (brown) ---------------------------------------------------- - -ACTOR Demon2 : Demon1 -{ - Obituary "$OB_DEMON2" - Species "Demon2" - States - { - Spawn: - DEM2 AA 10 A_Look - Loop - See: - DEM2 ABCD 4 A_Chase - Loop - Pain: - DEM2 E 4 - DEM2 E 4 A_Pain - Goto See - Melee: - DEM2 E 6 A_FaceTarget - DEM2 F 8 A_FaceTarget - DEM2 G 6 A_CustomMeleeAttack(random[DemonAttack1](1,8)*2) - Goto See - Missile: - DEM2 E 5 A_FaceTarget - DEM2 F 6 A_FaceTarget - DEM2 G 5 A_CustomMissile("Demon2FX1", 62, 0) - Goto See - Death: - DEM2 HI 6 - DEM2 J 6 A_Scream - DEM2 K 6 A_NoBlocking - DEM2 L 6 A_QueueCorpse - DEM2 MNO 6 - DEM2 P -1 - Stop - XDeath: - DEM2 H 6 - DEM2 I 0 A_SpawnItemEx("Demon2Chunk1", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle+90), frandom[DemonChunks](1,4.984375)*sin(Angle+90), 8, 90, ChunkFlags) - DEM2 I 0 A_SpawnItemEx("Demon2Chunk2", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags) - DEM2 I 0 A_SpawnItemEx("Demon2Chunk3", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags) - DEM2 I 0 A_SpawnItemEx("Demon2Chunk4", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags) - DEM2 I 6 A_SpawnItemEx("Demon2Chunk5", 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle-90), frandom[DemonChunks](1,4.984375)*sin(Angle-90), 8, 270, ChunkFlags) - Goto Death+2 - } -} - -// Demon, type 2, mashed ---------------------------------------------------- - -ACTOR Demon2Mash : Demon2 -{ - +NOBLOOD - +BLASTED - -TELESTOMP - +NOICEDEATH - RenderStyle Translucent - Alpha 0.4 - States - { - Death: - XDeath: - Ice: - Stop - } -} - -// Demon, type 2, chunk 1 --------------------------------------------------- - -ACTOR Demon2Chunk1 : DemonChunk -{ - States - { - Spawn: - DMBA A 4 - DMBA A 10 A_QueueCorpse - DMBA A 20 - Wait - Death: - DMBA A -1 - Stop - } -} - -// Demon, type 2, chunk 2 --------------------------------------------------- - -ACTOR Demon2Chunk2 : DemonChunk -{ - States - { - Spawn: - DMBB A 4 - DMBB A 10 A_QueueCorpse - DMBB A 20 - Wait - Death: - DMBB A -1 - Stop - } -} - -// Demon, type 2, chunk 3 --------------------------------------------------- - -ACTOR Demon2Chunk3 : DemonChunk -{ - States - { - Spawn: - DMBC A 4 - DMBC A 10 A_QueueCorpse - DMBC A 20 - Wait - Death: - DMBC A -1 - Stop - } -} - -// Demon, type 2, chunk 4 --------------------------------------------------- - -ACTOR Demon2Chunk4 : DemonChunk -{ - States - { - Spawn: - DMBD A 4 - DMBD A 10 A_QueueCorpse - DMBD A 20 - Wait - Death: - DMBD A -1 - Stop - } -} - -// Demon, type 2, chunk 5 --------------------------------------------------- - -ACTOR Demon2Chunk5 : DemonChunk -{ - States - { - Spawn: - DMBE A 4 - DMBE A 10 A_QueueCorpse - DMBE A 20 - Wait - Death: - DMBE A -1 - Stop - } -} - -// Demon, type 2, projectile ------------------------------------------------ - -ACTOR Demon2FX1 -{ - Speed 15 - Radius 10 - Height 6 - Damage 5 - DamageType Fire - Projectile - +SPAWNSOUNDSOURCE - RenderStyle Add - SeeSound "DemonMissileFire" - DeathSound "DemonMissileExplode" - States - { - Spawn: - D2FX ABCDEF 4 Bright - Loop - Death: - D2FX GHIJ 4 Bright - D2FX KL 3 Bright - Stop - } -} - diff --git a/wadsrc/static/actors/hexen/dragon.txt b/wadsrc/static/actors/hexen/dragon.txt deleted file mode 100644 index f6c3746f28..0000000000 --- a/wadsrc/static/actors/hexen/dragon.txt +++ /dev/null @@ -1,117 +0,0 @@ - -// Dragon ------------------------------------------------------------------- - -ACTOR Dragon -{ - Health 640 - PainChance 128 - Speed 10 - Height 65 - Mass 0x7fffffff - Monster - +NOGRAVITY +FLOAT +NOBLOOD - +BOSS - +DONTMORPH +NOTARGET - +NOICEDEATH - SeeSound "DragonSight" - AttackSound "DragonAttack" - PainSound "DragonPain" - DeathSound "DragonDeath" - ActiveSound "DragonActive" - Obituary "$OB_DRAGON" - - action native A_DragonInitFlight(); - action native A_DragonFlap(); - action native A_DragonFlight(); - action native A_DragonPain(); - action native A_DragonAttack(); - action native A_DragonCheckCrash(); - - States - { - Spawn: - DRAG D 10 A_Look - Loop - See: - DRAG CB 5 - DRAG A 5 A_DragonInitFlight - DRAG B 3 A_DragonFlap - DRAG BCCDDCCBBAA 3 A_DragonFlight - Goto See + 3 - Pain: - DRAG F 10 A_DragonPain - Goto See + 3 - Missile: - DRAG E 8 A_DragonAttack - Goto See + 3 - Death: - DRAG G 5 A_Scream - DRAG H 4 A_NoBlocking - DRAG I 4 - DRAG J 4 A_DragonCheckCrash - Wait - Crash: - DRAG KL 5 - DRAG M -1 - Stop - } -} - -// Dragon Fireball ---------------------------------------------------------- - -ACTOR DragonFireball -{ - Speed 24 - Radius 12 - Height 10 - Damage 6 - DamageType "Fire" - Projectile - -ACTIVATEIMPACT -ACTIVATEPCROSS - RenderStyle Add - DeathSound "DragonFireballExplode" - - action native A_DragonFX2(); - - States - { - Spawn: - DRFX ABCDEF 4 Bright - Loop - Death: - DRFX GHI 4 Bright - DRFX J 4 Bright A_DragonFX2 - DRFX KL 3 Bright - Stop - } -} - -// Dragon Fireball Secondary Explosion -------------------------------------- - -ACTOR DragonExplosion -{ - Radius 8 - Height 8 - DamageType "Fire" - +NOBLOCKMAP - +NOTELEPORT - +INVISIBLE - RenderStyle Add - DeathSound "DragonFireballExplode" - States - { - Spawn: - CFCF Q 1 Bright - CFCF Q 4 Bright A_UnHideThing - CFCF R 3 Bright A_Scream - CFCF S 4 Bright - CFCF T 3 Bright A_Explode (80, 128, 0) - CFCF U 4 Bright - CFCF V 3 Bright - CFCF W 4 Bright - CFCF X 3 Bright - CFCF Y 4 Bright - CFCF Z 3 Bright - Stop - } -} diff --git a/wadsrc/static/actors/hexen/ettin.txt b/wadsrc/static/actors/hexen/ettin.txt deleted file mode 100644 index 4ce13406c4..0000000000 --- a/wadsrc/static/actors/hexen/ettin.txt +++ /dev/null @@ -1,106 +0,0 @@ - -// Ettin -------------------------------------------------------------------- - -ACTOR Ettin -{ - Health 175 - Radius 25 - Height 68 - Mass 175 - Speed 13 - Damage 3 - Painchance 60 - Monster - +FLOORCLIP - +TELESTOMP - SeeSound "EttinSight" - AttackSound "EttinAttack" - PainSound "EttinPain" - DeathSound "EttinDeath" - ActiveSound "EttinActive" - HowlSound "PuppyBeat" - Obituary "$OB_ETTIN" - States - { - Spawn: - ETTN AA 10 A_Look - Loop - See: - ETTN ABCD 5 A_Chase - Loop - Pain: - ETTN H 7 A_Pain - Goto See - Melee: - ETTN EF 6 A_FaceTarget - ETTN G 8 A_CustomMeleeAttack(random[EttinAttack](1,8)*2) - Goto See - Death: - ETTN IJ 4 - ETTN K 4 A_Scream - ETTN L 4 A_NoBlocking - ETTN M 4 A_QueueCorpse - ETTN NOP 4 - ETTN Q -1 - Stop - XDeath: - ETTB A 4 - ETTB B 4 A_NoBlocking - ETTB C 4 A_SpawnItemEx("EttinMace", 0,0,8.5, - random[DropMace](-128,127) * 0.03125, - random[DropMace](-128,127) * 0.03125, - 10 + random[DropMace](0,255) * 0.015625, 0, SXF_ABSOLUTEVELOCITY) - ETTB D 4 A_Scream - ETTB E 4 A_QueueCorpse - ETTB FGHIJK 4 - ETTB L -1 - Stop - Ice: - ETTN R 5 A_FreezeDeath - ETTN R 1 A_FreezeDeathChunks - Wait - } -} - -// Ettin mace --------------------------------------------------------------- - -ACTOR EttinMace -{ - Radius 5 - Height 5 - +DROPOFF - +CORPSE - +NOTELEPORT - +FLOORCLIP - States - { - Spawn: - ETTB MNOP 5 - Loop - Crash: - ETTB Q 5 - ETTB R 5 A_QueueCorpse - ETTB S -1 - Stop - } -} - -// Ettin mash --------------------------------------------------------------- - -ACTOR EttinMash : Ettin -{ - +NOBLOOD - +NOICEDEATH - RenderStyle Translucent - Alpha 0.4 - States - { - Death: - XDeath: - Ice: - Stop - } -} - - - diff --git a/wadsrc/static/actors/hexen/fighteraxe.txt b/wadsrc/static/actors/hexen/fighteraxe.txt deleted file mode 100644 index 28642c7d1b..0000000000 --- a/wadsrc/static/actors/hexen/fighteraxe.txt +++ /dev/null @@ -1,113 +0,0 @@ - -// The Fighter's Axe -------------------------------------------------------- - -ACTOR FWeapAxe : FighterWeapon native -{ - Weapon.SelectionOrder 1500 - +WEAPON.AXEBLOOD +WEAPON.AMMO_OPTIONAL +WEAPON.MELEEWEAPON - Weapon.AmmoUse1 2 - Weapon.AmmoGive1 25 - Weapon.KickBack 150 - Weapon.YAdjust -12 - Weapon.AmmoType1 "Mana1" - Inventory.PickupMessage "$TXT_WEAPON_F2" - Obituary "$OB_MPFWEAPAXE" - Tag "$TAG_FWEAPAXE" - - action native A_FAxeCheckUp(); - action native A_FAxeCheckReady(); - action native A_FAxeCheckAtk(); - action native A_FAxeAttack(); - action native A_FAxeCheckUpG(); - action native A_FAxeCheckReadyG(); - - States - { - Spawn: - WFAX A -1 - Stop - Select: - FAXE A 1 A_FAxeCheckUp - Loop - Deselect: - FAXE A 1 A_Lower - Loop - Ready: - FAXE A 1 A_FAxeCheckReady - Loop - Fire: - FAXE B 4 Offset (15, 32) A_FAxeCheckAtk - FAXE C 3 Offset (15, 32) - FAXE D 2 Offset (15, 32) - FAXE D 1 Offset (-5, 70) A_FAxeAttack - FAXE D 2 Offset (-25, 90) - FAXE E 1 Offset (15, 32) - FAXE E 2 Offset (10, 54) - FAXE E 7 Offset (10, 150) - FAXE A 1 Offset (0, 60) A_ReFire - FAXE A 1 Offset (0, 52) - FAXE A 1 Offset (0, 44) - FAXE A 1 Offset (0, 36) - FAXE A 1 - Goto Ready - SelectGlow: - FAXE L 1 A_FAxeCheckUpG - Loop - DeselectGlow: - FAXE L 1 A_Lower - Loop - ReadyGlow: - FAXE LLL 1 A_FAxeCheckReadyG - FAXE MMM 1 A_FAxeCheckReadyG - Loop - FireGlow: - FAXE N 4 Offset (15, 32) - FAXE O 3 Offset (15, 32) - FAXE P 2 Offset (15, 32) - FAXE P 1 Offset (-5, 70) A_FAxeAttack - FAXE P 2 Offset (-25, 90) - FAXE Q 1 Offset (15, 32) - FAXE Q 2 Offset (10, 54) - FAXE Q 7 Offset (10, 150) - FAXE A 1 Offset (0, 60) A_ReFire - FAXE A 1 Offset (0, 52) - FAXE A 1 Offset (0, 44) - FAXE A 1 Offset (0, 36) - FAXE A 1 - Goto ReadyGlow - } -} - -// Axe Puff ----------------------------------------------------------------- - -ACTOR AxePuff -{ - +NOBLOCKMAP +NOGRAVITY - +PUFFONACTORS - RenderStyle Translucent - Alpha 0.6 - SeeSound "FighterAxeHitThing" - AttackSound "FighterHammerHitWall" - ActiveSound "FighterHammerMiss" - States - { - Spawn: - FHFX STUVW 4 - Stop - } -} - -// Glowing Axe Puff --------------------------------------------------------- - -ACTOR AxePuffGlow : AxePuff -{ - +PUFFONACTORS - RenderStyle Add - Alpha 1 - States - { - Spawn: - FAXE RSTUVWX 4 Bright - Stop - } -} diff --git a/wadsrc/static/actors/hexen/fighterboss.txt b/wadsrc/static/actors/hexen/fighterboss.txt deleted file mode 100644 index 195c0a1a3a..0000000000 --- a/wadsrc/static/actors/hexen/fighterboss.txt +++ /dev/null @@ -1,80 +0,0 @@ - -// Fighter Boss (Zedek) ----------------------------------------------------- - -ACTOR FighterBoss -{ - health 800 - PainChance 50 - Speed 25 - Radius 16 - Height 64 - Monster - +FLOORCLIP - +TELESTOMP - +DONTMORPH - PainSound "PlayerFighterPain" - DeathSound "PlayerFighterCrazyDeath" - Obituary "$OB_FBOSS" - - action native A_FighterAttack(); - - States - { - Spawn: - PLAY A 2 - PLAY A 3 A_ClassBossHealth - PLAY A 5 A_Look - Wait - See: - PLAY ABCD 4 A_FastChase - Loop - Pain: - PLAY G 4 - PLAY G 4 A_Pain - Goto See - Melee: - Missile: - PLAY E 8 A_FaceTarget - PLAY F 8 A_FighterAttack - Goto See - Death: - PLAY H 6 - PLAY I 6 A_Scream - PLAY JK 6 - PLAY L 6 A_NoBlocking - PLAY M 6 - PLAY N -1 - Stop - XDeath: - PLAY O 5 A_Scream - PLAY P 5 A_SkullPop - PLAY R 5 A_NoBlocking - PLAY STUV 5 - PLAY W -1 - Stop - Ice: - PLAY X 5 A_FreezeDeath - PLAY X 1 A_FreezeDeathChunks - Wait - Burn: - FDTH A 5 Bright A_PlaySound("PlayerFighterBurnDeath") - FDTH B 4 Bright - FDTH G 5 Bright - FDTH H 4 Bright A_Scream - FDTH I 5 Bright - FDTH J 4 Bright - FDTH K 5 Bright - FDTH L 4 Bright - FDTH M 5 Bright - FDTH N 4 Bright - FDTH O 5 Bright - FDTH P 4 Bright - FDTH Q 5 Bright - FDTH R 4 Bright - FDTH S 5 Bright A_NoBlocking - FDTH T 4 Bright - FDTH U 5 Bright - FDTH V 4 Bright - Stop - } -} diff --git a/wadsrc/static/actors/hexen/fighterfist.txt b/wadsrc/static/actors/hexen/fighterfist.txt deleted file mode 100644 index b6a27332d5..0000000000 --- a/wadsrc/static/actors/hexen/fighterfist.txt +++ /dev/null @@ -1,64 +0,0 @@ - -// Fist (first weapon) ------------------------------------------------------ - -ACTOR FWeapFist : FighterWeapon -{ - +BLOODSPLATTER - Weapon.SelectionOrder 3400 - +WEAPON.MELEEWEAPON - Weapon.KickBack 150 - Obituary "$OB_MPFWEAPFIST" - Tag "$TAG_FWEAPFIST" - - action native A_FPunchAttack(); - - States - { - Select: - FPCH A 1 A_Raise - Loop - Deselect: - FPCH A 1 A_Lower - Loop - Ready: - FPCH A 1 A_WeaponReady - Loop - Fire: - FPCH B 5 Offset (5, 40) - FPCH C 4 Offset (5, 40) - FPCH D 4 Offset (5, 40) A_FPunchAttack - FPCH C 4 Offset (5, 40) - FPCH B 5 Offset (5, 40) A_ReFire - Goto Ready - Fire2: - FPCH DE 4 Offset (5, 40) - FPCH E 1 Offset (15, 50) - FPCH E 1 Offset (25, 60) - FPCH E 1 Offset (35, 70) - FPCH E 1 Offset (45, 80) - FPCH E 1 Offset (55, 90) - FPCH E 1 Offset (65, 90) - FPCH E 10 Offset (0, 150) - Goto Ready - } -} - -// Punch puff --------------------------------------------------------------- - -ACTOR PunchPuff -{ - +NOBLOCKMAP +NOGRAVITY - +PUFFONACTORS - RenderStyle Translucent - Alpha 0.6 - SeeSound "FighterPunchHitThing" - AttackSound "FighterPunchHitWall" - ActiveSound "FighterPunchMiss" - VSpeed 1 - States - { - Spawn: - FHFX STUVW 4 - Stop - } -} diff --git a/wadsrc/static/actors/hexen/fighterhammer.txt b/wadsrc/static/actors/hexen/fighterhammer.txt deleted file mode 100644 index d9932ae5f6..0000000000 --- a/wadsrc/static/actors/hexen/fighterhammer.txt +++ /dev/null @@ -1,101 +0,0 @@ - -// The Fighter's Hammer ----------------------------------------------------- - -ACTOR FWeapHammer : FighterWeapon -{ - +BLOODSPLATTER - Weapon.SelectionOrder 900 - +WEAPON.AMMO_OPTIONAL +WEAPON.MELEEWEAPON - Weapon.AmmoUse1 3 - Weapon.AmmoGive1 25 - Weapon.KickBack 150 - Weapon.YAdjust -10 - Weapon.AmmoType1 "Mana2" - Inventory.PickupMessage "$TXT_WEAPON_F3" - Obituary "$OB_MPFWEAPHAMMERM" - Tag "$TAG_FWEAPHAMMER" - - action native A_FHammerAttack(); - action native A_FHammerThrow(); - - States - { - Spawn: - WFHM A -1 - Stop - Select: - FHMR A 1 A_Raise - Loop - Deselect: - FHMR A 1 A_Lower - Loop - Ready: - FHMR A 1 A_WeaponReady - Loop - Fire: - FHMR B 6 Offset (5, 0) - FHMR C 3 Offset (5, 0) A_FHammerAttack - FHMR D 3 Offset (5, 0) - FHMR E 2 Offset (5, 0) - FHMR E 10 Offset (5, 150) A_FHammerThrow - FHMR A 1 Offset (0, 60) - FHMR A 1 Offset (0, 55) - FHMR A 1 Offset (0, 50) - FHMR A 1 Offset (0, 45) - FHMR A 1 Offset (0, 40) - FHMR A 1 Offset (0, 35) - FHMR A 1 - Goto Ready - } -} - -// Hammer Missile ----------------------------------------------------------- - -ACTOR HammerMissile -{ - Speed 25 - Radius 14 - Height 20 - Damage 10 - DamageType "Fire" - Projectile - DeathSound "FighterHammerExplode" - Obituary "$OB_MPFWEAPHAMMERR" - - States - { - Spawn: - FHFX A 2 Bright - FHFX B 2 Bright A_PlaySound ("FighterHammerContinuous") - FHFX CDEFGH 2 Bright - Loop - Death: - FHFX I 3 Bright A_SetTranslucent(1,1) - FHFX J 3 Bright - FHFX K 3 Bright A_Explode (128, 128, 0) - FHFX LM 3 Bright - FHFX N 3 - FHFX OPQR 3 Bright - Stop - } -} - -// Hammer Puff (also used by fist) ------------------------------------------ - -ACTOR HammerPuff -{ - +NOBLOCKMAP +NOGRAVITY - +PUFFONACTORS - RenderStyle "Translucent" - Alpha 0.6 - VSpeed 0.8 - SeeSound "FighterHammerHitThing" - AttackSound "FighterHammerHitWall" - ActiveSound "FighterHammerMiss" - States - { - Spawn: - FHFX STUVW 4 - Stop - } -} diff --git a/wadsrc/static/actors/hexen/fighterplayer.txt b/wadsrc/static/actors/hexen/fighterplayer.txt deleted file mode 100644 index 29de1f3a3d..0000000000 --- a/wadsrc/static/actors/hexen/fighterplayer.txt +++ /dev/null @@ -1,126 +0,0 @@ -// The fighter -------------------------------------------------------------- - -ACTOR FighterPlayer : PlayerPawn -{ - Health 100 - PainChance 255 - Radius 16 - Height 64 - Speed 1 - +NOSKIN - +NODAMAGETHRUST - +NOTHRUSTWHENINVUL - PainSound "PlayerFighterPain" - RadiusDamageFactor 0.25 - Player.JumpZ 9 - Player.Viewheight 48 - Player.SpawnClass "Fighter" - Player.DisplayName "Fighter" - Player.SoundClass "fighter" - Player.ScoreIcon "FITEFACE" - Player.HealRadiusType "Armor" - Player.Hexenarmor 15, 25, 20, 15, 5 - Player.StartItem "FWeapFist" - Player.ForwardMove 1.08, 1.2 - Player.SideMove 1.125, 1.475 - Player.Portrait "P_FWALK1" - Player.WeaponSlot 1, FWeapFist - Player.WeaponSlot 2, FWeapAxe - Player.WeaponSlot 3, FWeapHammer - Player.WeaponSlot 4, FWeapQuietus - - Player.ColorRange 246, 254 - Player.Colorset 0, "Gold", 246, 254, 253 - Player.ColorsetFile 1, "Red", "TRANTBL0", 0xAC - Player.ColorsetFile 2, "Blue", "TRANTBL1", 0x9D - Player.ColorsetFile 3, "Dull Green", "TRANTBL2", 0x3E - Player.ColorsetFile 4, "Green", "TRANTBL3", 0xC8 - Player.ColorsetFile 5, "Gray", "TRANTBL4", 0x2D - Player.ColorsetFile 6, "Brown", "TRANTBL5", 0x6F - Player.ColorsetFile 7, "Purple", "TRANTBL6", 0xEE - - States - { - Spawn: - PLAY A -1 - Stop - See: - PLAY ABCD 4 - Loop - Missile: - Melee: - PLAY EF 8 - Goto Spawn - Pain: - PLAY G 4 - PLAY G 4 A_Pain - Goto Spawn - Death: - PLAY H 6 - PLAY I 6 A_PlayerScream - PLAY JK 6 - PLAY L 6 A_NoBlocking - PLAY M 6 - PLAY N -1 - Stop - XDeath: - PLAY O 5 A_PlayerScream - PLAY P 5 A_SkullPop("BloodyFighterSkull") - PLAY R 5 A_NoBlocking - PLAY STUV 5 - PLAY W -1 - Stop - Ice: - PLAY X 5 A_FreezeDeath - PLAY X 1 A_FreezeDeathChunks - Wait - Burn: - FDTH A 5 BRIGHT A_PlaySound("*burndeath") - FDTH B 4 BRIGHT - FDTH G 5 BRIGHT - FDTH H 4 BRIGHT A_PlayerScream - FDTH I 5 BRIGHT - FDTH J 4 BRIGHT - FDTH K 5 BRIGHT - FDTH L 4 BRIGHT - FDTH M 5 BRIGHT - FDTH N 4 BRIGHT - FDTH O 5 BRIGHT - FDTH P 4 BRIGHT - FDTH Q 5 BRIGHT - FDTH R 4 BRIGHT - FDTH S 5 BRIGHT A_NoBlocking - FDTH T 4 BRIGHT - FDTH U 5 BRIGHT - FDTH V 4 BRIGHT - ACLO E 35 A_CheckPlayerDone - Wait - ACLO E 8 - Stop - } -} - -// The fighter's bloody skull -------------------------------------------------------------- - -Actor BloodyFighterSkull : PlayerChunk -{ - Radius 4 - Height 4 - +NOBLOCKMAP - +DROPOFF - +LOWGRAVITY - +CANNOTPUSH - +SKYEXPLODE - +NOBLOCKMONST - +NOSKIN - States - { - Spawn: - BSKL A 0 - BSKL ABCDFGH 5 A_CheckFloor("Hit") - Goto Spawn+1 - Hit: - BSKL I 16 A_CheckPlayerDone - Wait - } -} diff --git a/wadsrc/static/actors/hexen/fighterquietus.txt b/wadsrc/static/actors/hexen/fighterquietus.txt deleted file mode 100644 index 8d784ebf53..0000000000 --- a/wadsrc/static/actors/hexen/fighterquietus.txt +++ /dev/null @@ -1,164 +0,0 @@ - -// Fighter Weapon Piece ----------------------------------------------------- - -ACTOR FighterWeaponPiece : WeaponPiece -{ - Inventory.PickupSound "misc/w_pkup" - Inventory.PickupMessage "$TXT_QUIETUS_PIECE" - Inventory.ForbiddenTo ClericPlayer, MagePlayer - WeaponPiece.Weapon FWeapQuietus - +FLOATBOB -} - -// Fighter Weapon Piece 1 --------------------------------------------------- - -ACTOR FWeaponPiece1 : FighterWeaponPiece -{ - WeaponPiece.Number 1 - States - { - Spawn: - WFR1 A -1 Bright - Stop - } -} - -// Fighter Weapon Piece 2 --------------------------------------------------- - -ACTOR FWeaponPiece2 : FighterWeaponPiece -{ - WeaponPiece.Number 2 - States - { - Spawn: - WFR2 A -1 Bright - Stop - } -} - -// Fighter Weapon Piece 3 --------------------------------------------------- - -ACTOR FWeaponPiece3 : FighterWeaponPiece -{ - WeaponPiece.Number 3 - States - { - Spawn: - WFR3 A -1 Bright - Stop - } -} - -// Quietus Drop ------------------------------------------------------------- - -ACTOR QuietusDrop -{ - States - { - Spawn: - TNT1 A 1 - TNT1 A 1 A_DropWeaponPieces("FWeaponPiece1", "FWeaponPiece2", "FWeaponPiece3") - Stop - } -} - -// The Fighter's Sword (Quietus) -------------------------------------------- - -ACTOR FWeapQuietus : FighterWeapon -{ - Health 3 - Weapon.SelectionOrder 2900 - +WEAPON.PRIMARY_USES_BOTH - +Inventory.NoAttenPickupSound - Weapon.AmmoUse1 14 - Weapon.AmmoUse2 14 - Weapon.AmmoGive1 20 - Weapon.AmmoGive2 20 - Weapon.KickBack 150 - Weapon.YAdjust 10 - Weapon.AmmoType1 "Mana1" - Weapon.AmmoType2 "Mana2" - Inventory.PickupMessage "$TXT_WEAPON_F4" - Inventory.PickupSound "WeaponBuild" - Tag "$TAG_FWEAPQUIETUS" - - action native A_FSwordAttack(); - - States - { - Spawn: - TNT1 A -1 - Stop - Select: - FSRD A 1 Bright A_Raise - Loop - Deselect: - FSRD A 1 Bright A_Lower - Loop - Ready: - FSRD AAAABBBBCCCC 1 Bright A_WeaponReady - Loop - Fire: - FSRD DE 3 Bright Offset (5, 36) - FSRD F 2 Bright Offset (5, 36) - FSRD G 3 Bright Offset (5, 36) A_FSwordAttack - FSRD H 2 Bright Offset (5, 36) - FSRD I 2 Bright Offset (5, 36) - FSRD I 10 Bright Offset (5, 150) - FSRD A 1 Bright Offset (5, 60) - FSRD B 1 Bright Offset (5, 55) - FSRD C 1 Bright Offset (5, 50) - FSRD A 1 Bright Offset (5, 45) - FSRD B 1 Bright Offset (5, 40) - Goto Ready - } -} - -// Fighter Sword Missile ---------------------------------------------------- - -ACTOR FSwordMissile native -{ - Speed 30 - Radius 16 - Height 8 - Damage 8 - Projectile - +EXTREMEDEATH - RenderStyle Add - DeathSound "FighterSwordExplode" - Obituary "$OB_MPFWEAPQUIETUS" - - action native A_FSwordFlames(); - - States - { - Spawn: - FSFX ABC 3 Bright - Loop - Death: - FSFX D 4 Bright - FSFX E 3 Bright A_FSwordFlames - FSFX F 4 Bright A_Explode (64, 128, 0) - FSFX G 3 Bright - FSFX H 4 Bright - FSFX I 3 Bright - FSFX J 4 Bright - FSFX KLM 3 Bright - Stop - } -} - -// Fighter Sword Flame ------------------------------------------------------ - -ACTOR FSwordFlame -{ - +NOBLOCKMAP +NOGRAVITY - RenderStyle Translucent - Alpha 0.6 - States - { - Spawn: - FSFX NOPQRSTUVW 3 Bright - Stop - } -} diff --git a/wadsrc/static/actors/hexen/firedemon.txt b/wadsrc/static/actors/hexen/firedemon.txt deleted file mode 100644 index 3f96d22acd..0000000000 --- a/wadsrc/static/actors/hexen/firedemon.txt +++ /dev/null @@ -1,227 +0,0 @@ - -// FireDemon ---------------------------------------------------------------- - -ACTOR FireDemon -{ - Health 80 - ReactionTime 8 - PainChance 1 - Speed 13 - Radius 20 - Height 68 - Mass 75 - Damage 1 - Monster - +DROPOFF +NOGRAVITY +FLOAT - +FLOORCLIP +INVULNERABLE +TELESTOMP - SeeSound "FireDemonSpawn" - PainSound "FireDemonPain" - DeathSound "FireDemonDeath" - ActiveSound "FireDemonActive" - Obituary "$OB_FIREDEMON" - - action native A_FiredRocks(); - action native A_FiredChase(); - action native A_FiredAttack(); - action native A_FiredSplotch(); - - States - { - Spawn: - FDMN X 5 Bright - FDMN EFG 10 Bright A_Look - Goto Spawn + 1 - See: - FDMN E 8 Bright - FDMN F 6 Bright - FDMN G 5 Bright - FDMN F 8 Bright - FDMN E 6 Bright - FDMN G 7 Bright A_FiredRocks - FDMN HI 5 Bright - FDMN J 5 Bright A_UnSetInvulnerable - Chase: - FDMN ABC 5 Bright A_FiredChase - Loop - Pain: - FDMN D 0 Bright A_UnSetInvulnerable - FDMN D 6 Bright A_Pain - Goto Chase - Missile: - FDMN K 3 Bright A_FaceTarget - FDMN KKK 5 Bright A_FiredAttack - Goto Chase - Crash: - XDeath: - FDMN M 5 A_FaceTarget - FDMN N 5 A_NoBlocking - FDMN O 5 A_FiredSplotch - Stop - Death: - FDMN D 4 Bright A_FaceTarget - FDMN L 4 Bright A_Scream - FDMN L 4 Bright A_NoBlocking - FDMN L 200 Bright - Stop - Ice: - FDMN R 5 A_FreezeDeath - FDMN R 1 A_FreezeDeathChunks - Wait - } -} - -// FireDemonSplotch1 ------------------------------------------------------- - -ACTOR FireDemonSplotch1 -{ - Health 1000 - ReactionTime 8 - Radius 3 - Height 16 - Mass 100 - +DROPOFF +CORPSE - +NOTELEPORT +FLOORCLIP - States - { - Spawn: - FDMN P 3 - FDMN P 6 A_QueueCorpse - FDMN Y -1 - Stop - } -} - -// FireDemonSplotch2 ------------------------------------------------------- - -ACTOR FireDemonSplotch2 : FireDemonSplotch1 -{ - States - { - Spawn: - FDMN Q 3 - FDMN Q 6 A_QueueCorpse - FDMN Z -1 - Stop - } -} - -// FireDemonRock1 ------------------------------------------------------------ - -ACTOR FireDemonRock1 -{ - Health 1000 - ReactionTime 8 - Radius 3 - Height 5 - Mass 16 - +NOBLOCKMAP +DROPOFF +MISSILE - +NOTELEPORT - - action native A_SmBounce(); - - States - { - Spawn: - FDMN S 4 - Loop - Death: - FDMN S 5 A_SmBounce - XDeath: - FDMN S 200 - Stop - } -} - -// FireDemonRock2 ------------------------------------------------------------ - -ACTOR FireDemonRock2 : FireDemonRock1 -{ - States - { - Spawn: - FDMN T 4 - Loop - Death: - FDMN T 5 A_SmBounce - XDeath: - FDMN T 200 - Stop - } -} - -// FireDemonRock3 ------------------------------------------------------------ - -ACTOR FireDemonRock3 : FireDemonRock1 -{ - States - { - Spawn: - FDMN U 4 - Loop - Death: - FDMN U 5 A_SmBounce - XDeath: - FDMN U 200 - Stop - } -} - -// FireDemonRock4 ------------------------------------------------------------ - -ACTOR FireDemonRock4 : FireDemonRock1 -{ - States - { - Spawn: - FDMN V 4 - Loop - Death: - FDMN V 5 A_SmBounce - XDeath: - FDMN V 200 - Stop - } -} - -// FireDemonRock5 ------------------------------------------------------------ - -ACTOR FireDemonRock5 : FireDemonRock1 -{ - States - { - Spawn: - FDMN W 4 - Loop - Death: - FDMN W 5 A_SmBounce - XDeath: - FDMN W 200 - Stop - } -} - -// FireDemonMissile ----------------------------------------------------------- - -ACTOR FireDemonMissile -{ - Health 1000 - ReactionTime 8 - Speed 10 - Radius 10 - Height 6 - Mass 5 - Damage 1 - DamageType "Fire" - Projectile - RenderStyle Add - DeathSound "FireDemonMissileHit" - States - { - Spawn: - FDMB A 5 Bright - Loop - Death: - FDMB BCDE 5 Bright - Stop - } -} diff --git a/wadsrc/static/actors/hexen/flame.txt b/wadsrc/static/actors/hexen/flame.txt deleted file mode 100644 index b3e369a2e1..0000000000 --- a/wadsrc/static/actors/hexen/flame.txt +++ /dev/null @@ -1,106 +0,0 @@ -// Temp Small Flame -------------------------------------------------------- - -ACTOR FlameSmallTemp -{ - +NOTELEPORT - RenderStyle Add - States - { - Spawn: - FFSM AB 3 Bright - FFSM C 2 Bright A_CountdownArg(0) - FFSM C 2 Bright - FFSM D 3 Bright - FFSM E 3 Bright A_CountdownArg(0) - Loop - } -} - - -// Temp Large Flame --------------------------------------------------------- - -ACTOR FlameLargeTemp -{ - +NOTELEPORT - RenderStyle Add - States - { - Spawn: - FFLG A 4 Bright - FFLG B 4 Bright A_CountdownArg(0) - FFLG C 4 Bright - FFLG D 4 Bright A_CountdownArg(0) - FFLG E 4 Bright - FFLG F 4 Bright A_CountdownArg(0) - FFLG G 4 Bright - FFLG H 4 Bright A_CountdownArg(0) - FFLG I 4 Bright - FFLG J 4 Bright A_CountdownArg(0) - FFLG K 4 Bright - FFLG L 4 Bright A_CountdownArg(0) - FFLG M 4 Bright - FFLG N 4 Bright A_CountdownArg(0) - FFLG O 4 Bright - FFLG P 4 Bright A_CountdownArg(0) - Goto Spawn+4 - } -} - -// Small Flame -------------------------------------------------------------- - -ACTOR FlameSmall : SwitchableDecoration -{ - +NOTELEPORT - +INVISIBLE - Radius 15 - RenderStyle Add - States - { - Active: - FFSM A 0 Bright A_PlaySound("Ignite") - Spawn: - FFSM A 3 Bright - FFSM A 3 Bright A_UnHideThing - FFSM ABCDE 3 Bright - Goto Spawn+2 - Inactive: - FFSM A 2 - FFSM B 2 A_HideThing - FFSM C 200 - Wait - } -} - -ACTOR FlameSmall2 : FlameSmall -{ -} - -// Large Flame -------------------------------------------------------------- - -ACTOR FlameLarge : SwitchableDecoration -{ - +NOTELEPORT - +INVISIBLE - Radius 15 - RenderStyle Add - States - { - Active: - FFLG A 0 Bright A_PlaySound("Ignite") - Spawn: - FFLG A 2 Bright - FFLG A 2 Bright A_UnHideThing - FFLG ABCDEFGHIJKLMNOP 4 Bright - Goto Spawn+6 - Inactive: - FFLG DCB 2 - FFLG A 2 A_HideThing - FFLG A 200 - Wait - } -} - -ACTOR FlameLarge2 : FlameLarge -{ -} - diff --git a/wadsrc/static/actors/hexen/flechette.txt b/wadsrc/static/actors/hexen/flechette.txt deleted file mode 100644 index 2c7fbdc2b4..0000000000 --- a/wadsrc/static/actors/hexen/flechette.txt +++ /dev/null @@ -1,222 +0,0 @@ - -// Poison Bag (Flechette used by Cleric) ------------------------------------ - -ACTOR PoisonBag -{ - Radius 5 - Height 5 - +NOBLOCKMAP +NOGRAVITY - - action native A_PoisonBagInit(); - - States - { - Spawn: - PSBG A 18 Bright - PSBG B 4 Bright - PSBG C 3 - PSBG C 1 A_PoisonBagInit - Stop - } -} - -// Fire Bomb (Flechette used by Mage) --------------------------------------- - -ACTOR FireBomb -{ - DamageType "Fire" - +NOGRAVITY - +FOILINVUL - RenderStyle Translucent - Alpha 0.6 - DeathSound "FlechetteExplode" - - action native A_TimeBomb(); - - States - { - Spawn: - PSBG A 20 - PSBG AA 10 - PSBG B 4 - PSBG C 4 A_Scream - XPL1 A 4 Bright A_TimeBomb - XPL1 BCDEF 4 Bright - Stop - } -} - -// Throwing Bomb (Flechette used by Fighter) -------------------------------- - -ACTOR ThrowingBomb -{ - Health 48 - Speed 12 - Radius 8 - Height 10 - DamageType "Fire" - +NOBLOCKMAP +DROPOFF +MISSILE - BounceType "HexenCompat" - SeeSound "FlechetteBounce" - DeathSound "FlechetteExplode" - - action native A_CheckThrowBomb(); - action native A_CheckThrowBomb2(); - - States - { - Spawn: - THRW A 4 A_CheckThrowBomb - THRW BCDE 3 A_CheckThrowBomb - THRW F 3 A_CheckThrowBomb2 - Loop - THRW G 6 A_CheckThrowBomb - THRW F 4 A_CheckThrowBomb - THRW H 6 A_CheckThrowBomb - THRW F 4 A_CheckThrowBomb - THRW G 6 A_CheckThrowBomb - THRW F 3 A_CheckThrowBomb - Wait - Death: - CFCF Q 4 Bright A_NoGravity - CFCF R 3 Bright A_Scream - CFCF S 4 Bright A_Explode - CFCF T 3 Bright - CFCF U 4 Bright - CFCF W 3 Bright - CFCF X 4 Bright - CFCF Z 3 Bright - Stop - } -} - -// Poison Bag Artifact (Flechette) ------------------------------------------ - -ACTOR ArtiPoisonBag : Inventory native -{ - +FLOATBOB - Inventory.DefMaxAmount - Inventory.PickupFlash "PickupFlash" - +INVBAR +FANCYPICKUPSOUND - Inventory.Icon "ARTIPSBG" - Inventory.PickupSound "misc/p_pkup" - Inventory.PickupMessage "$TXT_ARTIPOISONBAG" - Tag "$TAG_ARTIPOISONBAG" - States - { - Spawn: - PSBG A -1 - Stop - } -} - -// Poison Bag 1 (The Cleric's) ---------------------------------------------- - -ACTOR ArtiPoisonBag1 : ArtiPoisonBag native -{ - Inventory.Icon "ARTIPSB1" - Tag "$TAG_ARTIPOISONBAG1" -} - -// Poison Bag 2 (The Mage's) ------------------------------------------------ - -ACTOR ArtiPoisonBag2 : ArtiPoisonBag native -{ - Inventory.Icon "ARTIPSB2" - Tag "$TAG_ARTIPOISONBAG2" -} - -// Poison Bag 3 (The Fighter's) --------------------------------------------- - -ACTOR ArtiPoisonBag3 : ArtiPoisonBag native -{ - Inventory.Icon "ARTIPSB3" - Tag "$TAG_ARTIPOISONBAG3" -} - - -// Poison Bag 4 (Custom Giver) ---------------------------------------------- - -ACTOR ArtiPoisonBagGiver : ArtiPoisonBag native -{ - Inventory.Icon "ARTIPSB4" -} - -// Poison Bag 5 (Custom Thrower) -------------------------------------------- - -ACTOR ArtiPoisonBagShooter : ArtiPoisonBag native -{ - Inventory.Icon "ARTIPSB5" -} - -// Poison Cloud ------------------------------------------------------------- - -ACTOR PoisonCloud native -{ - Radius 20 - Height 30 - Mass 0x7fffffff - +NOBLOCKMAP +NOGRAVITY +DROPOFF - +NODAMAGETHRUST - +DONTSPLASH +FOILINVUL +CANBLAST +BLOODLESSIMPACT +BLOCKEDBYSOLIDACTORS - RenderStyle Translucent - Alpha 0.6 - DeathSound "PoisonShroomDeath" - DamageType PoisonCloud - - action native A_PoisonBagDamage(); - action native A_PoisonBagCheck(); - - States - { - Spawn: - PSBG D 1 - PSBG D 1 A_Scream - PSBG DEEEFFFGGGHHHII 2 A_PoisonBagDamage - PSBG I 2 A_PoisonBagCheck - PSBG I 1 A_PoisonBagCheck - Goto Spawn + 3 - Death: - PSBG HG 7 - PSBG FD 6 - Stop - } -} - -// Poison Shroom ------------------------------------------------------------ - -ACTOR ZPoisonShroom : PoisonBag -{ - Radius 6 - Height 20 - PainChance 255 - Health 30 - Mass 0x7fffffff - +SHOOTABLE - +SOLID - +NOBLOOD - +NOICEDEATH - -NOBLOCKMAP - -NOGRAVITY - PainSound "PoisonShroomPain" - DeathSound "PoisonShroomDeath" - - action native A_PoisonShroom(); - - States - { - Spawn: - SHRM A 5 A_PoisonShroom - Goto Pain+1 - Pain: - SHRM A 6 - SHRM B 8 A_Pain - Goto Spawn - Death: - SHRM CD 5 - SHRM E 5 A_PoisonBagInit - SHRM F -1 - Stop - } -} - diff --git a/wadsrc/static/actors/hexen/flies.txt b/wadsrc/static/actors/hexen/flies.txt deleted file mode 100644 index e297cc2890..0000000000 --- a/wadsrc/static/actors/hexen/flies.txt +++ /dev/null @@ -1,27 +0,0 @@ - -// Buzzy fly ---------------------------------------------------------------- - -ACTOR LittleFly -{ - +NOBLOCKMAP +NOGRAVITY - +CANPASS - - Speed 6 - Radius 5 - Height 5 - Mass 2 - ActiveSound "FlyBuzz" - - action native A_FlySearch(); - action native A_FlyBuzz(); - - States - { - Spawn: - TNT1 A 20 A_FlySearch // [RH] Invisible when not flying - Loop - Buzz: - AFLY ABCD 3 A_FlyBuzz - Loop - } -} diff --git a/wadsrc/static/actors/hexen/fog.txt b/wadsrc/static/actors/hexen/fog.txt deleted file mode 100644 index 18effbb779..0000000000 --- a/wadsrc/static/actors/hexen/fog.txt +++ /dev/null @@ -1,72 +0,0 @@ - -// Fog Spawner -------------------------------------------------------------- - -ACTOR FogSpawner -{ - +NOSECTOR +NOBLOCKMAP - +FLOATBOB - +NOGRAVITY - +INVISIBLE - - action native A_FogSpawn(); - - States - { - Spawn: - TNT1 A 20 A_FogSpawn - Loop - } -} - -// Small Fog Patch ---------------------------------------------------------- - -ACTOR FogPatchSmall -{ - Speed 1 - +NOBLOCKMAP +NOGRAVITY +NOCLIP +FLOAT - +NOTELEPORT - RenderStyle Translucent - Alpha 0.6 - - action native A_FogMove(); - - States - { - Spawn: - FOGS ABCDE 7 A_FogMove - Loop - Death: - FOGS E 5 - Stop - } -} - -// Medium Fog Patch --------------------------------------------------------- - -ACTOR FogPatchMedium : FogPatchSmall -{ - States - { - Spawn: - FOGM ABCDE 7 A_FogMove - Loop - Death: - FOGS ABCDE 5 - Goto Super::Death - } -} - -// Large Fog Patch ---------------------------------------------------------- - -ACTOR FogPatchLarge : FogPatchMedium -{ - States - { - Spawn: - FOGL ABCDE 7 A_FogMove - Loop - Death: - FOGM ABCDEF 4 - Goto Super::Death - } -} diff --git a/wadsrc/static/actors/hexen/healingradius.txt b/wadsrc/static/actors/hexen/healingradius.txt deleted file mode 100644 index cc921f59cd..0000000000 --- a/wadsrc/static/actors/hexen/healingradius.txt +++ /dev/null @@ -1,23 +0,0 @@ - -// Healing Radius Artifact -------------------------------------------------- - -ACTOR ArtiHealingRadius : Inventory native -{ - +COUNTITEM - +FLOATBOB - Inventory.DefMaxAmount - +INVENTORY.INVBAR - +INVENTORY.PICKUPFLASH - +INVENTORY.FANCYPICKUPSOUND - Inventory.Icon "ARTIHRAD" - Inventory.PickupSound "misc/p_pkup" - Inventory.PickupMessage "$TXT_ARTIHEALINGRADIUS" - Tag "$TAG_ARTIHEALINGRADIUS" - States - { - Spawn: - HRAD ABCDEFGHIJKLMNOP 4 Bright - Loop - } -} - diff --git a/wadsrc/static/actors/hexen/heresiarch.txt b/wadsrc/static/actors/hexen/heresiarch.txt deleted file mode 100644 index 4d32f701eb..0000000000 --- a/wadsrc/static/actors/hexen/heresiarch.txt +++ /dev/null @@ -1,335 +0,0 @@ - -// The Heresiarch him/itself ------------------------------------------------ - -ACTOR Heresiarch native -{ - Health 5000 - Painchance 10 - Speed 16 - Radius 40 - Height 110 - Mass 500 - Damage 9 - Monster - +FLOORCLIP - +BOSS - +DONTMORPH - +NOTARGET - +NOICEDEATH - +DEFLECT - +NOBLOOD - SeeSound "SorcererSight" - PainSound "SorcererPain" - DeathSound "SorcererDeathScream" - ActiveSound "SorcererActive" - Obituary "$OB_HERESIARCH" - - action native A_SorcSpinBalls(); - action native A_SpeedBalls(); - action native A_SorcBossAttack(); - action native A_SpawnFizzle(); - - States - { - Spawn: - SORC A 3 - SORC A 2 A_SorcSpinBalls - Idle: - SORC A 10 A_Look - Wait - See: - SORC ABCD 5 A_Chase - Loop - Pain: - SORC G 8 - SORC G 8 A_Pain - Goto See - Missile: - SORC F 6 Bright A_FaceTarget - SORC F 6 Bright A_SpeedBalls - SORC F 6 Bright A_FaceTarget - Wait - Attack1: - SORC E 6 Bright - SORC E 6 Bright A_SpawnFizzle - SORC E 5 Bright A_FaceTarget - Goto Attack1+1 - Attack2: - SORC E 2 Bright - SORC E 2 Bright A_SorcBossAttack - Goto See - Death: - SORC H 5 Bright - SORC I 5 Bright A_FaceTarget - SORC J 5 Bright A_Scream - SORC KLMNOPQRST 5 Bright - SORC U 5 Bright A_NoBlocking - SORC VWXY 5 Bright - SORC Z -1 Bright - Stop - } -} - -// Base class for the balls flying around the Heresiarch's head ------------- - -ACTOR SorcBall native -{ - Speed 10 - Radius 5 - Height 5 - Projectile - -ACTIVATEIMPACT - -ACTIVATEPCROSS - +FULLVOLDEATH - +CANBOUNCEWATER - +NOWALLBOUNCESND - BounceType "HexenCompat" - SeeSound "SorcererBallBounce" - DeathSound "SorcererBigBallExplode" - - action native A_SorcBallOrbit(); - action native A_SorcBallPop(); - action native A_BounceCheck (); -} - -// First ball (purple) - fires projectiles ---------------------------------- - -ACTOR SorcBall1 : SorcBall native -{ - States - { - Spawn: - SBMP ABCDEFGHIJKLMNOP 2 A_SorcBallOrbit - Loop - Pain: - SBMP A 5 A_SorcBallPop - SBMP B 2 A_BounceCheck - Wait - Death: - SBS4 D 0 A_ChangeFlag("NOBOUNCESOUND", 1) - SBS4 D 5 A_Explode(255,255) - SBS4 E 5 - SBS4 FGH 6 - Stop - } -} - - -// Second ball (blue) - generates the shield -------------------------------- - -ACTOR SorcBall2 : SorcBall native -{ - States - { - Spawn: - SBMB ABCDEFGHIJKLMNOP 2 A_SorcBallOrbit - Loop - Pain: - SBMB A 5 A_SorcBallPop - SBMB B 2 A_BounceCheck - Wait - Death: - SBS4 D 0 A_ChangeFlag("NOBOUNCESOUND", 1) - SBS3 D 5 A_Explode(255,255) - SBS3 E 5 - SBS3 FGH 6 - Stop - } -} - -// Third ball (green) - summons Bishops ------------------------------------- - -ACTOR SorcBall3 : SorcBall native -{ - States - { - Spawn: - SBMG ABCDEFGHIJKLMNOP 2 A_SorcBallOrbit - Loop - Pain: - SBMG A 5 A_SorcBallPop - SBMG B 2 A_BounceCheck - Wait - Death: - SBS4 D 0 A_ChangeFlag("NOBOUNCESOUND", 1) - SBS3 D 5 A_Explode(255,255) - SBS3 E 5 - SBS3 FGH 6 - Stop - } -} - - -// Sorcerer spell 1 (The burning, bouncing head thing) ---------------------- - -ACTOR SorcFX1 -{ - Speed 7 - Radius 5 - Height 5 - Projectile - -ACTIVATEIMPACT - -ACTIVATEPCROSS - -NOGRAVITY - +FULLVOLDEATH - +CANBOUNCEWATER - +NOWALLBOUNCESND - BounceFactor 1.0 - +HEXENBOUNCE - SeeSound "SorcererBallBounce" - DeathSound "SorcererHeadScream" - - action native A_SorcFX1Seek(); - - States - { - Spawn: - SBS1 A 2 Bright - SBS1 BCD 3 Bright A_SorcFX1Seek - Loop - Death: - FHFX S 2 Bright A_Explode(30, 128) - FHFX SS 6 Bright - Stop - } -} - - -// Sorcerer spell 2 (The visible part of the shield) ------------------------ - -ACTOR SorcFX2 -{ - Speed 15 - Radius 5 - Height 5 - +NOBLOCKMAP - +NOGRAVITY - +NOTELEPORT - - action native A_SorcFX2Split(); - action native A_SorcFX2Orbit (); - - states - { - Spawn: - SBS2 A 3 Bright A_SorcFX2Split - Loop - Orbit: - SBS2 A 2 Bright - SBS2 BCDEFGHIJKLMNOPA 2 Bright A_SorcFX2Orbit - Goto Orbit+1 - Death: - SBS2 A 10 - Stop - } -} - -// The translucent trail behind SorcFX2 ------------------------------------- - -ACTOR SorcFX2T1 : SorcFX2 -{ - RenderStyle Translucent - Alpha 0.4 - States - { - Spawn: - Goto Death - } -} - - -// Sorcerer spell 3 (The Bishop spawner) ------------------------------------ - -ACTOR SorcFX3 -{ - Speed 15 - Radius 22 - Height 65 - +NOBLOCKMAP - +MISSILE - +NOTELEPORT - SeeSound "SorcererBishopSpawn" - - action native A_SpawnBishop(); - action native A_SorcererBishopEntry(); - - States - { - Spawn: - SBS3 ABC 2 Bright - Loop - Death: - SBS3 A 4 Bright - BISH P 4 A_SorcererBishopEntry - BISH ON 4 - BISH MLKJIH 3 - BISH G 3 A_SpawnBishop - Stop - } -} - - -// The Bishop spawner's explosion animation --------------------------------- - -ACTOR SorcFX3Explosion -{ - +NOBLOCKMAP - +NOGRAVITY - +NOTELEPORT - RenderStyle Translucent - Alpha 0.4 - States - { - Spawn: - SBS3 DEFGH 3 - Stop - } -} - - -// Sorcerer spell 4 (The purple projectile) --------------------------------- - -ACTOR SorcFX4 -{ - Speed 12 - Radius 10 - Height 10 - Projectile - -ACTIVATEIMPACT - -ACTIVATEPCROSS - DeathSound "SorcererBallExplode" - - action native A_SorcFX4Check(); - - States - { - Spawn: - SBS4 ABC 2 Bright A_SorcFX4Check - Loop - Death: - SBS4 D 2 Bright - SBS4 E 2 Bright A_Explode(20, 128) - SBS4 FGH 2 Bright - Stop - } -} - - -// Spark that appears when shooting SorcFX4 --------------------------------- - -ACTOR SorcSpark1 -{ - Radius 5 - Height 5 - Gravity 0.125 - +NOBLOCKMAP - +DROPOFF - +NOTELEPORT - RenderStyle Add - States - { - Spawn: - SBFX ABCDEFG 4 Bright - Stop - } -} diff --git a/wadsrc/static/actors/hexen/hexenarmor.txt b/wadsrc/static/actors/hexen/hexenarmor.txt deleted file mode 100644 index 53be60fe0d..0000000000 --- a/wadsrc/static/actors/hexen/hexenarmor.txt +++ /dev/null @@ -1,65 +0,0 @@ - -// Mesh Armor (1) ----------------------------------------------------------- - -ACTOR MeshArmor : HexenArmor -{ - +NOGRAVITY - Health 0 // Armor class - Inventory.Amount 0 - Inventory.PickupMessage "$TXT_ARMOR1" - States - { - Spawn: - AR_1 A -1 - Stop - } -} - -// Falcon Shield (2) -------------------------------------------------------- - -ACTOR FalconShield : HexenArmor -{ - +NOGRAVITY - Health 1 // Armor class - Inventory.Amount 0 - Inventory.PickupMessage "$TXT_ARMOR2" - States - { - Spawn: - AR_2 A -1 - Stop - } -} - -// Platinum Helm (3) -------------------------------------------------------- - -ACTOR PlatinumHelm : HexenArmor -{ - +NOGRAVITY - Health 2 // Armor class - Inventory.Amount 0 - Inventory.PickupMessage "$TXT_ARMOR3" - States - { - Spawn: - AR_3 A -1 - Stop - } -} - -// Amulet of Warding (4) ---------------------------------------------------- - -ACTOR AmuletOfWarding : HexenArmor -{ - +NOGRAVITY - Health 3 // Armor class - Inventory.Amount 0 - Inventory.PickupMessage "$TXT_ARMOR4" - States - { - Spawn: - AR_4 A -1 - Stop - } -} - diff --git a/wadsrc/static/actors/hexen/hexendecorations.txt b/wadsrc/static/actors/hexen/hexendecorations.txt deleted file mode 100644 index 87af4eff5a..0000000000 --- a/wadsrc/static/actors/hexen/hexendecorations.txt +++ /dev/null @@ -1,1396 +0,0 @@ -ACTOR ZWingedStatue -{ - Radius 10 - Height 62 - +SOLID - States - { - Spawn: - STTW A -1 - Stop - } -} - -ACTOR ZRock1 -{ - Radius 20 - Height 16 - States - { - Spawn: - RCK1 A -1 - Stop - } -} - -ACTOR ZRock2 -{ - Radius 20 - Height 16 - States - { - Spawn: - RCK2 A -1 - Stop - } -} - -ACTOR ZRock3 -{ - Radius 20 - Height 16 - States - { - Spawn: - RCK3 A -1 - Stop - } -} - -ACTOR ZRock4 -{ - Radius 20 - Height 16 - States - { - Spawn: - RCK4 A -1 - Stop - } -} - -ACTOR ZChandelier -{ - Radius 20 - Height 60 - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - CDLR ABC 4 - Loop - } -} - -ACTOR ZChandelierUnlit -{ - Radius 20 - Height 60 - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - CDLR D -1 - Stop - } -} - -ACTOR ZTreeDead -{ - Radius 10 - Height 96 - +SOLID - States - { - Spawn: - ZTRE A -1 - Stop - } -} - -ACTOR ZTree -{ - Radius 15 - Height 128 - +SOLID - States - { - Spawn: - ZTRE A -1 - Stop - } -} - -ACTOR ZTreeSwamp150 -{ - Radius 10 - Height 150 - +SOLID - States - { - Spawn: - TRES A -1 - Stop - } -} - -ACTOR ZTreeSwamp120 -{ - Radius 10 - Height 120 - +SOLID - States - { - Spawn: - TRE3 A -1 - Stop - } -} - -ACTOR ZStumpBurned -{ - Radius 12 - Height 20 - +SOLID - States - { - Spawn: - STM1 A -1 - Stop - } -} - -ACTOR ZStumpBare -{ - Radius 12 - Height 20 - +SOLID - States - { - Spawn: - STM2 A -1 - Stop - } -} - -ACTOR ZStumpSwamp1 -{ - Radius 20 - Height 16 - States - { - Spawn: - STM3 A -1 - Stop - } -} - -ACTOR ZStumpSwamp2 -{ - Radius 20 - Height 16 - States - { - Spawn: - STM4 A -1 - Stop - } -} - -ACTOR ZShroomLarge1 -{ - Radius 20 - Height 16 - States - { - Spawn: - MSH1 A -1 - Stop - } -} - -ACTOR ZShroomLarge2 -{ - Radius 20 - Height 16 - States - { - Spawn: - MSH2 A -1 - Stop - } -} - -ACTOR ZShroomLarge3 -{ - Radius 20 - Height 16 - States - { - Spawn: - MSH3 A -1 - Stop - } -} - -ACTOR ZShroomSmall1 -{ - Radius 20 - Height 16 - States - { - Spawn: - MSH4 A -1 - Stop - } -} - -ACTOR ZShroomSmall2 -{ - Radius 20 - Height 16 - States - { - Spawn: - MSH5 A -1 - Stop - } -} - -ACTOR ZShroomSmall3 -{ - Radius 20 - Height 16 - States - { - Spawn: - MSH6 A -1 - Stop - } -} - -ACTOR ZShroomSmall4 -{ - Radius 20 - Height 16 - States - { - Spawn: - MSH7 A -1 - Stop - } -} - -ACTOR ZShroomSmall5 -{ - Radius 20 - Height 16 - States - { - Spawn: - MSH8 A -1 - Stop - } -} - -ACTOR ZStalagmitePillar -{ - Radius 8 - Height 138 - +SOLID - States - { - Spawn: - SGMP A -1 - Stop - } -} - -ACTOR ZStalagmiteLarge -{ - Radius 8 - Height 48 - +SOLID - States - { - Spawn: - SGM1 A -1 - Stop - } -} - -ACTOR ZStalagmiteMedium -{ - Radius 6 - Height 40 - +SOLID - States - { - Spawn: - SGM2 A -1 - Stop - } -} - -ACTOR ZStalagmiteSmall -{ - Radius 8 - Height 36 - +SOLID - States - { - Spawn: - SGM3 A -1 - Stop - } -} - -ACTOR ZStalactiteLarge -{ - Radius 8 - Height 66 - +SOLID - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - SLC1 A -1 - Stop - } -} - -ACTOR ZStalactiteMedium -{ - Radius 6 - Height 50 - +SOLID - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - SLC2 A -1 - Stop - } -} - -ACTOR ZStalactiteSmall -{ - Radius 8 - Height 40 - +SOLID - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - SLC3 A -1 - Stop - } -} - -ACTOR ZMossCeiling1 -{ - Radius 20 - Height 20 - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - MSS1 A -1 - Stop - } -} - -ACTOR ZMossCeiling2 -{ - Radius 20 - Height 24 - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - MSS2 A -1 - Stop - } -} - -ACTOR ZSwampVine -{ - Radius 8 - Height 52 - +SOLID - States - { - Spawn: - SWMV A -1 - Stop - } -} - -ACTOR ZCorpseKabob -{ - Radius 10 - Height 92 - +SOLID - States - { - Spawn: - CPS1 A -1 - Stop - } -} - -ACTOR ZCorpseSleeping -{ - Radius 20 - Height 16 - States - { - Spawn: - CPS2 A -1 - Stop - } -} - -ACTOR ZTombstoneRIP -{ - Radius 10 - Height 46 - +SOLID - States - { - Spawn: - TMS1 A -1 - Stop - } -} - -ACTOR ZTombstoneShane -{ - Radius 10 - Height 46 - +SOLID - States - { - Spawn: - TMS2 A -1 - Stop - } -} - -ACTOR ZTombstoneBigCross -{ - Radius 10 - Height 46 - +SOLID - States - { - Spawn: - TMS3 A -1 - Stop - } -} - -ACTOR ZTombstoneBrianR -{ - Radius 10 - Height 52 - +SOLID - States - { - Spawn: - TMS4 A -1 - Stop - } -} - -ACTOR ZTombstoneCrossCircle -{ - Radius 10 - Height 52 - +SOLID - States - { - Spawn: - TMS5 A -1 - Stop - } -} - -ACTOR ZTombstoneSmallCross -{ - Radius 8 - Height 46 - +SOLID - States - { - Spawn: - TMS6 A -1 - Stop - } -} - -ACTOR ZTombstoneBrianP -{ - Radius 8 - Height 46 - +SOLID - States - { - Spawn: - TMS7 A -1 - Stop - } -} - -ACTOR ZCorpseHanging -{ - Radius 6 - Height 75 - +SOLID - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - CPS3 A -1 - Stop - } -} - -ACTOR ZStatueGargoyleGreenTall -{ - Radius 14 - Height 108 - +SOLID - States - { - Spawn: - STT2 A -1 - Stop - } -} - -ACTOR ZStatueGargoyleBlueTall -{ - Radius 14 - Height 108 - +SOLID - States - { - Spawn: - STT3 A -1 - Stop - } -} - -ACTOR ZStatueGargoyleGreenShort -{ - Radius 14 - Height 62 - +SOLID - States - { - Spawn: - STT4 A -1 - Stop - } -} - -ACTOR ZStatueGargoyleBlueShort -{ - Radius 14 - Height 62 - +SOLID - States - { - Spawn: - STT5 A -1 - Stop - } -} - -ACTOR ZStatueGargoyleStripeTall -{ - Radius 14 - Height 108 - +SOLID - States - { - Spawn: - GAR1 A -1 - Stop - } -} - -ACTOR ZStatueGargoyleDarkRedTall -{ - Radius 14 - Height 108 - +SOLID - States - { - Spawn: - GAR2 A -1 - Stop - } -} - -ACTOR ZStatueGargoyleRedTall -{ - Radius 14 - Height 108 - +SOLID - States - { - Spawn: - GAR3 A -1 - Stop - } -} - -ACTOR ZStatueGargoyleTanTall -{ - Radius 14 - Height 108 - +SOLID - States - { - Spawn: - GAR4 A -1 - Stop - } -} - -ACTOR ZStatueGargoyleRustTall -{ - Radius 14 - Height 108 - +SOLID - States - { - Spawn: - GAR5 A -1 - Stop - } -} - -ACTOR ZStatueGargoyleDarkRedShort -{ - Radius 14 - Height 62 - +SOLID - States - { - Spawn: - GAR6 A -1 - Stop - } -} - -ACTOR ZStatueGargoyleRedShort -{ - Radius 14 - Height 62 - +SOLID - States - { - Spawn: - GAR7 A -1 - Stop - } -} - -ACTOR ZStatueGargoyleTanShort -{ - Radius 14 - Height 62 - +SOLID - States - { - Spawn: - GAR8 A -1 - Stop - } -} - -ACTOR ZStatueGargoyleRustShort -{ - Radius 14 - Height 62 - +SOLID - States - { - Spawn: - GAR9 A -1 - Stop - } -} - -ACTOR ZBannerTattered -{ - Radius 8 - Height 120 - +SOLID - States - { - Spawn: - BNR1 A -1 - Stop - } -} - -ACTOR ZTreeLarge1 -{ - Radius 15 - Height 180 - +SOLID - States - { - Spawn: - TRE4 A -1 - Stop - } -} - -ACTOR ZTreeLarge2 -{ - Radius 15 - Height 180 - +SOLID - States - { - Spawn: - TRE5 A -1 - Stop - } -} - -ACTOR ZTreeGnarled1 -{ - Radius 22 - Height 100 - +SOLID - States - { - Spawn: - TRE6 A -1 - Stop - } -} - -ACTOR ZTreeGnarled2 -{ - Radius 22 - Height 100 - +SOLID - States - { - Spawn: - TRE7 A -1 - Stop - } -} - -ACTOR ZLog -{ - Radius 20 - Height 25 - +SOLID - States - { - Spawn: - LOGG A -1 - Stop - } -} - -ACTOR ZStalactiteIceLarge -{ - Radius 8 - Height 66 - +SOLID - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - ICT1 A -1 - Stop - } -} - -ACTOR ZStalactiteIceMedium -{ - Radius 5 - Height 50 - +SOLID - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - ICT2 A -1 - Stop - } -} - -ACTOR ZStalactiteIceSmall -{ - Radius 4 - Height 32 - +SOLID - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - ICT3 A -1 - Stop - } -} - -ACTOR ZStalactiteIceTiny -{ - Radius 4 - Height 8 - +SOLID - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - ICT4 A -1 - Stop - } -} - -ACTOR ZStalagmiteIceLarge -{ - Radius 8 - Height 66 - +SOLID - States - { - Spawn: - ICM1 A -1 - Stop - } -} - -ACTOR ZStalagmiteIceMedium -{ - Radius 5 - Height 50 - +SOLID - States - { - Spawn: - ICM2 A -1 - Stop - } -} - -ACTOR ZStalagmiteIceSmall -{ - Radius 4 - Height 32 - +SOLID - States - { - Spawn: - ICM3 A -1 - Stop - } -} - -ACTOR ZStalagmiteIceTiny -{ - Radius 4 - Height 8 - +SOLID - States - { - Spawn: - ICM4 A -1 - Stop - } -} - -ACTOR ZRockBrown1 -{ - Radius 17 - Height 72 - +SOLID - States - { - Spawn: - RKBL A -1 - Stop - } -} - -ACTOR ZRockBrown2 -{ - Radius 15 - Height 50 - +SOLID - States - { - Spawn: - RKBS A -1 - Stop - } -} - -ACTOR ZRockBlack -{ - Radius 20 - Height 40 - +SOLID - States - { - Spawn: - RKBK A -1 - Stop - } -} - -ACTOR ZRubble1 -{ - Radius 20 - Height 16 - States - { - Spawn: - RBL1 A -1 - Stop - } -} - -ACTOR ZRubble2 -{ - Radius 20 - Height 16 - States - { - Spawn: - RBL2 A -1 - Stop - } -} - -ACTOR ZRubble3 -{ - Radius 20 - Height 16 - States - { - Spawn: - RBL3 A -1 - Stop - } -} - -ACTOR ZVasePillar -{ - Radius 12 - Height 54 - +SOLID - States - { - Spawn: - VASE A -1 - Stop - } -} - -ACTOR ZCorpseLynched -{ - Radius 11 - Height 95 - +SOLID - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - CPS4 A -1 - Stop - } -} - -ACTOR ZCandle -{ - Radius 20 - Height 16 - +NOGRAVITY - +NOBLOCKMAP - States - { - Spawn: - CNDL ABC 4 Bright - Loop - } -} - -ACTOR ZBarrel -{ - Radius 15 - Height 32 - +SOLID - States - { - Spawn: - ZBAR A -1 - Stop - } -} - -ACTOR ZBucket -{ - Radius 8 - Height 72 - +SOLID - +SPAWNCEILING - +NOGRAVITY - States - { - Spawn: - BCKT A -1 - Stop - } -} - -ACTOR FireThing -{ - Radius 5 - Height 10 - +SOLID - States - { - Spawn: - FSKL A 4 Bright - FSKL B 3 Bright - FSKL C 4 Bright - FSKL D 3 Bright - FSKL E 4 Bright - FSKL F 3 Bright - FSKL G 4 Bright - FSKL H 3 Bright - FSKL I 4 Bright - Loop - } -} - -ACTOR BrassTorch -{ - Radius 6 - Height 35 - +SOLID - States - { - Spawn: - BRTR ABCDEFGHIJKLM 4 Bright - Loop - } -} - -ACTOR ZBlueCandle -{ - Radius 20 - Height 16 - +NOBLOCKMAP - States - { - Spawn: - BCAN ABCDE 5 Bright - Loop - } -} - -ACTOR ZIronMaiden -{ - Radius 12 - Height 60 - +SOLID - States - { - Spawn: - IRON A -1 - Stop - } -} - -ACTOR ZChainBit32 -{ - Radius 4 - Height 32 - +SPAWNCEILING - +NOGRAVITY - +NOBLOCKMAP - States - { - Spawn: - CHNS A -1 - Stop - } -} - -ACTOR ZChainBit64 -{ - Radius 4 - Height 64 - +SPAWNCEILING - +NOGRAVITY - +NOBLOCKMAP - States - { - Spawn: - CHNS B -1 - Stop - } -} - -ACTOR ZChainEndHeart -{ - Radius 4 - Height 32 - +SPAWNCEILING - +NOGRAVITY - +NOBLOCKMAP - States - { - Spawn: - CHNS C -1 - Stop - } -} - -ACTOR ZChainEndHook1 -{ - Radius 4 - Height 32 - +SPAWNCEILING - +NOGRAVITY - +NOBLOCKMAP - States - { - Spawn: - CHNS D -1 - Stop - } -} - -ACTOR ZChainEndHook2 -{ - Radius 4 - Height 32 - +SPAWNCEILING - +NOGRAVITY - +NOBLOCKMAP - States - { - Spawn: - CHNS E -1 - Stop - } -} - -ACTOR ZChainEndSpike -{ - Radius 4 - Height 32 - +SPAWNCEILING - +NOGRAVITY - +NOBLOCKMAP - States - { - Spawn: - CHNS F -1 - Stop - } -} - -ACTOR ZChainEndSkull -{ - Radius 4 - Height 32 - +SPAWNCEILING - +NOGRAVITY - +NOBLOCKMAP - States - { - Spawn: - CHNS G -1 - Stop - } -} - -ACTOR TableShit1 -{ - Radius 20 - Height 16 - +NOBLOCKMAP - States - { - Spawn: - TST1 A -1 - Stop - } -} - -ACTOR TableShit2 -{ - Radius 20 - Height 16 - +NOBLOCKMAP - States - { - Spawn: - TST2 A -1 - Stop - } -} - -ACTOR TableShit3 -{ - Radius 20 - Height 16 - +NOBLOCKMAP - States - { - Spawn: - TST3 A -1 - Stop - } -} - -ACTOR TableShit4 -{ - Radius 20 - Height 16 - +NOBLOCKMAP - States - { - Spawn: - TST4 A -1 - Stop - } -} - -ACTOR TableShit5 -{ - Radius 20 - Height 16 - +NOBLOCKMAP - States - { - Spawn: - TST5 A -1 - Stop - } -} - -ACTOR TableShit6 -{ - Radius 20 - Height 16 - +NOBLOCKMAP - States - { - Spawn: - TST6 A -1 - Stop - } -} - -ACTOR TableShit7 -{ - Radius 20 - Height 16 - +NOBLOCKMAP - States - { - Spawn: - TST7 A -1 - Stop - } -} - -ACTOR TableShit8 -{ - Radius 20 - Height 16 - +NOBLOCKMAP - States - { - Spawn: - TST8 A -1 - Stop - } -} - -ACTOR TableShit9 -{ - Radius 20 - Height 16 - +NOBLOCKMAP - States - { - Spawn: - TST9 A -1 - Stop - } -} - -ACTOR TableShit10 -{ - Radius 20 - Height 16 - +NOBLOCKMAP - States - { - Spawn: - TST0 A -1 - Stop - } -} - -ACTOR TeleSmoke -{ - Radius 20 - Height 16 - +NOGRAVITY - +NOBLOCKMAP - RenderStyle Translucent - Alpha 0.6 - States - { - Spawn: - TSMK A 4 - TSMK B 3 - TSMK C 4 - TSMK D 3 - TSMK E 4 - TSMK F 3 - TSMK G 4 - TSMK H 3 - TSMK I 4 - TSMK J 3 - TSMK K 4 - TSMK L 3 - TSMK M 4 - TSMK N 3 - TSMK O 4 - TSMK P 3 - TSMK Q 4 - TSMK R 3 - TSMK S 4 - TSMK T 3 - TSMK U 4 - TSMK V 3 - TSMK W 4 - TSMK X 3 - TSMK Y 4 - TSMK Z 3 - Loop - } -} - diff --git a/wadsrc/static/actors/hexen/hexenkeys.txt b/wadsrc/static/actors/hexen/hexenkeys.txt deleted file mode 100644 index b65d59e164..0000000000 --- a/wadsrc/static/actors/hexen/hexenkeys.txt +++ /dev/null @@ -1,139 +0,0 @@ - -ACTOR HexenKey : Key -{ - Radius 8 - Height 20 -} - -ACTOR KeySteel : HexenKey -{ - Inventory.Icon KEYSLOT1 - Inventory.PickupMessage "$TXT_KEY_STEEL" - States - { - Spawn: - KEY1 A -1 - Stop - } -} - -ACTOR KeyCave : HexenKey -{ - Inventory.Icon KEYSLOT2 - Inventory.PickupMessage "$TXT_KEY_CAVE" - States - { - Spawn: - KEY2 A -1 - Stop - } -} - -ACTOR KeyAxe : HexenKey -{ - Inventory.Icon KEYSLOT3 - Inventory.PickupMessage "$TXT_KEY_AXE" - States - { - Spawn: - KEY3 A -1 - Stop - } -} - -ACTOR KeyFire : HexenKey -{ - Inventory.Icon KEYSLOT4 - Inventory.PickupMessage "$TXT_KEY_FIRE" - States - { - Spawn: - KEY4 A -1 - Stop - } -} - -ACTOR KeyEmerald : HexenKey -{ - Inventory.Icon KEYSLOT5 - Inventory.PickupMessage "$TXT_KEY_EMERALD" - States - { - Spawn: - KEY5 A -1 - Stop - } -} - -ACTOR KeyDungeon : HexenKey -{ - Inventory.Icon KEYSLOT6 - Inventory.PickupMessage "$TXT_KEY_DUNGEON" - States - { - Spawn: - KEY6 A -1 - Stop - } -} - -ACTOR KeySilver : HexenKey -{ - Inventory.Icon KEYSLOT7 - Inventory.PickupMessage "$TXT_KEY_SILVER" - States - { - Spawn: - KEY7 A -1 - Stop - } -} - -ACTOR KeyRusted : HexenKey -{ - Inventory.Icon KEYSLOT8 - Inventory.PickupMessage "$TXT_KEY_RUSTED" - States - { - Spawn: - KEY8 A -1 - Stop - } -} - -ACTOR KeyHorn : HexenKey -{ - Inventory.Icon KEYSLOT9 - Inventory.PickupMessage "$TXT_KEY_HORN" - States - { - Spawn: - KEY9 A -1 - Stop - } -} - -ACTOR KeySwamp : HexenKey -{ - Inventory.Icon KEYSLOTA - Inventory.PickupMessage "$TXT_KEY_SWAMP" - States - { - Spawn: - KEYA A -1 - Stop - } -} - -ACTOR KeyCastle : HexenKey -{ - Inventory.Icon KEYSLOTB - Inventory.PickupMessage "$TXT_KEY_CASTLE" - States - { - Spawn: - KEYB A -1 - Stop - } -} - diff --git a/wadsrc/static/actors/hexen/hexenspecialdecs.txt b/wadsrc/static/actors/hexen/hexenspecialdecs.txt deleted file mode 100644 index cd50633858..0000000000 --- a/wadsrc/static/actors/hexen/hexenspecialdecs.txt +++ /dev/null @@ -1,684 +0,0 @@ - -// Winged Statue (no skull) ------------------------------------------------- - -ACTOR ZWingedStatueNoSkull : SwitchingDecoration -{ - Radius 10 - Height 62 - +SOLID - States - { - Spawn: - STWN A -1 - Stop - Active: - STWN B -1 - Stop - } -} - - -// Gem pedestal ------------------------------------------------------------- - -ACTOR ZGemPedestal : SwitchingDecoration -{ - Radius 10 - Height 40 - +SOLID - States - { - Spawn: - GMPD A -1 - Stop - Active: - GMPD B -1 - Stop - } -} - - -// Tree (destructible) ------------------------------------------------------ - -ACTOR TreeDestructible -{ - Health 70 - Radius 15 - Height 180 - DeathHeight 24 - Mass 0x7fffffff - PainSound "TreeExplode" - DeathSound "TreeBreak" - +SOLID +SHOOTABLE +NOBLOOD +NOICEDEATH - States - { - Spawn: - TRDT A -1 - Stop - Death: - TRDT B 5 - TRDT C 5 A_Scream - TRDT DEF 5 - TRDT G -1 - Stop - Burn: - TRDT H 5 Bright A_Pain - TRDT IJKL 5 Bright - TRDT M 5 Bright A_Explode(10, 128) - TRDT N 5 Bright - TRDT OP 5 - TRDT Q -1 - Stop - } -} - - -// Pottery1 ------------------------------------------------------------------ - -ACTOR Pottery1 native -{ - Health 15 - Speed 10 - Height 32 - +SOLID +SHOOTABLE +NOBLOOD +DROPOFF - +SLIDESONWALLS +PUSHABLE +TELESTOMP +CANPASS - +NOICEDEATH - - action native A_PotteryExplode(); - - States - { - Spawn: - POT1 A -1 - Loop - Death: - POT1 A 0 A_PotteryExplode - Stop - } -} - -// Pottery2 ----------------------------------------------------------------- - -ACTOR Pottery2 : Pottery1 -{ - Height 25 - States - { - Spawn: - POT2 A -1 - Stop - } -} - -// Pottery3 ----------------------------------------------------------------- - -ACTOR Pottery3 : Pottery1 -{ - Height 25 - States - { - Spawn: - POT3 A -1 - Stop - } -} - -// Pottery Bit -------------------------------------------------------------- - -ACTOR PotteryBit -{ - Radius 5 - Height 5 - +MISSILE - +NOTELEPORT - +NOICEDEATH - - action native A_PotteryChooseBit(); - action native A_PotteryCheck(); - - States - { - Spawn: - PBIT ABCDE -1 - Stop - Death: - PBIT F 0 A_PotteryChooseBit - Stop - Pottery1: - PBIT F 140 - PBIT F 1 A_PotteryCheck - Stop - Pottery2: - PBIT G 140 - PBIT G 1 A_PotteryCheck - Stop - Pottery3: - PBIT H 140 - PBIT H 1 A_PotteryCheck - Stop - Pottery4: - PBIT I 140 - PBIT I 1 A_PotteryCheck - Stop - Pottery5: - PBIT J 140 - PBIT J 1 A_PotteryCheck - Stop - } -} - - -// Blood pool --------------------------------------------------------------- - -ACTOR BloodPool -{ - States - { - Spawn: - BDPL A -1 - Stop - } -} - - -// Lynched corpse (no heart) ------------------------------------------------ - -ACTOR ZCorpseLynchedNoHeart native -{ - Radius 10 - Height 100 - +SOLID +SPAWNCEILING +NOGRAVITY - - action native A_CorpseBloodDrip(); - - States - { - Spawn: - CPS5 A 140 A_CorpseBloodDrip - Loop - } -} - - -// CorpseBloodDrip ---------------------------------------------------------- - -ACTOR CorpseBloodDrip -{ - Radius 1 - Height 4 - Gravity 0.125 - +MISSILE - +NOICEDEATH - DeathSound "Drip" - States - { - Spawn: - BDRP A -1 - Stop - Death: - BDSH AB 3 - BDSH CD 2 - Stop - } -} - - -// Corpse bit --------------------------------------------------------------- - -ACTOR CorpseBit -{ - Radius 5 - Height 5 - +NOBLOCKMAP - +TELESTOMP - States - { - Spawn: - CPB1 A -1 - Stop - CPB2 A -1 - Stop - CPB3 A -1 - Stop - CPB4 A -1 - Stop - } -} - - -// Corpse (sitting, splatterable) ------------------------------------------- - -ACTOR ZCorpseSitting -{ - Health 30 - Radius 15 - Height 35 - +SOLID +SHOOTABLE +NOBLOOD - +NOICEDEATH - DeathSound "FireDemonDeath" - - action native A_CorpseExplode(); - - States - { - Spawn: - CPS6 A -1 - Stop - Death: - CPS6 A 1 A_CorpseExplode - Stop - } -} - - -// Leaf Spawner ------------------------------------------------------------- - -ACTOR LeafSpawner -{ - +NOBLOCKMAP +NOSECTOR - +INVISIBLE - - action native A_LeafSpawn(); - - States - { - Spawn: - TNT1 A 20 A_LeafSpawn - Loop - } -} - - -// Leaf 1 ------------------------------------------------------------------- - -ACTOR Leaf1 -{ - Radius 2 - Height 4 - Gravity 0.125 - +NOBLOCKMAP +MISSILE - +NOTELEPORT +DONTSPLASH - +NOICEDEATH - - action native A_LeafThrust(); - action native A_LeafCheck(); - - States - { - Spawn: - LEF1 ABC 4 - LEF1 D 4 A_LeafThrust - LEF1 EFG 4 - LEF1 H 4 A_LeafThrust - LEF1 I 4 - LEF1 AB 4 - LEF1 C 4 A_LeafThrust - LEF1 DEF 4 - LEF1 G 4 A_LeafThrust - LEF1 HI 4 - Stop - Death: - LEF3 D 10 A_LeafCheck - Wait - } -} - - -// Leaf 2 ------------------------------------------------------------------- - -ACTOR Leaf2 : Leaf1 -{ - States - { - Spawn: - LEF2 ABC 4 - LEF2 D 4 A_LeafThrust - LEF2 EFG 4 - LEF2 H 4 A_LeafThrust - LEF2 I 4 - LEF2 AB 4 - LEF2 C 4 A_LeafThrust - LEF2 DEF 4 - LEF2 G 4 A_LeafThrust - LEF2 HI 4 - Stop - } -} - - -// Twined torch ------------------------------------------------------------- - -ACTOR ZTwinedTorch : SwitchableDecoration -{ - Radius 10 - Height 64 - +SOLID - States - { - Active: - TWTR A 0 Bright A_PlaySound("Ignite") - Spawn: - TWTR ABCDEFGH 4 Bright - Loop - Inactive: - TWTR I -1 - Stop - } -} - -ACTOR ZTwinedTorchUnlit : ZTwinedTorch -{ - States - { - Spawn: - Goto Super::Inactive - } -} - - -// Wall torch --------------------------------------------------------------- - -ACTOR ZWallTorch : SwitchableDecoration -{ - +NOBLOCKMAP - +NOGRAVITY - +FIXMAPTHINGPOS - Radius 6.5 - States - { - Active: - WLTR A 0 Bright A_PlaySound("Ignite") - Spawn: - WLTR ABCDEFGH 5 Bright - Loop - Inactive: - WLTR I -1 - Stop - } -} - -ACTOR ZWallTorchUnlit : ZWallTorch -{ - States - { - Spawn: - Goto Super::Inactive - } -} - - -// Shrub1 ------------------------------------------------------------------- - -ACTOR ZShrub1 -{ - Radius 8 - Height 24 - Health 20 - Mass 0x7fffffff - +SOLID +SHOOTABLE +NOBLOOD +NOICEDEATH - DeathSound "TreeExplode" - States - { - Spawn: - SHB1 A -1 - Stop - Burn: - SHB1 B 7 Bright - SHB1 C 6 Bright A_Scream - SHB1 D 5 Bright - Stop - } -} - - -// Shrub2 ------------------------------------------------------------------- - -ACTOR ZShrub2 -{ - Radius 16 - Height 40 - Health 20 - Mass 0x7fffffff - +SOLID +SHOOTABLE +NOBLOOD +NOICEDEATH - DeathSound "TreeExplode" - States - { - Spawn: - SHB2 A -1 - Stop - Burn: - SHB2 B 7 Bright - SHB2 C 6 Bright A_Scream - SHB2 D 5 Bright A_Explode(30, 64) - SHB2 E 5 Bright - Stop - } -} - - -// Fire Bull ---------------------------------------------------------------- - -ACTOR ZFireBull : SwitchableDecoration -{ - Radius 20 - Height 80 - +SOLID - States - { - Active: - FBUL I 4 Bright A_PlaySound("Ignite") - FBUL J 4 Bright - Spawn: - FBUL ABCDEFG 4 Bright - Loop - Inactive: - FBUL JI 4 Bright - FBUL H -1 - Stop - } -} - -ACTOR ZFireBullUnlit : ZFireBull -{ - States - { - Spawn: - Goto Super::Inactive+2 - } -} - - -// Suit of armor ------------------------------------------------------------ - -ACTOR ZSuitOfArmor -{ - Health 60 - Radius 16 - Height 72 - Mass 0x7fffffff - +SOLID +SHOOTABLE +NOBLOOD - +NOICEDEATH - DeathSound "SuitofArmorBreak" - - action native A_SoAExplode(); - - States - { - Spawn: - ZSUI A -1 - Stop - Death: - ZSUI A 1 A_SoAExplode - Stop - } -} - - -// Armor chunk -------------------------------------------------------------- - -ACTOR ZArmorChunk -{ - Radius 4 - Height 8 - States - { - Spawn: - ZSUI B -1 - Stop - ZSUI C -1 - Stop - ZSUI D -1 - Stop - ZSUI E -1 - Stop - ZSUI F -1 - Stop - ZSUI G -1 - Stop - ZSUI H -1 - Stop - ZSUI I -1 - Stop - ZSUI J -1 - Stop - ZSUI K -1 - Stop - } -} - - -// Bell --------------------------------------------------------------------- - -ACTOR ZBell native -{ - Health 5 - Radius 56 - Height 120 - Mass 0x7fffffff - +SOLID +SHOOTABLE +NOBLOOD +NOGRAVITY +SPAWNCEILING - +NOICEDEATH - DeathSound "BellRing" - - action native A_BellReset1(); - action native A_BellReset2(); - - States - { - Spawn: - BBLL F -1 - Stop - Death: - BBLL A 4 A_BellReset1 - BBLL BC 4 - BBLL D 5 A_Scream - BBLL CB 4 - BBLL A 3 - BBLL E 4 - BBLL F 5 - BBLL G 6 A_Scream - BBLL F 5 - BBLL EA 4 - BBLL BC 5 - BBLL D 6 A_Scream - BBLL CB 5 - BBLL A 4 - BBLL EF 5 - BBLL G 7 A_Scream - BBLL FEA 5 - BBLL B 6 - BBLL C 6 - BBLL D 7 A_Scream - BBLL CB 6 - BBLL A 5 - BBLL EF 6 - BBLL G 7 A_Scream - BBLL FEABC 6 - BBLL B 7 - BBLL A 8 - BBLL E 12 - BBLL A 10 - BBLL B 12 - BBLL A 12 - BBLL E 14 - BBLL A 1 A_BellReset2 - Goto Spawn - } -} - - -// "Christmas" Tree --------------------------------------------------------- - -ACTOR ZXmasTree -{ - Radius 11 - Height 130 - Health 20 - Mass 0x7fffffff - +SOLID +SHOOTABLE +NOBLOOD +NOICEDEATH - DeathSound "TreeExplode" - States - { - Spawn: - XMAS A -1 - Stop - Burn: - XMAS B 6 Bright - XMAS C 6 Bright A_Scream - XMAS D 5 Bright - XMAS E 5 Bright A_Explode(30, 64) - XMAS F 5 Bright - XMAS G 4 Bright - XMAS H 5 - XMAS I 4 A_NoBlocking - XMAS J 4 - XMAS K -1 - Stop - } -} - -// Cauldron ----------------------------------------------------------------- - -ACTOR ZCauldron : SwitchableDecoration -{ - Radius 12 - Height 26 - +SOLID - States - { - Active: - CDRN B 0 Bright A_PlaySound("Ignite") - Spawn: - CDRN BCDEFGH 4 Bright - Loop - Inactive: - CDRN A -1 - Stop - } -} - -ACTOR ZCauldronUnlit : ZCauldron -{ - States - { - Spawn: - Goto Super::Inactive - } -} - - -// Water Drip --------------------------------------------------------------- - -ACTOR HWaterDrip -{ - +MISSILE - +LOWGRAVITY - +NOTELEPORT - Mass 1 - DeathSound "Drip" - States - { - Spawn: - HWAT A -1 - Stop - } -} - diff --git a/wadsrc/static/actors/hexen/iceguy.txt b/wadsrc/static/actors/hexen/iceguy.txt deleted file mode 100644 index 235be474fa..0000000000 --- a/wadsrc/static/actors/hexen/iceguy.txt +++ /dev/null @@ -1,167 +0,0 @@ - -// Ice Guy ------------------------------------------------------------------ - -ACTOR IceGuy -{ - Health 120 - PainChance 144 - Speed 14 - Radius 22 - Height 75 - Mass 150 - DamageType "Ice" - Monster - +NOBLOOD - +TELESTOMP - +NOICEDEATH - SeeSound "IceGuySight" - AttackSound "IceGuyAttack" - ActiveSound "IceGuyActive" - Obituary "$OB_ICEGUY" - - action native A_IceGuyLook(); - action native A_IceGuyChase(); - action native A_IceGuyAttack(); - - States - { - Spawn: - ICEY A 10 A_IceGuyLook - Loop - See: - ICEY A 4 A_Chase - ICEY B 4 A_IceGuyChase - ICEY CD 4 A_Chase - Loop - Pain: - ICEY A 1 A_Pain - Goto See - Missile: - ICEY EF 3 A_FaceTarget - ICEY G 8 Bright A_IceGuyAttack - ICEY F 4 A_FaceTarget - Goto See - Death: - ICEY A 1 A_IceGuyDie - Stop - Inactive: - ICEY A -1 - Goto See - } -} - -// Ice Guy Projectile ------------------------------------------------------- - -ACTOR IceGuyFX -{ - Speed 14 - Radius 8 - Height 10 - Damage 1 - DamageType "Ice" - Projectile - -ACTIVATEIMPACT -ACTIVATEPCROSS - DeathSound "IceGuyMissileExplode" - - action native A_IceGuyMissileExplode(); - - States - { - Spawn: - ICPR ABC 3 Bright A_SpawnItemEx("IceFXPuff", 0,0,2) - Loop - Death: - ICPR D 4 Bright - ICPR E 4 Bright A_IceGuyMissileExplode - ICPR FG 4 Bright - ICPR H 3 Bright - Stop - } -} - -// Ice Guy Projectile's Puff ------------------------------------------------ - -ACTOR IceFXPuff -{ - Radius 1 - Height 1 - +NOBLOCKMAP +NOGRAVITY +DROPOFF +SHADOW - +NOTELEPORT - RenderStyle Translucent - Alpha 0.4 - States - { - Spawn: - ICPR IJK 3 - ICPR LM 2 - Stop - } -} - -// Secondary Ice Guy Projectile (ejected by the primary projectile) --------- - -ACTOR IceGuyFX2 -{ - Speed 10 - Radius 4 - Height 4 - Damage 1 - DamageType "Ice" - Gravity 0.125 - +NOBLOCKMAP +DROPOFF +MISSILE - +NOTELEPORT - +STRIFEDAMAGE - States - { - Spawn: - ICPR NOP 3 Bright - Loop - } -} - -// Ice Guy Bit -------------------------------------------------------------- - -ACTOR IceGuyBit -{ - Radius 1 - Height 1 - Gravity 0.125 - +NOBLOCKMAP +DROPOFF - +NOTELEPORT - States - { - Spawn: - ICPR Q 50 Bright - Stop - ICPR R 50 Bright - Stop - } -} - -// Ice Guy Wisp 1 ----------------------------------------------------------- - -ACTOR IceGuyWisp1 -{ - +NOBLOCKMAP +NOGRAVITY +DROPOFF +MISSILE - +NOTELEPORT - RenderStyle Translucent - Alpha 0.4 - States - { - Spawn: - ICWS ABCDEFGHI 2 - Stop - } -} - -// Ice Guy Wisp 2 ----------------------------------------------------------- - -ACTOR IceGuyWisp2 : IceGuyWisp1 -{ - States - { - Spawn: - ICWS JKLMNOPQR 2 - Stop - } -} diff --git a/wadsrc/static/actors/hexen/korax.txt b/wadsrc/static/actors/hexen/korax.txt deleted file mode 100644 index a35183ad6b..0000000000 --- a/wadsrc/static/actors/hexen/korax.txt +++ /dev/null @@ -1,124 +0,0 @@ -ACTOR Korax -{ - Health 5000 - Painchance 20 - Speed 10 - Radius 65 - Height 115 - Mass 2000 - Damage 15 - Monster - +BOSS - +FLOORCLIP - +TELESTOMP - +DONTMORPH - +NOTARGET - +NOICEDEATH - SeeSound "KoraxSight" - AttackSound "KoraxAttack" - PainSound "KoraxPain" - DeathSound "KoraxDeath" - ActiveSound "KoraxActive" - Obituary "$OB_KORAX" // "%o was swept from the board by Korax." - - action native A_KoraxChase(); - action native A_KoraxDecide(); - action native A_KoraxBonePop(); - action native A_KoraxMissile(); - action native A_KoraxCommand(); - - States - { - Spawn: - KORX A 5 A_Look - Loop - See: - KORX AAA 3 A_KoraxChase - KORX B 3 A_Chase - KORX BBB 3 A_KoraxChase - KORX C 0 A_PlaySound("KoraxStep") - KORX C 3 A_Chase - KORX CCC 3 A_KoraxChase - KORX D 3 A_Chase - KORX DDD 3 A_KoraxChase - KORX A 0 A_PlaySound("KoraxStep") - KORX A 3 A_Chase - Loop - Pain: - KORX H 5 A_Pain - KORX H 5 - Goto See - Missile: - KORX E 2 Bright A_FaceTarget - KORX E 5 Bright A_KoraxDecide - Wait - Death: - KORX I 5 - KORX J 5 A_FaceTarget - KORX K 5 A_Scream - KORX LMNOP 5 - KORX Q 10 - KORX R 5 A_KoraxBonePop - KORX S 5 A_NoBlocking - KORX TU 5 - KORX V -1 - Stop - Attack: - KORX E 4 Bright A_FaceTarget - KORX F 8 Bright A_KoraxMissile - KORX E 8 Bright - Goto See - Command: - KORX E 5 Bright A_FaceTarget - KORX W 10 Bright A_FaceTarget - KORX G 15 Bright A_KoraxCommand - KORX W 10 Bright - KORX E 5 Bright - Goto See - } -} - -ACTOR KoraxSpirit -{ - Speed 8 - Projectile - +NOCLIP - -ACTIVATEPCROSS - -ACTIVATEIMPACT - RenderStyle Translucent - Alpha 0.4 - - action native A_KSpiritRoam(); - - States - { - Spawn: - SPIR AB 5 A_KSpiritRoam - Loop - Death: - SPIR DEFGHI 5 - Stop - } -} - -ACTOR KoraxBolt -{ - Radius 15 - Height 35 - Projectile - -ACTIVATEPCROSS - -ACTIVATEIMPACT - RenderStyle Add - - action native A_KBolt(); - action native A_KBoltRaise(); - - States - { - Spawn: - MLFX I 2 Bright - MLFX J 2 Bright A_KBoltRaise - MLFX IJKLM 2 Bright A_KBolt - Stop - } -} diff --git a/wadsrc/static/actors/hexen/mageboss.txt b/wadsrc/static/actors/hexen/mageboss.txt deleted file mode 100644 index 95f36954ba..0000000000 --- a/wadsrc/static/actors/hexen/mageboss.txt +++ /dev/null @@ -1,83 +0,0 @@ - -// Mage Boss (Menelkir) ----------------------------------------------------- - -ACTOR MageBoss -{ - Health 800 - PainChance 50 - Speed 25 - Radius 16 - Height 64 - Monster - +FLOORCLIP +TELESTOMP - +DONTMORPH - PainSound "PlayerMagePain" - DeathSound "PlayerMageCrazyDeath" - Obituary "$OB_MBOSS" - - action native A_MageAttack(); - - States - { - Spawn: - MAGE A 2 - MAGE A 3 A_ClassBossHealth - MAGE A 5 A_Look - Wait - See: - MAGE ABCD 4 A_FastChase - Loop - Pain: - MAGE G 4 - MAGE G 4 A_Pain - Goto See - Melee: - Missile: - MAGE E 8 A_FaceTarget - MAGE F 8 Bright A_MageAttack - Goto See - Death: - MAGE H 6 - MAGE I 6 A_Scream - MAGE JK 6 - MAGE L 6 A_NoBlocking - MAGE M 6 - MAGE N -1 - Stop - XDeath: - MAGE O 5 A_Scream - MAGE P 5 - MAGE R 5 A_NoBlocking - MAGE S 5 - MAGE T 5 - MAGE U 5 - MAGE V 5 - MAGE W 5 - MAGE X -1 - Stop - Ice: - MAGE Y 5 A_FreezeDeath - MAGE Y 1 A_FreezeDeathChunks - Wait - Burn: - FDTH E 5 Bright A_PlaySound("PlayerMageBurnDeath") - FDTH F 4 Bright - FDTH G 5 Bright - FDTH H 4 Bright A_Scream - FDTH I 5 Bright - FDTH J 4 Bright - FDTH K 5 Bright - FDTH L 4 Bright - FDTH M 5 Bright - FDTH N 4 Bright - FDTH O 5 Bright - FDTH P 4 Bright - FDTH Q 5 Bright - FDTH R 4 Bright - FDTH S 5 Bright A_NoBlocking - FDTH T 4 Bright - FDTH U 5 Bright - FDTH V 4 Bright - Stop - } -} diff --git a/wadsrc/static/actors/hexen/magecone.txt b/wadsrc/static/actors/hexen/magecone.txt deleted file mode 100644 index 72c37c38cd..0000000000 --- a/wadsrc/static/actors/hexen/magecone.txt +++ /dev/null @@ -1,89 +0,0 @@ - -// The Mage's Frost Cone ---------------------------------------------------- - -ACTOR MWeapFrost : MageWeapon -{ - +BLOODSPLATTER - Weapon.SelectionOrder 1700 - Weapon.AmmoUse1 3 - Weapon.AmmoGive1 25 - Weapon.KickBack 150 - Weapon.YAdjust 20 - Weapon.AmmoType1 "Mana1" - Inventory.PickupMessage "$TXT_WEAPON_M2" - Obituary "$OB_MPMWEAPFROST" - Tag "$TAG_MWEAPFROST" - - action native A_FireConePL1(); - - States - { - Spawn: - WMCS ABC 8 Bright - Loop - Select: - CONE A 1 A_Raise - Loop - Deselect: - CONE A 1 A_Lower - Loop - Ready: - CONE A 1 A_WeaponReady - Loop - Fire: - CONE B 3 - CONE C 4 - Hold: - CONE D 3 - CONE E 5 - CONE F 3 A_FireConePL1 - CONE G 3 - CONE A 9 - CONE A 10 A_ReFire - Goto Ready - } -} - -// Frost Missile ------------------------------------------------------------ - -ACTOR FrostMissile native -{ - Speed 25 - Radius 13 - Height 8 - Damage 1 - DamageType "Ice" - Projectile - DeathSound "MageShardsExplode" - Obituary "$OB_MPMWEAPFROST" - - action native A_ShedShard(); - - States - { - Spawn: - SHRD A 2 Bright - SHRD A 3 Bright A_ShedShard - SHRD B 3 Bright - SHRD C 3 Bright - Loop - Death: - SHEX ABCDE 5 Bright - Stop - } -} - -// Ice Shard ---------------------------------------------------------------- - -ACTOR IceShard : FrostMissile -{ - DamageType "Ice" - -ACTIVATEIMPACT - -ACTIVATEPCROSS - States - { - Spawn: - SHRD ABC 3 Bright - Loop - } -} diff --git a/wadsrc/static/actors/hexen/magelightning.txt b/wadsrc/static/actors/hexen/magelightning.txt deleted file mode 100644 index d12b7d389d..0000000000 --- a/wadsrc/static/actors/hexen/magelightning.txt +++ /dev/null @@ -1,154 +0,0 @@ - -// The Mage's Lightning Arc of Death ---------------------------------------- - -ACTOR MWeapLightning : MageWeapon -{ - +NOGRAVITY - Weapon.SelectionOrder 1100 - Weapon.AmmoUse1 5 - Weapon.AmmoGive1 25 - Weapon.KickBack 0 - Weapon.YAdjust 20 - Weapon.AmmoType1 "Mana2" - Inventory.PickupMessage "$TXT_WEAPON_M3" - Tag "$TAG_MWEAPLIGHTNING" - - action native A_LightningReady(); - action native A_MLightningAttack(class floor = "LightningFloor", class ceiling = "LightningCeiling"); - - States - { - Spawn: - WMLG ABCDEFGH 4 Bright - Loop - Select: - MLNG A 1 Bright A_Raise - Loop - Deselect: - MLNG A 1 Bright A_Lower - Loop - Ready: - MLNG AAAAA 1 Bright A_WeaponReady - MLNG A 1 Bright A_LightningReady - MLNG BBBBBB 1 Bright A_WeaponReady - MLNG CCCCC 1 Bright A_WeaponReady - MLNG C 1 Bright A_LightningReady - MLNG BBBBBB 1 Bright A_WeaponReady - Loop - Fire: - MLNG DE 3 Bright - MLNG F 4 Bright A_MLightningAttack - MLNG G 4 Bright - MLNG HI 3 Bright - MLNG I 6 Bright Offset (0, 199) - MLNG C 2 Bright Offset (0, 55) - MLNG B 2 Bright Offset (0, 50) - MLNG B 2 Bright Offset (0, 45) - MLNG B 2 Bright Offset (0, 40) - Goto Ready - } -} - -// Ceiling Lightning -------------------------------------------------------- - -ACTOR Lightning native -{ - MissileType "LightningZap" - AttackSound "MageLightningZap" - ActiveSound "MageLightningContinuous" - Obituary "$OB_MPMWEAPLIGHTNING" -} - -ACTOR LightningCeiling : Lightning -{ - Health 144 - Speed 25 - Radius 16 - Height 40 - Damage 8 - Projectile - +CEILINGHUGGER - RenderStyle Add - - action native A_LightningZap(); - action native A_LightningClip(); - action native A_LightningRemove(); - - States - { - Spawn: - MLFX A 2 Bright A_LightningZap - MLFX BCD 2 Bright A_LightningClip - Loop - Death: - MLF2 A 2 Bright A_LightningRemove - MLF2 BCDEKLM 3 Bright - ACLO E 35 - MLF2 NO 3 Bright - MLF2 P 4 Bright - MLF2 QP 3 Bright - MLF2 Q 4 Bright - MLF2 P 3 Bright - MLF2 O 3 Bright - MLF2 P 3 Bright - MLF2 P 1 Bright A_HideThing - ACLO E 1050 - Stop - } -} - -// Floor Lightning ---------------------------------------------------------- - -ACTOR LightningFloor : LightningCeiling -{ - -CEILINGHUGGER - +FLOORHUGGER - RenderStyle Add - - action native A_LastZap(); - - States - { - Spawn: - MLFX E 2 Bright A_LightningZap - MLFX FGH 2 Bright A_LightningClip - Loop - Death: - MLF2 F 2 Bright A_LightningRemove - MLF2 GHIJKLM 3 Bright - ACLO E 20 - MLF2 NO 3 Bright - MLF2 P 4 Bright - MLF2 QP 3 Bright - MLF2 Q 4 Bright A_LastZap - MLF2 POP 3 Bright - MLF2 P 1 Bright A_HideThing - Goto Super::Death + 19 - } -} - -// Lightning Zap ------------------------------------------------------------ - -ACTOR LightningZap native -{ - Radius 15 - Height 35 - Damage 2 - Projectile - -ACTIVATEIMPACT - -ACTIVATEPCROSS - RenderStyle Add - Obituary "$OB_MPMWEAPLIGHTNING" - - action native A_ZapMimic(); - - States - { - Spawn: - MLFX IJKLM 2 Bright A_ZapMimic - Loop - Death: - MLFX NOPQRSTU 2 Bright - Stop - } -} diff --git a/wadsrc/static/actors/hexen/mageplayer.txt b/wadsrc/static/actors/hexen/mageplayer.txt deleted file mode 100644 index 9cf4117a5e..0000000000 --- a/wadsrc/static/actors/hexen/mageplayer.txt +++ /dev/null @@ -1,104 +0,0 @@ -// The mage ----------------------------------------------------------------- - -ACTOR MagePlayer : PlayerPawn -{ - Health 100 - ReactionTime 0 - PainChance 255 - Radius 16 - Height 64 - Speed 1 - +NOSKIN - +NODAMAGETHRUST - +NOTHRUSTWHENINVUL - PainSound "PlayerMagePain" - RadiusDamageFactor 0.25 - Player.JumpZ 9 - Player.Viewheight 48 - Player.SpawnClass "Mage" - Player.DisplayName "Mage" - Player.SoundClass "mage" - Player.ScoreIcon "MAGEFACE" - Player.InvulnerabilityMode "Reflective" - Player.HealRadiusType "Mana" - Player.Hexenarmor 5, 5, 15, 10, 25 - Player.StartItem "MWeapWand" - Player.ForwardMove 0.88, 0.92 - Player.SideMove 0.875, 0.925 - Player.Portrait "P_MWALK1" - Player.WeaponSlot 1, MWeapWand - Player.WeaponSlot 2, MWeapFrost - Player.WeaponSlot 3, MWeapLightning - Player.WeaponSlot 4, MWeapBloodscourge - Player.FlechetteType "ArtiPoisonBag2" - - Player.ColorRange 146, 163 - Player.Colorset 0, "Blue", 146, 163, 161 - Player.ColorsetFile 1, "Red", "TRANTBL7", 0xB3 - Player.ColorsetFile 2, "Gold", "TRANTBL8", 0x8C - Player.ColorsetFile 3, "Dull Green", "TRANTBL9", 0x41 - Player.ColorsetFile 4, "Green", "TRANTBLA", 0xC9 - Player.ColorsetFile 5, "Gray", "TRANTBLB", 0x30 - Player.ColorsetFile 6, "Brown", "TRANTBLC", 0x72 - Player.ColorsetFile 7, "Purple", "TRANTBLD", 0xEE - - States - { - Spawn: - MAGE A -1 - Stop - See: - MAGE ABCD 4 - Loop - Missile: - Melee: - MAGE EF 8 - Goto Spawn - Pain: - MAGE G 4 - MAGE G 4 A_Pain - Goto Spawn - Death: - MAGE H 6 - MAGE I 6 A_PlayerScream - MAGE JK 6 - MAGE L 6 A_NoBlocking - MAGE M 6 - MAGE N -1 - Stop - XDeath: - MAGE O 5 A_PlayerScream - MAGE P 5 - MAGE R 5 A_NoBlocking - MAGE STUVW 5 - MAGE X -1 - Stop - Ice: - MAGE Y 5 A_FreezeDeath - MAGE Y 1 A_FreezeDeathChunks - Wait - Burn: - FDTH E 5 BRIGHT A_PlaySound("*burndeath") - FDTH F 4 BRIGHT - FDTH G 5 BRIGHT - FDTH H 4 BRIGHT A_PlayerScream - FDTH I 5 BRIGHT - FDTH J 4 BRIGHT - FDTH K 5 BRIGHT - FDTH L 4 BRIGHT - FDTH M 5 BRIGHT - FDTH N 4 BRIGHT - FDTH O 5 BRIGHT - FDTH P 4 BRIGHT - FDTH Q 5 BRIGHT - FDTH R 4 BRIGHT - FDTH S 5 BRIGHT A_NoBlocking - FDTH T 4 BRIGHT - FDTH U 5 BRIGHT - FDTH V 4 BRIGHT - ACLO E 35 A_CheckPlayerDone - Wait - ACLO E 8 - Stop - } -} diff --git a/wadsrc/static/actors/hexen/magestaff.txt b/wadsrc/static/actors/hexen/magestaff.txt deleted file mode 100644 index 381588ce50..0000000000 --- a/wadsrc/static/actors/hexen/magestaff.txt +++ /dev/null @@ -1,142 +0,0 @@ - -// Mage Weapon Piece -------------------------------------------------------- - -ACTOR MageWeaponPiece : WeaponPiece -{ - Inventory.PickupSound "misc/w_pkup" - Inventory.PickupMessage "$TXT_BLOODSCOURGE_PIECE" - Inventory.ForbiddenTo FighterPlayer, ClericPlayer - WeaponPiece.Weapon MWeapBloodscourge - +FLOATBOB -} - -// Mage Weapon Piece 1 ------------------------------------------------------ - -ACTOR MWeaponPiece1 : MageWeaponPiece -{ - WeaponPiece.Number 1 - States - { - Spawn: - WMS1 A -1 Bright - Stop - } -} - -// Mage Weapon Piece 2 ------------------------------------------------------ - -ACTOR MWeaponPiece2 : MageWeaponPiece -{ - WeaponPiece.Number 2 - States - { - Spawn: - WMS2 A -1 Bright - Stop - } -} - -// Mage Weapon Piece 3 ------------------------------------------------------ - -ACTOR MWeaponPiece3 : MageWeaponPiece -{ - WeaponPiece.Number 3 - States - { - Spawn: - WMS3 A -1 Bright - Stop - } -} - -// Bloodscourge Drop -------------------------------------------------------- - -ACTOR BloodscourgeDrop -{ - States - { - Spawn: - TNT1 A 1 - TNT1 A 1 A_DropWeaponPieces("MWeaponPiece1", "MWeaponPiece2", "MWeaponPiece3") - Stop - } -} - -// The Mages's Staff (Bloodscourge) ----------------------------------------- - -ACTOR MWeapBloodscourge : MageWeapon native -{ - Health 3 - Weapon.SelectionOrder 3100 - Weapon.AmmoUse1 15 - Weapon.AmmoUse2 15 - Weapon.AmmoGive1 20 - Weapon.AmmoGive2 20 - Weapon.KickBack 150 - Weapon.YAdjust 20 - Weapon.AmmoType1 "Mana1" - Weapon.AmmoType2 "Mana2" - +WEAPON.PRIMARY_USES_BOTH - +Inventory.NoAttenPickupSound - Inventory.PickupMessage "$TXT_WEAPON_M4" - Inventory.PickupSound "WeaponBuild" - Tag "$TAG_MWEAPBLOODSCOURGE" - - action native A_MStaffAttack(); - action native A_MStaffPalette(); - - States - { - Spawn: - TNT1 A -1 - Stop - Select: - MSTF A 1 A_Raise - Loop - Deselect: - MSTF A 1 A_Lower - Loop - Ready: - MSTF AAAAAABBBBBBCCCCCCDDDDDDEEEEEEFFFFF 1 A_WeaponReady - Loop - Fire: - MSTF G 4 Offset (0, 40) - MSTF H 4 Bright Offset (0, 48) A_MStaffAttack - MSTF H 2 Bright Offset (0, 48) A_MStaffPalette - MSTF II 2 Offset (0, 48) A_MStaffPalette - MSTF I 1 Offset (0, 40) - MSTF J 5 Offset (0, 36) - Goto Ready - } -} - -// Mage Staff FX2 (Bloodscourge) -------------------------------------------- - -ACTOR MageStaffFX2 native -{ - Speed 17 - Height 8 - Damage 4 - DamageType "Fire" - Projectile - +SEEKERMISSILE - +SCREENSEEKER - +EXTREMEDEATH - DeathSound "MageStaffExplode" - Obituary "$OB_MPMWEAPBLOODSCOURGE" - - action native A_MStaffTrack(); - - States - { - Spawn: - MSP2 ABCD 2 Bright A_MStaffTrack - Loop - Death: - MSP2 E 4 Bright A_SetTranslucent(1,1) - MSP2 F 5 Bright A_Explode (80, 192, 0) - MSP2 GH 5 Bright - MSP2 I 4 Bright - Stop - } -} diff --git a/wadsrc/static/actors/hexen/magewand.txt b/wadsrc/static/actors/hexen/magewand.txt deleted file mode 100644 index e9a1f339bc..0000000000 --- a/wadsrc/static/actors/hexen/magewand.txt +++ /dev/null @@ -1,73 +0,0 @@ - -// The Mage's Wand ---------------------------------------------------------- - -ACTOR MWeapWand : MageWeapon -{ - Weapon.SelectionOrder 3600 - Weapon.KickBack 0 - Weapon.YAdjust 9 - Tag "$TAG_MWEAPWAND" - - States - { - Select: - MWND A 1 A_Raise - Loop - Deselect: - MWND A 1 A_Lower - Loop - Ready: - MWND A 1 A_WeaponReady - Loop - Fire: - MWND A 6 - MWND B 6 Bright Offset (0, 48) A_FireCustomMissile ("MageWandMissile") - MWND A 3 Offset (0, 40) - MWND A 3 Offset (0, 36) A_ReFire - Goto Ready - } -} - -// Wand Smoke --------------------------------------------------------------- - -ACTOR MageWandSmoke -{ - +NOBLOCKMAP +NOGRAVITY +SHADOW - +NOTELEPORT +CANNOTPUSH +NODAMAGETHRUST - RenderStyle Translucent - Alpha 0.6 - States - { - Spawn: - MWND CDCD 4 - Stop - } -} - -// Wand Missile ------------------------------------------------------------- - -ACTOR MageWandMissile : FastProjectile -{ - Speed 184 - Radius 12 - Height 8 - Damage 2 - +RIPPER +CANNOTPUSH +NODAMAGETHRUST - +SPAWNSOUNDSOURCE - MissileType "MageWandSmoke" - SeeSound "MageWandFire" - Obituary "$OB_MPMWEAPWAND" - States - { - Spawn: - MWND CD 4 Bright - Loop - Death: - MWND E 4 Bright - MWND F 3 Bright - MWND G 4 Bright - MWND H 3 Bright - MWND I 4 Bright - Stop - } -} diff --git a/wadsrc/static/actors/hexen/mana.txt b/wadsrc/static/actors/hexen/mana.txt deleted file mode 100644 index 4a50e368a1..0000000000 --- a/wadsrc/static/actors/hexen/mana.txt +++ /dev/null @@ -1,87 +0,0 @@ -// Blue mana ---------------------------------------------------------------- - -ACTOR Mana1 : Ammo -{ - Inventory.Amount 15 - Inventory.MaxAmount 200 - Ammo.BackpackAmount 15 - Ammo.BackpackMaxAmount 200 - Radius 8 - Height 8 - +FLOATBOB - Inventory.Icon "MAN1I0" - Inventory.PickupMessage "$TXT_MANA_1" - States - { - Spawn: - MAN1 ABCDEFGHI 4 Bright - Loop - } -} - -// Green mana --------------------------------------------------------------- - -ACTOR Mana2 : Ammo -{ - Inventory.Amount 15 - Inventory.MaxAmount 200 - Ammo.BackpackAmount 15 - Ammo.BackpackMaxAmount 200 - Radius 8 - Height 8 - +FLOATBOB - Inventory.Icon "MAN2G0" - Inventory.PickupMessage "$TXT_MANA_2" - States - { - Spawn: - MAN2 ABCDEFGHIJKLMNOP 4 Bright - Loop - } -} - -// Combined mana ------------------------------------------------------------ - -ACTOR Mana3 : CustomInventory -{ - Radius 8 - Height 8 - +FLOATBOB - Inventory.PickupMessage "$TXT_MANA_BOTH" - States - { - Spawn: - MAN3 ABCDEFGHIJKLMNOP 4 Bright - Loop - Pickup: - TNT1 A 0 A_GiveInventory("Mana1", 20) - TNT1 A 0 A_GiveInventory("Mana2", 20) - Stop - } -} - -// Boost Mana Artifact Krater of Might ------------------------------------ - -ACTOR ArtiBoostMana : CustomInventory -{ - +FLOATBOB - +COUNTITEM - +INVENTORY.INVBAR - +INVENTORY.PICKUPFLASH - +INVENTORY.FANCYPICKUPSOUND - Inventory.DefMaxAmount - Inventory.Icon "ARTIBMAN" - Inventory.PickupSound "misc/p_pkup" - Inventory.PickupMessage "$TXT_ARTIBOOSTMANA" - Tag "$TAG_ARTIBOOSTMANA" - States - { - Spawn: - BMAN A -1 - Stop - Use: - TNT1 A 0 A_GiveInventory("Mana1", 200) - TNT1 A 0 A_GiveInventory("Mana2", 200) - Stop - } -} diff --git a/wadsrc/static/actors/hexen/pig.txt b/wadsrc/static/actors/hexen/pig.txt deleted file mode 100644 index 9d986e7eb1..0000000000 --- a/wadsrc/static/actors/hexen/pig.txt +++ /dev/null @@ -1,155 +0,0 @@ - - -// Snout puff --------------------------------------------------------------- - -ACTOR SnoutPuff -{ - +NOBLOCKMAP - +NOGRAVITY - Renderstyle Translucent - Alpha 0.6 - States - { - Spawn: - FHFX STUVW 4 - Stop - } -} - - -// Snout -------------------------------------------------------------------- - -ACTOR Snout : Weapon -{ - Weapon.SelectionOrder 10000 - +WEAPON.DONTBOB - +WEAPON.MELEEWEAPON - Weapon.Kickback 150 - Weapon.YAdjust 10 - - action native A_SnoutAttack (); - - States - { - Ready: - WPIG A 1 A_WeaponReady - Loop - Deselect: - WPIG A 1 A_Lower - Loop - Select: - WPIG A 1 A_Raise - Fire: - WPIG A 4 A_SnoutAttack - WPIG B 8 A_SnoutAttack - Goto Ready - Grunt: - WPIG B 8 - Goto Ready - } -} - - -// Pig player --------------------------------------------------------------- - -ACTOR PigPlayer : PlayerPawn native -{ - Health 30 - ReactionTime 0 - PainChance 255 - Radius 16 - Height 24 - Speed 1 - +WINDTHRUST - +NOSKIN - -PICKUP - PainSound "PigPain" - DeathSound "PigDeath" - Player.JumpZ 6 - Player.Viewheight 28 - Player.ForwardMove 0.96, 0.98 - Player.SideMove 0.95833333, 0.975 - Player.SpawnClass "Pig" - Player.SoundClass "Pig" - Player.DisplayName "Pig" - Player.MorphWeapon "Snout" - States - { - Spawn: - PIGY A -1 - Stop - See: - PIGY ABCD 3 - Loop - Pain: - PIGY D 4 A_PigPain - Goto Spawn - Melee: - Missile: - PIGY A 12 - Goto Spawn - Death: - PIGY E 4 A_Scream - PIGY F 3 A_NoBlocking - PIGY G 4 - PIGY H 3 - PIGY IJK 4 - PIGY L -1 - Stop - Ice: - PIGY M 5 A_FreezeDeath - PIGY M 1 A_FreezeDeathChunks - Wait - } -} - - - -// Pig (non-player) --------------------------------------------------------- - -ACTOR Pig : MorphedMonster -{ - Health 25 - Painchance 128 - Speed 10 - Radius 12 - Height 22 - Mass 60 - Monster - -COUNTKILL - +WINDTHRUST - +DONTMORPH - SeeSound "PigActive1" - PainSound "PigPain" - DeathSound "PigDeath" - ActiveSound "PigActive1" - States - { - Spawn: - PIGY B 10 A_Look - Loop - See: - PIGY ABCD 3 A_Chase - Loop - Pain: - PIGY D 4 A_PigPain - Goto See - Melee: - PIGY A 5 A_FaceTarget - PIGY A 10 A_CustomMeleeAttack(random[PigAttack](2,3), "PigAttack") - Goto See - Death: - PIGY E 4 A_Scream - PIGY F 3 A_NoBlocking - PIGY G 4 A_QueueCorpse - PIGY H 3 - PIGY IJK 4 - PIGY L -1 - Stop - Ice: - PIGY M 5 A_FreezeDeath - PIGY M 1 A_FreezeDeathChunks - Wait - } -} - diff --git a/wadsrc/static/actors/hexen/puzzleitems.txt b/wadsrc/static/actors/hexen/puzzleitems.txt deleted file mode 100644 index ad1187da01..0000000000 --- a/wadsrc/static/actors/hexen/puzzleitems.txt +++ /dev/null @@ -1,287 +0,0 @@ - -// Yorick's Skull ----------------------------------------------------------- - -ACTOR PuzzSkull : PuzzleItem -{ - PuzzleItem.Number 0 - Inventory.Icon ARTISKLL - Inventory.PickupMessage "$TXT_ARTIPUZZSKULL" - Tag "$TAG_ARTIPUZZSKULL" - States - { - Spawn: - ASKU A -1 - Stop - } -} - - -// Heart of D'Sparil -------------------------------------------------------- - -ACTOR PuzzGemBig : PuzzleItem -{ - PuzzleItem.Number 1 - Inventory.Icon ARTIBGEM - Inventory.PickupMessage "$TXT_ARTIPUZZGEMBIG" - Tag "$TAG_ARTIPUZZGEMBIG" - States - { - Spawn: - ABGM A -1 - Stop - } -} - -// Red Gem (Ruby Planet) ---------------------------------------------------- - -ACTOR PuzzGemRed : PuzzleItem -{ - PuzzleItem.Number 2 - Inventory.Icon ARTIGEMR - Inventory.PickupMessage "$TXT_ARTIPUZZGEMRED" - Tag "$TAG_ARTIPUZZGEMRED" - States - { - Spawn: - AGMR A -1 - Stop - } -} - - -// Green Gem 1 (Emerald Planet) --------------------------------------------- - -ACTOR PuzzGemGreen1 : PuzzleItem -{ - PuzzleItem.Number 3 - Inventory.Icon ARTIGEMG - Inventory.PickupMessage "$TXT_ARTIPUZZGEMGREEN1" - Tag "$TAG_ARTIPUZZGEMGREEN1" - States - { - Spawn: - AGMG A -1 - Stop - } -} - - -// Green Gem 2 (Emerald Planet) --------------------------------------------- - -ACTOR PuzzGemGreen2 : PuzzleItem -{ - PuzzleItem.Number 4 - Inventory.Icon ARTIGMG2 - Inventory.PickupMessage "$TXT_ARTIPUZZGEMGREEN2" - Tag "$TAG_ARTIPUZZGEMGREEN2" - States - { - Spawn: - AGG2 A -1 - Stop - } -} - - -// Blue Gem 1 (Sapphire Planet) --------------------------------------------- - -ACTOR PuzzGemBlue1 : PuzzleItem -{ - PuzzleItem.Number 5 - Inventory.Icon ARTIGEMB - Inventory.PickupMessage "$TXT_ARTIPUZZGEMBLUE1" - Tag "$TAG_ARTIPUZZGEMBLUE1" - States - { - Spawn: - AGMB A -1 - Stop - } -} - - -// Blue Gem 2 (Sapphire Planet) --------------------------------------------- - -ACTOR PuzzGemBlue2 : PuzzleItem -{ - PuzzleItem.Number 6 - Inventory.Icon ARTIGMB2 - Inventory.PickupMessage "$TXT_ARTIPUZZGEMBLUE2" - Tag "$TAG_ARTIPUZZGEMBLUE2" - States - { - Spawn: - AGB2 A -1 - Stop - } -} - - -// Book 1 (Daemon Codex) ---------------------------------------------------- - -ACTOR PuzzBook1 : PuzzleItem -{ - PuzzleItem.Number 7 - Inventory.Icon ARTIBOK1 - Inventory.PickupMessage "$TXT_ARTIPUZZBOOK1" - Tag "$TAG_ARTIPUZZBOOK1" - States - { - Spawn: - ABK1 A -1 - Stop - } -} - - -// Book 2 (Liber Oscura) ---------------------------------------------------- - -ACTOR PuzzBook2 : PuzzleItem -{ - PuzzleItem.Number 8 - Inventory.Icon ARTIBOK2 - Inventory.PickupMessage "$TXT_ARTIPUZZBOOK2" - Tag "$TAG_ARTIPUZZBOOK2" - States - { - Spawn: - ABK2 A -1 - Stop - } -} - - -// Flame Mask --------------------------------------------------------------- - - -ACTOR PuzzFlameMask : PuzzleItem -{ - PuzzleItem.Number 9 - Inventory.Icon ARTISKL2 - Inventory.PickupMessage "$TXT_ARTIPUZZSKULL2" - Tag "$TAG_ARTIPUZZSKULL2" - States - { - Spawn: - ASK2 A -1 - Stop - } -} - -// Fighter Weapon (Glaive Seal) --------------------------------------------- - -ACTOR PuzzFWeapon : PuzzleItem -{ - PuzzleItem.Number 10 - Inventory.Icon ARTIFWEP - Inventory.PickupMessage "$TXT_ARTIPUZZFWEAPON" - Tag "$TAG_ARTIPUZZFWEAPON" - States - { - Spawn: - AFWP A -1 - Stop - } -} - - -// Cleric Weapon (Holy Relic) ----------------------------------------------- - -ACTOR PuzzCWeapon : PuzzleItem -{ - PuzzleItem.Number 11 - Inventory.Icon ARTICWEP - Inventory.PickupMessage "$TXT_ARTIPUZZCWEAPON" - Tag "$TAG_ARTIPUZZCWEAPON" - States - { - Spawn: - ACWP A -1 - Stop - } -} - - -// Mage Weapon (Sigil of the Magus) ----------------------------------------- - -ACTOR PuzzMWeapon : PuzzleItem -{ - PuzzleItem.Number 12 - Inventory.Icon ARTIMWEP - Inventory.PickupMessage "$TXT_ARTIPUZZMWEAPON" - Tag "$TAG_ARTIPUZZMWEAPON" - States - { - Spawn: - AMWP A -1 - Stop - } -} - -// Clock Gear 1 ------------------------------------------------------------- - -ACTOR PuzzGear1 : PuzzleItem -{ - PuzzleItem.Number 13 - Inventory.Icon ARTIGEAR - Inventory.PickupMessage "$TXT_ARTIPUZZGEAR" - Tag "$TAG_ARTIPUZZGEAR1" - States - { - Spawn: - AGER ABCDEFGH 4 Bright - Loop - } -} - - -// Clock Gear 2 ------------------------------------------------------------- - -ACTOR PuzzGear2 : PuzzleItem -{ - PuzzleItem.Number 14 - Inventory.Icon ARTIGER2 - Inventory.PickupMessage "$TXT_ARTIPUZZGEAR" - Tag "$TAG_ARTIPUZZGEAR2" - States - { - Spawn: - AGR2 ABCDEFGH 4 Bright - Loop - } -} - - -// Clock Gear 3 ------------------------------------------------------------- - -ACTOR PuzzGear3 : PuzzleItem -{ - PuzzleItem.Number 15 - Inventory.Icon ARTIGER3 - Inventory.PickupMessage "$TXT_ARTIPUZZGEAR" - Tag "$TAG_ARTIPUZZGEAR3" - States - { - Spawn: - AGR3 ABCDEFGH 4 Bright - Loop - } -} - - -// Clock Gear 4 ------------------------------------------------------------- - -ACTOR PuzzGear4 : PuzzleItem -{ - PuzzleItem.Number 16 - Inventory.Icon ARTIGER4 - Inventory.PickupMessage "$TXT_ARTIPUZZGEAR" - Tag "$TAG_ARTIPUZZGEAR4" - States - { - Spawn: - AGR4 ABCDEFGH 4 Bright - Loop - } -} - diff --git a/wadsrc/static/actors/hexen/scriptprojectiles.txt b/wadsrc/static/actors/hexen/scriptprojectiles.txt deleted file mode 100644 index d031be3ee6..0000000000 --- a/wadsrc/static/actors/hexen/scriptprojectiles.txt +++ /dev/null @@ -1,123 +0,0 @@ -// Fire Ball ---------------------------------------------------------------- - -ACTOR FireBall -{ - Speed 2 - Radius 8 - Height 8 - Damage 4 - DamageType Fire - +NOBLOCKMAP +NOGRAVITY +DROPOFF +MISSILE - +NOTELEPORT - RenderStyle Add - DeathSound "Fireball" - States - { - Spawn: - FBL1 AB 4 Bright - Loop - Death: - XPL1 ABCDEF 4 Bright - Stop - } -} - -// Arrow -------------------------------------------------------------------- - -ACTOR Arrow -{ - Speed 6 - Radius 8 - Height 4 - Damage 4 - +NOBLOCKMAP +NOGRAVITY +DROPOFF +MISSILE - +NOTELEPORT - States - { - Spawn: - ARRW A -1 - Stop - Death: - ARRW A 1 - Stop - } -} - -// Dart --------------------------------------------------------------------- - -ACTOR Dart -{ - Speed 6 - Radius 8 - Height 4 - Damage 2 - +NOBLOCKMAP +NOGRAVITY +DROPOFF +MISSILE - +NOTELEPORT - States - { - Spawn: - DART A -1 - Stop - Death: - DART A 1 - Stop - } -} - -// Poison Dart -------------------------------------------------------------- - -ACTOR PoisonDart : Dart -{ - PoisonDamage 20 -} - -// Ripper Ball -------------------------------------------------------------- - -ACTOR RipperBall -{ - Speed 6 - Radius 8 - Damage 2 - +NOBLOCKMAP +NOGRAVITY +DROPOFF +MISSILE - +NOTELEPORT +RIPPER - States - { - Spawn: - RIPP ABC 3 - Loop - Death: - CFCF Q 4 Bright - CFCF R 3 Bright - CFCF S 4 Bright - CFCF T 3 Bright - CFCF U 4 Bright - CFCF V 3 Bright - CFCF W 4 Bright - CFCF X 3 Bright - CFCF Y 4 Bright - CFCF Z 3 Bright - Stop - } -} - -// Projectile Blade --------------------------------------------------------- - -ACTOR ProjectileBlade -{ - Speed 6 - Radius 6 - Height 6 - Damage 3 - +NOBLOCKMAP +NOGRAVITY +DROPOFF +MISSILE - +NOTELEPORT - States - { - Spawn: - BLAD A -1 - Stop - Death: - BLAD A 1 - Stop - } -} - diff --git a/wadsrc/static/actors/hexen/serpent.txt b/wadsrc/static/actors/hexen/serpent.txt deleted file mode 100644 index 50d81bf8ac..0000000000 --- a/wadsrc/static/actors/hexen/serpent.txt +++ /dev/null @@ -1,224 +0,0 @@ - -// Serpent ------------------------------------------------------------------ - -ACTOR Serpent -{ - Health 90 - PainChance 96 - Speed 12 - Radius 32 - Height 70 - Mass 0x7fffffff - Monster - -SHOOTABLE - +NOBLOOD - +CANTLEAVEFLOORPIC +NONSHOOTABLE - +STAYMORPHED +DONTBLAST +NOTELEOTHER - +INVISIBLE - SeeSound "SerpentSight" - AttackSound "SerpentAttack" - PainSound "SerpentPain" - DeathSound "SerpentDeath" - HitObituary "$OB_SERPENTHIT" - - action native A_SerpentHumpDecide(); - action native A_SerpentHide(); - action native A_SerpentCheckForAttack(); - action native A_SerpentSpawnGibs(); - action native A_SerpentUnHide(); - action native A_SerpentRaiseHump(); - action native A_SerpentLowerHump(); - action native A_SerpentChooseAttack(); - action native A_SerpentMeleeAttack(); - - States - { - Spawn: - SSPT H 10 A_Look - Loop - See: - SSPT HH 1 A_Chase("Melee", "None", CHF_NIGHTMAREFAST|CHF_NOPLAYACTIVE) - SSPT H 2 A_SerpentHumpDecide - Loop - Pain: - SSPT L 5 - SSPT L 5 A_Pain - Dive: - SSDV ABC 4 - SSDV D 4 A_UnSetShootable - SSDV E 3 A_PlaySoundEx("SerpentActive", "Body") - SSDV F 3 - SSDV GH 4 - SSDV I 3 - SSDV J 3 A_SerpentHide - Goto See - Melee: - SSPT A 1 A_UnHideThing - SSPT A 1 A_PlaySoundEx("SerpentBirth", "Voice") - SSPT B 3 A_SetShootable - SSPT C 3 - SSPT D 4 A_SerpentCheckForAttack - Goto Dive - Death: - SSPT O 4 - SSPT P 4 A_Scream - SSPT Q 4 A_NoBlocking - SSPT RSTUVWXYZ 4 - Stop - XDeath: - SSXD A 4 - SSXD B 4 A_SpawnItemEx("SerpentHead", 0, 0, 45) - SSXD C 4 A_NoBlocking - SSXD DE 4 - SSXD FG 3 - SSXD H 3 A_SerpentSpawnGibs - Stop - Ice: - SSPT [ 5 A_FreezeDeath - SSPT [ 1 A_FreezeDeathChunks - Wait - Walk: - SSPT IJI 5 A_Chase("Attack", "None", CHF_NIGHTMAREFAST) - SSPT J 5 A_SerpentCheckForAttack - Goto Dive - Hump: - SSPT H 3 A_SerpentUnHide - SSPT EFGEF 3 A_SerpentRaiseHump - SSPT GEF 3 - SSPT GEFGE 3 A_SerpentLowerHump - SSPT F 3 A_SerpentHide - Goto See - Attack: - SSPT K 6 A_FaceTarget - SSPT L 5 A_SerpentChooseAttack - Goto MeleeAttack - MeleeAttack: - SSPT N 5 A_SerpentMeleeAttack - Goto Dive - } -} - -// Serpent Leader ----------------------------------------------------------- - -ACTOR SerpentLeader : Serpent -{ - Mass 200 - Obituary "$OB_SERPENT" - States - { - Missile: - SSPT N 5 A_CustomMissile("SerpentFX", 32, 0) - Goto Dive - } -} - -// Serpent Missile Ball ----------------------------------------------------- - -ACTOR SerpentFX -{ - Speed 15 - Radius 8 - Height 10 - Damage 4 - Projectile - -ACTIVATEIMPACT -ACTIVATEPCROSS - RenderStyle Add - DeathSound "SerpentFXHit" - - States - { - Spawn: - SSFX A 0 - SSFX A 3 Bright A_PlaySoundEx("SerpentFXContinuous", "Body", 1) - SSFX BAB 3 Bright - Goto Spawn+1 - Death: - SSFX C 4 Bright A_StopSoundEx("Body") - SSFX DEFGH 4 Bright - Stop - } -} - -// Serpent Head ------------------------------------------------------------- - -ACTOR SerpentHead -{ - Radius 5 - Height 10 - Gravity 0.125 - +NOBLOCKMAP - - action native A_SerpentHeadCheck(); - - States - { - Spawn: - SSXD IJKLMNOP 4 A_SerpentHeadCheck - Loop - Death: - SSXD S -1 - Loop - } -} - -// Serpent Gib 1 ------------------------------------------------------------ - -ACTOR SerpentGib1 -{ - Radius 3 - Height 3 - +NOBLOCKMAP +NOGRAVITY - - action native A_FloatGib(); - action native A_DelayGib(); - action native A_SinkGib(); - - States - { - Spawn: - SSXD Q 6 - SSXD Q 6 A_FloatGib - SSXD QQ 8 A_FloatGib - SSXD QQ 12 A_FloatGib - SSXD Q 232 A_DelayGib - SSXD QQ 12 A_SinkGib - SSXD QQQ 8 A_SinkGib - Stop - } -} - -// Serpent Gib 2 ------------------------------------------------------------ - -ACTOR SerpentGib2 : SerpentGib1 -{ - States - { - Spawn: - SSXD R 6 - SSXD R 6 A_FloatGib - SSXD RR 8 A_FloatGib - SSXD RR 12 A_FloatGib - SSXD R 232 A_DelayGib - SSXD RR 12 A_SinkGib - SSXD RRR 8 A_SinkGib - Stop - } -} - -// Serpent Gib 3 ------------------------------------------------------------ - -ACTOR SerpentGib3 : SerpentGib1 -{ - States - { - Spawn: - SSXD T 6 - SSXD T 6 A_FloatGib - SSXD TT 8 A_FloatGib - SSXD TT 12 A_FloatGib - SSXD T 232 A_DelayGib - SSXD TT 12 A_SinkGib - SSXD TTT 8 A_SinkGib - Stop - } -} diff --git a/wadsrc/static/actors/hexen/speedboots.txt b/wadsrc/static/actors/hexen/speedboots.txt deleted file mode 100644 index 2ae4dcd019..0000000000 --- a/wadsrc/static/actors/hexen/speedboots.txt +++ /dev/null @@ -1,18 +0,0 @@ - - -ACTOR ArtiSpeedBoots : PowerupGiver -{ - +FLOATBOB - +COUNTITEM - +INVENTORY.PICKUPFLASH - Inventory.Icon ARTISPED - Inventory.PickupMessage "$TXT_ARTISPEED" - Tag "$TAG_ARTISPEED" - Powerup.Type Speed - States - { - Spawn: - SPED ABCDEFGH 3 Bright - Loop - } -} diff --git a/wadsrc/static/actors/hexen/spike.txt b/wadsrc/static/actors/hexen/spike.txt deleted file mode 100644 index eaadfe012d..0000000000 --- a/wadsrc/static/actors/hexen/spike.txt +++ /dev/null @@ -1,104 +0,0 @@ - -// Dirt clump (spawned by spike) -------------------------------------------- - -ACTOR DirtClump -{ - +NOBLOCKMAP - +NOTELEPORT - States - { - Spawn: - TSPK C 20 - Loop - } -} - -// Spike (thrust floor) ----------------------------------------------------- - -ACTOR ThrustFloor native -{ - Radius 20 - Height 128 - - action native A_ThrustRaise(); - action native A_ThrustImpale(); - action native A_ThrustLower(); - action native A_ThrustInitDn(); - action native A_ThrustInitUp(); - - States - { - ThrustRaising: - TSPK A 2 A_ThrustRaise - Loop - BloodThrustRaising: - TSPK B 2 A_ThrustRaise - Loop - ThrustLower: - TSPK A 2 A_ThrustLower - Loop - BloodThrustLower: - TSPK B 2 A_ThrustLower - Loop - ThrustInit1: - TSPK A 3 - TSPK A 4 A_ThrustInitDn - TSPK A -1 - Loop - BloodThrustInit1: - TSPK B 3 - TSPK B 4 A_ThrustInitDn - TSPK B -1 - Loop - ThrustInit2: - TSPK A 3 - TSPK A 4 A_ThrustInitUp - TSPK A 10 - Loop - BloodThrustInit2: - TSPK B 3 - TSPK B 4 A_ThrustInitUp - TSPK B 10 - Loop - ThrustRaise: - TSPK A 8 A_ThrustRaise - TSPK A 6 A_ThrustRaise - TSPK A 4 A_ThrustRaise - TSPK A 3 A_SetSolid - TSPK A 2 A_ThrustImpale - Loop - BloodThrustRaise: - TSPK B 8 A_ThrustRaise - TSPK B 6 A_ThrustRaise - TSPK B 4 A_ThrustRaise - TSPK B 3 A_SetSolid - TSPK B 2 A_ThrustImpale - Loop - } -} - -// Spike up ----------------------------------------------------------------- - -ACTOR ThrustFloorUp : ThrustFloor -{ - +SOLID - +NOTELEPORT +FLOORCLIP - States - { - Spawn: - Goto ThrustInit2 - } -} - -// Spike down --------------------------------------------------------------- - -ACTOR ThrustFloorDown : ThrustFloor -{ - +NOTELEPORT +FLOORCLIP - +INVISIBLE - States - { - Spawn: - Goto ThrustInit1 - } -} diff --git a/wadsrc/static/actors/hexen/summon.txt b/wadsrc/static/actors/hexen/summon.txt deleted file mode 100644 index 7a2971562c..0000000000 --- a/wadsrc/static/actors/hexen/summon.txt +++ /dev/null @@ -1,61 +0,0 @@ - -// Dark Servant Artifact ---------------------------------------------------- - -ACTOR ArtiDarkServant : Inventory native -{ - +COUNTITEM - +FLOATBOB - Inventory.RespawnTics 4230 - Inventory.DefMaxAmount - Inventory.PickupFlash "PickupFlash" - +INVBAR +FANCYPICKUPSOUND - Inventory.Icon "ARTISUMN" - Inventory.PickupSound "misc/p_pkup" - Inventory.PickupMessage "$TXT_ARTISUMMON" - Tag "$TAG_ARTISUMMON" - States - { - Spawn: - SUMN A 350 - Loop - } -} - -// Summoning Doll ----------------------------------------------------------- - -ACTOR SummoningDoll -{ - Speed 20 - +NOBLOCKMAP +DROPOFF +MISSILE - +NOTELEPORT - - action native A_Summon(); - - States - { - Spawn: - SUMN A 4 - Loop - Death: - SUMN AA 4 - SUMN A 4 A_Summon - Stop - } -} - -// Minotaur Smoke ----------------------------------------------------------- - -ACTOR MinotaurSmoke -{ - +NOBLOCKMAP +NOGRAVITY - +NOTELEPORT - RenderStyle Translucent - Alpha 0.6 - - States - { - Spawn: - MNSM ABCDEFGHIJKLMNOPQ 3 - Stop - } -} diff --git a/wadsrc/static/actors/hexen/teleportother.txt b/wadsrc/static/actors/hexen/teleportother.txt deleted file mode 100644 index 7ef86636d7..0000000000 --- a/wadsrc/static/actors/hexen/teleportother.txt +++ /dev/null @@ -1,112 +0,0 @@ - -// Teleport Other Artifact -------------------------------------------------- - -ACTOR ArtiTeleportOther : Inventory native -{ - +COUNTITEM - +FLOATBOB - +INVENTORY.INVBAR - +INVENTORY.PICKUPFLASH - +INVENTORY.FANCYPICKUPSOUND - Inventory.DefMaxAmount - Inventory.Icon "ARTITELO" - Inventory.PickupSound "misc/p_pkup" - Inventory.PickupMessage "$TXT_ARTITELEPORTOTHER" - Tag "$TAG_ARTITELEPORTOTHER" - States - { - Spawn: - TELO ABCD 5 - Loop - } -} - - -// Teleport Other FX -------------------------------------------------------- - -ACTOR TelOtherFX1 native -{ - Damage 10001 - Projectile - -ACTIVATEIMPACT - -ACTIVATEPCROSS - +BLOODLESSIMPACT - Radius 16 - Height 16 - Speed 20 - - action native A_TeloSpawnA (); - action native A_TeloSpawnB (); - action native A_TeloSpawnC (); - action native A_TeloSpawnD (); - action native A_CheckTeleRing (); - - States - { - Spawn: - TRNG E 5 Bright - TRNG D 4 Bright - TRNG C 3 Bright A_TeloSpawnC - TRNG B 3 Bright A_TeloSpawnB - TRNG A 3 Bright A_TeloSpawnA - TRNG B 3 Bright A_TeloSpawnB - TRNG C 3 Bright A_TeloSpawnC - TRNG D 3 Bright A_TeloSpawnD - Goto Spawn+2 - Death: - TRNG E 3 Bright - Stop - } -} - - -ACTOR TelOtherFX2 : TelOtherFX1 -{ - Speed 16 - States - { - Spawn: - TRNG BCDCB 4 Bright - TRNG A 4 Bright A_CheckTeleRing - Loop - } -} - -ACTOR TelOtherFX3 : TelOtherFX1 -{ - Speed 16 - States - { - Spawn: - TRNG CDCBA 4 Bright - TRNG B 4 Bright A_CheckTeleRing - Loop - } -} - -ACTOR TelOtherFX4 : TelOtherFX1 -{ - Speed 16 - States - { - Spawn: - TRNG DCBAB 4 Bright - TRNG C 4 Bright A_CheckTeleRing - Loop - } - -} - -ACTOR TelOtherFX5 : TelOtherFX1 -{ - Speed 16 - States - { - Spawn: - TRNG CBABC 4 Bright - TRNG D 4 Bright A_CheckTeleRing - Loop - } -} - - diff --git a/wadsrc/static/actors/hexen/wraith.txt b/wadsrc/static/actors/hexen/wraith.txt deleted file mode 100644 index 8d25bc74a8..0000000000 --- a/wadsrc/static/actors/hexen/wraith.txt +++ /dev/null @@ -1,218 +0,0 @@ - -// Wraith ------------------------------------------------------------------- - -ACTOR Wraith -{ - Health 150 - PainChance 25 - Speed 11 - Height 55 - Mass 75 - Damage 10 - Monster - +NOGRAVITY +DROPOFF +FLOAT - +FLOORCLIP +TELESTOMP - SeeSound "WraithSight" - AttackSound "WraithAttack" - PainSound "WraithPain" - DeathSound "WraithDeath" - ActiveSound "WraithActive" - HitObituary "$OB_WRAITHHIT" - Obituary "$OB_WRAITH" - - action native A_WraithInit(); - action native A_WraithChase(); - action native A_WraithFX3(); - action native A_WraithMelee(); - - States - { - Spawn: - WRTH A 10 - WRTH B 5 A_WraithInit - Goto Look - Look: - WRTH AB 15 A_Look - Loop - See: - WRTH ABCD 4 A_WraithChase - Loop - Pain: - WRTH A 2 - WRTH H 6 A_Pain - Goto See - Melee: - WRTH E 6 A_FaceTarget - WRTH F 6 A_WraithFX3 - WRTH G 6 A_WraithMelee - Goto See - Missile: - WRTH E 6 A_FaceTarget - WRTH F 6 - WRTH G 6 A_CustomMissile("WraithFX1", 32, 0) - Goto See - Death: - WRTH I 4 - WRTH J 4 A_Scream - WRTH KL 4 - WRTH M 4 A_NoBlocking - WRTH N 4 A_QueueCorpse - WRTH O 4 - WRTH PQ 5 - WRTH R -1 - Stop - XDeath: - WRT2 A 5 - WRT2 B 5 A_Scream - WRT2 CD 5 - WRT2 E 5 A_NoBlocking - WRT2 F 5 A_QueueCorpse - WRT2 G 5 - WRT2 H -1 - Stop - Ice: - WRT2 I 5 A_FreezeDeath - WRT2 I 1 A_FreezeDeathChunks - Wait - } -} - -// Buried wraith ------------------------------------------------------------ - -ACTOR WraithBuried : Wraith -{ - Height 68 - -SHOOTABLE - -SOLID - +DONTMORPH - +DONTBLAST - +SPECIALFLOORCLIP - +STAYMORPHED - +INVISIBLE - PainChance 0 - - action native A_WraithRaiseInit(); - action native A_WraithRaise(); - - States - { - Spawn: - Goto Super::Look - See: - WRTH A 2 A_WraithRaiseInit - WRTH A 2 A_WraithRaise - WRTH A 2 A_FaceTarget - WRTH BB 2 A_WraithRaise - Goto See + 1 - Chase: - Goto Super::See - } -} - -// Wraith FX 1 -------------------------------------------------------------- - -ACTOR WraithFX1 -{ - Speed 14 - Radius 10 - Height 6 - Mass 5 - Damage 5 - DamageType "Fire" - Projectile - +FLOORCLIP - SeeSound "WraithMissileFire" - DeathSound "WraithMissileExplode" - - action native A_WraithFX2(); - - States - { - Spawn: - WRBL A 3 Bright - WRBL B 3 Bright A_WraithFX2 - WRBL C 3 Bright - Loop - Death: - WRBL D 4 Bright - WRBL E 4 Bright A_WraithFX2 - WRBL F 4 Bright - WRBL GH 3 Bright A_WraithFX2 - WRBL I 3 Bright - Stop - } -} - -// Wraith FX 2 -------------------------------------------------------------- - -ACTOR WraithFX2 -{ - Radius 2 - Height 5 - Mass 5 - +NOBLOCKMAP +DROPOFF - +FLOORCLIP +NOTELEPORT - States - { - Spawn: - WRBL JKLMNOP 4 Bright - Stop - } -} - -// Wraith FX 3 -------------------------------------------------------------- - -ACTOR WraithFX3 -{ - Radius 2 - Height 5 - Mass 5 - +NOBLOCKMAP +DROPOFF +MISSILE - +FLOORCLIP +NOTELEPORT - DeathSound "Drip" - States - { - Spawn: - WRBL QRS 4 Bright - Loop - Death: - WRBL S 4 Bright - Stop - } -} - -// Wraith FX 4 -------------------------------------------------------------- - -ACTOR WraithFX4 -{ - Radius 2 - Height 5 - Mass 5 - +NOBLOCKMAP +DROPOFF +MISSILE - +NOTELEPORT - DeathSound "Drip" - States - { - Spawn: - WRBL TUVW 4 - Loop - Death: - WRBL W 10 - Stop - } -} - -// Wraith FX 5 -------------------------------------------------------------- - -ACTOR WraithFX5 : WraithFX4 -{ - States - { - Spawn: - WRBL XYZ 7 - Loop - Death: - WRBL Z 35 - Stop - } -} diff --git a/wadsrc/static/actors/raven/artiegg.txt b/wadsrc/static/actors/raven/artiegg.txt deleted file mode 100644 index 1c4a8f190b..0000000000 --- a/wadsrc/static/actors/raven/artiegg.txt +++ /dev/null @@ -1,102 +0,0 @@ - -// Egg missile -------------------------------------------------------------- - -ACTOR EggFX : MorphProjectile -{ - Radius 8 - Height 8 - Speed 18 - MorphProjectile.PlayerClass "ChickenPlayer" - MorphProjectile.MonsterClass "Chicken" - MorphProjectile.MorphStyle MRF_UNDOBYTOMEOFPOWER - States - { - Spawn: - EGGM ABCDE 4 - Loop - Death: - FX01 FFGH 3 Bright - Stop - } -} - - -// Morph Ovum ---------------------------------------------------------------- - -ACTOR ArtiEgg : CustomInventory -{ - +COUNTITEM - +FLOATBOB - +INVENTORY.INVBAR - +INVENTORY.PICKUPFLASH - +INVENTORY.FANCYPICKUPSOUND - Inventory.Icon "ARTIEGGC" - Inventory.PickupSound "misc/p_pkup" - Inventory.PickupMessage "$TXT_ARTIEGG" - Inventory.DefMaxAmount - Tag "$TAG_ARTIEGG" - States - { - Spawn: - EGGC ABCB 6 - Loop - Use: - TNT1 A 0 A_FireCustomMissile("EggFX", -15, 0, 0, 0, 1) - TNT1 A 0 A_FireCustomMissile("EggFX", -7.5, 0, 0, 0, 1) - TNT1 A 0 A_FireCustomMissile("EggFX", 0, 0, 0, 0, 1) - TNT1 A 0 A_FireCustomMissile("EggFX", 7.5, 0, 0, 0, 1) - TNT1 A 0 A_FireCustomMissile("EggFX", 15, 0, 0, 0, 1) - Stop - } -} - -// Pork missile -------------------------------------------------------------- - -ACTOR PorkFX : MorphProjectile -{ - Radius 8 - Height 8 - Speed 18 - MorphProjectile.PlayerClass "PigPlayer" - MorphProjectile.MonsterClass "Pig" - MorphProjectile.MorphStyle MRF_UNDOBYTOMEOFPOWER|MRF_UNDOBYCHAOSDEVICE - States - { - Spawn: - PRKM ABCDE 4 - Loop - Death: - FHFX IJKL 3 Bright - Stop - } -} - -// Porkalator --------------------------------------------------------------- - -ACTOR ArtiPork : CustomInventory -{ - +COUNTITEM - +FLOATBOB - +INVENTORY.INVBAR - +INVENTORY.PICKUPFLASH - +INVENTORY.FANCYPICKUPSOUND - Inventory.Icon "ARTIPORK" - Inventory.PickupSound "misc/p_pkup" - Inventory.PickupMessage "$TXT_ARTIEGG2" - Inventory.DefMaxAmount - Tag "$TAG_ARTIPORK" - States - { - Spawn: - PORK ABCDEFGH 5 - Loop - Use: - TNT1 A 0 A_FireCustomMissile("PorkFX", -15, 0, 0, 0, 1) - TNT1 A 0 A_FireCustomMissile("PorkFX", -7.5, 0, 0, 0, 1) - TNT1 A 0 A_FireCustomMissile("PorkFX", 0, 0, 0, 0, 1) - TNT1 A 0 A_FireCustomMissile("PorkFX", 7.5, 0, 0, 0, 1) - TNT1 A 0 A_FireCustomMissile("PorkFX", 15, 0, 0, 0, 1) - Stop - } -} - diff --git a/wadsrc/static/actors/raven/artitele.txt b/wadsrc/static/actors/raven/artitele.txt deleted file mode 100644 index 569926d16d..0000000000 --- a/wadsrc/static/actors/raven/artitele.txt +++ /dev/null @@ -1,24 +0,0 @@ - -// Teleport (self) ---------------------------------------------------------- - -ACTOR ArtiTeleport : Inventory native -{ - +COUNTITEM - +FLOATBOB - +INVENTORY.INVBAR - +INVENTORY.PICKUPFLASH - +INVENTORY.FANCYPICKUPSOUND - Inventory.DefMaxAmount - Inventory.Icon "ARTIATLP" - Inventory.PickupSound "misc/p_pkup" - Inventory.PickupMessage "$TXT_ARTITELEPORT" - Tag "$TAG_ARTITELEPORT" - States - { - Spawn: - ATLP ABCB 4 - Loop - } -} - - diff --git a/wadsrc/static/actors/raven/minotaur.txt b/wadsrc/static/actors/raven/minotaur.txt deleted file mode 100644 index 134bf9d52f..0000000000 --- a/wadsrc/static/actors/raven/minotaur.txt +++ /dev/null @@ -1,218 +0,0 @@ -ACTOR Minotaur native -{ - Health 3000 - Radius 28 - Height 100 - Mass 800 - Speed 16 - Damage 7 - Painchance 25 - Monster - +DROPOFF - +FLOORCLIP - +BOSS - +NORADIUSDMG - +DONTMORPH - +NOTARGET - +BOSSDEATH - SeeSound "minotaur/sight" - AttackSound "minotaur/attack1" - PainSound "minotaur/pain" - DeathSound "minotaur/death" - ActiveSound "minotaur/active" - DropItem "ArtiSuperHealth", 51 - DropItem "PhoenixRodAmmo", 84, 10 - - action native A_MinotaurDecide(); - action native A_MinotaurAtk1(); - action native A_MinotaurAtk2(); - action native A_MinotaurAtk3(); - action native A_MinotaurCharge(); - action native A_MinotaurLook(); - action native A_MinotaurRoam(); - action native A_MinotaurChase(); - action native A_MinotaurDeath(); - - States - { - Spawn: - MNTR AB 10 A_MinotaurLook - Loop - Roam: - MNTR ABCD 5 A_MinotaurRoam - Loop - See: - MNTR ABCD 5 A_MinotaurChase - Loop - Melee: - MNTR V 10 A_FaceTarget - MNTR W 7 A_FaceTarget - MNTR X 12 A_MinotaurAtk1 - Goto See - Missile: - MNTR V 10 A_MinotaurDecide - MNTR Y 4 A_FaceTarget - MNTR Z 9 A_MinotaurAtk2 - Goto See - Hammer: - MNTR V 10 A_FaceTarget - MNTR W 7 A_FaceTarget - MNTR X 12 A_MinotaurAtk3 - Goto See - HammerLoop: - MNTR X 12 - Goto Hammer - Charge: - MNTR U 2 A_MinotaurCharge - Loop - Pain: - MNTR E 3 - MNTR E 6 A_Pain - Goto See - Death: - MNTR F 6 A_MinotaurDeath - MNTR G 5 - MNTR H 6 A_Scream - MNTR I 5 - MNTR J 6 - MNTR K 5 - MNTR L 6 - MNTR M 5 A_NoBlocking - MNTR N 6 - MNTR O 5 - MNTR P 6 - MNTR Q 5 - MNTR R 6 - MNTR S 5 - MNTR T -1 A_BossDeath - Stop - FadeOut: - MNTR E 6 - MNTR E 2 A_Scream - MNTR E 5 A_SpawnItemEx("MinotaurSmokeExit") - MNTR E 5 - MNTR E 5 A_NoBlocking - MNTR E 5 - MNTR E 5 A_SetTranslucent(0.66, 0) - MNTR E 5 A_SetTranslucent(0.33, 0) - MNTR E 10 A_BossDeath - Stop - } -} - -ACTOR MinotaurFriend : Minotaur native -{ - Health 2500 - -DROPOFF - -BOSS - -DONTMORPH - +FRIENDLY - +NOTARGETSWITCH - +STAYMORPHED - +TELESTOMP - +SUMMONEDMONSTER - RenderStyle Translucent - Alpha 0.3333 - DropItem "None" - States - { - Spawn: - MNTR A 15 - MNTR A 15 A_SetTranslucent(0.66, 0) - MNTR A 3 A_SetTranslucent(1, 0) - Goto Super::Spawn - Idle: - Goto Super::Spawn - Death: - Goto FadeOut - } -} - -// Minotaur FX 1 ------------------------------------------------------------ - -ACTOR MinotaurFX1 -{ - Radius 10 - Height 6 - Speed 20 - FastSpeed 26 - Damage 3 - DamageType Fire - Projectile - -ACTIVATEIMPACT - -ACTIVATEPCROSS - RenderStyle Add - States - { - Spawn: - FX12 AB 6 Bright - Loop - Death: - FX12 CDEFGH 5 Bright - Stop - } -} - - -// Minotaur FX 2 ------------------------------------------------------------ - -ACTOR MinotaurFX2 : MinotaurFX1 -{ - Radius 5 - Height 12 - Speed 14 - FastSpeed 20 - Damage 4 - +FLOORHUGGER - ExplosionDamage 24 - DeathSound "minotaur/fx2hit" - - action native A_MntrFloorFire(); - - states - { - Spawn: - FX13 A 2 Bright A_MntrFloorFire - Loop - Death: - FX13 I 4 Bright A_Explode - FX13 JKLM 4 Bright - Stop - } -} - -// Minotaur FX 3 ------------------------------------------------------------ - -ACTOR MinotaurFX3 : MinotaurFX2 -{ - Radius 8 - Height 16 - Speed 0 - DeathSound "minotaur/fx3hit" - ExplosionDamage 128 - States - { - Spawn: - FX13 DC 4 Bright - FX13 BCDE 5 Bright - FX13 FGH 4 Bright - Stop - } -} - -// Minotaur Smoke Exit ------------------------------------------------------ - -ACTOR MinotaurSmokeExit -{ - +NOBLOCKMAP - +NOTELEPORT - RenderStyle Translucent - Alpha 0.4 - States - { - Spawn: - MNSM ABCDEFGHIJIHGFEDCBA 3 - Stop - } -} - diff --git a/wadsrc/static/actors/raven/ravenambient.txt b/wadsrc/static/actors/raven/ravenambient.txt deleted file mode 100644 index f7312de022..0000000000 --- a/wadsrc/static/actors/raven/ravenambient.txt +++ /dev/null @@ -1,36 +0,0 @@ - - -// Wind --------------------------------------------------------------------- - -ACTOR SoundWind -{ - +NOBLOCKMAP - +NOSECTOR - +DONTSPLASH - States - { - Spawn: - TNT1 A 2 A_PlaySoundEx("world/wind", "SoundSlot6", 1) - Loop - } -} - -ACTOR SoundWindHexen : SoundWind -{ -} - - -// Waterfall ---------------------------------------------------------------- - -ACTOR SoundWaterfall -{ - +NOBLOCKMAP - +NOSECTOR - +DONTSPLASH - States - { - Spawn: - TNT1 A 2 A_PlaySoundEx("world/waterfall", "SoundSlot6", 1) - Loop - } -} diff --git a/wadsrc/static/actors/raven/ravenartifacts.txt b/wadsrc/static/actors/raven/ravenartifacts.txt deleted file mode 100644 index 43a5e87fcc..0000000000 --- a/wadsrc/static/actors/raven/ravenartifacts.txt +++ /dev/null @@ -1,125 +0,0 @@ - -// Health ------------------------------------------------------------------- - -ACTOR ArtiHealth : HealthPickup -{ - Health 25 - +COUNTITEM - +FLOATBOB - +INVENTORY.PICKUPFLASH - +INVENTORY.FANCYPICKUPSOUND - Inventory.Icon ARTIPTN2 - Inventory.PickupSound "misc/p_pkup" - Inventory.PickupMessage "$TXT_ARTIHEALTH" - Tag "$TAG_ARTIHEALTH" - HealthPickup.Autouse 1 - States - { - Spawn: - PTN2 ABC 4 - Loop - } -} - -// Super health ------------------------------------------------------------- - -ACTOR ArtiSuperHealth : HealthPickup -{ - Health 100 - +COUNTITEM - +FLOATBOB - +INVENTORY.PICKUPFLASH - +INVENTORY.FANCYPICKUPSOUND - Inventory.Icon ARTISPHL - Inventory.PickupSound "misc/p_pkup" - Inventory.PickupMessage "$TXT_ARTISUPERHEALTH" - Tag "$TAG_ARTISUPERHEALTH" - HealthPickup.Autouse 2 - States - { - Spawn: - SPHL A 350 - Loop - } -} - -// Flight ------------------------------------------------------------------- - -ACTOR ArtiFly : PowerupGiver -{ - +COUNTITEM - +FLOATBOB - +INVENTORY.PICKUPFLASH - +INVENTORY.INTERHUBSTRIP - Inventory.RespawnTics 4230 - Inventory.Icon ARTISOAR - Inventory.PickupMessage "$TXT_ARTIFLY" - Tag "$TAG_ARTIFLY" - Powerup.Type Flight - States - { - Spawn: - SOAR ABCB 5 - Loop - } -} - -// Invulnerability Heretic (Ring of invincibility) -------------------------- - -ACTOR ArtiInvulnerability : PowerupGiver -{ - +COUNTITEM - +FLOATBOB - +INVENTORY.PICKUPFLASH - Inventory.RespawnTics 4230 - Inventory.Icon ARTIINVU - Inventory.PickupMessage "$TXT_ARTIINVULNERABILITY" - Tag "$TAG_ARTIINVULNERABILITY" - Powerup.Type Invulnerable - Powerup.Color GoldMap - States - { - Spawn: - INVU ABCD 3 - Loop - } -} - -// Invulnerability Hexen (Icon of the defender) ----------------------------- - -ACTOR ArtiInvulnerability2 : PowerupGiver -{ - +COUNTITEM - +FLOATBOB - +INVENTORY.PICKUPFLASH - Inventory.RespawnTics 4230 - Inventory.Icon ARTIDEFN - Inventory.PickupMessage "$TXT_ARTIINVULNERABILITY2" - Powerup.Type Invulnerable - Tag "$TAG_ARTIDEFENDER" - States - { - Spawn: - DEFN ABCD 3 - Loop - } -} - -// Torch -------------------------------------------------------------------- - -ACTOR ArtiTorch : PowerupGiver -{ - +COUNTITEM - +FLOATBOB - +INVENTORY.PICKUPFLASH - Inventory.Icon ARTITRCH - Inventory.PickupMessage "$TXT_ARTITORCH" - Tag "$TAG_ARTITORCH" - Powerup.Type Torch - States - { - Spawn: - TRCH ABC 3 Bright - Loop - } -} diff --git a/wadsrc/static/actors/raven/ravenhealth.txt b/wadsrc/static/actors/raven/ravenhealth.txt deleted file mode 100644 index 99e6692bac..0000000000 --- a/wadsrc/static/actors/raven/ravenhealth.txt +++ /dev/null @@ -1,13 +0,0 @@ -ACTOR CrystalVial : Health -{ - +FLOATBOB - Inventory.Amount 10 - Inventory.PickupMessage "$TXT_ITEMHEALTH" - States - { - Spawn: - PTN1 ABC 3 - Loop - } -} - diff --git a/wadsrc/static/actors/shared/action.txt b/wadsrc/static/actors/shared/action.txt deleted file mode 100644 index fc0e713130..0000000000 --- a/wadsrc/static/actors/shared/action.txt +++ /dev/null @@ -1,56 +0,0 @@ - - -//========================================================================== -// -// Ice chunk -// -//========================================================================== - -ACTOR IceChunk -{ - Radius 3 - Height 4 - Mass 5 - Gravity 0.125 - +DROPOFF - +CANNOTPUSH - +FLOORCLIP - +NOTELEPORT - +NOBLOCKMAP - +MOVEWITHSECTOR - - action native A_IceSetTics (); - - States - { - Spawn: - ICEC A 1 - ICEC ABCD 10 A_IceSetTics - Stop - } -} - -//========================================================================== -// -// A chunk of ice that is also a player -// -//========================================================================== - -ACTOR IceChunkHead : PlayerChunk -{ - Radius 3 - Height 4 - Mass 5 - Gravity 0.125 - DamageType Ice - +DROPOFF - +CANNOTPUSH - States - { - Spawn: - ICEC A 0 - ICEC A 10 A_CheckPlayerDone - wait - } -} - diff --git a/wadsrc/static/actors/shared/blood.txt b/wadsrc/static/actors/shared/blood.txt deleted file mode 100644 index ab33fee75c..0000000000 --- a/wadsrc/static/actors/shared/blood.txt +++ /dev/null @@ -1,69 +0,0 @@ - -// Blood sprite ------------------------------------------------------------ - -ACTOR Blood -{ - Mass 5 - +NOBLOCKMAP - +NOTELEPORT - +ALLOWPARTICLES - States - { - Spawn: - BLUD CBA 8 - Stop - Spray: - SPRY ABCDEF 3 - SPRY G 2 - Stop - } -} - -// Blood splatter ----------------------------------------------------------- - -ACTOR BloodSplatter -{ - Radius 2 - Height 4 - +NOBLOCKMAP - +MISSILE - +DROPOFF - +NOTELEPORT - +CANNOTPUSH - +ALLOWPARTICLES - Mass 5 - States - { - Spawn: - BLUD CBA 8 - Stop - Death: - BLUD A 6 - Stop - } -} - -// Axe Blood ---------------------------------------------------------------- - -ACTOR AxeBlood -{ - Radius 2 - Height 4 - +NOBLOCKMAP - +NOGRAVITY - +DROPOFF - +NOTELEPORT - +CANNOTPUSH - +ALLOWPARTICLES - Mass 5 - States - { - Spawn: - FAXE FGHIJ 3 - Death: - FAXE K 3 - Stop - } -} - - \ No newline at end of file diff --git a/wadsrc/static/actors/shared/botstuff.txt b/wadsrc/static/actors/shared/botstuff.txt deleted file mode 100644 index 4b1992bde4..0000000000 --- a/wadsrc/static/actors/shared/botstuff.txt +++ /dev/null @@ -1,19 +0,0 @@ - -ACTOR CajunBodyNode -{ - +NOSECTOR - +NOGRAVITY - +INVISIBLE -} - -ACTOR CajunTrace -{ - Speed 12 - Radius 6 - Height 8 - +NOBLOCKMAP - +DROPOFF - +MISSILE - +NOGRAVITY - +NOTELEPORT -} diff --git a/wadsrc/static/actors/shared/bridge.txt b/wadsrc/static/actors/shared/bridge.txt deleted file mode 100644 index 97d4c22ad1..0000000000 --- a/wadsrc/static/actors/shared/bridge.txt +++ /dev/null @@ -1,105 +0,0 @@ -// Bridge ball ------------------------------------------------------------- - -ACTOR BridgeBall -{ - +NOBLOCKMAP - +NOTELEPORT - +NOGRAVITY - - action native A_BridgeOrbit(); - - States - { - Spawn: - TLGL A 2 Bright - TLGL A 1 Bright A_BridgeOrbit - Wait - } - -} - -// The bridge itself ------------------------------------------------------- - -ACTOR CustomBridge native -{ - +SOLID - +NOGRAVITY - +NOLIFTDROP - +ACTLIKEBRIDGE - Radius 32 - Height 2 - RenderStyle None - - action native A_BridgeInit(class balltype = "BridgeBall"); - - states - { - Spawn: - TLGL ABCDE 3 Bright - Loop - See: - TLGL A 2 - TLGL A 2 A_BridgeInit - TLGL A -1 - Stop - Death: - TLGL A 2 - TLGL A 300 - Stop - } -} - -// The Hexen bridge ------------------------------------------------------- - -ACTOR Bridge : CustomBridge -{ - RenderStyle None - Args 32, 2, 3, 0 -} - -// The ZDoom bridge ------------------------------------------------------- - -ACTOR ZBridge : CustomBridge -{ - Args 36, 4, 0, 0 -} - - -// Invisible bridge -------------------------------------------------------- - -ACTOR InvisibleBridge native -{ - RenderStyle None - Radius 32 - Height 4 - +SOLID - +NOGRAVITY - +NOLIFTDROP - +ACTLIKEBRIDGE - States - { - Spawn: - TNT1 A -1 - Stop - } -} - -// And some invisible bridges from Skull Tag ------------------------------- - -ACTOR InvisibleBridge32 : InvisibleBridge -{ - Radius 32 - Height 8 -} - -ACTOR InvisibleBridge16 : InvisibleBridge -{ - Radius 16 - Height 8 -} - -ACTOR InvisibleBridge8 : InvisibleBridge -{ - Radius 8 - Height 8 -} diff --git a/wadsrc/static/actors/shared/camera.txt b/wadsrc/static/actors/shared/camera.txt deleted file mode 100644 index 46816f9eab..0000000000 --- a/wadsrc/static/actors/shared/camera.txt +++ /dev/null @@ -1,23 +0,0 @@ -ACTOR DoomBuilderCamera -{ - States - { - Spawn: - TNT1 A 1 - Stop - } -} - - -ACTOR SecurityCamera native -{ - +NOBLOCKMAP - +NOGRAVITY - +DONTSPLASH - RenderStyle None - CameraHeight 0 -} - -ACTOR AimingCamera : SecurityCamera native -{ -} diff --git a/wadsrc/static/actors/shared/damagetypes.txt b/wadsrc/static/actors/shared/damagetypes.txt deleted file mode 100644 index 9e5f1e2540..0000000000 --- a/wadsrc/static/actors/shared/damagetypes.txt +++ /dev/null @@ -1,4 +0,0 @@ -damagetype Drowning -{ - NoArmor -} diff --git a/wadsrc/static/actors/shared/debris.txt b/wadsrc/static/actors/shared/debris.txt deleted file mode 100644 index 5d14a48fad..0000000000 --- a/wadsrc/static/actors/shared/debris.txt +++ /dev/null @@ -1,331 +0,0 @@ - -// Rocks -------------------------------------------------------------------- - -ACTOR Rock1 -{ - +NOBLOCKMAP - +DROPOFF - +MISSILE - +NOTELEPORT - States - { - Spawn: - ROKK A 20 - Loop - Death: - ROKK A 10 - Stop - } -} - -ACTOR Rock2 -{ - +NOBLOCKMAP - +DROPOFF - +MISSILE - +NOTELEPORT - States - { - Spawn: - ROKK B 20 - Loop - Death: - ROKK B 10 - Stop - } -} - - -ACTOR Rock3 -{ - +NOBLOCKMAP - +DROPOFF - +MISSILE - +NOTELEPORT - States - { - Spawn: - ROKK C 20 - Loop - Death: - ROKK C 10 - Stop - } -} - - -// Dirt -------------------------------------------------------------------- - -ACTOR Dirt1 -{ - +NOBLOCKMAP - +DROPOFF - +MISSILE - +NOTELEPORT - States - { - Spawn: - ROKK D 20 - Loop - Death: - ROKK D 10 - Stop - } -} - -ACTOR Dirt2 -{ - +NOBLOCKMAP - +DROPOFF - +MISSILE - +NOTELEPORT - States - { - Spawn: - ROKK E 20 - Loop - Death: - ROKK E 10 - Stop - } -} - -ACTOR Dirt3 -{ - +NOBLOCKMAP - +DROPOFF - +MISSILE - +NOTELEPORT - States - { - Spawn: - ROKK F 20 - Loop - Death: - ROKK F 10 - Stop - } -} - -ACTOR Dirt4 -{ - +NOBLOCKMAP - +DROPOFF - +MISSILE - +NOTELEPORT - States - { - Spawn: - ROKK G 20 - Loop - Death: - ROKK G 10 - Stop - } -} - -ACTOR Dirt5 -{ - +NOBLOCKMAP - +DROPOFF - +MISSILE - +NOTELEPORT - States - { - Spawn: - ROKK H 20 - Loop - Death: - ROKK H 10 - Stop - } -} - -ACTOR Dirt6 -{ - +NOBLOCKMAP - +DROPOFF - +MISSILE - +NOTELEPORT - States - { - Spawn: - ROKK I 20 - Loop - Death: - ROKK I 10 - Stop - } -} - -// Stained glass ------------------------------------------------------------ - -ACTOR GlassShard native -{ - Radius 5 - Mass 5 - Projectile - -ACTIVATEPCROSS - -ACTIVATEIMPACT - BounceType "HexenCompat" - BounceFactor 0.3 -} - -ACTOR SGShard1 : GlassShard -{ - States - { - Spawn: - SGSA ABCDE 4 - Loop - Death: - SGSA E 30 - Stop - } -} - -ACTOR SGShard2 : GlassShard -{ - States - { - Spawn: - SGSA FGHIJ 4 - Loop - Death: - SGSA J 30 - Stop - } -} - -ACTOR SGShard3 : GlassShard -{ - States - { - Spawn: - SGSA KLMNO 4 - Loop - Death: - SGSA O 30 - Stop - } -} - -ACTOR SGShard4 : GlassShard -{ - States - { - Spawn: - SGSA PQRST 4 - Loop - Death: - SGSA T 30 - Stop - } -} - -ACTOR SGShard5 : GlassShard -{ - States - { - Spawn: - SGSA UVWXY 4 - Loop - Death: - SGSA Y 30 - Stop - } -} - -ACTOR SGShard6 : GlassShard -{ - States - { - Spawn: - SGSB A 4 - Loop - Death: - SGSB A 30 - Stop - } -} - -ACTOR SGShard7 : GlassShard -{ - States - { - Spawn: - SGSB B 4 - Loop - Death: - SGSB B 30 - Stop - } -} - -ACTOR SGShard8 : GlassShard -{ - States - { - Spawn: - SGSB C 4 - Loop - Death: - SGSB C 30 - Stop - } -} - -ACTOR SGShard9 : GlassShard -{ - States - { - Spawn: - SGSB D 4 - Loop - Death: - SGSB D 30 - Stop - } -} - -ACTOR SGShard0 : GlassShard -{ - States - { - Spawn: - SGSB E 4 - Loop - Death: - SGSB E 30 - Stop - } -} - -ACTOR GlassJunk -{ - +NOCLIP - +NOBLOCKMAP - RenderStyle Translucent - Alpha 0.4 - Health 3 // Number of different shards - States - { - // Are the first three frames used anywhere? - SHAR A 128 - Goto Death - SHAR B 128 - Goto Death - SHAR C 128 - Goto Death - Spawn: - SHAR D 128 - Goto Death - SHAR E 128 - Goto Death - SHAR F 128 - Goto Death - Death: - "----" A 1 A_FadeOut(0.03) - Wait - } -} diff --git a/wadsrc/static/actors/shared/decal.txt b/wadsrc/static/actors/shared/decal.txt deleted file mode 100644 index 25e7062c8e..0000000000 --- a/wadsrc/static/actors/shared/decal.txt +++ /dev/null @@ -1,3 +0,0 @@ -ACTOR Decal native -{ -} diff --git a/wadsrc/static/actors/shared/dog.txt b/wadsrc/static/actors/shared/dog.txt deleted file mode 100644 index 1004fba204..0000000000 --- a/wadsrc/static/actors/shared/dog.txt +++ /dev/null @@ -1,44 +0,0 @@ -ACTOR MBFHelperDog -{ - Health 500 - Speed 10 - PainChance 180 - Radius 12 - Height 28 - Mass 100 - Monster - +JUMPDOWN - ActiveSound "dog/active" - AttackSound "dog/attack" - DeathSound "dog/death" - PainSound "dog/pain" - SeeSound "dog/sight" - Obituary "$OB_DOG" - States - { - Spawn: - DOGS AB 10 A_Look - Loop - See: - DOGS AABBCCDD 2 A_Chase - Loop - Melee: - DOGS EF 8 A_FaceTarget - DOGS G 8 A_SargAttack - Goto See - Pain: - DOGS H 2 - DOGS H 2 A_Pain - Goto See - Death: - DOGS I 8 - DOGS J 8 A_Scream - DOGS K 4 - DOGS L 4 A_Fall - DOGS M 4 - DOGS N -1 - Raise: - DOGS NMLKJI 5 - Goto See - } -} diff --git a/wadsrc/static/actors/shared/dynlights.txt b/wadsrc/static/actors/shared/dynlights.txt deleted file mode 100644 index 4a2940be10..0000000000 --- a/wadsrc/static/actors/shared/dynlights.txt +++ /dev/null @@ -1,102 +0,0 @@ -ACTOR DynamicLight native -{ - Height 0 - Radius 0.1 - FloatBobPhase 0 - +NOBLOCKMAP - +NOGRAVITY - +FIXMAPTHINGPOS - +INVISIBLE -} - - -ACTOR PointLight : DynamicLight -{ - DynamicLight.Type "Point" -} - -ACTOR PointLightPulse : PointLight -{ - DynamicLight.Type "Pulse" -} - -ACTOR PointLightFlicker : PointLight -{ - DynamicLight.Type "Flicker" -} - -ACTOR SectorPointLight : PointLight -{ - DynamicLight.Type "Sector" -} - -ACTOR PointLightFlickerRandom : PointLight -{ - DynamicLight.Type "RandomFlicker" -} - -// MISSILEMORE and MISSILEEVENMORE are used by the lights for additive and subtractive lights - -ACTOR PointLightAdditive : PointLight -{ - +MISSILEMORE -} - -ACTOR PointLightPulseAdditive : PointLightPulse -{ - +MISSILEMORE -} - -ACTOR PointLightFlickerAdditive : PointLightFlicker -{ - +MISSILEMORE -} - -ACTOR SectorPointLightAdditive : SectorPointLight -{ - +MISSILEMORE -} - -ACTOR PointLightFlickerRandomAdditive :PointLightFlickerRandom -{ - +MISSILEMORE -} - -ACTOR PointLightSubtractive : PointLight -{ - +MISSILEEVENMORE -} - -ACTOR PointLightPulseSubtractive : PointLightPulse -{ - +MISSILEEVENMORE -} - -ACTOR PointLightFlickerSubtractive : PointLightFlicker -{ - +MISSILEEVENMORE -} - -ACTOR SectorPointLightSubtractive : SectorPointLight -{ - +MISSILEEVENMORE -} - -ACTOR PointLightFlickerRandomSubtractive : PointLightFlickerRandom -{ - +MISSILEEVENMORE -} - - -ACTOR VavoomLight : DynamicLight native -{ -} - -ACTOR VavoomLightWhite : VavoomLight native -{ -} - -ACTOR VavoomLightColor : VavoomLight native -{ -} - diff --git a/wadsrc/static/actors/shared/fountain.txt b/wadsrc/static/actors/shared/fountain.txt deleted file mode 100644 index d9c31e88e5..0000000000 --- a/wadsrc/static/actors/shared/fountain.txt +++ /dev/null @@ -1,42 +0,0 @@ -ACTOR ParticleFountain native -{ - Height 0 - +NOBLOCKMAP - +NOGRAVITY - +INVISIBLE -} - -ACTOR RedParticleFountain : ParticleFountain -{ - Health 1 -} - -ACTOR GreenParticleFountain : ParticleFountain -{ - Health 2 -} - -ACTOR BlueParticleFountain : ParticleFountain -{ - Health 3 -} - -ACTOR YellowParticleFountain : ParticleFountain -{ - Health 4 -} - -ACTOR PurpleParticleFountain : ParticleFountain -{ - Health 5 -} - -ACTOR BlackParticleFountain : ParticleFountain -{ - Health 6 -} - -ACTOR WhiteParticleFountain : ParticleFountain -{ - Health 7 -} diff --git a/wadsrc/static/actors/shared/hatetarget.txt b/wadsrc/static/actors/shared/hatetarget.txt deleted file mode 100644 index 75442c65c3..0000000000 --- a/wadsrc/static/actors/shared/hatetarget.txt +++ /dev/null @@ -1,19 +0,0 @@ - - -// Hate Target -------------------------------------------------------------- - -ACTOR HateTarget native -{ - Radius 20 - Height 56 - +SHOOTABLE - +NOGRAVITY - +NOBLOOD - +DONTSPLASH - Mass 0x7fffffff - States - { - Spawn: - TNT1 A -1 - } -} \ No newline at end of file diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt deleted file mode 100644 index 43a33f93aa..0000000000 --- a/wadsrc/static/actors/shared/inventory.txt +++ /dev/null @@ -1,376 +0,0 @@ -ACTOR Inventory native -{ - Inventory.Amount 1 - Inventory.MaxAmount 1 - Inventory.InterHubAmount 1 - Inventory.UseSound "misc/invuse" - Inventory.PickupSound "misc/i_pkup" - Inventory.PickupMessage "$TXT_DEFAULTPICKUPMSG" - - action native state A_JumpIfNoAmmo(state label); - action native A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class pufftype = "BulletPuff", float range = 0, float lifesteal = 0, int lifestealmax = 0, class armorbonustype = "ArmorBonus", sound MeleeSound = "", sound MissSound = ""); - action native A_FireBullets(float/*angle*/ spread_xy, float/*angle*/ spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", int flags = 1, float range = 0, class missile = "", float Spawnheight = 32, float Spawnofs_xy = 0); - action native A_FireCustomMissile(class missiletype, float angle = 0, bool useammo = true, float spawnofs_xy = 0, float spawnheight = 0, int flags = 0, float pitch = 0); - action native A_RailAttack(int damage, int spawnofs_xy = 0, bool useammo = true, color color1 = "", color color2 = "", int flags = 0, float maxdiff = 0, class pufftype = "BulletPuff", float/*angle*/ spread_xy = 0, float/*angle*/ spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class spawnclass = "none", float spawnofs_z = 0, int spiraloffset = 270, int limit = 0); - action native A_Light(int extralight); - action native A_Light0(); - action native A_Light1(); - action native A_Light2(); - action native A_LightInverse(); - action native A_WeaponReady(int flags = 0); - action native A_Lower(); - action native A_Raise(); - action native A_FirePistol(); - action native A_FireShotgun(); - action native A_FireShotgun2(); - action native A_OpenShotgun2(); - action native A_LoadShotgun2(); - action native A_CloseShotgun2(); - action native A_FireCGun(); - action native A_FireSTGrenade(class grenadetype = "Grenade"); - action native A_FireMissile(); - action native A_FirePlasma(); - action native A_FireRailgun(); - action native A_FireRailgunLeft(); - action native A_FireRailgunRight(); - action native A_RailWait(); - action native A_BFGsound(); - action native A_FireBFG(); - action native A_FireOldBFG(); - action native A_ReFire(state flash = ""); - action native A_ClearReFire(); - action native A_CheckReload(); - action native A_GunFlash(state flash = "", int flags = 0); - action native A_Saw(sound fullsound = "weapons/sawfull", sound hitsound = "weapons/sawhit", int damage = 2, class pufftype = "BulletPuff", int flags = 0, float range = 0, float/*angle*/ spread_xy = 2.8125, float/*angle*/ spread_z = 0, float lifesteal = 0, int lifestealmax = 0, class armorbonustype = "ArmorBonus"); - action native state A_CheckForReload(int counter, state label, bool dontincrement = false); - action native A_ResetReloadCounter(); - action native A_RestoreSpecialPosition(); - action native A_RestoreSpecialDoomThing(); - action native A_RestoreSpecialThing1(); - action native A_RestoreSpecialThing2(); - - States - { - HideDoomish: - TNT1 A 1050 - TNT1 A 0 A_RestoreSpecialPosition - TNT1 A 1 A_RestoreSpecialDoomThing - Stop - HideSpecial: - ACLO E 1400 - ACLO A 0 A_RestoreSpecialPosition - ACLO A 4 A_RestoreSpecialThing1 - ACLO BABCBCDC 4 - ACLO D 4 A_RestoreSpecialThing2 - Stop - Held: - TNT1 A -1 - Stop - HoldAndDestroy: - TNT1 A 1 - Stop - } -} - -Actor ScoreItem : Inventory native -{ - Height 10 - +COUNTITEM - Inventory.Amount 1 - +Inventory.ALWAYSPICKUP -} - -Actor Ammo : Inventory native -{ - +INVENTORY.KEEPDEPLETED - Inventory.PickupSound "misc/ammo_pkup" -} - -Actor BackpackItem : Inventory native -{ -} - -ACTOR Armor : Inventory native -{ - Inventory.PickupSound "misc/armor_pkup" -} - -ACTOR BasicArmor : Armor native -{ - +Inventory.KEEPDEPLETED -} - -ACTOR BasicArmorBonus : Armor native -{ - +Inventory.AUTOACTIVATE - +Inventory.ALWAYSPICKUP - Inventory.MaxAmount 0 - Armor.SavePercent 33.335 - -} - -ACTOR BasicArmorPickup : Armor native -{ - +Inventory.AUTOACTIVATE - Inventory.MaxAmount 0 -} - -ACTOR HexenArmor : Armor native -{ - +Inventory.KEEPDEPLETED - +Inventory.UNDROPPABLE -} - -ACTOR DehackedPickup : Inventory native {} - -ACTOR FakeInventory : Inventory native {} - -ACTOR CustomInventory : Inventory native {} - -Actor Health : Inventory native -{ - Inventory.Amount 1 - Inventory.MaxAmount 0 - Inventory.PickupSound "misc/health_pkup" -} - -Actor HealthPickup : Inventory native -{ - Inventory.DefMaxAmount - +INVENTORY.INVBAR -} - -Actor Key : Inventory native -{ - +DONTGIB // Don't disappear due to a crusher - +INVENTORY.INTERHUBSTRIP - Inventory.PickupSound "misc/k_pkup" -} - -ACTOR PowerupGiver : Inventory native -{ - Inventory.DefMaxAmount - +INVENTORY.INVBAR - +INVENTORY.FANCYPICKUPSOUND - Inventory.PickupSound "misc/p_pkup" -} - -ACTOR Powerup : Inventory native {} - -ACTOR PowerInvulnerable : Powerup native -{ - Powerup.Duration -30 - inventory.icon "SPSHLD0" -} - -ACTOR PowerStrength : Powerup native -{ - Powerup.Duration 1 - Powerup.Color 255,0,0,0.5 - +INVENTORY.HUBPOWER -} - -ACTOR PowerInvisibility : Powerup native -{ - +SHADOW - Powerup.Duration -60 - Powerup.Strength 80 - Powerup.Mode "Fuzzy" -} - -ACTOR PowerGhost : PowerInvisibility -{ - +GHOST - Powerup.Duration -60 - Powerup.Strength 60 - Powerup.Mode "None" -} - -ACTOR PowerShadow : PowerInvisibility -{ - +INVENTORY.HUBPOWER - Powerup.Duration -55 - Powerup.Strength 75 - Powerup.Mode "Cumulative" -} - -ACTOR PowerIronFeet : Powerup native -{ - Powerup.Duration -60 - Powerup.Color 0, 255, 0, 0.125 -} - -ACTOR PowerMask : PowerIronFeet native -{ - Powerup.Duration -80 - Powerup.Color 0,0,0,0 - +INVENTORY.HUBPOWER - Inventory.Icon "I_MASK" -} - -ACTOR PowerLightAmp : Powerup native -{ - Powerup.Duration -120 -} - -ACTOR PowerTorch : PowerLightAmp native {} - -ACTOR PowerFlight : Powerup native -{ - Powerup.Duration -60 - +INVENTORY.HUBPOWER -} - -ACTOR PowerWeaponLevel2 : Powerup native -{ - Powerup.Duration -40 - Inventory.Icon "SPINBK0" - +INVENTORY.NOTELEPORTFREEZE -} - -ACTOR PowerSpeed : Powerup native -{ - Powerup.Duration -45 - Speed 1.5 - Inventory.Icon "SPBOOT0" - +INVENTORY.NOTELEPORTFREEZE -} - -// Player Speed Trail (used by the Speed Powerup) ---------------------------- - -ACTOR PlayerSpeedTrail native -{ - +NOBLOCKMAP - +NOGRAVITY - Alpha 0.6 - RenderStyle Translucent -} - -ACTOR PowerMinotaur : Powerup native -{ - Powerup.Duration -25 - Inventory.Icon "SPMINO0" -} - -ACTOR PowerTargeter : Powerup native -{ - Powerup.Duration -160 - +INVENTORY.HUBPOWER - States - { - Targeter: - TRGT A -1 - Stop - TRGT B -1 - Stop - TRGT C -1 - Stop - } -} - -ACTOR PowerFrightener : Powerup native -{ - Powerup.Duration -60 -} - -ACTOR PowerBuddha : Powerup native -{ - Powerup.Duration -60 -} - -ACTOR PowerScanner : Powerup native -{ - Powerup.Duration -80 - +INVENTORY.HUBPOWER -} - -ACTOR PowerTimeFreezer : Powerup native -{ - Powerup.Duration -12 -} - -ACTOR PowerDamage : Powerup native -{ - Powerup.Duration -25 -} - -ACTOR PowerProtection : Powerup native -{ - Powerup.Duration -25 -} - -ACTOR PowerDrain : Powerup native -{ - Powerup.Duration -60 -} - -ACTOR PowerRegeneration : Powerup native -{ - Powerup.Duration -120 - Powerup.Strength 5 -} - -ACTOR PowerHighJump : Powerup native {} - -ACTOR PowerDoubleFiringSpeed : Powerup native {} - -ACTOR PowerMorph : Powerup native -{ - Powerup.Duration -40 -} - -ACTOR PowerInfiniteAmmo : Powerup native -{ - Powerup.Duration -30 -} - -ACTOR MapRevealer : Inventory native {} - -ACTOR PuzzleItem : Inventory native -{ - +NOGRAVITY - +INVENTORY.INVBAR - Inventory.DefMaxAmount - Inventory.UseSound "PuzzleSuccess" - Inventory.PickupSound "misc/i_pkup" -} - -Actor Weapon : Inventory native -{ - Inventory.PickupSound "misc/w_pkup" - Weapon.DefaultKickback - Weapon.BobSpeed 1.0 - Weapon.BobRangeX 1.0 - Weapon.BobRangeY 1.0 - +WEAPONSPAWN - States - { - LightDone: - SHTG E 0 A_Light0 - Stop - } - - action native A_ZoomFactor(float scale = 1, int flags = 0); - const int ZOOM_INSTANT = 1; - const int ZOOM_NOSCALETURNING = 2; - - action native A_SetCrosshair(int xhair); -} - -ACTOR WeaponGiver : Weapon native -{ - Weapon.AmmoGive1 -1 - Weapon.AmmoGive2 -1 -} - -Actor WeaponHolder : Inventory native -{ - +NOBLOCKMAP - +NOSECTOR - +INVENTORY.UNDROPPABLE -} - -Actor WeaponPiece : Inventory native -{ - +WEAPONSPAWN -} diff --git a/wadsrc/static/actors/shared/mapmarker.txt b/wadsrc/static/actors/shared/mapmarker.txt deleted file mode 100644 index 9c5e36b44f..0000000000 --- a/wadsrc/static/actors/shared/mapmarker.txt +++ /dev/null @@ -1,15 +0,0 @@ - -ACTOR MapMarker native -{ - +NOBLOCKMAP - +NOGRAVITY - +DONTSPLASH - +INVISIBLE - Scale 0.5 - States - { - Spawn: - AMRK A -1 - Stop - } -} \ No newline at end of file diff --git a/wadsrc/static/actors/shared/morph.txt b/wadsrc/static/actors/shared/morph.txt deleted file mode 100644 index f5aac48d21..0000000000 --- a/wadsrc/static/actors/shared/morph.txt +++ /dev/null @@ -1,15 +0,0 @@ -ACTOR MorphProjectile native -{ - Damage 1 - Projectile - -ACTIVATEIMPACT - -ACTIVATEPCROSS -} - -ACTOR MorphedMonster native -{ - Monster - -COUNTKILL - +FLOORCLIP -} - diff --git a/wadsrc/static/actors/shared/movingcamera.txt b/wadsrc/static/actors/shared/movingcamera.txt deleted file mode 100644 index 4ba2291541..0000000000 --- a/wadsrc/static/actors/shared/movingcamera.txt +++ /dev/null @@ -1,34 +0,0 @@ -ACTOR InterpolationPoint native -{ - +NOBLOCKMAP - +NOGRAVITY - +DONTSPLASH - RenderStyle None -} - -ACTOR InterpolationSpecial native -{ - +NOBLOCKMAP - +NOSECTOR - +NOGRAVITY - +DONTSPLASH -} - -ACTOR PathFollower native -{ - +NOBLOCKMAP - +NOSECTOR - +NOGRAVITY - +DONTSPLASH -} - -ACTOR ActorMover : PathFollower native -{ -} - -ACTOR MovingCamera : PathFollower native -{ - CameraHeight 0 -} - - diff --git a/wadsrc/static/actors/shared/player.txt b/wadsrc/static/actors/shared/player.txt deleted file mode 100644 index 08d9a252ac..0000000000 --- a/wadsrc/static/actors/shared/player.txt +++ /dev/null @@ -1,53 +0,0 @@ -Actor PlayerPawn : Actor native -{ - Health 100 - Radius 16 - Height 56 - Mass 100 - Painchance 255 - Speed 1 - +SOLID - +SHOOTABLE - +DROPOFF - +PICKUP - +NOTDMATCH - +FRIENDLY - +SLIDESONWALLS - +CANPASS - +CANPUSHWALLS - +FLOORCLIP - +WINDTHRUST - +TELESTOMP - +NOBLOCKMONST - Player.AttackZOffset 8 - Player.JumpZ 8 - Player.GruntSpeed 12 - Player.FallingScreamSpeed 35,40 - Player.ViewHeight 41 - Player.UseRange 64 - Player.ForwardMove 1,1 - Player.SideMove 1,1 - Player.ColorRange 0,0 - Player.SoundClass "player" - Player.DamageScreenColor "ff 00 00" - Player.MugShotMaxHealth 0 - Player.FlechetteType "ArtiPoisonBag3" - Player.AirCapacity 1 - Player.ViewBob 1 - Obituary "$OB_MPDEFAULT" -} - -Actor PlayerChunk : PlayerPawn native -{ - +NOSKIN - -SOLID - -SHOOTABLE - -PICKUP - -NOTDMATCH - -FRIENDLY - -SLIDESONWALLS - -CANPUSHWALLS - -FLOORCLIP - -WINDTHRUST - -TELESTOMP -} diff --git a/wadsrc/static/actors/shared/secrettrigger.txt b/wadsrc/static/actors/shared/secrettrigger.txt deleted file mode 100644 index 8db3239936..0000000000 --- a/wadsrc/static/actors/shared/secrettrigger.txt +++ /dev/null @@ -1,9 +0,0 @@ - -ACTOR SecretTrigger native -{ - +NOBLOCKMAP - +NOSECTOR - +NOGRAVITY - +DONTSPLASH -} - diff --git a/wadsrc/static/actors/shared/setcolor.txt b/wadsrc/static/actors/shared/setcolor.txt deleted file mode 100644 index 136b0bbf4c..0000000000 --- a/wadsrc/static/actors/shared/setcolor.txt +++ /dev/null @@ -1,16 +0,0 @@ -ACTOR ColorSetter native -{ - +NOBLOCKMAP - +NOGRAVITY - +DONTSPLASH - RenderStyle None -} - - -ACTOR FadeSetter native -{ - +NOBLOCKMAP - +NOGRAVITY - +DONTSPLASH - RenderStyle None -} diff --git a/wadsrc/static/actors/shared/sharedmisc.txt b/wadsrc/static/actors/shared/sharedmisc.txt deleted file mode 100644 index fe5ac72d80..0000000000 --- a/wadsrc/static/actors/shared/sharedmisc.txt +++ /dev/null @@ -1,178 +0,0 @@ - -// Default actor for unregistered doomednums ------------------------------- - -ACTOR Unknown -{ - Radius 32 - Height 56 - +NOGRAVITY - +NOBLOCKMAP - +DONTSPLASH - States - { - Spawn: - UNKN A -1 - Stop - } -} - -// Route node for monster patrols ------------------------------------------- - -ACTOR PatrolPoint -{ - Radius 8 - Height 8 - Mass 10 - +NOGRAVITY - +NOBLOCKMAP - +DONTSPLASH - RenderStyle None -} - -// A special to execute when a monster reaches a matching patrol point ------ - -ACTOR PatrolSpecial -{ - Radius 8 - Height 8 - Mass 10 - +NOGRAVITY - +NOBLOCKMAP - +DONTSPLASH - RenderStyle None -} - -// Map spot ---------------------------------------------------------------- - -ACTOR MapSpot -{ - +NOBLOCKMAP - +NOSECTOR - +NOGRAVITY - +DONTSPLASH - RenderStyle None - CameraHeight 0 -} - -// same with different editor number for Legacy maps ----------------------- - -ACTOR FS_Mapspot : Mapspot -{ -} - -// Map spot with gravity --------------------------------------------------- - -ACTOR MapSpotGravity : MapSpot -{ - -NOBLOCKMAP - -NOSECTOR - -NOGRAVITY -} - -// Point Pushers ----------------------------------------------------------- - -ACTOR PointPusher -{ - +NOBLOCKMAP - +INVISIBLE - +NOCLIP -} - -ACTOR PointPuller -{ - +NOBLOCKMAP - +INVISIBLE - +NOCLIP -} - -// Bloody gibs ------------------------------------------------------------- - -ACTOR RealGibs -{ - +DROPOFF - +CORPSE - +NOTELEPORT - +DONTGIB - States - { - Spawn: - goto GenericCrush - } -} - -// Gibs that can be placed on a map. --------------------------------------- -// -// These need to be a separate class from the above, in case someone uses -// a deh patch to change the gibs, since ZDoom actually creates a gib actor -// for actors that get crushed instead of changing their state as Doom did. - -ACTOR Gibs : RealGibs -{ - ClearFlags -} - -// Needed for loading Build maps ------------------------------------------- - -ACTOR CustomSprite native -{ - +NOBLOCKMAP - +NOGRAVITY - States - { - Spawn: - TNT1 A -1 - Stop - } -} - -// SwitchableDecoration: Activate and Deactivate change state -------------- - -ACTOR SwitchableDecoration native -{ -} - - -ACTOR SwitchingDecoration : SwitchableDecoration native -{ -} - -// Random spawner ---------------------------------------------------------- - -ACTOR RandomSpawner native -{ - +NOBLOCKMAP - +NOSECTOR - +NOGRAVITY - +THRUACTORS -} - -// Fast projectiles -------------------------------------------------------- - -ACTOR FastProjectile native -{ - Projectile - MissileHeight 0 -} - -// Sector flag setter ------------------------------------------------------ - -ACTOR SectorFlagSetter native -{ - +NOBLOCKMAP - +NOGRAVITY - +DONTSPLASH - RenderStyle None -} - -// Marker for sounds ------------------------------------------------------- - -ACTOR SpeakerIcon : Unknown -{ - States - { - Spawn: - SPKR A -1 BRIGHT - Stop - } - Scale 0.125 -} diff --git a/wadsrc/static/actors/shared/skies.txt b/wadsrc/static/actors/shared/skies.txt deleted file mode 100644 index 89f742573c..0000000000 --- a/wadsrc/static/actors/shared/skies.txt +++ /dev/null @@ -1,40 +0,0 @@ -ACTOR SkyViewpoint native -{ - +NOSECTOR - +NOBLOCKMAP - +NOGRAVITY - +DONTSPLASH -} - -ACTOR SkyPicker native -{ - +NOSECTOR - +NOBLOCKMAP - +NOGRAVITY - +DONTSPLASH -} - -Actor SkyCamCompat : SkyViewpoint native -{ -} - -ACTOR StackPoint : SkyViewpoint native -{ -} - -ACTOR UpperStackLookOnly : StackPoint -{ -} - -ACTOR LowerStackLookOnly : StackPoint -{ -} - - -ACTOR SectorSilencer native -{ - +NOBLOCKMAP - +NOGRAVITY - +DONTSPLASH - RenderStyle None -} diff --git a/wadsrc/static/actors/shared/soundenvironment.txt b/wadsrc/static/actors/shared/soundenvironment.txt deleted file mode 100644 index 822a723f81..0000000000 --- a/wadsrc/static/actors/shared/soundenvironment.txt +++ /dev/null @@ -1,9 +0,0 @@ - -ACTOR SoundEnvironment native -{ - +NOSECTOR - +NOBLOCKMAP - +NOGRAVITY - +DONTSPLASH -} - diff --git a/wadsrc/static/actors/shared/soundsequence.txt b/wadsrc/static/actors/shared/soundsequence.txt deleted file mode 100644 index 5fe34b3265..0000000000 --- a/wadsrc/static/actors/shared/soundsequence.txt +++ /dev/null @@ -1,79 +0,0 @@ - -ACTOR AmbientSound native -{ - +NOBLOCKMAP - +NOSECTOR - +DONTSPLASH -} - -ACTOR AmbientSoundNoGravity : AmbientSound -{ - +NOGRAVITY -} - -ACTOR SoundSequenceSlot native -{ - +NOSECTOR - +NOBLOCKMAP - +DONTSPLASH -} - -ACTOR SoundSequence native -{ - +NOSECTOR - +NOBLOCKMAP - +DONTSPLASH -} - -// Heretic Sound sequences ----------------------------------------------------------- - -ACTOR HereticSoundSequence1 : SoundSequence -{ - Args 0 -} - -ACTOR HereticSoundSequence2 : SoundSequence -{ - Args 1 -} - -ACTOR HereticSoundSequence3 : SoundSequence -{ - Args 2 -} - -ACTOR HereticSoundSequence4 : SoundSequence -{ - Args 3 -} - -ACTOR HereticSoundSequence5 : SoundSequence -{ - Args 4 -} - -ACTOR HereticSoundSequence6 : SoundSequence -{ - Args 5 -} - -ACTOR HereticSoundSequence7 : SoundSequence -{ - Args 6 -} - -ACTOR HereticSoundSequence8 : SoundSequence -{ - Args 7 -} - -ACTOR HereticSoundSequence9 : SoundSequence -{ - Args 8 -} - -ACTOR HereticSoundSequence10 : SoundSequence -{ - Args 9 -} - diff --git a/wadsrc/static/actors/shared/spark.txt b/wadsrc/static/actors/shared/spark.txt deleted file mode 100644 index 240d98152e..0000000000 --- a/wadsrc/static/actors/shared/spark.txt +++ /dev/null @@ -1,8 +0,0 @@ - -ACTOR Spark native -{ - +NOSECTOR - +NOBLOCKMAP - +NOGRAVITY - +DONTSPLASH -} \ No newline at end of file diff --git a/wadsrc/static/actors/shared/specialspot.txt b/wadsrc/static/actors/shared/specialspot.txt deleted file mode 100644 index fc2bd254ac..0000000000 --- a/wadsrc/static/actors/shared/specialspot.txt +++ /dev/null @@ -1,5 +0,0 @@ - -ACTOR SpecialSpot native -{ - action native A_SpawnSingleItem(class type, int fail_sp = 0, int fail_co = 0, int fail_dm = 0); -} diff --git a/wadsrc/static/actors/shared/splashes.txt b/wadsrc/static/actors/shared/splashes.txt deleted file mode 100644 index 4c71b45653..0000000000 --- a/wadsrc/static/actors/shared/splashes.txt +++ /dev/null @@ -1,237 +0,0 @@ - -// Water -------------------------------------------------------------------- - -ACTOR WaterSplash -{ - Radius 2 - Height 4 - +NOBLOCKMAP - +MISSILE - +DROPOFF - +NOTELEPORT - +LOWGRAVITY - +CANNOTPUSH - +DONTSPLASH - +DONTBLAST - States - { - Spawn: - SPSH ABC 8 - SPSH D 16 - Stop - Death: - SPSH D 10 - Stop - } -} - - -ACTOR WaterSplashBase -{ - +NOBLOCKMAP - +NOCLIP - +NOGRAVITY - +DONTSPLASH - +DONTBLAST - States - { - Spawn: - SPSH EFGHIJK 5 - Stop - } -} - -// Lava --------------------------------------------------------------------- - -ACTOR LavaSplash -{ - +NOBLOCKMAP - +NOCLIP - +NOGRAVITY - +DONTSPLASH - +DONTBLAST - States - { - Spawn: - LVAS ABCDEF 5 Bright - Stop - } -} - -ACTOR LavaSmoke -{ - +NOBLOCKMAP - +NOCLIP - +NOGRAVITY - +DONTSPLASH - RenderStyle Translucent - DefaultAlpha - States - { - Spawn: - LVAS GHIJK 5 Bright - Stop - } -} - -// Sludge ------------------------------------------------------------------- - -ACTOR SludgeChunk -{ - Radius 2 - Height 4 - +NOBLOCKMAP - +MISSILE - +DROPOFF - +NOTELEPORT - +LOWGRAVITY - +CANNOTPUSH - +DONTSPLASH - States - { - Spawn: - SLDG ABCD 8 - Stop - Death: - SLDG D 6 - Stop - } -} - -ACTOR SludgeSplash -{ - +NOBLOCKMAP - +NOCLIP - +NOGRAVITY - +DONTSPLASH - States - { - Spawn: - SLDG EFGH 6 - Stop - } -} - -/* - * These next four classes are not used by me anywhere. - * They are for people who want to use them in a TERRAIN lump. - */ - -// Blood (water with a different sprite) ------------------------------------ - -ACTOR BloodSplash -{ - Radius 2 - Height 4 - +NOBLOCKMAP - +MISSILE - +DROPOFF - +NOTELEPORT - +LOWGRAVITY - +CANNOTPUSH - +DONTSPLASH - +DONTBLAST - States - { - Spawn: - BSPH ABC 8 - BSPH D 16 - Stop - Death: - BSPH D 10 - Stop - } -} - - -ACTOR BloodSplashBase -{ - +NOBLOCKMAP - +NOCLIP - +NOGRAVITY - +DONTSPLASH - +DONTBLAST - States - { - Spawn: - BSPH EFGHIJK 5 - Stop - } -} - -// Slime (sludge with a different sprite) ----------------------------------- - -ACTOR SlimeChunk -{ - Radius 2 - Height 4 - +NOBLOCKMAP - +MISSILE - +DROPOFF - +NOTELEPORT - +LOWGRAVITY - +CANNOTPUSH - +DONTSPLASH - States - { - Spawn: - SLIM ABCD 8 - Stop - Death: - SLIM D 6 - Stop - } -} - -ACTOR SlimeSplash -{ - +NOBLOCKMAP - +NOCLIP - +NOGRAVITY - +DONTSPLASH - States - { - Spawn: - SLIM EFGH 6 - Stop - } -} - -// Smoke trail for rocket ----------------------------------- - -ACTOR RocketSmokeTrail -{ - RenderStyle Translucent - Alpha 0.4 - VSpeed 1 - +NOBLOCKMAP - +NOCLIP - +NOGRAVITY - +DONTSPLASH - +NOTELEPORT - States - { - Spawn: - RSMK ABCDE 5 - Stop - } -} - -ACTOR GrenadeSmokeTrail -{ - RenderStyle Translucent - Alpha 0.4 - +NOBLOCKMAP - +NOCLIP - +DONTSPLASH - +NOTELEPORT - Gravity 0.1 - VSpeed 0.5 - Scale 0.6 - States - { - Spawn: - RSMK ABCDE 4 - Stop - } -} diff --git a/wadsrc/static/actors/shared/teleport.txt b/wadsrc/static/actors/shared/teleport.txt deleted file mode 100644 index 0bce22ea36..0000000000 --- a/wadsrc/static/actors/shared/teleport.txt +++ /dev/null @@ -1,42 +0,0 @@ - -ACTOR TeleportFog native -{ - +NOBLOCKMAP - +NOTELEPORT - +NOGRAVITY - RenderStyle Add - States - { - Spawn: - TFOG ABABCDEFGHIJ 6 Bright - Stop - - Raven: - TELE ABCDEFGHGFEDC 6 Bright - Stop - - Strife: - TFOG ABCDEFEDCB 6 Bright - Stop - } -} - - - -ACTOR TeleportDest -{ - +NOBLOCKMAP - +NOSECTOR - +DONTSPLASH -} - -ACTOR TeleportDest2 : TeleportDest -{ - +NOGRAVITY -} - -ACTOR TeleportDest3 : TeleportDest2 -{ - -NOGRAVITY -} - diff --git a/wadsrc/static/actors/shared/waterzone.txt b/wadsrc/static/actors/shared/waterzone.txt deleted file mode 100644 index b6cf4bd297..0000000000 --- a/wadsrc/static/actors/shared/waterzone.txt +++ /dev/null @@ -1,7 +0,0 @@ -ACTOR WaterZone native -{ - +NOSECTOR - +NOBLOCKMAP - +NOGRAVITY - +DONTSPLASH -} diff --git a/wadsrc/static/actors/strife/acolyte.txt b/wadsrc/static/actors/strife/acolyte.txt deleted file mode 100644 index f190fb928f..0000000000 --- a/wadsrc/static/actors/strife/acolyte.txt +++ /dev/null @@ -1,185 +0,0 @@ - -// Base class for the acolytes ---------------------------------------------- - -ACTOR Acolyte : StrifeHumanoid -{ - Health 70 - PainChance 150 - Speed 7 - Radius 24 - Height 64 - Mass 400 - Monster - +SEESDAGGERS - +NOSPLASHALERT - +FLOORCLIP - +NEVERRESPAWN - MinMissileChance 150 - Tag "$TAG_ACOLYTE" - SeeSound "acolyte/sight" - PainSound "acolyte/pain" - AttackSound "acolyte/rifle" - DeathSound "acolyte/death" - ActiveSound "acolyte/active" - Obituary "$OB_ACOLYTE" - - action native A_BeShadowyFoe (); - action native A_AcolyteBits (); - action native A_AcolyteDie (); - - States - { - Spawn: - AGRD A 5 A_Look2 - Wait - AGRD B 8 A_ClearShadow - Loop - AGRD D 8 - Loop - AGRD ABCDABCD 5 A_Wander - Loop - See: - AGRD A 6 Fast Slow A_AcolyteBits - AGRD BCD 6 Fast Slow A_Chase - Loop - Missile: - AGRD E 8 Fast Slow A_FaceTarget - AGRD FE 4 Fast Slow A_ShootGun - AGRD F 6 Fast Slow A_ShootGun - Goto See - Pain: - AGRD O 8 Fast Slow A_Pain - Goto See - Death: - AGRD G 4 - AGRD H 4 A_Scream - AGRD I 4 - AGRD J 3 - AGRD K 3 A_NoBlocking - AGRD L 3 - AGRD M 3 A_AcolyteDie - AGRD N -1 - Stop - XDeath: - GIBS A 5 A_NoBlocking - GIBS BC 5 A_TossGib - GIBS D 4 A_TossGib - GIBS E 4 A_XScream - GIBS F 4 A_TossGib - GIBS GH 4 - GIBS I 5 - GIBS J 5 A_AcolyteDie - GIBS K 5 - GIBS L 1400 - Stop - } -} - - -// Acolyte 1 ---------------------------------------------------------------- - -ACTOR AcolyteTan : Acolyte -{ - +MISSILEMORE +MISSILEEVENMORE - DropItem "ClipOfBullets" -} - -// Acolyte 2 ---------------------------------------------------------------- - -ACTOR AcolyteRed : Acolyte -{ - +MISSILEMORE +MISSILEEVENMORE - Translation 0 -} - -// Acolyte 3 ---------------------------------------------------------------- - -ACTOR AcolyteRust : Acolyte -{ - +MISSILEMORE +MISSILEEVENMORE - Translation 1 -} - -// Acolyte 4 ---------------------------------------------------------------- - -ACTOR AcolyteGray : Acolyte -{ - +MISSILEMORE +MISSILEEVENMORE - Translation 2 -} - -// Acolyte 5 ---------------------------------------------------------------- - -ACTOR AcolyteDGreen : Acolyte -{ - +MISSILEMORE +MISSILEEVENMORE - Translation 3 -} - -// Acolyte 6 ---------------------------------------------------------------- - -ACTOR AcolyteGold : Acolyte -{ - +MISSILEMORE +MISSILEEVENMORE - Translation 4 -} - -// Acolyte 7 ---------------------------------------------------------------- - -ACTOR AcolyteLGreen : Acolyte -{ - Health 60 - Translation 5 -} - -// Acolyte 8 ---------------------------------------------------------------- - -ACTOR AcolyteBlue : Acolyte -{ - Health 60 - Translation 6 -} - -// Shadow Acolyte ----------------------------------------------------------- - -ACTOR AcolyteShadow : Acolyte -{ - +MISSILEMORE - DropItem "ClipOfBullets" - States - { - See: - AGRD A 6 A_BeShadowyFoe - Goto Super::See+1 - Pain: - AGRD O 0 Fast Slow A_SetShadow - AGRD O 8 Fast Slow A_Pain - Goto See - } -} - -// Some guy turning into an acolyte ----------------------------------------- - -ACTOR AcolyteToBe : Acolyte -{ - Health 61 - Radius 20 - Height 56 - DeathSound "becoming/death" - -COUNTKILL - -ISMONSTER - - action native A_HideDecepticon (); - - States - { - Spawn: - ARMR A -1 - Stop - Pain: - ARMR A -1 A_HideDecepticon - Stop - Death: - Goto XDeath - } -} diff --git a/wadsrc/static/actors/strife/alienspectres.txt b/wadsrc/static/actors/strife/alienspectres.txt deleted file mode 100644 index 0476fdfdf1..0000000000 --- a/wadsrc/static/actors/strife/alienspectres.txt +++ /dev/null @@ -1,202 +0,0 @@ - -// Alien Spectre 1 ----------------------------------------------------------- - -ACTOR AlienSpectre1 : SpectralMonster -{ - Health 1000 - Painchance 250 - Speed 12 - Radius 64 - Height 64 - FloatSpeed 5 - Mass 1000 - MinMissileChance 150 - RenderStyle Translucent - Alpha 0.666 - SeeSound "alienspectre/sight" - AttackSound "alienspectre/blade" - PainSound "alienspectre/pain" - DeathSound "alienspectre/death" - ActiveSound "alienspectre/active" - Obituary "$OB_ALIENSPECTRE" - +NOGRAVITY - +FLOAT - +SHADOW - +NOTDMATCH - +DONTMORPH - +NOBLOCKMONST - +INCOMBAT - +LOOKALLAROUND - +NOICEDEATH - - action native A_AlienSpectreDeath (); - - states - { - Spawn: - ALN1 A 10 A_Look - ALN1 B 10 A_SentinelBob - Loop - See: - ALN1 AB 4 Bright A_Chase - ALN1 C 4 Bright A_SentinelBob - ALN1 DEF 4 Bright A_Chase - ALN1 G 4 Bright A_SentinelBob - ALN1 HIJ 4 Bright A_Chase - ALN1 K 4 Bright A_SentinelBob - Loop - Melee: - ALN1 J 4 Bright A_FaceTarget - ALN1 I 4 Bright A_CustomMeleeAttack((random[SpectreMelee](0,255)&9)*5) - ALN1 H 4 Bright - Goto See - Missile: - ALN1 J 4 Bright A_FaceTarget - ALN1 I 4 Bright A_SpotLightning - ALN1 H 4 Bright - Goto See+10 - Pain: - ALN1 J 2 A_Pain - Goto See+6 - Death: - AL1P A 6 Bright A_SpectreChunkSmall - AL1P B 6 Bright A_Scream - AL1P C 6 Bright A_SpectreChunkSmall - AL1P DE 6 Bright - AL1P F 6 Bright A_SpectreChunkSmall - AL1P G 6 Bright - AL1P H 6 Bright A_SpectreChunkSmall - AL1P IJK 6 Bright - AL1P LM 5 Bright - AL1P N 5 Bright A_SpectreChunkLarge - AL1P OPQ 5 Bright - AL1P R 5 Bright A_AlienSpectreDeath - Stop - } -} - - -// Alien Spectre 2 ----------------------------------------------------------- - -ACTOR AlienSpectre2 : AlienSpectre1 -{ - Health 1200 - Painchance 50 - Radius 24 - DropItem "Sigil2" - States - { - Missile: - ALN1 F 4 A_FaceTarget - ALN1 I 4 A_CustomMissile("SpectralLightningH3", 32, 0) - ALN1 E 4 - Goto See+10 - } -} - -// Alien Spectre 3 ---------------------------------------------------------- -// This is the Oracle's personal spectre, so it's a little different. - -ACTOR AlienSpectre3 : AlienSpectre1 -{ - Health 1500 - Painchance 50 - Radius 24 - +SPAWNCEILING - DropItem "Sigil3" - DamageFactor "SpectralLow", 0 - states - { - Spawn: - ALN1 ABCDEFGHIJK 5 - Loop - See: - ALN1 AB 5 A_Chase - ALN1 C 5 A_SentinelBob - ALN1 DEF 5 A_Chase - ALN1 G 5 A_SentinelBob - ALN1 HIJ 5 A_Chase - ALN1 K 5 A_SentinelBob - Loop - Melee: - ALN1 J 4 A_FaceTarget - ALN1 I 4 A_CustomMeleeAttack((random[SpectreMelee](0,255)&9)*5) - ALN1 C 4 - Goto See+2 - Missile: - ALN1 F 4 A_FaceTarget - ALN1 I 4 A_Spectre3Attack - ALN1 E 4 - Goto See+10 - Pain: - ALN1 J 2 A_Pain - Goto See+6 - } -} - - -// Alien Spectre 4 ----------------------------------------------------------- - -ACTOR AlienSpectre4 : AlienSpectre1 -{ - Health 1700 - Painchance 50 - Radius 24 - DropItem "Sigil4" - States - { - Missile: - ALN1 F 4 A_FaceTarget - ALN1 I 4 A_CustomMissile("SpectralLightningBigV2", 32, 0) - ALN1 E 4 - Goto See+10 - } -} - - -// Alien Spectre 5 ----------------------------------------------------------- - -ACTOR AlienSpectre5 : AlienSpectre1 -{ - Health 2000 - Painchance 50 - Radius 24 - DropItem "Sigil5" - States - { - Missile: - ALN1 F 4 A_FaceTarget - ALN1 I 4 A_CustomMissile("SpectralLightningBigBall2", 32, 0) - ALN1 E 4 - Goto See+10 - } -} - -// Small Alien Chunk -------------------------------------------------------- - -ACTOR AlienChunkSmall -{ - +NOBLOCKMAP - +NOCLIP - States - { - Spawn: - NODE ABCDEFG 6 Bright - Stop - } -} - -// Large Alien Chunk -------------------------------------------------------- - -ACTOR AlienChunkLarge -{ - +NOBLOCKMAP - +NOCLIP - States - { - Spawn: - MTHD ABCDEFGHIJK 5 Bright - Stop - } -} - diff --git a/wadsrc/static/actors/strife/beggars.txt b/wadsrc/static/actors/strife/beggars.txt deleted file mode 100644 index eca6e67f44..0000000000 --- a/wadsrc/static/actors/strife/beggars.txt +++ /dev/null @@ -1,87 +0,0 @@ - -// Base class for the beggars --------------------------------------------- - -ACTOR Beggar : StrifeHumanoid -{ - Health 20 - PainChance 250 - Speed 3 - Radius 20 - Height 56 - Monster - +JUSTHIT - -COUNTKILL - +NOSPLASHALERT - MinMissileChance 150 - Tag "$TAG_BEGGAR" - MaxStepHeight 16 - MaxDropoffHeight 32 - HitObituary "$OB_BEGGAR" - - AttackSound "beggar/attack" - PainSound "beggar/pain" - DeathSound "beggar/death" - States - { - Spawn: - BEGR A 10 A_Look - Loop - See: - BEGR AABBCC 4 A_Wander - Loop - Melee: - BEGR D 8 - BEGR D 8 A_CustomMeleeAttack(2*random[PeasantAttack](1,5)+2) - BEGR E 1 A_Chase - BEGR D 8 A_SentinelRefire - Loop - Pain: - BEGR A 3 A_Pain - BEGR A 3 A_Chase - Goto Melee - Death: - BEGR F 4 - BEGR G 4 A_Scream - BEGR H 4 - BEGR I 4 A_NoBlocking - BEGR JKLM 4 - BEGR N -1 - Stop - XDeath: - BEGR F 5 A_TossGib - GIBS M 5 A_TossGib - GIBS N 5 A_XScream - GIBS O 5 A_NoBlocking - GIBS PQRST 4 A_TossGib - GIBS U 5 - GIBS V 1400 - Stop - } -} - - -// Beggars ----------------------------------------------------------------- - -ACTOR Beggar1 : Beggar -{ -} - - -ACTOR Beggar2 : Beggar -{ -} - - -ACTOR Beggar3 : Beggar -{ -} - - -ACTOR Beggar4 : Beggar -{ -} - - -ACTOR Beggar5 : Beggar -{ -} diff --git a/wadsrc/static/actors/strife/coin.txt b/wadsrc/static/actors/strife/coin.txt deleted file mode 100644 index b410d25a17..0000000000 --- a/wadsrc/static/actors/strife/coin.txt +++ /dev/null @@ -1,84 +0,0 @@ - -// Coin --------------------------------------------------------------------- - -ACTOR Coin : Inventory native -{ - +DROPPED - +NOTDMATCH - +FLOORCLIP - Inventory.MaxAmount 0x7fffffff - +INVENTORY.INVBAR - Tag "$TAG_COIN" - Inventory.Icon "I_COIN" - Inventory.PickupMessage "$TXT_COIN" - States - { - Spawn: - COIN A -1 - Stop - } -} - - -// 10 Gold ------------------------------------------------------------------ - -ACTOR Gold10 : Coin -{ - Inventory.Amount 10 - Tag "$TAG_10GOLD" - Inventory.PickupMessage "$TXT_10GOLD" - States - { - Spawn: - CRED A -1 - Stop - } -} - -// 25 Gold ------------------------------------------------------------------ - -ACTOR Gold25 : Coin -{ - Inventory.Amount 25 - Tag "$TAG_25GOLD" - Inventory.PickupMessage "$TXT_25GOLD" - States - { - Spawn: - SACK A -1 - Stop - } -} - -// 50 Gold ------------------------------------------------------------------ - -ACTOR Gold50 : Coin -{ - Inventory.Amount 50 - Tag "$TAG_50GOLD" - Inventory.PickupMessage "$TXT_50GOLD" - States - { - Spawn: - CHST A -1 - Stop - } -} - -// 300 Gold ------------------------------------------------------------------ - -ACTOR Gold300 : Coin -{ - Inventory.Amount 300 - Tag "$TAG_300GOLD" - Inventory.PickupMessage "$TXT_300GOLD" - Inventory.GiveQuest 3 - +INVENTORY.ALWAYSPICKUP - States - { - Spawn: - TOKN A -1 - Stop - } -} - diff --git a/wadsrc/static/actors/strife/crusader.txt b/wadsrc/static/actors/strife/crusader.txt deleted file mode 100644 index c397474716..0000000000 --- a/wadsrc/static/actors/strife/crusader.txt +++ /dev/null @@ -1,122 +0,0 @@ - -// Crusader ----------------------------------------------------------------- - -ACTOR Crusader -{ - Speed 8 - Radius 40 - Height 56 - Mass 400 - Health 400 - Painchance 128 - Monster - +FLOORCLIP - +DONTMORPH - +MISSILEMORE - +INCOMBAT - +NOICEDEATH - +NOBLOOD - MinMissileChance 120 - MaxDropoffHeight 32 - DropItem "EnergyPod", 256, 20 - SeeSound "crusader/sight" - PainSound "crusader/pain" - DeathSound "crusader/death" - ActiveSound "crusader/active" - Obituary "$OB_CRUSADER" - - action native A_CrusaderChoose (); - action native A_CrusaderSweepLeft (); - action native A_CrusaderSweepRight (); - action native A_CrusaderRefire (); - action native A_CrusaderDeath (); - - States - { - Spawn: - ROB2 Q 10 A_Look - Loop - See: - ROB2 AABBCCDD 3 A_Chase - Loop - Missile: - ROB2 E 3 Slow A_FaceTarget - ROB2 F 2 Slow Bright A_CrusaderChoose - ROB2 E 2 Slow Bright A_CrusaderSweepLeft - ROB2 F 3 Slow Bright A_CrusaderSweepLeft - ROB2 EF 2 Slow Bright A_CrusaderSweepLeft - ROB2 EFE 2 Slow Bright A_CrusaderSweepRight - ROB2 F 2 Slow A_CrusaderRefire - Loop - Pain: - ROB2 D 1 Slow A_Pain - Goto See - Death: - ROB2 G 3 A_Scream - ROB2 H 5 A_TossGib - ROB2 I 4 Bright A_TossGib - ROB2 J 4 Bright A_Explode(64,64,1,1) - ROB2 K 4 Bright A_Fall - ROB2 L 4 A_Explode(64,64,1,1) - ROB2 MN 4 A_TossGib - ROB2 O 4 A_Explode(64,64,1,1) - ROB2 P -1 A_CrusaderDeath - Stop - } -} - - -// Fast Flame Projectile (used by Crusader) --------------------------------- - -ACTOR FastFlameMissile : FlameMissile -{ - Mass 50 - Damage 1 - Speed 35 -} - -// Crusader Missile --------------------------------------------------------- -// This is just like the mini missile the player shoots, except it doesn't -// explode when it dies, and it does slightly less damage for a direct hit. - -ACTOR CrusaderMissile -{ - Speed 20 - Radius 10 - Height 14 - Damage 7 - Projectile - +STRIFEDAMAGE - MaxStepHeight 4 - SeeSound "crusader/misl" - DeathSound "crusader/mislx" - States - { - Spawn: - MICR A 6 Bright A_RocketInFlight - Loop - Death: - SMIS A 0 Bright A_SetTranslucent(1,1) - SMIS A 5 Bright - SMIS B 5 Bright - SMIS C 4 Bright - SMIS DEFG 2 Bright - Stop - } -} - - -// Dead Crusader ------------------------------------------------------------ - -ACTOR DeadCrusader -{ - States - { - Spawn: - ROB2 N 4 - ROB2 O 4 - ROB2 P -1 - Stop - } -} - diff --git a/wadsrc/static/actors/strife/entityboss.txt b/wadsrc/static/actors/strife/entityboss.txt deleted file mode 100644 index ddd19d9efb..0000000000 --- a/wadsrc/static/actors/strife/entityboss.txt +++ /dev/null @@ -1,199 +0,0 @@ - -// Entity Nest -------------------------------------------------------------- - -ACTOR EntityNest -{ - Radius 84 - Height 47 - +SOLID - +NOTDMATCH - +FLOORCLIP - States - { - Spawn: - NEST A -1 - Stop - } -} - -// Entity Pod --------------------------------------------------------------- - -ACTOR EntityPod -{ - Radius 25 - Height 91 - +SOLID - +NOTDMATCH - SeeSound "misc/gibbed" - - action native A_SpawnEntity (); - - States - { - Spawn: - PODD A 60 A_Look - Loop - See: - PODD A 360 - PODD B 9 A_NoBlocking - PODD C 9 - PODD D 9 A_SpawnEntity - PODD E -1 - Stop - } -} - - -// Entity Boss -------------------------------------------------------------- - -ACTOR EntityBoss : SpectralMonster -{ - Health 2500 - Painchance 255 - Speed 13 - Radius 130 - Height 200 - FloatSpeed 5 - Mass 1000 - Monster - +SPECIAL - +NOGRAVITY - +FLOAT - +SHADOW - +NOTDMATCH - +DONTMORPH - +NOTARGET - +NOBLOCKMONST - +INCOMBAT - +LOOKALLAROUND - +SPECTRAL - +NOICEDEATH - MinMissileChance 150 - RenderStyle Translucent - Alpha 0.5 - SeeSound "entity/sight" - AttackSound "entity/melee" - PainSound "entity/pain" - DeathSound "entity/death" - ActiveSound "entity/active" - Obituary "$OB_ENTITY" - - action native A_EntityAttack(); - action native A_EntityDeath(); - - States - { - Spawn: - MNAM A 100 - MNAM B 60 Bright - MNAM CDEFGHIJKL 4 Bright - MNAL A 4 Bright A_Look - MNAL B 4 Bright A_SentinelBob - Goto Spawn+12 - See: - MNAL AB 4 Bright A_Chase - MNAL C 4 Bright A_SentinelBob - MNAL DEF 4 Bright A_Chase - MNAL G 4 Bright A_SentinelBob - MNAL HIJ 4 Bright A_Chase - MNAL K 4 Bright A_SentinelBob - Loop - Melee: - MNAL J 4 Bright A_FaceTarget - MNAL I 4 Bright A_CustomMeleeAttack((random[SpectreMelee](0,255)&9)*5) - MNAL C 4 Bright - Goto See+2 - Missile: - MNAL F 4 Bright A_FaceTarget - MNAL I 4 Bright A_EntityAttack - MNAL E 4 Bright - Goto See+10 - Pain: - MNAL J 2 Bright A_Pain - Goto See+6 - Death: - MNAL L 7 Bright A_SpectreChunkSmall - MNAL M 7 Bright A_Scream - MNAL NO 7 Bright A_SpectreChunkSmall - MNAL P 7 Bright A_SpectreChunkLarge - MNAL Q 64 Bright A_SpectreChunkSmall - MNAL Q 6 Bright A_EntityDeath - Stop - } -} - -// Second Entity Boss ------------------------------------------------------- - -ACTOR EntitySecond : SpectralMonster -{ - Health 990 - Painchance 255 - Speed 14 - Radius 130 - Height 200 - FloatSpeed 5 - Mass 1000 - Monster - +SPECIAL - +NOGRAVITY - +FLOAT - +SHADOW - +NOTDMATCH - +DONTMORPH - +NOBLOCKMONST - +INCOMBAT - +LOOKALLAROUND - +SPECTRAL - +NOICEDEATH - MinMissileChance 150 - RenderStyle Translucent - Alpha 0.25 - SeeSound "alienspectre/sight" - AttackSound "alienspectre/blade" - PainSound "alienspectre/pain" - DeathSound "alienspectre/death" - ActiveSound "alienspectre/active" - Obituary "$OB_ENTITY" - - action native A_SubEntityDeath (); - - States - { - Spawn: - MNAL R 10 Bright A_Look - Loop - See: - MNAL R 5 Bright A_SentinelBob - MNAL ST 5 Bright A_Chase - MNAL U 5 Bright A_SentinelBob - MNAL V 5 Bright A_Chase - MNAL W 5 Bright A_SentinelBob - Loop - Melee: - MNAL S 4 Bright A_FaceTarget - MNAL R 4 Bright A_CustomMeleeAttack((random[SpectreMelee](0,255)&9)*5) - MNAL T 4 Bright A_SentinelBob - Goto See+1 - Missile: - MNAL W 4 Bright A_FaceTarget - MNAL U 4 Bright A_CustomMissile("SpectralLightningH3",32,0) - MNAL V 4 Bright A_SentinelBob - Goto See+4 - Pain: - MNAL R 2 Bright A_Pain - Goto See - Death: - MDTH A 3 Bright A_Scream - MDTH B 3 Bright A_TossGib - MDTH C 3 Bright A_NoBlocking - MDTH DEFGHIJKLMN 3 Bright A_TossGib - MDTH O 3 Bright A_SubEntityDeath - Stop - } -} - - - - - - diff --git a/wadsrc/static/actors/strife/inquisitor.txt b/wadsrc/static/actors/strife/inquisitor.txt deleted file mode 100644 index 5b9495d40f..0000000000 --- a/wadsrc/static/actors/strife/inquisitor.txt +++ /dev/null @@ -1,141 +0,0 @@ - -// Inquisitor --------------------------------------------------------------- - -ACTOR Inquisitor -{ - Health 1000 - Speed 12 - Radius 40 - Height 110 - Mass 0x7fffffff - Monster - +DROPOFF - +NOBLOOD - +BOSS - +FLOORCLIP - +DONTMORPH - +NORADIUSDMG - MaxDropOffHeight 32 - MinMissileChance 150 - SeeSound "inquisitor/sight" - DeathSound "inquisitor/death" - ActiveSound "inquisitor/active" - Obituary "$OB_INQUISITOR" - - action native A_InquisitorWalk (); - action native A_InquisitorDecide (); - action native A_InquisitorAttack (); - action native A_InquisitorJump (); - action native A_InquisitorCheckLand (); - action native A_TossArm (); - action native A_ReaverRanged (); - - states - { - Spawn: - ROB3 AB 10 A_Look - Loop - See: - ROB3 B 3 A_InquisitorWalk - ROB3 B 3 A_Chase - ROB3 CCDD 4 A_Chase - ROB3 E 3 A_InquisitorWalk - ROB3 E 3 A_InquisitorDecide - Loop - Missile: - ROB3 A 2 A_InquisitorDecide - ROB3 F 6 A_FaceTarget - ROB3 G 8 Bright A_ReaverRanged - ROB3 G 8 A_ReaverRanged - Goto See - Grenade: - ROB3 K 12 A_FaceTarget - ROB3 J 6 Bright A_InquisitorAttack - ROB3 K 12 - Goto See - Jump: - ROB3 H 8 Bright A_InquisitorJump - ROB3 I 4 Bright A_InquisitorCheckLand - ROB3 H 4 Bright A_InquisitorCheckLand - Goto Jump+1 - Death: - ROB3 L 0 A_StopSoundEx("Item") - ROB3 L 4 A_TossGib - ROB3 M 4 A_Scream - ROB3 N 4 A_TossGib - ROB3 O 4 Bright A_Explode(128,128,1,1) - ROB3 P 4 Bright A_TossGib - ROB3 Q 4 Bright A_NoBlocking - ROB3 RSTUV 4 A_TossGib - ROB3 W 4 Bright A_Explode(128,128,1,1) - ROB3 XY 4 Bright A_TossGib - ROB3 Z 4 A_TossGib - ROB3 "[" 4 A_TossGib - ROB3 "\" 3 A_TossGib - ROB3 "]" 3 Bright A_Explode(128,128,1,1) - RBB3 A 3 Bright A_TossArm - RBB3 B 3 Bright A_TossGib - RBB3 CD 3 A_TossGib - RBB3 E -1 - Stop - } -} - -// Inquisitor Shot ---------------------------------------------------------- - -ACTOR InquisitorShot -{ - ReactionTime 15 - Speed 25 - Radius 13 - Height 13 - Mass 15 - Projectile - -ACTIVATEIMPACT - -ACTIVATEPCROSS - -NOGRAVITY - +STRIFEDAMAGE - MaxStepHeight 4 - SeeSound "inquisitor/attack" - DeathSound "inquisitor/atkexplode" - States - { - Spawn: - UBAM AB 3 A_Countdown - Loop - Death: - BNG2 A 0 Bright A_SetTranslucent(1,1) - BNG2 A 4 Bright A_Explode(192, 192, 1, 1) - BNG2 B 4 Bright - BNG2 C 4 Bright - BNG2 D 4 Bright - BNG2 E 4 Bright - BNG2 F 4 Bright - BNG2 G 4 Bright - BNG2 H 4 Bright - BNG2 I 4 Bright - Stop - } - -} - - -// The Dead Inquisitor's Detached Arm --------------------------------------- - -ACTOR InquisitorArm -{ - Speed 25 - +NOBLOCKMAP - +NOCLIP - +NOBLOOD - States - { - Spawn: - RBB3 FG 5 Bright - RBB3 H -1 - Stop - } -} - - - diff --git a/wadsrc/static/actors/strife/loremaster.txt b/wadsrc/static/actors/strife/loremaster.txt deleted file mode 100644 index fd2b400cb8..0000000000 --- a/wadsrc/static/actors/strife/loremaster.txt +++ /dev/null @@ -1,114 +0,0 @@ - -// Loremaster (aka Priest) -------------------------------------------------- - -ACTOR Loremaster -{ - Health 800 - Speed 10 - Radius 15 - Height 56 - FloatSpeed 5 - Monster - +FLOAT - +NOBLOOD - +NOGRAVITY - +NOTDMATCH - +FLOORCLIP - +NOBLOCKMONST - +INCOMBAT - +LOOKALLAROUND - +NOICEDEATH - +NEVERRESPAWN - DamageFactor "Fire", 0.5 - MinMissileChance 150 - Tag "$TAG_PRIEST" - SeeSound "loremaster/sight" - AttackSound "loremaster/attack" - PainSound "loremaster/pain" - DeathSound "loremaster/death" - ActiveSound "loremaster/active" - Obituary "$OB_LOREMASTER" - DropItem "Junk" - states - { - Spawn: - PRST A 10 A_Look - PRST B 10 A_SentinelBob - Loop - See: - PRST A 4 A_Chase - PRST A 4 A_SentinelBob - PRST B 4 A_Chase - PRST B 4 A_SentinelBob - PRST C 4 A_Chase - PRST C 4 A_SentinelBob - PRST D 4 A_Chase - PRST D 4 A_SentinelBob - Loop - Melee: - PRST E 4 A_FaceTarget - PRST F 4 A_CustomMeleeAttack((random[SpectreMelee](0,255)&9)*5) - PRST E 4 A_SentinelBob - Goto See - Missile: - PRST E 4 A_FaceTarget - PRST F 4 A_CustomMissile("LoreShot", 32, 0) - PRST E 4 A_SentinelBob - Goto See - Death: - PDED A 6 - PDED B 6 A_Scream - PDED C 6 - PDED D 6 A_Fall - PDED E 6 - PDED FGHIJIJIJKL 5 - PDED MNOP 4 - PDED Q 4 A_SpawnItemEx("AlienSpectre5", 0, 0, 0, 0, 0, random[spectrespawn](0,255)*0.0078125, 0, SXF_NOCHECKPOSITION) - PDED RS 4 - PDED T -1 - Stop - } -} - - -// Loremaster Projectile ---------------------------------------------------- - -ACTOR LoreShot native -{ - Speed 20 - Height 14 - Radius 10 - Projectile - +STRIFEDAMAGE - Damage 2 - MaxStepHeight 4 - SeeSound "loremaster/chain" - ActiveSound "loremaster/swish" - - action native A_LoremasterChain (); - - States - { - Spawn: - OCLW A 2 A_LoremasterChain - Loop - Death: - OCLW A 6 - Stop - } -} - -// Loremaster Subprojectile ------------------------------------------------- - -ACTOR LoreShot2 -{ - +NOBLOCKMAP - +NOGRAVITY - States - { - Spawn: - TEND A 20 - Stop - } -} - diff --git a/wadsrc/static/actors/strife/macil.txt b/wadsrc/static/actors/strife/macil.txt deleted file mode 100644 index 7c03d1f24b..0000000000 --- a/wadsrc/static/actors/strife/macil.txt +++ /dev/null @@ -1,89 +0,0 @@ - -// Macil (version 1) --------------------------------------------------------- - -ACTOR Macil1 -{ - Health 95 - Radius 20 - Height 56 - Speed 8 - Painchance 250 - Monster - -COUNTKILL - +NOTDMATCH - +NOICEDEATH - +NOSPLASHALERT - +NODAMAGE - +NEVERRESPAWN - DamageFactor "Fire", 0.5 - MinMissileChance 150 - SeeSound "macil/sight" - PainSound "macil/pain" - ActiveSound "macil/active" - CrushPainSound "misc/pcrush" - Tag "$TAG_MACIL1" - Obituary "$OB_MACIL" - DropItem "BoxOfBullets" - MaxStepHeight 16 - MaxDropoffHeight 32 - States - { - Spawn: - LEDR C 5 A_Look2 - Loop - LEDR A 8 - Loop - LEDR B 8 - Loop - LEAD ABCD 6 A_Wander - Loop - See: - LEAD AABBCCDD 3 A_Chase - Loop - Missile: - Death: - LEAD E 2 A_FaceTarget - LEAD F 2 BRIGHT A_ShootGun - LEAD E 1 A_SentinelRefire - Loop - Pain: - LEAD Y 3 - LEAD Y 3 A_Pain - Goto See - } -} - - -// Macil (version 2) --------------------------------------------------------- - -ACTOR Macil2 : Macil1 -{ - Painchance 200 - +COUNTKILL - +SPECTRAL - -NODAMAGE - Tag "$TAG_MACIL2" - DeathSound "macil/slop" - DropItem "None" - DamageFactor "SpectralLow", 0 - States - { - Missile: - LEAD E 4 A_FaceTarget - LEAD F 4 BRIGHT A_ShootGun - LEAD E 2 A_SentinelRefire - Loop - Death: - LEAD G 5 - LEAD H 5 A_Scream - LEAD IJ 4 - LEAD K 3 - LEAD L 3 A_NoBlocking - LEAD MNOPQRSTUV 3 - LEAD W 3 A_SpawnItemEx("AlienSpectre4", 0, 0, 0, 0, 0, random[spectrespawn](0,255)*0.0078125, 0, SXF_NOCHECKPOSITION) - LEAD X -1 - Stop - } -} - - diff --git a/wadsrc/static/actors/strife/merchants.txt b/wadsrc/static/actors/strife/merchants.txt deleted file mode 100644 index 1a843f47a3..0000000000 --- a/wadsrc/static/actors/strife/merchants.txt +++ /dev/null @@ -1,93 +0,0 @@ -// Base class for the merchants --------------------------------------------- - -ACTOR Merchant -{ - Health 10000000 - PainChance 256 // a merchant should always enter the pain state when getting hurt - Radius 20 - Height 56 - Mass 5000 - CrushPainSound "misc/pcrush" - +SOLID - +SHOOTABLE - +NOTDMATCH - +NOSPLASHALERT - +NODAMAGE - States - { - Spawn: - MRST A 10 A_Look2 - Loop - MRLK A 30 A_ActiveSound - Loop - MRLK B 30 - Loop - MRBD ABCDEDCB 4 - MRBD A 5 - MRBD F 6 - Loop - See: - Pain: - MRPN A 1 - MRPN A 2 A_AlertMonsters - MRPN B 3 A_Pain - MRPN C 3 - MRPN D 9 Door_CloseWaitOpen(999, 64, 960) - MRPN C 4 - MRPN B 3 - MRPN A 3 A_ClearSoundTarget - Goto Spawn - Yes: - MRYS A 20 - // Fall through - Greetings: - MRGT ABCDEFGHI 5 - Goto Spawn - No: - MRNO AB 6 - MRNO C 10 - MRNO BA 6 - Goto Greetings - } -} - - -// Weapon Smith ------------------------------------------------------------- - -ACTOR WeaponSmith : Merchant -{ - PainSound "smith/pain" - Tag "$TAG_WEAPONSMITH" -} - - -// Bar Keep ----------------------------------------------------------------- - -ACTOR BarKeep : Merchant -{ - Translation 4 - PainSound "barkeep/pain" - ActiveSound "barkeep/active" - Tag "$TAG_BARKEEP" -} - - -// Armorer ------------------------------------------------------------------ - -ACTOR Armorer : Merchant -{ - Translation 5 - PainSound "armorer/pain" - Tag "$TAG_ARMORER" -} - - -// Medic -------------------------------------------------------------------- - -ACTOR Medic : Merchant -{ - Translation 6 - PainSound "medic/pain" - Tag "$TAG_MEDIC" -} - diff --git a/wadsrc/static/actors/strife/oracle.txt b/wadsrc/static/actors/strife/oracle.txt deleted file mode 100644 index 8502bae96b..0000000000 --- a/wadsrc/static/actors/strife/oracle.txt +++ /dev/null @@ -1,35 +0,0 @@ - -// Oracle ------------------------------------------------------------------- - -ACTOR Oracle -{ - Health 1 - Radius 15 - Height 56 - Monster - +NOTDMATCH - +NOBLOOD - +NEVERRESPAWN - DamageFactor "Fire", 0.5 - DamageFactor "SpectralLow", 0 - MaxDropoffHeight 32 - Tag "$TAG_ORACLE" - DropItem "Meat" - - action native A_WakeOracleSpectre (); - - States - { - Spawn: - ORCL A -1 - Stop - Death: - ORCL BCDEFGHIJK 5 - ORCL L 5 A_NoBlocking - ORCL M 5 - ORCL N 5 A_WakeOracleSpectre - ORCL OP 5 - ORCL Q -1 - Stop - } -} diff --git a/wadsrc/static/actors/strife/peasants.txt b/wadsrc/static/actors/strife/peasants.txt deleted file mode 100644 index b5ec89258c..0000000000 --- a/wadsrc/static/actors/strife/peasants.txt +++ /dev/null @@ -1,182 +0,0 @@ - -// Peasant Base Class ------------------------------------------------------- - -ACTOR Peasant : StrifeHumanoid -{ - Health 31 - PainChance 200 - Speed 8 - Radius 20 - Height 56 - Monster - +NEVERTARGET - -COUNTKILL - +NOSPLASHALERT - +FLOORCLIP - +JUSTHIT - MinMissileChance 150 - MaxStepHeight 16 - MaxDropoffHeight 32 - SeeSound "peasant/sight" - AttackSound "peasant/attack" - PainSound "peasant/pain" - DeathSound "peasant/death" - HitObituary "$OB_PEASANT" - States - { - Spawn: - PEAS A 10 A_Look2 - Loop - See: - PEAS AABBCCDD 5 A_Wander - Goto Spawn - Melee: - PEAS E 10 A_FaceTarget - PEAS F 8 A_CustomMeleeAttack(2*random[PeasantAttack](1,5)+2) - PEAS E 8 - Goto See - Pain: - PEAS O 3 - PEAS O 3 A_Pain - Goto Melee - Wound: - PEAS G 5 - PEAS H 10 A_GetHurt - PEAS I 6 - Goto Wound+1 - Death: - PEAS G 5 - PEAS H 5 A_Scream - PEAS I 6 - PEAS J 5 A_NoBlocking - PEAS K 5 - PEAS L 6 - PEAS M 8 - PEAS N 1400 - GIBS U 5 - GIBS V 1400 - Stop - XDeath: - GIBS M 5 A_TossGib - GIBS N 5 A_XScream - GIBS O 5 A_NoBlocking - GIBS PQRS 4 A_TossGib - Goto Death+8 - } -} - -// Peasant Variant 1 -------------------------------------------------------- - -ACTOR Peasant1 : Peasant -{ - Speed 4 -} - -ACTOR Peasant2 : Peasant -{ - Speed 5 -} - -ACTOR Peasant3 : Peasant -{ - Speed 5 -} - -ACTOR Peasant4 : Peasant -{ - Translation 0 - Speed 7 -} - -ACTOR Peasant5 : Peasant -{ - Translation 0 - Speed 7 -} - -ACTOR Peasant6 : Peasant -{ - Translation 0 - Speed 7 -} - -ACTOR Peasant7 : Peasant -{ - Translation 2 -} - -ACTOR Peasant8 : Peasant -{ - Translation 2 -} - -ACTOR Peasant9 : Peasant -{ - Translation 2 -} - -ACTOR Peasant10 : Peasant -{ - Translation 1 -} - -ACTOR Peasant11 : Peasant -{ - Translation 1 -} - -ACTOR Peasant12 : Peasant -{ - Translation 1 -} - -ACTOR Peasant13 : Peasant -{ - Translation 3 -} - -ACTOR Peasant14 : Peasant -{ - Translation 3 -} - -ACTOR Peasant15 : Peasant -{ - Translation 3 -} - -ACTOR Peasant16 : Peasant -{ - Translation 5 -} - -ACTOR Peasant17 : Peasant -{ - Translation 5 -} - -ACTOR Peasant18 : Peasant -{ - Translation 5 -} - -ACTOR Peasant19 : Peasant -{ - Translation 4 -} - -ACTOR Peasant20 : Peasant -{ - Translation 4 -} - -ACTOR Peasant21 : Peasant -{ - Translation 4 -} - -ACTOR Peasant22 : Peasant -{ - Translation 6 -} - diff --git a/wadsrc/static/actors/strife/programmer.txt b/wadsrc/static/actors/strife/programmer.txt deleted file mode 100644 index d9544af9c2..0000000000 --- a/wadsrc/static/actors/strife/programmer.txt +++ /dev/null @@ -1,107 +0,0 @@ - -// Programmer --------------------------------------------------------------- - -ACTOR Programmer -{ - Health 1100 - PainChance 50 - Speed 26 - FloatSpeed 5 - Radius 45 - Height 60 - Mass 800 - Damage 4 - Monster - +NOGRAVITY - +FLOAT - +NOBLOOD - +NOTDMATCH - +DONTMORPH - +NOBLOCKMONST - +LOOKALLAROUND - +NOICEDEATH - +NOTARGETSWITCH - DamageFactor "Fire", 0.5 - MinMissileChance 150 - AttackSound "programmer/attack" - PainSound "programmer/pain" - DeathSound "programmer/death" - ActiveSound "programmer/active" - Obituary "$OB_PROGRAMMER" - DropItem "Sigil1" - - action native A_ProgrammerMelee (); - action native A_SpawnProgrammerBase (); - action native A_ProgrammerDeath (); - action native A_SpotLightning(); - - States - { - Spawn: - PRGR A 5 A_Look - PRGR A 1 A_SentinelBob - Loop - See: - PRGR A 160 A_SentinelBob - PRGR BCD 5 A_SentinelBob - PRGR EF 2 A_SentinelBob - PRGR EF 3 A_Chase - Goto See+4 - Melee: - PRGR E 2 A_SentinelBob - PRGR F 3 A_SentinelBob - PRGR E 3 A_FaceTarget - PRGR F 4 A_ProgrammerMelee - Goto See+4 - Missile: - PRGR G 5 A_FaceTarget - PRGR H 5 A_SentinelBob - PRGR I 5 Bright A_FaceTarget - PRGR J 5 Bright A_SpotLightning - Goto See+4 - Pain: - PRGR K 5 A_Pain - PRGR L 5 A_SentinelBob - Goto See+4 - Death: - PRGR L 7 Bright A_TossGib - PRGR M 7 Bright A_Scream - PRGR N 7 Bright A_TossGib - PRGR O 7 Bright A_NoBlocking - PRGR P 7 Bright A_TossGib - PRGR Q 7 Bright A_SpawnProgrammerBase - PRGR R 7 Bright - PRGR S 6 Bright - PRGR TUVW 5 Bright - PRGR X 32 Bright - PRGR X -1 Bright A_ProgrammerDeath - Stop - } -} - - -// The Programmer's base for when he dies ----------------------------------- - -ACTOR ProgrammerBase -{ - +NOBLOCKMAP - +NOCLIP - +NOBLOOD - states - { - Spawn: - BASE A 5 Bright A_Explode(32,32,1,1) - BASE BCD 5 Bright - BASE EFG 5 - BASE H -1 - Stop - } -} - - -// The Programmer level ending thing ---------------------------------------- - -ACTOR ProgLevelEnder : Inventory native -{ - +INVENTORY.UNDROPPABLE -} diff --git a/wadsrc/static/actors/strife/ratbuddy.txt b/wadsrc/static/actors/strife/ratbuddy.txt deleted file mode 100644 index c6a1baf9c6..0000000000 --- a/wadsrc/static/actors/strife/ratbuddy.txt +++ /dev/null @@ -1,34 +0,0 @@ - -ACTOR RatBuddy -{ - Health 5 - Speed 13 - Radius 10 - Height 16 - +NOBLOOD +FLOORCLIP +CANPASS - +ISMONSTER +INCOMBAT - MinMissileChance 150 - MaxStepHeight 16 - MaxDropoffHeight 32 - Tag "$TAG_RATBUDDY" - SeeSound "rat/sight" - DeathSound "rat/death" - ActiveSound "rat/active" - States - { - Spawn: - RATT A 10 A_Look - Loop - See: - RATT AABB 4 A_Chase - Loop - Melee: - RATT A 8 A_Wander - RATT B 4 A_Wander - Goto See - Death: - MEAT Q 700 - Stop - } -} - diff --git a/wadsrc/static/actors/strife/reaver.txt b/wadsrc/static/actors/strife/reaver.txt deleted file mode 100644 index 816070d475..0000000000 --- a/wadsrc/static/actors/strife/reaver.txt +++ /dev/null @@ -1,64 +0,0 @@ - -ACTOR Reaver -{ - Health 150 - Painchance 128 - Speed 12 - Radius 20 - Height 60 - Monster - +NOBLOOD - +INCOMBAT - MinMissileChance 150 - MaxDropoffHeight 32 - Mass 500 - SeeSound "reaver/sight" - PainSound "reaver/pain" - DeathSound "reaver/death" - ActiveSound "reaver/active" - HitObituary "$OB_REAVERHIT" - Obituary "$OB_REAVER" - - action native A_ReaverRanged (); - - States - { - Spawn: - ROB1 A 10 A_Look - Loop - See: - ROB1 BBCCDDEE 3 A_Chase - Loop - Melee: - ROB1 H 6 Slow A_FaceTarget - ROB1 I 8 Slow A_CustomMeleeAttack(random[ReaverMelee](1,8)*3, "reaver/blade") - ROB1 H 6 Slow - Goto See - Missile: - ROB1 F 8 Slow A_FaceTarget - ROB1 G 11 Slow BRIGHT A_ReaverRanged - Goto See - Pain: - ROB1 A 2 Slow - ROB1 A 2 A_Pain - Goto See - Death: - ROB1 J 6 - ROB1 K 6 A_Scream - ROB1 L 5 - ROB1 M 5 A_NoBlocking - ROB1 NOP 5 - ROB1 Q 6 A_Explode(32,32,1,1) - ROB1 R -1 - Stop - XDeath: - ROB1 L 5 A_TossGib - ROB1 M 5 A_Scream - ROB1 N 5 A_TossGib - ROB1 O 5 A_NoBlocking - ROB1 P 5 A_TossGib - Goto Death+7 - } - -} - \ No newline at end of file diff --git a/wadsrc/static/actors/strife/rebels.txt b/wadsrc/static/actors/strife/rebels.txt deleted file mode 100644 index 2dcb5ac1ad..0000000000 --- a/wadsrc/static/actors/strife/rebels.txt +++ /dev/null @@ -1,131 +0,0 @@ - - -// Base class for the rebels ------------------------------------------------ - -ACTOR Rebel : StrifeHumanoid -{ - Health 60 - Painchance 250 - Speed 8 - Radius 20 - Height 56 - Monster - +FRIENDLY - -COUNTKILL - +NOSPLASHALERT - MinMissileChance 150 - Tag "$TAG_REBEL" - SeeSound "rebel/sight" - PainSound "rebel/pain" - DeathSound "rebel/death" - ActiveSound "rebel/active" - Obituary "$OB_REBEL" - States - { - Spawn: - HMN1 P 5 A_Look2 - Loop - HMN1 Q 8 - Loop - HMN1 R 8 - Loop - HMN1 ABCDABCD 6 A_Wander - Loop - See: - HMN1 AABBCCDD 3 A_Chase - Loop - Missile: - HMN1 E 10 A_FaceTarget - HMN1 F 10 BRIGHT A_ShootGun - HMN1 E 10 A_ShootGun - Goto See - Pain: - HMN1 O 3 - HMN1 O 3 A_Pain - Goto See - Death: - HMN1 G 5 - HMN1 H 5 A_Scream - HMN1 I 3 A_NoBlocking - HMN1 J 4 - HMN1 KLM 3 - HMN1 N -1 - Stop - XDeath: - RGIB A 4 A_TossGib - RGIB B 4 A_XScream - RGIB C 3 A_NoBlocking - RGIB DEF 3 A_TossGib - RGIB G 3 - RGIB H 1400 - Stop - } -} - -// Rebel 1 ------------------------------------------------------------------ - -ACTOR Rebel1 : Rebel -{ - DropItem "ClipOfBullets" -} - -// Rebel 2 ------------------------------------------------------------------ - -ACTOR Rebel2 : Rebel -{ -} - -// Rebel 3 ------------------------------------------------------------------ - -ACTOR Rebel3 : Rebel -{ -} - -// Rebel 4 ------------------------------------------------------------------ - -ACTOR Rebel4 : Rebel -{ -} - -// Rebel 5 ------------------------------------------------------------------ - -ACTOR Rebel5 : Rebel -{ -} - -// Rebel 6 ------------------------------------------------------------------ - -ACTOR Rebel6 : Rebel -{ -} - -// Teleporter Beacon -------------------------------------------------------- - -ACTOR TeleporterBeacon : Inventory native -{ - Health 5 - Radius 16 - Height 16 - Inventory.MaxAmount 3 - +DROPPED - +INVENTORY.INVBAR - Inventory.Icon "I_BEAC" - Tag "$TAG_TELEPORTERBEACON" - Inventory.PickupMessage "$TXT_BEACON" - - action native A_Beacon (); - - States - { - Spawn: - BEAC A -1 - Stop - Drop: - BEAC A 30 - BEAC A 160 A_Beacon - Wait - Death: - BEAC A 1 A_FadeOut(0.015) - Loop - } -} \ No newline at end of file diff --git a/wadsrc/static/actors/strife/sentinel.txt b/wadsrc/static/actors/strife/sentinel.txt deleted file mode 100644 index ca61f2bf80..0000000000 --- a/wadsrc/static/actors/strife/sentinel.txt +++ /dev/null @@ -1,95 +0,0 @@ - -// Sentinel ----------------------------------------------------------------- - -ACTOR Sentinel -{ - Health 100 - Painchance 255 - Speed 7 - Radius 23 - Height 53 - Mass 300 - Monster - +SPAWNCEILING - +NOGRAVITY - +DROPOFF - +NOBLOOD - +NOBLOCKMONST - +INCOMBAT - +MISSILEMORE - +LOOKALLAROUND - +NEVERRESPAWN - MinMissileChance 150 - SeeSound "sentinel/sight" - DeathSound "sentinel/death" - ActiveSound "sentinel/active" - Obituary "$OB_SENTINEL" - - action native A_SentinelAttack (); - - States - { - Spawn: - SEWR A 10 A_Look - Loop - See: - SEWR A 6 A_SentinelBob - SEWR A 6 A_Chase - Loop - Missile: - SEWR B 4 A_FaceTarget - SEWR C 8 Bright A_SentinelAttack - SEWR C 4 Bright A_SentinelRefire - Goto Missile+1 - Pain: - SEWR D 5 A_Pain - Goto Missile+2 - Death: - SEWR D 7 A_Fall - SEWR E 8 Bright A_TossGib - SEWR F 5 Bright A_Scream - SEWR GH 4 Bright A_TossGib - SEWR I 4 - SEWR J 5 - Stop - } -} - -// Sentinel FX 1 ------------------------------------------------------------ - -ACTOR SentinelFX1 -{ - Speed 40 - Radius 10 - Height 8 - Damage 0 - DamageType Disintegrate - Projectile - +STRIFEDAMAGE - MaxStepHeight 4 - RenderStyle Add - States - { - Spawn: - SHT1 AB 4 - Loop - Death: - POW1 J 4 - Stop - } -} - -// Sentinel FX 2 ------------------------------------------------------------ - -ACTOR SentinelFX2 : SentinelFX1 -{ - SeeSound "sentinel/plasma" - Damage 1 - States - { - Death: - POW1 FGHI 4 - Goto Super::Death - } -} - diff --git a/wadsrc/static/actors/strife/sigil.txt b/wadsrc/static/actors/strife/sigil.txt deleted file mode 100644 index 4c5f552d5f..0000000000 --- a/wadsrc/static/actors/strife/sigil.txt +++ /dev/null @@ -1,161 +0,0 @@ - -// The Almighty Sigil! ------------------------------------------------------ - -ACTOR Sigil : Weapon native -{ - - Weapon.Kickback 100 - Weapon.SelectionOrder 4000 - Health 1 - +FLOORCLIP - +WEAPON.CHEATNOTWEAPON - Inventory.PickupSound "weapons/sigilcharge" - Tag "$TAG_SIGIL" - Inventory.Icon "I_SGL1" - Inventory.PickupMessage "$TXT_SIGIL" - - action native A_SelectPiece (); - action native A_SelectSigilView (); - action native A_SelectSigilDown (); - action native A_SelectSigilAttack (); - action native A_SigilCharge (); - action native A_FireSigil1 (); - action native A_FireSigil2 (); - action native A_FireSigil3 (); - action native A_FireSigil4 (); - action native A_FireSigil5 (); - - States - { - Spawn: - SIGL A 1 - SIGL A -1 A_SelectPiece - Stop - SIGL B -1 - Stop - SIGL C -1 - Stop - SIGL D -1 - Stop - SIGL E -1 - Stop - Ready: - SIGH A 0 Bright A_SelectSigilView - Wait - SIGH A 1 Bright A_WeaponReady - Wait - SIGH B 1 Bright A_WeaponReady - Wait - SIGH C 1 Bright A_WeaponReady - Wait - SIGH D 1 Bright A_WeaponReady - Wait - SIGH E 1 Bright A_WeaponReady - Wait - Deselect: - SIGH A 1 Bright A_SelectSigilDown - Wait - SIGH A 1 Bright A_Lower - Wait - SIGH B 1 Bright A_Lower - Wait - SIGH C 1 Bright A_Lower - Wait - SIGH D 1 Bright A_Lower - Wait - SIGH E 1 Bright A_Lower - Wait - Select: - SIGH A 1 Bright A_SelectSigilView - Wait - SIGH A 1 Bright A_Raise - Wait - SIGH B 1 Bright A_Raise - Wait - SIGH C 1 Bright A_Raise - Wait - SIGH D 1 Bright A_Raise - Wait - SIGH E 1 Bright A_Raise - Wait - - Fire: - SIGH A 0 Bright A_SelectSigilAttack - - SIGH A 18 Bright A_SigilCharge - SIGH A 3 Bright A_GunFlash - SIGH A 10 A_FireSigil1 - SIGH A 5 - Goto Ready - - SIGH B 18 Bright A_SigilCharge - SIGH B 3 Bright A_GunFlash - SIGH B 10 A_FireSigil2 - SIGH B 5 - Goto Ready - - SIGH C 18 Bright A_SigilCharge - SIGH C 3 Bright A_GunFlash - SIGH C 10 A_FireSigil3 - SIGH C 5 - Goto Ready - - SIGH D 18 Bright A_SigilCharge - SIGH D 3 Bright A_GunFlash - SIGH D 10 A_FireSigil4 - SIGH D 5 - Goto Ready - - SIGH E 18 Bright A_SigilCharge - SIGH E 3 Bright A_GunFlash - SIGH E 10 A_FireSigil5 - SIGH E 5 - Goto Ready - Flash: - SIGF A 4 Bright A_Light2 - SIGF B 6 Bright A_LightInverse - SIGF C 4 Bright A_Light1 - SIGF C 0 Bright A_Light0 - Stop - } -} - -// Sigil 1 ------------------------------------------------------------------ - -ACTOR Sigil1 : Sigil -{ - Inventory.Icon "I_SGL1" - Health 1 -} - -// Sigil 2 ------------------------------------------------------------------ - -ACTOR Sigil2 : Sigil -{ - Inventory.Icon "I_SGL2" - Health 2 -} - -// Sigil 3 ------------------------------------------------------------------ - -ACTOR Sigil3 : Sigil -{ - Inventory.Icon "I_SGL3" - Health 3 -} - -// Sigil 4 ------------------------------------------------------------------ - -ACTOR Sigil4 : Sigil -{ - Inventory.Icon "I_SGL4" - Health 4 -} - -// Sigil 5 ------------------------------------------------------------------ - -ACTOR Sigil5 : Sigil -{ - Inventory.Icon "I_SGL5" - Health 5 -} diff --git a/wadsrc/static/actors/strife/spectral.txt b/wadsrc/static/actors/strife/spectral.txt deleted file mode 100644 index 6f9c87c0c0..0000000000 --- a/wadsrc/static/actors/strife/spectral.txt +++ /dev/null @@ -1,262 +0,0 @@ - - -// base for all spectral monsters which hurt when being touched-------------- - -ACTOR SpectralMonster native -{ - Monster - +SPECIAL - +SPECTRAL - +NOICEDEATH - - action native A_SpectreChunkSmall (); - action native A_SpectreChunkLarge (); - action native A_Spectre3Attack (); - action native A_SpotLightning (); -} - - -// Container for all spectral lightning deaths ------------------------------ - -ACTOR SpectralLightningBase -{ - +NOTELEPORT - +ACTIVATEIMPACT - +ACTIVATEPCROSS - +STRIFEDAMAGE - MaxStepHeight 4 - RenderStyle Add - SeeSound "weapons/sigil" - DeathSound "weapons/sigilhit" - States - { - Death: - ZAP1 B 3 A_Explode(32,32) - ZAP1 A 3 A_AlertMonsters - ZAP1 BCDEFE 3 - ZAP1 DCB 2 - ZAP1 A 1 - Stop - } -} - -// Spectral Lightning death that does not explode --------------------------- - -ACTOR SpectralLightningDeath1 : SpectralLightningBase -{ - States - { - Death: - Goto Super::Death+1 - } -} - -// Spectral Lightning death that does not alert monsters -------------------- - -ACTOR SpectralLightningDeath2 : SpectralLightningBase -{ - States - { - Death: - Goto Super::Death+2 - } -} - -// Spectral Lightning death that is shorter than the rest ------------------- - -ACTOR SpectralLightningDeathShort : SpectralLightningBase -{ - States - { - Death: - Goto Super::Death+6 - } -} - -// Spectral Lightning (Ball Shaped #1) -------------------------------------- - -ACTOR SpectralLightningBall1 : SpectralLightningBase -{ - Speed 30 - Radius 8 - Height 16 - Damage 70 - Projectile - +SPECTRAL - States - { - Spawn: - ZOT3 ABCDE 4 Bright - Loop - } -} - -// Spectral Lightning (Ball Shaped #2) -------------------------------------- - -ACTOR SpectralLightningBall2 : SpectralLightningBall1 -{ - Damage 20 -} - -// Spectral Lightning (Horizontal #1) --------------------------------------- - -ACTOR SpectralLightningH1 : SpectralLightningBase -{ - Speed 30 - Radius 8 - Height 16 - Damage 70 - Projectile - +SPECTRAL - - action native A_SpectralLightningTail (); - - States - { - Spawn: - ZAP6 A 4 Bright - ZAP6 BC 4 Bright A_SpectralLightningTail - Loop - } -} - - -// Spectral Lightning (Horizontal #2) ------------------------------------- - -ACTOR SpectralLightningH2 : SpectralLightningH1 -{ - Damage 20 -} - -// Spectral Lightning (Horizontal #3) ------------------------------------- - -ACTOR SpectralLightningH3 : SpectralLightningH1 -{ - Damage 10 -} - -// ASpectralLightningHTail -------------------------------------------------- - -ACTOR SpectralLightningHTail -{ - +NOBLOCKMAP - +NOGRAVITY - +DROPOFF - RenderStyle Add - States - { - Spawn: - ZAP6 ABC 5 Bright - Stop - } -} - -// Spectral Lightning (Big Ball #1) ----------------------------------------- - -ACTOR SpectralLightningBigBall1 : SpectralLightningDeath2 -{ - Speed 18 - Radius 20 - Height 40 - Damage 130 - Projectile - +SPECTRAL - - action native A_SpectralBigBallLightning (); - - States - { - Spawn: - ZAP7 AB 4 Bright A_SpectralBigBallLightning - ZAP7 CDE 6 Bright A_SpectralBigBallLightning - Loop - } -} - - -// Spectral Lightning (Big Ball #2 - less damaging) ------------------------- - -ACTOR SpectralLightningBigBall2 : SpectralLightningBigBall1 -{ - Damage 30 -} - -// Sigil Lightning (Vertical #1) -------------------------------------------- - -ACTOR SpectralLightningV1 : SpectralLightningDeathShort -{ - Speed 22 - Radius 8 - Height 24 - Damage 100 - Projectile - DamageType "SpectralLow" - +SPECTRAL - States - { - Spawn: - ZOT1 AB 4 Bright - ZOT1 CDE 6 Bright - Loop - } -} - -// Sigil Lightning (Vertical #2 - less damaging) ---------------------------- - -ACTOR SpectralLightningV2 : SpectralLightningV1 -{ - Damage 50 -} - -// Sigil Lightning Spot (roams around dropping lightning from above) -------- - -ACTOR SpectralLightningSpot : SpectralLightningDeath1 -{ - Speed 18 - ReactionTime 70 - +NOBLOCKMAP - +NOBLOCKMONST - +NODROPOFF - RenderStyle Translucent - Alpha 0.6 - - action native A_SpectralLightning (); - - States - { - Spawn: - ZAP5 A 4 Bright A_Countdown - ZAP5 B 4 Bright A_SpectralLightning - ZAP5 CD 4 Bright A_Countdown - Loop - } -} - -// Sigil Lightning (Big Vertical #1) ---------------------------------------- - -ACTOR SpectralLightningBigV1 : SpectralLightningDeath1 -{ - Speed 28 - Radius 8 - Height 16 - Damage 120 - Projectile - +SPECTRAL - States - { - Spawn: - ZOT2 ABCDE 4 Bright A_Tracer2 - Loop - } -} - -// Actor 90 ----------------------------------------------------------------- - -ACTOR SpectralLightningBigV2 : SpectralLightningBigV1 -{ - Damage 60 -} - - - - diff --git a/wadsrc/static/actors/strife/stalker.txt b/wadsrc/static/actors/strife/stalker.txt deleted file mode 100644 index 7f469e6103..0000000000 --- a/wadsrc/static/actors/strife/stalker.txt +++ /dev/null @@ -1,76 +0,0 @@ - - -// Stalker ------------------------------------------------------------------ - -ACTOR Stalker -{ - Health 80 - Painchance 40 - Speed 16 - Radius 31 - Height 25 - Monster - +NOGRAVITY - +DROPOFF - +NOBLOOD - +SPAWNCEILING - +INCOMBAT - +NOVERTICALMELEERANGE - MaxDropOffHeight 32 - MinMissileChance 150 - SeeSound "stalker/sight" - AttackSound "stalker/attack" - PainSound "stalker/pain" - DeathSound "stalker/death" - ActiveSound "stalker/active" - HitObituary "$OB_STALKER" - - action native A_StalkerLookInit (); - action native A_StalkerChaseDecide (); - action native A_StalkerWalk (); - action native A_StalkerDrop (); - action native A_StalkerAttack (); - - states - { - Spawn: - STLK A 1 A_StalkerLookInit - Loop - LookCeiling: - STLK A 10 A_Look - Loop - LookFloor: - STLK J 10 A_Look - Loop - See: - STLK A 1 Slow A_StalkerChaseDecide - STLK ABB 3 Slow A_Chase - STLK C 3 Slow A_StalkerWalk - STLK C 3 Slow A_Chase - Loop - Melee: - STLK J 3 Slow A_FaceTarget - STLK K 3 Slow A_StalkerAttack - SeeFloor: - STLK J 3 A_StalkerWalk - STLK KK 3 A_Chase - STLK L 3 A_StalkerWalk - STLK L 3 A_Chase - Loop - Pain: - STLK L 1 A_Pain - Goto See - Drop: - STLK C 2 A_StalkerDrop - STLK IHGFED 3 - Goto SeeFloor - Death: - STLK O 4 - STLK P 4 A_Scream - STLK QRST 4 - STLK U 4 A_NoBlocking - STLK VW 4 - STLK "XYZ[" 4 Bright - Stop - } -} diff --git a/wadsrc/static/actors/strife/strifeammo.txt b/wadsrc/static/actors/strife/strifeammo.txt deleted file mode 100644 index e432a71448..0000000000 --- a/wadsrc/static/actors/strife/strifeammo.txt +++ /dev/null @@ -1,202 +0,0 @@ -// HE-Grenade Rounds -------------------------------------------------------- - -ACTOR HEGrenadeRounds : Ammo -{ - +FLOORCLIP - Inventory.Amount 6 - Inventory.MaxAmount 30 - Ammo.BackpackAmount 6 - Ammo.BackpackMaxAmount 60 - Inventory.Icon "I_GRN1" - Tag "$TAG_HEGRENADES" - Inventory.PickupMessage "$TXT_HEGRENADES" - States - { - Spawn: - GRN1 A -1 - Stop - } -} - -// Phosphorus-Grenade Rounds ------------------------------------------------ - -ACTOR PhosphorusGrenadeRounds : Ammo -{ - +FLOORCLIP - Inventory.Amount 4 - Inventory.MaxAmount 16 - Ammo.BackpackAmount 4 - Ammo.BackpackMaxAmount 32 - Inventory.Icon "I_GRN2" - Tag "$TAG_PHGRENADES" - Inventory.PickupMessage "$TXT_PHGRENADES" - States - { - Spawn: - GRN2 A -1 - Stop - } -} - -// Clip of Bullets ---------------------------------------------------------- - -ACTOR ClipOfBullets : Ammo -{ - +FLOORCLIP - Inventory.Amount 10 - Inventory.MaxAmount 250 - Ammo.BackpackAmount 10 - Ammo.BackpackMaxAmount 500 - Inventory.Icon "I_BLIT" - Tag "$TAG_CLIPOFBULLETS" - Inventory.PickupMessage "$TXT_CLIPOFBULLETS" - States - { - Spawn: - BLIT A -1 - Stop - } -} - -// Box of Bullets ----------------------------------------------------------- - -ACTOR BoxOfBullets : ClipOfBullets -{ - Inventory.Amount 50 - Tag "$TAG_BOXOFBULLETS" - Inventory.PickupMessage "$TXT_BOXOFBULLETS" - States - { - Spawn: - BBOX A -1 - Stop - } -} - -// Mini Missiles ------------------------------------------------------------ - -ACTOR MiniMissiles : Ammo -{ - +FLOORCLIP - Inventory.Amount 4 - Inventory.MaxAmount 100 - Ammo.BackpackAmount 4 - Ammo.BackpackMaxAmount 200 - Inventory.Icon "I_ROKT" - Tag "$TAG_MINIMISSILES" - Inventory.PickupMessage "$TXT_MINIMISSILES" - States - { - Spawn: - MSSL A -1 - Stop - } -} - -// Crate of Missiles -------------------------------------------------------- - -ACTOR CrateOfMissiles : MiniMissiles -{ - Inventory.Amount 20 - Tag "$TAG_CRATEOFMISSILES" - Inventory.PickupMessage "$TXT_CRATEOFMISSILES" - States - { - Spawn: - ROKT A -1 - Stop - } -} - -// Energy Pod --------------------------------------------------------------- - -ACTOR EnergyPod : Ammo -{ - +FLOORCLIP - Inventory.Amount 20 - Inventory.MaxAmount 400 - Ammo.BackpackAmount 20 - Ammo.BackpackMaxAmount 800 - Ammo.DropAmount 20 - Inventory.Icon "I_BRY1" - Tag "$TAG_ENERGYPOD" - Inventory.PickupMessage "$TXT_ENERGYPOD" - States - { - Spawn: - BRY1 AB 6 - Loop - } -} - -// Energy pack --------------------------------------------------------------- - -ACTOR EnergyPack : EnergyPod -{ - Inventory.Amount 100 - Tag "$TAG_ENERGYPACK" - Inventory.PickupMessage "$TXT_ENERGYPACK" - States - { - Spawn: - CPAC AB 6 - Loop - } -} - -// Poison Bolt Quiver ------------------------------------------------------- - -ACTOR PoisonBolts : Ammo -{ - +FLOORCLIP - Inventory.Amount 10 - Inventory.MaxAmount 25 - Ammo.BackpackAmount 2 - Ammo.BackpackMaxAmount 50 - Inventory.Icon "I_PQRL" - Tag "$TAG_POISONBOLTS" - Inventory.PickupMessage "$TXT_POISONBOLTS" - States - { - Spawn: - PQRL A -1 - Stop - } -} - -// Electric Bolt Quiver ------------------------------------------------------- - -ACTOR ElectricBolts : Ammo -{ - +FLOORCLIP - Inventory.Amount 20 - Inventory.MaxAmount 50 - Ammo.BackpackAmount 4 - Ammo.BackpackMaxAmount 100 - Inventory.Icon "I_XQRL" - Tag "$TAG_ELECTRICBOLTS" - Inventory.PickupMessage "$TXT_ELECTRICBOLTS" - States - { - Spawn: - XQRL A -1 - Stop - } -} - -// Ammo Satchel ------------------------------------------------------------- - -ACTOR AmmoSatchel : BackpackItem -{ - +FLOORCLIP - Inventory.Icon "I_BKPK" - Tag "$TAG_AMMOSATCHEL" - Inventory.PickupMessage "$TXT_AMMOSATCHEL" - States - { - Spawn: - BKPK A -1 - Stop - } -} - diff --git a/wadsrc/static/actors/strife/strifearmor.txt b/wadsrc/static/actors/strife/strifearmor.txt deleted file mode 100644 index 3722d9338d..0000000000 --- a/wadsrc/static/actors/strife/strifearmor.txt +++ /dev/null @@ -1,43 +0,0 @@ - -ACTOR MetalArmor : BasicArmorPickup -{ - Radius 20 - Height 16 - +FLOORCLIP - +INVENTORY.AUTOACTIVATE - +INVENTORY.INVBAR - Inventory.MaxAmount 3 - Inventory.Icon "I_ARM1" - Inventory.PickupMessage "$TXT_METALARMOR" - Armor.SaveAmount 200 - Armor.SavePercent 50 - Tag "$TAG_METALARMOR" - States - { - Spawn: - ARM3 A -1 - Stop - } -} - -ACTOR LeatherArmor : BasicArmorPickup -{ - Radius 20 - Height 16 - +FLOORCLIP - +INVENTORY.AUTOACTIVATE - +INVENTORY.INVBAR - Inventory.MaxAmount 5 - Inventory.Icon "I_ARM2" - Inventory.PickupMessage "$TXT_LEATHERARMOR" - Armor.SaveAmount 100 - Armor.SavePercent 33.335 - Tag "$TAG_LEATHER" - States - { - Spawn: - ARM4 A -1 - Stop - } -} - diff --git a/wadsrc/static/actors/strife/strifebishop.txt b/wadsrc/static/actors/strife/strifebishop.txt deleted file mode 100644 index e64b247b17..0000000000 --- a/wadsrc/static/actors/strife/strifebishop.txt +++ /dev/null @@ -1,94 +0,0 @@ - -// Bishop ------------------------------------------------------------------- - -ACTOR StrifeBishop -{ - Health 500 - Painchance 128 - Speed 8 - Radius 40 - Height 56 - Mass 500 - Monster - +NOBLOOD - +NOTDMATCH - +FLOORCLIP - +INCOMBAT - +NOICEDEATH - +NEVERRESPAWN - DamageFactor "Fire", 0.5 - MinMissileChance 150 - MaxDropoffHeight 32 - SeeSound "bishop/sight" - PainSound "bishop/pain" - DeathSound "bishop/death" - ActiveSound "bishop/active" - DropItem "CrateOfMissiles", 256, 20 - Obituary "$OB_STFBISHOP" - States - { - Spawn: - MLDR A 10 A_Look - Loop - See: - MLDR AABBCCDD 3 A_Chase - Loop - Missile: - MLDR E 3 A_FaceTarget - MLDR F 2 Bright A_CustomMissile("BishopMissile", 64, 0, 0, CMF_AIMOFFSET) - Goto See - Pain: - MLDR D 1 A_Pain - Goto See - Death: - MLDR G 3 Bright - MLDR H 5 Bright A_Scream - MLDR I 4 Bright A_TossGib - MLDR J 4 Bright A_Explode(64,64,1,1) - MLDR KL 3 Bright - MLDR M 4 Bright A_NoBlocking - MLDR N 4 Bright - MLDR O 4 Bright A_TossGib - MLDR P 4 Bright - MLDR Q 4 Bright A_TossGib - MLDR R 4 Bright - MLDR S 4 Bright A_TossGib - MLDR T 4 Bright - MLDR U 4 Bright A_TossGib - MLDR V 4 Bright A_SpawnItemEx("AlienSpectre2", 0, 0, 0, 0, 0, random[spectrespawn](0,255)*0.0078125, 0, SXF_NOCHECKPOSITION) - Stop - } -} - - -// The Bishop's missile ----------------------------------------------------- - -ACTOR BishopMissile -{ - Speed 20 - Radius 10 - Height 14 - Damage 10 - Projectile - +SEEKERMISSILE - +STRIFEDAMAGE - MaxStepHeight 4 - SeeSound "bishop/misl" - DeathSound "bishop/mislx" - States - { - Spawn: - MISS A 4 Bright A_RocketInFlight - MISS B 3 Bright A_Tracer2 - Loop - Death: - SMIS A 0 Bright A_SetTranslucent(1,1) - SMIS A 0 Bright // State left for savegame compatibility - SMIS A 5 Bright A_Explode(64,64,1,1) - SMIS B 5 Bright - SMIS C 4 Bright - SMIS DEFG 2 Bright - Stop - } -} - diff --git a/wadsrc/static/actors/strife/strifehumanoid.txt b/wadsrc/static/actors/strife/strifehumanoid.txt deleted file mode 100644 index 7168065644..0000000000 --- a/wadsrc/static/actors/strife/strifehumanoid.txt +++ /dev/null @@ -1,53 +0,0 @@ - -// Humanoid Base Class ------------------------------------------------------ - - -ACTOR StrifeHumanoid -{ - MaxStepHeight 16 - MaxDropoffHeight 32 - - CrushPainSound "misc/pcrush" - States - { - Burn: - BURN A 3 Bright A_PlaySoundEx("human/imonfire", "Voice") - BURN B 3 Bright A_DropFire - BURN C 3 Bright A_Wander - BURN D 3 Bright A_NoBlocking - BURN E 5 Bright A_DropFire - BURN FGH 5 Bright A_Wander - BURN I 5 Bright A_DropFire - BURN JKL 5 Bright A_Wander - BURN M 5 Bright A_DropFire - BURN N 5 Bright - BURN OPQPQ 5 Bright - BURN RSTU 7 Bright - BURN V -1 - Stop - Disintegrate: - DISR A 5 A_PlaySoundEx("misc/disruptordeath", "Voice") - DISR BC 5 - DISR D 5 A_NoBlocking - DISR EF 5 - DISR GHIJ 4 - MEAT D 700 - Stop - } -} - -// Fire Droplet ------------------------------------------------------------- - -ACTOR FireDroplet -{ - +NOBLOCKMAP - +NOCLIP - States - { - Spawn: - FFOT ABCD 9 Bright - Stop - } -} - - diff --git a/wadsrc/static/actors/strife/strifeitems.txt b/wadsrc/static/actors/strife/strifeitems.txt deleted file mode 100644 index 357d64ad5a..0000000000 --- a/wadsrc/static/actors/strife/strifeitems.txt +++ /dev/null @@ -1,519 +0,0 @@ -// Med patch ----------------------------------------------------------------- - -ACTOR MedPatch : HealthPickup -{ - Health 10 - +FLOORCLIP - +INVENTORY.INVBAR - Inventory.MaxAmount 20 - Tag "$TAG_MEDPATCH" - Inventory.Icon "I_STMP" - Inventory.PickupMessage "$TXT_MEDPATCH" - HealthPickup.Autouse 3 - States - { - Spawn: - STMP A -1 - Stop - } -} - - -// Medical Kit --------------------------------------------------------------- - -ACTOR MedicalKit : HealthPickup -{ - Health 25 - +FLOORCLIP - +INVENTORY.INVBAR - Inventory.MaxAmount 15 - Tag "$TAG_MEDICALKIT" - Inventory.Icon "I_MDKT" - Inventory.PickupMessage "$TXT_MEDICALKIT" - HealthPickup.Autouse 3 - States - { - Spawn: - MDKT A -1 - Stop - } -} - - -// Surgery Kit -------------------------------------------------------------- - -ACTOR SurgeryKit : HealthPickup -{ - +FLOORCLIP - +INVENTORY.INVBAR - Health -100 - Inventory.MaxAmount 5 - Tag "$TAG_SURGERYKIT" - Inventory.Icon "I_FULL" - Inventory.PickupMessage "$TXT_SURGERYKIT" - States - { - Spawn: - FULL AB 35 - Loop - } -} - - -// StrifeMap ---------------------------------------------------------------- - -ACTOR StrifeMap : MapRevealer -{ - +FLOORCLIP - Inventory.PickupSound "misc/p_pkup" - Inventory.PickupMessage "$TXT_STRIFEMAP" - States - { - Spawn: - SMAP AB 6 Bright - Loop - } -} - - -// Beldin's Ring ------------------------------------------------------------ - -ACTOR BeldinsRing : Inventory -{ - +NOTDMATCH - +FLOORCLIP - +INVENTORY.INVBAR - Tag "$TAG_BELDINSRING" - Inventory.Icon "I_RING" - Inventory.GiveQuest 1 - Inventory.PickupMessage "$TXT_BELDINSRING" - States - { - Spawn: - RING A -1 - Stop - } -} - - -// Offering Chalice --------------------------------------------------------- - -ACTOR OfferingChalice : Inventory -{ - +DROPPED - +FLOORCLIP - +INVENTORY.INVBAR - Radius 10 - Height 16 - Tag "$TAG_OFFERINGCHALICE" - Inventory.Icon "I_RELC" - Inventory.PickupMessage "$TXT_OFFERINGCHALICE" - Inventory.GiveQuest 2 - States - { - Spawn: - RELC A -1 - Stop - } -} - - -// Ear ---------------------------------------------------------------------- - -ACTOR Ear : Inventory -{ - +FLOORCLIP - +INVENTORY.INVBAR - Tag "$TAG_EAR" - Inventory.Icon "I_EARS" - Inventory.PickupMessage "$TXT_EAR" - Inventory.GiveQuest 9 - States - { - Spawn: - EARS A -1 - Stop - } -} - - -// Broken Power Coupling ---------------------------------------------------- - -ACTOR BrokenPowerCoupling : Inventory -{ - Health 40 - +DROPPED - +FLOORCLIP - +INVENTORY.INVBAR - Radius 16 - Height 16 - Tag "$TAG_BROKENCOUPLING" - Inventory.MaxAmount 1 - Inventory.Icon "I_COUP" - Inventory.PickupMessage "$TXT_BROKENCOUPLING" - Inventory.GiveQuest 8 - States - { - Spawn: - COUP C -1 - Stop - } -} - - -// Shadow Armor ------------------------------------------------------------- - -ACTOR ShadowArmor : PowerupGiver -{ - +FLOORCLIP - +VISIBILITYPULSE - +INVENTORY.INVBAR - -INVENTORY.FANCYPICKUPSOUND - RenderStyle Translucent - Tag "$TAG_SHADOWARMOR" - Inventory.MaxAmount 2 - Powerup.Type "Shadow" - Inventory.Icon "I_SHD1" - Inventory.PickupSound "misc/i_pkup" - Inventory.PickupMessage "$TXT_SHADOWARMOR" - States - { - Spawn: - SHD1 A -1 Bright - Stop - } -} - - -// Environmental suit ------------------------------------------------------- - -ACTOR EnvironmentalSuit : PowerupGiver -{ - +FLOORCLIP - +INVENTORY.INVBAR - -INVENTORY.FANCYPICKUPSOUND - Inventory.MaxAmount 5 - Powerup.Type "Mask" - Tag "$TAG_ENVSUIT" - Inventory.Icon "I_MASK" - Inventory.PickupSound "misc/i_pkup" - Inventory.PickupMessage "$TXT_ENVSUIT" - States - { - Spawn: - MASK A -1 - Stop - } -} - - -// Guard Uniform ------------------------------------------------------------ - -ACTOR GuardUniform : Inventory -{ - +FLOORCLIP - +INVENTORY.INVBAR - Tag "$TAG_GUARDUNIFORM" - Inventory.Icon "I_UNIF" - Inventory.PickupMessage "$TXT_GUARDUNIFORM" - Inventory.GiveQuest 15 - States - { - Spawn: - UNIF A -1 - Stop - } -} - - -// Officer's Uniform -------------------------------------------------------- - -ACTOR OfficersUniform : Inventory -{ - +FLOORCLIP - +INVENTORY.INVBAR - Tag "$TAG_OFFICERSUNIFORM" - Inventory.Icon "I_OFIC" - Inventory.PickupMessage "$TXT_OFFICERSUNIFORM" - States - { - Spawn: - OFIC A -1 - Stop - } -} - - -// Flame Thrower Parts ------------------------------------------------------ - -ACTOR FlameThrowerParts : Inventory -{ - +FLOORCLIP - +INVENTORY.INVBAR - Inventory.Icon "I_BFLM" - Tag "$TAG_FTHROWERPARTS" - Inventory.PickupMessage "$TXT_FTHROWERPARTS" - States - { - Spawn: - BFLM A -1 - Stop - } -} - -// InterrogatorReport ------------------------------------------------------- -// SCRIPT32 in strife0.wad has an Acolyte that drops this, but I couldn't -// find that Acolyte in the map. It seems to be totally unused in the -// final game. - -ACTOR InterrogatorReport : Inventory -{ - +FLOORCLIP - Tag "$TAG_REPORT" - Inventory.PickupMessage "$TXT_REPORT" - States - { - Spawn: - TOKN A -1 - Stop - } -} - - -// Info --------------------------------------------------------------------- - -ACTOR Info : Inventory -{ - +FLOORCLIP - +INVENTORY.INVBAR - Tag "$TAG_INFO" - Inventory.Icon "I_TOKN" - Inventory.PickupMessage "$TXT_INFO" - States - { - Spawn: - TOKN A -1 - Stop - } -} - - -// Targeter ----------------------------------------------------------------- - -ACTOR Targeter : PowerupGiver -{ - +FLOORCLIP - +INVENTORY.INVBAR - -INVENTORY.FANCYPICKUPSOUND - Tag "$TAG_TARGETER" - Powerup.Type "Targeter" - Inventory.MaxAmount 5 - Inventory.Icon "I_TARG" - Inventory.PickupSound "misc/i_pkup" - Inventory.PickupMessage "$TXT_TARGETER" - States - { - Spawn: - TARG A -1 - Stop - } -} - -// Communicator ----------------------------------------------------------------- - -ACTOR Communicator : Inventory -{ - +NOTDMATCH - Tag "$TAG_COMMUNICATOR" - Inventory.Icon "I_COMM" - Inventory.PickupSound "misc/p_pkup" - Inventory.PickupMessage "$TXT_COMMUNICATOR" - States - { - Spawn: - COMM A -1 - Stop - } -} - -// Degnin Ore --------------------------------------------------------------- - -ACTOR DegninOre : Inventory native -{ - Health 10 - Radius 16 - Height 16 - Inventory.MaxAmount 10 - +SOLID - +SHOOTABLE - +NOBLOOD - +FLOORCLIP - +INCOMBAT - +INVENTORY.INVBAR - Tag "$TAG_DEGNINORE" - DeathSound "ore/explode" - Inventory.Icon "I_XPRK" - Inventory.PickupMessage "$TXT_DEGNINORE" - States - { - Spawn: - XPRK A -1 - Stop - Death: - XPRK A 1 A_RemoveForceField - BNG3 A 0 A_SetTranslucent(1,1) - BNG3 A 0 A_Scream - BNG3 A 3 Bright A_Explode(192,192,1,1) - BNG3 BCDEFGH 3 Bright - Stop - } -} - -// Gun Training ------------------------------------------------------------- - -ACTOR GunTraining : Inventory -{ - +FLOORCLIP - +INVENTORY.INVBAR - +INVENTORY.UNDROPPABLE - Inventory.MaxAmount 100 - Tag "$TAG_GUNTRAINING" - Inventory.Icon "I_GUNT" - States - { - Spawn: - GUNT A -1 - Stop - } -} - -// Health Training ---------------------------------------------------------- - -ACTOR HealthTraining : Inventory native -{ - +FLOORCLIP - +INVENTORY.INVBAR - +INVENTORY.UNDROPPABLE - Inventory.MaxAmount 100 - Tag "$TAG_HEALTHTRAINING" - Inventory.Icon "I_HELT" - States - { - Spawn: - HELT A -1 - Stop - } -} - - - -// Scanner ------------------------------------------------------------------ - -ACTOR Scanner : PowerupGiver native -{ - +FLOORCLIP - +INVENTORY.FANCYPICKUPSOUND - Inventory.MaxAmount 1 - Tag "$TAG_SCANNER" - Inventory.Icon "I_PMUP" - Powerup.Type "Scanner" - Inventory.PickupSound "misc/i_pkup" - Inventory.PickupMessage "$TXT_SCANNER" - States - { - Spawn: - PMUP AB 6 - Loop - } -} - -// Prison Pass -------------------------------------------------------------- - -ACTOR PrisonPass : Key native -{ - Inventory.Icon "I_TOKN" - Tag "$TAG_PRISONPASS" - Inventory.PickupMessage "$TXT_PRISONPASS" - States - { - Spawn: - TOKN A -1 - Stop - } -} - -//--------------------------------------------------------------------------- -// Dummy items. They are just used by Strife to perform --------------------- -// actions and cannot be held. ---------------------------------------------- -//--------------------------------------------------------------------------- - -ACTOR DummyStrifeItem : Inventory native -{ - States - { - Spawn: - TOKN A -1 - Stop - } -} - -// Sound the alarm! --------------------------------------------------------- - -ACTOR RaiseAlarm : DummyStrifeItem native -{ - Tag "$TAG_ALARM" -} - -// Open door tag 222 -------------------------------------------------------- - -ACTOR OpenDoor222 : DummyStrifeItem native -{ -} - -// Close door tag 222 ------------------------------------------------------- - -ACTOR CloseDoor222 : DummyStrifeItem native -{ -} - -// Open door tag 224 -------------------------------------------------------- - -ACTOR OpenDoor224 : DummyStrifeItem native -{ -} - -// Ammo --------------------------------------------------------------------- - -ACTOR AmmoFillup : DummyStrifeItem native -{ - Tag "$TAG_AMMOFILLUP" -} - -// Health ------------------------------------------------------------------- - -ACTOR HealthFillup : DummyStrifeItem native -{ - Tag "$TAG_HEALTHFILLUP" -} - -// Upgrade Stamina ---------------------------------------------------------- - -ACTOR UpgradeStamina : DummyStrifeItem native -{ - Inventory.Amount 10 - Inventory.MaxAmount 100 -} - -// Upgrade Accuracy --------------------------------------------------------- - -ACTOR UpgradeAccuracy : DummyStrifeItem native -{ -} - -// Start a slideshow -------------------------------------------------------- - -ACTOR SlideshowStarter : DummyStrifeItem native -{ -} - - diff --git a/wadsrc/static/actors/strife/strifekeys.txt b/wadsrc/static/actors/strife/strifekeys.txt deleted file mode 100644 index 1a58505bb2..0000000000 --- a/wadsrc/static/actors/strife/strifekeys.txt +++ /dev/null @@ -1,460 +0,0 @@ -ACTOR StrifeKey : Key -{ - Radius 20 - Height 16 - +NOTDMATCH - +FLOORCLIP -} - -// Base Key ----------------------------------------------------------------- - -ACTOR BaseKey : StrifeKey -{ - Inventory.Icon "I_FUSL" - Tag "$TAG_BASEKEY" - Inventory.PickupMessage "$TXT_BASEKEY" - States - { - Spawn: - FUSL A -1 - Stop - } -} - - -// Govs Key ----------------------------------------------------------------- - -ACTOR GovsKey : StrifeKey -{ - Inventory.Icon "I_REBL" - Tag "$TAG_GOVSKEY" - Inventory.PickupMessage "$TXT_GOVSKEY" - States - { - Spawn: - REBL A -1 - Stop - } -} - - -// Passcard ----------------------------------------------------------------- - -ACTOR Passcard : StrifeKey -{ - Inventory.Icon "I_TPAS" - Tag "$TAG_PASSCARD" - Inventory.PickupMessage "$TXT_PASSCARD" - States - { - Spawn: - TPAS A -1 - Stop - } -} - - -// ID Badge ----------------------------------------------------------------- - -ACTOR IDBadge : StrifeKey -{ - Inventory.Icon "I_CRD1" - Tag "$TAG_IDBADGE" - Inventory.PickupMessage "$TXT_IDBADGE" - States - { - Spawn: - CRD1 A -1 - Stop - } -} - - -// Prison Key --------------------------------------------------------------- - -ACTOR PrisonKey : StrifeKey -{ - Inventory.Icon "I_PRIS" - Tag "$TAG_PRISONKEY" - Inventory.GiveQuest 11 - Inventory.PickupMessage "$TXT_PRISONKEY" - States - { - Spawn: - PRIS A -1 - Stop - } -} - - -// Severed Hand ------------------------------------------------------------- - -ACTOR SeveredHand : StrifeKey -{ - Inventory.Icon "I_HAND" - Tag "$TAG_SEVEREDHAND" - Inventory.GiveQuest 12 - Inventory.PickupMessage "$TXT_SEVEREDHAND" - States - { - Spawn: - HAND A -1 - Stop - } -} - - -// Power1 Key --------------------------------------------------------------- - -ACTOR Power1Key : StrifeKey -{ - Inventory.Icon "I_PWR1" - Tag "$TAG_POWER1KEY" - Inventory.PickupMessage "$TXT_POWER1KEY" - States - { - Spawn: - PWR1 A -1 - Stop - } -} - - -// Power2 Key --------------------------------------------------------------- - -ACTOR Power2Key : StrifeKey -{ - Inventory.Icon "I_PWR2" - Tag "$TAG_POWER2KEY" - Inventory.PickupMessage "$TXT_POWER2KEY" - States - { - Spawn: - PWR2 A -1 - Stop - } -} - - -// Power3 Key --------------------------------------------------------------- - -ACTOR Power3Key : StrifeKey -{ - Inventory.Icon "I_PWR3" - Tag "$TAG_POWER3KEY" - Inventory.PickupMessage "$TXT_POWER3KEY" - States - { - Spawn: - PWR3 A -1 - Stop - } -} - - -// Gold Key ----------------------------------------------------------------- - -ACTOR GoldKey : StrifeKey -{ - Inventory.Icon "I_KY1G" - Tag "$TAG_GOLDKEY" - Inventory.PickupMessage "$TXT_GOLDKEY" - States - { - Spawn: - KY1G A -1 - Stop - } -} - - -// ID Card ------------------------------------------------------------------ - -ACTOR IDCard : StrifeKey -{ - Inventory.Icon "I_CRD2" - Tag "$TAG_IDCARD" - Inventory.PickupMessage "$TXT_IDCARD" - States - { - Spawn: - CRD2 A -1 - Stop - } -} - - -// Silver Key --------------------------------------------------------------- - -ACTOR SilverKey : StrifeKey -{ - Inventory.Icon "I_KY2S" - Tag "$TAG_SILVERKEY" - Inventory.PickupMessage "$TXT_SILVERKEY" - States - { - Spawn: - KY2S A -1 - Stop - } -} - - -// Oracle Key --------------------------------------------------------------- - -ACTOR OracleKey : StrifeKey -{ - Inventory.Icon "I_ORAC" - Tag "$TAG_ORACLEKEY" - Inventory.PickupMessage "$TXT_ORACLEKEY" - States - { - Spawn: - ORAC A -1 - Stop - } -} - - -// Military ID -------------------------------------------------------------- - -ACTOR MilitaryID : StrifeKey -{ - Inventory.Icon "I_GYID" - Tag "$TAG_MILITARYID" - Inventory.PickupMessage "$TXT_MILITARYID" - States - { - Spawn: - GYID A -1 - Stop - } -} - - -// Order Key ---------------------------------------------------------------- - -ACTOR OrderKey : StrifeKey -{ - Inventory.Icon "I_FUBR" - Tag "$TAG_ORDERKEY" - Inventory.PickupMessage "$TXT_ORDERKEY" - States - { - Spawn: - FUBR A -1 - Stop - } -} - - -// Warehouse Key ------------------------------------------------------------ - -ACTOR WarehouseKey : StrifeKey -{ - Inventory.Icon "I_WARE" - Tag "$TAG_WAREHOUSEKEY" - Inventory.PickupMessage "$TXT_WAREHOUSEKEY" - States - { - Spawn: - WARE A -1 - Stop - } -} - - -// Brass Key ---------------------------------------------------------------- - -ACTOR BrassKey : StrifeKey -{ - Inventory.Icon "I_KY3B" - Tag "$TAG_BRASSKEY" - Inventory.PickupMessage "$TXT_BRASSKEY" - States - { - Spawn: - KY3B A -1 - Stop - } -} - - -// Red Crystal Key ---------------------------------------------------------- - -ACTOR RedCrystalKey : StrifeKey -{ - Inventory.Icon "I_RCRY" - Tag "$TAG_REDCRYSTALKEY" - Inventory.PickupMessage "$TXT_REDCRYSTAL" - States - { - Spawn: - RCRY A -1 Bright - Stop - } -} - - -// Blue Crystal Key --------------------------------------------------------- - -ACTOR BlueCrystalKey : StrifeKey -{ - Inventory.Icon "I_BCRY" - Tag "$TAG_BLUECRYSTALKEY" - Inventory.PickupMessage "$TXT_BLUECRYSTAL" - States - { - Spawn: - BCRY A -1 Bright - Stop - } -} - - -// Chapel Key --------------------------------------------------------------- - -ACTOR ChapelKey : StrifeKey -{ - Inventory.Icon "I_CHAP" - Tag "$TAG_CHAPELKEY" - Inventory.PickupMessage "$TXT_CHAPELKEY" - States - { - Spawn: - CHAP A -1 - Stop - } -} - - -// Catacomb Key ------------------------------------------------------------- - -ACTOR CatacombKey : StrifeKey -{ - Inventory.Icon "I_TUNL" - Tag "$TAG_CATACOMBKEY" - Inventory.GiveQuest 28 - Inventory.PickupMessage "$TXT_CATACOMBKEY" - States - { - Spawn: - TUNL A -1 - Stop - } -} - - -// Security Key ------------------------------------------------------------- - -ACTOR SecurityKey : StrifeKey -{ - Inventory.Icon "I_SECK" - Tag "$TAG_SECURITYKEY" - Inventory.PickupMessage "$TXT_SECURITYKEY" - States - { - Spawn: - SECK A -1 - Stop - } -} - - -// Core Key ----------------------------------------------------------------- - -ACTOR CoreKey : StrifeKey -{ - Inventory.Icon "I_GOID" - Tag "$TAG_COREKEY" - Inventory.PickupMessage "$TXT_COREKEY" - States - { - Spawn: - GOID A -1 - Stop - } -} - - -// Mauler Key --------------------------------------------------------------- - -ACTOR MaulerKey : StrifeKey -{ - Inventory.Icon "I_BLTK" - Tag "$TAG_MAULERKEY" - Inventory.PickupMessage "$TXT_MAULERKEY" - States - { - Spawn: - BLTK A -1 - Stop - } -} - - -// Factory Key -------------------------------------------------------------- - -ACTOR FactoryKey : StrifeKey -{ - Inventory.Icon "I_PROC" - Tag "$TAG_FACTORYKEY" - Inventory.PickupMessage "$TXT_FACTORYKEY" - States - { - Spawn: - PROC A -1 - Stop - } -} - - -// Mine Key ----------------------------------------------------------------- - -ACTOR MineKey : StrifeKey -{ - Inventory.Icon "I_MINE" - Tag "$TAG_MINEKEY" - Inventory.PickupMessage "$TXT_MINEKEY" - States - { - Spawn: - MINE A -1 - Stop - } -} - - -// New Key5 ----------------------------------------------------------------- - -ACTOR NewKey5 : StrifeKey -{ - Inventory.Icon "I_BLTK" - Tag "$TAG_NEWKEY5" - Inventory.PickupMessage "$TXT_NEWKEY5" - States - { - Spawn: - BLTK A -1 - Stop - } -} - - -// Oracle Pass -------------------------------------------------------------- - -ACTOR OraclePass : Inventory -{ - +INVENTORY.INVBAR - Inventory.Icon "I_OTOK" - Inventory.GiveQuest 18 - Inventory.PickupMessage "$TXT_ORACLEPASS" - Tag "$TAG_ORACLEPASS" - States - { - Spawn: - OTOK A -1 - Stop - } -} - diff --git a/wadsrc/static/actors/strife/strifeplayer.txt b/wadsrc/static/actors/strife/strifeplayer.txt deleted file mode 100644 index 77135dcbf9..0000000000 --- a/wadsrc/static/actors/strife/strifeplayer.txt +++ /dev/null @@ -1,102 +0,0 @@ -// The player --------------------------------------------------------------- - -ACTOR StrifePlayer : PlayerPawn -{ - Health 100 - Radius 18 - Height 56 - Mass 100 - PainChance 255 - Speed 1 - MaxStepHeight 16 - CrushPainSound "misc/pcrush" - Player.DisplayName "Rebel" - Player.StartItem "PunchDagger" - Player.RunHealth 15 - Player.WeaponSlot 1, PunchDagger - Player.WeaponSlot 2, StrifeCrossbow2, StrifeCrossbow - Player.WeaponSlot 3, AssaultGun - Player.WeaponSlot 4, MiniMissileLauncher - Player.WeaponSlot 5, StrifeGrenadeLauncher2, StrifeGrenadeLauncher - Player.WeaponSlot 6, FlameThrower - Player.WeaponSlot 7, Mauler2, Mauler - Player.WeaponSlot 8, Sigil - - Player.ColorRange 128, 143 - Player.Colorset 0, "Brown", 0x80, 0x8F, 0x82 - Player.Colorset 1, "Red", 0x40, 0x4F, 0x42, 0x20, 0x3F, 0x00, 0x1F, 0xF1, 0xF6, 0xE0, 0xE5, 0xF7, 0xFB, 0xF1, 0xF5 - Player.Colorset 2, "Rust", 0xB0, 0xBF, 0xB2, 0x20, 0x3F, 0x00, 0x1F - Player.Colorset 3, "Gray", 0x10, 0x1F, 0x12, 0x20, 0x2F, 0xD0, 0xDF, 0x30, 0x3F, 0xD0, 0xDF - Player.Colorset 4, "Dark Green", 0x30, 0x3F, 0x32, 0x20, 0x2F, 0xD0, 0xDF, 0x30, 0x3F, 0xD0, 0xDF - - Player.Colorset 5, "Gold", 0x50, 0x5F, 0x52, 0x20, 0x3F, 0x00, 0x1F, 0x50, 0x5F, 0x80, 0x8F, 0xC0, 0xCF, 0xA0, 0xAF, 0xD0, 0xDF, 0xB0, 0xBF - Player.Colorset 6, "Bright Green", 0x60, 0x6F, 0x62, 0x20, 0x3F, 0x00, 0x1F, 0x50, 0x5F, 0x10, 0x1F, 0xC0, 0xCF, 0x20, 0x2F, 0xD0, 0xDF, 0x30, 0x3F - Player.Colorset 7, "Blue", 0x90, 0x9F, 0x92, 0x20, 0x3F, 0x00, 0x1F, 0x50, 0x5F, 0x40, 0x4F, 0xC1, 0xCF, 0x01, 0x0F, 0xC0,0xC0,1,1, 0xD0, 0xDF, 0x10, 0x1F - - action native A_ItBurnsItBurns(); - action native A_CrispyPlayer(); - action native A_HandLower(); - - States - { - Spawn: - PLAY A -1 - stop - See: - PLAY ABCD 4 - loop - Missile: - PLAY E 12 - goto Spawn - Melee: - PLAY F 6 - goto Missile - Pain: - PLAY Q 4 - PLAY Q 4 A_Pain - Goto Spawn - Death: - PLAY H 3 - PLAY I 3 A_PlayerScream - PLAY J 3 A_NoBlocking - PLAY KLMNO 4 - PLAY P -1 - Stop - XDeath: - RGIB A 5 A_TossGib - RGIB B 5 A_XScream - RGIB C 5 A_NoBlocking - RGIB DEFG 5 A_TossGib - RGIB H -1 A_TossGib - Burn: - BURN A 3 Bright A_ItBurnsItBurns - BURN B 3 Bright A_DropFire - BURN C 3 Bright A_Wander - BURN D 3 Bright A_NoBlocking - BURN E 5 Bright A_DropFire - BURN FGH 5 Bright A_Wander - BURN I 5 Bright A_DropFire - BURN JKL 5 Bright A_Wander - BURN M 5 Bright A_DropFire - BURN N 5 Bright A_CrispyPlayer - BURN OPQPQ 5 Bright - BURN RSTU 7 Bright - BURN V -1 - Stop - Disintegrate: - DISR A 5 A_PlaySoundEx("misc/disruptordeath", "Voice") - DISR BC 5 - DISR D 5 A_NoBlocking - DISR EF 5 - DISR GHIJ 4 - MEAT D -1 - Stop - Firehands: - WAVE ABCD 3 - Loop - Firehandslower: - WAVE ABCD 3 A_HandLower - Loop - } -} - diff --git a/wadsrc/static/actors/strife/strifestuff.txt b/wadsrc/static/actors/strife/strifestuff.txt deleted file mode 100644 index 95d6d93cd5..0000000000 --- a/wadsrc/static/actors/strife/strifestuff.txt +++ /dev/null @@ -1,1723 +0,0 @@ -// Tank 1 Huge ------------------------------------------------------------ - -ACTOR Tank1 -{ - Radius 16 - Height 192 - +SOLID - States - { - Spawn: - TNK1 A 15 - TNK1 B 11 - TNK1 C 40 - Loop - } -} - -// Tank 2 Huge ------------------------------------------------------------ - -ACTOR Tank2 -{ - Radius 16 - Height 192 - +SOLID - States - { - Spawn: - TNK2 A 15 - TNK2 B 11 - TNK2 C 40 - Loop - } -} - -// Tank 3 Huge ------------------------------------------------------------ - -ACTOR Tank3 -{ - Radius 16 - Height 192 - +SOLID - States - { - Spawn: - TNK3 A 15 - TNK3 B 11 - TNK3 C 40 - Loop - } -} - -// Tank 4 ------------------------------------------------------------------- - -ACTOR Tank4 -{ - Radius 16 - Height 56 - +SOLID - States - { - Spawn: - TNK4 A 15 - TNK4 B 11 - TNK4 C 40 - Loop - } -} - -// Tank 5 ------------------------------------------------------------------- - -ACTOR Tank5 -{ - Radius 16 - Height 56 - +SOLID - States - { - Spawn: - TNK5 A 15 - TNK5 B 11 - TNK5 C 40 - Loop - } -} - -// Tank 6 ------------------------------------------------------------------- - -ACTOR Tank6 -{ - Radius 16 - Height 56 - +SOLID - States - { - Spawn: - TNK6 A 15 - TNK6 B 11 - TNK6 C 40 - Loop - } -} - -// Water Bottle ------------------------------------------------------------- - -ACTOR WaterBottle -{ - States - { - Spawn: - WATR A -1 - Stop - } -} - -// Mug ---------------------------------------------------------------------- - -ACTOR Mug -{ - States - { - Spawn: - MUGG A -1 - Stop - } -} - -// Wooden Barrel ------------------------------------------------------------ - -ACTOR WoodenBarrel -{ - Health 10 - Radius 10 - Height 32 - +SOLID +SHOOTABLE +NOBLOOD - +INCOMBAT - DeathSound "woodenbarrel/death" - States - { - Spawn: - BARW A -1 - Stop - Death: - BARW B 2 A_Scream - BARW C 2 - BARW D 2 A_NoBlocking - BARW EFG 2 - BARW H -1 - Stop - } -} - -// Strife's explosive barrel ------------------------------------------------ - -ACTOR ExplosiveBarrel2 -{ - Health 30 - Radius 10 - Height 32 - +SOLID +SHOOTABLE +NOBLOOD +OLDRADIUSDMG - DeathSound "world/barrelx" - +INCOMBAT - States - { - Spawn: - BART A -1 - Stop - Death: - BART B 2 Bright A_Scream - BART CD 2 Bright - BART E 2 Bright A_NoBlocking - BART F 2 Bright A_Explode(64, 64, 1, 1) - BART GHIJ 2 Bright - BART K 3 Bright - BART L -1 - Stop - } -} - -// Light Silver, Fluorescent ---------------------------------------------- - -ACTOR LightSilverFluorescent -{ - Radius 2.5 - Height 16 - +NOBLOCKMAP - +FIXMAPTHINGPOS - States - { - Spawn: - LITS A -1 Bright - Stop - } -} - -// Light Brown, Fluorescent ----------------------------------------------- - -ACTOR LightBrownFluorescent -{ - Radius 2.5 - Height 16 - +NOBLOCKMAP - +FIXMAPTHINGPOS - States - { - Spawn: - LITB A -1 Bright - Stop - } -} - -// Light Gold, Fluorescent ------------------------------------------------ - -ACTOR LightGoldFluorescent -{ - Radius 2.5 - Height 16 - +NOBLOCKMAP - +FIXMAPTHINGPOS - States - { - Spawn: - LITG A -1 Bright - Stop - } -} - -// Light Globe -------------------------------------------------------------- - -ACTOR LightGlobe -{ - Radius 16 - Height 16 - +SOLID - States - { - Spawn: - LITE A -1 Bright - Stop - } -} - -// Techno Pillar ------------------------------------------------------------ - -ACTOR PillarTechno -{ - Radius 20 - Height 128 - +SOLID - States - { - Spawn: - MONI A -1 - Stop - } -} - -// Aztec Pillar ------------------------------------------------------------- - -ACTOR PillarAztec -{ - Radius 16 - Height 128 - +SOLID - States - { - Spawn: - STEL A -1 - Stop - } -} - -// Damaged Aztec Pillar ----------------------------------------------------- - -ACTOR PillarAztecDamaged -{ - Radius 16 - Height 80 - +SOLID - States - { - Spawn: - STLA A -1 - Stop - } -} - -// Ruined Aztec Pillar ------------------------------------------------------ - -ACTOR PillarAztecRuined -{ - Radius 16 - Height 40 - +SOLID - States - { - Spawn: - STLE A -1 - Stop - } -} - -// Huge Tech Pillar --------------------------------------------------------- - -ACTOR PillarHugeTech -{ - Radius 24 - Height 192 - +SOLID - States - { - Spawn: - HUGE ABCD 4 - Loop - } -} - -// Alien Power Crystal in a Pillar ------------------------------------------ - -ACTOR PillarAlienPower -{ - Radius 24 - Height 192 - +SOLID - ActiveSound "ambient/alien2" - States - { - Spawn: - APOW A 4 A_LoopActiveSound - Loop - } -} - -// SStalactiteBig ----------------------------------------------------------- - -ACTOR SStalactiteBig -{ - Radius 16 - Height 54 - +SOLID +SPAWNCEILING +NOGRAVITY - States - { - Spawn: - STLG C -1 - Stop - } -} - -// SStalactiteSmall --------------------------------------------------------- - -ACTOR SStalactiteSmall -{ - Radius 16 - Height 40 - +SOLID +SPAWNCEILING +NOGRAVITY - States - { - Spawn: - STLG A -1 - Stop - } -} - -// SStalagmiteBig ----------------------------------------------------------- - -ACTOR SStalagmiteBig -{ - Radius 16 - Height 40 - +SOLID - States - { - Spawn: - STLG B -1 - Stop - } -} - -// Cave Pillar Top ---------------------------------------------------------- - -ACTOR CavePillarTop -{ - Radius 16 - Height 128 - +SOLID +SPAWNCEILING +NOGRAVITY - States - { - Spawn: - STLG D -1 - Stop - } -} - -// Cave Pillar Bottom ------------------------------------------------------- - -ACTOR CavePillarBottom -{ - Radius 16 - Height 128 - +SOLID - States - { - Spawn: - STLG E -1 - Stop - } -} - -// SStalagmiteSmall --------------------------------------------------------- - -ACTOR SStalagmiteSmall -{ - Radius 16 - Height 25 - +SOLID - States - { - Spawn: - STLG F -1 - Stop - } -} - -// Candle ------------------------------------------------------------------- - -ACTOR Candle -{ - States - { - Spawn: - KNDL A -1 Bright - Stop - } -} - -// StrifeCandelabra --------------------------------------------------------- - -ACTOR StrifeCandelabra -{ - Radius 16 - Height 40 - +SOLID - States - { - Spawn: - CLBR A -1 - Stop - } -} - -// Floor Water Drop --------------------------------------------------------- - -ACTOR WaterDropOnFloor -{ - +NOBLOCKMAP - ActiveSound "world/waterdrip" - States - { - Spawn: - DRIP A 6 A_FLoopActiveSound - DRIP BC 4 - DRIP D 4 A_FLoopActiveSound - DRIP EF 4 - DRIP G 4 A_FLoopActiveSound - DRIP H 4 - Loop - } -} - -// Waterfall Splash --------------------------------------------------------- - -ACTOR WaterfallSplash -{ - +NOBLOCKMAP - ActiveSound "world/waterfall" - States - { - Spawn: - SPLH ABCDEFG 4 - SPLH H 4 A_LoopActiveSound - Loop - } -} - -// Ceiling Water Drip ------------------------------------------------------- - -ACTOR WaterDrip -{ - Height 1 - +NOBLOCKMAP +SPAWNCEILING +NOGRAVITY - States - { - Spawn: - CDRP A 10 - CDRP BCD 8 - Loop - } -} - -// WaterFountain ------------------------------------------------------------ - -ACTOR WaterFountain -{ - +NOBLOCKMAP - ActiveSound "world/watersplash" - States - { - Spawn: - WTFT ABC 4 - WTFT D 4 A_LoopActiveSound - Loop - } -} - -// Hearts in Tank ----------------------------------------------------------- - -ACTOR HeartsInTank -{ - Radius 16 - Height 56 - +SOLID - States - { - Spawn: - HERT ABC 4 Bright - Loop - } -} - -// Teleport Swirl ----------------------------------------------------------- - -ACTOR TeleportSwirl -{ - +NOBLOCKMAP - RenderStyle Add - Alpha 0.25 - States - { - Spawn: - TELP ABCD 3 Bright - Loop - } -} - -// Dead Player -------------------------------------------------------------- -// Strife's disappeared. This one doesn't. - -ACTOR DeadStrifePlayer -{ - States - { - Spawn: - PLAY P 700 - RGIB H -1 - Stop - } -} - -// Dead Peasant ------------------------------------------------------------- -// Unlike Strife's, this one does not turn into gibs and disappear. - -ACTOR DeadPeasant -{ - States - { - Spawn: - PEAS N -1 - Stop - } -} - -// Dead Acolyte ------------------------------------------------------------- -// Unlike Strife's, this one does not turn into gibs and disappear. - -ACTOR DeadAcolyte -{ - States - { - Spawn: - AGRD N -1 - Stop - } -} - -// Dead Reaver -------------------------------------------------------------- - -ACTOR DeadReaver -{ - States - { - Spawn: - ROB1 R -1 - Stop - } -} - -// Dead Rebel --------------------------------------------------------------- - -ACTOR DeadRebel -{ - States - { - Spawn: - HMN1 N -1 - Stop - } -} - -// Sacrificed Guy ----------------------------------------------------------- - -ACTOR SacrificedGuy -{ - States - { - Spawn: - SACR A -1 - Stop - } -} - -// Pile of Guts ------------------------------------------------------------- - -ACTOR PileOfGuts -{ - // Strife used a doomednum, which is the same as the Aztec Pillar. Since - // the pillar came first in the mobjinfo list, you could not spawn this - // in a map. Pity. - States - { - Spawn: - DEAD A -1 - Stop - } -} - -// Burning Barrel ----------------------------------------------------------- - -ACTOR StrifeBurningBarrel -{ - Radius 16 - Height 48 - +SOLID - States - { - Spawn: - BBAR ABCD 4 Bright - Loop - } -} - -// Burning Bowl ----------------------------------------------------------- - -ACTOR BurningBowl -{ - Radius 16 - Height 16 - +SOLID - ActiveSound "world/smallfire" - States - { - Spawn: - BOWL ABCD 4 Bright - Loop - } -} - -// Burning Brazier ----------------------------------------------------------- - -ACTOR BurningBrazier -{ - Radius 10 - Height 32 - +SOLID - ActiveSound "world/smallfire" - States - { - Spawn: - BRAZ ABCD 4 Bright - Loop - } -} - -// Small Torch Lit -------------------------------------------------------- - -ACTOR SmallTorchLit -{ - Radius 2.5 - Height 16 - +NOBLOCKMAP - +FIXMAPTHINGPOS - - // It doesn't have any action functions, so how does it use this sound? - ActiveSound "world/smallfire" - States - { - Spawn: - TRHL ABCD 4 Bright - Loop - } -} - -// Small Torch Unlit -------------------------------------------------------- - -ACTOR SmallTorchUnlit -{ - Radius 2.5 - Height 16 - +NOBLOCKMAP - +FIXMAPTHINGPOS - States - { - Spawn: - TRHO A -1 - Stop - } -} - -// Ceiling Chain ------------------------------------------------------------ - -ACTOR CeilingChain -{ - Radius 20 - Height 93 - +NOBLOCKMAP +SPAWNCEILING +NOGRAVITY - States - { - Spawn: - CHAN A -1 - Stop - } -} - -// Cage Light --------------------------------------------------------------- - -ACTOR CageLight -{ - // No, it's not bright even though it's a light. - Height 3 - +NOBLOCKMAP +SPAWNCEILING +NOGRAVITY - States - { - Spawn: - CAGE A -1 - Stop - } -} - -// Statue ------------------------------------------------------------------- - -ACTOR Statue -{ - Radius 20 - Height 64 - +SOLID - States - { - Spawn: - STAT A -1 - Stop - } -} - -// Ruined Statue ------------------------------------------------------------ - -ACTOR StatueRuined -{ - Radius 20 - Height 56 - +SOLID - States - { - Spawn: - DSTA A -1 - Stop - } -} - -// Medium Torch ------------------------------------------------------------- - -ACTOR MediumTorch -{ - Radius 4 - Height 72 - +SOLID - States - { - Spawn: - LTRH ABCD 4 - Loop - } -} - -// Outside Lamp ------------------------------------------------------------- - -ACTOR OutsideLamp -{ - // No, it's not bright. - Radius 3 - Height 80 - +SOLID - States - { - Spawn: - LAMP A -1 - Stop - } -} - -// Pole Lantern ------------------------------------------------------------- - -ACTOR PoleLantern -{ - // No, it's not bright. - Radius 3 - Height 80 - +SOLID - States - { - Spawn: - LANT A -1 - Stop - } -} - -// Rock 1 ------------------------------------------------------------------- - -ACTOR SRock1 -{ - +NOBLOCKMAP - States - { - Spawn: - ROK1 A -1 - Stop - } -} - -// Rock 2 ------------------------------------------------------------------- - -ACTOR SRock2 -{ - +NOBLOCKMAP - States - { - Spawn: - ROK2 A -1 - Stop - } -} - -// Rock 3 ------------------------------------------------------------------- - -ACTOR SRock3 -{ - +NOBLOCKMAP - States - { - Spawn: - ROK3 A -1 - Stop - } -} - -// Rock 4 ------------------------------------------------------------------- - -ACTOR SRock4 -{ - +NOBLOCKMAP - States - { - Spawn: - ROK4 A -1 - Stop - } -} - -// Stick in Water ----------------------------------------------------------- - -ACTOR StickInWater -{ - +NOBLOCKMAP - +FLOORCLIP - ActiveSound "world/river" - States - { - Spawn: - LOGW ABCD 5 A_LoopActiveSound - Loop - } -} - -// Rubble 1 ----------------------------------------------------------------- - -ACTOR Rubble1 -{ - +NOBLOCKMAP +NOCLIP - States - { - Spawn: - RUB1 A -1 - Stop - } -} - -// Rubble 2 ----------------------------------------------------------------- - -ACTOR Rubble2 -{ - +NOBLOCKMAP +NOCLIP - States - { - Spawn: - RUB2 A -1 - Stop - } -} - -// Rubble 3 ----------------------------------------------------------------- - -ACTOR Rubble3 -{ - +NOBLOCKMAP +NOCLIP - States - { - Spawn: - RUB3 A -1 - Stop - } -} - -// Rubble 4 ----------------------------------------------------------------- - -ACTOR Rubble4 -{ - +NOBLOCKMAP +NOCLIP - States - { - Spawn: - RUB4 A -1 - Stop - } -} - -// Rubble 5 ----------------------------------------------------------------- - -ACTOR Rubble5 -{ - +NOBLOCKMAP +NOCLIP - States - { - Spawn: - RUB5 A -1 - Stop - } -} - -// Rubble 6 ----------------------------------------------------------------- - -ACTOR Rubble6 -{ - +NOBLOCKMAP +NOCLIP - States - { - Spawn: - RUB6 A -1 - Stop - } -} - -// Rubble 7 ----------------------------------------------------------------- - -ACTOR Rubble7 -{ - +NOBLOCKMAP +NOCLIP - States - { - Spawn: - RUB7 A -1 - Stop - } -} - -// Rubble 8 ----------------------------------------------------------------- - -ACTOR Rubble8 -{ - +NOBLOCKMAP +NOCLIP - States - { - Spawn: - RUB8 A -1 - Stop - } -} - -// Surgery Crab ------------------------------------------------------------- - -ACTOR SurgeryCrab -{ - +SOLID +SPAWNCEILING +NOGRAVITY - Radius 20 - Height 16 - States - { - Spawn: - CRAB A -1 - Stop - } -} - -// Large Torch -------------------------------------------------------------- - -ACTOR LargeTorch -{ - Radius 10 - Height 72 - +SOLID - ActiveSound "world/smallfire" - States - { - Spawn: - LMPC ABCD 4 Bright - Loop - } -} - -// Huge Torch -------------------------------------------------------------- - -ACTOR HugeTorch -{ - Radius 10 - Height 80 - +SOLID - ActiveSound "world/smallfire" - States - { - Spawn: - LOGS ABCD 4 - Loop - } -} - -// Palm Tree ---------------------------------------------------------------- - -ACTOR PalmTree -{ - Radius 15 - Height 109 - +SOLID - States - { - Spawn: - TREE A -1 - Stop - } -} - -// Big Tree ---------------------------------------------------------------- - -ACTOR BigTree2 -{ - Radius 15 - Height 109 - +SOLID - States - { - Spawn: - TREE B -1 - Stop - } -} - -// Potted Tree ---------------------------------------------------------------- - -ACTOR PottedTree -{ - Radius 15 - Height 64 - +SOLID - States - { - Spawn: - TREE C -1 - Stop - } -} - -// Tree Stub ---------------------------------------------------------------- - -ACTOR TreeStub -{ - Radius 15 - Height 80 - +SOLID - States - { - Spawn: - TRET A -1 - Stop - } -} - -// Short Bush --------------------------------------------------------------- - -ACTOR ShortBush -{ - Radius 15 - Height 40 - +SOLID - States - { - Spawn: - BUSH A -1 - Stop - } -} - -// Tall Bush --------------------------------------------------------------- - -ACTOR TallBush -{ - Radius 20 - Height 64 - +SOLID - States - { - Spawn: - SHRB A -1 - Stop - } -} - -// Chimney Stack ------------------------------------------------------------ - -ACTOR ChimneyStack -{ - Radius 20 - Height 64 // This height does not fit the sprite - +SOLID - States - { - Spawn: - STAK A -1 - Stop - } -} - -// Barricade Column --------------------------------------------------------- - -ACTOR BarricadeColumn -{ - Radius 16 - Height 128 - +SOLID - States - { - Spawn: - BARC A -1 - Stop - } -} - -// Pot ---------------------------------------------------------------------- - -ACTOR Pot -{ - Radius 12 - Height 24 - +SOLID - States - { - Spawn: - VAZE A -1 - Stop - } -} - -// Pitcher ------------------------------------------------------------------ - -ACTOR Pitcher -{ - Radius 12 - Height 32 - +SOLID - States - { - Spawn: - VAZE B -1 - Stop - } -} - -// Stool -------------------------------------------------------------------- - -ACTOR Stool -{ - Radius 6 - Height 24 - +SOLID - States - { - Spawn: - STOL A -1 - Stop - } -} - -// Metal Pot ---------------------------------------------------------------- - -ACTOR MetalPot -{ - +NOBLOCKMAP - States - { - Spawn: - MPOT A -1 - Stop - } -} - -// Tub ---------------------------------------------------------------------- - -ACTOR Tub -{ - +NOBLOCKMAP - States - { - Spawn: - TUB1 A -1 - Stop - } -} - -// Anvil -------------------------------------------------------------------- - -ACTOR Anvil -{ - Radius 16 - Height 32 - +SOLID - States - { - Spawn: - ANVL A -1 - Stop - } -} - -// Silver Tech Lamp ---------------------------------------------------------- - -ACTOR TechLampSilver -{ - Radius 11 - Height 64 - +SOLID - States - { - Spawn: - TECH A -1 - Stop - } -} - -// Brass Tech Lamp ---------------------------------------------------------- - -ACTOR TechLampBrass -{ - Radius 8 - Height 64 - +SOLID - States - { - Spawn: - TECH B -1 - Stop - } -} - -// Tray -------------------------------------------------------------------- - -ACTOR Tray -{ - Radius 24 - Height 40 - +SOLID - States - { - Spawn: - TRAY A -1 - Stop - } -} - -// AmmoFiller --------------------------------------------------------------- - -ACTOR AmmoFiller -{ - Radius 12 - Height 24 - +SOLID - States - { - Spawn: - AFED A -1 - Stop - } -} - -// Sigil Banner ------------------------------------------------------------- - -ACTOR SigilBanner -{ - Radius 24 - Height 96 - +NOBLOCKMAP // I take it this was once solid, yes? - States - { - Spawn: - SBAN A -1 - Stop - } -} - -// RebelBoots --------------------------------------------------------------- - -ACTOR RebelBoots -{ - +NOBLOCKMAP - States - { - Spawn: - BOTR A -1 - Stop - } -} - -// RebelHelmet -------------------------------------------------------------- - -ACTOR RebelHelmet -{ - +NOBLOCKMAP - States - { - Spawn: - HATR A -1 - Stop - } -} - -// RebelShirt --------------------------------------------------------------- - -ACTOR RebelShirt -{ - +NOBLOCKMAP - States - { - Spawn: - TOPR A -1 - Stop - } -} - -// Alien Bubble Column ------------------------------------------------------ - -ACTOR AlienBubbleColumn -{ - Radius 16 - Height 128 - +SOLID - ActiveSound "ambient/alien5" - States - { - Spawn: - BUBB A 4 A_LoopActiveSound - Loop - } -} - -// Alien Floor Bubble ------------------------------------------------------- - -ACTOR AlienFloorBubble -{ - Radius 16 - Height 72 - +SOLID - ActiveSound "ambient/alien6" - States - { - Spawn: - BUBF A 4 A_LoopActiveSound - Loop - } -} - -// Alien Ceiling Bubble ----------------------------------------------------- - -ACTOR AlienCeilingBubble -{ - Radius 16 - Height 72 - +SOLID +SPAWNCEILING +NOGRAVITY - ActiveSound "ambient/alien4" - States - { - Spawn: - BUBC A 4 A_LoopActiveSound - Loop - } -} - -// Alien Asp Climber -------------------------------------------------------- - -ACTOR AlienAspClimber -{ - Radius 16 - Height 128 - +SOLID - ActiveSound "ambient/alien3" - States - { - Spawn: - ASPR A 4 A_LoopActiveSound - Loop - } -} - -// Alien Spider Light ------------------------------------------------------- - -ACTOR AlienSpiderLight -{ - Radius 32 - Height 56 - +SOLID - ActiveSound "ambient/alien1" - States - { - Spawn: - SPDL ABC 5 A_LoopActiveSound - Loop - } -} - -// Target Practice ----------------------------------------------------------- - -ACTOR TargetPractice -{ - Health 99999999 - PainChance 255 - Radius 10 - Height 72 - Mass 9999999 - +SOLID +SHOOTABLE +NOBLOOD - +INCOMBAT +NODAMAGE - PainSound "misc/metalhit" - States - { - Spawn: - HOGN A 2 A_CheckTerrain - Loop - Pain: - HOGN B 1 A_CheckTerrain - HOGN C 1 A_Pain - Goto Spawn - } -} - -// Force Field Guard -------------------------------------------------------- - -ACTOR ForceFieldGuard native -{ - Health 10 - Radius 2 - Height 1 - Mass 10000 - +SHOOTABLE - +NOSECTOR - +NOBLOOD - +INCOMBAT - States - { - Spawn: - TNT1 A -1 - Stop - Death: - TNT1 A 1 A_RemoveForceField - Stop - } -} - -// Kneeling Guy ------------------------------------------------------------- - -ACTOR KneelingGuy -{ - Health 51 - Painchance 255 - Radius 6 - Height 17 - Mass 50000 - +SOLID - +SHOOTABLE - +NOBLOOD - +ISMONSTER - +INCOMBAT - PainSound "misc/static" - DeathSound "misc/static" - ActiveSound "misc/chant" - states - { - Spawn: - See: - NEAL A 15 A_LoopActiveSound - NEAL B 40 A_LoopActiveSound - Loop - Pain: - NEAL C 5 A_SetShadow - NEAL B 4 A_Pain - NEAL C 5 A_ClearShadow - Goto Spawn - Wound: - NEAL B 6 - NEAL C 13 A_GetHurt - Loop - Death: - NEAL D 5 - NEAL E 5 A_Scream - NEAL F 6 - NEAL G 5 A_NoBlocking - NEAL H 5 - NEAL I 6 - NEAL J -1 - Stop - } - - -} - -// Klaxon Warning Light ----------------------------------------------------- - -ACTOR KlaxonWarningLight -{ - ReactionTime 60 - Radius 5 - +NOBLOCKMAP +AMBUSH - +SPAWNCEILING +NOGRAVITY - +FIXMAPTHINGPOS +NOSPLASHALERT - +SYNCHRONIZED - States - { - Spawn: - KLAX A 5 A_TurretLook - Loop - See: - KLAX B 6 A_KlaxonBlare - KLAX C 60 - Loop - } - -} - -// CeilingTurret ------------------------------------------------------------ - -ACTOR CeilingTurret -{ - Health 125 - Speed 0 - Painchance 0 - Mass 10000000 - Monster - -SOLID - -CANPASS - +AMBUSH - +SPAWNCEILING - +NOGRAVITY - +NOBLOOD - +NOSPLASHALERT - +DONTFALL - MinMissileChance 150 - DeathSound "turret/death" - States - { - Spawn: - TURT A 5 A_TurretLook - Loop - See: - TURT A 2 A_Chase - Loop - Missile: - Pain: - TURT B 4 Slow A_ShootGun - TURT D 3 Slow A_SentinelRefire - TURT A 4 A_SentinelRefire - Loop - Death: - BALL A 6 Bright A_Scream - BALL BCDE 6 Bright - TURT C -1 - Stop - } -} - - -// Power Coupling ----------------------------------------------------------- - -ACTOR PowerCoupling native -{ - Health 40 - Radius 17 - Height 64 - Mass 999999 - +SOLID - +SHOOTABLE - +DROPPED - +NOBLOOD - +NOTDMATCH - +INCOMBAT - States - { - Spawn: - COUP AB 5 - Loop - } -} - -// Gibs for things that bleed ----------------------------------------------- - -ACTOR Meat native -{ - +NOCLIP - States - { - Spawn: - MEAT A 700 - Stop - MEAT B 700 - Stop - MEAT C 700 - Stop - MEAT D 700 - Stop - MEAT E 700 - Stop - MEAT F 700 - Stop - MEAT G 700 - Stop - MEAT H 700 - Stop - MEAT I 700 - Stop - MEAT J 700 - Stop - MEAT K 700 - Stop - MEAT L 700 - Stop - MEAT M 700 - Stop - MEAT N 700 - Stop - MEAT O 700 - Stop - MEAT P 700 - Stop - MEAT Q 700 - Stop - MEAT R 700 - Stop - MEAT S 700 - Stop - MEAT T 700 - Stop - } -} - -// Gibs for things that don't bleed ----------------------------------------- - -ACTOR Junk : Meat -{ -states -{ - Spawn: - JUNK A 700 - Stop - JUNK B 700 - Stop - JUNK C 700 - Stop - JUNK D 700 - Stop - JUNK E 700 - Stop - JUNK F 700 - Stop - JUNK G 700 - Stop - JUNK H 700 - Stop - JUNK I 700 - Stop - JUNK J 700 - Stop - JUNK K 700 - Stop - JUNK L 700 - Stop - JUNK M 700 - Stop - JUNK N 700 - Stop - JUNK O 700 - Stop - JUNK P 700 - Stop - JUNK Q 700 - Stop - JUNK R 700 - Stop - JUNK S 700 - Stop - JUNK T 700 - Stop - } -} - diff --git a/wadsrc/static/actors/strife/strifeweapons.txt b/wadsrc/static/actors/strife/strifeweapons.txt deleted file mode 100644 index b807f110a1..0000000000 --- a/wadsrc/static/actors/strife/strifeweapons.txt +++ /dev/null @@ -1,813 +0,0 @@ - -ACTOR StrifeWeapon : Weapon -{ - Weapon.Kickback 100 -} - -// Same as the bullet puff for Doom ----------------------------------------- - -ACTOR StrifePuff -{ - +NOBLOCKMAP - +NOGRAVITY - +ALLOWPARTICLES - RenderStyle Translucent - Alpha 0.25 - - states - { - Spawn: - POW3 ABCDEFGH 3 - Stop - Crash: - PUFY A 4 Bright - PUFY BCD 4 - Stop - } -} - - -// A spark when you hit something that doesn't bleed ------------------------ -// Only used by the dagger. - -ACTOR StrifeSpark : StrifePuff -{ - RenderStyle Add - States - { - Crash: - POW2 ABCD 4 - Stop - } -} - -// Punch Dagger ------------------------------------------------------------- - -ACTOR PunchDagger : StrifeWeapon -{ - Weapon.SelectionOrder 3900 - +WEAPON.NOALERT - Obituary "$OB_MPPUNCHDAGGER" - Tag "$TAG_PUNCHDAGGER" - - action native A_JabDagger (); - - States - { - Ready: - PNCH A 1 A_WeaponReady - Loop - Deselect: - PNCH A 1 A_Lower - Loop - Select: - PNCH A 1 A_Raise - Loop - Fire: - PNCH B 4 - PNCH C 4 A_JabDagger - PNCH D 5 - PNCH C 4 - PNCH B 5 A_ReFire - Goto Ready - } - -} - - -// The base for Strife projectiles that die with ZAP1 ----------------------- - -ACTOR StrifeZap1 -{ - +NOBLOCKMAP - +NOGRAVITY - +DROPOFF - States - { - Spawn: - Death: - ZAP1 A 3 A_AlertMonsters - ZAP1 BCDEFE 3 - ZAP1 DCB 2 - ZAP1 A 1 - Stop - } -} - - -// Electric Bolt ------------------------------------------------------------ - -ACTOR ElectricBolt : StrifeZap1 -{ - Speed 30 - Radius 10 - Height 10 - Damage 10 - Projectile - +STRIFEDAMAGE - MaxStepHeight 4 - SeeSound "misc/swish" - ActiveSound "misc/swish" - DeathSound "weapons/xbowhit" - Obituary "$OB_MPELECTRICBOLT" - States - { - Spawn: - AROW A 10 A_LoopActiveSound - Loop - } -} - - -// Poison Bolt -------------------------------------------------------------- - -ACTOR PoisonBolt native -{ - Speed 30 - Radius 10 - Height 10 - Damage 500 - Projectile - +STRIFEDAMAGE - MaxStepHeight 4 - SeeSound "misc/swish" - ActiveSound "misc/swish" - Obituary "$OB_MPPOISONBOLT" - States - { - Spawn: - ARWP A 10 A_LoopActiveSound - Loop - Death: - AROW A 1 - Stop - } -} - - -// Strife's Crossbow -------------------------------------------------------- - -ACTOR StrifeCrossbow : StrifeWeapon -{ - +FLOORCLIP - Weapon.SelectionOrder 1200 - +WEAPON.NOALERT - Weapon.AmmoUse1 1 - Weapon.AmmoGive1 8 - Weapon.AmmoType1 "ElectricBolts" - Weapon.SisterWeapon "StrifeCrossbow2" - Inventory.PickupMessage "$TXT_STRIFECROSSBOW" - Tag "$TAG_STRIFECROSSBOW1" - Inventory.Icon "CBOWA0" - - action native A_ClearFlash (); - action native A_ShowElectricFlash (); - action native A_FireArrow (class proj); - - states - { - Spawn: - CBOW A -1 - Stop - Ready: - XBOW A 0 A_ShowElectricFlash - XBOW A 1 A_WeaponReady - Wait - Deselect: - XBOW A 1 A_Lower - Loop - Select: - XBOW A 1 A_Raise - Loop - Fire: - XBOW A 3 A_ClearFlash - XBOW B 6 A_FireArrow("ElectricBolt") - XBOW C 4 - XBOW D 6 - XBOW E 3 - XBOW F 5 - XBOW G 0 A_ShowElectricFlash - XBOW G 5 A_CheckReload - Goto Ready+1 - Flash: - XBOW KLM 5 - Loop - } -} - - -ACTOR StrifeCrossbow2 : StrifeCrossbow -{ - Weapon.SelectionOrder 2700 - Weapon.AmmoUse1 1 - Weapon.AmmoGive1 0 - Weapon.AmmoType1 "PoisonBolts" - Weapon.SisterWeapon "StrifeCrossbow" - Tag "$TAG_STRIFECROSSBOW2" - - States - { - Ready: - XBOW H 1 A_WeaponReady - Loop - Deselect: - XBOW H 1 A_Lower - Loop - Select: - XBOW H 1 A_Raise - Loop - Fire: - XBOW H 3 - XBOW B 6 A_FireArrow("PoisonBolt") - XBOW C 4 - XBOW D 6 - XBOW E 3 - XBOW I 5 - XBOW J 5 A_CheckReload - Goto Ready - Flash: - Stop - } -} - -// Assault Gun -------------------------------------------------------------- - -actor AssaultGun : StrifeWeapon -{ - +FLOORCLIP - Weapon.SelectionOrder 600 - Weapon.AmmoUse1 1 - Weapon.AmmoGive1 20 - Weapon.AmmoType1 "ClipOfBullets" - Inventory.Icon "RIFLA0" - Tag "$TAG_ASSAULTGUN" - Inventory.PickupMessage "$TXT_ASSAULTGUN" - Obituary "$OB_MPASSAULTGUN" - States - { - Spawn: - RIFL A -1 - Stop - Ready: - RIFG A 1 A_WeaponReady - Loop - Deselect: - RIFG B 1 A_Lower - Loop - Select: - RIFG A 1 A_Raise - Loop - Fire: - RIFF AB 3 A_FireAssaultGun - RIFG D 3 A_FireAssaultGun - RIFG C 0 A_ReFire - RIFG B 2 A_Light0 - Goto Ready - } -} - - -// Standing variant of the assault gun -------------------------------------- - -ACTOR AssaultGunStanding : WeaponGiver -{ - DropItem "AssaultGun" - Inventory.PickupMessage "$TXT_ASSAULTGUN" - States - { - Spawn: - RIFL B -1 - Stop - } -} - - -// Mini-Missile Launcher ---------------------------------------------------- - - -ACTOR MiniMissileLauncher : StrifeWeapon -{ - +FLOORCLIP - Weapon.SelectionOrder 1800 - Weapon.AmmoUse1 1 - Weapon.AmmoGive1 8 - Weapon.AmmoType1 "MiniMissiles" - Inventory.Icon "MMSLA0" - Tag "$TAG_MMLAUNCHER" - Inventory.PickupMessage "$TXT_MMLAUNCHER" - - action native A_FireMiniMissile (); - - States - { - Spawn: - MMSL A -1 - Stop - Ready: - MMIS A 1 A_WeaponReady - Loop - Deselect: - MMIS A 1 A_Lower - Loop - Select: - MMIS A 1 A_Raise - Loop - Fire: - MMIS A 4 A_FireMiniMissile - MMIS B 4 A_Light1 - MMIS C 5 Bright - MMIS D 2 Bright A_Light2 - MMIS E 2 Bright - MMIS F 2 Bright A_Light0 - MMIS F 0 A_ReFire - Goto Ready - } -} - - -// Rocket Trail ------------------------------------------------------------- - -ACTOR RocketTrail -{ - +NOBLOCKMAP - +NOGRAVITY - RenderStyle Translucent - Alpha 0.25 - SeeSound "misc/missileinflight" - States - { - Spawn: - PUFY BCBCD 4 - Stop - } -} - -// Rocket Puff -------------------------------------------------------------- - -ACTOR MiniMissilePuff : StrifePuff -{ - -ALLOWPARTICLES - States - { - Spawn: - Goto Crash - } -} - -// Mini Missile ------------------------------------------------------------- - -ACTOR MiniMissile -{ - Speed 20 - Radius 10 - Height 14 - Damage 10 - Projectile - +STRIFEDAMAGE - MaxStepHeight 4 - SeeSound "weapons/minimissile" - DeathSound "weapons/minimissilehit" - Obituary "$OB_MPMINIMISSILELAUNCHER" - States - { - Spawn: - MICR A 6 Bright A_RocketInFlight - Loop - Death: - SMIS A 0 Bright A_SetTranslucent(1,1) - SMIS A 0 Bright // State left for savegame compatibility - SMIS A 5 Bright A_Explode(64,64,1,1) - SMIS B 5 Bright - SMIS C 4 Bright - SMIS DEFG 2 Bright - Stop - } -} - -// Flame Thrower ------------------------------------------------------------ - -ACTOR FlameThrower : StrifeWeapon -{ - +FLOORCLIP - Weapon.SelectionOrder 2100 - Weapon.Kickback 0 - Weapon.AmmoUse1 1 - Weapon.AmmoGive1 100 - Weapon.UpSound "weapons/flameidle" - Weapon.ReadySound "weapons/flameidle" - Weapon.AmmoType1 "EnergyPod" - Inventory.Icon "FLAMA0" - Tag "$TAG_FLAMER" - Inventory.PickupMessage "$TXT_FLAMER" - - action native A_FireFlamer (); - - States - { - Spawn: - FLAM A -1 - Stop - Ready: - FLMT AB 3 A_WeaponReady - Loop - Deselect: - FLMT A 1 A_Lower - Loop - Select: - FLMT A 1 A_Raise - Loop - Fire: - FLMF A 2 A_FireFlamer - FLMF B 3 A_ReFire - Goto Ready - } -} - - -// Flame Thrower Projectile ------------------------------------------------- - -ACTOR FlameMissile -{ - Speed 15 - Height 11 - Radius 8 - Mass 10 - Damage 4 - DamageType Fire - ReactionTime 8 - Projectile - -NOGRAVITY - +STRIFEDAMAGE - MaxStepHeight 4 - RenderStyle Add - SeeSound "weapons/flamethrower" - Obituary "$OB_MPFLAMETHROWER" - - action native A_FlameDie (); - - States - { - Spawn: - FRBL AB 3 Bright - FRBL C 3 Bright A_Countdown - Loop - Death: - FRBL D 5 Bright A_FlameDie - FRBL EFGHI 5 Bright - Stop - } - -} - - -// Mauler ------------------------------------------------------------------- -// The scatter version - -ACTOR Mauler : StrifeWeapon -{ - +FLOORCLIP - Weapon.SelectionOrder 300 - Weapon.AmmoUse1 20 - Weapon.AmmoGive1 40 - Weapon.AmmoType1 "EnergyPod" - Weapon.SisterWeapon "Mauler2" - Inventory.Icon "TRPDA0" - Tag "$TAG_MAULER1" - Inventory.PickupMessage "$TXT_MAULER" - Obituary "$OB_MPMAULER1" - - action native A_FireMauler1 (); - - States - { - Ready: - MAUL FGHA 6 A_WeaponReady - Loop - Deselect: - MAUL A 1 A_Lower - Loop - Select: - MAUL A 1 A_Raise - Loop - Fire: - BLSF A 5 Bright A_FireMauler1 - MAUL B 3 Bright A_Light1 - MAUL C 2 A_Light2 - MAUL DE 2 - MAUL A 7 A_Light0 - MAUL H 7 - MAUL G 7 A_CheckReload - Goto Ready - Spawn: - TRPD A -1 - Stop - } -} - - -// Mauler Torpedo version --------------------------------------------------- - -ACTOR Mauler2 : Mauler -{ - Weapon.SelectionOrder 3300 - Weapon.AmmoUse1 30 - Weapon.AmmoGive1 0 - Weapon.AmmoType1 "EnergyPod" - Weapon.SisterWeapon "Mauler" - Tag "$TAG_MAULER2" - - action native A_FireMauler2Pre (); - action native A_FireMauler2 (); - - States - { - Ready: - MAUL IJKL 7 A_WeaponReady - Loop - Deselect: - MAUL I 1 A_Lower - Loop - Select: - MAUL I 1 A_Raise - Loop - Fire: - MAUL I 20 A_FireMauler2Pre - MAUL J 10 A_Light1 - BLSF A 10 Bright A_FireMauler2 - MAUL B 10 Bright A_Light2 - MAUL C 2 - MAUL D 2 A_Light0 - MAUL E 2 A_ReFire - Goto Ready - } -} - - -// Mauler "Bullet" Puff ----------------------------------------------------- - -ACTOR MaulerPuff -{ - +NOBLOCKMAP - +NOGRAVITY - +PUFFONACTORS - RenderStyle Add - DamageType Disintegrate - states - { - Spawn: - MPUF AB 5 - POW1 ABCDE 4 - Stop - } -} - -// The Mauler's Torpedo ----------------------------------------------------- - -ACTOR MaulerTorpedo -{ - Speed 20 - Height 8 - Radius 13 - Damage 1 - DamageType Disintegrate - Projectile - +STRIFEDAMAGE - MaxStepHeight 4 - RenderStyle Add - SeeSound "weapons/mauler2fire" - DeathSound "weapons/mauler2hit" - Obituary "$OB_MPMAULER" - - action native A_MaulerTorpedoWave (); - - States - { - Spawn: - TORP ABCD 4 Bright - Loop - Death: - THIT AB 8 Bright - THIT C 8 Bright A_MaulerTorpedoWave - THIT DE 8 Bright - Stop - } -} - - -// The mini torpedoes shot by the big torpedo -------------------------------- - -ACTOR MaulerTorpedoWave -{ - Speed 35 - Radius 13 - Height 13 - Damage 10 - DamageType Disintegrate - Projectile - +STRIFEDAMAGE - MaxStepHeight 4 - RenderStyle Add - Obituary "$OB_MPMAULER" - States - { - Spawn: - TWAV AB 9 Bright - Death: - TWAV C 9 Bright - Stop - } -} - - -// High-Explosive Grenade --------------------------------------------------- - -ACTOR HEGrenade -{ - Speed 15 - Radius 13 - Height 13 - Mass 20 - Damage 1 - Reactiontime 30 - Projectile - -NOGRAVITY - +STRIFEDAMAGE - +BOUNCEONACTORS - +EXPLODEONWATER - MaxStepHeight 4 - BounceType "Doom" - BounceFactor 0.5 - BounceCount 2 - SeeSound "weapons/hegrenadeshoot" - DeathSound "weapons/hegrenadebang" - Obituary "$OB_MPSTRIFEGRENADE" - States - { - Spawn: - GRAP AB 3 A_Countdown - Loop - Death: - BNG4 A 0 Bright A_NoGravity - BNG4 A 0 Bright A_SetTranslucent(1,1) - BNG4 A 2 Bright A_Explode(192,192,1,1) - BNG4 BCDEFGHIJKLMN 3 Bright - Stop - } -} - -// White Phosphorous Grenade ------------------------------------------------ - -ACTOR PhosphorousGrenade -{ - Speed 15 - Radius 13 - Height 13 - Mass 20 - Damage 1 - Reactiontime 40 - Projectile - -NOGRAVITY - +STRIFEDAMAGE - +BOUNCEONACTORS - +EXPLODEONWATER - BounceType "Doom" - MaxStepHeight 4 - BounceFactor 0.5 - BounceCount 2 - SeeSound "weapons/phgrenadeshoot" - DeathSound "weapons/phgrenadebang" - Obituary "$OB_MPPHOSPHOROUSGRENADE" - States - { - Spawn: - GRIN AB 3 A_Countdown - Loop - Death: - BNG3 A 2 A_SpawnItemEx("PhosphorousFire") - Stop - } -} - -// Fire from the Phoshorous Grenade ----------------------------------------- - -ACTOR PhosphorousFire native -{ - Reactiontime 120 - DamageType Fire - +NOBLOCKMAP - +FLOORCLIP - +NOTELEPORT - +NODAMAGETHRUST - +DONTSPLASH - RenderStyle Add - Obituary "$OB_MPPHOSPHOROUSGRENADE" - - action native A_Burnarea (); - action native A_Burnination (); - - states - { - Spawn: - BNG3 B 2 Bright A_Burnarea - BNG3 C 2 Bright A_Countdown - FLBE A 2 Bright A_Burnination - FLBE B 2 Bright A_Countdown - FLBE C 2 Bright A_Burnarea - FLBE D 3 Bright A_Countdown - FLBE E 3 Bright A_Burnarea - FLBE F 3 Bright A_Countdown - FLBE G 3 Bright A_Burnination - Goto Spawn+5 - Death: - FLBE H 2 Bright - FLBE I 2 Bright A_Burnination - FLBE JK 2 Bright - Stop - } -} - -// High-Explosive Grenade Launcher ------------------------------------------ - -ACTOR StrifeGrenadeLauncher : StrifeWeapon -{ - +FLOORCLIP - Weapon.SelectionOrder 2400 - Weapon.AmmoUse1 1 - Weapon.AmmoGive1 12 - Weapon.AmmoType1 "HEGrenadeRounds" - Weapon.SisterWeapon "StrifeGrenadeLauncher2" - Inventory.Icon "GRNDA0" - Tag "$TAG_GLAUNCHER1" - Inventory.PickupMessage "$TXT_GLAUNCHER" - - action native A_FireGrenade (class grenadetype, float angleofs, state flash); - - States - { - Spawn: - GRND A -1 - Stop - Ready: - GREN A 1 A_WeaponReady - Loop - Deselect: - GREN A 1 A_Lower - Loop - Select: - GREN A 1 A_Raise - Loop - Fire: - GREN A 5 A_FireGrenade("HEGrenade", -90, "Flash") - GREN B 10 - GREN A 5 A_FireGrenade("HEGrenade", 90, "Flash2") - GREN C 10 - GREN A 0 A_ReFire - Goto Ready - Flash: - GREF A 5 Bright A_Light1 - Goto LightDone - Flash2: - GREF B 5 Bright A_Light2 - Goto LightDone - } - -} - -// White Phosphorous Grenade Launcher --------------------------------------- - -ACTOR StrifeGrenadeLauncher2 : StrifeGrenadeLauncher -{ - Weapon.SelectionOrder 3200 - Weapon.AmmoUse1 1 - Weapon.AmmoGive1 0 - Weapon.AmmoType1 "PhosphorusGrenadeRounds" - Weapon.SisterWeapon "StrifeGrenadeLauncher" - Tag "$TAG_GLAUNCHER2" - - States - { - Ready: - GREN D 1 A_WeaponReady - Loop - Deselect: - GREN D 1 A_Lower - Loop - Select: - GREN D 1 A_Raise - Loop - Fire: - GREN D 5 A_FireGrenade("PhosphorousGrenade", -90, "Flash") - GREN E 10 - GREN D 5 A_FireGrenade("PhosphorousGrenade", 90, "Flash2") - GREN F 10 - GREN A 0 A_ReFire - Goto Ready - Flash: - GREF C 5 Bright A_Light1 - Goto LightDone - Flash2: - GREF D 5 Bright A_Light2 - Goto LightDone - } -} - diff --git a/wadsrc/static/actors/strife/templar.txt b/wadsrc/static/actors/strife/templar.txt deleted file mode 100644 index f15195c3d8..0000000000 --- a/wadsrc/static/actors/strife/templar.txt +++ /dev/null @@ -1,66 +0,0 @@ - -ACTOR Templar -{ - Health 300 - Painchance 100 - Speed 8 - Radius 20 - Height 60 - Mass 500 - Monster - +NOBLOOD - +SEESDAGGERS - +NOSPLASHALERT - MaxdropoffHeight 32 - MinMissileChance 200 - SeeSound "templar/sight" - PainSound "templar/pain" - DeathSound "templar/death" - ActiveSound "templar/active" - CrushPainSound "misc/pcrush" - Tag "$TAG_TEMPLAR" - HitObituary "$OB_TEMPLARHIT" - Obituary "$OB_TEMPLAR" - DropItem "EnergyPod" - - action native A_TemplarAttack(); - - States - { - Spawn: - PGRD A 5 A_Look2 - Loop - PGRD B 10 - Loop - PGRD C 10 - Loop - PGRD B 10 A_Wander - Loop - See: - PGRD AABBCCDD 3 A_Chase - Loop - Melee: - PGRD E 8 A_FaceTarget - PGRD F 8 A_CustomMeleeAttack(random[ReaverMelee](1,8)*3, "reaver/blade") - Goto See - Missile: - PGRD G 8 BRIGHT A_FaceTarget - PGRD H 8 BRIGHT A_TemplarAttack - Goto See - Pain: - PGRD A 2 - PGRD A 2 A_Pain - Goto See - Death: - PGRD I 4 A_TossGib - PGRD J 4 A_Scream - PGRD K 4 A_TossGib - PGRD L 4 A_NoBlocking - PGRD MN 4 - PGRD O 4 A_TossGib - PGRD "PQRSTUVWXYZ[" 4 - PGRD "\" -1 - Stop - } -} - diff --git a/wadsrc/static/actors/strife/thingstoblowup.txt b/wadsrc/static/actors/strife/thingstoblowup.txt deleted file mode 100644 index 8f81488095..0000000000 --- a/wadsrc/static/actors/strife/thingstoblowup.txt +++ /dev/null @@ -1,141 +0,0 @@ - - -// A Cloud used for varius explosions --------------------------------------- -// This actor has no direct equivalent in strife. To create this, Strife -// spawned a spark and then changed its state to that of this explosion -// cloud. Weird. - -ACTOR Bang4Cloud -{ - +NOBLOCKMAP - +NOGRAVITY - RenderStyle Add - VSpeed 1 - States - { - Spawn: - BNG4 BCDEFGHIJKLMN 3 Bright - Stop - } -} - -// Piston ------------------------------------------------------------------- - -ACTOR Piston -{ - Health 100 - Speed 16 - Radius 20 - Height 76 - Mass 10000000 - +SOLID - +SHOOTABLE - +NOBLOOD - +FLOORCLIP - +INCOMBAT - DeathSound "misc/explosion" - states - { - Spawn: - PSTN AB 8 - Loop - Death: - PSTN A 4 Bright A_Scream - PSTN B 4 Bright A_NoBlocking - PSTN C 4 Bright A_GiveQuestItem(16) - PSTN D 4 Bright A_Bang4Cloud - PSTN E 4 Bright A_TossGib - PSTN F 4 Bright - PSTN G 4 Bright A_Bang4Cloud - PSTN H 4 - PSTN I -1 - Stop - } - -} - -// Computer ----------------------------------------------------------------- - -ACTOR Computer -{ - Health 80 - Speed 27 - Radius 26 - Height 128 - Mass 10000000 - +SOLID - +SHOOTABLE - +NOBLOOD - +FLOORCLIP - +INCOMBAT - DeathSound "misc/explosion" - states - { - Spawn: - SECR ABCD 4 Bright - Loop - Death: - SECR E 5 Bright A_Bang4Cloud - SECR F 5 Bright A_NoBlocking - SECR G 5 Bright A_GiveQuestItem(27) - SECR H 5 Bright A_TossGib - SECR I 5 Bright A_Bang4Cloud - SECR J 5 - SECR K 5 A_Bang4Cloud - SECR L 5 - SECR M 5 A_Bang4Cloud - SECR N 5 - SECR O 5 A_Bang4Cloud - SECR P -1 - Stop - } -} - - -// Power Crystal ------------------------------------------------------------ - -ACTOR PowerCrystal -{ - Health 50 - Speed 14 - Radius 20 - Height 16 - Mass 99999999 - +SOLID - +SHOOTABLE - +NOGRAVITY - +NOBLOOD - +FLOORCLIP - DeathSound "misc/explosion" - ActiveSound "misc/reactor" - - action native A_ExtraLightOff (); - action native A_Explode512 (); - action native A_LightGoesOut (); - - States - { - Spawn: - CRYS A 16 A_LoopActiveSound - CRYS B 5 A_LoopActiveSound - CRYS CDEF 4 A_LoopActiveSound - Loop - Death: - BOOM A 0 Bright A_Scream - BOOM A 1 Bright A_Explode512 - BOOM B 3 Bright A_GiveQuestItem(14) - BOOM C 2 Bright A_LightGoesOut - BOOM D 3 Bright A_Bang4Cloud - BOOM EF 3 Bright - BOOM G 3 Bright A_Bang4Cloud - BOOM H 1 Bright A_Explode512 - BOOM I 3 Bright - BOOM JKL 3 Bright A_Bang4Cloud - BOOM MN 3 Bright - BOOM O 3 Bright A_Bang4Cloud - BOOM PQRST 3 Bright - BOOM U 3 Bright A_ExtraLightOff - BOOM VWXY 3 Bright - Stop - } -} diff --git a/wadsrc/static/actors/strife/zombie.txt b/wadsrc/static/actors/strife/zombie.txt deleted file mode 100644 index 54683b824c..0000000000 --- a/wadsrc/static/actors/strife/zombie.txt +++ /dev/null @@ -1,58 +0,0 @@ - -// Zombie ------------------------------------------------------------------- - -ACTOR Zombie : StrifeHumanoid -{ - Health 31 - Radius 20 - Height 56 - PainChance 0 - +SOLID - +SHOOTABLE - +FLOORCLIP - +CANPASS - +CANPUSHWALLS - +ACTIVATEMCROSS - MinMissileChance 150 - MaxStepHeight 16 - MaxDropOffHeight 32 - Translation 0 - DeathSound "zombie/death" - CrushPainSound "misc/pcrush" - States - { - Spawn: - PEAS A 5 A_CheckTerrain - Loop - Pain: - AGRD A 5 A_CheckTerrain - Loop - Death: - GIBS M 5 A_TossGib - GIBS N 5 A_XScream - GIBS O 5 A_NoBlocking - GIBS PQRST 4 A_TossGib - GIBS U 5 - GIBS V -1 - Stop - } -} - - -// Zombie Spawner ----------------------------------------------------------- - -ACTOR ZombieSpawner -{ - Health 20 - +SHOOTABLE - +NOSECTOR - RenderStyle None - ActiveSound "zombie/spawner" // Does Strife use this somewhere else? - States - { - Spawn: - TNT1 A 175 A_SpawnItemEx("Zombie") - Loop - } -} - diff --git a/wadsrc/static/decorate.txt b/wadsrc/static/decorate.txt deleted file mode 100644 index 71c7d549b5..0000000000 --- a/wadsrc/static/decorate.txt +++ /dev/null @@ -1,181 +0,0 @@ -#include "actors/constants.txt" -#include "actors/actor.txt" - -#include "actors/shared/inventory.txt" -#include "actors/shared/player.txt" -#include "actors/shared/morph.txt" -#include "actors/shared/botstuff.txt" -#include "actors/shared/sharedmisc.txt" -#include "actors/shared/blood.txt" -#include "actors/shared/debris.txt" -#include "actors/shared/decal.txt" -#include "actors/shared/splashes.txt" -#include "actors/shared/pickups.txt" -#include "actors/shared/fountain.txt" -#include "actors/shared/spark.txt" -#include "actors/shared/soundsequence.txt" -#include "actors/shared/soundenvironment.txt" -#include "actors/shared/bridge.txt" -#include "actors/shared/specialspot.txt" -#include "actors/shared/teleport.txt" -#include "actors/shared/camera.txt" -#include "actors/shared/movingcamera.txt" -#include "actors/shared/mapmarker.txt" -#include "actors/shared/waterzone.txt" -#include "actors/shared/skies.txt" -#include "actors/shared/hatetarget.txt" -#include "actors/shared/secrettrigger.txt" -#include "actors/shared/setcolor.txt" -#include "actors/shared/sectoraction.txt" -#include "actors/shared/action.txt" -#include "actors/shared/dog.txt" -#include "actors/shared/damagetypes.txt" -#include "actors/shared/dynlights.txt" - -#include "actors/doom/doomplayer.txt" -#include "actors/doom/possessed.txt" -#include "actors/doom/doomimp.txt" -#include "actors/doom/demon.txt" -#include "actors/doom/lostsoul.txt" -#include "actors/doom/cacodemon.txt" -#include "actors/doom/bruiser.txt" -#include "actors/doom/revenant.txt" -#include "actors/doom/arachnotron.txt" -#include "actors/doom/fatso.txt" -#include "actors/doom/painelemental.txt" -#include "actors/doom/archvile.txt" -#include "actors/doom/cyberdemon.txt" -#include "actors/doom/spidermaster.txt" -#include "actors/doom/keen.txt" -#include "actors/doom/bossbrain.txt" - -#include "actors/doom/deadthings.txt" -#include "actors/doom/doomammo.txt" -#include "actors/doom/doomarmor.txt" -#include "actors/doom/doomartifacts.txt" -#include "actors/doom/doomhealth.txt" -#include "actors/doom/doomkeys.txt" -#include "actors/doom/doommisc.txt" -#include "actors/doom/doomdecorations.txt" -#include "actors/doom/doomweapons.txt" -#include "actors/doom/stealthmonsters.txt" -#include "actors/doom/scriptedmarine.txt" - -#include "actors/raven/artiegg.txt" -#include "actors/raven/artitele.txt" -#include "actors/raven/ravenartifacts.txt" -#include "actors/raven/ravenhealth.txt" -#include "actors/raven/ravenambient.txt" -#include "actors/raven/minotaur.txt" - -#include "actors/heretic/hereticplayer.txt" -#include "actors/heretic/hereticammo.txt" -#include "actors/heretic/hereticarmor.txt" -#include "actors/heretic/hereticartifacts.txt" -#include "actors/heretic/heretickeys.txt" -#include "actors/heretic/hereticdecorations.txt" -#include "actors/heretic/hereticmisc.txt" -#include "actors/heretic/hereticweaps.txt" -#include "actors/heretic/mummy.txt" -#include "actors/heretic/clink.txt" -#include "actors/heretic/beast.txt" -#include "actors/heretic/snake.txt" -#include "actors/heretic/hereticimp.txt" -#include "actors/heretic/knight.txt" -#include "actors/heretic/wizard.txt" -#include "actors/heretic/ironlich.txt" -#include "actors/heretic/dsparil.txt" -#include "actors/heretic/chicken.txt" - -#include "actors/hexen/baseweapons.txt" -#include "actors/hexen/korax.txt" -#include "actors/hexen/fighterplayer.txt" -#include "actors/hexen/clericplayer.txt" -#include "actors/hexen/mageplayer.txt" -#include "actors/hexen/pig.txt" -#include "actors/hexen/flame.txt" -#include "actors/hexen/flies.txt" -#include "actors/hexen/hexenarmor.txt" -#include "actors/hexen/hexendecorations.txt" -#include "actors/hexen/hexenkeys.txt" -#include "actors/hexen/hexenspecialdecs.txt" -#include "actors/hexen/mana.txt" -#include "actors/hexen/puzzleitems.txt" -#include "actors/hexen/scriptprojectiles.txt" -#include "actors/hexen/speedboots.txt" -#include "actors/hexen/ettin.txt" -#include "actors/hexen/centaur.txt" -#include "actors/hexen/demons.txt" -#include "actors/hexen/firedemon.txt" -#include "actors/hexen/fog.txt" -#include "actors/hexen/summon.txt" -#include "actors/hexen/flechette.txt" -#include "actors/hexen/clericboss.txt" -#include "actors/hexen/fighterboss.txt" -#include "actors/hexen/mageboss.txt" -#include "actors/hexen/bats.txt" -#include "actors/hexen/bishop.txt" -#include "actors/hexen/blastradius.txt" -#include "actors/hexen/boostarmor.txt" -#include "actors/hexen/clericmace.txt" -#include "actors/hexen/clericflame.txt" -#include "actors/hexen/clericholy.txt" -#include "actors/hexen/clericstaff.txt" -#include "actors/hexen/magewand.txt" -#include "actors/hexen/magecone.txt" -#include "actors/hexen/magelightning.txt" -#include "actors/hexen/magestaff.txt" -#include "actors/hexen/fighterfist.txt" -#include "actors/hexen/fighteraxe.txt" -#include "actors/hexen/fighterhammer.txt" -#include "actors/hexen/fighterquietus.txt" -#include "actors/hexen/dragon.txt" -#include "actors/hexen/healingradius.txt" -#include "actors/hexen/teleportother.txt" -#include "actors/hexen/iceguy.txt" -#include "actors/hexen/serpent.txt" -#include "actors/hexen/spike.txt" -#include "actors/hexen/wraith.txt" -#include "actors/hexen/heresiarch.txt" - -#include "actors/strife/strifehumanoid.txt" -#include "actors/strife/strifeplayer.txt" -#include "actors/strife/strifeweapons.txt" -#include "actors/strife/spectral.txt" -#include "actors/strife/acolyte.txt" -#include "actors/strife/alienspectres.txt" -#include "actors/strife/beggars.txt" -#include "actors/strife/coin.txt" -#include "actors/strife/crusader.txt" -#include "actors/strife/entityboss.txt" -#include "actors/strife/inquisitor.txt" -#include "actors/strife/loremaster.txt" -#include "actors/strife/macil.txt" -#include "actors/strife/merchants.txt" -#include "actors/strife/peasants.txt" -#include "actors/strife/strifebishop.txt" -#include "actors/strife/oracle.txt" -#include "actors/strife/programmer.txt" -#include "actors/strife/questitems.txt" -#include "actors/strife/ratbuddy.txt" -#include "actors/strife/rebels.txt" -#include "actors/strife/reaver.txt" -#include "actors/strife/sentinel.txt" -#include "actors/strife/stalker.txt" -#include "actors/strife/strifeammo.txt" -#include "actors/strife/strifearmor.txt" -#include "actors/strife/strifeitems.txt" -#include "actors/strife/strifekeys.txt" -#include "actors/strife/strifestuff.txt" -#include "actors/strife/thingstoblowup.txt" -#include "actors/strife/templar.txt" -#include "actors/strife/zombie.txt" -#include "actors/strife/sigil.txt" - -#include "actors/chex/chexmonsters.txt" -#include "actors/chex/chexkeys.txt" -#include "actors/chex/chexammo.txt" -#include "actors/chex/chexweapons.txt" -#include "actors/chex/chexitems.txt" -#include "actors/chex/chexdecorations.txt" -#include "actors/chex/chexplayer.txt" diff --git a/wadsrc/static/dehsupp.txt b/wadsrc/static/dehsupp.txt index 78948677f4..436e894b48 100644 --- a/wadsrc/static/dehsupp.txt +++ b/wadsrc/static/dehsupp.txt @@ -327,7 +327,7 @@ StateMap BossEye, Spawn, 3, // S_BRAINEYE - S_BRAINEYE1 SpawnShot, Spawn, 4, // S_SPAWN1 - S_SPAWN4 SpawnFire, Spawn, 8, // S_SPAWNFIRE1 - S_SPAWNFIRE8 - BossBrain, BrainExplode, 3, // S_BRAINEXPLODE1 - S_BRAINEXPLODE3 + Rocket, BrainExplode, 3, // S_BRAINEXPLODE1 - S_BRAINEXPLODE3 GreenArmor, Spawn, 2, // S_ARM1 - S_ARM1A BlueArmor, Spawn, 2, // S_ARM2 - S_ARM2A ExplosiveBarrel, Spawn, 7, // S_BAR1 - S_BEXP5 diff --git a/wadsrc/static/filter/doom.doom1/sprofs.txt b/wadsrc/static/filter/doom.doom1/sprofs.txt new file mode 100644 index 0000000000..eab3dc4ef0 --- /dev/null +++ b/wadsrc/static/filter/doom.doom1/sprofs.txt @@ -0,0 +1,164 @@ +BAR1A0, 10, 32, iwad +BAR1B0, 10, 32, iwad +BEXPA0, 10, 32, iwad +BEXPB0, 10, 31, iwad +BEXPC0, 19, 36, iwad +BEXPD0, 27, 49, iwad +BEXPE0, 29, 52, iwad +BOS2I0, 20, 71, iwad +BOS2J0, 26, 62, iwad +BOS2K0, 26, 52, iwad +BOS2L0, 29, 33, iwad +BOS2M0, 30, 29, iwad +BOS2N0, 30, 29, iwad +BOS2O0, 30, 29, iwad +BOSSI0, 20, 72, iwad +BOSSJ0, 26, 63, iwad +BOSSK0, 26, 51, iwad +BOSSL0, 29, 33, iwad +BOSSM0, 30, 29, iwad +BOSSN0, 30, 29, iwad +BOSSO0, 30, 29, iwad +BRS1A0, 13, 8, iwad +BSPIJ0, 50, 54, iwad +BSPIK0, 50, 57, iwad +BSPIL0, 47, 52, iwad +BSPIM0, 45, 44, iwad +BSPIN0, 45, 42, iwad +BSPIO0, 45, 30, iwad +BSPIP0, 45, 28, iwad +CBRAA0, 15, 60, iwad +CEYEA0, 21, 59, iwad +CEYEB0, 21, 58, iwad +CEYEC0, 21, 59, iwad +COL1A0, 16, 51, iwad +COL2A0, 16, 39, iwad +COL3A0, 16, 52, iwad +COL4A0, 17, 39, iwad +COL5A0, 16, 44, iwad +COL5B0, 16, 45, iwad +COL6A0, 17, 47, iwad +COLUA0, 9, 45, iwad +CPOSH0, 20, 61, iwad +CPOSI0, 23, 64, iwad +CPOSJ0, 28, 59, iwad +CPOSK0, 30, 48, iwad +CPOSL0, 31, 34, iwad +CPOSM0, 32, 22, iwad +CPOSN0, 32, 18, iwad +CPOSO0, 26, 59, iwad +CPOSP0, 28, 59, iwad +CPOSQ0, 30, 48, iwad +CPOSR0, 32, 40, iwad +CPOSS0, 32, 31, iwad +CPOST0, 32, 19, iwad +CYBRH0, 60, 108, iwad +CYBRI0, 55, 110, iwad +CYBRJ0, 49, 113, iwad +CYBRK0, 56, 114, iwad +CYBRL0, 62, 121, iwad +CYBRM0, 67, 128, iwad +CYBRN0, 70, 132, iwad +CYBRO0, 69, 132, iwad +CYBRP0, 60, 28, iwad +ELECA0, 19, 125, iwad +FATTO0, 35, 43, iwad +FATTP0, 36, 41, iwad +FATTQ0, 36, 40, iwad +FATTR0, 36, 40, iwad +FATTS0, 36, 40, iwad +FATTT0, 36, 39, iwad +FCANA0, 19, 52, iwad +FCANB0, 19, 52, iwad +FCANC0, 19, 50, iwad +PLAYH0, 16, 50, iwad +PLAYI0, 11, 42, iwad +PLAYJ0, 12, 45, iwad +PLAYK0, 17, 37, iwad +PLAYL0, 27, 14, iwad +PLAYM0, 27, 14, iwad +PLAYN0, 27, 14, iwad +POB1A0, 16, 6, iwad +POB2A0, 14, 3, iwad +POL1A0, 22, 65, iwad +POL2A0, 19, 66, iwad +POL3A0, 19, 42, iwad +POL3B0, 19, 42, iwad +POL4A0, 19, 55, iwad +POL5A0, 27, 8, iwad +POL6A0, 17, 65, iwad +POL6B0, 19, 65, iwad +POSSH0, 19, 55, iwad +POSSL0, 22, 14, iwad +SARGI0, 25, 56, iwad +SARGM0, 33, 43, iwad +SARGN0, 33, 29, iwad +SKELM0, 27, 78, iwad +SKELN0, 38, 69, iwad +SKELO0, 28, 55, iwad +SKELP0, 28, 35, iwad +SKELQ0, 40, 20, iwad +SMITA0, 22, 44, iwad +SPIDJ0, 79, 102, iwad +SPIDK0, 95, 95, iwad +SPIDL0, 94, 88, iwad +SPIDM0, 94, 76, iwad +SPIDN0, 98, 71, iwad +SPIDO0, 101, 68, iwad +SPIDP0, 104, 85, iwad +SPIDQ0, 109, 90, iwad +SPIDR0, 110, 111, iwad +SPIDS0, 98, 35, iwad +SPOSH0, 14, 60, iwad +SPOSL0, 24, 15, iwad +SSWVG0, 17, 55, iwad +SSWVH0, 17, 52, iwad +SSWVI0, 18, 54, iwad +SSWVJ0, 15, 44, iwad +SSWVK0, 15, 40, iwad +SSWVL0, 15, 25, iwad +SSWVM0, 24, 13, iwad +SSWVN0, 15, 57, iwad +SSWVO0, 22, 59, iwad +SSWVP0, 25, 58, iwad +TBLUA0, 14, 94, iwad +TBLUB0, 14, 94, iwad +TBLUC0, 14, 94, iwad +TBLUD0, 14, 95, iwad +TGRNA0, 14, 94, iwad +TGRNB0, 14, 89, iwad +TGRNC0, 14, 89, iwad +TGRND0, 14, 95, iwad +TLMPA0, 11, 78, iwad +TLMPB0, 11, 78, iwad +TLMPC0, 11, 78, iwad +TLMPD0, 11, 78, iwad +TLP2A0, 10, 58, iwad +TLP2B0, 10, 58, iwad +TLP2C0, 10, 58, iwad +TLP2D0, 10, 58, iwad +TRE1A0, 25, 67, iwad +TREDA0, 14, 94, iwad +TREDB0, 14, 89, iwad +TREDC0, 14, 89, iwad +TREDD0, 14, 95, iwad +TROOI0, 22, 62, iwad +TROOJ0, 21, 59, iwad +TROOM0, 29, 20, iwad +TROON0, 24, 59, iwad +TROOO0, 20, 61, iwad +TROOP0, 24, 61, iwad +TROOQ0, 24, 61, iwad +TROOR0, 24, 44, iwad +TROOS0, 27, 34, iwad +TROOT0, 27, 31, iwad +TROOU0, 27, 18, iwad +VILER0, 18, 80, iwad +VILES0, 23, 76, iwad +VILET0, 27, 69, iwad +VILEU0, 35, 56, iwad +VILEV0, 34, 45, iwad +VILEW0, 34, 35, iwad +VILEX0, 34, 23, iwad +VILEY0, 34, 20, iwad +VILEZ0, 34, 20, iwad diff --git a/wadsrc/static/filter/doom.doom2/sprofs.txt b/wadsrc/static/filter/doom.doom2/sprofs.txt new file mode 100644 index 0000000000..eab3dc4ef0 --- /dev/null +++ b/wadsrc/static/filter/doom.doom2/sprofs.txt @@ -0,0 +1,164 @@ +BAR1A0, 10, 32, iwad +BAR1B0, 10, 32, iwad +BEXPA0, 10, 32, iwad +BEXPB0, 10, 31, iwad +BEXPC0, 19, 36, iwad +BEXPD0, 27, 49, iwad +BEXPE0, 29, 52, iwad +BOS2I0, 20, 71, iwad +BOS2J0, 26, 62, iwad +BOS2K0, 26, 52, iwad +BOS2L0, 29, 33, iwad +BOS2M0, 30, 29, iwad +BOS2N0, 30, 29, iwad +BOS2O0, 30, 29, iwad +BOSSI0, 20, 72, iwad +BOSSJ0, 26, 63, iwad +BOSSK0, 26, 51, iwad +BOSSL0, 29, 33, iwad +BOSSM0, 30, 29, iwad +BOSSN0, 30, 29, iwad +BOSSO0, 30, 29, iwad +BRS1A0, 13, 8, iwad +BSPIJ0, 50, 54, iwad +BSPIK0, 50, 57, iwad +BSPIL0, 47, 52, iwad +BSPIM0, 45, 44, iwad +BSPIN0, 45, 42, iwad +BSPIO0, 45, 30, iwad +BSPIP0, 45, 28, iwad +CBRAA0, 15, 60, iwad +CEYEA0, 21, 59, iwad +CEYEB0, 21, 58, iwad +CEYEC0, 21, 59, iwad +COL1A0, 16, 51, iwad +COL2A0, 16, 39, iwad +COL3A0, 16, 52, iwad +COL4A0, 17, 39, iwad +COL5A0, 16, 44, iwad +COL5B0, 16, 45, iwad +COL6A0, 17, 47, iwad +COLUA0, 9, 45, iwad +CPOSH0, 20, 61, iwad +CPOSI0, 23, 64, iwad +CPOSJ0, 28, 59, iwad +CPOSK0, 30, 48, iwad +CPOSL0, 31, 34, iwad +CPOSM0, 32, 22, iwad +CPOSN0, 32, 18, iwad +CPOSO0, 26, 59, iwad +CPOSP0, 28, 59, iwad +CPOSQ0, 30, 48, iwad +CPOSR0, 32, 40, iwad +CPOSS0, 32, 31, iwad +CPOST0, 32, 19, iwad +CYBRH0, 60, 108, iwad +CYBRI0, 55, 110, iwad +CYBRJ0, 49, 113, iwad +CYBRK0, 56, 114, iwad +CYBRL0, 62, 121, iwad +CYBRM0, 67, 128, iwad +CYBRN0, 70, 132, iwad +CYBRO0, 69, 132, iwad +CYBRP0, 60, 28, iwad +ELECA0, 19, 125, iwad +FATTO0, 35, 43, iwad +FATTP0, 36, 41, iwad +FATTQ0, 36, 40, iwad +FATTR0, 36, 40, iwad +FATTS0, 36, 40, iwad +FATTT0, 36, 39, iwad +FCANA0, 19, 52, iwad +FCANB0, 19, 52, iwad +FCANC0, 19, 50, iwad +PLAYH0, 16, 50, iwad +PLAYI0, 11, 42, iwad +PLAYJ0, 12, 45, iwad +PLAYK0, 17, 37, iwad +PLAYL0, 27, 14, iwad +PLAYM0, 27, 14, iwad +PLAYN0, 27, 14, iwad +POB1A0, 16, 6, iwad +POB2A0, 14, 3, iwad +POL1A0, 22, 65, iwad +POL2A0, 19, 66, iwad +POL3A0, 19, 42, iwad +POL3B0, 19, 42, iwad +POL4A0, 19, 55, iwad +POL5A0, 27, 8, iwad +POL6A0, 17, 65, iwad +POL6B0, 19, 65, iwad +POSSH0, 19, 55, iwad +POSSL0, 22, 14, iwad +SARGI0, 25, 56, iwad +SARGM0, 33, 43, iwad +SARGN0, 33, 29, iwad +SKELM0, 27, 78, iwad +SKELN0, 38, 69, iwad +SKELO0, 28, 55, iwad +SKELP0, 28, 35, iwad +SKELQ0, 40, 20, iwad +SMITA0, 22, 44, iwad +SPIDJ0, 79, 102, iwad +SPIDK0, 95, 95, iwad +SPIDL0, 94, 88, iwad +SPIDM0, 94, 76, iwad +SPIDN0, 98, 71, iwad +SPIDO0, 101, 68, iwad +SPIDP0, 104, 85, iwad +SPIDQ0, 109, 90, iwad +SPIDR0, 110, 111, iwad +SPIDS0, 98, 35, iwad +SPOSH0, 14, 60, iwad +SPOSL0, 24, 15, iwad +SSWVG0, 17, 55, iwad +SSWVH0, 17, 52, iwad +SSWVI0, 18, 54, iwad +SSWVJ0, 15, 44, iwad +SSWVK0, 15, 40, iwad +SSWVL0, 15, 25, iwad +SSWVM0, 24, 13, iwad +SSWVN0, 15, 57, iwad +SSWVO0, 22, 59, iwad +SSWVP0, 25, 58, iwad +TBLUA0, 14, 94, iwad +TBLUB0, 14, 94, iwad +TBLUC0, 14, 94, iwad +TBLUD0, 14, 95, iwad +TGRNA0, 14, 94, iwad +TGRNB0, 14, 89, iwad +TGRNC0, 14, 89, iwad +TGRND0, 14, 95, iwad +TLMPA0, 11, 78, iwad +TLMPB0, 11, 78, iwad +TLMPC0, 11, 78, iwad +TLMPD0, 11, 78, iwad +TLP2A0, 10, 58, iwad +TLP2B0, 10, 58, iwad +TLP2C0, 10, 58, iwad +TLP2D0, 10, 58, iwad +TRE1A0, 25, 67, iwad +TREDA0, 14, 94, iwad +TREDB0, 14, 89, iwad +TREDC0, 14, 89, iwad +TREDD0, 14, 95, iwad +TROOI0, 22, 62, iwad +TROOJ0, 21, 59, iwad +TROOM0, 29, 20, iwad +TROON0, 24, 59, iwad +TROOO0, 20, 61, iwad +TROOP0, 24, 61, iwad +TROOQ0, 24, 61, iwad +TROOR0, 24, 44, iwad +TROOS0, 27, 34, iwad +TROOT0, 27, 31, iwad +TROOU0, 27, 18, iwad +VILER0, 18, 80, iwad +VILES0, 23, 76, iwad +VILET0, 27, 69, iwad +VILEU0, 35, 56, iwad +VILEV0, 34, 45, iwad +VILEW0, 34, 35, iwad +VILEX0, 34, 23, iwad +VILEY0, 34, 20, iwad +VILEZ0, 34, 20, iwad diff --git a/wadsrc/static/filter/heretic/sprofs.txt b/wadsrc/static/filter/heretic/sprofs.txt new file mode 100644 index 0000000000..5f51dcde1f --- /dev/null +++ b/wadsrc/static/filter/heretic/sprofs.txt @@ -0,0 +1,97 @@ +BARLA0, 14, 35, iwad +BEASK0, 37, 77, iwad +BEASM0, 42, 74, iwad +BEASQ0, 29, 11, iwad +BEASU0, 44, 91, iwad +BEASV0, 49, 79, iwad +BEASW0, 51, 68, iwad +BEASX0, 52, 56, iwad +BEASY0, 41, 41, iwad +BEASZ0, 41, 30, iwad +BRPLA0, 28, 128, iwad +CHKNF0, 18, 25, iwad +CHKNG0, 17, 27, iwad +CHKNH0, 18, 30, iwad +CHKNI0, 20, 29, iwad +CHKNJ0, 20, 25, iwad +CHKNK0, 17, 9, iwad +CHKNL0, 13, 4, iwad +CLNKO0, 23, 16, iwad +FDTHA0, 21, 55, iwad +FDTHB0, 21, 60, iwad +FDTHC0, 29, 80, iwad +FDTHD0, 21, 76, iwad +FDTHE0, 22, 75, iwad +FDTHF0, 23, 59, iwad +FDTHG0, 24, 51, iwad +FDTHH0, 23, 48, iwad +FDTHI0, 23, 53, iwad +FDTHJ0, 22, 53, iwad +FDTHK0, 22, 55, iwad +FDTHL0, 23, 56, iwad +FDTHM0, 25, 58, iwad +FDTHN0, 26, 58, iwad +FDTHO0, 24, 59, iwad +IMPXI0, 22, 24, iwad +IMPXJ0, 22, 34, iwad +IMPXK0, 21, 34, iwad +IMPXL0, 22, 9, iwad +IMPXW0, 32, 49, iwad +IMPXX0, 33, 41, iwad +IMPXY0, 33, 25, iwad +IMPXZ0, 33, 11, iwad +KFR1A0, 20, 77, iwad +KFR1B0, 20, 78, iwad +KFR1C0, 20, 81, iwad +KFR1D0, 20, 81, iwad +KFR1E0, 20, 76, iwad +KFR1F0, 20, 78, iwad +KFR1G0, 20, 80, iwad +KFR1H0, 20, 78, iwad +KGZ1A0, 18, 52, iwad +MUMMI0, 33, 64, iwad +MUMMJ0, 34, 66, iwad +MUMMK0, 39, 71, iwad +MUMML0, 40, 66, iwad +MUMMM0, 36, 55, iwad +MUMMN0, 37, 37, iwad +MUMMO0, 38, 19, iwad +MUMMP0, 31, 10, iwad +PLAYS0, 34, 71, iwad +PLAYT0, 35, 68, iwad +PLAYU0, 30, 44, iwad +PLAYV0, 30, 24, iwad +PLAYW0, 30, 23, iwad +PLAYX0, 30, 17, iwad +PLAYY0, 30, 14, iwad +SFFIA0, 5, 20, iwad +SFFIB0, 6, 15, iwad +SFFIC0, 6, 11, iwad +SFFID0, 5, 8, iwad +SFFIE0, 4, 5, iwad +SMPLA0, 14, 37, iwad +SNKEM0, 54, 48, iwad +SNKEN0, 49, 35, iwad +SNKEO0, 48, 23, iwad +SNKEP0, 46, 13, iwad +SRCRE0, 59, 131, iwad +SRCRF0, 52, 120, iwad +SRCRG0, 68, 122, iwad +SRCRH0, 60, 114, iwad +SRCRI0, 63, 105, iwad +SRCRJ0, 67, 76, iwad +SRCRK0, 67, 32, iwad +SRCRL0, 67, 23, iwad +SRCRM0, 67, 28, iwad +SRCRN0, 67, 29, iwad +SRCRO0, 67, 23, iwad +SRCRP0, 67, 17, iwad +SRTCA0, 5, 63, iwad +SRTCB0, 5, 63, iwad +SRTCC0, 5, 61, iwad +STGLA0, 18, 69, iwad +STGSA0, 9, 37, iwad +WZRDJ0, 34, 59, iwad +WZRDK0, 30, 49, iwad +WZRDL0, 29, 26, iwad +WZRDM0, 27, 12, iwad diff --git a/wadsrc/static/filter/hexen/sprofs.txt b/wadsrc/static/filter/hexen/sprofs.txt new file mode 100644 index 0000000000..a8d614ca07 --- /dev/null +++ b/wadsrc/static/filter/hexen/sprofs.txt @@ -0,0 +1,377 @@ +ZBARA0, 12, 33, iwad +BDPLA0, 7, 2, iwad +BDSHA0, 8, 6, iwad +BDSHB0, 8, 7, iwad +BDSHC0, 8, 7, iwad +BDSHD0, 9, 5, iwad +BISHK0, 43, 74, iwad +BISHL0, 45, 74, iwad +BISHM0, 45, 65, iwad +BISHN0, 43, 22, iwad +BISHO0, 40, 12, iwad +BISHP0, 30, 9, iwad +BRTRA0, 13, 61, iwad +BRTRB0, 13, 59, iwad +BRTRC0, 13, 57, iwad +BRTRD0, 13, 60, iwad +BRTRE0, 13, 59, iwad +BRTRF0, 13, 54, iwad +BRTRG0, 13, 54, iwad +BRTRH0, 13, 57, iwad +BRTRI0, 13, 60, iwad +BRTRJ0, 13, 62, iwad +BRTRK0, 13, 62, iwad +BRTRL0, 13, 58, iwad +BRTRM0, 13, 59, iwad +BCANA0, 10, 38, iwad +BCANB0, 10, 36, iwad +BCANC0, 10, 35, iwad +BCAND0, 10, 35, iwad +BCANE0, 10, 35, iwad +CDRNA0, 14, 24, iwad +CDRNB0, 14, 24, iwad +CDRNC0, 14, 24, iwad +CDRND0, 14, 24, iwad +CDRNE0, 14, 24, iwad +CDRNF0, 14, 24, iwad +CDRNG0, 14, 24, iwad +CDRNH0, 14, 24, iwad +CENTK0, 42, 73, iwad +CENTN0, 49, 76, iwad +CENTO0, 45, 83, iwad +CENTP0, 47, 80, iwad +CENTQ0, 55, 63, iwad +CENTR0, 53, 38, iwad +CENTS0, 43, 27, iwad +CENTT0, 43, 27, iwad +CLERM0, 28, 51, iwad +CLERN0, 26, 42, iwad +CLERO0, 26, 34, iwad +CLERQ0, 26, 16, iwad +CLERR0, 23, 67, iwad +CLERS0, 30, 67, iwad +CLERT0, 35, 68, iwad +CLERU0, 34, 64, iwad +CLERV0, 35, 61, iwad +CLERW0, 37, 53, iwad +CLERX0, 37, 43, iwad +CLERY0, 38, 30, iwad +CLERZ0, 38, 18, iwad +CLER[0, 38, 12, iwad +CPB1A0, 8, 7, iwad +CPB2A0, 7, 6, iwad +CPB3A0, 12, 4, iwad +CPB4A0, 5, 10, iwad +CPS2A0, 24, 13, iwad +CPS6A0, 22, 36, iwad +CTDPJ0, 21, 9, iwad +DEM2H0, 50, 92, iwad +DEM2I0, 67, 124, iwad +DEM2J0, 60, 121, iwad +DEM2K0, 76, 123, iwad +DEM2L0, 68, 115, iwad +DEM2M0, 71, 105, iwad +DEM2N0, 75, 76, iwad +DEM2O0, 75, 32, iwad +DEM2P0, 75, 17, iwad +DEMNH0, 50, 92, iwad +DEMNI0, 67, 124, iwad +DEMNJ0, 60, 121, iwad +DEMNK0, 76, 123, iwad +DEMNL0, 68, 115, iwad +DEMNM0, 71, 105, iwad +DEMNN0, 75, 76, iwad +DEMNO0, 75, 32, iwad +DEMNP0, 75, 17, iwad +DRAGM0, 45, 22, iwad +ETTBB0, 45, 73, iwad +ETTBC0, 39, 80, iwad +ETTBD0, 45, 87, iwad +ETTBE0, 51, 84, iwad +ETTBF0, 53, 74, iwad +ETTBG0, 48, 70, iwad +ETTBH0, 49, 64, iwad +ETTBI0, 50, 52, iwad +ETTBJ0, 50, 31, iwad +ETTBK0, 50, 22, iwad +ETTBL0, 50, 22, iwad +ETTBM0, 14, 20, iwad +ETTNO0, 42, 46, iwad +ETTNP0, 42, 56, iwad +ETTNQ0, 36, 34, iwad +FDTHA0, 29, 64, iwad +FDTHB0, 29, 64, iwad +FDTHE0, 28, 62, iwad +FDTHF0, 28, 62, iwad +FDTHG0, 29, 80, iwad +FDTHH0, 17, 76, iwad +FDTHI0, 19, 76, iwad +FDTHJ0, 20, 56, iwad +FDTHK0, 21, 51, iwad +FDTHL0, 21, 47, iwad +FDTHM0, 21, 46, iwad +FDTHN0, 21, 47, iwad +FDTHO0, 20, 49, iwad +FDTHP0, 21, 49, iwad +FDTHQ0, 19, 50, iwad +FDTHR0, 20, 51, iwad +FFLGA0, 4, 4, iwad +FFLGB0, 4, 11, iwad +FFLGC0, 6, 24, iwad +FFLGD0, 10, 28, iwad +FFLGE0, 6, 35, iwad +FFLGF0, 7, 40, iwad +FFLGG0, 7, 40, iwad +FFLGH0, 7, 34, iwad +FFLGI0, 7, 33, iwad +FFLGJ0, 7, 28, iwad +FFLGK0, 7, 28, iwad +FFLGL0, 7, 31, iwad +FFLGM0, 7, 34, iwad +FFLGN0, 7, 37, iwad +FFLGO0, 7, 39, iwad +FFLGP0, 7, 40, iwad +FFLGQ0, 7, 33, iwad +FFSMA0, 2, 20, iwad +FFSMB0, 2, 20, iwad +FFSMC0, 2, 18, iwad +FFSMD0, 2, 16, iwad +FFSME0, 2, 17, iwad +FSKLA0, 11, 54, iwad +FSKLB0, 11, 52, iwad +FSKLC0, 11, 50, iwad +FSKLD0, 11, 53, iwad +FSKLE0, 11, 47, iwad +FSKLF0, 11, 47, iwad +FSKLG0, 11, 53, iwad +FSKLH0, 11, 48, iwad +FSKLI0, 11, 51, iwad +GAR1A0, 25, 121, iwad +GAR2A0, 25, 121, iwad +GAR3A0, 25, 121, iwad +GAR4A0, 25, 121, iwad +GAR5A0, 25, 121, iwad +GAR6A0, 25, 75, iwad +GAR7A0, 25, 75, iwad +GAR8A0, 24, 75, iwad +GAR9A0, 25, 75, iwad +GMPDA0, 14, 46, iwad +GMPDB0, 14, 53, iwad +ICM4A0, 2, 23, iwad +IRONA0, 23, 62, iwad +LOGGA0, 20, 55, iwad +MAGEK0, 41, 42, iwad +MAGEL0, 43, 33, iwad +MAGEM0, 43, 21, iwad +MAGEN0, 31, 12, iwad +MAGEO0, 26, 71, iwad +MAGEP0, 30, 72, iwad +MAGEQ0, 33, 66, iwad +MAGER0, 34, 60, iwad +MAGES0, 36, 57, iwad +MAGET0, 37, 50, iwad +MAGEU0, 35, 39, iwad +MAGEV0, 36, 30, iwad +MAGEW0, 35, 18, iwad +MAGEX0, 35, 9, iwad +MSH1A0, 15, 25, iwad +MSH2A0, 13, 25, iwad +MSH3A0, 11, 21, iwad +MSH4A0, 7, 15, iwad +MSH5A0, 7, 11, iwad +MSH6A0, 6, 11, iwad +MSH7A0, 7, 12, iwad +MSH8A0, 5, 16, iwad +PIGYE0, 12, 24, iwad +PIGYF0, 17, 29, iwad +PIGYG0, 22, 41, iwad +PLAYL0, 36, 42, iwad +PLAYM0, 36, 31, iwad +PLAYN0, 40, 17, iwad +PLAYO0, 24, 72, iwad +PLAYP0, 31, 74, iwad +PLAYQ0, 35, 70, iwad +PLAYR0, 38, 64, iwad +PLAYS0, 38, 55, iwad +PLAYT0, 40, 44, iwad +PLAYU0, 40, 34, iwad +PLAYV0, 41, 28, iwad +PLAYW0, 39, 13, iwad +POT1A0, 10, 37, iwad +POT2A0, 10, 30, iwad +POT3A0, 12, 24, iwad +RBL1A0, 21, 9, iwad +RBL2A0, 14, 8, iwad +RBL3A0, 15, 10, iwad +RCK1A0, 7, 7, iwad +RCK2A0, 10, 11, iwad +RCK3A0, 14, 18, iwad +RCK4A0, 24, 22, iwad +RKBKA0, 30, 40, iwad +RKBSA0, 18, 50, iwad +ROKKA0, 11, 16, iwad +ROKKB0, 8, 11, iwad +ROKKC0, 4, 6, iwad +ROKKD0, 6, 6, iwad +ROKKE0, 4, 5, iwad +ROKKG0, 3, 5, iwad +ROKKH0, 3, 3, iwad +SGM1A0, 17, 69, iwad +SGM2A0, 12, 54, iwad +SGM3A0, 14, 44, iwad +SGMPA0, 18, 126, iwad +SHRMA0, 13, 25, iwad +SHRMB0, 15, 26, iwad +SHRMC0, 21, 36, iwad +SHRMD0, 23, 40, iwad +SHRME0, 17, 26, iwad +SHRMF0, 19, 15, iwad +SLTRA0, 23, 52, iwad +SORCH0, 29, 92, iwad +SORCI0, 34, 97, iwad +SORCJ0, 36, 98, iwad +SORCK0, 41, 101, iwad +SORCL0, 48, 97, iwad +SORCM0, 50, 97, iwad +SORCN0, 47, 97, iwad +SORCO0, 46, 97, iwad +SORCP0, 46, 95, iwad +SORCQ0, 34, 95, iwad +SORCR0, 34, 86, iwad +SORCS0, 34, 72, iwad +SORCT0, 34, 50, iwad +SORCU0, 34, 29, iwad +SORCV0, 40, 31, iwad +SORCW0, 52, 41, iwad +SORCX0, 54, 46, iwad +SORCY0, 48, 33, iwad +SORCZ0, 34, 12, iwad +SSPTO0, 36, 66, iwad +SSPTP0, 38, 73, iwad +SSPTQ0, 35, 69, iwad +SSPTR0, 33, 53, iwad +SSPTS0, 34, 52, iwad +SSPTT0, 44, 43, iwad +SSPTU0, 47, 30, iwad +SSPTV0, 41, 35, iwad +SSPTW0, 35, 43, iwad +SSPTX0, 29, 47, iwad +SSPTY0, 24, 33, iwad +SSPTZ0, 27, 17, iwad +SSXDA0, 36, 66, iwad +SSXDB0, 37, 68, iwad +SSXDC0, 52, 68, iwad +SSXDD0, 58, 54, iwad +SSXDE0, 59, 37, iwad +SSXDF0, 61, 22, iwad +SSXDG0, 57, 18, iwad +SSXDH0, 52, 13, iwad +STM1A0, 24, 39, iwad +STM2A0, 25, 32, iwad +STM3A0, 13, 25, iwad +STM4A0, 12, 34, iwad +STT2A0, 25, 121, iwad +STT3A0, 25, 121, iwad +STT4A0, 25, 75, iwad +STT5A0, 25, 75, iwad +STTWA0, 29, 83, iwad +STWNA0, 29, 83, iwad +STWNB0, 29, 83, iwad +ZSUIA0, 18, 80, iwad +ZSUIB0, 8, 8, iwad +ZSUIC0, 6, 11, iwad +ZSUID0, 6, 9, iwad +ZSUIE0, 9, 11, iwad +ZSUIF0, 6, 10, iwad +ZSUIG0, 4, 7, iwad +ZSUIH0, 12, 14, iwad +ZSUII0, 11, 7, iwad +ZSUIJ0, 7, 3, iwad +ZSUIK0, 13, 3, iwad +SWMVA0, 22, 68, iwad +TMS1A0, 19, 52, iwad +TMS2A0, 19, 52, iwad +TMS3A0, 20, 52, iwad +TMS4A0, 16, 58, iwad +TMS5A0, 18, 58, iwad +TMS6A0, 14, 54, iwad +TMS7A0, 15, 54, iwad +TRDTA0, 57, 187, iwad +TRDTB0, 76, 181, iwad +TRDTC0, 88, 153, iwad +TRDTD0, 84, 85, iwad +TRDTE0, 81, 52, iwad +TRDTF0, 61, 31, iwad +TRDTG0, 23, 31, iwad +TRDTH0, 58, 187, iwad +TRDTI0, 77, 183, iwad +TRDTJ0, 89, 191, iwad +TRDTK0, 85, 191, iwad +TRDTL0, 82, 156, iwad +TRDTM0, 62, 141, iwad +TRDTN0, 48, 140, iwad +TRDTO0, 48, 82, iwad +TRDTP0, 38, 39, iwad +TRDTQ0, 26, 39, iwad +ZTREA0, 43, 134, iwad +TRESA0, 51, 179, iwad +TRE4A0, 73, 187, iwad +TRE5A0, 72, 187, iwad +TRE6A0, 56, 122, iwad +TRE7A0, 55, 122, iwad +TSPKB0, 26, 131, iwad +TSPKD0, 22, 9, iwad +TST0A0, 12, 22, iwad +TST1A0, 6, 20, iwad +TST2A0, 6, 16, iwad +TST3A0, 9, 25, iwad +TST4A0, 6, 21, iwad +TST5A0, 6, 25, iwad +TST6A0, 8, 10, iwad +TST7A0, 6, 13, iwad +TST8A0, 6, 10, iwad +TST9A0, 6, 10, iwad +TWTRA0, 14, 79, iwad +TWTRB0, 14, 81, iwad +TWTRC0, 14, 83, iwad +TWTRD0, 14, 83, iwad +TWTRE0, 14, 79, iwad +TWTRF0, 14, 80, iwad +TWTRG0, 14, 82, iwad +TWTRH0, 14, 80, iwad +TWTRI0, 14, 65, iwad +VASEA0, 11, 53, iwad +XMASA0, 23, 150, iwad +XMASB0, 25, 151, iwad +XMASC0, 25, 151, iwad +XMASD0, 30, 151, iwad +XMASE0, 20, 151, iwad +XMASF0, 14, 156, iwad +XMASG0, 5, 163, iwad +XMASH0, 5, 152, iwad +XMASI0, 8, 132, iwad +XMASJ0, 10, 72, iwad +XMASK0, 13, 17, iwad +FHFXN0, 26, 21, iwad +CTDPG0, 15, 15, iwad +CTDPH0, 21, 7, iwad +CTDPI0, 17, 12, iwad +CTDPJ0, 21, 11, iwad +CTDPR0, 18, 12, iwad +CTDPS0, 21, 6, iwad +CTDPT0, 23, 3, iwad +ETTBM0, 14, 15, iwad +ETTBN0, 18, 8, iwad +ETTBO0, 15, 5, iwad +ETTBP0, 13, 8, iwad +ETTBQ0, 9, 16, iwad +ETTBR0, 18, 18, iwad +ETTBS0, 20, 15, iwad +THRWA0, 10, 15, iwad +THRWB0, 10, 18, iwad +THRWC0, 8, 20, iwad +THRWD0, 6, 18, iwad +THRWE0, 6, 16, iwad +THRWF0, 8, 19, iwad +THRWG0, 8, 19, iwad +THRWH0, 11, 19, iwad diff --git a/wadsrc/static/filter/strife/sprofs.txt b/wadsrc/static/filter/strife/sprofs.txt new file mode 100644 index 0000000000..d7118297bc --- /dev/null +++ b/wadsrc/static/filter/strife/sprofs.txt @@ -0,0 +1,364 @@ +TWAVA0, 47, 20, iwad +TWAVB0, 20, 15, iwad +ZAP5A0, 13, 6, iwad +ZAP5B0, 15, 6, iwad +ZAP5C0, 13, 6, iwad +ZAP5D0, 14, 6, iwad +BARTB0, 11, 31, iwad +BARTC0, 14, 31, iwad +BARTD0, 19, 34, iwad +BARTE0, 23, 36, iwad +BARTF0, 26, 40, iwad +BARTG0, 27, 43, iwad +BARTH0, 27, 44, iwad +BARTI0, 27, 45, iwad +BARTJ0, 27, 46, iwad +BARTK0, 27, 50, iwad +BARTL0, 27, 7, iwad +BARWB0, 12, 30, iwad +BARWC0, 14, 30, iwad +BARWD0, 15, 29, iwad +BARWE0, 15, 26, iwad +BARWF0, 18, 23, iwad +BARWG0, 19, 18, iwad +BARWH0, 19, 11, iwad +FLBEC0, 21, 51, iwad +FLBED0, 24, 77, iwad +DIE1A0, 27, 7, iwad +DEADA0, 31, 11, iwad +SACRA0, 31, 13, iwad +RGIBD0, 27, 48, iwad +RGIBE0, 27, 30, iwad +RGIBF0, 27, 17, iwad +RGIBG0, 27, 12, iwad +RGIBH0, 27, 10, iwad +GIBSM0, 18, 54, iwad +GIBSN0, 23, 58, iwad +GIBSO0, 23, 60, iwad +GIBSP0, 26, 54, iwad +GIBSQ0, 27, 42, iwad +GIBSR0, 27, 29, iwad +GIBSS0, 27, 19, iwad +GIBST0, 27, 11, iwad +GIBSU0, 27, 8, iwad +GIBSV0, 27, 7, iwad +GIBSA0, 28, 58, iwad +GIBSB0, 31, 62, iwad +GIBSC0, 31, 62, iwad +GIBSD0, 31, 60, iwad +GIBSE0, 31, 54, iwad +GIBSF0, 31, 38, iwad +GIBSG0, 31, 22, iwad +GIBSH0, 31, 13, iwad +GIBSI0, 31, 10, iwad +GIBSJ0, 31, 10, iwad +GIBSK0, 31, 10, iwad +GIBSL0, 31, 10, iwad +PLAYG0, 26, 54, iwad +PLAYN0, 24, 28, iwad +PLAYO0, 27, 22, iwad +PLAYP0, 27, 13, iwad +BURNA0, 15, 55, iwad +BURNB0, 23, 58, iwad +BURNC0, 23, 61, iwad +BURND0, 22, 67, iwad +BURNE0, 20, 65, iwad +BURNF0, 18, 69, iwad +BURNQ0, 23, 54, iwad +BURNR0, 23, 22, iwad +BURNS0, 23, 30, iwad +BURNT0, 23, 21, iwad +BURNU0, 23, 13, iwad +BURNV0, 23, 11, iwad +MRSTA0, 11, 59, iwad +MRLKA0, 11, 59, iwad +MRLKB0, 11, 59, iwad +MRBDA0, 11, 59, iwad +MRBDB0, 8, 59, iwad +MRBDC0, 8, 59, iwad +MRBDD0, 8, 59, iwad +MRBDE0, 8, 60, iwad +MRBDF0, 11, 59, iwad +MRYSA0, 16, 55, iwad +MRPNA0, 16, 50, iwad +MRPNB0, 11, 47, iwad +MRPNC0, 11, 43, iwad +MRPND0, 10, 41, iwad +MRGTA0, 17, 59, iwad +MRGTB0, 17, 59, iwad +MRGTC0, 19, 59, iwad +MRGTD0, 17, 59, iwad +MRGTE0, 17, 59, iwad +MRGTF0, 18, 59, iwad +MRGTG0, 16, 59, iwad +MRGTH0, 13, 59, iwad +MRGTI0, 14, 59, iwad +MRNOA0, 11, 59, iwad +MRNOB0, 11, 59, iwad +MRNOC0, 11, 58, iwad +ARMRA0, 31, 68, iwad +PEASG0, 14, 49, iwad +PEASH0, 11, 42, iwad +PEASI0, 12, 45, iwad +PEASJ0, 11, 43, iwad +PEASK0, 14, 37, iwad +PEASL0, 26, 16, iwad +PEASM0, 27, 13, iwad +PEASN0, 27, 13, iwad +BEGRF0, 10, 54, iwad +BEGRG0, 14, 58, iwad +BEGRH0, 18, 60, iwad +BEGRL0, 15, 37, iwad +BEGRM0, 17, 21, iwad +BEGRN0, 19, 10, iwad +HMN1G0, 23, 53, iwad +HMN1H0, 22, 50, iwad +HMN1J0, 20, 49, iwad +HMN1K0, 20, 45, iwad +HMN1L0, 20, 39, iwad +HMN1M0, 20, 24, iwad +HMN1N0, 20, 16, iwad +LEADG0, 26, 52, iwad +LEADH0, 24, 51, iwad +LEADI0, 23, 53, iwad +LEADJ0, 22, 51, iwad +LEADK0, 22, 49, iwad +LEADL0, 22, 47, iwad +LEADM0, 22, 49, iwad +LEADN0, 22, 53, iwad +LEADO0, 22, 50, iwad +LEADP0, 22, 43, iwad +LEADQ0, 31, 40, iwad +LEADR0, 31, 33, iwad +LEADS0, 31, 30, iwad +LEADT0, 31, 27, iwad +LEADU0, 31, 23, iwad +LEADV0, 31, 18, iwad +LEADW0, 31, 13, iwad +LEADX0, 31, 10, iwad +ROB2G0, 40, 67, iwad +ROB2H0, 48, 70, iwad +ROB2I0, 54, 92, iwad +ROB2J0, 48, 92, iwad +ROB2K0, 52, 79, iwad +ROB2L0, 58, 85, iwad +ROB2M0, 55, 92, iwad +ROB2N0, 51, 93, iwad +ROB2O0, 47, 98, iwad +SEWRI0, 46, 48, iwad +SEWRJ0, 29, 30, iwad +DISRA0, 23, 55, iwad +DISRB0, 23, 57, iwad +DISRC0, 22, 57, iwad +DISRD0, 16, 62, iwad +DISRE0, 19, 61, iwad +DISRF0, 19, 59, iwad +DISRG0, 22, 55, iwad +DISRH0, 23, 44, iwad +DISRI0, 23, 38, iwad +DISRJ0, 23, 32, iwad +PRGRA0, 51, 69, iwad +PRGRS0, 51, 28, iwad +PRGRT0, 51, 21, iwad +PRGRU0, 51, 20, iwad +PRGRV0, 51, 19, iwad +PRGRW0, 51, 19, iwad +PRGRX0, 51, 18, iwad +BASEG0, 35, 23, iwad +BASEH0, 35, 23, iwad +SPIDB1, 30, 34, iwad +SPIDB2, 37, 33, iwad +SPIDB3, 26, 34, iwad +SPIDB4, 37, 34, iwad +SPIDB5, 33, 32, iwad +SPIDB6, 37, 34, iwad +SPIDB7, 27, 34, iwad +SPIDB8, 37, 32, iwad +ROB3L0, 60, 122, iwad +ROB3M0, 65, 121, iwad +ROB3N0, 98, 114, iwad +ROB3O0, 94, 105, iwad +RBB3D0, 43, 43, iwad +RBB3E0, 43, 29, iwad +RBB3G0, 33, 46, iwad +RBB3H0, 37, 36, iwad +PGRDI0, 27, 56, iwad +PGRDJ0, 31, 56, iwad +PGRDK0, 35, 60, iwad +PGRDL0, 31, 61, iwad +PGRDM0, 27, 60, iwad +PGRDN0, 27, 63, iwad +PGRDO0, 31, 60, iwad +PGRDP0, 39, 53, iwad +PGRDQ0, 43, 39, iwad +PGRDR0, 43, 32, iwad +PGRDS0, 39, 26, iwad +PGRDT0, 35, 28, iwad +PGRDU0, 35, 28, iwad +PGRDV0, 35, 28, iwad +PGRDW0, 35, 28, iwad +PGRDX0, 35, 28, iwad +PGRDY0, 35, 28, iwad +PGRDZ0, 35, 28, iwad +PGRD[0, 35, 28, iwad +PGRD\0, 35, 28, iwad +PDEDE0, 22, 20, iwad +PDEDF0, 23, 16, iwad +PDEDG0, 23, 15, iwad +PDEDH0, 23, 15, iwad +PDEDI0, 23, 15, iwad +PDEDJ0, 23, 17, iwad +PDEDK0, 23, 20, iwad +PDEDL0, 23, 22, iwad +PDEDM0, 22, 23, iwad +PDEDN0, 22, 26, iwad +PDEDO0, 23, 26, iwad +PDEDP0, 23, 24, iwad +PDEDQ0, 23, 21, iwad +PDEDR0, 23, 15, iwad +PDEDS0, 23, 11, iwad +PDEDT0, 23, 5, iwad +ORCLB0, 23, 77, iwad +ORCLC0, 23, 70, iwad +ORCLD0, 23, 70, iwad +ORCLE0, 23, 70, iwad +ORCLF0, 23, 70, iwad +ORCLG0, 23, 70, iwad +ORCLH0, 23, 70, iwad +ORCLI0, 23, 71, iwad +ORCLJ0, 23, 68, iwad +ORCLK0, 23, 61, iwad +ORCLL0, 23, 53, iwad +ORCLM0, 23, 50, iwad +ORCLN0, 23, 45, iwad +ORCLO0, 23, 42, iwad +ORCLP0, 23, 42, iwad +ORCLQ0, 23, 42, iwad +NEALD0, 14, 48, iwad +NEALE0, 10, 43, iwad +NEALF0, 7, 38, iwad +NEALG0, 4, 35, iwad +NEALH0, 3, 32, iwad +NEALI0, 3, 28, iwad +NEALJ0, 3, 11, iwad +MLDRH0, 41, 131, iwad +MLDRI0, 54, 122, iwad +MLDRJ0, 57, 115, iwad +MLDRK0, 59, 127, iwad +MLDRL0, 72, 126, iwad +MLDRM0, 72, 134, iwad +MLDRN0, 63, 102, iwad +MLDRQ0, 38, 85, iwad +MLDRR0, 59, 61, iwad +MLDRT0, 55, 44, iwad +MLDRU0, 55, 44, iwad +MLDRV0, 55, 46, iwad +TRAYA0, 11, 39, iwad +RUB1A0, 4, 9, iwad +RUB2A0, 4, 10, iwad +RUB5A0, 2, 12, iwad +RUB7A0, 3, 12, iwad +RUB8A0, 4, 11, iwad +SPLHA0, 4, 8, iwad +SPLHB0, 4, 8, iwad +SPLHC0, 4, 8, iwad +SPLHD0, 4, 8, iwad +SPLHE0, 4, 8, iwad +SPLHF0, 4, 8, iwad +SPLHG0, 4, 7, iwad +CNDLA0, 4, 16, iwad +BARLA0, 12, 41, iwad +BARLB0, 12, 41, iwad +BARLC0, 12, 41, iwad +BARLD0, 12, 41, iwad +MUGGA0, 7, 11, iwad +VASEA0, 11, 22, iwad +STATA0, 19, 64, iwad +LTRHA0, 10, 70, iwad +LTRHB0, 10, 65, iwad +LTRHC0, 10, 69, iwad +LTRHD0, 10, 68, iwad +HERTA0, 15, 56, iwad +HERTB0, 15, 56, iwad +HERTC0, 15, 56, iwad +MONIA0, 19, 125, iwad +STELA0, 15, 127, iwad +STLEA0, 15, 40, iwad +VASEB0, 11, 31, iwad +STOLA0, 7, 23, iwad +POT1A0, 7, 13, iwad +LAMPA0, 11, 79, iwad +TUB1A0, 11, 14, iwad +TREEC0, 14, 63, iwad +BUSHA0, 15, 47, iwad +SHRBA0, 23, 63, iwad +BAR1A0, 15, 57, iwad +HUGEA0, 23, 190, iwad +HUGEB0, 23, 190, iwad +HUGEC0, 23, 190, iwad +HUGED0, 23, 190, iwad +STLGB0, 16, 60, iwad +STLGE0, 16, 100, iwad +STLGF0, 6, 31, iwad +TNK1A0, 15, 192, iwad +TNK1B0, 15, 192, iwad +TNK1C0, 15, 192, iwad +TNK2A0, 15, 192, iwad +TNK2B0, 15, 192, iwad +TNK2C0, 15, 192, iwad +TNK4A0, 15, 56, iwad +TNK4B0, 15, 56, iwad +TNK4C0, 15, 56, iwad +TNK3A0, 15, 192, iwad +TNK3B0, 15, 192, iwad +TNK3C0, 15, 192, iwad +TNK5A0, 15, 56, iwad +TNK5B0, 15, 56, iwad +TNK5C0, 15, 56, iwad +TNK6A0, 15, 56, iwad +TNK6B0, 15, 56, iwad +TNK6C0, 15, 56, iwad +APOWA0, 27, 198, iwad +LANTA0, 8, 79, iwad +LMPCA0, 11, 78, iwad +LMPCB0, 11, 78, iwad +LMPCC0, 11, 74, iwad +LMPCD0, 11, 78, iwad +LMPCE0, 11, 78, iwad +STLAA0, 15, 78, iwad +TLMPA0, 10, 63, iwad +TLMPB0, 11, 78, iwad +LOGSA0, 14, 91, iwad +LOGSB0, 14, 93, iwad +LOGSC0, 14, 93, iwad +LOGSD0, 14, 93, iwad +LOGSE0, 14, 93, iwad +HOGNA0, 23, 80, iwad +HOGNB0, 11, 80, iwad +HOGNC0, 2, 80, iwad +PSTNA0, 23, 128, iwad +PSTNB0, 23, 128, iwad +PSTNC0, 23, 128, iwad +PSTND0, 23, 128, iwad +PSTNE0, 23, 128, iwad +FLGRA0, 8, 39, iwad +FLGBA0, 8, 39, iwad +FLGGA0, 8, 39, iwad +PSTNF0, 23, 126, iwad +PSTNG0, 23, 94, iwad +PSTNH0, 23, 63, iwad +PSTNI0, 23, 15, iwad +STAKA0, 17, 127, iwad +COUPA0, 11, 22, iwad +COUPB0, 11, 22, iwad +COUPC0, 11, 22, iwad +AFEDA0, 11, 24, iwad +BOTRA0, 8, 16, iwad +HATRA0, 4, 13, iwad +TOPRA0, 12, 11, iwad +BUBBA0, 15, 127, iwad +BUBFA0, 15, 65, iwad +ASPRA0, 23, 127, iwad +SPDLA0, 30, 52, iwad +SPDLB0, 30, 52, iwad +SPDLC0, 30, 51, iwad diff --git a/wadsrc/static/mapinfo/common.txt b/wadsrc/static/mapinfo/common.txt index 5e69a3ef9d..81a791de6b 100644 --- a/wadsrc/static/mapinfo/common.txt +++ b/wadsrc/static/mapinfo/common.txt @@ -585,3 +585,8 @@ Intermission Inter_Chess Position = 5, 135 } } + +DamageType Drowning +{ + NoArmor +} diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt new file mode 100644 index 0000000000..f12e554bba --- /dev/null +++ b/wadsrc/static/zscript.txt @@ -0,0 +1,212 @@ +#include "zscript/base.txt" +#include "zscript/constants.txt" +#include "zscript/actor.txt" +#include "zscript/actor_checks.txt" + +#include "zscript/shared/inventory.txt" +#include "zscript/shared/inv_misc.txt" +#include "zscript/shared/weapons.txt" +#include "zscript/shared/armor.txt" +#include "zscript/shared/powerups.txt" +#include "zscript/shared/player.txt" +#include "zscript/shared/morph.txt" +#include "zscript/shared/botstuff.txt" +#include "zscript/shared/sharedmisc.txt" +#include "zscript/shared/blood.txt" +#include "zscript/shared/debris.txt" +#include "zscript/shared/decal.txt" +#include "zscript/shared/splashes.txt" +#include "zscript/shared/itemeffects.txt" +#include "zscript/shared/fountain.txt" +#include "zscript/shared/spark.txt" +#include "zscript/shared/soundsequence.txt" +#include "zscript/shared/soundenvironment.txt" +#include "zscript/shared/bridge.txt" +#include "zscript/shared/specialspot.txt" +#include "zscript/shared/teleport.txt" +#include "zscript/shared/camera.txt" +#include "zscript/shared/movingcamera.txt" +#include "zscript/shared/mapmarker.txt" +#include "zscript/shared/waterzone.txt" +#include "zscript/shared/skies.txt" +#include "zscript/shared/hatetarget.txt" +#include "zscript/shared/secrettrigger.txt" +#include "zscript/shared/setcolor.txt" +#include "zscript/shared/sectoraction.txt" +#include "zscript/shared/ice.txt" +#include "zscript/shared/dog.txt" +#include "zscript/shared/fastprojectile.txt" +#include "zscript/shared/dynlights.txt" + +#include "zscript/doom/doomplayer.txt" +#include "zscript/doom/possessed.txt" +#include "zscript/doom/doomimp.txt" +#include "zscript/doom/demon.txt" +#include "zscript/doom/lostsoul.txt" +#include "zscript/doom/cacodemon.txt" +#include "zscript/doom/bruiser.txt" +#include "zscript/doom/revenant.txt" +#include "zscript/doom/arachnotron.txt" +#include "zscript/doom/fatso.txt" +#include "zscript/doom/painelemental.txt" +#include "zscript/doom/archvile.txt" +#include "zscript/doom/cyberdemon.txt" +#include "zscript/doom/spidermaster.txt" +#include "zscript/doom/keen.txt" +#include "zscript/doom/bossbrain.txt" +#include "zscript/doom/weaponfist.txt" +#include "zscript/doom/weaponpistol.txt" +#include "zscript/doom/weaponshotgun.txt" +#include "zscript/doom/weaponssg.txt" +#include "zscript/doom/weaponchaingun.txt" +#include "zscript/doom/weaponchainsaw.txt" +#include "zscript/doom/weaponrlaunch.txt" +#include "zscript/doom/weaponplasma.txt" +#include "zscript/doom/weaponbfg.txt" + +#include "zscript/doom/deadthings.txt" +#include "zscript/doom/doomammo.txt" +#include "zscript/doom/doomarmor.txt" +#include "zscript/doom/doomartifacts.txt" +#include "zscript/doom/doomhealth.txt" +#include "zscript/doom/doomkeys.txt" +#include "zscript/doom/doommisc.txt" +#include "zscript/doom/doomdecorations.txt" +#include "zscript/doom/doomweapons.txt" +#include "zscript/doom/stealthmonsters.txt" +#include "zscript/doom/scriptedmarine.txt" + +#include "zscript/raven/artiegg.txt" +#include "zscript/raven/artitele.txt" +#include "zscript/raven/ravenartifacts.txt" +#include "zscript/raven/ravenhealth.txt" +#include "zscript/raven/ravenambient.txt" +#include "zscript/raven/minotaur.txt" + +#include "zscript/heretic/hereticplayer.txt" +#include "zscript/heretic/hereticammo.txt" +#include "zscript/heretic/hereticarmor.txt" +#include "zscript/heretic/hereticartifacts.txt" +#include "zscript/heretic/heretickeys.txt" +#include "zscript/heretic/hereticdecorations.txt" +#include "zscript/heretic/hereticmisc.txt" +#include "zscript/heretic/mummy.txt" +#include "zscript/heretic/clink.txt" +#include "zscript/heretic/beast.txt" +#include "zscript/heretic/snake.txt" +#include "zscript/heretic/hereticimp.txt" +#include "zscript/heretic/knight.txt" +#include "zscript/heretic/wizard.txt" +#include "zscript/heretic/ironlich.txt" +#include "zscript/heretic/dsparil.txt" +#include "zscript/heretic/chicken.txt" +#include "zscript/heretic/weaponstaff.txt" +#include "zscript/heretic/weaponwand.txt" +#include "zscript/heretic/weaponcrossbow.txt" +#include "zscript/heretic/weapongauntlets.txt" +#include "zscript/heretic/weaponmace.txt" +#include "zscript/heretic/weaponblaster.txt" +#include "zscript/heretic/weaponskullrod.txt" +#include "zscript/heretic/weaponphoenix.txt" + +#include "zscript/hexen/baseweapons.txt" +#include "zscript/hexen/korax.txt" +#include "zscript/hexen/fighterplayer.txt" +#include "zscript/hexen/clericplayer.txt" +#include "zscript/hexen/mageplayer.txt" +#include "zscript/hexen/pig.txt" +#include "zscript/hexen/flame.txt" +#include "zscript/hexen/flies.txt" +#include "zscript/hexen/hexenarmor.txt" +#include "zscript/hexen/hexendecorations.txt" +#include "zscript/hexen/hexenkeys.txt" +#include "zscript/hexen/hexenspecialdecs.txt" +#include "zscript/hexen/mana.txt" +#include "zscript/hexen/puzzleitems.txt" +#include "zscript/hexen/scriptprojectiles.txt" +#include "zscript/hexen/speedboots.txt" +#include "zscript/hexen/ettin.txt" +#include "zscript/hexen/centaur.txt" +#include "zscript/hexen/demons.txt" +#include "zscript/hexen/firedemon.txt" +#include "zscript/hexen/fog.txt" +#include "zscript/hexen/summon.txt" +#include "zscript/hexen/flechette.txt" +#include "zscript/hexen/clericboss.txt" +#include "zscript/hexen/fighterboss.txt" +#include "zscript/hexen/mageboss.txt" +#include "zscript/hexen/bats.txt" +#include "zscript/hexen/bishop.txt" +#include "zscript/hexen/blastradius.txt" +#include "zscript/hexen/boostarmor.txt" +#include "zscript/hexen/clericmace.txt" +#include "zscript/hexen/clericflame.txt" +#include "zscript/hexen/clericholy.txt" +#include "zscript/hexen/clericstaff.txt" +#include "zscript/hexen/magewand.txt" +#include "zscript/hexen/magecone.txt" +#include "zscript/hexen/magelightning.txt" +#include "zscript/hexen/magestaff.txt" +#include "zscript/hexen/fighterfist.txt" +#include "zscript/hexen/fighteraxe.txt" +#include "zscript/hexen/fighterhammer.txt" +#include "zscript/hexen/fighterquietus.txt" +#include "zscript/hexen/dragon.txt" +#include "zscript/hexen/healingradius.txt" +#include "zscript/hexen/teleportother.txt" +#include "zscript/hexen/iceguy.txt" +#include "zscript/hexen/serpent.txt" +#include "zscript/hexen/spike.txt" +#include "zscript/hexen/wraith.txt" +#include "zscript/hexen/heresiarch.txt" + +#include "zscript/strife/strifehumanoid.txt" +#include "zscript/strife/strifeplayer.txt" +#include "zscript/strife/strifeweapons.txt" +#include "zscript/strife/spectral.txt" +#include "zscript/strife/acolyte.txt" +#include "zscript/strife/alienspectres.txt" +#include "zscript/strife/beggars.txt" +#include "zscript/strife/coin.txt" +#include "zscript/strife/crusader.txt" +#include "zscript/strife/entityboss.txt" +#include "zscript/strife/inquisitor.txt" +#include "zscript/strife/klaxon.txt" +#include "zscript/strife/loremaster.txt" +#include "zscript/strife/macil.txt" +#include "zscript/strife/merchants.txt" +#include "zscript/strife/peasants.txt" +#include "zscript/strife/strifebishop.txt" +#include "zscript/strife/oracle.txt" +#include "zscript/strife/programmer.txt" +#include "zscript/strife/questitems.txt" +#include "zscript/strife/ratbuddy.txt" +#include "zscript/strife/rebels.txt" +#include "zscript/strife/reaver.txt" +#include "zscript/strife/sentinel.txt" +#include "zscript/strife/stalker.txt" +#include "zscript/strife/strifeammo.txt" +#include "zscript/strife/strifearmor.txt" +#include "zscript/strife/strifefunctions.txt" +#include "zscript/strife/strifeitems.txt" +#include "zscript/strife/strifekeys.txt" +#include "zscript/strife/strifestuff.txt" +#include "zscript/strife/thingstoblowup.txt" +#include "zscript/strife/templar.txt" +#include "zscript/strife/zombie.txt" +#include "zscript/strife/weapondagger.txt" +#include "zscript/strife/weaponcrossbow.txt" +#include "zscript/strife/weaponassault.txt" +#include "zscript/strife/weaponmissile.txt" +#include "zscript/strife/weaponflamer.txt" +#include "zscript/strife/weapongrenade.txt" +#include "zscript/strife/weaponmauler.txt" +#include "zscript/strife/sigil.txt" + +#include "zscript/chex/chexmonsters.txt" +#include "zscript/chex/chexkeys.txt" +#include "zscript/chex/chexammo.txt" +#include "zscript/chex/chexweapons.txt" +#include "zscript/chex/chexitems.txt" +#include "zscript/chex/chexdecorations.txt" +#include "zscript/chex/chexplayer.txt" diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt new file mode 100644 index 0000000000..1e5c394160 --- /dev/null +++ b/wadsrc/static/zscript/actor.txt @@ -0,0 +1,857 @@ +class Actor : Thinker native +{ + const DEFAULT_HEALTH = 1000; + const ONFLOORZ = -2147483648.0; + const ONCEILINGZ = 2147483647.0; + const FLOATRANDZ = ONCEILINGZ-1; + const TELEFRAG_DAMAGE = 1000000; + const MinVel = 1./65536; + const LARGE_MASS = 10000000; // not INT_MAX on purpose + + + // flags are not defined here, the native fields for those get synthesized from the internal tables. + + // for some comments on these fields, see their native representations in actor.h. + native readonly Actor snext; // next in sector list. + native PlayerInfo Player; + native readonly vector3 Pos; + native vector3 Prev; + native double spriteAngle; + native double spriteRotation; + native double VisibleStartAngle; + native double VisibleStartPitch; + native double VisibleEndAngle; + native double VisibleEndPitch; + native double Angle; + native double Pitch; + native double Roll; + native vector3 Vel; + native double Speed; + native double FloatSpeed; + native SpriteID sprite; + native uint8 frame; + native vector2 Scale; + native TextureID picnum; + native double Alpha; + native readonly color fillcolor; // must be set with SetShade to initialize correctly. + native Sector CurSector; + native double CeilingZ; + native double FloorZ; + native double DropoffZ; + native Sector floorsector; + native TextureID floorpic; + native int floorterrain; + native Sector ceilingsector; + native TextureID ceilingpic; + native double Height; + native readonly double Radius; + native double projectilepassheight; + native int tics; + native readonly State CurState; + native readonly int Damage; + native int projectilekickback; + native int special1; + native int special2; + native double specialf1; + native double specialf2; + native int weaponspecial; + native int Health; + native uint8 movedir; + native int8 visdir; + native int16 movecount; + native int16 strafecount; + native Actor Target; + native Actor Master; + native Actor Tracer; + native Actor LastHeard; + native Actor LastEnemy; + native Actor LastLookActor; + native int ReactionTime; + native int Threshold; + native readonly int DefThreshold; + native readonly vector3 SpawnPoint; + native readonly uint16 SpawnAngle; + native int StartHealth; + native uint8 WeaveIndexXY; + native uint8 WeaveIndexZ; + native int skillrespawncount; + native int Args[5]; + native int Mass; + native int Special; + native readonly int TID; + native readonly int TIDtoHate; + native readonly int WaterLevel; + native int Score; + native int Accuracy; + native int Stamina; + native double MeleeRange; + native int PainThreshold; + native double Gravity; + native double FloorClip; + native name DamageType; + native name DamageTypeReceived; + native uint8 FloatBobPhase; + native int RipperLevel; + native int RipLevelMin; + native int RipLevelMax; + native name Species; + native Actor Alternative; + native Actor goal; + native uint8 MinMissileChance; + native int8 LastLookPlayerNumber; + native uint SpawnFlags; + native double meleethreshold; + native double maxtargetrange; + native double bouncefactor; + native double wallbouncefactor; + native int bouncecount; + native double friction; + native int FastChaseStrafeCount; + native double pushfactor; + native int lastpush; + native int activationtype; + native int lastbump; + native int DesignatedTeam; + native Actor BlockingMobj; + native int PoisonDamage; + native name PoisonDamageType; + native int PoisonDuration; + native int PoisonPeriod; + native int PoisonDamageReceived; + native name PoisonDamageTypeReceived; + native int PoisonDurationReceived; + native int PoisonPeriodReceived; + native Actor Poisoner; + native Inventory Inv; + native uint8 smokecounter; + native uint8 FriendPlayer; + native uint Translation; + native sound AttackSound; + native sound DeathSound; + native sound SeeSound; + native sound PainSound; + native sound ActiveSound; + native sound UseSound; + native sound BounceSound; + native sound WallBounceSound; + native sound CrushPainSound; + native double MaxDropoffHeight; + native double MaxStepHeight; + native int16 PainChance; + native name PainType; + native name DeathType; + native double DamageFactor; + native double DamageMultiply; + native Class TelefogSourceType; + native Class TelefogDestType; + native readonly State SpawnState; + native readonly State SeeState; + native State MeleeState; + native State MissileState; + + native meta String Obituary; // Player was killed by this actor + native meta String HitObituary; // Player was killed by this actor in melee + native meta double DeathHeight; // Height on normal death + native meta double BurnHeight; // Height on burning death + native meta color BloodColor; // Colorized blood + native meta int GibHealth; // Negative health below which this monster dies an extreme death + native meta int WoundHealth; // Health needed to enter wound state + native meta double FastSpeed; // speed in fast mode + native meta double RDFactor; // Radius damage factor + native meta double CameraHeight; // Height of camera when used as such + native meta Sound HowlSound; // Sound being played when electrocuted or poisoned + native meta Name BloodType; // Blood replacement type + native meta Name BloodType2; // Bloopsplatter replacement type + native meta Name BloodType3; // AxeBlood replacement type + native meta bool DontHurtShooter; + native meta int ExplosionRadius; + native meta int ExplosionDamage; + native meta int MeleeDamage; + native meta Sound MeleeSound; + native meta Name MissileName; + native meta double MissileHeight; + + + // need some definition work first + //FRenderStyle RenderStyle; + //line_t *BlockingLine; // Line that blocked the last move + //int ConversationRoot; // THe root of the current dialogue + //DecalBase DecalGenerator; + + // deprecated things. + native readonly deprecated double X; + native readonly deprecated double Y; + native readonly deprecated double Z; + native readonly deprecated double VelX; + native readonly deprecated double VelY; + native readonly deprecated double VelZ; + native readonly deprecated double MomX; + native readonly deprecated double MomY; + native readonly deprecated double MomZ; + native deprecated double ScaleX; + native deprecated double ScaleY; + + //int ConversationRoot; // THe root of the current dialogue; + //FStrifeDialogueNode *Conversation; // [RH] The dialogue to show when this actor is used.; + + + Default + { + Scale 1; + Health DEFAULT_HEALTH; + Reactiontime 8; + Radius 20; + Height 16; + Mass 100; + RenderStyle 'Normal'; + Alpha 1; + MinMissileChance 200; + MeleeRange 64 - 20; + MaxDropoffHeight 24; + MaxStepHeight 24; + BounceFactor 0.7; + WallBounceFactor 0.75; + BounceCount -1; + FloatSpeed 4; + FloatBobPhase -1; // randomly initialize by default + Gravity 1; + Friction 1; + DamageFactor 1.0; // damage multiplier as target of damage. + DamageMultiply 1.0; // damage multiplier as source of damage. + PushFactor 0.25; + WeaveIndexXY 0; + WeaveIndexZ 16; + DesignatedTeam 255; + PainType "Normal"; + DeathType "Normal"; + TeleFogSourceType "TeleportFog"; + TeleFogDestType 'TeleportFog'; + RipperLevel 0; + RipLevelMin 0; + RipLevelMax 0; + DefThreshold 100; + BloodType "Blood", "BloodSplatter", "AxeBlood"; + ExplosionDamage 128; + MissileHeight 32; + SpriteAngle 0; + SpriteRotation 0; + StencilColor "00 00 00"; + VisibleAngles 0, 0; + VisiblePitch 0, 0; + DefaultStateUsage SUF_ACTOR|SUF_OVERLAY; + } + + // Functions + + // 'parked' global functions. + native static double deltaangle(double ang1, double ang2); + native static double absangle(double ang1, double ang2); + native static Vector2 AngleToVector(double angle, double length = 1); + native static Vector2 RotateVector(Vector2 vec, double angle); + + + bool IsPointerEqual(int ptr_select1, int ptr_select2) + { + return GetPointer(ptr_select1) == GetPointer(ptr_select2); + } + + static double BobSin(double fb) + { + return sin(fb * (180./32)) * 8; + } + + virtual native void BeginPlay(); + virtual native void Activate(Actor activator); + virtual native void Deactivate(Actor activator); + virtual native int DoSpecialDamage (Actor target, int damage, Name damagetype); + virtual native int TakeSpecialDamage (Actor inflictor, Actor source, int damage, Name damagetype); + virtual native void Die(Actor source, Actor inflictor, int dmgflags = 0); + virtual native bool Slam(Actor victim); + virtual native void Touch(Actor toucher); + virtual native bool CanCollideWith(Actor other, bool passive); // This is an empty native function, it's native for the sole reason of performance as this is in a performance critical spot. + + // Called when an actor is to be reflected by a disc of repulsion. + // Returns true to continue normal blast processing. + virtual bool SpecialBlastHandling (Actor source, double strength) // this is entirely on the script side with no native part at all. + { + return true; + } + + virtual int SpecialMissileHit (Actor victim) // for this no native version exists + { + return -1; + } + + + native static int GetSpriteIndex(name sprt); + native static double GetDefaultSpeed(class type); + native static class GetSpawnableType(int spawnnum); + native void RemoveFromHash(); + native void ChangeTid(int newtid); + native static int FindUniqueTid(int start = 0, int limit = 0); + native void SetShade(color col); + + native string GetTag(string defstr = ""); + native void SetTag(string defstr = ""); + native double GetBobOffset(double frac = 0); + native void ClearCounters(); + native bool GiveBody (int num, int max=0); + native bool HitFloor(); + native bool isTeammate(Actor other); + native int PlayerNumber(); + native void SetFriendPlayer(PlayerInfo player); + native void NoiseAlert(Actor target, bool splash = false, double maxdist = 0); + native void DaggerAlert(Actor target); + native void ClearBounce(); + native TerrainDef GetFloorTerrain(); + native bool CheckLocalView(int consoleplayer); + + native void ExplodeMissile(line lin = null, Actor target = null); + native void RestoreDamage(); + native int SpawnHealth(); + native void SetDamage(int dmg); + native double Distance2D(Actor other); + native double Distance3D(Actor other); + native void SetOrigin(vector3 newpos, bool moving); + native void SetXYZ(vector3 newpos); + native Actor GetPointer(int aaptr); + native double BulletSlope(out FTranslatedLineTarget pLineTarget = null, int aimflags = 0); + native Actor AimTarget(); + native bool CheckMissileSpawn(double maxdist); + native bool CheckPosition(Vector2 pos, bool actorsonly = false); + native bool TestMobjLocation(); + native static Actor Spawn(class type, vector3 pos = (0,0,0), int replace = NO_REPLACE); + native Actor SpawnMissile(Actor dest, class type, Actor owner = null); + native Actor SpawnMissileXYZ(Vector3 pos, Actor dest, Class type, bool checkspawn = true, Actor owner = null); + native Actor SpawnMissileZ (double z, Actor dest, class type); + native Actor SpawnMissileAngleZSpeed (double z, class type, double angle, double vz, double speed, Actor owner = null, bool checkspawn = true); + native Actor SpawnMissileZAimed (double z, Actor dest, Class type); + native Actor SpawnSubMissile(Class type, Actor target); + native Actor, Actor SpawnPlayerMissile(class type, double angle = 0, double x = 0, double y = 0, double z = 0, out FTranslatedLineTarget pLineTarget = null, bool nofreeaim = false, bool noautoaim = false, int aimflags = 0); + native void SpawnTeleportFog(Vector3 pos, bool beforeTele, bool setTarget); + native Actor RoughMonsterSearch(int distance, bool onlyseekable = false, bool frontonly = false); + native int ApplyDamageFactor(Name damagetype, int damage); + native int GetModifiedDamage(Name damagetype, int damage, bool passive); + native bool CheckBossDeath(); + + void A_Light(int extralight) { if (player) player.extralight = clamp(extralight, -20, 20); } + void A_Light0() { if (player) player.extralight = 0; } + void A_Light1() { if (player) player.extralight = 1; } + void A_Light2() { if (player) player.extralight = 2; } + void A_LightInverse() { if (player) player.extralight = 0x80000000; } + + native Actor OldSpawnMissile(Actor dest, class type, Actor owner = null); + native Actor SpawnPuff(class pufftype, vector3 pos, double hitdir, double particledir, int updown, int flags = 0, Actor victim = null); + native void SpawnBlood (Vector3 pos1, double dir, int damage); + native void BloodSplatter (Vector3 pos, double hitangle, bool axe = false); + native bool HitWater (sector sec, Vector3 pos, bool checkabove = false, bool alert = true, bool force = false); + native void PlaySpawnSound(Actor missile); + native bool CountsAsKill(); + + native bool Teleport(Vector3 pos, double angle, int flags); + native void TraceBleed(int damage, Actor missile); + native void TraceBleedAngle(int damage, double angle, double pitch); + + native void SetIdle(bool nofunction = false); + native bool CheckMeleeRange(); + native bool CheckMeleeRange2(); + native int DamageMobj(Actor inflictor, Actor source, int damage, Name mod, int flags = 0, double angle = 0); + native void PoisonMobj (Actor inflictor, Actor source, int damage, int duration, int period, Name type); + native double AimLineAttack(double angle, double distance, out FTranslatedLineTarget pLineTarget = null, double vrange = 0., int flags = 0, Actor target = null, Actor friender = null); + native Actor, int LineAttack(double angle, double distance, double pitch, int damage, Name damageType, class pufftype, int flags = 0, out FTranslatedLineTarget victim = null); + native bool CheckSight(Actor target, int flags = 0); + native bool IsVisible(Actor other, bool allaround, LookExParams params = null); + native bool HitFriend(); + native bool MonsterMove(); + + native void FindFloorCeiling(int flags = 0); + native double, double GetFriction(); + native bool, Actor TestMobjZ(bool quick = false); + native bool InStateSequence(State newstate, State basestate); + + bool TryWalk () + { + if (!MonsterMove ()) + { + return false; + } + movecount = random[TryWalk]() & 15; + return true; + } + + native bool TryMove(vector2 newpos, int dropoff); + native void NewChaseDir(); + native void RandomChaseDir(); + native bool CheckMissileRange(); + native bool SetState(state st, bool nofunction = false); + native state FindState(statelabel st, bool exact = false); + bool SetStateLabel(statelabel st, bool nofunction = false) { return SetState(FindState(st), nofunction); } + native action state ResolveState(statelabel st); // this one, unlike FindState, is context aware. + native void LinkToWorld(); + native void UnlinkFromWorld(); + native bool CanSeek(Actor target); + native double AngleTo(Actor target, bool absolute = false); + native void AddZ(double zadd, bool moving = true); + native void SetZ(double z); + native vector2 Vec2To(Actor other); + native vector3 Vec3To(Actor other); + native vector3 Vec3Offset(double x, double y, double z, bool absolute = false); + native vector3 Vec3Angle(double length, double angle, double z = 0, bool absolute = false); + native vector2 Vec2Angle(double length, double angle, bool absolute = false); + native vector2 Vec2Offset(double x, double y, bool absolute = false); + native vector3 Vec2OffsetZ(double x, double y, double atz, bool absolute = false); + native void VelFromAngle(double speed = 0, double angle = 0); + native void Vel3DFromAngle(double speed, double angle, double pitch); + native void Thrust(double speed = 0, double angle = 0); + native bool isFriend(Actor other); + native bool isHostile(Actor other); + native void AdjustFloorClip(); + native DropItem GetDropItems(); + native void CopyFriendliness (Actor other, bool changeTarget, bool resetHealth = true); + native bool LookForMonsters(); + native bool LookForTid(bool allaround, LookExParams params = null); + native bool LookForEnemies(bool allaround, LookExParams params = null); + native bool LookForPlayers(bool allaround, LookExParams params = null); + native bool TeleportMove(Vector3 pos, bool telefrag, bool modifyactor = true); + native double DistanceBySpeed(Actor other, double speed); + native name GetSpecies(); + native void PlayActiveSound(); + native void Howl(); + native void DrawSplash (int count, double angle, int kind); + native void GiveSecret(bool printmsg = true, bool playsound = true); + native double GetCameraHeight(); + native double GetGravity(); + + native bool CheckClass(class checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false); + native void AddInventory(Inventory inv); + native void RemoveInventory(Inventory inv); + native void ClearInventory(); + native Inventory FindInventory(class itemtype, bool subclass = false); + native Inventory GiveInventoryType(class itemtype); + native Inventory DropInventory (Inventory item); + native bool UseInventory(Inventory item); + native bool GiveAmmo (Class type, int amount); + native float AccuracyFactor(); + + // DECORATE compatible functions + native int CountInv(class itemtype, int ptr_select = AAPTR_DEFAULT); + native double GetDistance(bool checkz, int ptr = AAPTR_TARGET); + native double GetAngle(int flags, int ptr = AAPTR_TARGET); + native double GetZAt(double px = 0, double py = 0, double angle = 0, int flags = 0, int pick_pointer = AAPTR_DEFAULT); + native int GetSpawnHealth(); + native int GetGibHealth(); + native double GetCrouchFactor(int ptr = AAPTR_PLAYER1); + native double GetCVar(string cvar); + native int GetPlayerInput(int inputnum, int ptr = AAPTR_DEFAULT); + native int CountProximity(class classname, double distance, int flags = 0, int ptr = AAPTR_DEFAULT); + native double GetSpriteAngle(int ptr = AAPTR_DEFAULT); + native double GetSpriteRotation(int ptr = AAPTR_DEFAULT); + native int GetMissileDamage(int mask, int add, int ptr = AAPTR_DEFAULT); + action native int OverlayID(); + action native double OverlayX(int layer = 0); + action native double OverlayY(int layer = 0); + + // DECORATE setters - it probably makes more sense to set these values directly now... + void A_SetMass(int newmass) { mass = newmass; } + void A_SetInvulnerable() { bInvulnerable = true; } + void A_UnSetInvulnerable() { bInvulnerable = false; } + void A_SetReflective() { bReflective = true; } + void A_UnSetReflective() { bReflective = false; } + void A_SetReflectiveInvulnerable() { bInvulnerable = true; bReflective = true; } + void A_UnSetReflectiveInvulnerable() { bInvulnerable = false; bReflective = false; } + void A_SetShootable() { bShootable = true; bNonShootable = false; } + void A_UnSetShootable() { bShootable = false; bNonShootable = true; } + void A_NoGravity() { bNoGravity = true; } + void A_Gravity() { bNoGravity = false; Gravity = 1; } + void A_LowGravity() { bNoGravity = false; Gravity = 0.125; } + void A_SetGravity(double newgravity) { gravity = clamp(newgravity, 0., 10.); } + void A_SetFloorClip() { bFloorClip = true; AdjustFloorClip(); } + void A_UnSetFloorClip() { bFloorClip = false; FloorClip = 0; } + void A_HideThing() { bInvisible = true; } + void A_UnHideThing() { bInvisible = false; } + void A_SetArg(int arg, int val) { if (arg >= 0 && arg < 5) args[arg] = val; } + void A_Turn(double turn = 0) { angle += turn; } + void A_SetDamageType(name newdamagetype) { damagetype = newdamagetype; } + void A_SetSolid() { bSolid = true; } + void A_UnsetSolid() { bSolid = false; } + void A_SetFloat() { bFloat = true; } + void A_UnsetFloat() { bFloat = false; } + void A_SetFloatBobPhase(int bob) { if (bob >= 0 && bob <= 63) FloatBobPhase = bob; } + void A_SetRipperLevel(int level) { RipperLevel = level; } + void A_SetRipMin(int minimum) { RipLevelMin = minimum; } + void A_SetRipMax(int maximum) { RipLevelMax = maximum; } + void A_ScreamAndUnblock() { A_Scream(); A_NoBlocking(); } + void A_ActiveAndUnblock() { A_ActiveSound(); A_NoBlocking(); } + + //--------------------------------------------------------------------------- + // + // FUNC P_SpawnMissileAngle + // + // Returns NULL if the missile exploded immediately, otherwise returns + // a mobj_t pointer to the missile. + // + //--------------------------------------------------------------------------- + + Actor SpawnMissileAngle (class type, double angle, double vz) + { + return SpawnMissileAngleZSpeed (pos.z + 32 + GetBobOffset(), type, angle, vz, GetDefaultSpeed (type)); + } + + Actor SpawnMissileAngleZ (double z, class type, double angle, double vz) + { + return SpawnMissileAngleZSpeed (z, type, angle, vz, GetDefaultSpeed (type)); + } + + + void A_SetScale(double scalex, double scaley = 0, int ptr = AAPTR_DEFAULT, bool usezero = false) + { + Actor aptr = GetPointer(ptr); + if (aptr) + { + aptr.Scale.X = scalex; + aptr.Scale.Y = scaley != 0 || usezero? scaley : scalex; // use scalex here, too, if only one parameter. + } + } + void A_SetSpeed(double speed, int ptr = AAPTR_DEFAULT) + { + Actor aptr = GetPointer(ptr); + if (aptr) aptr.Speed = speed; + } + void A_SetFloatSpeed(double speed, int ptr = AAPTR_DEFAULT) + { + Actor aptr = GetPointer(ptr); + if (aptr) aptr.FloatSpeed = speed; + } + void A_SetPainThreshold(int threshold, int ptr = AAPTR_DEFAULT) + { + Actor aptr = GetPointer(ptr); + if (aptr) aptr.PainThreshold = threshold; + } + bool A_SetSpriteAngle(double angle = 0, int ptr = AAPTR_DEFAULT) + { + Actor aptr = GetPointer(ptr); + if (!aptr) return false; + aptr.SpriteAngle = angle; + return true; + } + bool A_SetSpriteRotation(double angle = 0, int ptr = AAPTR_DEFAULT) + { + Actor aptr = GetPointer(ptr); + if (!aptr) return false; + aptr.SpriteRotation = angle; + return true; + } + + deprecated void A_FaceConsolePlayer(double MaxTurnAngle = 0) {} + + void A_SetSpecial(int spec, int arg0 = 0, int arg1 = 0, int arg2 = 0, int arg3 = 0, int arg4 = 0) + { + special = spec; + args[0] = arg0; + args[1] = arg1; + args[2] = arg2; + args[3] = arg3; + args[4] = arg4; + } + + void A_ClearTarget() + { + target = null; + lastheard = null; + lastenemy = null; + } + + void A_ChangeLinkFlags(int blockmap = FLAG_NO_CHANGE, int sector = FLAG_NO_CHANGE) + { + UnlinkFromWorld(); + if (blockmap != FLAG_NO_CHANGE) bNoBlockmap = blockmap; + if (sector != FLAG_NO_CHANGE) bNoSector = sector; + LinkToWorld(); + } + + // killough 11/98: kill an object + void A_Die(name damagetype = "none") + { + DamageMobj(null, null, health, damagetype, DMG_FORCED); + } + + void SpawnDirt (double radius) + { + static const class chunks[] = { "Dirt1", "Dirt2", "Dirt3", "Dirt4", "Dirt5", "Dirt6" }; + double zo = random[Dirt]() / 128. + 1; + Vector3 pos = Vec3Angle(radius, random[Dirt]() * (360./256), zo); + + Actor mo = Spawn (chunks[random[Dirt](0, 5)], pos, ALLOW_REPLACE); + if (mo) + { + mo.Vel.Z = random[Dirt]() / 64.; + } + } + + // + // A_SinkMobj + // Sink a mobj incrementally into the floor + // + + bool SinkMobj (double speed) + { + if (Floorclip < Height) + { + Floorclip += speed; + return false; + } + return true; + } + + // + // A_RaiseMobj + // Raise a mobj incrementally from the floor to + // + + bool RaiseMobj (double speed) + { + // Raise a mobj from the ground + if (Floorclip > 0) + { + Floorclip -= speed; + if (Floorclip <= 0) + { + Floorclip = 0; + return true; + } + else + { + return false; + } + } + return true; + } + + + native void A_Face(Actor faceto, double max_turn = 0, double max_pitch = 270, double ang_offset = 0, double pitch_offset = 0, int flags = 0, double z_ofs = 0); + + void A_FaceTarget(double max_turn = 0, double max_pitch = 270, double ang_offset = 0, double pitch_offset = 0, int flags = 0, double z_ofs = 0) + { + A_Face(target, max_turn, max_pitch, ang_offset, pitch_offset, flags, z_ofs); + } + void A_FaceTracer(double max_turn = 0, double max_pitch = 270, double ang_offset = 0, double pitch_offset = 0, int flags = 0, double z_ofs = 0) + { + A_Face(tracer, max_turn, max_pitch, ang_offset, pitch_offset, flags, z_ofs); + } + void A_FaceMaster(double max_turn = 0, double max_pitch = 270, double ang_offset = 0, double pitch_offset = 0, int flags = 0, double z_ofs = 0) + { + A_Face(master, max_turn, max_pitch, ang_offset, pitch_offset, flags, z_ofs); + } + + // Action functions + // Meh, MBF redundant functions. Only for DeHackEd support. + native bool A_LineEffect(int boomspecial = 0, int tag = 0); + // End of MBF redundant functions. + + native void A_MonsterRail(); + native void A_Pain(); + native void A_NoBlocking(bool drop = true); + void A_Fall() { A_NoBlocking(); } + native void A_XScream(); + native void A_Look(); + native void A_Chase(statelabel melee = null, statelabel missile = null, int flags = 0); + native void A_Scream(); + native void A_VileChase(); + native void A_BossDeath(); + native void A_Detonate(); + native bool A_CallSpecial(int special, int arg1=0, int arg2=0, int arg3=0, int arg4=0, int arg5=0); + + native void A_ActiveSound(); + + native void A_FastChase(); + native void A_FreezeDeath(); + native void A_FreezeDeathChunks(); + void A_GenericFreezeDeath() + { + A_SetTranslation('Ice'); + A_FreezeDeath(); + } + native void A_PlayerScream(); + native void A_SkullPop(class skulltype = "BloodySkull"); + native void A_CheckPlayerDone(); + native void A_CheckTerrain(); + + native void A_Wander(int flags = 0); + native void A_Look2(); + + deprecated native void A_MissileAttack(); + deprecated native void A_MeleeAttack(); + deprecated native void A_ComboAttack(); + deprecated native void A_BulletAttack(); + native void A_WolfAttack(int flags = 0, sound whattoplay = "weapons/pistol", double snipe = 1.0, int maxdamage = 64, int blocksize = 128, int pointblank = 2, int longrange = 4, double runspeed = 160.0, class pufftype = "BulletPuff"); + native void A_PlaySound(sound whattoplay = "weapons/pistol", int slot = CHAN_BODY, double volume = 1.0, bool looping = false, double attenuation = ATTN_NORM, bool local = false); + deprecated void A_PlayWeaponSound(sound whattoplay) { A_PlaySound(whattoplay, CHAN_WEAPON); } + native void A_StopSound(int slot = CHAN_VOICE); // Bad default but that's what is originally was... + deprecated native void A_PlaySoundEx(sound whattoplay, name slot, bool looping = false, int attenuation = 0); + deprecated native void A_StopSoundEx(name slot); + native void A_SeekerMissile(int threshold, int turnmax, int flags = 0, int chance = 50, int distance = 10); + native action state A_Jump(int chance, statelabel label, ...); + native void A_CustomMissile(class missiletype, double spawnheight = 32, double spawnofs_xy = 0, double angle = 0, int flags = 0, double pitch = 0, int ptr = AAPTR_TARGET); + native void A_CustomBulletAttack(double spread_xy, double spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", double range = 0, int flags = 0, int ptr = AAPTR_TARGET, class missile = null, double Spawnheight = 32, double Spawnofs_xy = 0); + native void A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = 0, color color2 = 0, int flags = 0, int aim = 0, double maxdiff = 0, class pufftype = "BulletPuff", double spread_xy = 0, double spread_z = 0, double range = 0, int duration = 0, double sparsity = 1.0, double driftspeed = 1.0, class spawnclass = null, double spawnofs_z = 0, int spiraloffset = 270, int limit = 0); + native bool A_SetInventory(class itemtype, int amount, int ptr = AAPTR_DEFAULT, bool beyondMax = false); + native bool A_GiveInventory(class itemtype, int amount = 0, int giveto = AAPTR_DEFAULT); + native bool A_TakeInventory(class itemtype, int amount = 0, int flags = 0, int giveto = AAPTR_DEFAULT); + action native bool A_SpawnItem(class itemtype = "Unknown", double distance = 0, double zheight = 0, bool useammo = true, bool transfer_translation = false); + native bool A_SpawnItemEx(class itemtype, double xofs = 0, double yofs = 0, double zofs = 0, double xvel = 0, double yvel = 0, double zvel = 0, double angle = 0, int flags = 0, int failchance = 0, int tid=0); + native void A_Print(string whattoprint, double time = 0, name fontname = "none"); + native void A_PrintBold(string whattoprint, double time = 0, name fontname = "none"); + native void A_Log(string whattoprint); + native void A_LogInt(int whattoprint); + native void A_LogFloat(double whattoprint); + native void A_SetTranslucent(double alpha, int style = 0); + native void A_SetRenderStyle(double alpha, int style); + native void A_FadeIn(double reduce = 0.1, int flags = 0); + native void A_FadeOut(double reduce = 0.1, int flags = 1); //bool remove == true + native void A_FadeTo(double target, double amount = 0.1, int flags = 0); + native void A_SpawnDebris(class spawntype, bool transfer_translation = false, double mult_h = 1, double mult_v = 1); + native void A_SpawnParticle(color color1, int flags = 0, int lifetime = 35, double size = 1, double angle = 0, double xoff = 0, double yoff = 0, double zoff = 0, double velx = 0, double vely = 0, double velz = 0, double accelx = 0, double accely = 0, double accelz = 0, double startalphaf = 1, double fadestepf = -1, double sizestep = 0); + native void A_ExtChase(bool usemelee, bool usemissile, bool playactive = true, bool nightmarefast = false); + native void A_DropInventory(class itemtype); + native void A_SetBlend(color color1, double alpha, int tics, color color2 = 0); + deprecated native void A_ChangeFlag(string flagname, bool value); + native void A_ChangeCountFlags(int kill = FLAG_NO_CHANGE, int item = FLAG_NO_CHANGE, int secret = FLAG_NO_CHANGE); + native void A_RaiseMaster(bool copy = 0); + native void A_RaiseChildren(bool copy = 0); + native void A_RaiseSiblings(bool copy = 0); + deprecated native void A_BasicAttack(int meleedamage, sound meleesound, class missiletype, double missileheight); + action native bool A_ThrowGrenade(class itemtype, double zheight = 0, double xyvel = 0, double zvel = 0, bool useammo = true); + native void A_Weave(int xspeed, int yspeed, double xdist, double ydist); + + + action native state, bool A_Teleport(statelabel teleportstate = null, class targettype = "BossSpot", class fogtype = "TeleportFog", int flags = 0, double mindist = 0, double maxdist = 128, int ptr = AAPTR_DEFAULT); + action native state, bool A_Warp(int ptr_destination, double xofs = 0, double yofs = 0, double zofs = 0, double angle = 0, int flags = 0, statelabel success_state = null, double heightoffset = 0, double radiusoffset = 0, double pitch = 0); + native void A_CountdownArg(int argnum, statelabel targstate = null); + native state A_MonsterRefire(int chance, statelabel label); + native void A_LookEx(int flags = 0, double minseedist = 0, double maxseedist = 0, double maxheardist = 0, double fov = 0, statelabel label = null); + + native void A_Recoil(double xyvel); + native bool A_GiveToTarget(class itemtype, int amount = 0, int forward_ptr = AAPTR_DEFAULT); + native bool A_TakeFromTarget(class itemtype, int amount = 0, int flags = 0, int forward_ptr = AAPTR_DEFAULT); + native int A_RadiusGive(class itemtype, double distance, int flags, int amount = 0, class filter = null, name species = "None", double mindist = 0, int limit = 0); + native void A_CustomMeleeAttack(int damage = 0, sound meleesound = "", sound misssound = "", name damagetype = "none", bool bleed = true); + native void A_CustomComboAttack(class missiletype, double spawnheight, int damage, sound meleesound = "", name damagetype = "none", bool bleed = true); + native void A_Burst(class chunktype); + native void A_RadiusThrust(int force = 128, int distance = -1, int flags = RTF_AFFECTSOURCE, int fullthrustdistance = 0); + native void A_RadiusDamageSelf(int damage = 128, double distance = 128, int flags = 0, class flashtype = null); + native int A_Explode(int damage = -1, int distance = -1, int flags = XF_HURTSOURCE, bool alert = false, int fulldamagedistance = 0, int nails = 0, int naildamage = 10, class pufftype = "BulletPuff", name damagetype = "none"); + native void A_Stop(); + native void A_Respawn(int flags = 1); + native void A_RestoreSpecialPosition(); + native void A_QueueCorpse(); + native void A_DeQueueCorpse(); + native void A_ClearLastHeard(); + native bool A_SelectWeapon(class whichweapon, int flags = 0); + native void A_ClassBossHealth(); + native void A_SetAngle(double angle = 0, int flags = 0, int ptr = AAPTR_DEFAULT); + native void A_SetPitch(double pitch, int flags = 0, int ptr = AAPTR_DEFAULT); + native void A_SetRoll(double roll, int flags = 0, int ptr = AAPTR_DEFAULT); + native void A_ScaleVelocity(double scale, int ptr = AAPTR_DEFAULT); + native void A_ChangeVelocity(double x = 0, double y = 0, double z = 0, int flags = 0, int ptr = AAPTR_DEFAULT); + deprecated native void A_SetUserVar(name varname, int value); + deprecated native void A_SetUserArray(name varname, int index, int value); + deprecated native void A_SetUserVarFloat(name varname, double value); + deprecated native void A_SetUserArrayFloat(name varname, int index, double value); + native void A_Quake(int intensity, int duration, int damrad, int tremrad, sound sfx = "world/quake"); + native void A_QuakeEx(int intensityX, int intensityY, int intensityZ, int duration, int damrad, int tremrad, sound sfx = "world/quake", int flags = 0, double mulWaveX = 1, double mulWaveY = 1, double mulWaveZ = 1, int falloff = 0, int highpoint = 0, double rollIntensity = 0, double rollWave = 0); + action native void A_SetTics(int tics); + native void A_DropItem(class item, int dropamount = -1, int chance = 256); + native void A_DamageSelf(int amount, name damagetype = "none", int flags = 0, class filter = null, name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); + native void A_DamageTarget(int amount, name damagetype = "none", int flags = 0, class filter = null, name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); + native void A_DamageMaster(int amount, name damagetype = "none", int flags = 0, class filter = null, name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); + native void A_DamageTracer(int amount, name damagetype = "none", int flags = 0, class filter = null, name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); + native void A_DamageChildren(int amount, name damagetype = "none", int flags = 0, class filter = null, name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); + native void A_DamageSiblings(int amount, name damagetype = "none", int flags = 0, class filter = null, name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); + native void A_KillTarget(name damagetype = "none", int flags = 0, class filter = null, name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); + native void A_KillMaster(name damagetype = "none", int flags = 0, class filter = null, name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); + native void A_KillTracer(name damagetype = "none", int flags = 0, class filter = null, name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); + native void A_KillChildren(name damagetype = "none", int flags = 0, class filter = null, name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); + native void A_KillSiblings(name damagetype = "none", int flags = 0, class filter = null, name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); + native void A_RemoveTarget(int flags = 0, class filter = null, name species = "None"); + native void A_RemoveMaster(int flags = 0, class filter = null, name species = "None"); + native void A_RemoveTracer(int flags = 0, class filter = null, name species = "None"); + native void A_RemoveChildren(bool removeall = false, int flags = 0, class filter = null, name species = "None"); + native void A_RemoveSiblings(bool removeall = false, int flags = 0, class filter = null, name species = "None"); + native void A_Remove(int removee, int flags = 0, class filter = null, name species = "None"); + native int A_GiveToChildren(class itemtype, int amount = 0); + native int A_GiveToSiblings(class itemtype, int amount = 0); + native int A_TakeFromChildren(class itemtype, int amount = 0); + native int A_TakeFromSiblings(class itemtype, int amount = 0); + native void A_SetTeleFog(class oldpos, class newpos); + native void A_SwapTeleFog(); + native void A_SetHealth(int health, int ptr = AAPTR_DEFAULT); + native void A_ResetHealth(int ptr = AAPTR_DEFAULT); + native void A_SetSpecies(name species, int ptr = AAPTR_DEFAULT); + native void A_SetChaseThreshold(int threshold, bool def = false, int ptr = AAPTR_DEFAULT); + native bool A_FaceMovementDirection(double offset = 0, double anglelimit = 0, double pitchlimit = 0, int flags = 0, int ptr = AAPTR_DEFAULT); + native int A_ClearOverlays(int sstart = 0, int sstop = 0, bool safety = true); + native bool A_CopySpriteFrame(int from, int to, int flags = 0); + native bool A_SetVisibleRotation(double anglestart = 0, double angleend = 0, double pitchstart = 0, double pitchend = 0, int flags = 0, int ptr = AAPTR_DEFAULT); + native void A_SetTranslation(name transname); + + native void A_RearrangePointers(int newtarget, int newmaster = AAPTR_DEFAULT, int newtracer = AAPTR_DEFAULT, int flags=0); + native void A_TransferPointer(int ptr_source, int ptr_recepient, int sourcefield, int recepientfield=AAPTR_DEFAULT, int flags=0); + native void A_CopyFriendliness(int ptr_source = AAPTR_MASTER); + + action native bool A_Overlay(int layer, statelabel start = null, bool nooverride = false); + native void A_WeaponOffset(double wx = 0, double wy = 32, int flags = 0); + action native void A_OverlayOffset(int layer = PSP_WEAPON, double wx = 0, double wy = 32, int flags = 0); + action native void A_OverlayFlags(int layer, int flags, bool set); + + int ACS_NamedExecute(name script, int mapnum=0, int arg1=0, int arg2=0, int arg3=0) + { + return ACS_Execute(-int(script), mapnum, arg1, arg2, arg3); + } + int ACS_NamedSuspend(name script, int mapnum=0) + { + return ACS_Suspend(-int(script), mapnum); + } + int ACS_NamedTerminate(name script, int mapnum=0) + { + return ACS_Terminate(-int(script), mapnum); + } + int ACS_NamedLockedExecute(name script, int mapnum=0, int arg1=0, int arg2=0, int lock=0) + { + return ACS_LockedExecute(-int(script), mapnum, arg1, arg2, lock); + } + int ACS_NamedLockedExecuteDoor(name script, int mapnum=0, int arg1=0, int arg2=0, int lock=0) + { + return ACS_LockedExecuteDoor(-int(script), mapnum, arg1, arg2, lock); + } + int ACS_NamedExecuteWithResult(name script, int arg1=0, int arg2=0, int arg3=0, int arg4=0) + { + return ACS_ExecuteWithResult(-int(script), arg1, arg2, arg3, arg4); + } + int ACS_NamedExecuteAlways(name script, int mapnum=0, int arg1=0, int arg2=0, int arg3=0) + { + return ACS_ExecuteAlways(-int(script), mapnum, arg1, arg2, arg3); + } + + States(Actor, Overlay, Weapon, Item) + { + Spawn: + TNT1 A -1; + Stop; + Null: + TNT1 A 1; + Stop; + GenericFreezeDeath: + // Generic freeze death frames. Woo! + #### # 5 A_GenericFreezeDeath; + ---- A 1 A_FreezeDeathChunks; + Wait; + GenericCrush: + POL5 A -1; + Stop; + } + + // Internal functions + deprecated private native int __decorate_internal_int__(int i); + deprecated private native bool __decorate_internal_bool__(bool b); + deprecated private native double __decorate_internal_float__(double f); +} diff --git a/wadsrc/static/zscript/actor_checks.txt b/wadsrc/static/zscript/actor_checks.txt new file mode 100644 index 0000000000..a4f7da1d8e --- /dev/null +++ b/wadsrc/static/zscript/actor_checks.txt @@ -0,0 +1,274 @@ +extend class Actor +{ + //========================================================================== + // + // This file contains all the A_Jump* checker functions, all split up + // into an actual checker and a simple wrapper around ResolveState. + // + //========================================================================== + + action state A_JumpIf(bool expression, statelabel label) + { + return expression? ResolveState(label) : null; + } + + + //========================================================================== + // + // + // + //========================================================================== + + action state A_JumpIfHealthLower(int health, statelabel label, int ptr_selector = AAPTR_DEFAULT) + { + Actor aptr = GetPointer(ptr_selector); + return aptr && aptr.health < health? ResolveState(label) : null; + } + + //========================================================================== + // + // + // + //========================================================================== + + bool CheckIfCloser(Actor targ, double dist, bool noz = false) + { + if (!targ) return false; + return + (Distance2D(targ) < dist && (noz || + ((pos.z > targ.pos.z && pos.z - targ.pos.z - targ.height < dist) || + (pos.z <= targ.pos.z && targ.pos.z - pos.z - height < dist) + ) + )); + } + + action state A_JumpIfCloser(double distance, statelabel label, bool noz = false) + { + Actor targ; + + if (player == NULL) + { + targ = target; + } + else + { + // Does the player aim at something that can be shot? + targ = AimTarget(); + } + + return CheckIfCloser(targ, distance, noz)? ResolveState(label) : null; + } + + action state A_JumpIfTracerCloser(double distance, statelabel label, bool noz = false) + { + return CheckIfCloser(tracer, distance, noz)? ResolveState(label) : null; + } + + action state A_JumpIfMasterCloser(double distance, statelabel label, bool noz = false) + { + return CheckIfCloser(master, distance, noz)? ResolveState(label) : null; + } + + //========================================================================== + // + // + // + //========================================================================== + + action state A_JumpIfTargetOutsideMeleeRange(statelabel label) + { + return CheckMeleeRange()? null : ResolveState(label); + } + + action state A_JumpIfTargetInsideMeleeRange(statelabel label) + { + return CheckMeleeRange()? ResolveState(label) : null; + } + + //========================================================================== + // + // + // + //========================================================================== + + native bool CheckInventory(class itemtype, int itemamount, int owner = AAPTR_DEFAULT); + + action state A_JumpIfInventory(class itemtype, int itemamount, statelabel label, int owner = AAPTR_DEFAULT) + { + return CheckInventory(itemtype, itemamount, owner)? ResolveState(label) : null; + } + + action state A_JumpIfInTargetInventory(class itemtype, int amount, statelabel label, int forward_ptr = AAPTR_DEFAULT) + { + if (target == null) return null; + return target.CheckInventory(itemtype, amount, forward_ptr)? ResolveState(label) : null; + } + + //========================================================================== + // + // + // + //========================================================================== + + native bool CheckArmorType(name Type, int amount = 1); + + action state A_JumpIfArmorType(name Type, statelabel label, int amount = 1) + { + return CheckArmorType(Type, amount)? ResolveState(label) : null; + } + + //========================================================================== + // + // + // + //========================================================================== + + native bool CheckIfSeen(); + native bool CheckSightOrRange(double distance, bool two_dimension = false); + native bool CheckRange(double distance, bool two_dimension = false); + + action state A_CheckSight(statelabel label) + { + return CheckIfSeen()? ResolveState(label) : null; + } + + action state A_CheckSightOrRange(double distance, statelabel label, bool two_dimension = false) + { + return CheckSightOrRange(distance, two_dimension)? ResolveState(label) : null; + } + + action state A_CheckRange(double distance, statelabel label, bool two_dimension = false) + { + return CheckRange(distance, two_dimension)? ResolveState(label) : null; + } + + //========================================================================== + // + // + // + //========================================================================== + + action state A_CheckFloor(statelabel label) + { + return pos.z <= floorz? ResolveState(label) : null; + } + + action state A_CheckCeiling(statelabel label) + { + return pos.z + height >= ceilingz? ResolveState(label) : null; + } + + //========================================================================== + // + // since this is deprecated the checker is private. + // + //========================================================================== + + private native bool CheckFlag(string flagname, int check_pointer = AAPTR_DEFAULT); + + deprecated action state A_CheckFlag(string flagname, statelabel label, int check_pointer = AAPTR_DEFAULT) + { + return CheckFlag(flagname, check_pointer)? ResolveState(label) : null; + } + + //========================================================================== + // + // + // + //========================================================================== + + native bool PlayerSkinCheck(); + + action state A_PlayerSkinCheck(statelabel label) + { + return PlayerSkinCheck()? ResolveState(label) : null; + } + + //========================================================================== + // + // + // + //========================================================================== + + action state A_CheckSpecies(statelabel label, name species = 'none', int ptr = AAPTR_DEFAULT) + { + Actor aptr = GetPointer(ptr); + return aptr && aptr.GetSpecies() == species? ResolveState(label) : null; + } + + //========================================================================== + // + // + // + //========================================================================== + + native bool CheckLOF(int flags = 0, double range = 0, double minrange = 0, double angle = 0, double pitch = 0, double offsetheight = 0, double offsetwidth = 0, int ptr_target = AAPTR_DEFAULT, double offsetforward = 0); + native bool CheckIfTargetInLOS (double fov = 0, int flags = 0, double dist_max = 0, double dist_close = 0); + native bool CheckIfInTargetLOS (double fov = 0, int flags = 0, double dist_max = 0, double dist_close = 0); + native bool CheckProximity(class classname, double distance, int count = 1, int flags = 0, int ptr = AAPTR_DEFAULT); + native bool CheckBlock(int flags = 0, int ptr = AAPTR_DEFAULT, double xofs = 0, double yofs = 0, double zofs = 0, double angle = 0); + + action state A_CheckLOF(statelabel label, int flags = 0, double range = 0, double minrange = 0, double angle = 0, double pitch = 0, double offsetheight = 0, double offsetwidth = 0, int ptr_target = AAPTR_DEFAULT, double offsetforward = 0) + { + return CheckLOF(flags, range, minrange, angle, pitch, offsetheight, offsetwidth, ptr_target, offsetforward)? ResolveState(label) : null; + } + + action state A_JumpIfTargetInLOS (statelabel label, double fov = 0, int flags = 0, double dist_max = 0, double dist_close = 0) + { + return CheckIfTargetInLOS(fov, flags, dist_max, dist_close)? ResolveState(label) : null; + } + + action state A_JumpIfInTargetLOS (statelabel label, double fov = 0, int flags = 0, double dist_max = 0, double dist_close = 0) + { + return CheckIfInTargetLOS(fov, flags, dist_max, dist_close)? ResolveState(label) : null; + } + + action state A_CheckProximity(statelabel label, class classname, double distance, int count = 1, int flags = 0, int ptr = AAPTR_DEFAULT) + { + // This one was doing some weird stuff that needs to be preserved. + state jumpto = ResolveState(label); + if (!jumpto) + { + if (!(flags & (CPXF_SETTARGET | CPXF_SETMASTER | CPXF_SETTRACER))) + { + return null; + } + } + return CheckProximity(classname, distance, count, flags, ptr)? jumpto : null; + } + + action state A_CheckBlock(statelabel label, int flags = 0, int ptr = AAPTR_DEFAULT, double xofs = 0, double yofs = 0, double zofs = 0, double angle = 0) + { + return CheckBlock(flags, ptr, xofs, yofs, zofs, angle)? ResolveState(label) : null; + } + + //=========================================================================== + // A_JumpIfHigherOrLower + // + // Jumps if a target, master, or tracer is higher or lower than the calling + // actor. Can also specify how much higher/lower the actor needs to be than + // itself. Can also take into account the height of the actor in question, + // depending on which it's checking. This means adding height of the + // calling actor's self if the pointer is higher, or height of the pointer + // if its lower. + //=========================================================================== + + action state A_JumpIfHigherOrLower(statelabel high, statelabel low, double offsethigh = 0, double offsetlow = 0, bool includeHeight = true, int ptr = AAPTR_TARGET) + { + Actor mobj = GetPointer(ptr); + + if (mobj != null && mobj != self) //AAPTR_DEFAULT is completely useless in this regard. + { + if ((high) && (mobj.pos.z > ((includeHeight ? Height : 0) + pos.z + offsethigh))) + { + return ResolveState(high); + } + else if ((low) && (mobj.pos.z + (includeHeight ? mobj.Height : 0)) < (pos.z + offsetlow)) + { + return ResolveState(low); + } + } + return null; + } + +} \ No newline at end of file diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt new file mode 100644 index 0000000000..6db88ab0ad --- /dev/null +++ b/wadsrc/static/zscript/base.txt @@ -0,0 +1,504 @@ +class Object native +{ + native bool bDestroyed; + + // These really should be global functions... + native static int G_SkillPropertyInt(int p); + native static double G_SkillPropertyFloat(int p); + native static vector3, int G_PickDeathmatchStart(); + native static vector3, int G_PickPlayerStart(int pnum, int flags = 0); + native static int GameType(); + native static void S_Sound (Sound sound_id, int channel, float volume = 1, float attenuation = ATTN_NORM); + native static bool S_ChangeMusic(String music_name, int order = 0, bool looping = true, bool force = false); + native static void C_MidPrint(string fontname, string textlabel, bool bold = false); // always uses the stringtable. + native static uint BAM(double angle); + + /*virtual*/ native void Destroy(); +} + +class Thinker : Object native +{ + enum EStatnums + { + // Thinkers that don't actually think + STAT_INFO, // An info queue + STAT_DECAL, // A decal + STAT_AUTODECAL, // A decal that can be automatically deleted + STAT_CORPSEPOINTER, // An entry in Hexen's corpse queue + STAT_TRAVELLING, // An actor temporarily travelling to a new map + + // Thinkers that do think + STAT_FIRST_THINKING=32, + STAT_SCROLLER=STAT_FIRST_THINKING, // A DScroller thinker + STAT_PLAYER, // A player actor + STAT_BOSSTARGET, // A boss brain target + STAT_LIGHTNING, // The lightning thinker + STAT_DECALTHINKER, // An object that thinks for a decal + STAT_INVENTORY, // An inventory item + STAT_LIGHT, // A sector light effect + STAT_LIGHTTRANSFER, // A sector light transfer. These must be ticked after the light effects. + STAT_EARTHQUAKE, // Earthquake actors + STAT_MAPMARKER, // Map marker actors + + STAT_DEFAULT = 100, // Thinkers go here unless specified otherwise. + STAT_SECTOREFFECT, // All sector effects that cause floor and ceiling movement + STAT_ACTORMOVER, // actor movers + STAT_SCRIPTS, // The ACS thinker. This is to ensure that it can't tick before all actors called PostBeginPlay + STAT_BOT, // Bot thinker + MAX_STATNUM = 127 + } + + const TICRATE = 35; + + virtual native void Tick(); + virtual native void PostBeginPlay(); + virtual native void ChangeStatNum(int stat); +} + +class ThinkerIterator : Object native +{ + + native static ThinkerIterator Create(class type = "Actor", int statnum=Thinker.MAX_STATNUM+1); + native Thinker Next(bool exact = false); + native void Reinit(); +} + +class ActorIterator : Object native +{ + native static ActorIterator Create(int tid, class type = "Actor"); + native Actor Next(); + native void Reinit(); +} + +class BlockThingsIterator : Object native +{ + native Actor thing; + native Vector3 position; + native int portalflags; + + native static BlockThingsIterator Create(Actor origin, double checkradius = -1, bool ignorerestricted = false); + native static BlockThingsIterator CreateFromPos(double checkx, double checky, double checkz, double checkh, double checkradius, bool ignorerestricted); + native bool Next(); +} + +class DropItem : Object native +{ + native readonly DropItem Next; + native readonly name Name; + native readonly int Probability; + native int Amount; +} + +class SpotState : Object native +{ + native static SpotState GetSpotState(); + native SpecialSpot GetNextInList(class type, int skipcounter); + native SpecialSpot GetSpotWithMinMaxDistance(Class type, double x, double y, double mindist, double maxdist); + +} + +struct LevelLocals native +{ + native readonly int time; + native readonly int maptime; + native readonly int totaltime; + native readonly int starttime; + native readonly int partime; + native readonly int sucktime; + native readonly int cluster; + native readonly int clusterflags; + native readonly int levelnum; + native readonly String LevelName; + native readonly String MapName; + native String NextMap; + native String NextSecretMap; + native readonly int maptype; + native readonly String Music; + native readonly int musicorder; + native int total_secrets; + native int found_secrets; + native int total_items; + native int found_items; + native int total_monsters; + native int killed_monsters; + native double gravity; + native double aircontrol; + native double airfriction; + native int airsupply; + native double teamdamage; + native bool monsterstelefrag; + native bool actownspecial; + native bool sndseqtotalctrl; + native bool allmap; + native bool missilesactivateimpact; + native bool monsterfallingdamage; + native bool checkswitchrange; + native bool polygrind; + native bool nomonsters; +// level_info_t *info cannot be done yet. +} + +struct StringTable native +{ + native static String Localize(String val); +} + +// a few values of this need to be readable by the play code. +// Most are handled at load time and are omitted here. +struct DehInfo native +{ + native int MaxSoulsphere; + native uint8 ExplosionStyle; + native double ExplosionAlpha; + native int NoAutofreeze; + native int BFGCells; +} + +struct State native +{ + native State NextState; + native int sprite; + native int16 Tics; + native uint16 TicRange; + native uint8 Frame; + native uint8 UseFlags; + native int Misc1; + native int Misc2; + native uint16 bSlow; + native uint16 bFast; + native bool bFullbright; + native bool bNoDelay; + native bool bSameFrame; + native bool bCanRaise; + native bool bDehacked; + + native int DistanceTo(state other); +} + +struct F3DFloor native +{ +} + +struct Line native +{ + enum ELineFlags + { + ML_BLOCKING =0x00000001, // solid, is an obstacle + ML_BLOCKMONSTERS =0x00000002, // blocks monsters only + ML_TWOSIDED =0x00000004, // backside will not be present at all if not two sided + ML_DONTPEGTOP = 0x00000008, // upper texture unpegged + ML_DONTPEGBOTTOM = 0x00000010, // lower texture unpegged + ML_SECRET = 0x00000020, // don't map as two sided: IT'S A SECRET! + ML_SOUNDBLOCK = 0x00000040, // don't let sound cross two of these + ML_DONTDRAW = 0x00000080, // don't draw on the automap + ML_MAPPED = 0x00000100, // set if already drawn in automap + ML_REPEAT_SPECIAL = 0x00000200, // special is repeatable + ML_ADDTRANS = 0x00000400, // additive translucency (can only be set internally) + + // Extended flags + ML_MONSTERSCANACTIVATE = 0x00002000, // [RH] Monsters (as well as players) can activate the line + ML_BLOCK_PLAYERS = 0x00004000, + ML_BLOCKEVERYTHING = 0x00008000, // [RH] Line blocks everything + ML_ZONEBOUNDARY = 0x00010000, + ML_RAILING = 0x00020000, + ML_BLOCK_FLOATERS = 0x00040000, + ML_CLIP_MIDTEX = 0x00080000, // Automatic for every Strife line + ML_WRAP_MIDTEX = 0x00100000, + ML_3DMIDTEX = 0x00200000, + ML_CHECKSWITCHRANGE = 0x00400000, + ML_FIRSTSIDEONLY = 0x00800000, // activated only when crossed from front side + ML_BLOCKPROJECTILE = 0x01000000, + ML_BLOCKUSE = 0x02000000, // blocks all use actions through this line + ML_BLOCKSIGHT = 0x04000000, // blocks monster line of sight + ML_BLOCKHITSCAN = 0x08000000, // blocks hitscan attacks + ML_3DMIDTEX_IMPASS = 0x10000000, // [TP] if 3D midtex, behaves like a height-restricted ML_BLOCKING + }; + + + //native readonly vertex v1, v2; // vertices, from v1 to v2 + native readonly Vector2 delta; // precalculated v2 - v1 for side checking + native uint flags; + native uint activation; // activation type + native int special; + native int args[5]; // <--- hexen-style arguments (expanded to ZDoom's full width) + native double alpha; // <--- translucency (0=invisibile, FRACUNIT=opaque) + //native Side sidedef[2]; + native readonly double bbox[4]; // bounding box, for the extent of the LineDef. + native readonly Sector frontsector, backsector; + native int validcount; // if == validcount, already checked + native int locknumber; // [Dusk] lock number for special + native readonly uint portalindex; +} + +struct Sector native +{ + //secplane_t floorplane, ceilingplane; + //FDynamicColormap *ColorMap; // [RH] Per-sector colormap + + native Actor SoundTarget; + + native int16 special; + native int16 lightlevel; + native int16 seqType; + + native int sky; + native Name SeqName; + + native readonly Vector2 centerspot; + native int validcount; + native Actor thinglist; + + native double friction, movefactor; + native int terrainnum[2]; + + // thinker_t for reversable actions + //SectorEffect floordata; + //SectorEffect ceilingdata; + //SectorEffect lightingdata; + + enum EInterpolationType + { + CeilingMove, + FloorMove, + CeilingScroll, + FloorScroll + }; + //Interpolation interpolations[4]; + + native uint8 soundtraversed; + native int8 stairlock; + native int prevsec; + native int nextsec; + + native readonly int16 linecount; + //line_t **lines; // this is defined internally to avoid exposing some overly complicated type to the parser + + native readonly Sector heightsec; + + native uint bottommap, midmap, topmap; + + //struct msecnode_t *touching_thinglist; + //struct msecnode_t *render_thinglist; + + native double gravity; + native Name damagetype; + native int damageamount; + native int16 damageinterval; + native int16 leakydamage; + + native uint16 ZoneNumber; + + enum ESectorMoreFlags + { + SECMF_FAKEFLOORONLY = 2, // when used as heightsec in R_FakeFlat, only copies floor + SECMF_CLIPFAKEPLANES = 4, // as a heightsec, clip planes to target sector's planes + SECMF_NOFAKELIGHT = 8, // heightsec does not change lighting + SECMF_IGNOREHEIGHTSEC= 16, // heightsec is only for triggering sector actions + SECMF_UNDERWATER = 32, // sector is underwater + SECMF_FORCEDUNDERWATER= 64, // sector is forced to be underwater + SECMF_UNDERWATERMASK = 32+64, + SECMF_DRAWN = 128, // sector has been drawn at least once + SECMF_HIDDEN = 256, // Do not draw on textured automap + } + native uint16 MoreFlags; + + enum ESectorFlags + { + SECF_SILENT = 1, // actors in sector make no noise + SECF_NOFALLINGDAMAGE= 2, // No falling damage in this sector + SECF_FLOORDROP = 4, // all actors standing on this floor will remain on it when it lowers very fast. + SECF_NORESPAWN = 8, // players can not respawn in this sector + SECF_FRICTION = 16, // sector has friction enabled + SECF_PUSH = 32, // pushers enabled + SECF_SILENTMOVE = 64, // Sector movement makes mo sound (Eternity got this so this may be useful for an extended cross-port standard.) + SECF_DMGTERRAINFX = 128, // spawns terrain splash when inflicting damage + SECF_ENDGODMODE = 256, // getting damaged by this sector ends god mode + SECF_ENDLEVEL = 512, // ends level when health goes below 10 + SECF_HAZARD = 1024, // Change to Strife's delayed damage handling. + + SECF_WASSECRET = 1 << 30, // a secret that was discovered + SECF_SECRET = 1 << 31, // a secret sector + + SECF_DAMAGEFLAGS = SECF_ENDGODMODE|SECF_ENDLEVEL|SECF_DMGTERRAINFX|SECF_HAZARD, + SECF_NOMODIFY = SECF_SECRET|SECF_WASSECRET, // not modifiable by Sector_ChangeFlags + SECF_SPECIALFLAGS = SECF_DAMAGEFLAGS|SECF_FRICTION|SECF_PUSH, // these flags originate from 'special and must be transferrable by floor thinkers + } + native uint Flags; + + native SectorAction SecActTarget; + + native readonly uint Portals[2]; + native readonly int PortalGroup; + + native readonly int sectornum; + + + native double, Sector, F3DFloor NextHighestCeilingAt(double x, double y, double bottomz, double topz, int flags = 0); + native double, Sector, F3DFloor NextLowestFloorAt(double x, double y, double z, int flags = 0, double steph = 0); + + native void RemoveForceField(); + native static Sector PointInSector(Vector2 pt); + native void SetColor(color c, int desat = 0); + native void SetFade(color c); +} + +struct Wads +{ + enum WadNamespace + { + ns_hidden = -1, + + ns_global = 0, + ns_sprites, + ns_flats, + ns_colormaps, + ns_acslibrary, + ns_newtextures, + ns_bloodraw, + ns_bloodsfx, + ns_bloodmisc, + ns_strifevoices, + ns_hires, + ns_voxels, + + ns_specialzipdirectory, + ns_sounds, + ns_patches, + ns_graphics, + ns_music, + + ns_firstskin, + } + + native static int CheckNumForName(string name, int ns, int wadnum = -1, bool exact = false); +} + +struct TerrainDef native +{ + native Name TerrainName; + native int Splash; + native int DamageAmount; + native Name DamageMOD; + native int DamageTimeMask; + native double FootClip; + native float StepVolume; + native int WalkStepTics; + native int RunStepTics; + native Sound LeftStepSound; + native Sound RightStepSound; + native bool IsLiquid; + native bool AllowProtection; + native double Friction; + native double MoveFactor; +}; + +enum EPickStart +{ + PPS_FORCERANDOM = 1, + PPS_NOBLOCKINGCHECK = 2, +} + +// Although String is a builtin type, this is a convenient way to attach methods to it. +struct String native +{ + native void Replace(String pattern, String replacement); +} + +class Floor : Thinker native +{ + // only here so that some constants and functions can be added. Not directly usable yet. + enum EFloor + { + floorLowerToLowest, + floorLowerToNearest, + floorLowerToHighest, + floorLowerByValue, + floorRaiseByValue, + floorRaiseToHighest, + floorRaiseToNearest, + floorRaiseAndCrush, + floorRaiseAndCrushDoom, + floorCrushStop, + floorLowerInstant, + floorRaiseInstant, + floorMoveToValue, + floorRaiseToLowestCeiling, + floorRaiseByTexture, + + floorLowerAndChange, + floorRaiseAndChange, + + floorRaiseToLowest, + floorRaiseToCeiling, + floorLowerToLowestCeiling, + floorLowerByTexture, + floorLowerToCeiling, + + donutRaise, + + buildStair, + waitStair, + resetStair, + + // Not to be used as parameters to EV_DoFloor() + genFloorChg0, + genFloorChgT, + genFloorChg + }; + + native static bool CreateFloor(sector sec, EFloor floortype, line ln, double speed, double height = 0, int crush = -1, int change = 0, bool crushmode = false, bool hereticlower = false); +} + +class Ceiling : Thinker native +{ + enum ECeiling + { + ceilLowerByValue, + ceilRaiseByValue, + ceilMoveToValue, + ceilLowerToHighestFloor, + ceilLowerInstant, + ceilRaiseInstant, + ceilCrushAndRaise, + ceilLowerAndCrush, + ceil_placeholder, + ceilCrushRaiseAndStay, + ceilRaiseToNearest, + ceilLowerToLowest, + ceilLowerToFloor, + + // The following are only used by Generic_Ceiling + ceilRaiseToHighest, + ceilLowerToHighest, + ceilRaiseToLowest, + ceilLowerToNearest, + ceilRaiseToHighestFloor, + ceilRaiseToFloor, + ceilRaiseByTexture, + ceilLowerByTexture, + + genCeilingChg0, + genCeilingChgT, + genCeilingChg + } + + enum ECrushMode + { + crushDoom = 0, + crushHexen = 1, + crushSlowdown = 2 + } + + native bool CreateCeiling(sector sec, int type, line ln, double speed, double speed2, double height = 0, int crush = -1, int silent = 0, int change = 0, int crushmode = crushDoom); + +} + +struct LookExParams +{ + double Fov; + double minDist; + double maxDist; + double maxHeardist; + int flags; + State seestate; +}; diff --git a/wadsrc/static/zscript/chex/chexammo.txt b/wadsrc/static/zscript/chex/chexammo.txt new file mode 100644 index 0000000000..23c3cccd5f --- /dev/null +++ b/wadsrc/static/zscript/chex/chexammo.txt @@ -0,0 +1,101 @@ +// Renaming and changing messages + +// Mini Zorch ----------------------------------------------------------------- + +class MiniZorchRecharge : Clip +{ + Default + { + inventory.pickupmessage "$GOTZORCHRECHARGE"; + } +} + +class MiniZorchPack : Clip +{ + Default + { + Inventory.PickupMessage "$GOTMINIZORCHPACK"; + Inventory.Amount 50; + } + States + { + Spawn: + AMMO A -1; + Stop; + } +} + +// Large Zorch ---------------------------------------------------------------- + +class LargeZorchRecharge : Shell +{ + Default + { + inventory.pickupmessage "$GOTLARGEZORCHERRECHARGE"; + } +} + +class LargeZorchPack : Shell +{ + Default + { + Inventory.PickupMessage "$GOTLARGEZORCHERPACK"; + Inventory.Amount 20; + } + States + { + Spawn: + SBOX A -1; + Stop; + } +} + +// Zorch Propulsor ------------------------------------------------------------ + +class PropulsorZorch : RocketAmmo +{ + Default + { + inventory.pickupmessage "$GOTPROPULSORRECHARGE"; + } +} + +class PropulsorZorchPack : RocketAmmo +{ + Default + { + Inventory.PickupMessage "$GOTPROPULSORPACK"; + Inventory.Amount 5; + } + States + { + Spawn: + BROK A -1; + Stop; + } +} + +// Phasing Zorch -------------------------------------------------------------- + +class PhasingZorch : Cell +{ + Default + { + inventory.pickupmessage "$GOTPHASINGZORCHERRECHARGE"; + } +} + +class PhasingZorchPack : Cell +{ + Default + { + Inventory.PickupMessage "$GOTPHASINGZORCHERPACK"; + Inventory.Amount 100; + } + States + { + Spawn: + CELP A -1; + Stop; + } +} diff --git a/wadsrc/static/zscript/chex/chexdecorations.txt b/wadsrc/static/zscript/chex/chexdecorations.txt new file mode 100644 index 0000000000..2db19181dd --- /dev/null +++ b/wadsrc/static/zscript/chex/chexdecorations.txt @@ -0,0 +1,180 @@ +// Doom items renamed with height changes + +// Civilians ------------------------------------------------------------------ + +class ChexCivilian1 : GreenTorch +{ + Default + { + height 54; + } +} + +class ChexCivilian2 : ShortGreenTorch +{ + Default + { + height 54; + } +} + +class ChexCivilian3 : ShortRedTorch +{ + Default + { + height 48; + } +} + +// Landing Zone --------------------------------------------------------------- + +class ChexLandingLight : Column +{ + Default + { + height 35; + } +} + +class ChexSpaceship : TechPillar +{ + Default + { + height 52; + } +} + +// Trees and Plants ----------------------------------------------------------- + +class ChexAppleTree : Stalagtite +{ + Default + { + height 92; + } +} + +class ChexBananaTree : BigTree +{ + Default + { + height 108; + } +} + +class ChexOrangeTree : TorchTree +{ + Default + { + height 92; + } +} + +class ChexSubmergedPlant : ShortGreenColumn +{ + Default + { + height 42; + } +} + +class ChexTallFlower : HeadsOnAStick +{ + Default + { + height 25; + } +} + +class ChexTallFlower2 : DeadStick +{ + Default + { + height 25; + } +} + +// Slime Fountain ------------------------------------------------------------- + +class ChexSlimeFountain : BlueTorch +{ + Default + { + height 48; + } + States + { + Spawn: + TBLU ABCD 4; + Loop; + } +} + +// Cavern Decorations --------------------------------------------------------- + +class ChexCavernColumn : TallRedColumn +{ + Default + { + height 128; + } +} + +class ChexCavernStalagmite : TallGreenColumn +{ + Default + { + height 60; + } +} + +// Misc. Props ---------------------------------------------------------------- + +class ChexChemicalBurner : EvilEye +{ + Default + { + height 25; + } +} + +class ChexChemicalFlask : Candlestick +{ + Default + { + RenderStyle "Translucent"; + alpha 0.75; + } +} + +class ChexFlagOnPole : SkullColumn +{ + Default + { + height 128; + } +} + +class ChexGasTank : Candelabra +{ + Default + { + height 36; + } +} + +class ChexLightColumn : ShortBlueTorch +{ + Default + { + height 86; + } +} + +class ChexMineCart : ShortRedColumn +{ + Default + { + height 30; + } +} diff --git a/wadsrc/static/zscript/chex/chexitems.txt b/wadsrc/static/zscript/chex/chexitems.txt new file mode 100644 index 0000000000..fc5d4c8174 --- /dev/null +++ b/wadsrc/static/zscript/chex/chexitems.txt @@ -0,0 +1,89 @@ + +// General Pickups ============================================================ + +// Health --------------------------------------------------------------------- + +class GlassOfWater : HealthBonus +{ + Default + { + inventory.pickupmessage "$GOTWATER"; + } +} + +class BowlOfFruit : Stimpack +{ + Default + { + inventory.pickupmessage "$GOTFRUIT"; + } +} + +class BowlOfVegetables : Medikit +{ + Default + { + inventory.pickupmessage "$GOTVEGETABLES"; + health.lowmessage 25, "$GOTVEGETABLESNEED"; + } +} + +class SuperchargeBreakfast : Soulsphere +{ + Default + { + inventory.pickupmessage "$GOTBREAKFAST"; + } +} + +// Armor ---------------------------------------------------------------------- + +class SlimeRepellent : ArmorBonus +{ + Default + { + inventory.pickupmessage "$GOTREPELLENT"; + } +} + +class ChexArmor : GreenArmor +{ + Default + { + inventory.pickupmessage "$GOTCHEXARMOR"; + } +} + +class SuperChexArmor : BlueArmor +{ + Default + { + inventory.pickupmessage "$GOTSUPERCHEXARMOR"; + } +} + +// Powerups =================================================================== + +class ComputerAreaMap : Allmap +{ + Default + { + inventory.pickupmessage "$GOTCHEXMAP"; + } +} + +class SlimeProofSuit : RadSuit +{ + Default + { + inventory.pickupmessage "$GOTSLIMESUIT"; + } +} + +class Zorchpack : Backpack +{ + Default + { + inventory.pickupmessage "$GOTZORCHPACK"; + } +} diff --git a/wadsrc/static/zscript/chex/chexkeys.txt b/wadsrc/static/zscript/chex/chexkeys.txt new file mode 100644 index 0000000000..5ac28330eb --- /dev/null +++ b/wadsrc/static/zscript/chex/chexkeys.txt @@ -0,0 +1,25 @@ +// These are merely renames of the Doom cards + +class ChexBlueCard : BlueCard +{ + Default + { + inventory.pickupmessage "$GOTCBLUEKEY"; + } +} + +class ChexYellowCard : YellowCard +{ + Default + { + inventory.pickupmessage "$GOTCYELLOWKEY"; + } +} + +class ChexRedCard : RedCard +{ + Default + { + inventory.pickupmessage "$GOTCREDKEY"; + } +} diff --git a/wadsrc/static/actors/chex/chexmonsters.txt b/wadsrc/static/zscript/chex/chexmonsters.txt similarity index 62% rename from wadsrc/static/actors/chex/chexmonsters.txt rename to wadsrc/static/zscript/chex/chexmonsters.txt index 0ee3c34c57..22e3977027 100644 --- a/wadsrc/static/actors/chex/chexmonsters.txt +++ b/wadsrc/static/zscript/chex/chexmonsters.txt @@ -5,16 +5,19 @@ // //=========================================================================== -actor FlemoidusCommonus : ZombieMan +class FlemoidusCommonus : ZombieMan { - DropItem "" - Obituary "$OB_COMMONUS" + Default + { + DropItem ""; + Obituary "$OB_COMMONUS"; + } States { Missile: - stop + Stop; Melee: - goto Super::Missile + goto Super::Missile; } } @@ -24,16 +27,19 @@ actor FlemoidusCommonus : ZombieMan // //=========================================================================== -actor FlemoidusBipedicus : ShotgunGuy +class FlemoidusBipedicus : ShotgunGuy { - DropItem "" - Obituary "$OB_BIPEDICUS" + Default + { + DropItem ""; + Obituary "$OB_BIPEDICUS"; + } States { Missile: - stop + Stop; Melee: - goto Super::Missile + goto Super::Missile; } } @@ -43,10 +49,13 @@ actor FlemoidusBipedicus : ShotgunGuy // //=========================================================================== -actor ArmoredFlemoidusBipedicus : DoomImp +class ArmoredFlemoidusBipedicus : DoomImp { - Obituary "$OB_BIPEDICUS2" - HitObituary "$OB_BIPEDICUS2" + Default + { + Obituary "$OB_BIPEDICUS2"; + HitObituary "$OB_BIPEDICUS2"; + } } //=========================================================================== @@ -55,9 +64,12 @@ actor ArmoredFlemoidusBipedicus : DoomImp // //=========================================================================== -actor FlemoidusCycloptisCommonus : Demon +class FlemoidusCycloptisCommonus : Demon { - Obituary "$OB_CYCLOPTIS" + Default + { + Obituary "$OB_CYCLOPTIS"; + } } //=========================================================================== @@ -66,24 +78,30 @@ actor FlemoidusCycloptisCommonus : Demon // //=========================================================================== -actor Flembrane : BaronOfHell +class Flembrane : BaronOfHell { - radius 44 - height 100 - speed 0 - Obituary "$OB_FLEMBRANE" + Default + { + radius 44; + height 100; + speed 0; + Obituary "$OB_FLEMBRANE"; + } States { Missile: - BOSS EF 3 A_FaceTarget - BOSS G 0 A_BruisAttack - goto See + BOSS EF 3 A_FaceTarget; + BOSS G 0 A_BruisAttack; + goto See; } } //=========================================================================== -actor ChexSoul : LostSoul +class ChexSoul : LostSoul { - height 0 + Default + { + height 0; + } } diff --git a/wadsrc/static/zscript/chex/chexplayer.txt b/wadsrc/static/zscript/chex/chexplayer.txt new file mode 100644 index 0000000000..43f7fc1eee --- /dev/null +++ b/wadsrc/static/zscript/chex/chexplayer.txt @@ -0,0 +1,32 @@ +// Chex Warrior + +class ChexPlayer : DoomPlayer +{ + Default + { + player.displayname "Chex Warrior"; + player.crouchsprite ""; + player.colorrange 192, 207; //Not perfect, but its better than everyone being blue. + player.startitem "MiniZorcher"; + player.startitem "Bootspoon"; + player.startitem "MiniZorchRecharge", 50; + player.damagescreencolor "60 b0 58"; + player.WeaponSlot 1, "Bootspoon", "SuperBootspork"; + player.WeaponSlot 2, "MiniZorcher"; + player.WeaponSlot 3, "LargeZorcher", "SuperLargeZorcher"; + player.WeaponSlot 4, "RapidZorcher"; + player.WeaponSlot 5, "ZorchPropulsor"; + player.WeaponSlot 6, "PhasingZorcher"; + player.WeaponSlot 7, "LAZDevice"; + + Player.Colorset 0, "Light Blue", 0xC0, 0xCF, 0xC2; + Player.Colorset 1, "Green", 0x70, 0x7F, 0x72; + Player.Colorset 2, "Gray", 0x60, 0x6F, 0x62; + Player.Colorset 3, "Brown", 0x40, 0x4F, 0x42; + Player.Colorset 4, "Red", 0x20, 0x2F, 0x22; + Player.Colorset 5, "Light Gray", 0x58, 0x67, 0x5A; + Player.Colorset 6, "Light Brown", 0x38, 0x47, 0x3A; + Player.Colorset 7, "Light Red", 0xB0, 0xBF, 0xB2; + } + +} diff --git a/wadsrc/static/zscript/chex/chexweapons.txt b/wadsrc/static/zscript/chex/chexweapons.txt new file mode 100644 index 0000000000..a4c862d64c --- /dev/null +++ b/wadsrc/static/zscript/chex/chexweapons.txt @@ -0,0 +1,160 @@ +// Same as Doom weapons, but the obituaries are removed. + +class Bootspoon : Fist +{ + Default + { + obituary "$OB_MPSPOON"; + Tag "$TAG_SPOON"; + } +} + +class SuperBootspork : Chainsaw +{ + Default + { + obituary "$OB_MPBOOTSPORK"; + Inventory.PickupMessage "$GOTSUPERBOOTSPORK"; + Tag "$TAG_SPORK"; + } +} + +class MiniZorcher : Pistol +{ + Default + { + obituary "$OB_MPZORCH"; + inventory.pickupmessage "$GOTMINIZORCHER"; + Tag "$TAG_MINIZORCHER"; + } + States + { + Spawn: + MINZ A -1; + Stop; + } +} + +class LargeZorcher : Shotgun +{ + Default + { + obituary "$OB_MPZORCH"; + inventory.pickupmessage "$GOTLARGEZORCHER"; + Tag "$TAG_LARGEZORCHER"; + } +} + +class SuperLargeZorcher : SuperShotgun +{ + Default + { + obituary "$OB_MPMEGAZORCH"; + inventory.pickupmessage "$GOTSUPERLARGEZORCHER"; + Tag "$TAG_SUPERLARGEZORCHER"; + } +} + +class RapidZorcher : Chaingun +{ + Default + { + obituary "$OB_MPRAPIDZORCH"; + inventory.pickupmessage "$GOTRAPIDZORCHER"; + Tag "$TAG_RAPIDZORCHER"; + } +} + +class ZorchPropulsor : RocketLauncher +{ + Default + { + obituary ""; + inventory.pickupmessage "$GOTZORCHPROPULSOR"; + Tag "$TAG_ZORCHPROPULSOR"; + } + States + { + Fire: + MISG B 8 A_GunFlash; + MISG B 12 A_FireCustomMissile("PropulsorMissile"); + MISG B 0 A_ReFire; + Goto Ready; + } +} + +class PropulsorMissile : Rocket +{ + Default + { + -ROCKETTRAIL + -DEHEXPLOSION + RenderStyle "Translucent"; + Obituary "$OB_MPPROPULSOR"; + Alpha 0.75; + } +} + +class PhasingZorcher : PlasmaRifle +{ + Default + { + obituary ""; + inventory.pickupmessage "$GOTPHASINGZORCHER"; + Tag "$TAG_PHASINGZORCHER"; + } + States + { + Fire: + PLSG A 0 A_GunFlash; + PLSG A 3 A_FireCustomMissile("PhaseZorchMissile"); + PLSG B 20 A_ReFire; + Goto Ready; + Flash: + PLSF A 0 A_Jump(128, "Flash2"); + PLSF A 3 Bright A_Light1; + Goto LightDone; + Flash2: + PLSF B 3 Bright A_Light1; + Goto LightDone; + } +} + +class PhaseZorchMissile : PlasmaBall +{ + Default + { + RenderStyle "Translucent"; + Obituary "$OB_MPPHASEZORCH"; + Alpha 0.75; + } +} + +class LAZDevice : BFG9000 +{ + Default + { + obituary ""; + inventory.pickupmessage "$GOTLAZDEVICE"; + Tag "$TAG_LAZDEVICE"; + } + States + { + Fire: + BFGG A 20 A_BFGsound; + BFGG B 10 A_GunFlash; + BFGG B 10 A_FireCustomMissile("LAZBall"); + BFGG B 20 A_ReFire; + Goto Ready; + } +} + +class LAZBall : BFGBall +{ + Default + { + RenderStyle "Translucent"; + Obituary "$OB_MPLAZ_BOOM"; + Alpha 0.75; + } +} diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt new file mode 100644 index 0000000000..147b23e4ef --- /dev/null +++ b/wadsrc/static/zscript/constants.txt @@ -0,0 +1,1055 @@ +// for flag changer functions. +const FLAG_NO_CHANGE = -1; +const MAXPLAYERS = 8; + +enum EStateUseFlags +{ + SUF_ACTOR = 1, + SUF_OVERLAY = 2, + SUF_WEAPON = 4, + SUF_ITEM = 8, +}; + +// Flags for A_PainAttack +enum EPainAttackFlags +{ + PAF_NOSKULLATTACK = 1, + PAF_AIMFACING = 2, + PAF_NOTARGET = 4, +}; + +// Flags for A_VileAttack +enum EVileAttackFlags +{ + VAF_DMGTYPEAPPLYTODIRECT = 1, +}; + +// Flags for A_Saw +enum ESawFlags +{ + SF_NORANDOM = 1, + SF_RANDOMLIGHTMISS = 2, + SF_RANDOMLIGHTHIT = 4, + SF_RANDOMLIGHTBOTH = 6, + SF_NOUSEAMMOMISS = 8, + SF_NOUSEAMMO = 16, + SF_NOPULLIN = 32, + SF_NOTURN = 64, + SF_STEALARMOR = 128, +}; + +// Flags for A_BFGSpray +enum EBFGSprayFlags +{ + BFGF_HURTSOURCE = 1, + BFGF_MISSILEORIGIN = 2, +}; + +// Flags for A_CustomMissile +enum ECustomMissileFlags +{ + CMF_AIMOFFSET = 1, + CMF_AIMDIRECTION = 2, + CMF_TRACKOWNER = 4, + CMF_CHECKTARGETDEAD = 8, + CMF_ABSOLUTEPITCH = 16, + CMF_OFFSETPITCH = 32, + CMF_SAVEPITCH = 64, + CMF_ABSOLUTEANGLE = 128, +}; + +// Flags for A_CustomBulletAttack +enum ECustomBulletAttackFlags +{ + CBAF_AIMFACING = 1, + CBAF_NORANDOM = 2, + CBAF_EXPLICITANGLE = 4, + CBAF_NOPITCH = 8, + CBAF_NORANDOMPUFFZ = 16, + CBAF_PUFFTARGET = 32, + CBAF_PUFFMASTER = 64, + CBAF_PUFFTRACER = 128, +}; + +// Flags for A_GunFlash +enum EGunFlashFlags +{ + GFF_NOEXTCHANGE = 1, +}; + +// Flags for A_FireBullets +enum EFireBulletsFlags +{ + FBF_USEAMMO = 1, + FBF_NORANDOM = 2, + FBF_EXPLICITANGLE = 4, + FBF_NOPITCH = 8, + FBF_NOFLASH = 16, + FBF_NORANDOMPUFFZ = 32, + FBF_PUFFTARGET = 64, + FBF_PUFFMASTER = 128, + FBF_PUFFTRACER = 256, +}; + +// Flags for A_SpawnItemEx +enum ESpawnItemFlags +{ + SXF_TRANSFERTRANSLATION = 1 << 0, + SXF_ABSOLUTEPOSITION = 1 << 1, + SXF_ABSOLUTEANGLE = 1 << 2, + SXF_ABSOLUTEMOMENTUM = 1 << 3, //Since "momentum" is declared to be deprecated in the expressions, for compatibility + SXF_ABSOLUTEVELOCITY = 1 << 3, //purposes, this was made. It does the same thing though. Do not change the value. + SXF_SETMASTER = 1 << 4, + SXF_NOCHECKPOSITION = 1 << 5, + SXF_TELEFRAG = 1 << 6, + SXF_CLIENTSIDE = 1 << 7, // only used by Skulltag + SXF_TRANSFERAMBUSHFLAG = 1 << 8, + SXF_TRANSFERPITCH = 1 << 9, + SXF_TRANSFERPOINTERS = 1 << 10, + SXF_USEBLOODCOLOR = 1 << 11, + SXF_CLEARCALLERTID = 1 << 12, + SXF_MULTIPLYSPEED = 1 << 13, + SXF_TRANSFERSCALE = 1 << 14, + SXF_TRANSFERSPECIAL = 1 << 15, + SXF_CLEARCALLERSPECIAL = 1 << 16, + SXF_TRANSFERSTENCILCOL = 1 << 17, + SXF_TRANSFERALPHA = 1 << 18, + SXF_TRANSFERRENDERSTYLE = 1 << 19, + SXF_SETTARGET = 1 << 20, + SXF_SETTRACER = 1 << 21, + SXF_NOPOINTERS = 1 << 22, + SXF_ORIGINATOR = 1 << 23, + SXF_TRANSFERSPRITEFRAME = 1 << 24, + SXF_TRANSFERROLL = 1 << 25, + SXF_ISTARGET = 1 << 26, + SXF_ISMASTER = 1 << 27, + SXF_ISTRACER = 1 << 28, +}; + +// Flags for A_Chase +enum EChaseFlags +{ + CHF_FASTCHASE = 1, + CHF_NOPLAYACTIVE = 2, + CHF_NIGHTMAREFAST = 4, + CHF_RESURRECT = 8, + CHF_DONTMOVE = 16, + CHF_NORANDOMTURN = 32, + CHF_NODIRECTIONTURN = 64, + CHF_NOPOSTATTACKTURN = 128, + CHF_STOPIFBLOCKED = 256, + + CHF_DONTTURN = CHF_NORANDOMTURN | CHF_NOPOSTATTACKTURN | CHF_STOPIFBLOCKED +}; + +// Flags for A_LookEx +enum ELookFlags +{ + LOF_NOSIGHTCHECK = 1, + LOF_NOSOUNDCHECK = 2, + LOF_DONTCHASEGOAL = 4, + LOF_NOSEESOUND = 8, + LOF_FULLVOLSEESOUND = 16, + LOF_NOJUMP = 32, +}; + +// Flags for A_Respawn +enum ERespawnFlags +{ + RSF_FOG = 1, + RSF_KEEPTARGET = 2, + RSF_TELEFRAG = 4, +}; + +// Flags for A_JumpIfTargetInLOS and A_JumpIfInTargetLOS +enum EJumpFlags +{ + JLOSF_PROJECTILE = 1, + JLOSF_NOSIGHT = 1 << 1, + JLOSF_CLOSENOFOV = 1 << 2, + JLOSF_CLOSENOSIGHT = 1 << 3, + JLOSF_CLOSENOJUMP = 1 << 4, + JLOSF_DEADNOJUMP = 1 << 5, + JLOSF_CHECKMASTER = 1 << 6, + JLOSF_TARGETLOS = 1 << 7, + JLOSF_FLIPFOV = 1 << 8, + JLOSF_ALLYNOJUMP = 1 << 9, + JLOSF_COMBATANTONLY = 1 << 10, + JLOSF_NOAUTOAIM = 1 << 11, + JLOSF_CHECKTRACER = 1 << 12, +}; + +// Flags for A_ChangeVelocity +enum EChangeVelocityFlags +{ + CVF_RELATIVE = 1, + CVF_REPLACE = 2, +}; + +// Flags for A_WeaponReady +enum EWeaponReadyFlags +{ + WRF_NOBOB = 1, + WRF_NOSWITCH = 2, + WRF_NOPRIMARY = 4, + WRF_NOSECONDARY = 8, + WRF_NOFIRE = WRF_NOPRIMARY | WRF_NOSECONDARY, + WRF_ALLOWRELOAD = 16, + WRF_ALLOWZOOM = 32, + WRF_DISABLESWITCH = 64, + WRF_ALLOWUSER1 = 128, + WRF_ALLOWUSER2 = 256, + WRF_ALLOWUSER3 = 512, + WRF_ALLOWUSER4 = 1024, +}; + +// Flags for A_SelectWeapon +enum ESelectWeaponFlags +{ + SWF_SELECTPRIORITY = 1, +}; + +// Morph constants +enum EMorphFlags +{ + MRF_ADDSTAMINA = 1, + MRF_FULLHEALTH = 2, + MRF_UNDOBYTOMEOFPOWER = 4, + MRF_UNDOBYCHAOSDEVICE = 8, + MRF_FAILNOTELEFRAG = 16, + MRF_FAILNOLAUGH = 32, + MRF_WHENINVULNERABLE = 64, + MRF_LOSEACTUALWEAPON = 128, + MRF_NEWTIDBEHAVIOUR = 256, + MRF_UNDOBYDEATH = 512, + MRF_UNDOBYDEATHFORCED = 1024, + MRF_UNDOBYDEATHSAVES = 2048, + MRF_UNDOALWAYS = 4096, + MRF_TRANSFERTRANSLATION = 8192, +}; + +// Flags for A_RailAttack and A_CustomRailgun +enum ERailFlags +{ + RGF_SILENT = 1, + RGF_NOPIERCING = 2, + RGF_EXPLICITANGLE = 4, + RGF_FULLBRIGHT = 8, + RGF_CENTERZ = 16, + RGF_NORANDOMPUFFZ = 32, +}; + +// Flags for A_Mushroom +enum EMushroomFlags +{ + MSF_Standard = 0, + MSF_Classic = 1, + MSF_DontHurt = 2, +}; + +// Flags for A_Explode +enum EExplodeFlags +{ + XF_HURTSOURCE = 1, + XF_NOTMISSILE = 4, + XF_EXPLICITDAMAGETYPE = 8, + XF_NOSPLASH = 16, +}; + +// Flags for A_RadiusThrust +enum ERadiusThrustFlags +{ + RTF_AFFECTSOURCE = 1, + RTF_NOIMPACTDAMAGE = 2, + RTF_NOTMISSILE = 4, + RTF_THRUSTZ = 16, +}; + +// Flags for A_RadiusDamageSelf +enum ERadiusDamageSelfFlags +{ + RDSF_BFGDAMAGE = 1, +}; + +// Flags for A_Blast +enum EBlastFlags +{ + BF_USEAMMO = 1, + BF_DONTWARN = 2, + BF_AFFECTBOSSES = 4, + BF_NOIMPACTDAMAGE = 8, +}; + +// Flags for A_SeekerMissile +enum ESeekerMissileFlags +{ + SMF_LOOK = 1, + SMF_PRECISE = 2, + SMF_CURSPEED = 4, +}; + +// Flags for A_CustomPunch +enum ECustomPunchFlags +{ + CPF_USEAMMO = 1, + CPF_DAGGER = 2, + CPF_PULLIN = 4, + CPF_NORANDOMPUFFZ = 8, + CPF_NOTURN = 16, + CPF_STEALARMOR = 32, +}; + +enum EFireCustomMissileFlags +{ + FPF_AIMATANGLE = 1, + FPF_TRANSFERTRANSLATION = 2, + FPF_NOAUTOAIM = 4, +}; + +// Flags for A_Teleport +enum ETeleportFlags +{ + TF_TELEFRAG = 0x00000001, // Allow telefrag in order to teleport. + TF_RANDOMDECIDE = 0x00000002, // Randomly fail based on health. (A_Srcr2Decide) + TF_FORCED = 0x00000004, // Forget what's in the way. TF_Telefrag takes precedence though. + TF_KEEPVELOCITY = 0x00000008, // Preserve velocity. + TF_KEEPANGLE = 0x00000010, // Keep angle. + TF_USESPOTZ = 0x00000020, // Set the z to the spot's z, instead of the floor. + TF_NOSRCFOG = 0x00000040, // Don't leave any fog behind when teleporting. + TF_NODESTFOG = 0x00000080, // Don't spawn any fog at the arrival position. + TF_USEACTORFOG = 0x00000100, // Use the actor's TeleFogSourceType and TeleFogDestType fogs. + TF_NOJUMP = 0x00000200, // Don't jump after teleporting. + TF_OVERRIDE = 0x00000400, // Ignore NOTELEPORT. + TF_SENSITIVEZ = 0x00000800, // Fail if the actor wouldn't fit in the position (for Z). + + TF_KEEPORIENTATION = TF_KEEPVELOCITY|TF_KEEPANGLE, + TF_NOFOG = TF_NOSRCFOG|TF_NODESTFOG, +}; + +// Flags for A_WolfAttack +enum EWolfAttackFlags +{ + WAF_NORANDOM = 1, + WAF_USEPUFF = 2 +}; + +// Flags for A_RadiusGive +enum ERadiusGiveFlags +{ + RGF_GIVESELF = 1, + RGF_PLAYERS = 1 << 1, + RGF_MONSTERS = 1 << 2, + RGF_OBJECTS = 1 << 3, + RGF_VOODOO = 1 << 4, + RGF_CORPSES = 1 << 5, + RGF_NOTARGET = 1 << 6, + RGF_NOTRACER = 1 << 7, + RGF_NOMASTER = 1 << 8, + RGF_CUBE = 1 << 9, + RGF_NOSIGHT = 1 << 10, + RGF_MISSILES = 1 << 11, + RGF_INCLUSIVE = 1 << 12, + RGF_ITEMS = 1 << 13, + RGF_KILLED = 1 << 14, + RGF_EXFILTER = 1 << 15, + RGF_EXSPECIES = 1 << 16, + RGF_EITHER = 1 << 17, +}; + +// Activation flags +enum EActivationFlags +{ + THINGSPEC_Default = 0, + THINGSPEC_ThingActs = 1, + THINGSPEC_ThingTargets = 2, + THINGSPEC_TriggerTargets = 4, + THINGSPEC_MonsterTrigger = 8, + THINGSPEC_MissileTrigger = 16, + THINGSPEC_ClearSpecial = 32, + THINGSPEC_NoDeathSpecial = 64, + THINGSPEC_TriggerActs = 128, + THINGSPEC_Activate = 1<<8, // The thing is activated when triggered + THINGSPEC_Deactivate = 1<<9, // The thing is deactivated when triggered + THINGSPEC_Switch = 1<<10, // The thing is alternatively activated and deactivated when triggered + + // Shorter aliases for same + AF_Default = 0, + AF_ThingActs = 1, + AF_ThingTargets = 2, + AF_TriggerTargets = 4, + AF_MonsterTrigger = 8, + AF_MissileTrigger = 16, + AF_ClearSpecial = 32, + AF_NoDeathSpecial = 64, + AF_TriggerActs = 128, + AF_Activate = 1<<8, // The thing is activated when triggered + AF_Deactivate = 1<<9, // The thing is deactivated when triggered + AF_Switch = 1<<10, // The thing is alternatively activated and deactivated when triggered + +}; + +// Flags for A_TakeInventory and A_TakeFromTarget +enum ETakeFlags +{ + TIF_NOTAKEINFINITE = 1 +}; + +// constants for A_PlaySound +enum ESoundFlags +{ + CHAN_AUTO = 0, + CHAN_WEAPON = 1, + CHAN_VOICE = 2, + CHAN_ITEM = 3, + CHAN_BODY = 4, + CHAN_5 = 5, + CHAN_6 = 6, + CHAN_7 = 7, + + // modifier flags + CHAN_LISTENERZ = 8, + CHAN_MAYBE_LOCAL = 16, + CHAN_UI = 32, + CHAN_NOPAUSE = 64 +}; + +// sound attenuation values +const ATTN_NONE = 0; +const ATTN_NORM = 1; +const ATTN_IDLE = 1.001; +const ATTN_STATIC = 3; + +// For SetPlayerProprty action special +enum EPlayerProperties +{ + PROP_FROZEN = 0, + PROP_NOTARGET = 1, + PROP_INSTANTWEAPONSWITCH = 2, + PROP_FLY = 3, + PROP_TOTALLYFROZEN = 4, + PROP_INVULNERABILITY = 5, // (Deprecated) + PROP_STRENGTH = 6, // (Deprecated) + PROP_INVISIBILITY = 7, // (Deprecated) + PROP_RADIATIONSUIT = 8, // (Deprecated) + PROP_ALLMAP = 9, // (Deprecated) + PROP_INFRARED = 10, // (Deprecated) + PROP_WEAPONLEVEL2 = 11, // (Deprecated) + PROP_FLIGHT = 12, // (Deprecated) + PROP_SPEED = 15, // (Deprecated) + PROP_BUDDHA = 16, +} + +// Line_SetBlocking +enum EBlockFlags +{ + BLOCKF_CREATURES = 1, + BLOCKF_MONSTERS = 2, + BLOCKF_PLAYERS = 4, + BLOCKF_FLOATERS = 8, + BLOCKF_PROJECTILES = 16, + BLOCKF_EVERYTHING = 32, + BLOCKF_RAILING = 64, + BLOCKF_USE = 128, +}; + +// Pointer constants, bitfield-enabled +enum EPointerFlags +{ + AAPTR_DEFAULT = 0, + AAPTR_NULL = 0x1, + AAPTR_TARGET = 0x2, + AAPTR_MASTER = 0x4, + AAPTR_TRACER = 0x8, + + AAPTR_PLAYER_GETTARGET = 0x10, + AAPTR_PLAYER_GETCONVERSATION = 0x20, + + AAPTR_PLAYER1 = 0x40, + AAPTR_PLAYER2 = 0x80, + AAPTR_PLAYER3 = 0x100, + AAPTR_PLAYER4 = 0x200, + AAPTR_PLAYER5 = 0x400, + AAPTR_PLAYER6 = 0x800, + AAPTR_PLAYER7 = 0x1000, + AAPTR_PLAYER8 = 0x2000, + AAPTR_FRIENDPLAYER = 0x4000, + AAPTR_LINETARGET = 0x8000, +}; + +// Pointer operation flags + +enum EPointerOperations +{ + PTROP_UNSAFETARGET = 1, + PTROP_UNSAFEMASTER = 2, + PTROP_NOSAFEGUARDS = PTROP_UNSAFETARGET|PTROP_UNSAFEMASTER, +}; + +// Flags for A_Warp + +enum EWarpFlags +{ + WARPF_ABSOLUTEOFFSET = 0x1, + WARPF_ABSOLUTEANGLE = 0x2, + WARPF_USECALLERANGLE = 0x4, + WARPF_NOCHECKPOSITION = 0x8, + WARPF_INTERPOLATE = 0x10, + WARPF_WARPINTERPOLATION = 0x20, + WARPF_COPYINTERPOLATION = 0x40, + WARPF_STOP = 0x80, + WARPF_TOFLOOR = 0x100, + WARPF_TESTONLY = 0x200, + WAPRF_ABSOLUTEPOSITION = 0x400, + WARPF_ABSOLUTEPOSITION = 0x400, + WARPF_BOB = 0x800, + WARPF_MOVEPTR = 0x1000, + WARPF_USETID = 0x2000, + WARPF_COPYVELOCITY = 0x4000, + WARPF_COPYPITCH = 0x8000, +}; + +// flags for A_SetPitch/SetAngle/SetRoll +enum EAngleFlags +{ + SPF_FORCECLAMP = 1, + SPF_INTERPOLATE = 2, +}; + +// flags for A_CheckLOF + +enum ELOFFlags +{ + CLOFF_NOAIM_VERT = 0x1, + CLOFF_NOAIM_HORZ = 0x2, + + CLOFF_JUMPENEMY = 0x4, + CLOFF_JUMPFRIEND = 0x8, + CLOFF_JUMPOBJECT = 0x10, + CLOFF_JUMPNONHOSTILE = 0x20, + + CLOFF_SKIPENEMY = 0x40, + CLOFF_SKIPFRIEND = 0x80, + CLOFF_SKIPOBJECT = 0x100, + CLOFF_SKIPNONHOSTILE = 0x200, + + CLOFF_MUSTBESHOOTABLE = 0x400, + + CLOFF_SKIPTARGET = 0x800, + CLOFF_ALLOWNULL = 0x1000, + CLOFF_CHECKPARTIAL = 0x2000, + + CLOFF_MUSTBEGHOST = 0x4000, + CLOFF_IGNOREGHOST = 0x8000, + + CLOFF_MUSTBESOLID = 0x10000, + CLOFF_BEYONDTARGET = 0x20000, + + CLOFF_FROMBASE = 0x40000, + CLOFF_MUL_HEIGHT = 0x80000, + CLOFF_MUL_WIDTH = 0x100000, + + CLOFF_JUMP_ON_MISS = 0x200000, + CLOFF_AIM_VERT_NOOFFSET = 0x400000, + + CLOFF_SETTARGET = 0x800000, + CLOFF_SETMASTER = 0x1000000, + CLOFF_SETTRACER = 0x2000000, + + CLOFF_SKIPOBSTACLES = CLOFF_SKIPENEMY|CLOFF_SKIPFRIEND|CLOFF_SKIPOBJECT|CLOFF_SKIPNONHOSTILE, + CLOFF_NOAIM = CLOFF_NOAIM_VERT|CLOFF_NOAIM_HORZ +}; + +// Flags for A_Kill (Master/Target/Tracer/Children/Siblings) series +enum EKillFlags +{ + KILS_FOILINVUL = 0x00000001, + KILS_KILLMISSILES = 0x00000002, + KILS_NOMONSTERS = 0x00000004, + KILS_FOILBUDDHA = 0x00000008, + KILS_EXFILTER = 0x00000010, + KILS_EXSPECIES = 0x00000020, + KILS_EITHER = 0x00000040, +}; + +// Flags for A_Damage (Master/Target/Tracer/Children/Siblings/Self) series +enum EDamageFlags +{ + DMSS_FOILINVUL = 0x00000001, + DMSS_AFFECTARMOR = 0x00000002, + DMSS_KILL = 0x00000004, + DMSS_NOFACTOR = 0x00000008, + DMSS_FOILBUDDHA = 0x00000010, + DMSS_NOPROTECT = 0x00000020, + DMSS_EXFILTER = 0x00000040, + DMSS_EXSPECIES = 0x00000080, + DMSS_EITHER = 0x00000100, + DMSS_INFLICTORDMGTYPE = 0x00000200, +}; + +// Flags for A_AlertMonsters +enum EAlertFlags +{ + AMF_TARGETEMITTER = 1, + AMF_TARGETNONPLAYER = 2, + AMF_EMITFROMTARGET = 4, +} + +// Flags for A_Remove* +enum ERemoveFlags +{ + RMVF_MISSILES = 0x00000001, + RMVF_NOMONSTERS = 0x00000002, + RMVF_MISC = 0x00000004, + RMVF_EVERYTHING = 0x00000008, + RMVF_EXFILTER = 0x00000010, + RMVF_EXSPECIES = 0x00000020, + RMVF_EITHER = 0x00000040, +}; + +// Flags for A_Fade* +enum EFadeFlags +{ + FTF_REMOVE = 1 << 0, + FTF_CLAMP = 1 << 1, +}; + +// Flags for A_Face* +enum EFaceFlags +{ + FAF_BOTTOM = 1, + FAF_MIDDLE = 2, + FAF_TOP = 4, + FAF_NODISTFACTOR = 8, +}; + +// Flags for A_QuakeEx +enum EQuakeFlags +{ + QF_RELATIVE = 1, + QF_SCALEDOWN = 1 << 1, + QF_SCALEUP = 1 << 2, + QF_MAX = 1 << 3, + QF_FULLINTENSITY = 1 << 4, + QF_WAVE = 1 << 5, +}; + +// A_CheckProximity flags +enum EProximityFlags +{ + CPXF_ANCESTOR = 1, + CPXF_LESSOREQUAL = 1 << 1, + CPXF_NOZ = 1 << 2, + CPXF_COUNTDEAD = 1 << 3, + CPXF_DEADONLY = 1 << 4, + CPXF_EXACT = 1 << 5, + CPXF_SETTARGET = 1 << 6, + CPXF_SETMASTER = 1 << 7, + CPXF_SETTRACER = 1 << 8, + CPXF_FARTHEST = 1 << 9, + CPXF_CLOSEST = 1 << 10, + CPXF_SETONPTR = 1 << 11, + CPXF_CHECKSIGHT = 1 << 12, +}; + +// Flags for A_CheckBlock +// These flags only affect the calling actor('s pointer), not the ones being searched. +enum ECheckBlockFlags +{ + CBF_NOLINES = 1 << 0, //Don't check actors. + CBF_SETTARGET = 1 << 1, //Sets the caller/pointer's target to the actor blocking it. Actors only. + CBF_SETMASTER = 1 << 2, //^ but with master. + CBF_SETTRACER = 1 << 3, //^ but with tracer. + CBF_SETONPTR = 1 << 4, //Sets the pointer change on the actor doing the checking instead of self. + CBF_DROPOFF = 1 << 5, //Check for dropoffs. + CBF_NOACTORS = 1 << 6, //Don't check actors. + CBF_ABSOLUTEPOS = 1 << 7, //Absolute position for offsets. + CBF_ABSOLUTEANGLE = 1 << 8, //Absolute angle for offsets. +}; + +enum EParticleFlags +{ + SPF_FULLBRIGHT = 1, + SPF_RELPOS = 1 << 1, + SPF_RELVEL = 1 << 2, + SPF_RELACCEL = 1 << 3, + SPF_RELANG = 1 << 4, + SPF_NOTIMEFREEZE = 1 << 5, + + SPF_RELATIVE = SPF_RELPOS|SPF_RELVEL|SPF_RELACCEL|SPF_RELANG +}; + +//Flags for A_FaceMovementDirection +enum EMovementFlags +{ + FMDF_NOPITCH = 1 << 0, + FMDF_INTERPOLATE = 1 << 1, + FMDF_NOANGLE = 1 << 2, +}; + +// Flags for GetZAt +enum EZFlags +{ + GZF_ABSOLUTEPOS = 1, // Use the absolute position instead of an offsetted one. + GZF_ABSOLUTEANG = 1 << 1, // Don't add the actor's angle to the parameter. + GZF_CEILING = 1 << 2, // Check the ceiling instead of the floor. + GZF_3DRESTRICT = 1 << 3, // Ignore midtextures and 3D floors above the pointer's z. + GZF_NOPORTALS = 1 << 4, // Don't pass through any portals. + GZF_NO3DFLOOR = 1 << 5, // Pass all 3D floors. +}; + +// Flags for A_WeaponOffset +enum EWeaponOffsetFlags +{ + WOF_KEEPX = 1, + WOF_KEEPY = 1 << 1, + WOF_ADD = 1 << 2, +}; + +// Flags for psprite layers +enum EPSpriteFlags +{ + PSPF_ADDWEAPON = 1 << 0, + PSPF_ADDBOB = 1 << 1, + PSPF_POWDOUBLE = 1 << 2, + PSPF_CVARFAST = 1 << 3, + PSPF_FLIP = 1 << 6, +}; + +// Default psprite layers +enum EPSPLayers +{ + PSP_STRIFEHANDS = -1, + PSP_WEAPON = 1, + PSP_FLASH = 1000, +}; + +enum EInputFlags +{ + // These are the original inputs sent by the player. + INPUT_OLDBUTTONS, + INPUT_BUTTONS, + INPUT_PITCH, + INPUT_YAW, + INPUT_ROLL, + INPUT_FORWARDMOVE, + INPUT_SIDEMOVE, + INPUT_UPMOVE, + + // These are the inputs, as modified by P_PlayerThink(). + // Most of the time, these will match the original inputs, but + // they can be different if a player is frozen or using a + // chainsaw. + MODINPUT_OLDBUTTONS, + MODINPUT_BUTTONS, + MODINPUT_PITCH, + MODINPUT_YAW, + MODINPUT_ROLL, + MODINPUT_FORWARDMOVE, + MODINPUT_SIDEMOVE, + MODINPUT_UPMOVE +}; + +enum EButtons +{ + BT_ATTACK = 1<<0, // Press "Fire". + BT_USE = 1<<1, // Use button, to open doors, activate switches. + BT_JUMP = 1<<2, + BT_CROUCH = 1<<3, + BT_TURN180 = 1<<4, + BT_ALTATTACK = 1<<5, // Press your other "Fire". + BT_RELOAD = 1<<6, // [XA] Reload key. Causes state jump in A_WeaponReady. + BT_ZOOM = 1<<7, // [XA] Zoom key. Ditto. + + // The rest are all ignored by the play simulation and are for scripts. + BT_SPEED = 1<<8, + BT_STRAFE = 1<<9, + + BT_MOVERIGHT = 1<<10, + BT_MOVELEFT = 1<<11, + BT_BACK = 1<<12, + BT_FORWARD = 1<<13, + BT_RIGHT = 1<<14, + BT_LEFT = 1<<15, + BT_LOOKUP = 1<<16, + BT_LOOKDOWN = 1<<17, + BT_MOVEUP = 1<<18, + BT_MOVEDOWN = 1<<19, + BT_SHOWSCORES = 1<<20, + + BT_USER1 = 1<<21, + BT_USER2 = 1<<22, + BT_USER3 = 1<<23, + BT_USER4 = 1<<24, +}; + +// Flags for GetAngle +enum EGetAngleFlags +{ + GAF_RELATIVE = 1, + GAF_SWITCH = 1 << 1, +}; + +//Flags for A_CopySpriteFrame +enum ECopySpriteFrameFlags +{ + CPSF_NOSPRITE = 1, + CPSF_NOFRAME = 1 << 1, +}; + +//Flags for A_SetMaskRotation +enum EMaskRotationFlags +{ + VRF_NOANGLESTART = 1, + VRF_NOANGLEEND = 1 << 1, + VRF_NOPITCHSTART = 1 << 2, + VRF_NOPITCHEND = 1 << 3, + + VRF_NOANGLE = VRF_NOANGLESTART|VRF_NOANGLEEND, + VRF_NOPITCH = VRF_NOPITCHSTART|VRF_NOPITCHEND, +}; + +enum ERenderStyle +{ + STYLE_None, + STYLE_Normal, + STYLE_Fuzzy, + STYLE_SoulTrans, + STYLE_OptFuzzy, + STYLE_Stencil, + STYLE_Translucent, + STYLE_Add, + STYLE_Shaded, + STYLE_TranslucentStencil, + STYLE_Shadow, + STYLE_Subtract, + STYLE_AddStencil, + STYLE_AddShaded, +}; + +// Type definition for the implicit 'callingstate' parameter that gets passed to action functions. +enum EStateType +{ + STATE_Actor, + STATE_Psprite, + STATE_StateChain, +} + +struct FStateParamInfo +{ + state mCallingState; + /*EStateType*/int mStateType; + int mPSPIndex; +} + +// returned by AimLineAttack. +struct FTranslatedLineTarget +{ + Actor linetarget; + double angleFromSource; + double attackAngleFromSource; + bool unlinked; // found by a trace that went through an unlinked portal. + + native void TraceBleed(int damage, Actor missile); +} + +enum EAimFlags +{ + ALF_FORCENOSMART = 1, + ALF_CHECK3D = 2, + ALF_CHECKNONSHOOTABLE = 4, + ALF_CHECKCONVERSATION = 8, + ALF_NOFRIENDS = 16, + ALF_PORTALRESTRICT = 32, // only work through portals with a global offset (to be used for stuff that cannot remember the calculated FTranslatedLineTarget info) +} + +enum ELineAttackFlags +{ + LAF_ISMELEEATTACK = 1, + LAF_NORANDOMPUFFZ = 2, + LAF_NOIMPACTDECAL = 4, + LAF_NOINTERACT = 8, +} + +const MELEERANGE = 64; +const SAWRANGE = (64.+(1./65536.)); // use meleerange + 1 so the puff doesn't skip the flash (i.e. plays all states) +const MISSILERANGE = (32*64); +const PLAYERMISSILERANGE = 8192; // [RH] New MISSILERANGE for players + +enum ESightFlags +{ + SF_IGNOREVISIBILITY=1, + SF_SEEPASTSHOOTABLELINES=2, + SF_SEEPASTBLOCKEVERYTHING=4, + SF_IGNOREWATERBOUNDARY=8 +} + +enum EDmgFlags +{ + DMG_NO_ARMOR = 1, + DMG_INFLICTOR_IS_PUFF = 2, + DMG_THRUSTLESS = 4, + DMG_FORCED = 8, + DMG_NO_FACTOR = 16, + DMG_PLAYERATTACK = 32, + DMG_FOILINVUL = 64, + DMG_FOILBUDDHA = 128, + DMG_NO_PROTECT = 256, + DMG_USEANGLE = 512, +} + +enum EReplace +{ + NO_REPLACE = 0, + ALLOW_REPLACE = 1 +} + +// This translucency value produces the closest match to Heretic's TINTTAB. +// ~40% of the value of the overlaid image shows through. +const HR_SHADOW = (0x6800 / 65536.); +// Hexen's TINTTAB is the same as Heretic's, just reversed. +const HX_SHADOW = (0x9800 / 65536.); +const HX_ALTSHADOW = (0x6800 / 65536.); + +enum EMapThingFlags +{ + MTF_AMBUSH = 0x0008, // Thing is deaf + MTF_DORMANT = 0x0010, // Thing is dormant (use Thing_Activate) + + MTF_SINGLE = 0x0100, // Thing appears in single-player games + MTF_COOPERATIVE = 0x0200, // Thing appears in cooperative games + MTF_DEATHMATCH = 0x0400, // Thing appears in deathmatch games + + MTF_SHADOW = 0x0800, + MTF_ALTSHADOW = 0x1000, + MTF_FRIENDLY = 0x2000, + MTF_STANDSTILL = 0x4000, + MTF_STRIFESOMETHING = 0x8000, + + MTF_SECRET = 0x080000, // Secret pickup + MTF_NOINFIGHTING = 0x100000, +}; + +enum ESkillProperty +{ + SKILLP_FastMonsters, + SKILLP_Respawn, + SKILLP_RespawnLimit, + SKILLP_DisableCheats, + SKILLP_AutoUseHealth, + SKILLP_SpawnFilter, + SKILLP_EasyBossBrain, + SKILLP_ACSReturn, + SKILLP_NoPain, + SKILLP_EasyKey, + SKILLP_SlowMonsters, + SKILLP_Infight, +}; +enum EFSkillProperty // floating point properties +{ + SKILLP_AmmoFactor, + SKILLP_DropAmmoFactor, + SKILLP_ArmorFactor, + SKILLP_HealthFactor, + SKILLP_DamageFactor, + SKILLP_Aggressiveness, + SKILLP_MonsterHealth, + SKILLP_FriendlyHealth, +}; + +enum EWeaponPos +{ + WEAPONBOTTOM = 128, + WEAPONTOP = 32 +} + +enum ETranslationTable +{ + TRANSLATION_Invalid, + TRANSLATION_Players, + TRANSLATION_PlayersExtra, + TRANSLATION_Standard, + TRANSLATION_LevelScripted, + TRANSLATION_Decals, + TRANSLATION_PlayerCorpses, + TRANSLATION_Decorate, + TRANSLATION_Blood, + TRANSLATION_RainPillar, + TRANSLATION_Custom, +}; + +enum EFindFloorCeiling +{ + FFCF_ONLYSPAWNPOS = 1, + FFCF_SAMESECTOR = 2, + FFCF_ONLY3DFLOORS = 4, // includes 3D midtexes + FFCF_3DRESTRICT = 8, // ignore 3D midtexes and floors whose floorz are above thing's z + FFCF_NOPORTALS = 16, // ignore portals (considers them impassable.) + FFCF_NOFLOOR = 32, + FFCF_NOCEILING = 64, + FFCF_RESTRICTEDPORTAL = 128, // current values in the iterator's return are through a restricted portal type (i.e. some features are blocked.) + FFCF_NODROPOFF = 256, // Caller does not need a dropoff (saves some time when checking portals) +}; + +enum ETeleport +{ + TELF_DESTFOG = 1, + TELF_SOURCEFOG = 2, + TELF_KEEPORIENTATION = 4, + TELF_KEEPVELOCITY = 8, + TELF_KEEPHEIGHT = 16, + TELF_ROTATEBOOM = 32, + TELF_ROTATEBOOMINVERSE = 64, +}; + +enum EGameType +{ + GAME_Any = 0, + GAME_Doom = 1, + GAME_Heretic = 2, + GAME_Hexen = 4, + GAME_Strife = 8, + GAME_Chex = 16, //Chex is basically Doom, but we need to have a different set of actors. + + GAME_Raven = GAME_Heretic|GAME_Hexen, + GAME_DoomChex = GAME_Doom|GAME_Chex, + GAME_DoomStrifeChex = GAME_Doom|GAME_Strife|GAME_Chex +} + +enum PaletteFlashFlags +{ + PF_HEXENWEAPONS = 1, + PF_POISON = 2, + PF_ICE = 4, + PF_HAZARD = 8, +}; + +enum EGameAction +{ + ga_nothing, + ga_loadlevel, + ga_newgame, + ga_newgame2, + ga_recordgame, + ga_loadgame, + ga_loadgamehidecon, + ga_loadgameplaydemo, + ga_autoloadgame, + ga_savegame, + ga_autosave, + ga_playdemo, + ga_completed, + ga_slideshow, + ga_worlddone, + ga_screenshot, + ga_togglemap, + ga_fullconsole, +}; + +enum EPuffFlags +{ + PF_HITTHING = 1, + PF_MELEERANGE = 2, + PF_TEMPORARY = 4, + PF_HITTHINGBLEED = 8, + PF_NORANDOMZ = 16 +}; diff --git a/wadsrc/static/zscript/doom/arachnotron.txt b/wadsrc/static/zscript/doom/arachnotron.txt new file mode 100644 index 0000000000..c7e11ab146 --- /dev/null +++ b/wadsrc/static/zscript/doom/arachnotron.txt @@ -0,0 +1,114 @@ +//=========================================================================== +// +// Arachnotron +// +//=========================================================================== +class Arachnotron : Actor +{ + Default + { + Health 500; + Radius 64; + Height 64; + Mass 600; + Speed 12; + PainChance 128; + Monster; + +FLOORCLIP + +BOSSDEATH + SeeSound "baby/sight"; + PainSound "baby/pain"; + DeathSound "baby/death"; + ActiveSound "baby/active"; + Obituary "$OB_BABY"; + } + States + { + Spawn: + BSPI AB 10 A_Look; + Loop; + See: + BSPI A 20; + BSPI A 3 A_BabyMetal; + BSPI ABBCC 3 A_Chase; + BSPI D 3 A_BabyMetal; + BSPI DEEFF 3 A_Chase; + Goto See+1; + Missile: + BSPI A 20 BRIGHT A_FaceTarget; + BSPI G 4 BRIGHT A_BspiAttack; + BSPI H 4 BRIGHT; + BSPI H 1 BRIGHT A_SpidRefire; + Goto Missile+1; + Pain: + BSPI I 3; + BSPI I 3 A_Pain; + Goto See+1; + Death: + BSPI J 20 A_Scream; + BSPI K 7 A_NoBlocking; + BSPI LMNO 7; + BSPI P -1 A_BossDeath; + Stop; + Raise: + BSPI P 5; + BSPI ONMLKJ 5; + Goto See+1; + } +} + +//=========================================================================== +// +// Arachnotron plasma +// +//=========================================================================== +class ArachnotronPlasma : Actor +{ + Default + { + Radius 13; + Height 8; + Speed 25; + Damage 5; + Projectile; + +RANDOMIZE + RenderStyle "Add"; + Alpha 0.75; + SeeSound "baby/attack"; + DeathSound "baby/shotx"; + } + States + { + Spawn: + APLS AB 5 BRIGHT; + Loop; + Death: + APBX ABCDE 5 BRIGHT; + Stop; + } +} + +//=========================================================================== +// +// Code (must be attached to Actor) +// +//=========================================================================== + +extend class Actor +{ + void A_BspiAttack() + { + if (target) + { + A_FaceTarget(); + SpawnMissile(target, "ArachnotronPlasma"); + } + } + + void A_BabyMetal() + { + A_PlaySound("baby/walk", CHAN_BODY, 1, false, ATTN_IDLE); + A_Chase(); + } +} + diff --git a/wadsrc/static/zscript/doom/archvile.txt b/wadsrc/static/zscript/doom/archvile.txt new file mode 100644 index 0000000000..9faa804954 --- /dev/null +++ b/wadsrc/static/zscript/doom/archvile.txt @@ -0,0 +1,177 @@ +//=========================================================================== +// +// Arch Vile +// +//=========================================================================== + +class Archvile : Actor +{ + Default + { + Health 700; + Radius 20; + Height 56; + Mass 500; + Speed 15; + PainChance 10; + Monster; + MaxTargetRange 896; + +QUICKTORETALIATE + +FLOORCLIP + +NOTARGET + SeeSound "vile/sight"; + PainSound "vile/pain"; + DeathSound "vile/death"; + ActiveSound "vile/active"; + MeleeSound "vile/stop"; + Obituary "$OB_VILE"; + } + States + { + Spawn: + VILE AB 10 A_Look; + Loop; + See: + VILE AABBCCDDEEFF 2 A_VileChase; + Loop; + Missile: + VILE G 0 BRIGHT A_VileStart; + VILE G 10 BRIGHT A_FaceTarget; + VILE H 8 BRIGHT A_VileTarget; + VILE IJKLMN 8 BRIGHT A_FaceTarget; + VILE O 8 BRIGHT A_VileAttack; + VILE P 20 BRIGHT; + Goto See; + Heal: + VILE [\] 10 BRIGHT; + Goto See; + Pain: + VILE Q 5; + VILE Q 5 A_Pain; + Goto See; + Death: + VILE Q 7; + VILE R 7 A_Scream; + VILE S 7 A_NoBlocking; + VILE TUVWXY 7; + VILE Z -1; + Stop; + } +} + + +//=========================================================================== +// +// Arch Vile Fire +// +//=========================================================================== + +class ArchvileFire : Actor +{ + Default + { + +NOBLOCKMAP +NOGRAVITY + RenderStyle "Add"; + Alpha 1; + } + States + { + Spawn: + FIRE A 2 BRIGHT A_StartFire; + FIRE BAB 2 BRIGHT A_Fire; + FIRE C 2 BRIGHT A_FireCrackle; + FIRE BCBCDCDCDEDED 2 BRIGHT A_Fire; + FIRE E 2 BRIGHT A_FireCrackle; + FIRE FEFEFGHGHGH 2 BRIGHT A_Fire; + Stop; + } +} + + +//=========================================================================== +// +// Code (must be attached to Actor) +// +//=========================================================================== + +// A_VileAttack flags +//#define VAF_DMGTYPEAPPLYTODIRECT 1 + +extend class Actor +{ + + void A_VileStart() + { + A_PlaySound ("vile/start", CHAN_VOICE); + } + + // + // A_VileTarget + // Spawn the hellfire + // + void A_VileTarget(class fire = "ArchvileFire") + { + if (target) + { + A_FaceTarget (); + + Actor fog = Spawn (fire, target.Pos, ALLOW_REPLACE); + tracer = fog; + fog.target = self; + fog.tracer = self.target; + fog.A_Fire(0); + } + } + + void A_VileAttack(sound snd = "vile/stop", int initialdmg = 20, int blastdmg = 70, int blastradius = 70, double thrust = 1.0, name damagetype = "Fire", int flags = 0) + { + if (target) + { + A_FaceTarget(); + if (!CheckSight(target, 0)) return; + A_PlaySound(snd, CHAN_WEAPON); + int newdam = target.DamageMobj (self, self, initialdmg, (flags & VAF_DMGTYPEAPPLYTODIRECT)? damagetype : 'none'); + + TraceBleed (newdam > 0 ? newdam : initialdmg, target); + + Actor fire = tracer; + if (fire) + { + // move the fire between the vile and the player + fire.SetOrigin(target.Vec3Angle(-24., angle, 0), true); + fire.A_Explode(blastdmg, blastradius, XF_NOSPLASH, false, 0, 0, 0, "BulletPuff", damagetype); + } + if (!target.bDontThrust) + { + target.Vel.z = thrust * 1000 / max(1, target.Mass); + } + } + } + + void A_StartFire() + { + A_PlaySound ("vile/firestrt", CHAN_BODY); + A_Fire(); + } + + // + // A_Fire + // Keep fire in front of player unless out of sight + // + void A_Fire(double spawnheight = 0) + { + Actor dest = tracer; + if (!dest || !target) return; + + // don't move it if the vile lost sight + if (!target.CheckSight (dest, 0) ) return; + + SetOrigin(dest.Vec3Angle(24, dest.angle, height), true); + } + + void A_FireCrackle() + { + A_PlaySound ("vile/firecrkl", CHAN_BODY); + A_Fire(); + } +} diff --git a/wadsrc/static/zscript/doom/bossbrain.txt b/wadsrc/static/zscript/doom/bossbrain.txt new file mode 100644 index 0000000000..f22e4dd2b0 --- /dev/null +++ b/wadsrc/static/zscript/doom/bossbrain.txt @@ -0,0 +1,417 @@ + +//=========================================================================== +// +// Boss Brain +// +//=========================================================================== + +class BossBrain : Actor +{ + Default + { + Health 250; + Mass 10000000; + PainChance 255; + +SOLID +SHOOTABLE + +NOICEDEATH + +OLDRADIUSDMG + PainSound "brain/pain"; + DeathSound "brain/death"; + } + States + { + Spawn: + BBRN A -1; + Stop; + Pain: + BBRN B 36 A_BrainPain; + Goto Spawn; + Death: + BBRN A 100 A_BrainScream; + BBRN AA 10; + BBRN A -1 A_BrainDie; + Stop; + } +} + + +//=========================================================================== +// +// Boss Eye +// +//=========================================================================== + +class BossEye : Actor +{ + Default + { + Height 32; + +NOBLOCKMAP + +NOSECTOR + } + States + { + Spawn: + SSWV A 10 A_Look; + Loop; + See: + SSWV A 181 A_BrainAwake; + SSWV A 150 A_BrainSpit; + Wait; + } +} + +//=========================================================================== +// +// Boss Target +// +//=========================================================================== + +class BossTarget : SpecialSpot +{ + Default + { + Height 32; + +NOBLOCKMAP; + +NOSECTOR; + } +} + +//=========================================================================== +// +// Spawn shot +// +//=========================================================================== + +class SpawnShot : Actor +{ + Default + { + Radius 6; + Height 32; + Speed 10; + Damage 3; + Projectile; + +NOCLIP + -ACTIVATEPCROSS + +RANDOMIZE + SeeSound "brain/spit"; + DeathSound "brain/cubeboom"; + } + States + { + Spawn: + BOSF A 3 BRIGHT A_SpawnSound; + BOSF BCD 3 BRIGHT A_SpawnFly; + Loop; + } +} + +//=========================================================================== +// +// Spawn fire +// +//=========================================================================== + +class SpawnFire : Actor +{ + Default + { + Height 78; + +NOBLOCKMAP + +NOGRAVITY + RenderStyle "Add"; + } + States + { + Spawn: + FIRE ABCDEFGH 4 Bright A_Fire; + Stop; + } +} + + +//=========================================================================== +// +// Code (must be attached to Actor) +// +//=========================================================================== + +extend class Actor +{ + + void A_BrainAwake() + { + A_PlaySound("brain/sight", CHAN_VOICE, 1, false, ATTN_NONE); + } + + void A_BrainPain() + { + A_PlaySound("brain/pain", CHAN_VOICE, 1, false, ATTN_NONE); + } + + private static void BrainishExplosion(vector3 pos) + { + Actor boom = Actor.Spawn("Rocket", pos, NO_REPLACE); + if (boom) + { + boom.DeathSound = "misc/brainexplode"; + boom.Vel.z = random[BrainScream](0, 255)/128.; + + boom.SetStateLabel ("Brainexplode"); + boom.bRocketTrail = false; + boom.SetDamage(0); // disables collision detection which is not wanted here + boom.tics -= random[BrainScream](0, 7); + if (boom.tics < 1) boom.tics = 1; + } + } + + void A_BrainScream() + { + 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(Vec2OffsetZ(x, -320, (1 / 512.) + random[BrainExplode](0, 255) * 2)); + } + A_PlaySound("brain/death", CHAN_VOICE, 1, false, ATTN_NONE); + } + + void A_BrainExplode() + { + double x = random2[BrainExplode]() / 32.; + Vector3 pos = Vec2OffsetZ(x, 0, 1 / 512. + random[BrainExplode]() * 2); + BrainishExplosion(pos); + } + + void A_BrainDie() + { + // [RH] If noexit, then don't end the level. + if ((deathmatch || alwaysapplydmflags) && sv_noexit) + return; + + // New dmflag: Kill all boss spawned monsters before ending the level. + if (sv_killbossmonst) + { + int count; // Repeat until we have no more boss-spawned monsters. + ThinkerIterator it = ThinkerIterator.Create("Actor"); + do // (e.g. Pain Elementals can spawn more to kill upon death.) + { + Actor mo; + it.Reinit(); + count = 0; + while (mo = Actor(it.Next())) + { + if (mo.health > 0 && mo.bBossSpawned) + { + mo.DamageMobj(self, self, mo.health, "None", DMG_NO_ARMOR|DMG_FORCED|DMG_THRUSTLESS|DMG_NO_FACTOR); + count++; + } + } + } while (count != 0); + } + Exit_Normal(0); + } + + void A_BrainSpit(class spawntype = null) + { + SpotState spstate = SpotState.GetSpotState(); + Actor targ; + Actor spit; + bool isdefault = false; + + // shoot a cube at current target + targ = spstate.GetNextInList("BossTarget", G_SkillPropertyInt(SKILLP_EasyBossBrain)); + + if (targ) + { + if (spawntype == null) + { + spawntype = "SpawnShot"; + isdefault = true; + } + + // spawn brain missile + spit = SpawnMissile (targ, spawntype); + + if (spit) + { + // Boss cubes should move freely to their destination so it's + // probably best to disable all collision detection for them. + spit.bNoInteraction = spit.bNoClip; + + 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.xy == (0, 0)) + { + spit.special2 = 0; + } + else if (abs(spit.Vel.y) > abs(spit.Vel.x)) + { + spit.special2 = int((targ.pos.y - pos.y) / spit.Vel.y); + } + else + { + spit.special2 = int((targ.pos.x - pos.x) / spit.Vel.y); + } + // [GZ] Calculates when the projectile will have reached destination + spit.special2 += level.maptime; + spit.bBossCube = true; + } + + if (!isdefault) + { + A_PlaySound(self.AttackSound, CHAN_WEAPON, 1., false, ATTN_NONE); + } + else + { + // compatibility fallback + A_PlaySound("brain/spit", CHAN_WEAPON, 1., false, ATTN_NONE); + } + } + } + + private void SpawnFly(class spawntype, sound snd) + { + Actor newmobj; + Actor fog; + Actor eye = master; // The eye is the spawnshot's master, not the target! + Actor targ = target; // Unlike other projectiles, the target is the intended destination. + int r; + + // [GZ] Should be more viable than a countdown... + if (special2 != 0) + { + if (special2 > level.maptime) + return; // still flying + } + else + { + if (reactiontime == 0 || --reactiontime != 0) + return; // still flying + } + + if (spawntype) + { + fog = Spawn (spawntype, targ.pos, ALLOW_REPLACE); + if (fog) A_PlaySound(snd, CHAN_BODY); + } + + class SpawnName = null; + + DropItem di; // di will be our drop item list iterator + DropItem drop; // while drop stays as the reference point. + int n = 0; + + // First see if this cube has its own actor list + drop = 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 != '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 = random[pr_spawnfly](0, n); + while (n >= 0) + { + if (di.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 == null) + { + // Randomly select monster to spawn. + r = random[pr_spawnfly](0, 255); + + // 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"; + } + if (spawnname != null) + { + newmobj = Spawn (spawnname, 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.CurSector.SoundTarget; + + if (newmobj.SeeState != null && newmobj.LookForPlayers (true)) + { + newmobj.SetState (newmobj.SeeState); + } + if (!newmobj.bDestroyed) + { + // telefrag anything in this spot + newmobj.TeleportMove (newmobj.pos, true); + } + newmobj.bBossSpawned = true; + } + } + + // remove self (i.e., cube). + Destroy (); + } + + void A_SpawnFly(class spawntype = null) + { + sound snd; + if (spawntype != null) + { + snd = GetDefaultByType(spawntype).SeeSound; + } + else + { + spawntype = "SpawnFire"; + snd = "brain/spawn"; + } + SpawnFly(spawntype, snd); + } + + void A_SpawnSound() + { + // travelling cube sound + A_PlaySound("brain/cube", CHAN_BODY); + SpawnFly("SpawnFire", "brain/spawn"); + } +} diff --git a/wadsrc/static/zscript/doom/bruiser.txt b/wadsrc/static/zscript/doom/bruiser.txt new file mode 100644 index 0000000000..c1faa23c19 --- /dev/null +++ b/wadsrc/static/zscript/doom/bruiser.txt @@ -0,0 +1,167 @@ +//=========================================================================== +// +// Baron of Hell +// +//=========================================================================== +class BaronOfHell : Actor +{ + Default + { + Health 1000; + Radius 24; + Height 64; + Mass 1000; + Speed 8; + PainChance 50; + Monster; + +FLOORCLIP + +BOSSDEATH + SeeSound "baron/sight"; + PainSound "baron/pain"; + DeathSound "baron/death"; + ActiveSound "baron/active"; + Obituary "$OB_BARON"; + HitObituary "$OB_BARONHIT"; + } + States + { + Spawn: + BOSS AB 10 A_Look ; + Loop; + See: + BOSS AABBCCDD 3 A_Chase; + Loop; + Melee: + Missile: + BOSS EF 8 A_FaceTarget; + BOSS G 8 A_BruisAttack; + Goto See; + Pain: + BOSS H 2; + BOSS H 2 A_Pain; + Goto See; + Death: + BOSS I 8; + BOSS J 8 A_Scream; + BOSS K 8; + BOSS L 8 A_NoBlocking; + BOSS MN 8; + BOSS O -1 A_BossDeath; + Stop; + Raise: + BOSS O 8; + BOSS NMLKJI 8; + Goto See; + } +} + +//=========================================================================== +// +// Hell Knight +// +//=========================================================================== +class HellKnight : BaronOfHell +{ + Default + { + Health 500; + -BOSSDEATH; + SeeSound "knight/sight"; + ActiveSound "knight/active"; + PainSound "knight/pain"; + DeathSound "knight/death"; + HitObituary "$OB_KNIGHTHIT"; + Obituary "$OB_KNIGHT"; + } + States + { + Spawn: + BOS2 AB 10 A_Look; + Loop; + See: + BOS2 AABBCCDD 3 A_Chase; + Loop; + Melee: + Missile: + BOS2 EF 8 A_FaceTarget; + BOS2 G 8 A_BruisAttack; + Goto See; + Pain: + BOS2 H 2; + BOS2 H 2 A_Pain; + Goto See; + Death: + BOS2 I 8; + BOS2 J 8 A_Scream; + BOS2 K 8; + BOS2 L 8 A_NoBlocking; + BOS2 MN 8; + BOS2 O -1; + Stop; + Raise: + BOS2 O 8; + BOS2 NMLKJI 8; + Goto See; + } +} + +//=========================================================================== +// +// Baron slime ball +// +//=========================================================================== +class BaronBall : Actor +{ + Default + { + Radius 6; + Height 16; + Speed 15; + FastSpeed 20; + Damage 8; + Projectile ; + +RANDOMIZE + RenderStyle "Add"; + Alpha 1; + SeeSound "baron/attack"; + DeathSound "baron/shotx"; + Decal "BaronScorch"; + } + States + { + Spawn: + BAL7 AB 4 BRIGHT; + Loop; + Death: + BAL7 CDE 6 BRIGHT; + Stop; + } +} + +//=========================================================================== +// +// Code (must be attached to Actor) +// +//=========================================================================== + +extend class Actor +{ + void A_BruisAttack() + { + if (target) + { + if (CheckMeleeRange()) + { + int damage = random[pr_bruisattack](1, 8) * 10; + A_PlaySound ("baron/melee", CHAN_WEAPON); + int newdam = target.DamageMobj (self, self, damage, "Melee"); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + } + else + { + // launch a missile + SpawnMissile (target, "BaronBall"); + } + } + } +} diff --git a/wadsrc/static/zscript/doom/cacodemon.txt b/wadsrc/static/zscript/doom/cacodemon.txt new file mode 100644 index 0000000000..b21acacd24 --- /dev/null +++ b/wadsrc/static/zscript/doom/cacodemon.txt @@ -0,0 +1,117 @@ +//=========================================================================== +// +// Cacodemon +// +//=========================================================================== +class Cacodemon : Actor +{ + Default + { + Health 400; + Radius 31; + Height 56; + Mass 400; + Speed 8; + PainChance 128; + Monster; + +FLOAT +NOGRAVITY + SeeSound "caco/sight"; + PainSound "caco/pain"; + DeathSound "caco/death"; + ActiveSound "caco/active"; + Obituary "$OB_CACO"; + HitObituary "$OB_CACOHIT"; + } + States + { + Spawn: + HEAD A 10 A_Look; + Loop; + See: + HEAD A 3 A_Chase; + Loop; + Missile: + HEAD B 5 A_FaceTarget; + HEAD C 5 A_FaceTarget; + HEAD D 5 BRIGHT A_HeadAttack; + Goto See; + Pain: + HEAD E 3; + HEAD E 3 A_Pain; + HEAD F 6; + Goto See; + Death: + HEAD G 8; + HEAD H 8 A_Scream; + HEAD I 8; + HEAD J 8; + HEAD K 8 A_NoBlocking; + HEAD L -1 A_SetFloorClip; + Stop; + Raise: + HEAD L 8 A_UnSetFloorClip; + HEAD KJIHG 8; + Goto See; + } +} + +//=========================================================================== +// +// Cacodemon plasma ball +// +//=========================================================================== +class CacodemonBall : Actor +{ + Default + { + Radius 6; + Height 8; + Speed 10; + FastSpeed 20; + Damage 5; + Projectile; + +RANDOMIZE + RenderStyle "Add"; + Alpha 1; + SeeSound "caco/attack"; + DeathSound "caco/shotx"; + } + States + { + Spawn: + BAL2 AB 4 BRIGHT; + Loop; + Death: + BAL2 CDE 6 BRIGHT; + Stop; + } +} + + +//=========================================================================== +// +// Code (must be attached to Actor) +// +//=========================================================================== + +extend class Actor +{ + void A_HeadAttack() + { + if (target) + { + if (CheckMeleeRange()) + { + int damage = random[pr_headattack](1, 6) * 10; + A_PlaySound (AttackSound, CHAN_WEAPON); + int newdam = target.DamageMobj (self, self, damage, "Melee"); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + } + else + { + // launch a missile + SpawnMissile (target, "CacodemonBall"); + } + } + } +} diff --git a/wadsrc/static/zscript/doom/cyberdemon.txt b/wadsrc/static/zscript/doom/cyberdemon.txt new file mode 100644 index 0000000000..1a2890f9a5 --- /dev/null +++ b/wadsrc/static/zscript/doom/cyberdemon.txt @@ -0,0 +1,89 @@ + +//=========================================================================== +// +// Cyberdemon +// +//=========================================================================== +class Cyberdemon : Actor +{ + Default + { + Health 4000; + Radius 40; + Height 110; + Mass 1000; + Speed 16; + PainChance 20; + Monster; + MinMissileChance 160; + +BOSS + +MISSILEMORE + +FLOORCLIP + +NORADIUSDMG + +DONTMORPH + +BOSSDEATH + SeeSound "cyber/sight"; + PainSound "cyber/pain"; + DeathSound "cyber/death"; + ActiveSound "cyber/active"; + Obituary "$OB_CYBORG"; + } + States + { + Spawn: + CYBR AB 10 A_Look; + Loop; + See: + CYBR A 3 A_Hoof; + CYBR ABBCC 3 A_Chase; + CYBR D 3 A_Metal; + CYBR D 3 A_Chase; + Loop; + Missile: + CYBR E 6 A_FaceTarget; + CYBR F 12 A_CyberAttack; + CYBR E 12 A_FaceTarget; + CYBR F 12 A_CyberAttack; + CYBR E 12 A_FaceTarget; + CYBR F 12 A_CyberAttack; + Goto See; + Pain: + CYBR G 10 A_Pain; + Goto See; + Death: + CYBR H 10; + CYBR I 10 A_Scream; + CYBR JKL 10; + CYBR M 10 A_NoBlocking; + CYBR NO 10; + CYBR P 30; + CYBR P -1 A_BossDeath; + Stop; + } +} + + +//=========================================================================== +// +// Code (must be attached to Actor) +// +//=========================================================================== + +extend class Actor +{ + void A_CyberAttack() + { + if (target) + { + A_FaceTarget(); + SpawnMissile (target, "Rocket"); + } + } + + void A_Hoof() + { + A_PlaySound("cyber/hoof", CHAN_BODY, 1, false, ATTN_IDLE); + A_Chase(); + } + +} diff --git a/wadsrc/static/actors/doom/deadthings.txt b/wadsrc/static/zscript/doom/deadthings.txt similarity index 67% rename from wadsrc/static/actors/doom/deadthings.txt rename to wadsrc/static/zscript/doom/deadthings.txt index f90d35eefd..3a7e47610b 100644 --- a/wadsrc/static/actors/doom/deadthings.txt +++ b/wadsrc/static/zscript/doom/deadthings.txt @@ -1,30 +1,30 @@ // Gibbed marine ----------------------------------------------------------- -actor GibbedMarine +class GibbedMarine : Actor { States { Spawn: - PLAY W -1 - Stop + PLAY W -1; + Stop; } } // Gibbed marine (extra copy) ---------------------------------------------- -actor GibbedMarineExtra : GibbedMarine +class GibbedMarineExtra : GibbedMarine { } // Dead marine ------------------------------------------------------------- -actor DeadMarine +class DeadMarine : Actor { States { Spawn: - PLAY N -1 - Stop + PLAY N -1; + Stop; } } @@ -35,63 +35,78 @@ actor DeadMarine // Dead zombie man --------------------------------------------------------- -actor DeadZombieMan : ZombieMan +class DeadZombieMan : ZombieMan { - Skip_Super - DropItem None + Default + { + Skip_Super; + DropItem "None"; + } States { Spawn: - Goto Super::Death+4 + Goto Super::Death+4; } } // Dead shotgun guy -------------------------------------------------------- -actor DeadShotgunGuy : ShotgunGuy +class DeadShotgunGuy : ShotgunGuy { - Skip_Super - DropItem None + Default + { + Skip_Super; + DropItem "None"; + } States { Spawn: - Goto Super::Death+4 + Goto Super::Death+4; } } // Dead imp ---------------------------------------------------------------- -actor DeadDoomImp : DoomImp +class DeadDoomImp : DoomImp { - Skip_Super + Default + { + Skip_Super; + } States { Spawn: - Goto Super::Death+4 + Goto Super::Death+4; } } // Dead demon -------------------------------------------------------------- -actor DeadDemon : Demon +class DeadDemon : Demon { - Skip_Super + Default + { + Skip_Super; + } States { Spawn: - Goto Super::Death+5 + Goto Super::Death+5; } } // Dead cacodemon ---------------------------------------------------------- -actor DeadCacodemon : Cacodemon +class DeadCacodemon : Cacodemon { - Skip_Super + Default + { + Skip_Super; + } States { Spawn: - Goto Super::Death+5 + Goto Super::Death+5; } } @@ -103,12 +118,15 @@ actor DeadCacodemon : Cacodemon * a holdover from that.) */ -actor DeadLostSoul : LostSoul +class DeadLostSoul : LostSoul { - Skip_Super + Default + { + Skip_Super; + } States { Spawn: - Goto Super::Death+5 + Goto Super::Death+5; } } diff --git a/wadsrc/static/zscript/doom/demon.txt b/wadsrc/static/zscript/doom/demon.txt new file mode 100644 index 0000000000..d4cd9002cc --- /dev/null +++ b/wadsrc/static/zscript/doom/demon.txt @@ -0,0 +1,95 @@ +//=========================================================================== +// +// Pink Demon +// +//=========================================================================== +class Demon : Actor +{ + Default + { + Health 150; + PainChance 180; + Speed 10; + Radius 30; + Height 56; + Mass 400; + Monster; + +FLOORCLIP + SeeSound "demon/sight"; + AttackSound "demon/melee"; + PainSound "demon/pain"; + DeathSound "demon/death"; + ActiveSound "demon/active"; + Obituary "$OB_DEMONHIT"; + } + States + { + Spawn: + SARG AB 10 A_Look; + Loop; + See: + SARG AABBCCDD 2 Fast A_Chase; + Loop; + Melee: + SARG EF 8 Fast A_FaceTarget; + SARG G 8 Fast A_SargAttack; + Goto See; + Pain: + SARG H 2 Fast; + SARG H 2 Fast A_Pain; + Goto See; + Death: + SARG I 8; + SARG J 8 A_Scream; + SARG K 4; + SARG L 4 A_NoBlocking; + SARG M 4; + SARG N -1; + Stop; + Raise: + SARG N 5; + SARG MLKJI 5; + Goto See; + } +} + +//=========================================================================== +// +// Spectre +// +//=========================================================================== +class Spectre : Demon +{ + Default + { + +SHADOW + RenderStyle "OptFuzzy"; + Alpha 0.5; + SeeSound "spectre/sight"; + AttackSound "spectre/melee"; + PainSound "spectre/pain"; + DeathSound "spectre/death"; + ActiveSound "spectre/active"; + HitObituary "$OB_SPECTREHIT"; + } +} + + +//=========================================================================== +// +// Code (must be attached to Actor) +// +//=========================================================================== + +extend class Actor +{ + void A_SargAttack() + { + if (target && CheckMeleeRange()) + { + int damage = random[pr_sargattack](1, 10) * 4; + int newdam = target.DamageMobj (self, self, damage, "Melee"); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + } + } +} diff --git a/wadsrc/static/zscript/doom/doomammo.txt b/wadsrc/static/zscript/doom/doomammo.txt new file mode 100644 index 0000000000..394f13e94f --- /dev/null +++ b/wadsrc/static/zscript/doom/doomammo.txt @@ -0,0 +1,169 @@ +// Clip -------------------------------------------------------------------- + +class Clip : Ammo +{ + Default + { + Inventory.PickupMessage "$GOTCLIP"; + Inventory.Amount 10; + Inventory.MaxAmount 200; + Ammo.BackpackAmount 10; + Ammo.BackpackMaxAmount 400; + Inventory.Icon "CLIPA0"; + } + States + { + Spawn: + CLIP A -1; + Stop; + } +} + +// Clip box ---------------------------------------------------------------- + +class ClipBox : Clip +{ + Default + { + Inventory.PickupMessage "$GOTCLIPBOX"; + Inventory.Amount 50; + } + States + { + Spawn: + AMMO A -1; + Stop; + } +} + +// Rocket ------------------------------------------------------------------ + +class RocketAmmo : Ammo +{ + Default + { + Inventory.PickupMessage "$GOTROCKET"; + Inventory.Amount 1; + Inventory.MaxAmount 50; + Ammo.BackpackAmount 1; + Ammo.BackpackMaxAmount 100; + Inventory.Icon "ROCKA0"; + } + States + { + Spawn: + ROCK A -1; + Stop; + } +} + +// Rocket box -------------------------------------------------------------- + +class RocketBox : RocketAmmo +{ + Default + { + Inventory.PickupMessage "$GOTROCKBOX"; + Inventory.Amount 5; + } + States + { + Spawn: + BROK A -1; + Stop; + } +} + +// Cell -------------------------------------------------------------------- + +class Cell : Ammo +{ + Default + { + Inventory.PickupMessage "$GOTCELL"; + Inventory.Amount 20; + Inventory.MaxAmount 300; + Ammo.BackpackAmount 20; + Ammo.BackpackMaxAmount 600; + Inventory.Icon "CELLA0"; + } + States + { + Spawn: + CELL A -1; + Stop; + } +} + +// Cell pack --------------------------------------------------------------- + +class CellPack : Cell +{ + Default + { + Inventory.PickupMessage "$GOTCELLBOX"; + Inventory.Amount 100; + } + States + { + Spawn: + CELP A -1; + Stop; + } +} + +// Shells ------------------------------------------------------------------ + +class Shell : Ammo +{ + Default + { + Inventory.PickupMessage "$GOTSHELLS"; + Inventory.Amount 4; + Inventory.MaxAmount 50; + Ammo.BackpackAmount 4; + Ammo.BackpackMaxAmount 100; + Inventory.Icon "SHELA0"; + } + States + { + Spawn: + SHEL A -1; + Stop; + } +} + +// Shell box --------------------------------------------------------------- + +class ShellBox : Shell +{ + Default + { + Inventory.PickupMessage "$GOTSHELLBOX"; + Inventory.Amount 20; + } + States + { + Spawn: + SBOX A -1; + Stop; + } +} + +// Backpack --------------------------------------------------------------- + +class Backpack : BackpackItem +{ + Default + { + Height 26; + Inventory.PickupMessage "$GOTBACKPACK"; + } + States + { + Spawn: + BPAK A -1; + Stop; + } +} + diff --git a/wadsrc/static/zscript/doom/doomarmor.txt b/wadsrc/static/zscript/doom/doomarmor.txt new file mode 100644 index 0000000000..30ff9a1408 --- /dev/null +++ b/wadsrc/static/zscript/doom/doomarmor.txt @@ -0,0 +1,69 @@ + +// Armor bonus -------------------------------------------------------------- + +class ArmorBonus : BasicArmorBonus +{ + Default + { + Radius 20; + Height 16; + Inventory.Pickupmessage "$GOTARMBONUS"; + Inventory.Icon "BON2A0"; + Armor.Savepercent 33.335; + Armor.Saveamount 1; + Armor.Maxsaveamount 200; + +COUNTITEM + +INVENTORY.ALWAYSPICKUP + } + States + { + Spawn: + BON2 ABCDCB 6; + loop; + } +} + +// Green armor -------------------------------------------------------------- + +class GreenArmor : BasicArmorPickup +{ + Default + { + Radius 20; + Height 16; + Inventory.Pickupmessage "$GOTARMOR"; + Inventory.Icon "ARM1A0"; + Armor.SavePercent 33.335; + Armor.SaveAmount 100; + } + States + { + Spawn: + ARM1 A 6; + ARM1 B 7 bright; + loop; + } +} + +// Blue armor --------------------------------------------------------------- + +class BlueArmor : BasicArmorPickup +{ + Default + { + Radius 20; + Height 16; + Inventory.Pickupmessage "$GOTMEGA"; + Inventory.Icon "ARM2A0"; + Armor.Savepercent 50; + Armor.Saveamount 200; + } + States + { + Spawn: + ARM2 A 6; + ARM2 B 6 bright; + loop; + } +} + diff --git a/wadsrc/static/zscript/doom/doomartifacts.txt b/wadsrc/static/zscript/doom/doomartifacts.txt new file mode 100644 index 0000000000..ad5e304c66 --- /dev/null +++ b/wadsrc/static/zscript/doom/doomartifacts.txt @@ -0,0 +1,201 @@ +// Invulnerability Sphere --------------------------------------------------- + +class InvulnerabilitySphere : PowerupGiver +{ + Default + { + +COUNTITEM + +INVENTORY.AUTOACTIVATE + +INVENTORY.ALWAYSPICKUP + +INVENTORY.BIGPOWERUP + Inventory.MaxAmount 0; + Powerup.Type "PowerInvulnerable"; + Powerup.Color "InverseMap"; + Inventory.PickupMessage "$GOTINVUL"; + } + States + { + Spawn: + PINV ABCD 6 Bright; + Loop; + } +} + +// Soulsphere -------------------------------------------------------------- + +class Soulsphere : Health +{ + Default + { + +COUNTITEM; + +INVENTORY.AUTOACTIVATE; + +INVENTORY.ALWAYSPICKUP; + +INVENTORY.FANCYPICKUPSOUND; + Inventory.Amount 100; + Inventory.MaxAmount 200; + Inventory.PickupMessage "$GOTSUPER"; + Inventory.PickupSound "misc/p_pkup"; + } + States + { + Spawn: + SOUL ABCDCB 6 Bright; + Loop; + } +} + +// Mega sphere -------------------------------------------------------------- + +class MegasphereHealth : Health // for manipulation by Dehacked +{ + Default + { + Inventory.Amount 200; + Inventory.MaxAmount 200; + +INVENTORY.ALWAYSPICKUP + } +} + +// DeHackEd can only modify the blue armor's type, not the megasphere's. +class BlueArmorForMegasphere : BlueArmor +{ + Default + { + Armor.SavePercent 50; + Armor.SaveAmount 200; + } +} + +class Megasphere : CustomInventory +{ + Default + { + +COUNTITEM + +INVENTORY.ALWAYSPICKUP + Inventory.PickupMessage "$GOTMSPHERE"; + Inventory.PickupSound "misc/p_pkup"; + } + States + { + Spawn: + MEGA ABCD 6 BRIGHT; + Loop; + Pickup: + TNT1 A 0 A_GiveInventory("BlueArmorForMegasphere", 1); + TNT1 A 0 A_GiveInventory("MegasphereHealth", 1); + Stop; + } +} + +// Invisibility ------------------------------------------------------------- + +class BlurSphere : PowerupGiver +{ + Default + { + +COUNTITEM + +VISIBILITYPULSE + +INVENTORY.AUTOACTIVATE + +INVENTORY.ALWAYSPICKUP + +INVENTORY.BIGPOWERUP + Inventory.MaxAmount 0; + Powerup.Type "PowerInvisibility"; + RenderStyle "Translucent"; + Inventory.PickupMessage "$GOTINVIS"; + } + States + { + Spawn: + PINS ABCD 6 Bright; + Loop; + } +} + +// Radiation suit (aka iron feet) ------------------------------------------- + +class RadSuit : PowerupGiver +{ + Default + { + Height 46; + +INVENTORY.AUTOACTIVATE + +INVENTORY.ALWAYSPICKUP + Inventory.MaxAmount 0; + Inventory.PickupMessage "$GOTSUIT"; + Powerup.Type "PowerIronFeet"; + } + States + { + Spawn: + SUIT A -1 Bright; + Stop; + } +} + +// infrared ----------------------------------------------------------------- + +class Infrared : PowerupGiver +{ + Default + { + +COUNTITEM + +INVENTORY.AUTOACTIVATE + +INVENTORY.ALWAYSPICKUP + Inventory.MaxAmount 0; + Powerup.Type "PowerLightAmp"; + Inventory.PickupMessage "$GOTVISOR"; + } + States + { + Spawn: + PVIS A 6 Bright; + PVIS B 6; + Loop; + } +} + +// Allmap ------------------------------------------------------------------- + +class Allmap : MapRevealer +{ + Default + { + +COUNTITEM + +INVENTORY.FANCYPICKUPSOUND + +INVENTORY.ALWAYSPICKUP + Inventory.MaxAmount 0; + Inventory.PickupSound "misc/p_pkup"; + Inventory.PickupMessage "$GOTMAP"; + } + States + { + Spawn: + PMAP ABCDCB 6 Bright; + Loop; + } +} + +// Berserk ------------------------------------------------------------------ + +class Berserk : CustomInventory +{ + Default + { + +COUNTITEM + +INVENTORY.ALWAYSPICKUP + Inventory.PickupMessage "$GOTBERSERK"; + Inventory.PickupSound "misc/p_pkup"; + } + States + { + Spawn: + PSTR A -1; + Stop; + Pickup: + TNT1 A 0 A_GiveInventory("PowerStrength"); + TNT1 A 0 HealThing(100, 0); + TNT1 A 0 A_SelectWeapon("Fist"); + Stop; + } +} + diff --git a/wadsrc/static/zscript/doom/doomdecorations.txt b/wadsrc/static/zscript/doom/doomdecorations.txt new file mode 100644 index 0000000000..8eec812f6b --- /dev/null +++ b/wadsrc/static/zscript/doom/doomdecorations.txt @@ -0,0 +1,900 @@ + +// Tech lamp --------------------------------------------------------------- + +class TechLamp : Actor +{ + Default + { + Radius 16; + Height 80; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + TLMP ABCD 4 BRIGHT; + Loop; + } +} + +// Tech lamp 2 ------------------------------------------------------------- + +class TechLamp2 : Actor +{ + Default + { + Radius 16; + Height 60; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + TLP2 ABCD 4 BRIGHT; + Loop; + } +} + +// Column ------------------------------------------------------------------ + +class Column : Actor +{ + Default + { + Radius 16; + Height 48; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + COLU A -1 BRIGHT; + Stop; + } +} + +// Tall green column ------------------------------------------------------- + +class TallGreenColumn : Actor +{ + Default + { + Radius 16; + Height 52; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + COL1 A -1; + Stop; + } +} + +// Short green column ------------------------------------------------------ + +class ShortGreenColumn : Actor +{ + Default + { + Radius 16; + Height 40;; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + COL2 A -1; + Stop; + } +} + +// Tall red column --------------------------------------------------------- + +class TallRedColumn : Actor +{ + Default + { + Radius 16; + Height 52; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + COL3 A -1; + Stop; + } +} + +// Short red column -------------------------------------------------------- + +class ShortRedColumn : Actor +{ + Default + { + Radius 16; + Height 40; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + COL4 A -1; + Stop; + } +} + +// Skull column ------------------------------------------------------------ + +class SkullColumn : Actor +{ + Default + { + Radius 16; + Height 40; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + COL6 A -1; + Stop; + } +} + +// Heart column ------------------------------------------------------------ + +class HeartColumn : Actor +{ + Default + { + Radius 16; + Height 40; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + COL5 AB 14; + Loop; + } +} + +// Evil eye ---------------------------------------------------------------- + +class EvilEye : Actor +{ + Default + { + Radius 16; + Height 54; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + CEYE ABCB 6 BRIGHT; + Loop; + } +} + +// Floating skull ---------------------------------------------------------- + +class FloatingSkull : Actor +{ + Default + { + Radius 16; + Height 26; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + FSKU ABC 6 BRIGHT; + Loop; + } +} + +// Torch tree -------------------------------------------------------------- + +class TorchTree : Actor +{ + Default + { + Radius 16; + Height 56; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + TRE1 A -1; + Stop; + } +} + +// Blue torch -------------------------------------------------------------- + +class BlueTorch : Actor +{ + Default + { + Radius 16; + Height 68;; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + TBLU ABCD 4 BRIGHT; + Loop; + } +} + +// Green torch ------------------------------------------------------------- + +class GreenTorch : Actor +{ + Default + { + Radius 16; + Height 68; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + TGRN ABCD 4 BRIGHT; + Loop; + } +} + +// Red torch --------------------------------------------------------------- + +class RedTorch : Actor +{ + Default + { + Radius 16; + Height 68; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + TRED ABCD 4 BRIGHT; + Loop; + } +} + +// Short blue torch -------------------------------------------------------- + +class ShortBlueTorch : Actor +{ + Default + { + Radius 16; + Height 37; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + SMBT ABCD 4 BRIGHT; + Loop; + } +} + +// Short green torch ------------------------------------------------------- + +class ShortGreenTorch : Actor +{ + Default + { + Radius 16; + Height 37; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + SMGT ABCD 4 BRIGHT; + Loop; + } +} + +// Short red torch --------------------------------------------------------- + +class ShortRedTorch : Actor +{ + Default + { + Radius 16; + Height 37; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + SMRT ABCD 4 BRIGHT; + Loop; + } +} + +// Stalagtite -------------------------------------------------------------- + +class Stalagtite : Actor +{ + Default + { + Radius 16; + Height 40; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + SMIT A -1; + Stop; + } +} + +// Tech pillar ------------------------------------------------------------- + +class TechPillar : Actor +{ + Default + { + Radius 16; + Height 128; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + ELEC A -1; + Stop; + } +} + +// Candle stick ------------------------------------------------------------ + +class Candlestick : Actor +{ + Default + { + Radius 20; + Height 14; + ProjectilePassHeight -16; + } + States + { + Spawn: + CAND A -1 BRIGHT; + Stop; + } +} + +// Candelabra -------------------------------------------------------------- + +class Candelabra : Actor +{ + Default + { + Radius 16; + Height 60; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + CBRA A -1 BRIGHT; + Stop; + } +} + +// Bloody twitch ----------------------------------------------------------- + +class BloodyTwitch : Actor +{ + Default + { + Radius 16; + Height 68; + +SOLID + +NOGRAVITY + +SPAWNCEILING + } + States + { + Spawn: + GOR1 A 10; + GOR1 B 15; + GOR1 C 8; + GOR1 B 6; + Loop; + } +} + +// Meat 2 ------------------------------------------------------------------ + +class Meat2 : Actor +{ + Default + { + Radius 16; + Height 84; + +SOLID + +NOGRAVITY + +SPAWNCEILING + } + States + { + Spawn: + GOR2 A -1; + Stop; + } +} + +// Meat 3 ------------------------------------------------------------------ + +class Meat3 : Actor +{ + Default + { + Radius 16; + Height 84; + +SOLID + +NOGRAVITY + +SPAWNCEILING + } + States + { + Spawn: + GOR3 A -1; + Stop; + } +} + +// Meat 4 ------------------------------------------------------------------ + +class Meat4 : Actor +{ + Default + { + Radius 16; + Height 68; + +SOLID + +NOGRAVITY + +SPAWNCEILING + } + States + { + Spawn: + GOR4 A -1; + Stop; + } +} + +// Meat 5 ------------------------------------------------------------------ + +class Meat5 : Actor +{ + Default + { + Radius 16; + Height 52; + +SOLID + +NOGRAVITY + +SPAWNCEILING + } + States + { + Spawn: + GOR5 A -1; + Stop; + } +} + +// Nonsolid meat ----------------------------------------------------------- + +class NonsolidMeat2 : Meat2 +{ + Default + { + -SOLID + Radius 20; + } +} + +class NonsolidMeat3 : Meat3 +{ + Default + { + -SOLID + Radius 20; + } +} + +class NonsolidMeat4 : Meat4 +{ + Default + { + -SOLID + Radius 20; + } +} + +class NonsolidMeat5 : Meat5 +{ + Default + { + -SOLID + Radius 20; + } +} + +// Nonsolid bloody twitch -------------------------------------------------- + +class NonsolidTwitch : BloodyTwitch +{ + Default + { + -SOLID + Radius 20; + } +} + +// Head on a stick --------------------------------------------------------- + +class HeadOnAStick : Actor +{ + Default + { + Radius 16; + Height 56; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + POL4 A -1; + Stop; + } +} + +// Heads (plural!) on a stick ---------------------------------------------- + +class HeadsOnAStick : Actor +{ + Default + { + Radius 16; + Height 64;; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + POL2 A -1; + Stop; + } +} + +// Head candles ------------------------------------------------------------ + +class HeadCandles : Actor +{ + Default + { + Radius 16; + Height 42; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + POL3 AB 6 BRIGHT; + Loop; + } +} + +// Dead on a stick --------------------------------------------------------- + +class DeadStick : Actor +{ + Default + { + Radius 16; + Height 64; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + POL1 A -1; + Stop; + } +} + +// Still alive on a stick -------------------------------------------------- + +class LiveStick : Actor +{ + Default + { + Radius 16; + Height 64; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + POL6 A 6; + POL6 B 8; + Loop; + } +} + +// Big tree ---------------------------------------------------------------- + +class BigTree : Actor +{ + Default + { + Radius 32; + Height 108; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + TRE2 A -1; + Stop; + } +} + +// Burning barrel ---------------------------------------------------------- + +class BurningBarrel : Actor +{ + Default + { + Radius 16; + Height 32; + ProjectilePassHeight -16; + +SOLID + } + States + { + Spawn: + FCAN ABC 4 BRIGHT; + Loop; + } +} + +// Hanging with no guts ---------------------------------------------------- + +class HangNoGuts : Actor +{ + Default + { + Radius 16; + Height 88; + +SOLID + +NOGRAVITY + +SPAWNCEILING + } + States + { + Spawn: + HDB1 A -1; + Stop; + } +} + +// Hanging from bottom with no brain --------------------------------------- + +class HangBNoBrain : Actor +{ + Default + { + Radius 16; + Height 88; + +SOLID + +NOGRAVITY + +SPAWNCEILING + } + States + { + Spawn: + HDB2 A -1; + Stop; + } +} + +// Hanging from top, looking down ------------------------------------------ + +class HangTLookingDown : Actor +{ + Default + { + Radius 16; + Height 64; + +SOLID + +NOGRAVITY + +SPAWNCEILING + } + States + { + Spawn: + HDB3 A -1; + Stop; + } +} + +// Hanging from top, looking up -------------------------------------------- + +class HangTLookingUp : Actor +{ + Default + { + Radius 16; + Height 64; + +SOLID + +NOGRAVITY + +SPAWNCEILING + } + States + { + Spawn: + HDB5 A -1; + Stop; + } +} + +// Hanging from top, skully ------------------------------------------------ + +class HangTSkull : Actor +{ + Default + { + Radius 16; + Height 64; + +SOLID + +NOGRAVITY + +SPAWNCEILING + } + States + { + Spawn: + HDB4 A -1; + Stop; + } +} + +// Hanging from top without a brain ---------------------------------------- + +class HangTNoBrain : Actor +{ + Default + { + Radius 16; + Height 64; + +SOLID + +NOGRAVITY + +SPAWNCEILING + } + States + { + Spawn: + HDB6 A -1; + Stop; + } +} + +// Colon gibs -------------------------------------------------------------- + +class ColonGibs : Actor +{ + Default + { + Radius 20; + Height 4; + +NOBLOCKMAP + +MOVEWITHSECTOR + } + States + { + Spawn: + POB1 A -1; + Stop; + } +} + +// Small pool o' blood ----------------------------------------------------- + +class SmallBloodPool : Actor +{ + Default + { + Radius 20; + Height 1; + +NOBLOCKMAP + +MOVEWITHSECTOR + } + States + { + Spawn: + POB2 A -1; + Stop; + } +} + +// brain stem lying on the ground ------------------------------------------ + +class BrainStem : Actor +{ + Default + { + Radius 20; + Height 4; + +NOBLOCKMAP + +MOVEWITHSECTOR + } + States + { + Spawn: + BRS1 A -1; + Stop; + } +} + + +// Grey stalagmite (unused Doom sprite, definition taken from Skulltag ----- + +class Stalagmite : Actor +{ + Default + { + Radius 16; + Height 48; + +SOLID + } + States + { + Spawn: + SMT2 A -1; + Stop; + } +} + diff --git a/wadsrc/static/zscript/doom/doomhealth.txt b/wadsrc/static/zscript/doom/doomhealth.txt new file mode 100644 index 0000000000..c0ecf2dc01 --- /dev/null +++ b/wadsrc/static/zscript/doom/doomhealth.txt @@ -0,0 +1,54 @@ +// Health bonus ------------------------------------------------------------- + +class HealthBonus : Health +{ + Default + { + +COUNTITEM + +INVENTORY.ALWAYSPICKUP + Inventory.Amount 1; + Inventory.MaxAmount 200; + Inventory.PickupMessage "$GOTHTHBONUS"; + } + States + { + Spawn: + BON1 ABCDCB 6; + Loop; + } +} + +// Stimpack ----------------------------------------------------------------- + +class Stimpack : Health +{ + Default + { + Inventory.Amount 10; + Inventory.PickupMessage "$GOTSTIM"; + } + States + { + Spawn: + STIM A -1; + Stop; + } +} + +// Medikit ----------------------------------------------------------------- + +class Medikit : Health +{ + Default + { + Inventory.Amount 25; + Inventory.PickupMessage "$GOTMEDIKIT"; + Health.LowMessage 25, "$GOTMEDINEED"; + } + States + { + Spawn: + MEDI A -1; + Stop; + } +} diff --git a/wadsrc/static/zscript/doom/doomimp.txt b/wadsrc/static/zscript/doom/doomimp.txt new file mode 100644 index 0000000000..d2b93acdd7 --- /dev/null +++ b/wadsrc/static/zscript/doom/doomimp.txt @@ -0,0 +1,122 @@ +//=========================================================================== +// +// Imp +// +//=========================================================================== +class DoomImp : Actor +{ + Default + { + Health 60; + Radius 20; + Height 56; + Mass 100; + Speed 8; + PainChance 200; + Monster; + +FLOORCLIP + SeeSound "imp/sight"; + PainSound "imp/pain"; + DeathSound "imp/death"; + ActiveSound "imp/active"; + HitObituary "$OB_IMPHIT"; + Obituary "$OB_IMP"; + } + States + { + Spawn: + TROO AB 10 A_Look; + Loop; + See: + TROO AABBCCDD 3 A_Chase; + Loop; + Melee: + Missile: + TROO EF 8 A_FaceTarget; + TROO G 6 A_TroopAttack ; + Goto See; + Pain: + TROO H 2; + TROO H 2 A_Pain; + Goto See; + Death: + TROO I 8; + TROO J 8 A_Scream; + TROO K 6; + TROO L 6 A_NoBlocking; + TROO M -1; + Stop; + XDeath: + TROO N 5; + TROO O 5 A_XScream; + TROO P 5; + TROO Q 5 A_NoBlocking; + TROO RST 5; + TROO U -1; + Stop; + Raise: + TROO ML 8; + TROO KJI 6; + Goto See; + } +} + +//=========================================================================== +// +// Imp fireball +// +//=========================================================================== +class DoomImpBall : Actor +{ + Default + { + Radius 6; + Height 8; + Speed 10; + FastSpeed 20; + Damage 3; + Projectile; + +RANDOMIZE + RenderStyle "Add"; + Alpha 1; + SeeSound "imp/attack"; + DeathSound "imp/shotx"; + } + States + { + Spawn: + BAL1 AB 4 BRIGHT; + Loop; + Death: + BAL1 CDE 6 BRIGHT; + Stop; + } +} + +//=========================================================================== +// +// Code (must be attached to Actor) +// +//=========================================================================== + +extend class Actor +{ + void A_TroopAttack() + { + if (target) + { + if (CheckMeleeRange()) + { + int damage = random[pr_troopattack](1, 8) * 3; + A_PlaySound ("imp/melee", CHAN_WEAPON); + int newdam = target.DamageMobj (self, self, damage, "Melee"); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + } + else + { + // launch a missile + SpawnMissile (target, "DoomImpBall"); + } + } + } +} diff --git a/wadsrc/static/zscript/doom/doomkeys.txt b/wadsrc/static/zscript/doom/doomkeys.txt new file mode 100644 index 0000000000..9ae88dade6 --- /dev/null +++ b/wadsrc/static/zscript/doom/doomkeys.txt @@ -0,0 +1,119 @@ + +class DoomKey : Key +{ + Default + { + Radius 20; + Height 16; + +NOTDMATCH + } +} + +// Blue key card ------------------------------------------------------------ + +class BlueCard : DoomKey +{ + Default + { + Inventory.Pickupmessage "$GOTBLUECARD"; + Inventory.Icon "STKEYS0"; + } + States + { + Spawn: + BKEY A 10; + BKEY B 10 bright; + loop; + } +} + +// Yellow key card ---------------------------------------------------------- + +class YellowCard : DoomKey +{ + Default + { + Inventory.Pickupmessage "$GOTYELWCARD"; + Inventory.Icon "STKEYS1"; + } + States + { + Spawn: + YKEY A 10; + YKEY B 10 bright; + loop; + } +} + +// Red key card ------------------------------------------------------------- + +class RedCard : DoomKey +{ + Default + { + Inventory.Pickupmessage "$GOTREDCARD"; + Inventory.Icon "STKEYS2"; + } + States + { + Spawn: + RKEY A 10; + RKEY B 10 bright; + loop; + } +} + +// Blue skull key ----------------------------------------------------------- + +class BlueSkull : DoomKey +{ + Default + { + Inventory.Pickupmessage "$GOTBLUESKUL"; + Inventory.Icon "STKEYS3"; + } + States + { + Spawn: + BSKU A 10; + BSKU B 10 bright; + loop; + } +} + +// Yellow skull key --------------------------------------------------------- + +class YellowSkull : DoomKey +{ + Default + { + Inventory.Pickupmessage "$GOTYELWSKUL"; + Inventory.Icon "STKEYS4"; + } + States + { + Spawn: + YSKU A 10; + YSKU B 10 bright; + loop; + } +} + +// Red skull key ------------------------------------------------------------ + +class RedSkull : DoomKey +{ + Default + { + Inventory.Pickupmessage "$GOTREDSKUL"; + Inventory.Icon "STKEYS5"; + } + States + { + Spawn: + RSKU A 10; + RSKU B 10 bright; + loop; + } +} + diff --git a/wadsrc/static/zscript/doom/doommisc.txt b/wadsrc/static/zscript/doom/doommisc.txt new file mode 100644 index 0000000000..7d4c9dec4e --- /dev/null +++ b/wadsrc/static/zscript/doom/doommisc.txt @@ -0,0 +1,133 @@ +// The barrel of green goop ------------------------------------------------ + +class ExplosiveBarrel : Actor +{ + Default + { + Health 20; + Radius 10; + Height 42; + +SOLID + +SHOOTABLE + +NOBLOOD + +ACTIVATEMCROSS + +DONTGIB + +NOICEDEATH + +OLDRADIUSDMG + DeathSound "world/barrelx"; + Obituary "$OB_BARREL"; + } + States + { + Spawn: + BAR1 AB 6; + Loop; + Death: + BEXP A 5 BRIGHT; + BEXP B 5 BRIGHT A_Scream; + BEXP C 5 BRIGHT; + BEXP D 5 BRIGHT A_Explode; + BEXP E 10 BRIGHT; + TNT1 A 1050 BRIGHT A_BarrelDestroy; + TNT1 A 5 A_Respawn; + Wait; + } +} + +extend class Actor +{ + void A_BarrelDestroy() + { + if (sv_barrelrespawn) + { + Height = Default.Height; + bInvisible = true; + bSolid = false; + } + else + { + Destroy(); + } + } +} + +// Bullet puff ------------------------------------------------------------- + +class BulletPuff : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + +ALLOWPARTICLES + +RANDOMIZE + RenderStyle "Translucent"; + Alpha 0.5; + VSpeed 1; + Mass 5; + } + States + { + Spawn: + PUFF A 4 Bright; + PUFF B 4; + Melee: + PUFF CD 4; + Stop; + } +} + +// Container for an unused state ------------------------------------------- + +/* Doom defined the states S_STALAG, S_DEADTORSO, and S_DEADBOTTOM but never + * actually used them. For compatibility with DeHackEd patches, they still + * need to be kept around. This class serves that purpose. + */ + +class DoomUnusedStates : Actor +{ + States + { + Label1: + SMT2 A -1; + stop; + Label2: + PLAY N -1; + stop; + PLAY S -1; + stop; + TNT: // MBF compatibility + TNT1 A -1; + Loop; + } +} + +// MBF Beta emulation items + +class EvilSceptre : ScoreItem +{ + Default + { + Inventory.PickupMessage "$BETA_BONUS3"; + } + States + { + Spawn: + BON3 A 6; + Loop; + } +} + +class UnholyBible : ScoreItem +{ + Default + { + Inventory.PickupMessage "$BETA_BONUS4"; + } + States + { + Spawn: + BON4 A 6; + Loop; + } +} diff --git a/wadsrc/static/zscript/doom/doomplayer.txt b/wadsrc/static/zscript/doom/doomplayer.txt new file mode 100644 index 0000000000..6ec0d5f903 --- /dev/null +++ b/wadsrc/static/zscript/doom/doomplayer.txt @@ -0,0 +1,93 @@ +//=========================================================================== +// +// Player +// +//=========================================================================== +class DoomPlayer : PlayerPawn +{ + Default + { + Speed 1; + Health 100; + Radius 16; + Height 56; + Mass 100; + PainChance 255; + Player.DisplayName "Marine"; + Player.CrouchSprite "PLYC"; + Player.StartItem "Pistol"; + Player.StartItem "Fist"; + Player.StartItem "Clip", 50; + Player.WeaponSlot 1, "Fist", "Chainsaw"; + Player.WeaponSlot 2, "Pistol"; + Player.WeaponSlot 3, "Shotgun", "SuperShotgun"; + Player.WeaponSlot 4, "Chaingun"; + Player.WeaponSlot 5, "RocketLauncher"; + Player.WeaponSlot 6, "PlasmaRifle"; + Player.WeaponSlot 7, "BFG9000"; + + Player.ColorRange 112, 127; + Player.Colorset 0, "Green", 0x70, 0x7F, 0x72; + Player.Colorset 1, "Gray", 0x60, 0x6F, 0x62; + Player.Colorset 2, "Brown", 0x40, 0x4F, 0x42; + Player.Colorset 3, "Red", 0x20, 0x2F, 0x22; + // Doom Legacy additions + Player.Colorset 4, "Light Gray", 0x58, 0x67, 0x5A; + Player.Colorset 5, "Light Brown", 0x38, 0x47, 0x3A; + Player.Colorset 6, "Light Red", 0xB0, 0xBF, 0xB2; + Player.Colorset 7, "Light Blue", 0xC0, 0xCF, 0xC2; + } + + States + { + Spawn: + PLAY A -1; + Loop; + See: + PLAY ABCD 4; + Loop; + Missile: + PLAY E 12; + Goto Spawn; + Melee: + PLAY F 6 BRIGHT; + Goto Missile; + Pain: + PLAY G 4; + PLAY G 4 A_Pain; + Goto Spawn; + Death: + PLAY H 0 A_PlayerSkinCheck("AltSkinDeath"); + Death1: + PLAY H 10; + PLAY I 10 A_PlayerScream; + PLAY J 10 A_NoBlocking; + PLAY KLM 10; + PLAY N -1; + Stop; + XDeath: + PLAY O 0 A_PlayerSkinCheck("AltSkinXDeath"); + XDeath1: + PLAY O 5; + PLAY P 5 A_XScream; + PLAY Q 5 A_NoBlocking; + PLAY RSTUV 5; + PLAY W -1; + Stop; + AltSkinDeath: + PLAY H 6; + PLAY I 6 A_PlayerScream; + PLAY JK 6; + PLAY L 6 A_NoBlocking; + PLAY MNO 6; + PLAY P -1; + Stop; + AltSkinXDeath: + PLAY Q 5 A_PlayerScream; + PLAY R 0 A_NoBlocking; + PLAY R 5 A_SkullPop; + PLAY STUVWX 5; + PLAY Y -1; + Stop; + } +} diff --git a/wadsrc/static/zscript/doom/doomweapons.txt b/wadsrc/static/zscript/doom/doomweapons.txt new file mode 100644 index 0000000000..f3a40c22a2 --- /dev/null +++ b/wadsrc/static/zscript/doom/doomweapons.txt @@ -0,0 +1,64 @@ +// -------------------------------------------------------------------------- +// +// Doom weap base class +// +// -------------------------------------------------------------------------- + +class DoomWeapon : Weapon +{ + Default + { + Weapon.Kickback 100; + } +} + + + +extend class StateProvider +{ + + // + // [RH] A_FireRailgun + // [TP] This now takes a puff type to retain Skulltag's railgun's ability to pierce armor. + // + action void A_FireRailgun(class puffType = "BulletPuff", int offset_xy = 0) + { + if (player == null) + { + return; + } + + Weapon weap = player.ReadyWeapon; + if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + return; + + State flash = weap.FindState('Flash'); + if (flash != null) + { + player.SetSafeFlash(weap, flash, random[FireRail]()&1); + } + + } + + int damage = deathmatch ? 100 : 150; + A_RailAttack(damage, offset_xy, false, pufftype: puffType); // note that this function handles ammo depletion itself for Dehacked compatibility purposes. + } + + action void A_FireRailgunLeft() + { + A_FireRailgun(offset_xy: -10); + } + + action void A_FireRailgunRight() + { + A_FireRailgun(offset_xy: 10); + } + + action void A_RailWait() + { + // only here to satisfy old Dehacked patches. + } + +} diff --git a/wadsrc/static/zscript/doom/fatso.txt b/wadsrc/static/zscript/doom/fatso.txt new file mode 100644 index 0000000000..3831110c0e --- /dev/null +++ b/wadsrc/static/zscript/doom/fatso.txt @@ -0,0 +1,222 @@ +//=========================================================================== +// +// Mancubus +// +//=========================================================================== +class Fatso : Actor +{ + Default + { + Health 600; + Radius 48; + Height 64; + Mass 1000; + Speed 8; + PainChance 80; + Monster; + +FLOORCLIP + +BOSSDEATH + SeeSound "fatso/sight"; + PainSound "fatso/pain"; + DeathSound "fatso/death"; + ActiveSound "fatso/active"; + Obituary "$OB_FATSO"; + } + States + { + Spawn: + FATT AB 15 A_Look; + Loop; + See: + FATT AABBCCDDEEFF 4 A_Chase; + Loop; + Missile: + FATT G 20 A_FatRaise; + FATT H 10 BRIGHT A_FatAttack1; + FATT IG 5 A_FaceTarget; + FATT H 10 BRIGHT A_FatAttack2; + FATT IG 5 A_FaceTarget; + FATT H 10 BRIGHT A_FatAttack3; + FATT IG 5 A_FaceTarget; + Goto See; + Pain: + FATT J 3; + FATT J 3 A_Pain; + Goto See; + Death: + FATT K 6; + FATT L 6 A_Scream; + FATT M 6 A_NoBlocking; + FATT NOPQRS 6; + FATT T -1 A_BossDeath; + Stop; + Raise: + FATT R 5; + FATT QPONMLK 5; + Goto See; + } +} + + + +//=========================================================================== +// +// Mancubus fireball +// +//=========================================================================== +class FatShot : Actor +{ + Default + { + Radius 6; + Height 8; + Speed 20; + Damage 8; + Projectile; + +RANDOMIZE + RenderStyle "Add"; + Alpha 1; + SeeSound "fatso/attack"; + DeathSound "fatso/shotx"; + } + States + { + Spawn: + MANF AB 4 BRIGHT; + Loop; + Death: + MISL B 8 BRIGHT; + MISL C 6 BRIGHT; + MISL D 4 BRIGHT; + Stop; + } +} + + +//=========================================================================== +// +// Code (must be attached to Actor) +// +//=========================================================================== + +extend class Actor +{ + const FATSPREAD = 90./8; + + + void A_FatRaise() + { + A_FaceTarget(); + A_PlaySound("fatso/raiseguns", CHAN_WEAPON); + } + + // + // Mancubus attack, + // firing three missiles in three different directions? + // Doesn't look like it. + // + + void A_FatAttack1(class spawntype = "FatShot") + { + if (target) + { + A_FaceTarget (); + // Change direction to ... + Angle += FATSPREAD; + SpawnMissile (target, spawntype); + Actor missile = SpawnMissile (target, spawntype); + if (missile) + { + missile.Angle += FATSPREAD; + missile.VelFromAngle(); + } + } + } + + void A_FatAttack2(class spawntype = "FatShot") + { + if (target) + { + A_FaceTarget (); + // Now here choose opposite deviation. + Angle -= FATSPREAD; + SpawnMissile (target, spawntype); + Actor missile = SpawnMissile (target, spawntype); + if (missile) + { + missile.Angle -= FATSPREAD; + missile.VelFromAngle(); + } + } + } + + void A_FatAttack3(class spawntype = "FatShot") + { + if (target) + { + A_FaceTarget (); + Actor missile = SpawnMissile (target, spawntype); + if (missile) + { + missile.Angle -= FATSPREAD/2; + missile.VelFromAngle(); + } + missile = SpawnMissile (target, spawntype); + if (missile) + { + missile.Angle += FATSPREAD/2; + missile.VelFromAngle(); + } + } + } + + // + // killough 9/98: a mushroom explosion effect, sorta :) + // Original idea: Linguica + // + + void A_Mushroom(class spawntype = "FatShot", int numspawns = 0, int flags = 0, double vrange = 4.0, double hrange = 0.5) + { + int i, j; + + if (numspawns == 0) + { + numspawns = GetMissileDamage(0, 1); + } + + A_Explode(128, 128, (flags & MSF_DontHurt) ? 0 : XF_HURTSOURCE); + + // Now launch mushroom cloud + Actor aimtarget = Spawn("Mapspot", pos, NO_REPLACE); // We need something to aim at. + Actor owner = (flags & MSF_DontHurt) ? target : self; + aimtarget.Height = Height; + + bool shootmode = ((flags & MSF_Classic) || // Flag explicitely set, or no flags and compat options + (flags == 0 && CurState.bDehacked && compat_mushroom)); + + for (i = -numspawns; i <= numspawns; i += 8) + { + for (j = -numspawns; j <= numspawns; j += 8) + { + Actor mo; + aimtarget.SetXYZ(pos + (i, j, (i, j).Length() * vrange)); // Aim up fairly high + if (shootmode) + { // Use old function for MBF compatibility + mo = OldSpawnMissile(aimtarget, spawntype, owner); + } + else // Use normal function + { + mo = SpawnMissile(aimtarget, spawntype, owner); + } + if (mo) + { // Slow it down a bit + mo.Vel *= hrange; + mo.bNoGravity = false; // Make debris fall under gravity + } + } + } + aimtarget.Destroy(); + } + +} + diff --git a/wadsrc/static/zscript/doom/keen.txt b/wadsrc/static/zscript/doom/keen.txt new file mode 100644 index 0000000000..6d596c717a --- /dev/null +++ b/wadsrc/static/zscript/doom/keen.txt @@ -0,0 +1,81 @@ +//=========================================================================== +// +// Commander Keen +// +//=========================================================================== +class CommanderKeen : Actor +{ + Default + { + Health 100; + Radius 16; + Height 72; + Mass 10000000; + PainChance 256; + +SOLID + +SPAWNCEILING + +NOGRAVITY + +SHOOTABLE + +COUNTKILL + +NOICEDEATH + +ISMONSTER + PainSound "keen/pain"; + DeathSound "keen/death"; + } + States + { + Spawn: + KEEN A -1; + Loop; + Death: + KEEN AB 6; + KEEN C 6 A_Scream; + KEEN DEFGH 6; + KEEN I 6; + KEEN J 6; + KEEN K 6 A_KeenDie; + KEEN L -1; + Stop; + Pain: + KEEN M 4; + KEEN M 8 A_Pain; + Goto Spawn; + } +} + + +//=========================================================================== +// +// Code (must be attached to Actor) +// +//=========================================================================== + +extend class Actor +{ + + // + // A_KeenDie + // DOOM II special, map 32. + // Uses special tag 666 by default. + // + + void A_KeenDie(int doortag = 666) + { + A_NoBlocking(false); + + // scan the remaining thinkers to see if all Keens are dead + ThinkerIterator it = ThinkerIterator.Create(GetClass()); + Actor mo; + while (mo = Actor(it.Next(true))) + { + if (mo.health > 0 && mo != self) + { + // other Keen not dead + return; + } + } + Door_Open(doortag, 16); + } +} + + diff --git a/wadsrc/static/zscript/doom/lostsoul.txt b/wadsrc/static/zscript/doom/lostsoul.txt new file mode 100644 index 0000000000..89cefc42a9 --- /dev/null +++ b/wadsrc/static/zscript/doom/lostsoul.txt @@ -0,0 +1,121 @@ +//=========================================================================== +// +// Lost Soul +// +//=========================================================================== +class LostSoul : Actor +{ + Default + { + Health 100; + Radius 16; + Height 56; + Mass 50; + Speed 8; + Damage 3; + PainChance 256; + Monster; + +FLOAT +NOGRAVITY +MISSILEMORE +DONTFALL +NOICEDEATH; + AttackSound "skull/melee"; + PainSound "skull/pain"; + DeathSound "skull/death"; + ActiveSound "skull/active"; + RenderStyle "SoulTrans"; + Obituary "$OB_SKULL"; + } + States + { + Spawn: + SKUL AB 10 BRIGHT A_Look; + Loop; + See: + SKUL AB 6 BRIGHT A_Chase; + Loop; + Missile: + SKUL C 10 BRIGHT A_FaceTarget; + SKUL D 4 BRIGHT A_SkullAttack; + SKUL CD 4 BRIGHT; + Goto Missile+2; + Pain: + SKUL E 3 BRIGHT; + SKUL E 3 BRIGHT A_Pain; + Goto See; + Death: + SKUL F 6 BRIGHT; + SKUL G 6 BRIGHT A_Scream; + SKUL H 6 BRIGHT; + SKUL I 6 BRIGHT A_NoBlocking; + SKUL J 6; + SKUL K 6; + Stop; + } +} + +class BetaSkull : LostSoul +{ + States + { + Spawn: + SKUL A 10 A_Look; + Loop; + See: + SKUL BCDA 5 A_Chase; + Loop; + Missile: + SKUL E 4 A_FaceTarget; + SKUL F 5 A_BetaSkullAttack; + SKUL F 4; + Goto See; + Pain: + SKUL G 4; + SKUL H 2 A_Pain; + Goto See; + SKUL I 4; + Goto See; + Death: + SKUL JKLM 5; + SKUL N 5 A_Scream; + SKUL O 5; + SKUL P 5 A_Fall; + SKUL Q 5 A_Stop; + Wait; + } +} + +//=========================================================================== +// +// Code (must be attached to Actor) +// +//=========================================================================== + +extend class Actor +{ + const SKULLSPEED = 20; + + void A_SkullAttack(double skullspeed = SKULLSPEED) + { + if (target == null) return; + + if (skullspeed <= 0) skullspeed = SKULLSPEED; + + bSkullfly = true; + A_PlaySound(AttackSound, CHAN_VOICE); + A_FaceTarget(); + VelFromAngle(skullspeed); + Vel.Z = (target.pos.Z + target.Height/2 - pos.Z) / DistanceBySpeed(target, speed); + } + + void A_BetaSkullAttack() + { + if (target == null || target.GetSpecies() == self.GetSpecies()) return; + + A_PlaySound(AttackSound, CHAN_WEAPON); + A_FaceTarget(); + + int damage = GetMissileDamage(7,1); + target.DamageMobj(self, self, damage, 'None'); + } +} + + + diff --git a/wadsrc/static/zscript/doom/painelemental.txt b/wadsrc/static/zscript/doom/painelemental.txt new file mode 100644 index 0000000000..fe9e0590a0 --- /dev/null +++ b/wadsrc/static/zscript/doom/painelemental.txt @@ -0,0 +1,227 @@ +//=========================================================================== +// +// Pain Elemental +// +//=========================================================================== +class PainElemental : Actor +{ + Default + { + Health 400; + Radius 31; + Height 56; + Mass 400; + Speed 8; + PainChance 128; + Monster; + +FLOAT + +NOGRAVITY + SeeSound "pain/sight"; + PainSound "pain/pain"; + DeathSound "pain/death"; + ActiveSound "pain/active"; + } + States + { + Spawn: + PAIN A 10 A_Look; + Loop; + See: + PAIN AABBCC 3 A_Chase; + Loop; + Missile: + PAIN D 5 A_FaceTarget; + PAIN E 5 A_FaceTarget; + PAIN F 5 BRIGHT A_FaceTarget; + PAIN F 0 BRIGHT A_PainAttack; + Goto See; + Pain: + PAIN G 6; + PAIN G 6 A_Pain; + Goto See; + Death: + PAIN H 8 BRIGHT; + PAIN I 8 BRIGHT A_Scream; + PAIN JK 8 BRIGHT; + PAIN L 8 BRIGHT A_PainDie; + PAIN M 8 BRIGHT; + Stop; + Raise: + PAIN MLKJIH 8; + Goto See; + } +} + + +//=========================================================================== +// +// Code (must be attached to Actor) +// +//=========================================================================== + +extend class Actor +{ + // + // A_PainShootSkull + // Spawn a lost soul and launch it at the target + // + void A_PainShootSkull(Class spawntype, double angle, int flags = 0, int limit = -1) + { + // Don't spawn if we get massacred. + if (DamageType == 'Massacre') return; + + if (spawntype == null) spawntype = "LostSoul"; + + // [RH] check to make sure it's not too close to the ceiling + if (pos.z + height + 8 > ceilingz) + { + if (bFloat) + { + Vel.Z -= 2; + bInFloat = true; + bVFriction = true; + } + return; + } + + // [RH] make this optional + if (limit < 0 && compat_limitpain) + limit = 21; + + if (limit > 0) + { + // 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; + ThinkerIterator it = ThinkerIterator.Create(spawntype); + Thinker othink; + + while ( (othink = it.Next ()) ) + { + if (--count == 0) + return; + } + } + + // okay, there's room for another one + double otherradius = GetDefaultByType(spawntype).radius; + double prestep = 4 + (radius + otherradius) * 1.5; + + Vector2 move = AngleToVector(angle, prestep); + Vector3 spawnpos = pos + (0,0,8); + Vector3 destpos = spawnpos + move; + + Actor other = Spawn(spawntype, spawnpos, ALLOW_REPLACE); + + // Now check if the spawn is legal. Unlike Boom's hopeless attempt at fixing it, let's do it the same way + // P_XYMovement solves the line skipping: Spawn the Lost Soul near the PE's center and then use multiple + // smaller steps to get it to its intended position. This will also result in proper clipping, but + // it will avoid all the problems of the Boom method, which checked too many lines that weren't even touched + // and despite some adjustments never worked with portals. + + if (other != null) + { + double maxmove = other.radius - 1; + + if (maxmove <= 0) maxmove = 16; + + double xspeed = abs(move.X); + double yspeed = abs(move.Y); + + int steps = 1; + + if (xspeed > yspeed) + { + if (xspeed > maxmove) + { + steps = int(1 + xspeed / maxmove); + } + } + else + { + if (yspeed > maxmove) + { + steps = int(1 + yspeed / maxmove); + } + } + + Vector2 stepmove = move / steps; + bool savedsolid = bSolid; + bool savednoteleport = other.bNoTeleport; + + // make the PE nonsolid for the check and the LS non-teleporting so that P_TryMove doesn't do unwanted things. + bSolid = false; + other.bNoTeleport = true; + for (int i = 0; i < steps; i++) + { + Vector2 ptry = other.pos.xy + stepmove; + double oldangle = other.angle; + if (!other.TryMove(ptry, 0)) + { + // kill it immediately + other.ClearCounters(); + other.DamageMobj(self, self, TELEFRAG_DAMAGE, 'None'); + bSolid = savedsolid; + other.bNoTeleport = savednoteleport; + return; + } + + if (other.pos.xy != ptry) + { + // If the new position does not match the desired position, the player + // must have gone through a portal. + // For that we need to adjust the movement vector for the following steps. + double anglediff = deltaangle(oldangle, other.angle); + + if (anglediff != 0) + { + stepmove = RotateVector(stepmove, anglediff); + } + } + + } + bSolid = savedsolid; + other.bNoTeleport = savednoteleport; + + // [RH] Lost souls hate the same things as their pain elementals + other.CopyFriendliness (self, !(flags & PAF_NOTARGET)); + + if (!(flags & PAF_NOSKULLATTACK)) + { + other.A_SkullAttack(); + } + } + } + + + void A_PainAttack(class spawntype = "LostSoul", double addangle = 0, int flags = 0, int limit = -1) + { + if (target) + { + A_FaceTarget(); + A_PainShootSkull(spawntype, angle + addangle, flags, limit); + } + } + + void A_DualPainAttack(class spawntype = "LostSoul") + { + if (target) + { + A_FaceTarget(); + A_PainShootSkull(spawntype, angle + 45); + A_PainShootSkull(spawntype, angle - 45); + } + } + + void A_PainDie(class spawntype = "LostSoul") + { + if (target && IsFriend(target)) + { // And I thought you were my friend! + bFriendly = false; + } + A_NoBlocking(); + A_PainShootSkull(spawntype, angle + 90); + A_PainShootSkull(spawntype, angle + 180); + A_PainShootSkull(spawntype, angle + 270); + } +} diff --git a/wadsrc/static/zscript/doom/possessed.txt b/wadsrc/static/zscript/doom/possessed.txt new file mode 100644 index 0000000000..8b6612076b --- /dev/null +++ b/wadsrc/static/zscript/doom/possessed.txt @@ -0,0 +1,343 @@ + +//=========================================================================== +// +// Zombie man +// +//=========================================================================== +class ZombieMan : Actor +{ + Default + { + Health 20; + Radius 20; + Height 56; + Speed 8; + PainChance 200; + Monster; + +FLOORCLIP + SeeSound "grunt/sight"; + AttackSound "grunt/attack"; + PainSound "grunt/pain"; + DeathSound "grunt/death"; + ActiveSound "grunt/active"; + Obituary "$OB_ZOMBIE"; + DropItem "Clip"; + } + States + { + Spawn: + POSS AB 10 A_Look; + Loop; + See: + POSS AABBCCDD 4 A_Chase; + Loop; + Missile: + POSS E 10 A_FaceTarget; + POSS F 8 A_PosAttack; + POSS E 8; + Goto See; + Pain: + POSS G 3; + POSS G 3 A_Pain; + Goto See; + Death: + POSS H 5; + POSS I 5 A_Scream; + POSS J 5 A_NoBlocking; + POSS K 5; + POSS L -1; + Stop; + XDeath: + POSS M 5; + POSS N 5 A_XScream; + POSS O 5 A_NoBlocking; + POSS PQRST 5; + POSS U -1; + Stop; + Raise: + POSS K 5; + POSS JIH 5; + Goto See; + } +} + +//=========================================================================== +// +// Sergeant / Shotgun guy +// +//=========================================================================== +class ShotgunGuy : Actor +{ + Default + { + Health 30; + Radius 20; + Height 56; + Mass 100; + Speed 8; + PainChance 170; + Monster; + +FLOORCLIP + SeeSound "shotguy/sight"; + AttackSound "shotguy/attack"; + PainSound "shotguy/pain"; + DeathSound "shotguy/death"; + ActiveSound "shotguy/active"; + Obituary "$OB_SHOTGUY"; + DropItem "Shotgun"; + } + States + { + Spawn: + SPOS AB 10 A_Look; + Loop; + See: + SPOS AABBCCDD 3 A_Chase; + Loop; + Missile: + SPOS E 10 A_FaceTarget; + SPOS F 10 BRIGHT A_SposAttackUseAtkSound; + SPOS E 10; + Goto See; + Pain: + SPOS G 3; + SPOS G 3 A_Pain; + Goto See; + Death: + SPOS H 5; + SPOS I 5 A_Scream; + SPOS J 5 A_NoBlocking; + SPOS K 5; + SPOS L -1; + Stop; + XDeath: + SPOS M 5; + SPOS N 5 A_XScream; + SPOS O 5 A_NoBlocking; + SPOS PQRST 5; + SPOS U -1; + Stop; + Raise: + SPOS L 5; + SPOS KJIH 5; + Goto See; + } +} + +//=========================================================================== +// +// Chaingunner +// +//=========================================================================== +class ChaingunGuy : Actor +{ + Default + { + Health 70; + Radius 20; + Height 56; + Mass 100; + Speed 8; + PainChance 170; + Monster; + +FLOORCLIP + SeeSound "chainguy/sight"; + PainSound "chainguy/pain"; + DeathSound "chainguy/death"; + ActiveSound "chainguy/active"; + AttackSound "chainguy/attack"; + Obituary "$OB_CHAINGUY"; + Dropitem "Chaingun"; + } + States + { + Spawn: + CPOS AB 10 A_Look; + Loop; + See: + CPOS AABBCCDD 3 A_Chase; + Loop; + Missile: + CPOS E 10 A_FaceTarget; + CPOS FE 4 BRIGHT A_CPosAttack; + CPOS F 1 A_CPosRefire; + Goto Missile+1; + Pain: + CPOS G 3; + CPOS G 3 A_Pain; + Goto See; + Death: + CPOS H 5; + CPOS I 5 A_Scream; + CPOS J 5 A_NoBlocking; + CPOS KLM 5; + CPOS N -1; + Stop; + XDeath: + CPOS O 5; + CPOS P 5 A_XScream; + CPOS Q 5 A_NoBlocking; + CPOS RS 5; + CPOS T -1; + Stop; + Raise: + CPOS N 5; + CPOS MLKJIH 5; + Goto See; + } +} + +//=========================================================================== +// +// SS Nazi +// +//=========================================================================== +class WolfensteinSS : Actor +{ + Default + { + Health 50; + Radius 20; + Height 56; + Speed 8; + PainChance 170; + Monster; + +FLOORCLIP + SeeSound "wolfss/sight"; + PainSound "wolfss/pain"; + DeathSound "wolfss/death"; + ActiveSound "wolfss/active"; + AttackSound "wolfss/attack"; + Obituary "$OB_WOLFSS"; + Dropitem "Clip"; + } + States + { + Spawn: + SSWV AB 10 A_Look; + Loop; + See: + SSWV AABBCCDD 3 A_Chase; + Loop; + Missile: + SSWV E 10 A_FaceTarget; + SSWV F 10 A_FaceTarget; + SSWV G 4 BRIGHT A_CPosAttack; + SSWV F 6 A_FaceTarget; + SSWV G 4 BRIGHT A_CPosAttack; + SSWV F 1 A_CPosRefire; + Goto Missile+1; + Pain: + SSWV H 3; + SSWV H 3 A_Pain; + Goto See; + Death: + SSWV I 5; + SSWV J 5 A_Scream; + SSWV K 5 A_NoBlocking; + SSWV L 5; + SSWV M -1; + Stop; + XDeath: + SSWV N 5 ; + SSWV O 5 A_XScream; + SSWV P 5 A_NoBlocking; + SSWV QRSTU 5; + SSWV V -1; + Stop; + Raise: + SSWV M 5; + SSWV LKJI 5; + Goto See ; + } +} + +//=========================================================================== +// +// Code (must be attached to Actor) +// +//=========================================================================== + +extend class Actor +{ + void A_PosAttack() + { + if (target) + { + A_FaceTarget(); + double ang = angle; + double slope = AimLineAttack(ang, MISSILERANGE); + A_PlaySound("grunt/attack", CHAN_WEAPON); + ang += Random2[PosAttack]() * (22.5/256); + int damage = Random[PosAttack](1, 5) * 3; + LineAttack(ang, MISSILERANGE, slope, damage, "Hitscan", "Bulletpuff"); + } + } + + + private void A_SPosAttackInternal() + { + if (target) + { + A_FaceTarget(); + double bangle = angle; + double slope = AimLineAttack(bangle, MISSILERANGE); + + for (int i=0 ; i<3 ; i++) + { + double ang = bangle + Random2[SPosAttack]() * (22.5/256); + int damage = Random[SPosAttack](1, 5) * 3; + LineAttack(ang, MISSILERANGE, slope, damage, "Hitscan", "Bulletpuff"); + } + } + } + + void A_SPosAttackUseAtkSound() + { + if (target) + { + A_PlaySound(AttackSound, CHAN_WEAPON); + A_SPosAttackInternal(); + } + } + + // This version of the function, which uses a hard-coded sound, is meant for Dehacked only. + void A_SPosAttack() + { + if (target) + { + A_PlaySound("shotguy/attack", CHAN_WEAPON); + A_SPosAttackInternal(); + } + } + + void A_CPosAttack() + { + if (target) + { + if (bStealth) visdir = 1; + A_PlaySound(AttackSound, CHAN_WEAPON); + A_FaceTarget(); + double slope = AimLineAttack(angle, MISSILERANGE); + double ang = angle + Random2[SPosAttack]() * (22.5/256); + int damage = Random[CPosAttack](1, 5) * 3; + LineAttack(ang, MISSILERANGE, slope, damage, "Hitscan", "Bulletpuff"); + } + } + + void A_CPosRefire() + { + // keep firing unless target got out of sight + A_FaceTarget(); + if (Random[CPosRefire](0, 255) >= 40) + { + if (!target + || HitFriend() + || target.health <= 0 + || !CheckSight(target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES)) + { + SetState(SeeState); + } + } + } +} diff --git a/wadsrc/static/zscript/doom/revenant.txt b/wadsrc/static/zscript/doom/revenant.txt new file mode 100644 index 0000000000..2fa335a2df --- /dev/null +++ b/wadsrc/static/zscript/doom/revenant.txt @@ -0,0 +1,245 @@ +//=========================================================================== +// +// Revenant +// +//=========================================================================== +class Revenant : Actor +{ + Default + { + Health 300; + Radius 20; + Height 56; + Mass 500; + Speed 10; + PainChance 100; + Monster; + MeleeThreshold 196; + +MISSILEMORE + +FLOORCLIP + SeeSound "skeleton/sight"; + PainSound "skeleton/pain"; + DeathSound "skeleton/death"; + ActiveSound "skeleton/active"; + MeleeSound "skeleton/melee"; + HitObituary "$OB_UNDEADHIT"; + Obituary "$OB_UNDEAD"; + } + States + { + Spawn: + SKEL AB 10 A_Look; + Loop; + See: + SKEL AABBCCDDEEFF 2 A_Chase; + Loop; + Melee: + SKEL G 0 A_FaceTarget; + SKEL G 6 A_SkelWhoosh; + SKEL H 6 A_FaceTarget; + SKEL I 6 A_SkelFist; + Goto See; + Missile: + SKEL J 0 BRIGHT A_FaceTarget; + SKEL J 10 BRIGHT A_FaceTarget; + SKEL K 10 A_SkelMissile; + SKEL K 10 A_FaceTarget; + Goto See; + Pain: + SKEL L 5; + SKEL L 5 A_Pain; + Goto See; + Death: + SKEL LM 7; + SKEL N 7 A_Scream; + SKEL O 7 A_NoBlocking; + SKEL P 7; + SKEL Q -1; + Stop; + Raise: + SKEL Q 5; + SKEL PONML 5; + Goto See; + } +} + + +//=========================================================================== +// +// Revenant Tracer +// +//=========================================================================== +class RevenantTracer : Actor +{ + Default + { + Radius 11; + Height 8; + Speed 10; + Damage 10; + Projectile; + +SEEKERMISSILE + +RANDOMIZE + SeeSound "skeleton/attack"; + DeathSound "skeleton/tracex"; + RenderStyle "Add"; + } + States + { + Spawn: + FATB AB 2 BRIGHT A_Tracer; + Loop; + Death: + FBXP A 8 BRIGHT; + FBXP B 6 BRIGHT; + FBXP C 4 BRIGHT; + Stop; + } +} + + +//=========================================================================== +// +// Revenant Tracer Smoke +// +//=========================================================================== +class RevenantTracerSmoke : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + +NOTELEPORT + RenderStyle "Translucent"; + Alpha 0.5; + } + States + { + Spawn: + PUFF ABABC 4; + Stop; + } +} + +//=========================================================================== +// +// Code (must be attached to Actor) +// +//=========================================================================== + +extend class Actor +{ + void A_SkelMissile() + { + if (target == null) return; + A_FaceTarget(); + AddZ(16); + Actor missile = SpawnMissile(target, "RevenantTracer"); + AddZ(-16); + if (missile != null) + { + missile.SetOrigin(missile.Vec3Offset(missile.Vel.X, missile.Vel.Y, 0.), false); + missile.tracer = target; + } + } + + void A_SkelWhoosh() + { + if (target == null) return; + A_FaceTarget(); + A_PlaySound("skeleton/swing", CHAN_WEAPON); + } + + void A_SkelFist() + { + if (target == null) return; + A_FaceTarget(); + + if (CheckMeleeRange ()) + { + int damage = random[SkelFist](1, 10) * 6; + A_PlaySound("skeleton/melee", CHAN_WEAPON); + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + } + } + + void A_Tracer2(double traceang = 19.6875) + { + double dist; + double slope; + Actor dest; + + // adjust direction + dest = tracer; + + if (!dest || dest.health <= 0 || Speed == 0 || !CanSeek(dest)) + return; + + // change angle + double exact = AngleTo(dest); + double diff = deltaangle(angle, exact); + + if (diff < 0) + { + angle -= traceang; + if (deltaangle(angle, exact) > 0) + angle = exact; + } + else if (diff > 0) + { + angle += traceang; + if (deltaangle(angle, exact) < 0.) + angle = exact; + } + + VelFromAngle(); + + if (!bFloorHugger && !bCeilingHugger) + { + // change slope + dist = DistanceBySpeed(dest, Speed); + + if (dest.Height >= 56.) + { + slope = (dest.pos.z + 40. - pos.z) / dist; + } + else + { + slope = (dest.pos.z + Height*(2./3) - pos.z) / dist; + } + + if (slope < Vel.Z) + Vel.Z -= 1. / 8; + else + Vel.Z += 1. / 8; + } + } + + void A_Tracer() + { + // 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; + + // spawn a puff of smoke behind the rocket + SpawnPuff ("BulletPuff", pos, angle, angle, 3); + Actor smoke = Spawn ("RevenantTracerSmoke", Vec3Offset(-Vel.X, -Vel.Y, 0.), ALLOW_REPLACE); + + smoke.Vel.Z = 1.; + smoke.tics -= random[Tracer](0, 3); + if (smoke.tics < 1) + smoke.tics = 1; + + // The rest of this function was identical with Strife's version, except for the angle being used. + A_Tracer2(16.875); + } +} + diff --git a/wadsrc/static/zscript/doom/scriptedmarine.txt b/wadsrc/static/zscript/doom/scriptedmarine.txt new file mode 100644 index 0000000000..22766ac909 --- /dev/null +++ b/wadsrc/static/zscript/doom/scriptedmarine.txt @@ -0,0 +1,837 @@ + +// Scriptable marine ------------------------------------------------------- + +class ScriptedMarine : Actor +{ + const MARINE_PAIN_CHANCE = 160; + + enum EMarineWeapon + { + WEAPON_Dummy, + WEAPON_Fist, + WEAPON_BerserkFist, + WEAPON_Chainsaw, + WEAPON_Pistol, + WEAPON_Shotgun, + WEAPON_SuperShotgun, + WEAPON_Chaingun, + WEAPON_RocketLauncher, + WEAPON_PlasmaRifle, + WEAPON_Railgun, + WEAPON_BFG + }; + + struct WeaponStates + { + state melee; + state missile; + } + + int CurrentWeapon; + SpriteID SpriteOverride; + + Default + { + Health 100; + Radius 16; + Height 56; + Mass 100; + Speed 8; + Painchance MARINE_PAIN_CHANCE; + MONSTER; + -COUNTKILL + Translation 0; + Damage 100; + DeathSound "*death"; + PainSound "*pain50"; + } + + States + { + Spawn: + PLAY A 4 A_MarineLook; + PLAY A 4 A_MarineNoise; + Loop; + Idle: + PLAY A 4 A_MarineLook; + PLAY A 4 A_MarineNoise; + PLAY A 4 A_MarineLook; + PLAY B 4 A_MarineNoise; + PLAY B 4 A_MarineLook; + PLAY B 4 A_MarineNoise; + Loop; + See: + PLAY ABCD 4 A_MarineChase; + Loop; + + Melee.Fist: + PLAY E 4 A_FaceTarget; + PLAY E 4 A_M_Punch(1); + PLAY A 9; + PLAY A 0 A_M_Refire(1, "FistEnd"); + Loop; + FistEnd: + PLAY A 5 A_FaceTarget; + Goto See; + Melee.Berserk: + PLAY E 4 A_FaceTarget; + PLAY E 4 A_M_Punch(10); + PLAY A 9; + PLAY A 0 A_M_Refire(1, "FistEnd"); + Loop; + Melee.Chainsaw: + PLAY E 4 A_MarineNoise; + PLAY E 4 A_M_Saw; + PLAY E 0 A_M_SawRefire; + goto Melee.Chainsaw+1; + + Missile: + Missile.None: + PLAY E 12 A_FaceTarget; + Goto Idle; + PLAY F 6 BRIGHT; + Loop; + Missile.Pistol: + PLAY E 4 A_FaceTarget; + PLAY F 6 BRIGHT A_M_FirePistol(1); + PLAY A 4 A_FaceTarget; + PLAY A 0 A_M_Refire(0, "ShootEnd"); + Goto Fireloop.Pistol; + ShootEnd: + PLAY A 5; + Goto See; + Fireloop.Pistol: + PLAY F 6 BRIGHT A_M_FirePistol(0); + PLAY A 4 A_FaceTarget; + PLAY A 0 A_M_Refire(0, "ShootEnd"); + Goto Fireloop.Pistol; + Missile.Shotgun: + PLAY E 3 A_M_CheckAttack; + PLAY F 7 BRIGHT A_M_FireShotgun; + Goto See; + Missile.SSG: + PLAY E 3 A_M_CheckAttack; + PLAY F 7 BRIGHT A_M_FireShotgun2; + Goto See; + Missile.Chaingun: + PLAY E 4 A_FaceTarget; + PLAY FF 4 BRIGHT A_M_FireCGun(1); + PLAY FF 4 BRIGHT A_M_FireCGun(0); + PLAY A 0 A_M_Refire(0, "See"); + Goto Missile.Chaingun+3; + Missile.Rocket: + PLAY E 8; + PLAY F 6 BRIGHT A_M_FireMissile; + PLAY E 6; + PLAY A 0 A_M_Refire(0, "See"); + Loop; + Missile.Plasma: + PLAY E 2 A_FaceTarget; + PLAY E 0 A_FaceTarget; + PLAY F 3 BRIGHT A_M_FirePlasma; + PLAY A 0 A_M_Refire(0, "See"); + Goto Missile.Plasma+1; + Missile.Railgun: + PLAY E 4 A_M_CheckAttack; + PLAY F 6 BRIGHT A_M_FireRailgun; + Goto See; + Missile.BFG: + PLAY E 5 A_M_BFGSound; + PLAY EEEEE 5 A_FaceTarget; + PLAY F 6 BRIGHT A_M_FireBFG; + PLAY A 4 A_FaceTarget; + PLAY A 0 A_M_Refire(0, "See"); + Loop; + + SkipAttack: + PLAY A 1; + Goto See; + Pain: + PLAY G 4; + PLAY G 4 A_Pain; + Goto Idle; + Death: + PLAY H 10; + PLAY I 10 A_Scream; + PLAY J 10 A_NoBlocking; + PLAY KLM 10; + PLAY N -1; + Stop; + XDeath: + PLAY O 5; + PLAY P 5 A_XScream; + PLAY Q 5 A_NoBlocking; + PLAY RSTUV 5; + PLAY W -1; + Stop; + Raise: + PLAY MLKJIH 5; + Goto See; + } + + //============================================================================ + // + // + // + //============================================================================ + + private bool GetWeaponStates(int weap, out WeaponStates wstates) + { + static const statelabel MeleeNames[] = + { + "Melee.None", "Melee.Fist", "Melee.Berserk", "Melee.Chainsaw", "Melee.Pistol", "Melee.Shotgun", + "Melee.SSG", "Melee.Chaingun", "Melee.Rocket", "Melee.Plasma", "Melee.Railgun", "Melee.BFG" + }; + + static const statelabel MissileNames[] = + { + "Missile.None", "Missile.Fist", "Missile.Berserk", "Missile.Chainsaw", "Missile.Pistol", "Missile.Shotgun", + "Missile.SSG", "Missile.Chaingun", "Missile.Rocket", "Missile.Plasma", "Missile.Railgun", "Missile.BFG" + }; + + if (weap < WEAPON_Dummy || weap > WEAPON_BFG) weap = WEAPON_Dummy; + + wstates.melee = FindState(MeleeNames[weap], true); + wstates.missile = FindState(MissileNames[weap], true); + + return wstates.melee != null || wstates.missile != null; + } + + //============================================================================ + // + // + // + //============================================================================ + + override void BeginPlay () + { + Super.BeginPlay (); + + // Set the current weapon + for(int i = WEAPON_Dummy; i <= WEAPON_BFG; i++) + { + WeaponStates wstates; + if (GetWeaponStates(i, wstates)) + { + if (wstates.melee == MeleeState && wstates.missile == MissileState) + { + CurrentWeapon = i; + } + } + } + } + + //============================================================================ + // + // + // + //============================================================================ + + override void Tick () + { + Super.Tick (); + + // Override the standard sprite, if desired + if (SpriteOverride != 0 && sprite == SpawnState.sprite) + { + sprite = SpriteOverride; + } + + if (special1 != 0) + { + if (CurrentWeapon == WEAPON_SuperShotgun) + { // Play SSG reload sounds + int ticks = level.maptime - special1; + if (ticks < 47) + { + switch (ticks) + { + case 14: + A_PlaySound ("weapons/sshoto", CHAN_WEAPON); + break; + case 28: + A_PlaySound ("weapons/sshotl", CHAN_WEAPON); + break; + case 41: + A_PlaySound ("weapons/sshotc", CHAN_WEAPON); + break; + } + } + else + { + special1 = 0; + } + } + else + { // Wait for a long refire time + if (level.maptime >= special1) + { + special1 = 0; + } + else + { + bJustAttacked = true; + } + } + } + } + + //============================================================================ + // + // A_M_Refire + // + //============================================================================ + + void A_M_Refire (bool ignoremissile, statelabel jumpto) + { + if (target == null || target.health <= 0) + { + if (MissileState && random[SMarineRefire]() < 160) + { // Look for a new target most of the time + if (LookForPlayers (true) && CheckMissileRange ()) + { // Found somebody new and in range, so don't stop shooting + return; + } + } + SetStateLabel (jumpto); + return; + } + if (((ignoremissile || MissileState == null) && !CheckMeleeRange ()) || + !CheckSight (target) || random[SMarineRefire]() < 4) // Small chance of stopping even when target not dead + { + SetStateLabel (jumpto); + } + } + + //============================================================================ + // + // A_M_SawRefire + // + //============================================================================ + + void A_M_SawRefire () + { + if (target == null || target.health <= 0 || !CheckMeleeRange ()) + { + SetStateLabel ("See"); + } + } + + //============================================================================ + // + // A_MarineNoise + // + //============================================================================ + + void A_MarineNoise () + { + if (CurrentWeapon == WEAPON_Chainsaw) + { + A_PlaySound ("weapons/sawidle", CHAN_WEAPON); + } + } + + //============================================================================ + // + // A_MarineChase + // + //============================================================================ + + void A_MarineChase () + { + A_MarineNoise(); + A_Chase (); + } + + //============================================================================ + // + // A_MarineLook + // + //============================================================================ + + void A_MarineLook () + { + A_MarineNoise(); + A_Look(); + } + + //============================================================================ + // + // A_M_Punch (also used in the rocket attack.) + // + //============================================================================ + + void A_M_Punch(int damagemul) + { + FTranslatedLineTarget t; + + if (target == null) + return; + + int damage = (random[SMarinePunch](1, 10) << 1) * damagemul; + + A_FaceTarget (); + double ang = angle + random2[SMarinePunch]() * (5.625 / 256); + double pitch = AimLineAttack (ang, MELEERANGE); + LineAttack (ang, MELEERANGE, pitch, damage, 'Melee', "BulletPuff", true, t); + + // turn to face target + if (t.linetarget) + { + A_PlaySound ("*fist", CHAN_WEAPON); + angle = t.angleFromSource; + } + } + + //============================================================================ + // + // P_GunShot2 + // + //============================================================================ + + private void GunShot2 (bool accurate, double pitch, class pufftype) + { + int damage = 5 * random[SMarineGunshot](1,3); + double ang = angle; + + if (!accurate) + { + ang += Random2[SMarineGunshot]() * (5.625 / 256); + } + + LineAttack (ang, MISSILERANGE, pitch, damage, 'Hitscan', pufftype); + } + + //============================================================================ + // + // A_M_FirePistol + // + //============================================================================ + + void A_M_FirePistol (bool accurate) + { + if (target == null) + return; + + A_PlaySound ("weapons/pistol", CHAN_WEAPON); + A_FaceTarget (); + GunShot2 (accurate, AimLineAttack (angle, MISSILERANGE), "BulletPuff"); + } + + //============================================================================ + // + // A_M_FireShotgun + // + //============================================================================ + + void A_M_FireShotgun () + { + if (target == null) + return; + + A_PlaySound ("weapons/shotgf", CHAN_WEAPON); + A_FaceTarget (); + double pitch = AimLineAttack (angle, MISSILERANGE); + for (int i = 0; i < 7; ++i) + { + GunShot2 (false, pitch, "BulletPuff"); + } + special1 = level.maptime + 27; + } + + //============================================================================ + // + // A_M_CheckAttack + // + //============================================================================ + + void A_M_CheckAttack () + { + if (special1 != 0 || target == null) + { + SetStateLabel ("SkipAttack"); + } + else + { + A_FaceTarget (); + } + } + + //============================================================================ + // + // A_M_FireShotgun2 + // + //============================================================================ + + void A_M_FireShotgun2 () + { + if (target == null) + return; + + A_PlaySound ("weapons/sshotf", CHAN_WEAPON); + A_FaceTarget (); + double pitch = AimLineAttack (angle, MISSILERANGE); + for (int i = 0; i < 20; ++i) + { + int damage = 5*(random[SMarineFireSSG]()%3+1); + double ang = angle + Random2[SMarineFireSSG]() * (11.25 / 256); + + LineAttack (ang, MISSILERANGE, pitch + Random2[SMarineFireSSG]() * (7.097 / 256), damage, 'Hitscan', "BulletPuff"); + } + special1 = level.maptime; + } + + //============================================================================ + // + // A_M_FireCGun + // + //============================================================================ + + void A_M_FireCGun(bool accurate) + { + if (target == null) + return; + + A_PlaySound ("weapons/chngun", CHAN_WEAPON); + A_FaceTarget (); + GunShot2 (accurate, AimLineAttack (angle, MISSILERANGE), "BulletPuff"); + } + + //============================================================================ + // + // A_M_FireMissile + // + // Giving a marine a rocket launcher is probably a bad idea unless you pump + // up his health, because he's just as likely to kill himself as he is to + // kill anything else with it. + // + //============================================================================ + + void A_M_FireMissile () + { + if (target == null) + return; + + if (CheckMeleeRange ()) + { // If too close, punch it + A_M_Punch(1); + } + else + { + A_FaceTarget (); + SpawnMissile (target, "Rocket"); + } + } + + //============================================================================ + // + // A_M_FireRailgun + // + //============================================================================ + + void A_M_FireRailgun () + { + if (target == null) + return; + + A_MonsterRail(); + special1 = level.maptime + 50; + } + + //============================================================================ + // + // A_M_FirePlasma + // + //============================================================================ + + void A_M_FirePlasma () + { + if (target == null) + return; + + A_FaceTarget (); + SpawnMissile (target, "PlasmaBall"); + special1 = level.maptime + 20; + } + + //============================================================================ + // + // A_M_BFGsound + // + //============================================================================ + + void A_M_BFGsound () + { + if (target == null) + return; + + if (special1 != 0) + { + SetState (SeeState); + } + else + { + A_FaceTarget (); + A_PlaySound ("weapons/bfgf", CHAN_WEAPON); + // Don't interrupt the firing sequence + PainChance = 0; + } + } + + //============================================================================ + // + // A_M_FireBFG + // + //============================================================================ + + void A_M_FireBFG () + { + if (target == null) + return; + + A_FaceTarget (); + SpawnMissile (target, "BFGBall"); + special1 = level.maptime + 30; + PainChance = MARINE_PAIN_CHANCE; + } + + //--------------------------------------------------------------------------- + + final void SetWeapon (int type) + { + WeaponStates wstates; + if (GetWeaponStates(type, wstates)) + { + static const class classes[] = { + "ScriptedMarine", + "MarineFist", + "MarineBerserk", + "MarineChainsaw", + "MarinePistol", + "MarineShotgun", + "MarineSSG", + "MarineChaingun", + "MarineRocket", + "MarinePlasma", + "MarineRailgun", + "MarineBFG" + }; + + MeleeState = wstates.melee; + MissileState = wstates.missile; + DecalGenerator = GetDefaultByType(classes[type]).DecalGenerator; + } + } + + final void SetSprite (class source) + { + if (source == null) + { // A valid actor class wasn't passed, so use the standard sprite + SpriteOverride = sprite = SpawnState.sprite; + // Copy the standard scaling + Scale = Default.Scale; + } + else + { // Use the same sprite and scaling the passed class spawns with + readonly def = GetDefaultByType (source); + SpriteOverride = sprite = def.SpawnState.sprite; + Scale = def.Scale; + } + } +} + +extend class Actor +{ + //============================================================================ + // + // A_M_Saw (this is globally exported) + // + //============================================================================ + + void A_M_Saw(sound fullsound = "weapons/sawfull", sound hitsound = "weapons/sawhit", int damage = 2, class pufftype = "BulletPuff") + { + if (target == null) + return; + + if (pufftype == null) pufftype = "BulletPuff"; + if (damage == 0) damage = 2; + + A_FaceTarget (); + if (CheckMeleeRange ()) + { + FTranslatedLineTarget t; + + damage *= random[SMarineSaw](1, 10); + double ang = angle + Random2[SMarineSaw]() * (5.625 / 256); + + LineAttack (angle, SAWRANGE, AimLineAttack (angle, SAWRANGE), damage, 'Melee', pufftype, false, t); + + if (!t.linetarget) + { + A_PlaySound (fullsound, 1, CHAN_WEAPON); + return; + } + A_PlaySound (hitsound, CHAN_WEAPON); + + // turn to face target + ang = t.angleFromSource; + double anglediff = deltaangle(angle, ang); + + if (anglediff < 0.0) + { + if (anglediff < -4.5) + angle = ang + 90.0 / 21; + else + angle -= 4.5; + } + else + { + if (anglediff > 4.5) + angle = ang - 90.0 / 21; + else + angle += 4.5; + } + } + else + { + A_PlaySound (fullsound, 1, CHAN_WEAPON); + } + } +} + +//--------------------------------------------------------------------------- + +class MarineFist : ScriptedMarine +{ + States + { + Melee: + Goto Super::Melee.Fist; + Missile: + Stop; + } +} + + +//--------------------------------------------------------------------------- + +class MarineBerserk : MarineFist +{ + States + { + Melee: + Goto Super::Melee.Berserk; + Missile: + Stop; + } +} +//--------------------------------------------------------------------------- + +class MarineChainsaw : ScriptedMarine +{ + States + { + Melee: + Goto Super::Melee.Chainsaw; + Missile: + Stop; + } +} + + + +//--------------------------------------------------------------------------- + +class MarinePistol : ScriptedMarine +{ + States + { + Missile: + Goto Super::Missile.Pistol; + } + +} + +//--------------------------------------------------------------------------- + +class MarineShotgun : ScriptedMarine +{ + States + { + Missile: + Goto Super::Missile.Shotgun; + } + +} + + + +//--------------------------------------------------------------------------- + +class MarineSSG : ScriptedMarine +{ + States + { + Missile: + Goto Super::Missile.SSG; + } +} + +//--------------------------------------------------------------------------- + +class MarineChaingun : ScriptedMarine +{ + States + { + Missile: + Goto Super::Missile.Chaingun; + } +} + + +//--------------------------------------------------------------------------- + +class MarineRocket : MarineFist +{ + States + { + Missile: + Goto Super::Missile.Rocket; + } + +} + +//--------------------------------------------------------------------------- + +class MarinePlasma : ScriptedMarine +{ + States + { + Missile: + Goto Super::Missile.Plasma; + } + +} + +//--------------------------------------------------------------------------- + +class MarineRailgun : ScriptedMarine +{ + States + { + Missile: + Goto Super::Missile.Railgun; + } + +} + +//--------------------------------------------------------------------------- + +class MarineBFG : ScriptedMarine +{ + States + { + Missile: + Goto Super::Missile.BFG; + } +} diff --git a/wadsrc/static/zscript/doom/spidermaster.txt b/wadsrc/static/zscript/doom/spidermaster.txt new file mode 100644 index 0000000000..9a72a2bbe6 --- /dev/null +++ b/wadsrc/static/zscript/doom/spidermaster.txt @@ -0,0 +1,93 @@ +//=========================================================================== +// +// Spider boss +// +//=========================================================================== +class SpiderMastermind : Actor +{ + Default + { + Health 3000; + Radius 128; + Height 100; + Mass 1000; + Speed 12; + PainChance 40; + Monster; + MinMissileChance 160; + +BOSS + +MISSILEMORE + +FLOORCLIP + +NORADIUSDMG + +DONTMORPH + +BOSSDEATH + SeeSound "spider/sight"; + AttackSound "spider/attack"; + PainSound "spider/pain"; + DeathSound "spider/death"; + ActiveSound "spider/active"; + Obituary "$OB_SPIDER"; + } + States + { + Spawn: + SPID AB 10 A_Look; + Loop; + See: + SPID A 3 A_Metal; + SPID ABB 3 A_Chase; + SPID C 3 A_Metal; + SPID CDD 3 A_Chase; + SPID E 3 A_Metal; + SPID EFF 3 A_Chase; + Loop; + Missile: + SPID A 20 BRIGHT A_FaceTarget; + SPID G 4 BRIGHT A_SPosAttackUseAtkSound; + SPID H 4 BRIGHT A_SposAttackUseAtkSound; + SPID H 1 BRIGHT A_SpidRefire; + Goto Missile+1; + Pain: + SPID I 3; + SPID I 3 A_Pain; + Goto See; + Death: + SPID J 20 A_Scream; + SPID K 10 A_NoBlocking; + SPID LMNOPQR 10; + SPID S 30; + SPID S -1 A_BossDeath; + Stop; + } +} + +//=========================================================================== +// +// Code (must be attached to Actor) +// +//=========================================================================== + +extend class Actor +{ + void A_SpidRefire() + { + // keep firing unless target got out of sight + A_FaceTarget(); + if (Random[CPosRefire](0, 255) >= 10) + { + if (!target + || HitFriend() + || target.health <= 0 + || !CheckSight(target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES)) + { + SetState(SeeState); + } + } + } + + void A_Metal() + { + A_PlaySound("spider/walk", CHAN_BODY, 1, false, ATTN_IDLE); + A_Chase(); + } +} diff --git a/wadsrc/static/zscript/doom/stealthmonsters.txt b/wadsrc/static/zscript/doom/stealthmonsters.txt new file mode 100644 index 0000000000..785261fbba --- /dev/null +++ b/wadsrc/static/zscript/doom/stealthmonsters.txt @@ -0,0 +1,139 @@ + +class StealthArachnotron : Arachnotron +{ + Default + { + +STEALTH + RenderStyle "Translucent"; + Alpha 0; + Obituary "$OB_STEALTHBABY"; + } +} + +class StealthArchvile : Archvile +{ + Default + { + +STEALTH + RenderStyle "Translucent"; + Alpha 0; + Obituary "$OB_STEALTHVILE"; + } +} + +class StealthBaron : BaronOfHell +{ + Default + { + +STEALTH + RenderStyle "Translucent"; + Alpha 0; + Obituary "$OB_STEALTHBARON"; + HitObituary "$OB_STEALTHBARON"; + } +} + +class StealthCacodemon : Cacodemon +{ + Default + { + +STEALTH + RenderStyle "Translucent"; + Alpha 0; + Obituary "$OB_STEALTHCACO"; + HitObituary "$OB_STEALTHCACO"; + } +} + +class StealthChaingunGuy : ChaingunGuy +{ + Default + { + +STEALTH + RenderStyle "Translucent"; + Alpha 0; + Obituary "$OB_STEALTHCHAINGUY"; + } +} + +class StealthDemon : Demon +{ + Default + { + +STEALTH + RenderStyle "Translucent"; + Alpha 0; + Obituary "$OB_STEALTHDEMON"; + HitObituary "$OB_STEALTHDEMON"; + } +} + +class StealthHellKnight : HellKnight +{ + Default + { + +STEALTH + RenderStyle "Translucent"; + Alpha 0; + Obituary "$OB_STEALTHKNIGHT"; + HitObituary "$OB_STEALTHKNIGHT"; + } +} + +class StealthDoomImp : DoomImp +{ + Default + { + +STEALTH + RenderStyle "Translucent"; + Alpha 0; + Obituary "$OB_STEALTHIMP"; + HitObituary "$OB_STEALTHIMP"; + } +} + +class StealthFatso : Fatso +{ + Default + { + +STEALTH + RenderStyle "Translucent"; + Alpha 0; + Obituary "$OB_STEALTHFATSO"; + } +} + +class StealthRevenant : Revenant +{ + Default + { + +STEALTH + RenderStyle "Translucent"; + Alpha 0; + Obituary "$OB_STEALTHUNDEAD"; + HitObituary "$OB_STEALTHUNDEAD"; + } +} + +class StealthShotgunGuy : ShotgunGuy +{ + Default + { + +STEALTH + RenderStyle "Translucent"; + Alpha 0; + Obituary "$OB_STEALTHSHOTGUNGUY"; + } +} + +class StealthZombieMan : ZombieMan +{ + Default + { + +STEALTH + RenderStyle "Translucent"; + Alpha 0; + Obituary "$OB_STEALTHZOMBIE"; + } +} + diff --git a/wadsrc/static/zscript/doom/weaponbfg.txt b/wadsrc/static/zscript/doom/weaponbfg.txt new file mode 100644 index 0000000000..9bf0084b34 --- /dev/null +++ b/wadsrc/static/zscript/doom/weaponbfg.txt @@ -0,0 +1,259 @@ +// -------------------------------------------------------------------------- +// +// BFG 9000 +// +// -------------------------------------------------------------------------- + +class BFG9000 : DoomWeapon +{ + Default + { + Height 20; + Weapon.SelectionOrder 2800; + Weapon.AmmoUse 40; + Weapon.AmmoGive 40; + Weapon.AmmoType "Cell"; + +WEAPON.NOAUTOFIRE; + Inventory.PickupMessage "$GOTBFG9000"; + Tag "$TAG_BFG9000"; + } + States + { + Ready: + BFGG A 1 A_WeaponReady; + Loop; + Deselect: + BFGG A 1 A_Lower; + Loop; + Select: + BFGG A 1 A_Raise; + Loop; + Fire: + BFGG A 20 A_BFGsound; + BFGG B 10 A_GunFlash; + BFGG B 10 A_FireBFG; + BFGG B 20 A_ReFire; + Goto Ready; + Flash: + BFGF A 11 Bright A_Light1; + BFGF B 6 Bright A_Light2; + Goto LightDone; + Spawn: + BFUG A -1; + Stop; + OldFire: + BFGG A 10 A_BFGsound; + BFGG BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB 1 A_FireOldBFG; + BFGG B 0 A_Light0; + BFGG B 20 A_ReFire; + Goto Ready; + } +} + +//=========================================================================== +// +// Weapon code (must be attached to StateProvider) +// +//=========================================================================== + +extend class StateProvider +{ + action void A_BFGsound() + { + A_PlaySound("weapons/bfgf", CHAN_WEAPON); + } + + + // + // A_FireBFG + // + + action void A_FireBFG() + { + if (player == null) + { + return; + } + Weapon weap = player.ReadyWeapon; + if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, deh.BFGCells)) + return; + } + + SpawnPlayerMissile("BFGBall", angle, nofreeaim:sv_nobfgaim); + } + + + // + // 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. + + action void A_FireOldBFG() + { + bool doesautoaim = false; + + if (player == null) + { + return; + } + Weapon weap = player.ReadyWeapon; + + if (invoker != weap || stateinfo == null || stateinfo.mStateType != STATE_Psprite) weap = null; + if (weap != null) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + return; + + doesautoaim = weap.bNoAutoaim; + weap.bNoAutoaim = true; + } + player.extralight = 2; + + // Save values temporarily + double SavedPlayerAngle = angle; + double SavedPlayerPitch = pitch; + for (int i = 0; i < 2; i++) // Spawn two plasma balls in sequence + { + angle += ((random[OldBFG]() & 127) - 64) * (90./768); + pitch += ((random[OldBFG]() & 127) - 64) * (90./640); + SpawnPlayerMissile (i == 0? (class)("PlasmaBall1") : (class)("PlasmaBall2")); + // Restore saved values + angle = SavedPlayerAngle; + pitch = SavedPlayerPitch; + } + // Restore autoaim setting + if (weap != null) weap.bNoAutoaim = doesautoaim; + } +} + +class BFGBall : Actor +{ + Default + { + Radius 13; + Height 8; + Speed 25; + Damage 100; + Projectile; + +RANDOMIZE + RenderStyle "Add"; + Alpha 0.75; + DeathSound "weapons/bfgx"; + Obituary "$OB_MPBFG_BOOM"; + } + States + { + Spawn: + BFS1 AB 4 Bright; + Loop; + Death: + BFE1 AB 8 Bright; + BFE1 C 8 Bright A_BFGSpray; + BFE1 DEF 8 Bright; + Stop; + } +} + +class BFGExtra : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + RenderStyle "Add"; + Alpha 0.75; + DamageType "BFGSplash"; + } + States + { + Spawn: + BFE2 ABCD 8 Bright; + Stop; + } +} + + +//=========================================================================== +// +// Code (must be attached to Actor) +// +//=========================================================================== + +extend class Actor +{ + // + // A_BFGSpray + // Spawn a BFG explosion on every monster in view + // + void A_BFGSpray(class spraytype = "BFGExtra", int numrays = 40, int damagecnt = 15, double ang = 90, double distance = 16*64, double vrange = 32, int defdamage = 0, int flags = 0) + { + int damage; + FTranslatedLineTarget t; + + // validate parameters + if (spraytype == null) spraytype = "BFGExtra"; + if (numrays <= 0) numrays = 40; + if (damagecnt <= 0) damagecnt = 15; + if (ang == 0) ang = 90.; + if (distance <= 0) distance = 16 * 64; + if (vrange == 0) vrange = 32.; + + // [RH] Don't crash if no target + if (!target) return; + + // [XA] Set the originator of the rays to the projectile (self) if + // the new flag is set, else set it to the player (target) + Actor originator = (flags & BFGF_MISSILEORIGIN) ? self : target; + + // offset angles from its attack ang + for (int i = 0; i < numrays; i++) + { + double an = angle - ang / 2 + ang / numrays*i; + + originator.AimLineAttack(an, distance, t, vrange); + + if (t.linetarget != null) + { + Actor spray = Spawn(spraytype, t.linetarget.pos + (0, 0, t.linetarget.Height / 4), ALLOW_REPLACE); + + int dmgFlags = 0; + Name dmgType = 'BFGSplash'; + + if (spray != null) + { + if ((spray.bMThruSpecies && target.GetSpecies() == t.linetarget.GetSpecies()) || + (!(flags & BFGF_HURTSOURCE) && 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.bPuffGetsOwner) spray.target = target; + if (spray.bFoilInvul) dmgFlags |= DMG_FOILINVUL; + if (spray.bFoilBuddha) dmgFlags |= DMG_FOILBUDDHA; + dmgType = spray.DamageType; + } + + if (defdamage == 0) + { + damage = 0; + for (int j = 0; j < damagecnt; ++j) + damage += Random[BFGSpray](1, 8); + } + else + { + // if this is used, damagecnt will be ignored + damage = defdamage; + } + + int newdam = t.linetarget.DamageMobj(originator, target, damage, dmgType, dmgFlags|DMG_USEANGLE, t.angleFromSource); + t.TraceBleed(newdam > 0 ? newdam : damage, self); + } + } + } +} diff --git a/wadsrc/static/zscript/doom/weaponchaingun.txt b/wadsrc/static/zscript/doom/weaponchaingun.txt new file mode 100644 index 0000000000..3766b9b6e0 --- /dev/null +++ b/wadsrc/static/zscript/doom/weaponchaingun.txt @@ -0,0 +1,82 @@ +// -------------------------------------------------------------------------- +// +// Chaingun +// +// -------------------------------------------------------------------------- + +class Chaingun : DoomWeapon +{ + Default + { + Weapon.SelectionOrder 700; + Weapon.AmmoUse 1; + Weapon.AmmoGive 20; + Weapon.AmmoType "Clip"; + Inventory.PickupMessage "$GOTCHAINGUN"; + Obituary "$OB_MPCHAINGUN"; + Tag "$TAG_CHAINGUN"; + } + States + { + Ready: + CHGG A 1 A_WeaponReady; + Loop; + Deselect: + CHGG A 1 A_Lower; + Loop; + Select: + CHGG A 1 A_Raise; + Loop; + Fire: + CHGG AB 4 A_FireCGun; + CHGG B 0 A_ReFire; + Goto Ready; + Flash: + CHGF A 5 Bright A_Light1; + Goto LightDone; + CHGF B 5 Bright A_Light2; + Goto LightDone; + Spawn: + MGUN A -1; + Stop; + } +} + +//=========================================================================== +// +// Code (must be attached to StateProvider) +// +//=========================================================================== + +extend class StateProvider +{ + action void A_FireCGun() + { + if (player == null) + { + return; + } + + Weapon weap = player.ReadyWeapon; + if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + return; + + A_PlaySound ("weapons/chngun", CHAN_WEAPON); + + State flash = weap.FindState('Flash'); + if (flash != null) + { + // Removed most of the mess that was here in the C++ code because SetSafeFlash already does some thorough validation. + State atk = weap.FindState('Fire'); + State cur = player.GetPSprite(PSP_WEAPON).CurState; + int theflash = atk == cur? 0:1; + player.SetSafeFlash(weap, flash, theflash); + } + } + player.mo.PlayAttacking2 (); + + GunShot (!player.refire, "BulletPuff", BulletSlope ()); + } +} diff --git a/wadsrc/static/zscript/doom/weaponchainsaw.txt b/wadsrc/static/zscript/doom/weaponchainsaw.txt new file mode 100644 index 0000000000..88a8c87cdf --- /dev/null +++ b/wadsrc/static/zscript/doom/weaponchainsaw.txt @@ -0,0 +1,166 @@ +// -------------------------------------------------------------------------- +// +// Chainsaw +// +// -------------------------------------------------------------------------- + +class Chainsaw : Weapon +{ + Default + { + Weapon.Kickback 0; + Weapon.SelectionOrder 2200; + Weapon.UpSound "weapons/sawup"; + Weapon.ReadySound "weapons/sawidle"; + Inventory.PickupMessage "$GOTCHAINSAW"; + Obituary "$OB_MPCHAINSAW"; + Tag "$TAG_CHAINSAW"; + +WEAPON.MELEEWEAPON + } + States + { + Ready: + SAWG CD 4 A_WeaponReady; + Loop; + Deselect: + SAWG C 1 A_Lower; + Loop; + Select: + SAWG C 1 A_Raise; + Loop; + Fire: + SAWG AB 4 A_Saw; + SAWG B 0 A_ReFire; + Goto Ready; + Spawn: + CSAW A -1; + Stop; + } +} + + +extend class StateProvider +{ + action void A_Saw(sound fullsound = "weapons/sawfull", sound hitsound = "weapons/sawhit", int damage = 2, class pufftype = "BulletPuff", int flags = 0, double range = 0, double spread_xy = 2.8125, double spread_z = 0, double lifesteal = 0, int lifestealmax = 0, class armorbonustype = "ArmorBonus") + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + if (pufftype == null) + { + pufftype = 'BulletPuff'; + } + if (damage == 0) + { + damage = 2; + } + if (!(flags & SF_NORANDOM)) + { + damage *= random[Saw](1, 10); + } + if (range == 0) + { + range = SAWRANGE; + } + + double ang = angle + spread_xy * (Random2[Saw]() / 255.); + double slope = AimLineAttack (ang, range, t) + spread_z * (Random2[Saw]() / 255.); + + Weapon weap = player.ReadyWeapon; + if (weap != null && !(flags & SF_NOUSEAMMO) && !(!t.linetarget && (flags & SF_NOUSEAMMOMISS)) && !weap.bDehAmmo && + invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire)) + return; + } + + Actor puff; + int actualdamage; + [puff, actualdamage] = LineAttack (ang, range, slope, damage, 'Melee', pufftype, false, t); + + if (!t.linetarget) + { + if ((flags & SF_RANDOMLIGHTMISS) && (Random[Saw]() > 64)) + { + player.extralight = !player.extralight; + } + A_PlaySound (fullsound, CHAN_WEAPON); + return; + } + + if (flags & SF_RANDOMLIGHTHIT) + { + int randVal = Random[Saw](); + if (randVal < 64) + { + player.extralight = 0; + } + else if (randVal < 160) + { + player.extralight = 1; + } + else + { + player.extralight = 2; + } + } + + if (lifesteal && !t.linetarget.bDontDrain) + { + if (flags & SF_STEALARMOR) + { + if (armorbonustype == null) + { + armorbonustype = "ArmorBonus"; + } + if (armorbonustype != null) + { + BasicArmorBonus armorbonus = BasicArmorBonus(Spawn(armorbonustype)); + armorbonus.SaveAmount = int(armorbonus.SaveAmount * actualdamage * lifesteal); + armorbonus.MaxSaveAmount = lifestealmax <= 0 ? armorbonus.MaxSaveAmount : lifestealmax; + armorbonus.bDropped = true; + armorbonus.ClearCounters(); + + if (!armorbonus.CallTryPickup (self)) + { + armorbonus.Destroy (); + } + } + } + + else + { + GiveBody (int(actualdamage * lifesteal), lifestealmax); + } + } + + A_PlaySound (hitsound, CHAN_WEAPON); + + // turn to face target + if (!(flags & SF_NOTURN)) + { + double anglediff = deltaangle(angle, t.angleFromSource); + + if (anglediff < 0.0) + { + if (anglediff < -4.5) + angle = t.angleFromSource + 90.0 / 21; + else + angle -= 4.5; + } + else + { + if (anglediff > 4.5) + angle = t.angleFromSource - 90.0 / 21; + else + angle += 4.5; + } + } + if (!(flags & SF_NOPULLIN)) + bJustAttacked = true; + } +} diff --git a/wadsrc/static/zscript/doom/weaponfist.txt b/wadsrc/static/zscript/doom/weaponfist.txt new file mode 100644 index 0000000000..3c1cc992f5 --- /dev/null +++ b/wadsrc/static/zscript/doom/weaponfist.txt @@ -0,0 +1,80 @@ +// -------------------------------------------------------------------------- +// +// Fist +// +// -------------------------------------------------------------------------- + +class Fist : Weapon +{ + Default + { + Weapon.SelectionOrder 3700; + Weapon.Kickback 100; + Obituary "$OB_MPFIST"; + Tag "$TAG_FIST"; + +WEAPON.WIMPY_WEAPON + +WEAPON.MELEEWEAPON + } + States + { + Ready: + PUNG A 1 A_WeaponReady; + Loop; + Deselect: + PUNG A 1 A_Lower; + Loop; + Select: + PUNG A 1 A_Raise; + Loop; + Fire: + PUNG B 4; + PUNG C 4 A_Punch; + PUNG D 5; + PUNG C 4; + PUNG B 5 A_ReFire; + Goto Ready; + } +} + + +//=========================================================================== +// +// Code (must be attached to Actor) +// +//=========================================================================== + +extend class Actor +{ + action void A_Punch() + { + FTranslatedLineTarget t; + + if (player != null) + { + Weapon weap = player.ReadyWeapon; + if (weap != null && !weap.bDehAmmo && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire)) + return; + } + } + + int damage = random[Punch](1, 10) << 1; + + if (FindInventory("PowerStrength")) + damage *= 10; + + double ang = angle + Random2[Punch]() * (5.625 / 256); + double pitch = AimLineAttack (ang, MELEERANGE); + + LineAttack (ang, MELEERANGE, pitch, damage, 'Melee', "BulletPuff", LAF_ISMELEEATTACK, t); + + // turn to face target + if (t.linetarget) + { + A_PlaySound ("*fist", CHAN_WEAPON); + angle = t.angleFromSource; + } + } + +} \ No newline at end of file diff --git a/wadsrc/static/zscript/doom/weaponpistol.txt b/wadsrc/static/zscript/doom/weaponpistol.txt new file mode 100644 index 0000000000..45a1ebecdf --- /dev/null +++ b/wadsrc/static/zscript/doom/weaponpistol.txt @@ -0,0 +1,100 @@ +// -------------------------------------------------------------------------- +// +// Pistol +// +// -------------------------------------------------------------------------- + +class Pistol : DoomWeapon +{ + Default + { + Weapon.SelectionOrder 1900; + Weapon.AmmoUse 1; + Weapon.AmmoGive 20; + Weapon.AmmoType "Clip"; + Obituary "$OB_MPPISTOL"; + +WEAPON.WIMPY_WEAPON + Inventory.Pickupmessage "$PICKUP_PISTOL_DROPPED"; + Tag "$TAG_PISTOL"; + } + States + { + Ready: + PISG A 1 A_WeaponReady; + Loop; + Deselect: + PISG A 1 A_Lower; + Loop; + Select: + PISG A 1 A_Raise; + Loop; + Fire: + PISG A 4; + PISG B 6 A_FirePistol; + PISG C 4; + PISG B 5 A_ReFire; + Goto Ready; + Flash: + PISF A 7 Bright A_Light1; + Goto LightDone; + PISF A 7 Bright A_Light1; + Goto LightDone; + Spawn: + PIST A -1; + Stop; + } +} + +//=========================================================================== +// +// Code (must be attached to StateProvider) +// +//=========================================================================== + +extend class StateProvider +{ + //=========================================================================== + // This is also used by the shotgun and chaingun + //=========================================================================== + + protected action void GunShot(bool accurate, Class pufftype, double pitch) + { + int damage = 5 * random[GunShot](1, 3); + double ang = angle; + + if (!accurate) + { + ang += Random2[GunShot]() * (5.625 / 256); + } + + LineAttack(ang, PLAYERMISSILERANGE, pitch, damage, 'Hitscan', pufftype); + } + + //=========================================================================== + action void A_FirePistol() + { + bool accurate; + + if (player != null) + { + Weapon weap = player.ReadyWeapon; + if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + return; + + player.SetPsprite(PSP_FLASH, weap.FindState('Flash'), true); + } + player.mo.PlayAttacking2 (); + + accurate = !player.refire; + } + else + { + accurate = true; + } + + A_PlaySound ("weapons/pistol", CHAN_WEAPON); + GunShot (accurate, "BulletPuff", BulletSlope ()); + } +} \ No newline at end of file diff --git a/wadsrc/static/zscript/doom/weaponplasma.txt b/wadsrc/static/zscript/doom/weaponplasma.txt new file mode 100644 index 0000000000..945339a356 --- /dev/null +++ b/wadsrc/static/zscript/doom/weaponplasma.txt @@ -0,0 +1,148 @@ +// -------------------------------------------------------------------------- +// +// Plasma rifle +// +// -------------------------------------------------------------------------- + +class PlasmaRifle : DoomWeapon +{ + Default + { + Weapon.SelectionOrder 100; + Weapon.AmmoUse 1; + Weapon.AmmoGive 40; + Weapon.AmmoType "Cell"; + Inventory.PickupMessage "$GOTPLASMA"; + Tag "$TAG_PLASMARIFLE"; + } + States + { + Ready: + PLSG A 1 A_WeaponReady; + Loop; + Deselect: + PLSG A 1 A_Lower; + Loop; + Select: + PLSG A 1 A_Raise; + Loop; + Fire: + PLSG A 3 A_FirePlasma; + PLSG B 20 A_ReFire; + Goto Ready; + Flash: + PLSF A 4 Bright A_Light1; + Goto LightDone; + PLSF B 4 Bright A_Light1; + Goto LightDone; + Spawn: + PLAS A -1; + Stop; + } +} + +class PlasmaBall : Actor +{ + Default + { + Radius 13; + Height 8; + Speed 25; + Damage 5; + Projectile; + +RANDOMIZE + RenderStyle "Add"; + Alpha 0.75; + SeeSound "weapons/plasmaf"; + DeathSound "weapons/plasmax"; + Obituary "$OB_MPPLASMARIFLE"; + } + States + { + Spawn: + PLSS AB 6 Bright; + Loop; + Death: + PLSE ABCDE 4 Bright; + Stop; + } +} + +// -------------------------------------------------------------------------- +// +// BFG 2704 +// +// -------------------------------------------------------------------------- + +class PlasmaBall1 : PlasmaBall +{ + Default + { + Damage 4; + BounceType "Classic"; + BounceFactor 1.0; + Obituary "$OB_MPBFG_MBF"; + } + States + { + Spawn: + PLS1 AB 6 Bright; + Loop; + Death: + PLS1 CDEFG 4 Bright; + Stop; + } +} + +class PlasmaBall2 : PlasmaBall1 +{ + States + { + Spawn: + PLS2 AB 6 Bright; + Loop; + Death: + PLS2 CDE 4 Bright; + Stop; + } +} + + +//=========================================================================== +// +// Code (must be attached to StateProvider) +// +//=========================================================================== + +extend class StateProvider +{ + + //=========================================================================== + // + // A_FirePlasma + // + //=========================================================================== + + action void A_FirePlasma() + { + if (player == null) + { + return; + } + Weapon weap = player.ReadyWeapon; + if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + return; + + State flash = weap.FindState('Flash'); + if (flash != null) + { + player.SetSafeFlash(weap, flash, random[FirePlasma]()&1); + } + + } + + SpawnPlayerMissile ("PlasmaBall"); + } +} diff --git a/wadsrc/static/zscript/doom/weaponrlaunch.txt b/wadsrc/static/zscript/doom/weaponrlaunch.txt new file mode 100644 index 0000000000..906db38239 --- /dev/null +++ b/wadsrc/static/zscript/doom/weaponrlaunch.txt @@ -0,0 +1,189 @@ +// -------------------------------------------------------------------------- +// +// Rocket launcher +// +// -------------------------------------------------------------------------- + +class RocketLauncher : DoomWeapon +{ + Default + { + Weapon.SelectionOrder 2500; + Weapon.AmmoUse 1; + Weapon.AmmoGive 2; + Weapon.AmmoType "RocketAmmo"; + +WEAPON.NOAUTOFIRE + Inventory.PickupMessage "$GOTLAUNCHER"; + Tag "$TAG_ROCKETLAUNCHER"; + } + States + { + Ready: + MISG A 1 A_WeaponReady; + Loop; + Deselect: + MISG A 1 A_Lower; + Loop; + Select: + MISG A 1 A_Raise; + Loop; + Fire: + MISG B 8 A_GunFlash; + MISG B 12 A_FireMissile; + MISG B 0 A_ReFire; + Goto Ready; + Flash: + MISF A 3 Bright A_Light1; + MISF B 4 Bright; + MISF CD 4 Bright A_Light2; + Goto LightDone; + Spawn: + LAUN A -1; + Stop; + } +} + +class Rocket : Actor +{ + Default + { + Radius 11; + Height 8; + Speed 20; + Damage 20; + Projectile; + +RANDOMIZE + +DEHEXPLOSION + +ROCKETTRAIL + SeeSound "weapons/rocklf"; + DeathSound "weapons/rocklx"; + Obituary "$OB_MPROCKET"; + } + States + { + Spawn: + MISL A 1 Bright; + Loop; + Death: + MISL B 8 Bright A_Explode; + MISL C 6 Bright; + MISL D 4 Bright; + Stop; + BrainExplode: + MISL BC 10 Bright; + MISL D 10 A_BrainExplode; + Stop; + } +} + +// -------------------------------------------------------------------------- +// +// Grenade -- Taken and adapted from Skulltag, with MBF stuff added to it +// +// -------------------------------------------------------------------------- + +class Grenade : Actor +{ + Default + { + Radius 8; + Height 8; + Speed 25; + Damage 20; + Projectile; + -NOGRAVITY + +RANDOMIZE + +DEHEXPLOSION + +GRENADETRAIL + BounceType "Doom"; + Gravity 0.25; + SeeSound "weapons/grenlf"; + DeathSound "weapons/grenlx"; + BounceSound "weapons/grbnce"; + Obituary "$OB_GRENADE"; + DamageType "Grenade"; + } + States + { + Spawn: + SGRN A 1 Bright; + Loop; + Death: + MISL B 8 Bright A_Explode; + MISL C 6 Bright; + MISL D 4 Bright; + Stop; + Grenade: + MISL A 1000 A_Die; + Wait; + Detonate: + MISL B 4 A_Scream; + MISL C 6 A_Detonate; + MISL D 10; + Stop; + Mushroom: + MISL B 8 A_Mushroom; + Goto Death+1; + } +} + +//=========================================================================== +// +// Code (must be attached to StateProvider) +// +//=========================================================================== + +extend class StateProvider +{ + + //=========================================================================== + // + // A_FireMissile + // + //=========================================================================== + + action void A_FireMissile() + { + if (player == null) + { + return; + } + Weapon weap = player.ReadyWeapon; + if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + return; + } + + SpawnPlayerMissile ("Rocket"); + } + + //=========================================================================== + // + // A_FireSTGrenade: not exactly backported from ST, but should work the same + // + //=========================================================================== + + action void A_FireSTGrenade(class grenadetype = "Grenade") + { + if (grenadetype == null) + return; + + if (player == null) + { + return; + } + Weapon weap = player.ReadyWeapon; + if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + return; + } + + // Temporarily raise the pitch to send the grenadetype slightly upwards + double savedpitch = pitch; + pitch -= 6.328125; + SpawnPlayerMissile(grenadetype); + pitch = SavedPitch; + } +} \ No newline at end of file diff --git a/wadsrc/static/zscript/doom/weaponshotgun.txt b/wadsrc/static/zscript/doom/weaponshotgun.txt new file mode 100644 index 0000000000..6a08afc11d --- /dev/null +++ b/wadsrc/static/zscript/doom/weaponshotgun.txt @@ -0,0 +1,85 @@ +// -------------------------------------------------------------------------- +// +// Shotgun +// +// -------------------------------------------------------------------------- + +class Shotgun : DoomWeapon +{ + Default + { + Weapon.SelectionOrder 1300; + Weapon.AmmoUse 1; + Weapon.AmmoGive 8; + Weapon.AmmoType "Shell"; + Inventory.PickupMessage "$GOTSHOTGUN"; + Obituary "$OB_MPSHOTGUN"; + Tag "$TAG_SHOTGUN"; + } + States + { + Ready: + SHTG A 1 A_WeaponReady; + Loop; + Deselect: + SHTG A 1 A_Lower; + Loop; + Select: + SHTG A 1 A_Raise; + Loop; + Fire: + SHTG A 3; + SHTG A 7 A_FireShotgun; + SHTG BC 5; + SHTG D 4; + SHTG CB 5; + SHTG A 3; + SHTG A 7 A_ReFire; + Goto Ready; + Flash: + SHTF A 4 Bright A_Light1; + SHTF B 3 Bright A_Light2; + Goto LightDone; + Spawn: + SHOT A -1; + Stop; + } +} + +//=========================================================================== +// +// Code (must be attached to StateProvider) +// +//=========================================================================== + +extend class StateProvider +{ + + action void A_FireShotgun() + { + if (player == null) + { + return; + } + + A_PlaySound ("weapons/shotgf", CHAN_WEAPON); + Weapon weap = player.ReadyWeapon; + if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + return; + + player.SetPsprite(PSP_FLASH, weap.FindState('Flash'), true); + } + player.mo.PlayAttacking2 (); + + double pitch = BulletSlope (); + + for (int i = 0; i < 7; i++) + { + GunShot (false, "BulletPuff", pitch); + } + } + +} + diff --git a/wadsrc/static/zscript/doom/weaponssg.txt b/wadsrc/static/zscript/doom/weaponssg.txt new file mode 100644 index 0000000000..6c06fe6ec4 --- /dev/null +++ b/wadsrc/static/zscript/doom/weaponssg.txt @@ -0,0 +1,117 @@ +// -------------------------------------------------------------------------- +// +// Super Shotgun +// +// -------------------------------------------------------------------------- + +class SuperShotgun : DoomWeapon +{ + Default + { + Weapon.SelectionOrder 400; + Weapon.AmmoUse 2; + Weapon.AmmoGive 8; + Weapon.AmmoType "Shell"; + Inventory.PickupMessage "$GOTSHOTGUN2"; + Obituary "$OB_MPSSHOTGUN"; + Tag "$TAG_SUPERSHOTGUN"; + } + States + { + Ready: + SHT2 A 1 A_WeaponReady; + Loop; + Deselect: + SHT2 A 1 A_Lower; + Loop; + Select: + SHT2 A 1 A_Raise; + Loop; + Fire: + SHT2 A 3; + SHT2 A 7 A_FireShotgun2; + SHT2 B 7; + SHT2 C 7 A_CheckReload; + SHT2 D 7 A_OpenShotgun2; + SHT2 E 7; + SHT2 F 7 A_LoadShotgun2; + SHT2 G 6; + SHT2 H 6 A_CloseShotgun2; + SHT2 A 5 A_ReFire; + Goto Ready; + // unused states + SHT2 B 7; + SHT2 A 3; + Goto Deselect; + Flash: + SHT2 I 4 Bright A_Light1; + SHT2 J 3 Bright A_Light2; + Goto LightDone; + Spawn: + SGN2 A -1; + Stop; + } +} + + + +//=========================================================================== +// +// Code (must be attached to StateProvider) +// +//=========================================================================== + +extend class StateProvider +{ + action void A_FireShotgun2() + { + if (player == null) + { + return; + } + + A_PlaySound ("weapons/sshotf", CHAN_WEAPON); + Weapon weap = player.ReadyWeapon; + if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 2)) + return; + + player.SetPsprite(PSP_FLASH, weap.FindState('Flash'), true); + } + player.mo.PlayAttacking2 (); + + double pitch = BulletSlope (); + + for (int i = 0 ; i < 20 ; i++) + { + int damage = 5 * random[FireSG2](1, 3); + double ang = angle + Random2[FireSG2]() * (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. + + LineAttack (ang, PLAYERMISSILERANGE, pitch + Random2[FireSG2]() * (7.097 / 256), damage, 'Hitscan', "BulletPuff"); + } + } + + + action void A_OpenShotgun2() + { + A_PlaySound("weapons/sshoto", CHAN_WEAPON); + } + + action void A_LoadShotgun2() + { + A_PlaySound("weapons/sshotl", CHAN_WEAPON); + } + + action void A_CloseShotgun2() + { + A_PlaySound("weapons/sshotc", CHAN_WEAPON); + A_Refire(); + } +} diff --git a/wadsrc/static/zscript/heretic/beast.txt b/wadsrc/static/zscript/heretic/beast.txt new file mode 100644 index 0000000000..209b2da565 --- /dev/null +++ b/wadsrc/static/zscript/heretic/beast.txt @@ -0,0 +1,118 @@ + +// Beast -------------------------------------------------------------------- + +class Beast : Actor +{ + Default + { + Health 220; + Radius 32; + Height 74; + Mass 200; + Speed 14; + Painchance 100; + Monster; + +FLOORCLIP + SeeSound "beast/sight"; + AttackSound "beast/attack"; + PainSound "beast/pain"; + DeathSound "beast/death"; + ActiveSound "beast/active"; + Obituary "$OB_BEAST"; + DropItem "CrossbowAmmo", 84, 10; + } + States + { + Spawn: + BEAS AB 10 A_Look; + Loop; + See: + BEAS ABCDEF 3 A_Chase; + Loop; + Missile: + BEAS H 10 A_FaceTarget; + BEAS I 10 A_CustomComboAttack("BeastBall", 32, random[BeastAttack](1,8)*3, "beast/attack"); + Goto See; + Pain: + BEAS G 3; + BEAS G 3 A_Pain; + Goto See; + Death: + BEAS R 6; + BEAS S 6 A_Scream; + BEAS TUV 6; + BEAS W 6 A_NoBlocking; + BEAS XY 6; + BEAS Z -1; + Stop; + XDeath: + BEAS J 5; + BEAS K 6 A_Scream; + BEAS L 5; + BEAS M 6; + BEAS N 5; + BEAS O 6 A_NoBlocking; + BEAS P 5; + BEAS Q -1; + Stop; + } +} + +// Beast ball --------------------------------------------------------------- + +class BeastBall : Actor +{ + Default + { + Radius 9; + Height 8; + Speed 12; + FastSpeed 20; + Damage 4; + Projectile; + -ACTIVATEIMPACT + -ACTIVATEPCROSS + -NOBLOCKMAP + +WINDTHRUST + +SPAWNSOUNDSOURCE + RenderStyle "Add"; + SeeSound "beast/attack"; + } + States + { + Spawn: + FRB1 AABBCC 2 A_SpawnItemEx("Puffy", random2[BeastPuff]()*0.015625, random2[BeastPuff]()*0.015625, random2[BeastPuff]()*0.015625, + 0,0,0,0,SXF_ABSOLUTEPOSITION, 64); + Loop; + Death: + FRB1 DEFGH 4; + Stop; + } +} + +// Puffy -------------------------------------------------------------------- + +class Puffy : Actor +{ + Default + { + Radius 6; + Height 8; + Speed 10; + +NOBLOCKMAP + +NOGRAVITY + +MISSILE + +NOTELEPORT + +DONTSPLASH + RenderStyle "Add"; + } + States + { + Spawn: + FRB1 DEFGH 4; + Stop; + } +} + + + diff --git a/wadsrc/static/zscript/heretic/chicken.txt b/wadsrc/static/zscript/heretic/chicken.txt new file mode 100644 index 0000000000..5d6065f66a --- /dev/null +++ b/wadsrc/static/zscript/heretic/chicken.txt @@ -0,0 +1,346 @@ + +// Beak puff ---------------------------------------------------------------- + +class BeakPuff : StaffPuff +{ + Default + { + Mass 5; + Renderstyle "Translucent"; + Alpha 0.4; + AttackSound "chicken/attack"; + VSpeed 1; + } +} + +// Beak --------------------------------------------------------------------- + +class Beak : Weapon +{ + Default + { + Weapon.SelectionOrder 10000; + +WEAPON.DONTBOB + +WEAPON.MELEEWEAPON + Weapon.YAdjust 15; + Weapon.SisterWeapon "BeakPowered"; + } + + + States + { + Ready: + BEAK A 1 A_WeaponReady; + Loop; + Deselect: + BEAK A 1 A_Lower; + Loop; + Select: + BEAK A 1 A_BeakRaise; + Loop; + Fire: + BEAK A 18 A_BeakAttackPL1; + Goto Ready; + } + + //--------------------------------------------------------------------------- + // + // PROC A_BeakRaise + // + //--------------------------------------------------------------------------- + + action void A_BeakRaise () + { + + if (player == null) + { + return; + } + player.GetPSprite(PSP_WEAPON).y = WEAPONTOP; + player.SetPsprite(PSP_WEAPON, player.ReadyWeapon.GetReadyState()); + } + + //---------------------------------------------------------------------------- + // + // PROC A_BeakAttackPL1 + // + //---------------------------------------------------------------------------- + + action void A_BeakAttackPL1() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + int damage = random[BeakAtk](1,3); + double ang = angle; + double slope = AimLineAttack (ang, MELEERANGE); + LineAttack (ang, MELEERANGE, slope, damage, 'Melee', "BeakPuff", true, t); + if (t.linetarget) + { + angle = t.angleFromSource; + } + A_PlaySound ("chicken/peck", CHAN_VOICE); + player.chickenPeck = 12; + player.GetPSprite(PSP_WEAPON).Tics -= random[BeakAtk](0,7); + } +} + + +// BeakPowered --------------------------------------------------------------------- + +class BeakPowered : Beak +{ + Default + { + +WEAPON.POWERED_UP + Weapon.SisterWeapon "Beak"; + } + + + States + { + Fire: + BEAK A 12 A_BeakAttackPL2; + Goto Ready; + } + + //---------------------------------------------------------------------------- + // + // PROC A_BeakAttackPL2 + // + //---------------------------------------------------------------------------- + + action void A_BeakAttackPL2() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + int damage = random[BeakAtk](1,8) * 4; + double ang = angle; + double slope = AimLineAttack (ang, MELEERANGE); + LineAttack (ang, MELEERANGE, slope, damage, 'Melee', "BeakPuff", true, t); + if (t.linetarget) + { + angle = t.angleFromSource; + } + A_PlaySound ("chicken/peck", CHAN_VOICE); + player.chickenPeck = 12; + player.GetPSprite(PSP_WEAPON).Tics -= random[BeakAtk](0,3); + } + +} + +// Chicken player ----------------------------------------------------------- + +class ChickenPlayer : PlayerPawn +{ + Default + { + Health 30; + ReactionTime 0; + PainChance 255; + Radius 16; + Height 24; + Speed 1; + Gravity 0.125; + +NOSKIN + +PLAYERPAWN.CANSUPERMORPH + PainSound "chicken/pain"; + DeathSound "chicken/death"; + Player.JumpZ 1; + Player.Viewheight 21; + Player.ForwardMove 1.22, 1.22; + Player.SideMove 1.22, 1.22; + Player.SpawnClass "Chicken"; + Player.SoundClass "Chicken"; + Player.DisplayName "Chicken"; + Player.MorphWeapon "Beak"; + -PICKUP + } + + States + { + Spawn: + CHKN A -1; + Stop; + See: + CHKN ABAB 3; + Loop; + Melee: + Missile: + CHKN C 12; + Goto Spawn; + Pain: + CHKN D 4 A_Feathers; + CHKN C 4 A_Pain; + Goto Spawn; + Death: + CHKN E 6 A_Scream; + CHKN F 6 A_Feathers; + CHKN G 6; + CHKN H 6 A_NoBlocking; + CHKN IJK 6; + CHKN L -1; + Stop; + } + + //--------------------------------------------------------------------------- + // + // PROC P_UpdateBeak + // + //--------------------------------------------------------------------------- + + override void MorphPlayerThink () + { + if (health > 0) + { // Handle beak movement + PSprite pspr; + if (player != null && (pspr = player.FindPSprite(PSP_WEAPON)) != null) + { + pspr.y = WEAPONTOP + player.chickenPeck / 2; + } + } + if (player.morphTics & 15) + { + return; + } + if (Vel.X == 0 && Vel.Y == 0 && random[ChickenPlayerThink]() < 160) + { // Twitch view ang + angle += Random2[ChickenPlayerThink]() * (360. / 256. / 32.); + } + if ((pos.z <= floorz) && (random[ChickenPlayerThink]() < 32)) + { // Jump and noise + Vel.Z += JumpZ; + + State painstate = FindState('Pain'); + if (painstate != null) SetState (painstate); + } + if (random[ChickenPlayerThink]() < 48) + { // Just noise + A_PlaySound ("chicken/active", CHAN_VOICE); + } + } + +} + + + +// Chicken (non-player) ----------------------------------------------------- + +class Chicken : MorphedMonster +{ + Default + { + Health 10; + Radius 9; + Height 22; + Mass 40; + Speed 4; + Painchance 200; + Monster; + -COUNTKILL + +WINDTHRUST + +DONTMORPH + +FLOORCLIP + SeeSound "chicken/pain"; + AttackSound "chicken/attack"; + PainSound "chicken/pain"; + DeathSound "chicken/death"; + ActiveSound "chicken/active"; + Obituary "$OB_CHICKEN"; + } + States + { + Spawn: + CHKN AB 10 A_Look; + Loop; + See: + CHKN AB 3 A_Chase; + Loop; + Pain: + CHKN D 5 A_Feathers; + CHKN C 5 A_Pain; + Goto See; + Melee: + CHKN A 8 A_FaceTarget; + CHKN C 10 A_CustomMeleeAttack(random[ChicAttack](1,2)); + Goto See; + Death: + CHKN E 6 A_Scream; + CHKN F 6 A_Feathers; + CHKN G 6; + CHKN H 6 A_NoBlocking; + CHKN IJK 6; + CHKN L -1; + Stop; + } +} + + +// Feather ------------------------------------------------------------------ + +class Feather : Actor +{ + Default + { + Radius 2; + Height 4; + +MISSILE +DROPOFF + +NOTELEPORT +CANNOTPUSH + +WINDTHRUST +DONTSPLASH + Gravity 0.125; + } + + States + { + Spawn: + CHKN MNOPQPON 3; + Loop; + Death: + CHKN N 6; + Stop; + } +} + +extend class Actor +{ + //---------------------------------------------------------------------------- + // + // PROC A_Feathers + // This is used by both the chicken player and monster and must be in the + // common base class to be accessible by both + // + //---------------------------------------------------------------------------- + + void A_Feathers() + { + int count; + + if (health > 0) + { // Pain + count = random[Feathers]() < 32 ? 2 : 1; + } + else + { // Death + count = 5 + (random[Feathers]()&3); + } + for (int i = 0; i < count; i++) + { + Actor mo = Spawn("Feather", pos + (0, 0, 20), NO_REPLACE); + mo.target = self; + mo.Vel.X = Random2[Feathers]() / 256.; + mo.Vel.Y = Random2[Feathers]() / 256.; + mo.Vel.Z = 1. + random[Feathers]() / 128.; + mo.SetState (mo.SpawnState + (random[Feathers]()&7)); + } + } + +} \ No newline at end of file diff --git a/wadsrc/static/zscript/heretic/clink.txt b/wadsrc/static/zscript/heretic/clink.txt new file mode 100644 index 0000000000..7549ff097a --- /dev/null +++ b/wadsrc/static/zscript/heretic/clink.txt @@ -0,0 +1,48 @@ +class Clink : Actor +{ + Default + { + Health 150; + Radius 20; + Height 64; + Mass 75; + Speed 14; + Painchance 32; + Monster; + +NOBLOOD + +FLOORCLIP + SeeSound "clink/sight"; + AttackSound "clink/attack"; + PainSound "clink/pain"; + DeathSound "clink/death"; + ActiveSound "clink/active"; + Obituary "$OB_CLINK"; + DropItem "SkullRodAmmo", 84, 20; + } + States + { + Spawn: + CLNK AB 10 A_Look; + Loop; + See: + CLNK ABCD 3 A_Chase; + Loop; + Melee: + CLNK E 5 A_FaceTarget; + CLNK F 4 A_FaceTarget; + CLNK G 7 A_CustomMeleeAttack(random[ClinkAttack](3,9), "clink/attack", "clink/attack"); + Goto See; + Pain: + CLNK H 3; + CLNK H 3 A_Pain; + Goto See; + Death: + CLNK IJ 6; + CLNK K 5 A_Scream; + CLNK L 5 A_NoBlocking; + CLNK MN 5; + CLNK O -1; + Stop; + } +} + diff --git a/wadsrc/static/zscript/heretic/dsparil.txt b/wadsrc/static/zscript/heretic/dsparil.txt new file mode 100644 index 0000000000..54931b65e8 --- /dev/null +++ b/wadsrc/static/zscript/heretic/dsparil.txt @@ -0,0 +1,543 @@ + +// Boss spot ---------------------------------------------------------------- + +class BossSpot : SpecialSpot +{ + Default + { + +INVISIBLE + } +} + +// Sorcerer (D'Sparil on his serpent) --------------------------------------- + +class Sorcerer1 : Actor +{ + Default + { + Health 2000; + Radius 28; + Height 100; + Mass 800; + Speed 16; + PainChance 56; + Monster; + +BOSS + +DONTMORPH + +NORADIUSDMG + +NOTARGET + +NOICEDEATH + +FLOORCLIP + +DONTGIB + SeeSound "dsparilserpent/sight"; + AttackSound "dsparilserpent/attack"; + PainSound "dsparilserpent/pain"; + DeathSound "dsparilserpent/death"; + ActiveSound "dsparilserpent/active"; + Obituary "$OB_DSPARIL1"; + HitObituary "$OB_DSPARIL1HIT"; + } + + + States + { + Spawn: + SRCR AB 10 A_Look; + Loop; + See: + SRCR ABCD 5 A_Sor1Chase; + Loop; + Pain: + SRCR Q 6 A_Sor1Pain; + Goto See; + Missile: + SRCR Q 7 A_FaceTarget; + SRCR R 6 A_FaceTarget; + SRCR S 10 A_Srcr1Attack; + Goto See; + Missile2: + SRCR S 10 A_FaceTarget; + SRCR Q 7 A_FaceTarget; + SRCR R 6 A_FaceTarget; + SRCR S 10 A_Srcr1Attack; + Goto See; + Death: + SRCR E 7; + SRCR F 7 A_Scream; + SRCR G 7; + SRCR HIJK 6; + SRCR L 25 A_PlaySound("dsparil/zap", CHAN_BODY, 1, false, ATTN_NONE); + SRCR MN 5; + SRCR O 4; + SRCR L 20 A_PlaySound("dsparil/zap", CHAN_BODY, 1, false, ATTN_NONE); + SRCR MN 5; + SRCR O 4; + SRCR L 12; + SRCR P -1 A_SorcererRise; + } + + + //---------------------------------------------------------------------------- + // + // PROC A_Sor1Pain + // + //---------------------------------------------------------------------------- + + void A_Sor1Pain () + { + special1 = 20; // Number of steps to walk fast + A_Pain(); + } + + //---------------------------------------------------------------------------- + // + // PROC A_Sor1Chase + // + //---------------------------------------------------------------------------- + + void A_Sor1Chase () + { + if (special1) + { + special1--; + tics -= 3; + } + A_Chase(); + } + + //---------------------------------------------------------------------------- + // + // PROC A_Srcr1Attack + // + // Sorcerer demon attack. + // + //---------------------------------------------------------------------------- + + void A_Srcr1Attack () + { + if (!target) + { + return; + } + A_PlaySound (AttackSound, CHAN_BODY); + if (CheckMeleeRange ()) + { + int damage = random[Srcr1Attack](1,8) * 8; + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + return; + } + + if (health > (SpawnHealth()/3)*2) + { // Spit one fireball + SpawnMissileZ (pos.z + 48, target, "SorcererFX1"); + } + else + { // Spit three fireballs + Actor mo = SpawnMissileZ (pos.z + 48, target, "SorcererFX1"); + if (mo != null) + { + double ang = mo.angle; + SpawnMissileAngleZ(pos.z + 48, "SorcererFX1", ang - 3, mo.Vel.Z); + SpawnMissileAngleZ(pos.z + 48, "SorcererFX1", ang + 3, mo.Vel.Z); + } + if (health < SpawnHealth()/3) + { // Maybe attack again + if (special1) + { // Just attacked, so don't attack again + special1 = 0; + } + else + { // Set state to attack again + special1 = 1; + SetStateLabel("Missile2"); + } + } + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_SorcererRise + // + //---------------------------------------------------------------------------- + + void A_SorcererRise () + { + bSolid = false; + Actor mo = Spawn("Sorcerer2", Pos, ALLOW_REPLACE); + mo.Translation = Translation; + mo.SetStateLabel("Rise"); + mo.angle = angle; + mo.CopyFriendliness (self, true); + } + + +} + + +// Sorcerer FX 1 ------------------------------------------------------------ + +class SorcererFX1 : Actor +{ + Default + { + Radius 10; + Height 10; + Speed 20; + FastSpeed 28; + Damage 10; + DamageType "Fire"; + Projectile; + -ACTIVATEIMPACT + -ACTIVATEPCROSS + RenderStyle "Add"; + } + + States + { + Spawn: + FX14 ABC 6 BRIGHT; + Loop; + Death: + FX14 DEFGH 5 BRIGHT; + Stop; + } +} + + +// Sorcerer 2 (D'Sparil without his serpent) -------------------------------- + +class Sorcerer2 : Actor +{ + Default + { + Health 3500; + Radius 16; + Height 70; + Mass 300; + Speed 14; + Painchance 32; + Monster; + +DROPOFF + +BOSS + +DONTMORPH + +FULLVOLACTIVE + +NORADIUSDMG + +NOTARGET + +NOICEDEATH + +FLOORCLIP + +BOSSDEATH + SeeSound "dsparil/sight"; + AttackSound "dsparil/attack"; + PainSound "dsparil/pain"; + ActiveSound "dsparil/active"; + Obituary "$OB_DSPARIL2"; + HitObituary "$OB_DSPARIL2HIT"; + } + + + States + { + Spawn: + SOR2 MN 10 A_Look; + Loop; + See: + SOR2 MNOP 4 A_Chase; + Loop; + Rise: + SOR2 AB 4; + SOR2 C 4 A_PlaySound("dsparil/rise", CHAN_BODY, 1, false, ATTN_NONE); + SOR2 DEF 4; + SOR2 G 12 A_PlaySound("dsparil/sight", CHAN_BODY, 1, false, ATTN_NONE); + Goto See; + Pain: + SOR2 Q 3; + SOR2 Q 6 A_Pain; + Goto See; + Missile: + SOR2 R 9 A_Srcr2Decide; + SOR2 S 9 A_FaceTarget; + SOR2 T 20 A_Srcr2Attack; + Goto See; + Teleport: + SOR2 LKJIHG 6; + Goto See; + Death: + SDTH A 8 A_Sor2DthInit; + SDTH B 8; + SDTH C 8 A_PlaySound("dsparil/scream", CHAN_BODY, 1, false, ATTN_NONE); + DeathLoop: + SDTH DE 7; + SDTH F 7 A_Sor2DthLoop; + SDTH G 6 A_PlaySound("dsparil/explode", CHAN_BODY, 1, false, ATTN_NONE); + SDTH H 6; + SDTH I 18; + SDTH J 6 A_NoBlocking; + SDTH K 6 A_PlaySound("dsparil/bones", CHAN_BODY, 1, false, ATTN_NONE); + SDTH LMN 6; + SDTH O -1 A_BossDeath; + Stop; + } + + //---------------------------------------------------------------------------- + // + // PROC P_DSparilTeleport + // + //---------------------------------------------------------------------------- + + void DSparilTeleport () + { + SpotState state = SpotState.GetSpotState(); + if (state == null) return; + + Actor spot = state.GetSpotWithMinMaxDistance("BossSpot", pos.x, pos.y, 128, 0); + if (spot == null) return; + + Vector3 prev = Pos; + if (TeleportMove (spot.Pos, false)) + { + Actor mo = Spawn("Sorcerer2Telefade", prev, ALLOW_REPLACE); + if (mo) + { + mo.Translation = Translation; + mo.A_PlaySound("misc/teleport", CHAN_BODY); + } + SetStateLabel ("Teleport"); + A_PlaySound ("misc/teleport", CHAN_BODY); + SetZ(floorz); + angle = spot.angle; + vel = (0,0,0); + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_Srcr2Decide + // + //---------------------------------------------------------------------------- + + void A_Srcr2Decide () + { + static const int chance[] = + { + 192, 120, 120, 120, 64, 64, 32, 16, 0 + }; + + int health8 = max(1, SpawnHealth() / 8); + int chanceindex = min(8, health / health8); + + if (random[Srcr2Decide]() < chance[chanceindex]) + { + DSparilTeleport (); + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_Srcr2Attack + // + //---------------------------------------------------------------------------- + + void A_Srcr2Attack () + { + if (!target) + { + return; + } + A_PlaySound (AttackSound, CHAN_BODY, 1, false, ATTN_NONE); + if (CheckMeleeRange()) + { + int damage = random[Srcr2Atk](1, 8) * 20; + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + return; + } + int chance = health < SpawnHealth()/2 ? 96 : 48; + if (random[Srcr2Atk]() < chance) + { // Wizard spawners + + SpawnMissileAngle("Sorcerer2FX2", Angle - 45, 0.5); + SpawnMissileAngle("Sorcerer2FX2", Angle + 45, 0.5); + } + else + { // Blue bolt + SpawnMissile (target, "Sorcerer2FX1"); + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_Sor2DthInit + // + //---------------------------------------------------------------------------- + + void A_Sor2DthInit () + { + special1 = 7; // Animation loop counter + Thing_Destroy(0); // Kill monsters early + } + + //---------------------------------------------------------------------------- + // + // PROC A_Sor2DthLoop + // + //---------------------------------------------------------------------------- + + void A_Sor2DthLoop () + { + if (--special1) + { // Need to loop + SetStateLabel("DeathLoop"); + } + } +} + + + +// Sorcerer 2 FX 1 ---------------------------------------------------------- + +class Sorcerer2FX1 : Actor +{ + Default + { + Radius 10; + Height 6; + Speed 20; + FastSpeed 28; + Damage 1; + Projectile; + -ACTIVATEIMPACT + -ACTIVATEPCROSS + RenderStyle "Add"; + } + + States + { + Spawn: + FX16 ABC 3 BRIGHT A_BlueSpark; + Loop; + Death: + FX16 G 5 BRIGHT A_Explode(random[S2FX1](80,111)); + FX16 HIJKL 5 BRIGHT; + Stop; + } + + //---------------------------------------------------------------------------- + // + // PROC A_BlueSpark + // + //---------------------------------------------------------------------------- + + void A_BlueSpark () + { + for (int i = 0; i < 2; i++) + { + Actor mo = Spawn("Sorcerer2FXSpark", pos, ALLOW_REPLACE); + mo.Vel.X = Random2[BlueSpark]() / 128.; + mo.Vel.Y = Random2[BlueSpark]() / 128.; + mo.Vel.Z = 1. + Random[BlueSpark]() / 256.; + } + } +} + +// Sorcerer 2 FX Spark ------------------------------------------------------ + +class Sorcerer2FXSpark : Actor +{ + Default + { + Radius 20; + Height 16; + +NOBLOCKMAP + +NOGRAVITY + +NOTELEPORT + +CANNOTPUSH + RenderStyle "Add"; + } + + States + { + Spawn: + FX16 DEF 12 BRIGHT; + Stop; + } +} + +// Sorcerer 2 FX 2 ---------------------------------------------------------- + +class Sorcerer2FX2 : Actor +{ + Default + { + Radius 10; + Height 6; + Speed 6; + Damage 10; + Projectile; + -ACTIVATEIMPACT + -ACTIVATEPCROSS + RenderStyle "Add"; + } + + States + { + Spawn: + FX11 A 35 BRIGHT; + FX11 A 5 BRIGHT A_GenWizard; + FX11 B 5 BRIGHT; + Goto Spawn+1; + Death: + FX11 CDEFG 5 BRIGHT; + Stop; + + } + +//---------------------------------------------------------------------------- +// +// PROC A_GenWizard +// +//---------------------------------------------------------------------------- + + void A_GenWizard () + { + Actor mo = Spawn("Wizard", pos, ALLOW_REPLACE); + if (mo != null) + { + mo.AddZ(-mo.Default.Height / 2, false); + if (!mo.TestMobjLocation ()) + { // Didn't fit + mo.ClearCounters(); + mo.Destroy (); + } + else + { // [RH] Make the new wizards inherit D'Sparil's target + mo.CopyFriendliness (self.target, true); + + Vel = (0,0,0); + SetStateLabel('Death'); + bMissile = false; + mo.master = target; + SpawnTeleportFog(pos, false, true); + } + } + } +} + +// Sorcerer 2 Telefade ------------------------------------------------------ + +class Sorcerer2Telefade : Actor +{ + Default + { + +NOBLOCKMAP + } + + States + { + Spawn: + SOR2 GHIJKL 6; + Stop; + } +} + diff --git a/wadsrc/static/zscript/heretic/hereticammo.txt b/wadsrc/static/zscript/heretic/hereticammo.txt new file mode 100644 index 0000000000..cf1e50a3d7 --- /dev/null +++ b/wadsrc/static/zscript/heretic/hereticammo.txt @@ -0,0 +1,243 @@ + +// Wimpy ammo --------------------------------------------------------------- + +Class GoldWandAmmo : Ammo +{ + Default + { + Inventory.PickupMessage "$TXT_AMMOGOLDWAND1"; + Inventory.Amount 10; + Inventory.MaxAmount 100; + Ammo.BackpackAmount 10; + Ammo.BackpackMaxAmount 200; + Inventory.Icon "INAMGLD"; + } + States + { + Spawn: + AMG1 A -1; + Stop; + } +} + +// Hefty ammo --------------------------------------------------------------- + +Class GoldWandHefty : GoldWandAmmo +{ + Default + { + Inventory.PickupMessage "$TXT_AMMOGOLDWAND2"; + Inventory.Amount 50; + } + States + { + Spawn: + AMG2 ABC 4; + Loop; + } +} +// Wimpy ammo --------------------------------------------------------------- + +Class CrossbowAmmo : Ammo +{ + Default + { + Inventory.PickupMessage "$TXT_AMMOCROSSBOW1"; + Inventory.Amount 5; + Inventory.MaxAmount 50; + Ammo.BackpackAmount 5; + Ammo.BackpackMaxAmount 100; + Inventory.Icon "INAMBOW"; + } + States + { + Spawn: + AMC1 A -1; + Stop; + } +} + +// Hefty ammo --------------------------------------------------------------- + +Class CrossbowHefty : CrossbowAmmo +{ + Default + { + Inventory.PickupMessage "$TXT_AMMOCROSSBOW2"; + Inventory.Amount 20; + } + States + { + Spawn: + AMC2 ABC 5; + Loop; + } +} +// Wimpy ammo --------------------------------------------------------------- + +Class MaceAmmo : Ammo +{ + Default + { + Inventory.PickupMessage "$TXT_AMMOMACE1"; + Inventory.Amount 20; + Inventory.MaxAmount 150; + Ammo.BackpackAmount 20; + Ammo.BackpackMaxAmount 300; + Inventory.Icon "INAMLOB"; + } + States + { + Spawn: + AMM1 A -1; + Stop; + } +} + +// Hefty ammo --------------------------------------------------------------- + +Class MaceHefty : MaceAmmo +{ + Default + { + Inventory.PickupMessage "$TXT_AMMOMACE2"; + Inventory.Amount 100; + } + States + { + Spawn: + AMM2 A -1; + Stop; + } +} + +// Wimpy ammo --------------------------------------------------------------- + +Class BlasterAmmo : Ammo +{ + Default + { + Inventory.PickupMessage "$TXT_AMMOBLASTER1"; + Inventory.Amount 10; + Inventory.MaxAmount 200; + Ammo.BackpackAmount 10; + Ammo.BackpackMaxAmount 400; + Inventory.Icon "INAMBST"; + } + States + { + Spawn: + AMB1 ABC 4; + Loop; + } +} + +// Hefty ammo --------------------------------------------------------------- + +Class BlasterHefty : BlasterAmmo +{ + Default + { + Inventory.PickupMessage "$TXT_AMMOBLASTER2"; + Inventory.Amount 25; + } + States + { + Spawn: + AMB2 ABC 4; + Loop; + } +} + +// Wimpy ammo --------------------------------------------------------------- + +Class SkullRodAmmo : Ammo +{ + Default + { + Inventory.PickupMessage "$TXT_AMMOSKULLROD1"; + Inventory.Amount 20; + Inventory.MaxAmount 200; + Ammo.BackpackAmount 20; + Ammo.BackpackMaxAmount 400; + Inventory.Icon "INAMRAM"; + } + States + { + Spawn: + AMS1 AB 5; + Loop; + } +} + +// Hefty ammo --------------------------------------------------------------- + +Class SkullRodHefty : SkullRodAmmo +{ + Default + { + Inventory.PickupMessage "$TXT_AMMOSKULLROD2"; + Inventory.Amount 100; + } + States + { + Spawn: + AMS2 AB 5; + Loop; + } +} + +// Wimpy ammo --------------------------------------------------------------- + +Class PhoenixRodAmmo : Ammo +{ + Default + { + Inventory.PickupMessage "$TXT_AMMOPHOENIXROD1"; + Inventory.Amount 1; + Inventory.MaxAmount 20; + Ammo.BackpackAmount 1; + Ammo.BackpackMaxAmount 40; + Inventory.Icon "INAMPNX"; + } + States + { + Spawn: + AMP1 ABC 4; + Loop; + } +} +// Hefty ammo --------------------------------------------------------------- + +Class PhoenixRodHefty : PhoenixRodAmmo +{ + Default + { + Inventory.PickupMessage "$TXT_AMMOPHOENIXROD2"; + Inventory.Amount 10; + } + States + { + Spawn: + AMP2 ABC 4; + Loop; + } +} + +// --- Bag of holding ------------------------------------------------------- + +Class BagOfHolding : BackpackItem +{ + Default + { + Inventory.PickupMessage "$TXT_ITEMBAGOFHOLDING"; + +COUNTITEM + +FLOATBOB + } + States + { + Spawn: + BAGH A -1; + Stop; + } +} diff --git a/wadsrc/static/zscript/heretic/hereticarmor.txt b/wadsrc/static/zscript/heretic/hereticarmor.txt new file mode 100644 index 0000000000..8cbcb9fbcf --- /dev/null +++ b/wadsrc/static/zscript/heretic/hereticarmor.txt @@ -0,0 +1,41 @@ + +// Silver Shield (Shield1) -------------------------------------------------- + +Class SilverShield : BasicArmorPickup +{ + Default + { + +FLOATBOB + Inventory.Pickupmessage "$TXT_ITEMSHIELD1"; + Inventory.Icon "SHLDA0"; + Armor.Savepercent 50; + Armor.Saveamount 100; + } + States + { + Spawn: + SHLD A -1; + stop; + } +} + +// Enchanted shield (Shield2) ----------------------------------------------- + +Class EnchantedShield : BasicArmorPickup +{ + Default + { + +FLOATBOB + Inventory.Pickupmessage "$TXT_ITEMSHIELD2"; + Inventory.Icon "SHD2A0"; + Armor.Savepercent 75; + Armor.Saveamount 200; + } + States + { + Spawn: + SHD2 A -1; + stop; + } +} + diff --git a/wadsrc/static/zscript/heretic/hereticartifacts.txt b/wadsrc/static/zscript/heretic/hereticartifacts.txt new file mode 100644 index 0000000000..3ef265735a --- /dev/null +++ b/wadsrc/static/zscript/heretic/hereticartifacts.txt @@ -0,0 +1,156 @@ +// Super map ---------------------------------------------------------------- + +Class SuperMap : MapRevealer +{ + Default + { + +COUNTITEM + +INVENTORY.ALWAYSPICKUP + +FLOATBOB + Inventory.MaxAmount 0; + Inventory.PickupMessage "$TXT_ITEMSUPERMAP"; + } + States + { + Spawn: + SPMP A -1; + Stop; + } +} + + +// Invisibility ------------------------------------------------------------- + +Class ArtiInvisibility : PowerupGiver +{ + Default + { + +COUNTITEM + +FLOATBOB + Inventory.PickupFlash "PickupFlash"; + RenderStyle "Translucent"; + Alpha 0.4; + Inventory.RespawnTics 4230; + Inventory.Icon "ARTIINVS"; + Powerup.Type "PowerGhost"; + Inventory.PickupMessage "$TXT_ARTIINVISIBILITY"; + Tag "$TAG_ARTIINVISIBILITY"; + } + States + { + Spawn: + INVS A 350 Bright; + Loop; + } +} + + +// Tome of power ------------------------------------------------------------ + +Class ArtiTomeOfPower : PowerupGiver +{ + Default + { + +COUNTITEM + +FLOATBOB + Inventory.PickupFlash "PickupFlash"; + Inventory.Icon "ARTIPWBK"; + Powerup.Type "PowerWeaponlevel2"; + Inventory.PickupMessage "$TXT_ARTITOMEOFPOWER"; + Tag "$TAG_ARTITOMEOFPOWER"; + } + States + { + Spawn: + PWBK A 350; + Loop; + } + + bool Use (bool pickup) + { + Playerinfo p = Owner.player; + if (p && p.morphTics && (p.MorphStyle & MRF_UNDOBYTOMEOFPOWER)) + { // Attempt to undo chicken + if (!p.UndoPlayerMorph (p, MRF_UNDOBYTOMEOFPOWER)) + { // Failed + if (!(p.MorphStyle & MRF_FAILNOTELEFRAG)) + { + Owner.DamageMobj (null, null, TELEFRAG_DAMAGE, 'Telefrag'); + } + } + else + { // Succeeded + Owner.A_PlaySound ("*evillaugh", CHAN_VOICE); + } + return true; + } + else + { + return Super.Use (pickup); + } + } + +} + + +// Time bomb ---------------------------------------------------------------- + +Class ActivatedTimeBomb : Actor +{ + Default + { + +NOGRAVITY + RenderStyle "Translucent"; + Alpha 0.4; + DeathSound "misc/timebomb"; + } + + States + { + Spawn: + FBMB ABCD 10; + FBMB E 6 A_Scream; + XPL1 A 4 BRIGHT A_Timebomb; + XPL1 BCDEF 4 BRIGHT; + Stop; + } + + void A_TimeBomb() + { + AddZ(32, false); + A_SetRenderStyle(1., STYLE_Add); + A_Explode(); + } +} + + +Class ArtiTimeBomb : Inventory +{ + Default + { + +COUNTITEM + +FLOATBOB + Inventory.PickupFlash "PickupFlash"; + +INVENTORY.INVBAR + +INVENTORY.FANCYPICKUPSOUND + Inventory.Icon "ARTIFBMB"; + Inventory.PickupSound "misc/p_pkup"; + Inventory.PickupMessage "$TXT_ARTIFIREBOMB"; + Tag "$TAG_ARTIFIREBOMB"; + Inventory.DefMaxAmount; + } + States + { + Spawn: + FBMB E 350; + Loop; + } + + override bool Use (bool pickup) + { + Actor mo = Spawn("ActivatedTimeBomb", Owner.Vec3Angle(24., Owner.angle, - Owner.Floorclip), ALLOW_REPLACE); + mo.target = Owner; + return true; + } + +} diff --git a/wadsrc/static/zscript/heretic/hereticdecorations.txt b/wadsrc/static/zscript/heretic/hereticdecorations.txt new file mode 100644 index 0000000000..d38f47a394 --- /dev/null +++ b/wadsrc/static/zscript/heretic/hereticdecorations.txt @@ -0,0 +1,302 @@ +Class SkullHang70 : Actor +{ + Default + { + Radius 20; + Height 70; + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + SKH1 A -1; + Stop; + } +} + +Class SkullHang60 : Actor +{ + Default + { + Radius 20; + Height 60; + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + SKH2 A -1; + Stop; + } +} + +Class SkullHang45 : Actor +{ + Default + { + Radius 20; + Height 45; + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + SKH3 A -1; + Stop; + } +} + +Class SkullHang35 : Actor +{ + Default + { + Radius 20; + Height 35; + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + SKH4 A -1; + Stop; + } +} + +Class Chandelier : Actor +{ + Default + { + Radius 20; + Height 60; + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + CHDL ABC 4; + Loop; + } +} + +Class SerpentTorch : Actor +{ + Default + { + Radius 12; + Height 54; + +SOLID + } + States + { + Spawn: + SRTC ABC 4; + Loop; + } +} + +Class SmallPillar : Actor +{ + Default + { + Radius 16; + Height 34; + +SOLID + } + States + { + Spawn: + SMPL A -1; + Stop; + } +} + +Class StalagmiteSmall : Actor +{ + Default + { + Radius 8; + Height 32; + +SOLID + } + States + { + Spawn: + STGS A -1; + Stop; + } +} + +Class StalagmiteLarge : Actor +{ + Default + { + Radius 12; + Height 64; + +SOLID + } + States + { + Spawn: + STGL A -1; + Stop; + } +} + +Class StalactiteSmall : Actor +{ + Default + { + Radius 8; + Height 36; + +SOLID + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + STCS A -1; + Stop; + } +} + +Class StalactiteLarge : Actor +{ + Default + { + Radius 12; + Height 68; + +SOLID + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + STCL A -1; + Stop; + } +} + +Class FireBrazier : Actor +{ + Default + { + Radius 16; + Height 44; + +SOLID + } + States + { + Spawn: + KFR1 ABCDEFGH 3 Bright; + Loop; + } +} + +Class Barrel : Actor +{ + Default + { + Radius 12; + Height 32; + +SOLID + } + States + { + Spawn: + BARL A -1; + Stop; + } +} + +Class BrownPillar : Actor +{ + Default + { + Radius 14; + Height 128; + +SOLID + } + States + { + Spawn: + BRPL A -1; + Stop; + } +} + +Class Moss1 : Actor +{ + Default + { + Radius 20; + Height 23; + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + MOS1 A -1; + Stop; + } +} + +Class Moss2 : Actor +{ + Default + { + Radius 20; + Height 27; + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + MOS2 A -1; + Stop; + } +} + +Class WallTorch : Actor +{ + Default + { + Radius 6; + Height 16; + +NOGRAVITY + +FIXMAPTHINGPOS + } + States + { + Spawn: + WTRH ABC 6 Bright; + Loop; + } +} + +Class HangingCorpse : Actor +{ + Default + { + Radius 8; + Height 104; + +SOLID + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + HCOR A -1; + Stop; + } +} + diff --git a/wadsrc/static/zscript/heretic/hereticimp.txt b/wadsrc/static/zscript/heretic/hereticimp.txt new file mode 100644 index 0000000000..c1443de032 --- /dev/null +++ b/wadsrc/static/zscript/heretic/hereticimp.txt @@ -0,0 +1,238 @@ + +// Heretic imp (as opposed to the Doom variety) ----------------------------- + +class HereticImp : Actor +{ + bool extremecrash; + + Default + { + Health 40; + Radius 16; + Height 36; + Mass 50; + Speed 10; + Painchance 200; + Monster; + +FLOAT + +NOGRAVITY + +SPAWNFLOAT + +DONTOVERLAP + +MISSILEMORE + SeeSound "himp/sight"; + AttackSound "himp/attack"; + PainSound "himp/pain"; + DeathSound "himp/death"; + ActiveSound "himp/active"; + Obituary "$OB_HERETICIMP"; + HitObituary "$OB_HERETICIMPHIT"; + } + + States + { + Spawn: + IMPX ABCB 10 A_Look; + Loop; + See: + IMPX AABBCCBB 3 A_Chase; + Loop; + Melee: + IMPX DE 6 A_FaceTarget; + IMPX F 6 A_CustomMeleeAttack(random[ImpMeAttack](5,12), "himp/attack", "himp/attack"); + Goto See; + Missile: + IMPX A 10 A_FaceTarget; + IMPX B 6 A_ImpMsAttack; + IMPX CBAB 6; + Goto Missile+2; + Pain: + IMPX G 3; + IMPX G 3 A_Pain; + Goto See; + Death: + IMPX G 4 A_ImpDeath; + IMPX H 5; + Wait; + XDeath: + IMPX S 5 A_ImpXDeath1; + IMPX TU 5; + IMPX V 5 A_Gravity; + IMPX W 5; + Wait; + Crash: + IMPX I 7 A_ImpExplode; + IMPX J 7 A_Scream; + IMPX K 7; + IMPX L -1; + Stop; + XCrash: + IMPX X 7; + IMPX Y 7; + IMPX Z -1; + Stop; + } + + + //---------------------------------------------------------------------------- + // + // PROC A_ImpMsAttack + // + //---------------------------------------------------------------------------- + + void A_ImpMsAttack() + { + if (!target || random[ImpMSAtk]() > 64) + { + SetState (SeeState); + return; + } + A_SkullAttack(12); +} + + //---------------------------------------------------------------------------- + // + // PROC A_ImpExplode + // + //---------------------------------------------------------------------------- + + void A_ImpExplode() + { + Actor chunk; + + bNoGravity = false; + + chunk = Spawn("HereticImpChunk1", pos, ALLOW_REPLACE); + chunk.vel.x = random2[ImpExplode]() / 64.; + chunk.vel.y = random2[ImpExplode]() / 64.; + chunk.vel.z = 9; + + chunk = Spawn("HereticImpChunk2", pos, ALLOW_REPLACE); + chunk.vel.x = random2[ImpExplode]() / 64.; + chunk.vel.y = random2[ImpExplode]() / 64.; + chunk.vel.z = 9; + + if (extremecrash) + { + SetStateLabel ("XCrash"); + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_ImpDeath + // + //---------------------------------------------------------------------------- + + void A_ImpDeath() + { + bSolid = false; + bFloorClip = true; + } + + //---------------------------------------------------------------------------- + // + // PROC A_ImpXDeath1 + // + //---------------------------------------------------------------------------- + + void A_ImpXDeath1() + { + bSolid = false; + bFloorClip = true; + bNoGravity = true; + extremecrash = true; + } +} + +// Heretic imp leader ------------------------------------------------------- + +class HereticImpLeader : HereticImp +{ + Default + { + Species "HereticImpLeader"; + Health 80; + -MISSILEMORE + AttackSound "himp/leaderattack"; + } + States + { + Melee: + Stop; + Missile: + IMPX DE 6 A_FaceTarget; + IMPX F 6 A_CustomComboAttack("HereticImpBall", 32, random[ImpMsAttack2](5,12), "himp/leaderattack"); + Goto See; + } +} + +// Heretic imp chunk 1 ------------------------------------------------------ + +class HereticImpChunk1 : Actor +{ + Default + { + Mass 5; + Radius 4; + +NOBLOCKMAP + +MOVEWITHSECTOR + } + States + { + Spawn: + IMPX M 5; + IMPX NO 700; + Stop; + } +} + +// Heretic imp chunk 2 ------------------------------------------------------ + +class HereticImpChunk2 : Actor +{ + Default + { + Mass 5; + Radius 4; + +NOBLOCKMAP + +MOVEWITHSECTOR + } + States + { + Spawn: + IMPX P 5; + IMPX QR 700; + Stop; + } +} + +// Heretic imp ball --------------------------------------------------------- + +class HereticImpBall : Actor +{ + Default + { + Radius 8; + Height 8; + Speed 10; + FastSpeed 20; + Damage 1; + Projectile; + SeeSound "himp/leaderattack"; + +SPAWNSOUNDSOURCE + -ACTIVATEPCROSS + -ACTIVATEIMPACT + RenderStyle "Add"; + } + States + { + Spawn: + FX10 ABC 6 Bright; + Loop; + Death: + FX10 DEFG 5 Bright; + Stop; + } +} + + diff --git a/wadsrc/static/zscript/heretic/heretickeys.txt b/wadsrc/static/zscript/heretic/heretickeys.txt new file mode 100644 index 0000000000..d5532ce016 --- /dev/null +++ b/wadsrc/static/zscript/heretic/heretickeys.txt @@ -0,0 +1,174 @@ + +Class HereticKey : Key +{ + Default + { + +NOTDMATCH + Radius 20; + Height 16; + } +} + +// Green key ------------------------------------------------------------ + +Class KeyGreen : HereticKey +{ + Default + { + Inventory.PickupMessage "$TXT_GOTGREENKEY"; + Inventory.Icon "GKEYICON"; + } + States + { + Spawn: + AKYY ABCDEFGHIJ 3 Bright; + Loop; + } +} + +// Blue key ----------------------------------------------------------------- + +Class KeyBlue : HereticKey +{ + Default + { + Inventory.PickupMessage "$TXT_GOTBLUEKEY"; + Inventory.Icon "BKEYICON"; + } + States + { + Spawn: + BKYY ABCDEFGHIJ 3 Bright; + Loop; + } +} + +// Yellow key --------------------------------------------------------------- + +Class KeyYellow : HereticKey +{ + Default + { + Inventory.PickupMessage "$TXT_GOTYELLOWKEY"; + Inventory.Icon "YKEYICON"; + } + States + { + Spawn: + CKYY ABCDEFGHI 3 Bright; + Loop; + } +} + + +// --- Blue Key gizmo ----------------------------------------------------------- + +Class KeyGizmoBlue : Actor +{ + Default + { + Radius 16; + Height 50; + +SOLID + } + States + { + Spawn: + KGZ1 A 1; + KGZ1 A 1 A_SpawnItemEx("KeyGizmoFloatBlue", 0, 0, 60); + KGZ1 A -1; + Stop; + } +} + +Class KeyGizmoFloatBlue : Actor +{ + Default + { + Radius 16; + Height 16; + +SOLID + +NOGRAVITY + } + States + { + Spawn: + KGZB A -1 Bright; + Stop; + } +} + +// --- Green Key gizmo ----------------------------------------------------------- + +Class KeyGizmoGreen : Actor +{ + Default + { + Radius 16; + Height 50; + +SOLID + } + States + { + Spawn: + KGZ1 A 1; + KGZ1 A 1 A_SpawnItemEx("KeyGizmoFloatGreen", 0, 0, 60); + KGZ1 A -1; + Stop; + } +} + +Class KeyGizmoFloatGreen : Actor +{ + Default + { + Radius 16; + Height 16; + +SOLID + +NOGRAVITY + } + States + { + Spawn: + KGZG A -1 Bright; + Stop; + } +} + +// --- Yellow Key gizmo ----------------------------------------------------------- + +Class KeyGizmoYellow : Actor +{ + Default + { + Radius 16; + Height 50; + +SOLID + } + States + { + Spawn: + KGZ1 A 1; + KGZ1 A 1 A_SpawnItemEx("KeyGizmoFloatYellow", 0, 0, 60); + KGZ1 A -1; + Stop; + } +} + +Class KeyGizmoFloatYellow : Actor +{ + Default + { + Radius 16; + Height 16; + +SOLID + +NOGRAVITY + } + States + { + Spawn: + KGZY A -1 Bright; + Stop; + } +} + diff --git a/wadsrc/static/zscript/heretic/hereticmisc.txt b/wadsrc/static/zscript/heretic/hereticmisc.txt new file mode 100644 index 0000000000..ea79f5f803 --- /dev/null +++ b/wadsrc/static/zscript/heretic/hereticmisc.txt @@ -0,0 +1,393 @@ + +class HereticWeapon : Weapon +{ + Default + { + Weapon.Kickback 150; + } +} + +// Pod ---------------------------------------------------------------------- + +class Pod : Actor +{ + Default + { + Health 45; + Radius 16; + Height 54; + Painchance 255; + +SOLID +NOBLOOD +SHOOTABLE +DROPOFF + +WINDTHRUST +PUSHABLE +SLIDESONWALLS + +CANPASS +TELESTOMP +DONTMORPH + +NOBLOCKMONST +DONTGIB +OLDRADIUSDMG + DeathSound "world/podexplode"; + PushFactor 0.5; + } + + States + { + Spawn: + PPOD A 10; + Loop; + Pain: + PPOD B 14 A_PodPain; + Goto Spawn; + Death: + PPOD C 5 BRIGHT A_RemovePod; + PPOD D 5 BRIGHT A_Scream; + PPOD E 5 BRIGHT A_Explode; + PPOD F 10 BRIGHT; + Stop; + Grow: + PPOD IJKLMNOP 3; + Goto Spawn; + } + + //---------------------------------------------------------------------------- + // + // PROC A_PodPain + // + //---------------------------------------------------------------------------- + + void A_PodPain (class gootype = "PodGoo") + { + int chance = Random[PodPain](); + if (chance < 128) + { + return; + } + for (int count = chance > 240 ? 2 : 1; count; count--) + { + Actor goo = Spawn(gootype, pos + (0, 0, 48), ALLOW_REPLACE); + goo.target = self; + goo.Vel.X = Random2[PodPain]() / 128.; + goo.Vel.Y = Random2[PodPain]() / 128.; + goo.Vel.Z = 0.5 + random[PodPain]() / 128.; + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_RemovePod + // + //---------------------------------------------------------------------------- + + void A_RemovePod () + { + if (master && master.special1 > 0) + { + master.special1--; + } + } + +} + + +// Pod goo (falls from pod when damaged) ------------------------------------ + +class PodGoo : Actor +{ + Default + { + Radius 2; + Height 4; + Gravity 0.125; + +NOBLOCKMAP +MISSILE +DROPOFF + +NOTELEPORT +CANNOTPUSH + } + States + { + Spawn: + PPOD GH 8; + Loop; + Death: + PPOD G 10; + Stop; + } +} + +// Pod generator ------------------------------------------------------------ + +class PodGenerator : Actor +{ + Default + { + +NOBLOCKMAP + +NOSECTOR + +DONTSPLASH + AttackSound "world/podgrow"; + } + + + States + { + Spawn: + TNT1 A 35 A_MakePod; + Loop; + } + + //---------------------------------------------------------------------------- + // + // PROC A_MakePod + // + //---------------------------------------------------------------------------- + + const MAX_GEN_PODS = 16; + + void A_MakePod (class podtype = "Pod") + { + if (special1 >= MAX_GEN_PODS) + { // Too many generated pods + return; + } + Actor mo = Spawn(podtype, (pos.xy, ONFLOORZ), ALLOW_REPLACE); + if (!mo) return; + if (!mo.CheckPosition (mo.Pos.xy)) + { // Didn't fit + mo.Destroy (); + return; + } + mo.SetStateLabel("Grow"); + mo.Thrust(4.5, random[MakePod]() * (360. / 256)); + A_PlaySound (AttackSound, CHAN_BODY); + special1++; // Increment generated pod count + mo.master = self; // Link the generator to the pod + } +} + + +// Teleglitter generator 1 -------------------------------------------------- + +class TeleGlitterGenerator1 : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + +DONTSPLASH + +MOVEWITHSECTOR + } + States + { + Spawn: + TNT1 A 8 A_SpawnItemEx("TeleGlitter1", random[TeleGlitter](0,31)-16, random[TeleGlitter](0,31)-16, 0, 0,0,0.25); + Loop; + } +} + +// Teleglitter generator 2 -------------------------------------------------- + +class TeleGlitterGenerator2 : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + +DONTSPLASH + +MOVEWITHSECTOR + } + States + { + Spawn: + TNT1 A 8 A_SpawnItemEx("TeleGlitter2", random[TeleGlitter2](0,31)-16, random[TeleGlitter2](0,31)-16, 0, 0,0,0.25); + Loop; + } +} + + +// Teleglitter 1 ------------------------------------------------------------ + +class TeleGlitter1 : Actor +{ + Default + { + +NOBLOCKMAP +NOGRAVITY +MISSILE + RenderStyle "Add"; + Damage 0; + } + + + States + { + Spawn: + TGLT A 2 BRIGHT; + TGLT B 2 BRIGHT A_AccTeleGlitter; + TGLT C 2 BRIGHT; + TGLT D 2 BRIGHT A_AccTeleGlitter; + TGLT E 2 BRIGHT; + Loop; + } + + //---------------------------------------------------------------------------- + // + // PROC A_AccTeleGlitter + // + //---------------------------------------------------------------------------- + + void A_AccTeleGlitter () + { + if (++health > 35) + { + Vel.Z *= 1.5; + } + } +} + +// Teleglitter 2 ------------------------------------------------------------ + +class TeleGlitter2 : TeleGlitter1 +{ + States + { + Spawn: + TGLT F 2 BRIGHT; + TGLT G 2 BRIGHT A_AccTeleGlitter; + TGLT H 2 BRIGHT; + TGLT I 2 BRIGHT A_AccTeleGlitter; + TGLT J 2 BRIGHT; + Loop; + } +} + + +// --- Volcano -------------------------------------------------------------- + +class Volcano : Actor +{ + Default + { + Radius 12; + Height 20; + +SOLID + } + + States + { + Spawn: + VLCO A 350; + VLCO A 35 A_VolcanoSet; + VLCO BCDBCD 3; + VLCO E 10 A_VolcanoBlast; + Goto Spawn+1; + } + + //---------------------------------------------------------------------------- + // + // PROC A_VolcanoSet + // + //---------------------------------------------------------------------------- + + void A_VolcanoSet () + { + tics = 105 + (random[VolcanoSet]() & 127); + } + + //---------------------------------------------------------------------------- + // + // PROC A_VolcanoBlast + // + //---------------------------------------------------------------------------- + + void A_VolcanoBlast () + { + int count = random[VolcanoBlast](1,3); + for (int i = 0; i < count; i++) + { + Actor blast = Spawn("VolcanoBlast", pos + (0, 0, 44), ALLOW_REPLACE); + blast.target = self; + blast.Angle = random[VolcanoBlast]() * (360 / 256.); + blast.VelFromAngle(1.); + blast.Vel.Z = 2.5 + random[VolcanoBlast]() / 64.; + blast.A_PlaySound ("world/volcano/shoot", CHAN_BODY); + blast.CheckMissileSpawn (radius); + } + } +} + +// Volcano blast ------------------------------------------------------------ + +class VolcanoBlast : Actor +{ + Default + { + Radius 8; + Height 8; + Speed 2; + Damage 2; + DamageType "Fire"; + Gravity 0.125; + +NOBLOCKMAP +MISSILE +DROPOFF + +NOTELEPORT + DeathSound "world/volcano/blast"; + } + + States + { + Spawn: + VFBL AB 4 BRIGHT A_SpawnItemEx("Puffy", random2[BeastPuff]()*0.015625, random2[BeastPuff]()*0.015625, random2[BeastPuff]()*0.015625, + 0,0,0,0,SXF_ABSOLUTEPOSITION, 64); + Loop; + + Death: + XPL1 A 4 BRIGHT A_VolcBallImpact; + XPL1 BCDEF 4 BRIGHT; + Stop; + } + + //---------------------------------------------------------------------------- + // + // PROC A_VolcBallImpact + // + //---------------------------------------------------------------------------- + + void A_VolcBallImpact () + { + if (pos.Z <= floorz) + { + bNoGravity = true; + Gravity = 1; + AddZ(28); + } + A_Explode(25, 25, XF_NOSPLASH|XF_HURTSOURCE, false, 0, 0, 0, "BulletPuff", 'Fire'); + for (int i = 0; i < 4; i++) + { + Actor tiny = Spawn("VolcanoTBlast", Pos, ALLOW_REPLACE); + if (tiny) + { + tiny.target = self; + tiny.Angle = 90.*i; + tiny.VelFromAngle(0.7); + tiny.Vel.Z = 1. + random[VolcBallImpact]() / 128.; + tiny.CheckMissileSpawn (radius); + } + } + } +} + +// Volcano T Blast ---------------------------------------------------------- + +class VolcanoTBlast : Actor +{ + Default + { + Radius 8; + Height 6; + Speed 2; + Damage 1; + DamageType "Fire"; + Gravity 0.125; + +NOBLOCKMAP +MISSILE +DROPOFF + +NOTELEPORT + } + States + { + Spawn: + VTFB AB 4 BRIGHT; + Loop; + Death: + SFFI CBABCDE 4 BRIGHT; + Stop; + } +} + diff --git a/wadsrc/static/zscript/heretic/hereticplayer.txt b/wadsrc/static/zscript/heretic/hereticplayer.txt new file mode 100644 index 0000000000..26ff684f33 --- /dev/null +++ b/wadsrc/static/zscript/heretic/hereticplayer.txt @@ -0,0 +1,135 @@ +class HereticPlayer : PlayerPawn +{ + Default + { + Health 100; + Radius 16; + Height 56; + Mass 100; + Painchance 255; + Speed 1; + Player.DisplayName "Corvus"; + Player.StartItem "GoldWand"; + Player.StartItem "Staff"; + Player.StartItem "GoldWandAmmo", 50; + Player.WeaponSlot 1, "Staff", "Gauntlets"; + Player.WeaponSlot 2, "GoldWand"; + Player.WeaponSlot 3, "Crossbow"; + Player.WeaponSlot 4, "Blaster"; + Player.WeaponSlot 5, "SkullRod"; + Player.WeaponSlot 6, "PhoenixRod"; + Player.WeaponSlot 7, "Mace"; + + Player.ColorRange 225, 240; + Player.Colorset 0, "Green", 225, 240, 238; + Player.Colorset 1, "Yellow", 114, 129, 127; + Player.Colorset 2, "Red", 145, 160, 158; + Player.Colorset 3, "Blue", 190, 205, 203; + // Doom Legacy additions + Player.Colorset 4, "Brown", 67, 82, 80; + Player.Colorset 5, "Light Gray", 9, 24, 22; + Player.Colorset 6, "Light Brown", 74, 89, 87; + Player.Colorset 7, "Light Red", 150, 165, 163; + Player.Colorset 8, "Light Blue", 192, 207, 205; + Player.Colorset 9, "Beige", 95, 110, 108; + } + + States + { + Spawn: + PLAY A -1; + Stop; + See: + PLAY ABCD 4; + Loop; + Melee: + Missile: + PLAY F 6 BRIGHT; + PLAY E 12; + Goto Spawn; + Pain: + PLAY G 4; + PLAY G 4 A_Pain; + Goto Spawn; + Death: + PLAY H 6 A_PlayerSkinCheck("AltSkinDeath"); + PLAY I 6 A_PlayerScream; + PLAY JK 6; + PLAY L 6 A_NoBlocking; + PLAY MNO 6; + PLAY P -1; + Stop; + XDeath: + PLAY Q 0 A_PlayerSkinCheck("AltSkinXDeath"); + PLAY Q 5 A_PlayerScream; + PLAY R 0 A_NoBlocking; + PLAY R 5 A_SkullPop; + PLAY STUVWX 5; + PLAY Y -1; + Stop; + Burn: + FDTH A 5 BRIGHT A_PlaySound("*burndeath"); + FDTH B 4 BRIGHT; + FDTH C 5 BRIGHT; + FDTH D 4 BRIGHT A_PlayerScream; + FDTH E 5 BRIGHT; + FDTH F 4 BRIGHT; + FDTH G 5 BRIGHT A_PlaySound("*burndeath"); + FDTH H 4 BRIGHT; + FDTH I 5 BRIGHT; + FDTH J 4 BRIGHT; + FDTH K 5 BRIGHT; + FDTH L 4 BRIGHT; + FDTH M 5 BRIGHT; + FDTH N 4 BRIGHT; + FDTH O 5 BRIGHT A_NoBlocking; + FDTH P 4 BRIGHT; + FDTH Q 5 BRIGHT; + FDTH R 4 BRIGHT; + ACLO E 35 A_CheckPlayerDone; + Wait; + AltSkinDeath: + PLAY H 10; + PLAY I 10 A_PlayerScream; + PLAY J 10 A_NoBlocking; + PLAY KLM 10; + PLAY N -1; + Stop; + AltSkinXDeath: + PLAY O 5; + PLAY P 5 A_XScream; + PLAY Q 5 A_NoBlocking; + PLAY RSTUV 5; + PLAY W -1; + Stop; + } +} + +// The player's skull ------------------------------------------------------- + +class BloodySkull : PlayerChunk +{ + Default + { + Radius 4; + Height 4; + Gravity 0.125; + +NOBLOCKMAP + +DROPOFF + +CANNOTPUSH + +SKYEXPLODE + +NOBLOCKMONST + +NOSKIN + } + States + { + Spawn: + BSKL A 0; + BSKL ABCDE 5 A_CheckFloor("Hit"); + Goto Spawn+1; + Hit: + BSKL F 16 A_CheckPlayerDone; + Wait; + } +} + diff --git a/wadsrc/static/zscript/heretic/ironlich.txt b/wadsrc/static/zscript/heretic/ironlich.txt new file mode 100644 index 0000000000..8a4dd4c05c --- /dev/null +++ b/wadsrc/static/zscript/heretic/ironlich.txt @@ -0,0 +1,350 @@ + +// Ironlich ----------------------------------------------------------------- + +class Ironlich : Actor +{ + Default + { + Health 700; + Radius 40; + Height 72; + Mass 325; + Speed 6; + Painchance 32; + Monster; + +NOBLOOD + +DONTMORPH + +DONTSQUASH + +BOSSDEATH + SeeSound "ironlich/sight"; + AttackSound "ironlich/attack"; + PainSound "ironlich/pain"; + DeathSound "ironlich/death"; + ActiveSound "ironlich/active"; + Obituary "$OB_IRONLICH"; + HitObituary "$OB_IRONLICHHIT"; + DropItem "BlasterAmmo", 84, 10; + DropItem "ArtiEgg", 51, 0; + } + + + States + { + Spawn: + LICH A 10 A_Look; + Loop; + See: + LICH A 4 A_Chase; + Loop; + Missile: + LICH A 5 A_FaceTarget; + LICH B 20 A_LichAttack; + Goto See; + Pain: + LICH A 4; + LICH A 4 A_Pain; + Goto See; + Death: + LICH C 7; + LICH D 7 A_Scream; + LICH EF 7; + LICH G 7 A_NoBlocking; + LICH H 7; + LICH I -1 A_BossDeath; + Stop; + } + + //---------------------------------------------------------------------------- + // + // PROC A_LichAttack + // + //---------------------------------------------------------------------------- + + void A_LichAttack () + { + 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 + + if (target == null) + { + return; + } + A_FaceTarget (); + if (CheckMeleeRange ()) + { + int damage = random[LichAttack](1, 8) * 6; + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + return; + } + int dist = Distance2D(target) > 8 * 64; + int randAttack = random[LichAttack](); + if (randAttack < atkResolve1[dist]) + { // Ice ball + SpawnMissile (target, "HeadFX1"); + A_PlaySound ("ironlich/attack2", CHAN_BODY); + } + else if (randAttack < atkResolve2[dist]) + { // Fire column + Actor baseFire = SpawnMissile (target, "HeadFX3"); + if (baseFire != null) + { + baseFire.SetStateLabel("NoGrow"); + for (int i = 0; i < 5; i++) + { + Actor fire = Spawn("HeadFX3", baseFire.Pos, ALLOW_REPLACE); + if (i == 0) + { + A_PlaySound ("ironlich/attack1", CHAN_BODY); + } + fire.target = baseFire.target; + fire.angle = baseFire.angle; + fire.Vel = baseFire.Vel; + fire.SetDamage(0); + fire.health = (i+1) * 2; + fire.CheckMissileSpawn (radius); + } + } + } + else + { // Whirlwind + Actor mo = SpawnMissile (target, "Whirlwind"); + if (mo != null) + { + mo.AddZ(-32); + mo.tracer = target; + mo.health = 20*TICRATE; // Duration + A_PlaySound ("ironlich/attack3", CHAN_BODY); + } + } + } + +} + +// Head FX 1 ---------------------------------------------------------------- + +class HeadFX1 : Actor +{ + Default + { + Radius 12; + Height 6; + Speed 13; + FastSpeed 20; + Damage 1; + Projectile; + -ACTIVATEIMPACT + -ACTIVATEPCROSS + +THRUGHOST + RenderStyle "Add"; + } + + + States + { + Spawn: + FX05 ABC 6 BRIGHT; + Loop; + Death: + FX05 D 5 BRIGHT A_LichIceImpact; + FX05 EFG 5 BRIGHT; + Stop; + } + + //---------------------------------------------------------------------------- + // + // PROC A_LichIceImpact + // + //---------------------------------------------------------------------------- + + void A_LichIceImpact() + { + for (int i = 0; i < 8; i++) + { + Actor shard = Spawn("HeadFX2", Pos, ALLOW_REPLACE); + shard.target = target; + shard.angle = i*45.; + shard.VelFromAngle(); + shard.Vel.Z = -.6; + shard.CheckMissileSpawn (radius); + } + } +} + +// Head FX 2 ---------------------------------------------------------------- + +class HeadFX2 : Actor +{ + Default + { + Radius 12; + Height 6; + Speed 8; + Damage 3; + Projectile; + -ACTIVATEIMPACT + -ACTIVATEPCROSS + RenderStyle "Add"; + } + + States + { + Spawn: + FX05 HIJ 6 BRIGHT; + Loop; + Death: + FX05 DEFG 5 BRIGHT; + Stop; + } +} + + +// Head FX 3 ---------------------------------------------------------------- + +class HeadFX3 : Actor +{ + Default + { + Radius 14; + Height 12; + Speed 10; + FastSpeed 18; + Damage 5; + Projectile; + +WINDTHRUST + -ACTIVATEIMPACT + -ACTIVATEPCROSS + -NOBLOCKMAP + RenderStyle "Add"; + } + + States + { + Spawn: + FX06 ABC 4 BRIGHT A_LichFireGrow; + Loop; + NoGrow: + FX06 ABC 5 BRIGHT; + Loop; + Death: + FX06 DEFG 5 BRIGHT; + Stop; + } + + //---------------------------------------------------------------------------- + // + // PROC A_LichFireGrow + // + //---------------------------------------------------------------------------- + + void A_LichFireGrow () + { + health--; + AddZ(9.); + if (health == 0) + { + RestoreDamage(); + SetStateLabel("NoGrow"); + } + } +} + + +// Whirlwind ---------------------------------------------------------------- + +class Whirlwind : Actor +{ + Default + { + Radius 16; + Height 74; + Speed 10; + Damage 1; + Projectile; + -ACTIVATEIMPACT + -ACTIVATEMCROSS + +SEEKERMISSILE + +EXPLOCOUNT + +StepMissile + RenderStyle "Translucent"; + DefThreshold 60; + Threshold 50; + Alpha 0.4; + } + + States + { + Spawn: + FX07 DEFG 3; + FX07 ABC 3 A_WhirlwindSeek; + Goto Spawn+4; + Death: + FX07 GFED 4; + Stop; + } + + override int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + int randVal; + + if (!target.bDontThrust) + { + target.angle += Random2[WhirlwindDamage]() * (360 / 4096.); + target.Vel.X += Random2[WhirlwindDamage]() / 64.; + target.Vel.Y += Random2[WhirlwindDamage]() / 64.; + } + + if ((level.time & 16) && !target.bBoss && !target.bDontThrust) + { + randVal = min(160, random[WhirlwindSeek]()); + target.Vel.Z += randVal / 32.; + if (target.Vel.Z > 12) + { + target.Vel.Z = 12; + } + } + if (!(level.time & 7)) + { + target.DamageMobj (null, target, 3, 'Melee'); + } + return -1; + } + + //---------------------------------------------------------------------------- + // + // PROC A_WhirlwindSeek + // + //---------------------------------------------------------------------------- + + void A_WhirlwindSeek() + { + + health -= 3; + if (health < 0) + { + Vel = (0,0,0); + SetStateLabel("Death"); + bMissile = false; + return; + } + if ((threshold -= 3) < 0) + { + threshold = 58 + (random[WhirlwindSeek]() & 31); + A_PlaySound("ironlich/attack3", CHAN_BODY); + } + if (tracer && tracer.bShadow) + { + return; + } + A_SeekerMissile(10, 30); + } + +} + + + diff --git a/wadsrc/static/zscript/heretic/knight.txt b/wadsrc/static/zscript/heretic/knight.txt new file mode 100644 index 0000000000..01b7252c60 --- /dev/null +++ b/wadsrc/static/zscript/heretic/knight.txt @@ -0,0 +1,170 @@ + +// Knight ------------------------------------------------------------------- + +class Knight : Actor +{ + Default + { + Health 200; + Radius 24; + Height 78; + Mass 150; + Speed 12; + Painchance 100; + Monster; + +FLOORCLIP + SeeSound "hknight/sight"; + AttackSound "hknight/attack"; + PainSound "hknight/pain"; + DeathSound "hknight/death"; + ActiveSound "hknight/active"; + Obituary "$OB_BONEKNIGHT"; + HitObituary "$OB_BONEKNIGHTHIT"; + DropItem "CrossbowAmmo", 84, 5; + } + + States + { + Spawn: + KNIG AB 10 A_Look; + Loop; + See: + KNIG ABCD 4 A_Chase; + Loop; + Melee: + Missile: + KNIG E 10 A_FaceTarget; + KNIG F 8 A_FaceTarget; + KNIG G 8 A_KnightAttack; + KNIG E 10 A_FaceTarget; + KNIG F 8 A_FaceTarget; + KNIG G 8 A_KnightAttack; + Goto See; + Pain: + KNIG H 3; + KNIG H 3 A_Pain; + Goto See; + Death: + KNIG I 6; + KNIG J 6 A_Scream; + KNIG K 6; + KNIG L 6 A_NoBlocking; + KNIG MN 6; + KNIG O -1; + Stop; + } + + //---------------------------------------------------------------------------- + // + // PROC A_KnightAttack + // + //---------------------------------------------------------------------------- + + void A_KnightAttack () + { + if (!target) return; + if (CheckMeleeRange ()) + { + int damage = random[KnightAttack](1, 8) * 3; + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + A_PlaySound ("hknight/melee", CHAN_BODY); + return; + } + // Throw axe + A_PlaySound (AttackSound, CHAN_BODY); + if (self.bShadow || random[KnightAttack]() < 40) + { // Red axe + SpawnMissileZ (pos.Z + 36, target, "RedAxe"); + } + else + { // Green axe + SpawnMissileZ (pos.Z + 36, target, "KnightAxe"); + } + } +} + + +// Knight ghost ------------------------------------------------------------- + +class KnightGhost : Knight +{ + Default + { + +SHADOW + +GHOST + RenderStyle "Translucent"; + Alpha 0.4; + } +} + +// Knight axe --------------------------------------------------------------- + +class KnightAxe : Actor +{ + Default + { + Radius 10; + Height 8; + Speed 9; + FastSpeed 18; + Damage 2; + Projectile; + -NOBLOCKMAP + -ACTIVATEIMPACT + -ACTIVATEPCROSS + +WINDTHRUST + +THRUGHOST + DeathSound "hknight/hit"; + } + + States + { + Spawn: + SPAX A 3 BRIGHT A_PlaySound("hknight/axewhoosh"); + SPAX BC 3 BRIGHT; + Loop; + Death: + SPAX DEF 6 BRIGHT; + Stop; + } +} + + +// Red axe ------------------------------------------------------------------ + +class RedAxe : KnightAxe +{ + Default + { + +NOBLOCKMAP + -WINDTHRUST + Damage 7; + } + + States + { + Spawn: + RAXE AB 5 BRIGHT A_DripBlood; + Loop; + Death: + RAXE CDE 6 BRIGHT; + Stop; + } + + //---------------------------------------------------------------------------- + // + // PROC A_DripBlood + // + //---------------------------------------------------------------------------- + + void A_DripBlood () + { + double xo = random2[DripBlood]() / 32.0; + double yo = random2[DripBlood]() / 32.0; + Actor mo = Spawn ("Blood", Vec3Offset(xo, yo, 0.), ALLOW_REPLACE); + mo.Vel.X = random2[DripBlood]() / 64.0; + mo.Vel.Y = random2[DripBlood]() / 64.0; + mo.Gravity = 1./8; + } +} diff --git a/wadsrc/static/zscript/heretic/mummy.txt b/wadsrc/static/zscript/heretic/mummy.txt new file mode 100644 index 0000000000..6d01fcea42 --- /dev/null +++ b/wadsrc/static/zscript/heretic/mummy.txt @@ -0,0 +1,151 @@ + +// Mummy -------------------------------------------------------------------- + +class Mummy : Actor +{ + Default + { + Health 80; + Radius 22; + Height 62; + Mass 75; + Speed 12; + Painchance 128; + Monster; + +FLOORCLIP + SeeSound "mummy/sight"; + AttackSound "mummy/attack1"; + PainSound "mummy/pain"; + DeathSound "mummy/death"; + ActiveSound "mummy/active"; + HitObituary "$OB_MUMMY"; + DropItem "GoldWandAmmo", 84, 3; + } + States + { + Spawn: + MUMM AB 10 A_Look; + Loop; + See: + MUMM ABCD 4 A_Chase; + Loop; + Melee: + MUMM E 6 A_FaceTarget; + MUMM F 6 A_CustomMeleeAttack(random[MummyAttack](1,8)*2, "mummy/attack2", "mummy/attack"); + MUMM G 6; + Goto See; + Pain: + MUMM H 4; + MUMM H 4 A_Pain; + Goto See; + Death: + MUMM I 5; + MUMM J 5 A_Scream; + MUMM K 5 A_SpawnItemEx("MummySoul", 0,0,10, 0,0,1); + MUMM L 5; + MUMM M 5 A_NoBlocking; + MUMM NO 5; + MUMM P -1; + Stop; + } +} + +// Mummy leader ------------------------------------------------------------- + +class MummyLeader : Mummy +{ + Default + { + Species "MummyLeader"; + Health 100; + Painchance 64; + Obituary "$OB_MUMMYLEADER"; + } + States + { + Missile: + MUMM X 5 A_FaceTarget; + MUMM Y 5 Bright A_FaceTarget; + MUMM X 5 A_FaceTarget; + MUMM Y 5 Bright A_FaceTarget; + MUMM X 5 A_FaceTarget; + MUMM Y 5 Bright A_CustomComboAttack("MummyFX1", 32, random[MummyAttack2](1,8)*2, "mummy/attack2"); + Goto See; + } +} + +// Mummy ghost -------------------------------------------------------------- + +class MummyGhost : Mummy +{ + Default + { + +SHADOW + +GHOST + RenderStyle "Translucent"; + Alpha 0.4; + } +} + +// Mummy leader ghost ------------------------------------------------------- + +class MummyLeaderGhost : MummyLeader +{ + Default + { + Species "MummyLeaderGhost"; + +SHADOW + +GHOST + RenderStyle "Translucent"; + Alpha 0.4; + } +} + +// Mummy soul --------------------------------------------------------------- + +class MummySoul : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + } + States + { + Spawn: + MUMM QRS 5; + MUMM TUVW 9; + Stop; + } +} + +// Mummy FX 1 (flying head) ------------------------------------------------- + +class MummyFX1 : Actor +{ + Default + { + Radius 8; + Height 14; + Speed 9; + FastSpeed 18; + Damage 4; + RenderStyle "Add"; + Projectile; + -ACTIVATEPCROSS + -ACTIVATEIMPACT + +SEEKERMISSILE + } + States + { + Spawn: + FX15 A 5 Bright A_PlaySound("mummy/head"); + FX15 B 5 Bright A_SeekerMissile(10,20); + FX15 C 5 Bright; + FX15 B 5 Bright A_SeekerMissile(10,20); + Loop; + Death: + FX15 DEFG 5 Bright; + Stop; + } +} diff --git a/wadsrc/static/zscript/heretic/snake.txt b/wadsrc/static/zscript/heretic/snake.txt new file mode 100644 index 0000000000..613559a86c --- /dev/null +++ b/wadsrc/static/zscript/heretic/snake.txt @@ -0,0 +1,104 @@ + +class Snake : Actor +{ + Default + { + Health 280; + Radius 22; + Height 70; + Speed 10; + Painchance 48; + Monster; + +FLOORCLIP + AttackSound "snake/attack"; + SeeSound "snake/sight"; + PainSound "snake/pain"; + DeathSound "snake/death"; + ActiveSound "snake/active"; + Obituary "$OB_SNAKE"; + DropItem "PhoenixRodAmmo", 84, 5; + } + States + { + Spawn: + SNKE AB 10 A_Look; + Loop; + See: + SNKE ABCD 4 A_Chase; + Loop; + Missile: + SNKE FF 5 A_FaceTarget; + SNKE FFF 4 A_CustomMissile("SnakeProjA", 32, 0, 0, CMF_CHECKTARGETDEAD); + SNKE FFF 5 A_FaceTarget; + SNKE F 4 A_CustomMissile("SnakeProjB", 32, 0, 0, CMF_CHECKTARGETDEAD); + Goto See; + Pain: + SNKE E 3; + SNKE E 3 A_Pain; + Goto See; + Death: + SNKE G 5; + SNKE H 5 A_Scream; + SNKE IJKL 5; + SNKE M 5 A_NoBlocking; + SNKE NO 5; + SNKE P -1; + Stop; + } +} + +// Snake projectile A ------------------------------------------------------- + +class SnakeProjA : Actor +{ + Default + { + Radius 12; + Height 8; + Speed 14; + FastSpeed 20; + Damage 1; + Projectile; + -NOBLOCKMAP + -ACTIVATEIMPACT + -ACTIVATEPCROSS + +WINDTHRUST + +SPAWNSOUNDSOURCE + RenderStyle "Add"; + SeeSound "snake/attack"; + } + States + { + Spawn: + SNFX ABCD 5 Bright; + Loop; + Death: + SNFX EF 5 Bright; + SNFX G 4 Bright; + SNFX HI 3 Bright; + Stop; + } +} + +// Snake projectile B ------------------------------------------------------- + +class SnakeProjB : SnakeProjA +{ + Default + { + Damage 3; + +NOBLOCKMAP + -WINDTHRUST + } + States + { + Spawn: + SNFX JK 6 Bright; + Loop; + Death: + SNFX LM 5 Bright; + SNFX N 4 Bright; + SNFX O 3 Bright; + Stop; + } +} diff --git a/wadsrc/static/zscript/heretic/weaponblaster.txt b/wadsrc/static/zscript/heretic/weaponblaster.txt new file mode 100644 index 0000000000..8f4756b5b6 --- /dev/null +++ b/wadsrc/static/zscript/heretic/weaponblaster.txt @@ -0,0 +1,259 @@ +// Blaster ------------------------------------------------------------------ + +class Blaster : HereticWeapon +{ + Default + { + +BLOODSPLATTER + Weapon.SelectionOrder 500; + Weapon.AmmoUse 1; + Weapon.AmmoGive 30; + Weapon.YAdjust 15; + Weapon.AmmoType "BlasterAmmo"; + Weapon.SisterWeapon "BlasterPowered"; + Inventory.PickupMessage "$TXT_WPNBLASTER"; + Tag "$TAG_BLASTER"; + Obituary "$OB_MPBLASTER"; + } + + States + { + Spawn: + WBLS A -1; + Stop; + Ready: + BLSR A 1 A_WeaponReady; + Loop; + Deselect: + BLSR A 1 A_Lower; + Loop; + Select: + BLSR A 1 A_Raise; + Loop; + Fire: + BLSR BC 3; + Hold: + BLSR D 2 A_FireBlasterPL1; + BLSR CB 2; + BLSR A 0 A_ReFire; + Goto Ready; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FireBlasterPL1 + // + //---------------------------------------------------------------------------- + + action void A_FireBlasterPL1() + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + + double pitch = BulletSlope(); + int damage = random[FireBlaster](1, 8) * 4; + double ang = angle; + if (player.refire) + { + ang += Random2[FireBlaster]() * (5.625 / 256); + } + LineAttack (ang, PLAYERMISSILERANGE, pitch, damage, 'Hitscan', "BlasterPuff"); + A_PlaySound ("weapons/blastershoot", CHAN_WEAPON); + } +} + +class BlasterPowered : Blaster +{ + Default + { + +WEAPON.POWERED_UP + Weapon.AmmoUse 5; + Weapon.AmmoGive 0; + Weapon.SisterWeapon "Blaster"; + Tag "$TAG_BLASTERP"; + } + + States + { + Fire: + BLSR BC 0; + Hold: + BLSR D 3 A_FireCustomMissile("BlasterFX1"); + BLSR CB 4; + BLSR A 0 A_ReFire; + Goto Ready; + } +} + +// Blaster FX 1 ------------------------------------------------------------- + +class BlasterFX1 : FastProjectile +{ + Default + { + Radius 12; + Height 8; + Speed 184; + Damage 2; + SeeSound "weapons/blastershoot"; + DeathSound "weapons/blasterhit"; + +SPAWNSOUNDSOURCE + Obituary "$OB_MPPBLASTER"; + } + + States + { + Spawn: + ACLO E 200; + Loop; + Death: + FX18 A 3 BRIGHT A_SpawnRippers; + FX18 B 3 BRIGHT; + FX18 CDEFG 4 BRIGHT; + Stop; + } + + //---------------------------------------------------------------------------- + // + // + // + //---------------------------------------------------------------------------- + + override int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + if (target is "Ironlich") + { // Less damage to Ironlich bosses + damage = random[BlasterFX]() & 1; + if (!damage) + { + return -1; + } + } + return damage; + } + + override void Effect () + { + if (random[BlasterFX]() < 64) + { + Spawn("BlasterSmoke", (pos.xy, max(pos.z - 8, floorz)), ALLOW_REPLACE); + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_SpawnRippers + // + //---------------------------------------------------------------------------- + + void A_SpawnRippers() + { + for(int i = 0; i < 8; i++) + { + Actor ripper = Spawn("Ripper", pos, ALLOW_REPLACE); + ripper.target = target; + ripper.angle = i*45; + ripper.VelFromAngle(); + ripper.CheckMissileSpawn (radius); + } + } +} + +// Blaster smoke ------------------------------------------------------------ + +class BlasterSmoke : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + +NOTELEPORT + +CANNOTPUSH + RenderStyle "Translucent"; + Alpha 0.4; + } + + States + { + Spawn: + FX18 HIJKL 4; + Stop; + } +} + +// Ripper ------------------------------------------------------------------- + +class Ripper : Actor +{ + Default + { + Radius 8; + Height 6; + Speed 14; + Damage 1; + Projectile; + +RIPPER + DeathSound "weapons/blasterpowhit"; + Obituary "$OB_MPPBLASTER"; + } + + States + { + Spawn: + FX18 M 4; + FX18 N 5; + Loop; + Death: + FX18 OPQRS 4 BRIGHT; + Stop; + } + + int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + if (target is "Ironlich") + { // Less damage to Ironlich bosses + damage = random[Ripper]() & 1; + if (!damage) + { + return -1; + } + } + return damage; + } + +} + +// Blaster Puff ------------------------------------------------------------- + +class BlasterPuff : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + +PUFFONACTORS + RenderStyle "Add"; + SeeSound "weapons/blasterhit"; + } + + States + { + Crash: + FX17 ABCDE 4 BRIGHT; + Stop; + Spawn: + FX17 FG 3 BRIGHT; + FX17 HIJKL 4 BRIGHT; + Stop; + } +} + diff --git a/wadsrc/static/zscript/heretic/weaponcrossbow.txt b/wadsrc/static/zscript/heretic/weaponcrossbow.txt new file mode 100644 index 0000000000..bd5e9517ac --- /dev/null +++ b/wadsrc/static/zscript/heretic/weaponcrossbow.txt @@ -0,0 +1,208 @@ +// Crossbow ----------------------------------------------------------------- + +class Crossbow : HereticWeapon +{ + Default + { + Weapon.SelectionOrder 800; + Weapon.AmmoUse 1; + Weapon.AmmoGive 10; + Weapon.AmmoType "CrossbowAmmo"; + Weapon.SisterWeapon "CrossbowPowered"; + Weapon.YAdjust 15; + Inventory.PickupMessage "$TXT_WPNCROSSBOW"; + Tag "$TAG_CROSSBOW"; + } + + States + { + Spawn: + WBOW A -1; + Stop; + Ready: + CRBW AAAAAABBBBBBCCCCCC 1 A_WeaponReady; + Loop; + Deselect: + CRBW A 1 A_Lower; + Loop; + Select: + CRBW A 1 A_Raise; + Loop; + Fire: + CRBW D 6 A_FireCrossbowPL1; + CRBW EFGH 3; + CRBW AB 4; + CRBW C 5 A_ReFire; + Goto Ready; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FireCrossbowPL1 + // + //---------------------------------------------------------------------------- + + action void A_FireCrossbowPL1 () + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + SpawnPlayerMissile ("CrossbowFX1"); + SpawnPlayerMissile ("CrossbowFX3", angle - 4.5); + SpawnPlayerMissile ("CrossbowFX3", angle + 4.5); + } +} + + +class CrossbowPowered : Crossbow +{ + Default + { + +WEAPON.POWERED_UP + Weapon.AmmoGive 0; + Weapon.SisterWeapon "Crossbow"; + Tag "$TAG_CROSSBOWP"; + } + + States + { + Fire: + CRBW D 5 A_FireCrossbowPL2; + CRBW E 3; + CRBW F 2; + CRBW G 3; + CRBW H 2; + CRBW A 3; + CRBW B 3; + CRBW C 4 A_ReFire; + Goto Ready; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FireCrossbowPL2 + // + //---------------------------------------------------------------------------- + + action void A_FireCrossbowPL2() + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + SpawnPlayerMissile ("CrossbowFX2"); + SpawnPlayerMissile ("CrossbowFX2", angle - 4.5); + SpawnPlayerMissile ("CrossbowFX2", angle + 4.5); + SpawnPlayerMissile ("CrossbowFX3", angle - 9.); + SpawnPlayerMissile ("CrossbowFX3", angle + 9.); + } +} + + +// Crossbow FX1 ------------------------------------------------------------- + +class CrossbowFX1 : Actor +{ + Default + { + Radius 11; + Height 8; + Speed 30; + Damage 10; + Projectile; + RenderStyle "Add"; + SeeSound "weapons/bowshoot"; + DeathSound "weapons/bowhit"; + Obituary "$OB_MPCROSSBOW"; + } + + States + { + Spawn: + FX03 B 1 BRIGHT; + Loop; + Death: + FX03 HIJ 8 BRIGHT; + Stop; + } +} + + +// Crossbow FX2 ------------------------------------------------------------- + +class CrossbowFX2 : CrossbowFX1 +{ + Default + { + Speed 32; + Damage 6; + Obituary "$OB_MPPCROSSBOW"; + } + + States + { + Spawn: + FX03 B 1 BRIGHT A_SpawnItemEx("CrossbowFX4", random2[BoltSpark]()*0.015625, random2[BoltSpark]()*0.015625, 0, 0,0,0,0,SXF_ABSOLUTEPOSITION, 50); + Loop; + } +} + +// Crossbow FX3 ------------------------------------------------------------- + +class CrossbowFX3 : CrossbowFX1 +{ + Default + { + Speed 20; + Damage 2; + SeeSound ""; + -NOBLOCKMAP + +WINDTHRUST + +THRUGHOST + } + + States + { + Spawn: + FX03 A 1 BRIGHT; + Loop; + Death: + FX03 CDE 8 BRIGHT; + Stop; + } +} + +// Crossbow FX4 ------------------------------------------------------------- + +class CrossbowFX4 : Actor +{ + Default + { + +NOBLOCKMAP + Gravity 0.125; + RenderStyle "Add"; + } + + States + { + Spawn: + FX03 FG 8 BRIGHT; + Stop; + } +} + diff --git a/wadsrc/static/zscript/heretic/weapongauntlets.txt b/wadsrc/static/zscript/heretic/weapongauntlets.txt new file mode 100644 index 0000000000..d06efe4655 --- /dev/null +++ b/wadsrc/static/zscript/heretic/weapongauntlets.txt @@ -0,0 +1,210 @@ +// Gauntlets ---------------------------------------------------------------- + +class Gauntlets : Weapon +{ + Default + { + +BLOODSPLATTER + Weapon.SelectionOrder 2300; + +WEAPON.WIMPY_WEAPON + +WEAPON.MELEEWEAPON + Weapon.Kickback 0; + Weapon.YAdjust 15; + Weapon.UpSound "weapons/gauntletsactivate"; + Weapon.SisterWeapon "GauntletsPowered"; + Inventory.PickupMessage "$TXT_WPNGAUNTLETS"; + Tag "$TAG_GAUNTLETS"; + Obituary "$OB_MPGAUNTLETS"; + } + + States + { + Spawn: + WGNT A -1; + Stop; + Ready: + GAUN A 1 A_WeaponReady; + Loop; + Deselect: + GAUN A 1 A_Lower; + Loop; + Select: + GAUN A 1 A_Raise; + Loop; + Fire: + GAUN B 4 A_PlaySound("weapons/gauntletsuse", CHAN_WEAPON); + GAUN C 4; + Hold: + GAUN DEF 4 BRIGHT A_GauntletAttack(0); + GAUN C 4 A_ReFire; + GAUN B 4 A_Light0; + Goto Ready; + } + + //--------------------------------------------------------------------------- + // + // PROC A_GauntletAttack + // + //--------------------------------------------------------------------------- + + action void A_GauntletAttack (int power) + { + int damage; + double dist; + Class pufftype; + FTranslatedLineTarget t; + int actualdamage = 0; + Actor puff; + + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + + player.GetPSprite(PSP_WEAPON).x = ((random[GauntletAtk]() & 3) - 2); + player.GetPSprite(PSP_WEAPON).y = WEAPONTOP + (random[GauntletAtk]() & 3); + } + double ang = angle; + if (power) + { + damage = random[GauntletAtk](1, 8) * 2; + dist = 4*MELEERANGE; + ang += random2[GauntletAtk]() * (2.8125 / 256); + pufftype = "GauntletPuff2"; + } + else + { + damage = random[GauntletAtk](1, 8) * 2; + dist = SAWRANGE; + ang += random2[GauntletAtk]() * (5.625 / 256); + pufftype = "GauntletPuff1"; + } + double slope = AimLineAttack (ang, dist); + [puff, actualdamage] = LineAttack (ang, dist, slope, damage, 'Melee', pufftype, false, t); + if (!t.linetarget) + { + if (random[GauntletAtk]() > 64) + { + player.extralight = !player.extralight; + } + A_PlaySound ("weapons/gauntletson", CHAN_AUTO); + return; + } + int randVal = random[GauntletAtk](); + if (randVal < 64) + { + player.extralight = 0; + } + else if (randVal < 160) + { + player.extralight = 1; + } + else + { + player.extralight = 2; + } + if (power) + { + if (!t.linetarget.bDontDrain) GiveBody (actualdamage >> 1); + A_PlaySound ("weapons/gauntletspowhit", CHAN_AUTO); + } + else + { + A_PlaySound ("weapons/gauntletshit", CHAN_AUTO); + } + // turn to face target + ang = t.angleFromSource; + double anglediff = deltaangle(angle, ang); + + if (anglediff < 0.0) + { + if (anglediff < -4.5) + angle = ang + 90.0 / 21; + else + angle -= 4.5; + } + else + { + if (anglediff > 4.5) + angle = ang - 90.0 / 21; + else + angle += 4.5; + } + bJustAttacked = true; + } +} + + +class GauntletsPowered : Gauntlets +{ + Default + { + +WEAPON.POWERED_UP + Tag "$TAG_GAUNTLETSP"; + Obituary "$OB_MPPGAUNTLETS"; + Weapon.SisterWeapon "Gauntlets"; + } + + States + { + Ready: + GAUN GHI 4 A_WeaponReady; + Loop; + Deselect: + GAUN G 1 A_Lower; + Loop; + Select: + GAUN G 1 A_Raise; + Loop; + Fire: + GAUN J 4 A_PlaySound("weapons/gauntletsuse", CHAN_WEAPON); + GAUN K 4; + Hold: + GAUN LMN 4 BRIGHT A_GauntletAttack(1); + GAUN K 4 A_ReFire; + GAUN J 4 A_Light0; + Goto Ready; + } +} + + +// Gauntlet puff 1 ---------------------------------------------------------- + +class GauntletPuff1 : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + +PUFFONACTORS + RenderStyle "Translucent"; + Alpha 0.4; + VSpeed 0.8; + } + + States + { + Spawn: + PUF1 ABCD 4 BRIGHT; + Stop; + } +} + +// Gauntlet puff 2 --------------------------------------------------------- + +class GauntletPuff2 : GauntletPuff1 +{ + States + { + Spawn: + PUF1 EFGH 4 BRIGHT; + Stop; + } +} + diff --git a/wadsrc/static/zscript/heretic/weaponmace.txt b/wadsrc/static/zscript/heretic/weaponmace.txt new file mode 100644 index 0000000000..fd11e685fd --- /dev/null +++ b/wadsrc/static/zscript/heretic/weaponmace.txt @@ -0,0 +1,468 @@ +// The mace itself ---------------------------------------------------------- + +class Mace : HereticWeapon +{ + Default + { + Weapon.SelectionOrder 1400; + Weapon.AmmoUse 1; + Weapon.AmmoGive1 50; + Weapon.YAdjust 15; + Weapon.AmmoType "MaceAmmo"; + Weapon.SisterWeapon "MacePowered"; + Inventory.PickupMessage "$TXT_WPNMACE"; + Tag "$TAG_MACE"; + } + + States + { + Spawn: + WMCE A -1; + Stop; + Ready: + MACE A 1 A_WeaponReady; + Loop; + Deselect: + MACE A 1 A_Lower; + Loop; + Select: + MACE A 1 A_Raise; + Loop; + Fire: + MACE B 4; + Hold: + MACE CDEF 3 A_FireMacePL1; + MACE C 4 A_ReFire; + MACE DEFB 4; + Goto Ready; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FireMacePL1 + // + //---------------------------------------------------------------------------- + + action void A_FireMacePL1() + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + + if (random[MaceAtk]() < 28) + { + Actor ball = Spawn("MaceFX2", Pos + (0, 0, 28 - Floorclip), ALLOW_REPLACE); + ball.Vel.Z = 2 - clamp(tan(pitch), -5, 5); + ball.target = self; + ball.angle = self.angle; + ball.AddZ(ball.Vel.Z); + ball.VelFromAngle(); + ball.Vel += Vel.xy / 2; + ball.A_PlaySound ("weapons/maceshoot", CHAN_BODY); + ball.CheckMissileSpawn (radius); + } + else + { + player.GetPSprite(PSP_WEAPON).x = ((random[MaceAtk]() & 3) - 2); + player.GetPSprite(PSP_WEAPON).y = WEAPONTOP + (random[MaceAtk]() & 3); + Actor ball = SpawnPlayerMissile("MaceFX1", angle + (((random[MaceAtk]() & 7) - 4) * (360. / 256))); + if (ball) + { + ball.special1 = 16; // tics till dropoff + } + } + } +} + +class MacePowered : Mace +{ + Default + { + +WEAPON.POWERED_UP + Weapon.AmmoUse 5; + Weapon.AmmoGive 0; + Weapon.SisterWeapon "Mace"; + Tag "$TAG_MACEP"; + } + + States + { + Fire: + Hold: + MACE B 4; + MACE D 4 A_FireMacePL2; + MACE B 4; + MACE A 8 A_ReFire; + Goto Ready; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FireMacePL2 + // + //---------------------------------------------------------------------------- + + action void A_FireMacePL2() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + Actor mo = SpawnPlayerMissile ("MaceFX4", angle, pLineTarget:t); + if (mo) + { + mo.Vel.xy += Vel.xy; + mo.Vel.Z = 2 - clamp(tan(pitch), -5, 5); + if (t.linetarget && !t.unlinked) + { + mo.tracer = t.linetarget; + } + } + A_PlaySound ("weapons/maceshoot", CHAN_WEAPON); + } +} + +// Mace FX1 ----------------------------------------------------------------- + +class MaceFX1 : Actor +{ + const MAGIC_JUNK = 1234; + + Default + { + Radius 8; + Height 6; + Speed 20; + Damage 2; + Projectile; + +THRUGHOST + BounceType "HereticCompat"; + SeeSound "weapons/maceshoot"; + Obituary "$OB_MPMACE"; + } + + States + { + Spawn: + FX02 AB 4 A_MacePL1Check; + Loop; + Death: + FX02 F 4 BRIGHT A_MaceBallImpact; + FX02 GHIJ 4 BRIGHT; + Stop; + } + + //---------------------------------------------------------------------------- + // + // PROC A_MacePL1Check + // + //---------------------------------------------------------------------------- + + void A_MacePL1Check() + { + if (special1 == 0) return; + special1 -= 4; + if (special1 > 0) return; + special1 = 0; + bNoGravity = false; + Gravity = 1. / 8; + // [RH] Avoid some precision loss by scaling the velocity directly + double velscale = 7 / Vel.XY.Length(); + Vel.XY *= velscale; + Vel.Z *= 0.5; + } + + //---------------------------------------------------------------------------- + // + // PROC A_MaceBallImpact + // + //---------------------------------------------------------------------------- + + void A_MaceBallImpact() + { + if ((health != MAGIC_JUNK) && bInFloat) + { // Bounce + health = MAGIC_JUNK; + Vel.Z *= 0.75; + bBounceOnFloors = bBounceOnCeilings = false; + SetState (SpawnState); + A_PlaySound ("weapons/macebounce", CHAN_BODY); + } + else + { // Explode + Vel = (0,0,0); + bNoGravity = true; + Gravity = 1; + A_PlaySound ("weapons/macehit", CHAN_BODY); + } + } +} + +// Mace FX2 ----------------------------------------------------------------- + +class MaceFX2 : MaceFX1 +{ + Default + { + Speed 10; + Damage 6; + Gravity 0.125; + -NOGRAVITY + SeeSound ""; + } + + States + { + Spawn: + FX02 CD 4; + Loop; + Death: + FX02 F 4 A_MaceBallImpact2; + goto Super::Death+1; + } + + //---------------------------------------------------------------------------- + // + // PROC A_MaceBallImpact2 + // + //---------------------------------------------------------------------------- + + void A_MaceBallImpact2() + { + if ((pos.Z <= floorz) && HitFloor ()) + { // Landed in some sort of liquid + Destroy (); + return; + } + if (bInFloat) + { + if (Vel.Z >= 2) + { + // Bounce + Vel.Z *= 0.75; + SetState (SpawnState); + + Actor tiny = Spawn("MaceFX3", Pos, ALLOW_REPLACE); + tiny.target = target; + tiny.angle = angle + 90.; + tiny.VelFromAngle(Vel.Z - 1.); + tiny.Vel += (Vel.XY * .5, Vel.Z); + tiny.CheckMissileSpawn (radius); + + tiny = Spawn("MaceFX3", Pos, ALLOW_REPLACE); + tiny.target = target; + tiny.angle = angle - 90.; + tiny.VelFromAngle(Vel.Z - 1.); + tiny.Vel += (Vel.XY * .5, Vel.Z); + tiny.CheckMissileSpawn (radius); + return; + } + } + Vel = (0,0,0); + bNoGravity = true; + bBounceOnFloors = bBounceOnCeilings = false; + Gravity = 1; + } +} + +// Mace FX3 ----------------------------------------------------------------- + +class MaceFX3 : MaceFX1 +{ + Default + { + Speed 7; + Damage 4; + -NOGRAVITY; + Gravity 0.125; + } + + States + { + Spawn: + FX02 AB 4; + Loop; + } +} + + +// Mace FX4 ----------------------------------------------------------------- + +class MaceFX4 : Actor +{ + Default + { + Radius 8; + Height 6; + Speed 7; + Damage 18; + Gravity 0.125; + Projectile; + -NOGRAVITY + +TELESTOMP + +THRUGHOST + -NOTELEPORT + BounceType "HereticCompat"; + SeeSound ""; + Obituary "$OB_MPPMACE"; + } + + States + { + Spawn: + FX02 E 99; + Loop; + Death: + FX02 C 4 A_DeathBallImpact; + FX02 GHIJ 4 BRIGHT; + Stop; + } + + //--------------------------------------------------------------------------- + // + // FUNC P_AutoUseChaosDevice + // + //--------------------------------------------------------------------------- + + private bool AutoUseChaosDevice (PlayerInfo player) + { + Inventory arti = player.mo.FindInventory("ArtiTeleport"); + + if (arti != null) + { + player.mo.UseInventory (arti); + player.health = player.mo.health = (player.health+1)/2; + return true; + } + return false; + } + + //---------------------------------------------------------------------------- + // + // PROC DoSpecialDamage + // + //---------------------------------------------------------------------------- + + override int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + if (target.bBoss || target.bDontSquash || target.IsTeammate (self.target)) + { // Don't allow cheap boss kills and don't instagib teammates + return damage; + } + else if (target.player) + { // Player specific checks + if (target.player.mo.bInvulnerable) + { // Can't hurt invulnerable players + return -1; + } + if (AutoUseChaosDevice (target.player)) + { // Player was saved using chaos device + return -1; + } + } + return TELEFRAG_DAMAGE; // Something's gonna die + } + + //---------------------------------------------------------------------------- + // + // PROC A_DeathBallImpact + // + //---------------------------------------------------------------------------- + + void A_DeathBallImpact() + { + FTranslatedLineTarget t; + + if ((pos.Z <= floorz) && HitFloor ()) + { // Landed in some sort of liquid + Destroy (); + return; + } + if (bInFloat) + { + if (Vel.Z >= 2) + { + // Bounce + bool newAngle = false; + double ang = 0; + if (tracer) + { + if (!tracer.bShootable) + { // Target died + tracer = null; + } + else + { // Seek + ang = AngleTo(tracer); + newAngle = true; + } + } + else + { // Find new target + ang = 0.; + for (int i = 0; i < 16; i++) + { + AimLineAttack (ang, 640., t, 0., ALF_NOFRIENDS|ALF_PORTALRESTRICT, null, target); + if (t.linetarget && target != t.linetarget) + { + tracer = t.linetarget; + ang = t.angleFromSource; + newAngle = true; + break; + } + ang += 22.5; + } + } + if (newAngle) + { + angle = ang; + VelFromAngle(); + } + SetState (SpawnState); + A_PlaySound ("weapons/macestop", CHAN_BODY); + return; + } + } + Vel = (0,0,0); + bNoGravity = true; + Gravity = 1; + A_PlaySound ("weapons/maceexplode", CHAN_BODY); + } +} + + +// Mace spawn spot ---------------------------------------------------------- + +class MaceSpawner : SpecialSpot +{ + Default + { + +NOSECTOR + +NOBLOCKMAP + } + + States + { + Spawn: + TNT1 A 1; + TNT1 A -1 A_SpawnSingleItem("Mace", 64, 64, 0); + Stop; + } +} diff --git a/wadsrc/static/zscript/heretic/weaponphoenix.txt b/wadsrc/static/zscript/heretic/weaponphoenix.txt new file mode 100644 index 0000000000..6b949b8f61 --- /dev/null +++ b/wadsrc/static/zscript/heretic/weaponphoenix.txt @@ -0,0 +1,337 @@ +// Phoenix Rod -------------------------------------------------------------- + +class PhoenixRod : Weapon +{ + Default + { + +WEAPON.NOAUTOFIRE + Weapon.SelectionOrder 2600; + Weapon.Kickback 150; + Weapon.YAdjust 15; + Weapon.AmmoUse 1; + Weapon.AmmoGive 2; + Weapon.AmmoType "PhoenixRodAmmo"; + Weapon.Sisterweapon "PhoenixRodPowered"; + Inventory.PickupMessage "$TXT_WPNPHOENIXROD"; + Tag "$TAG_PHOENIXROD"; + } + + States + { + Spawn: + WPHX A -1; + Stop; + Ready: + PHNX A 1 A_WeaponReady; + Loop; + Deselect: + PHNX A 1 A_Lower; + Loop; + Select: + PHNX A 1 A_Raise; + Loop; + Fire: + PHNX B 5; + PHNX C 7 A_FirePhoenixPL1; + PHNX DB 4; + PHNX B 0 A_ReFire; + Goto Ready; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FirePhoenixPL1 + // + //---------------------------------------------------------------------------- + + action void A_FirePhoenixPL1() + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + SpawnPlayerMissile ("PhoenixFX1"); + Thrust(4, angle + 180); + } + + +} + +class PhoenixRodPowered : PhoenixRod +{ + const FLAME_THROWER_TICS = (10*TICRATE); + + private int FlameCount; // for flamethrower duration + + Default + { + +WEAPON.POWERED_UP + +WEAPON.MELEEWEAPON + Weapon.SisterWeapon "PhoenixRod"; + Weapon.AmmoGive 0; + Tag "$TAG_PHOENIXRODP"; + } + + States + { + Fire: + PHNX B 3 A_InitPhoenixPL2; + Hold: + PHNX C 1 A_FirePhoenixPL2; + PHNX B 4 A_ReFire; + Powerdown: + PHNX B 4 A_ShutdownPhoenixPL2; + Goto Ready; + } + + + override void EndPowerup () + { + DepleteAmmo (bAltFire); + Owner.player.refire = 0; + Owner.A_StopSound (CHAN_WEAPON); + Owner.player.ReadyWeapon = SisterWeapon; + Owner.player.SetPsprite(PSP_WEAPON, SisterWeapon.GetReadyState()); + } + + //---------------------------------------------------------------------------- + // + // PROC A_InitPhoenixPL2 + // + //---------------------------------------------------------------------------- + + action void A_InitPhoenixPL2() + { + if (player != null) + { + PhoenixRodPowered flamethrower = PhoenixRodPowered(player.ReadyWeapon); + if (flamethrower != null) + { + flamethrower.FlameCount = FLAME_THROWER_TICS; + } + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_FirePhoenixPL2 + // + // Flame thrower effect. + // + //---------------------------------------------------------------------------- + + action void A_FirePhoenixPL2() + { + if (player == null) + { + return; + } + + PhoenixRodPowered flamethrower = PhoenixRodPowered(player.ReadyWeapon); + + if (flamethrower == null || --flamethrower.FlameCount == 0) + { // Out of flame + player.SetPsprite(PSP_WEAPON, flamethrower.FindState("Powerdown")); + player.refire = 0; + A_StopSound (CHAN_WEAPON); + return; + } + + double slope = -clamp(tan(pitch), -5, 5); + double xo = Random2[FirePhoenixPL2]() / 128.; + double yo = Random2[FirePhoenixPL2]() / 128.; + Vector3 spawnpos = Vec3Offset(xo, yo, 26 + slope - Floorclip); + + slope += 0.1; + Actor mo = Spawn("PhoenixFX2", spawnpos, ALLOW_REPLACE); + mo.target = self; + mo.Angle = Angle; + mo.VelFromAngle(); + mo.Vel.XY += Vel.XY; + mo.Vel.Z = mo.Speed * slope; + if (!player.refire) + { + A_PlaySound("weapons/phoenixpowshoot", CHAN_WEAPON, 1, true); + } + mo.CheckMissileSpawn (radius); + } + + //---------------------------------------------------------------------------- + // + // PROC A_ShutdownPhoenixPL2 + // + //---------------------------------------------------------------------------- + + action void A_ShutdownPhoenixPL2() + { + if (player == null) + { + return; + } + A_StopSound (CHAN_WEAPON); + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + weapon.DepleteAmmo (weapon.bAltFire); + } + } + + +} + +// Phoenix FX 1 ------------------------------------------------------------- + +class PhoenixFX1 : Actor +{ + Default + { + Radius 11; + Height 8; + Speed 20; + Damage 20; + DamageType "Fire"; + Projectile; + +THRUGHOST + +SPECIALFIREDAMAGE + SeeSound "weapons/phoenixshoot"; + DeathSound "weapons/phoenixhit"; + Obituary "$OB_MPPHOENIXROD"; + } + + States + { + Spawn: + FX04 A 4 BRIGHT A_PhoenixPuff; + Loop; + Death: + FX08 A 6 BRIGHT A_Explode; + FX08 BC 5 BRIGHT; + FX08 DEFGH 4 BRIGHT; + Stop; + } + + override int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + Sorcerer2 s2 = Sorcerer2(target); + if (s2 != null && random[HornRodFX2]() < 96) + { // D'Sparil teleports away + s2.DSparilTeleport (); + return -1; + } + return damage; + } + + //---------------------------------------------------------------------------- + // + // PROC A_PhoenixPuff + // + //---------------------------------------------------------------------------- + + void A_PhoenixPuff() + { + //[RH] Heretic never sets the target for seeking + //P_SeekerMissile (self, 5, 10); + Actor puff = Spawn("PhoenixPuff", Pos, ALLOW_REPLACE); + puff.Vel.XY = AngleToVector(Angle + 90, 1.3); + + puff = Spawn("PhoenixPuff", Pos, ALLOW_REPLACE); + puff.Vel.XY = AngleToVector(Angle - 90, 1.3); + } + + +} + +// Phoenix puff ------------------------------------------------------------- + +class PhoenixPuff : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + +NOTELEPORT + +CANNOTPUSH + RenderStyle "Translucent"; + Alpha 0.4; + } + + States + { + Spawn: + FX04 BCDEF 4; + Stop; + } +} + +// Phoenix FX 2 ------------------------------------------------------------- + +class PhoenixFX2 : Actor +{ + Default + { + Radius 6; + Height 8; + Speed 10; + Damage 2; + DamageType "Fire"; + Projectile; + RenderStyle "Add"; + Obituary "$OB_MPPPHOENIXROD"; + } + + States + { + Spawn: + FX09 ABABA 2 BRIGHT; + FX09 B 2 BRIGHT A_FlameEnd; + FX09 CDEF 2 BRIGHT; + Stop; + Death: + FX09 G 3 BRIGHT; + FX09 H 3 BRIGHT A_FloatPuff; + FX09 I 4 BRIGHT; + FX09 JK 5 BRIGHT; + Stop; + } + + + int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + if (target.player && Random[PhoenixFX2]() < 128) + { // Freeze player for a bit + target.reactiontime += 4; + } + return damage; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FlameEnd + // + //---------------------------------------------------------------------------- + + void A_FlameEnd() + { + Vel.Z += 1.5; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FloatPuff + // + //---------------------------------------------------------------------------- + + void A_FloatPuff() + { + Vel.Z += 1.8; + } + + +} diff --git a/wadsrc/static/zscript/heretic/weaponskullrod.txt b/wadsrc/static/zscript/heretic/weaponskullrod.txt new file mode 100644 index 0000000000..a8d77e1d8c --- /dev/null +++ b/wadsrc/static/zscript/heretic/weaponskullrod.txt @@ -0,0 +1,425 @@ +// Skull (Horn) Rod --------------------------------------------------------- + +class SkullRod : HereticWeapon +{ + Default + { + Weapon.SelectionOrder 200; + Weapon.AmmoUse1 1; + Weapon.AmmoGive1 50; + Weapon.YAdjust 15; + Weapon.AmmoType1 "SkullRodAmmo"; + Weapon.SisterWeapon "SkullRodPowered"; + Inventory.PickupMessage "$TXT_WPNSKULLROD"; + Tag "$TAG_SKULLROD"; + } + + States + { + Spawn: + WSKL A -1; + Stop; + Ready: + HROD A 1 A_WeaponReady; + Loop; + Deselect: + HROD A 1 A_Lower; + Loop; + Select: + HROD A 1 A_Raise; + Loop; + Fire: + HROD AB 4 A_FireSkullRodPL1; + HROD B 0 A_ReFire; + Goto Ready; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FireSkullRodPL1 + // + //---------------------------------------------------------------------------- + + action void A_FireSkullRodPL1() + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + Actor mo = SpawnPlayerMissile ("HornRodFX1"); + // Randomize the first frame + if (mo && random[FireSkullRod]() > 128) + { + mo.SetState (mo.CurState.NextState); + } + } + + +} + +class SkullRodPowered : SkullRod +{ + Default + { + +WEAPON.POWERED_UP + Weapon.AmmoUse1 5; + Weapon.AmmoGive1 0; + Weapon.SisterWeapon "SkullRod"; + Tag "$TAG_SKULLRODP"; + } + + States + { + Fire: + HROD C 2; + HROD D 3; + HROD E 2; + HROD F 3; + HROD G 4 A_FireSkullRodPL2; + HROD F 2; + HROD E 3; + HROD D 2; + HROD C 2 A_ReFire; + Goto Ready; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FireSkullRodPL2 + // + // The special2 field holds the player number that shot the rain missile. + // The special1 field holds the id of the rain sound. + // + //---------------------------------------------------------------------------- + + action void A_FireSkullRodPL2() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + // Use MissileActor instead of the first return value from P_SpawnPlayerMissile + // because we need to give info to it, even if it exploded immediately. + Actor mo, MissileActor; + [mo, MissileActor] = SpawnPlayerMissile ("HornRodFX2", angle, pLineTarget: t); + if (MissileActor != null) + { + if (t.linetarget && !t.unlinked) + { + MissileActor.tracer = t.linetarget; + } + MissileActor.A_PlaySound ("weapons/hornrodpowshoot", CHAN_WEAPON); + } + } + + +} + +// Horn Rod FX 1 ------------------------------------------------------------ + +class HornRodFX1 : Actor +{ + Default + { + Radius 12; + Height 8; + Speed 22; + Damage 3; + Projectile; + +WINDTHRUST + -NOBLOCKMAP + RenderStyle "Add"; + SeeSound "weapons/hornrodshoot"; + DeathSound "weapons/hornrodhit"; + Obituary "$OB_MPSKULLROD"; + } + + States + { + Spawn: + FX00 AB 6 BRIGHT; + Loop; + Death: + FX00 HI 5 BRIGHT; + FX00 JK 4 BRIGHT; + FX00 LM 3 BRIGHT; + Stop; + } +} + + +// Horn Rod FX 2 ------------------------------------------------------------ + +class HornRodFX2 : Actor +{ + Default + { + Radius 12; + Height 8; + Speed 22; + Damage 10; + Health 140; + Projectile; + RenderStyle "Add"; + SeeSound "weapons/hornrodpowshoot"; + DeathSound "weapons/hornrodpowhit"; + Obituary "$OB_MPPSKULLROD"; + } + + States + { + Spawn: + FX00 C 3 BRIGHT; + FX00 D 3 BRIGHT A_SeekerMissile(10, 30); + FX00 E 3 BRIGHT; + FX00 F 3 BRIGHT A_SeekerMissile(10, 30); + Loop; + Death: + FX00 H 5 BRIGHT A_AddPlayerRain; + FX00 I 5 BRIGHT; + FX00 J 4 BRIGHT; + FX00 KLM 3 BRIGHT; + FX00 G 1 A_HideInCeiling; + FX00 G 1 A_SkullRodStorm; + Wait; + } + + override int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + Sorcerer2 s2 = Sorcerer2(target); + if (s2 != null && random[HornRodFX2]() < 96) + { // D'Sparil teleports away + s2.DSparilTeleport (); + return -1; + } + return damage; + } + + //---------------------------------------------------------------------------- + // + // PROC A_AddPlayerRain + // + //---------------------------------------------------------------------------- + + void A_AddPlayerRain() + { + RainTracker tracker; + + if (target == null || target.health <= 0) + { // Shooter is dead or nonexistant + return; + } + + tracker = RainTracker(target.FindInventory("RainTracker")); + + // They player is only allowed two rainstorms at a time. Shooting more + // than that will cause the oldest one to terminate. + if (tracker != null) + { + if (tracker.Rain1 && tracker.Rain2) + { // Terminate an active rain + if (tracker.Rain1.health < tracker.Rain2.health) + { + if (tracker.Rain1.health > 16) + { + tracker.Rain1.health = 16; + } + tracker.Rain1 = null; + } + else + { + if (tracker.Rain2.health > 16) + { + tracker.Rain2.health = 16; + } + tracker.Rain2 = null; + } + } + } + else + { + tracker = RainTracker(target.GiveInventoryType("RainTracker")); + } + // Add rain mobj to list + if (tracker.Rain1) + { + tracker.Rain2 = self; + } + else + { + tracker.Rain1 = self; + } + ActiveSound = "misc/rain"; + } + + //---------------------------------------------------------------------------- + // + // PROC A_HideInCeiling + // + //---------------------------------------------------------------------------- + + void A_HideInCeiling() + { + // This no longer hides in the ceiling. It just makes the actor invisible and keeps it in place. + // We need its actual position to determine the correct ceiling height in A_SkullRodStorm. + bInvisible = true; + bSolid = false; + bMissile = false; + Vel = (0,0,0); + } + + //---------------------------------------------------------------------------- + // + // PROC A_SkullRodStorm + // + //---------------------------------------------------------------------------- + + void A_SkullRodStorm() + { + static const Name translations[] = + { + "RainPillar1", "RainPillar2", "RainPillar3", "RainPillar4", + "RainPillar5", "RainPillar6", "RainPillar7", "RainPillar8" + }; + + if (health-- == 0) + { + A_StopSound (CHAN_BODY); + if (target == null) + { // Player left the game + Destroy (); + return; + } + RainTracker tracker = RainTracker(target.FindInventory("RainTracker")); + if (tracker != null) + { + if (tracker.Rain1 == self) + { + tracker.Rain1 = null; + } + else if (tracker.Rain2 == self) + { + tracker.Rain2 = null; + } + } + Destroy (); + return; + } + if (Random[SkullRodStorm]() < 25) + { // Fudge rain frequency + return; + } + double xo = ((Random[SkullRodStorm]() & 127) - 64); + double yo = ((Random[SkullRodStorm]() & 127) - 64); + Vector3 spawnpos = Vec2OffsetZ(xo, yo, pos.z); + Actor mo = Spawn("RainPillar", spawnpos, ALLOW_REPLACE); + if (!mo) return; + + // Find the ceiling above the spawn location. This may come from 3D floors but will not reach through portals. + // (should probably be fixed for portals, too.) + double newz = mo.CurSector.NextHighestCeilingAt(mo.pos.x, mo.pos.y, mo.pos.z, mo.pos.z, FFCF_NOPORTALS) - mo.height; + mo.SetZ(newz); + + if (multiplayer && target.player) + { + mo.A_SetTranslation(translations[target.PlayerNumber()]); + } + mo.target = target; + mo.Vel.X = MinVel; // Force collision detection + mo.Vel.Z = -mo.Speed; + mo.CheckMissileSpawn (radius); + if (ActiveSound > 0) A_PlaySound(ActiveSound, CHAN_BODY, 1, true); + } + + +} + +// Rain pillar 1 ------------------------------------------------------------ + +class RainPillar : Actor +{ + Default + { + Radius 5; + Height 12; + Speed 12; + Damage 5; + Mass 5; + Projectile; + -ACTIVATEPCROSS + -ACTIVATEIMPACT + RenderStyle "Add"; + Obituary "$OB_MPPSKULLROD"; + } + + States + { + Spawn: + FX22 A -1 BRIGHT; + Stop; + Death: + FX22 B 4 BRIGHT A_RainImpact; + FX22 CDEF 4 BRIGHT; + Stop; + NotFloor: + FX22 GHI 4 BRIGHT; + Stop; + } + + //---------------------------------------------------------------------------- + // + // PROC A_RainImpact + // + //---------------------------------------------------------------------------- + + void A_RainImpact() + { + if (pos.z > floorz) + { + SetStateLabel("NotFloor"); + } + else if (random[RainImpact]() < 40) + { + HitFloor (); + } + } + + // Rain pillar 1 ------------------------------------------------------------ + + int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + if (target.bBoss) + { // Decrease damage for bosses + damage = random[RainDamage](1, 8); + } + return damage; + } +} + +// Rain tracker "inventory" item -------------------------------------------- + +class RainTracker : Inventory +{ + Actor Rain1, Rain2; + + Default + { + +INVENTORY.UNDROPPABLE + } +} diff --git a/wadsrc/static/zscript/heretic/weaponstaff.txt b/wadsrc/static/zscript/heretic/weaponstaff.txt new file mode 100644 index 0000000000..6349bd61bb --- /dev/null +++ b/wadsrc/static/zscript/heretic/weaponstaff.txt @@ -0,0 +1,147 @@ +// Staff -------------------------------------------------------------------- + +class Staff : HereticWeapon +{ + Default + { + Weapon.SelectionOrder 3800; + +THRUGHOST + +WEAPON.WIMPY_WEAPON + +WEAPON.MELEEWEAPON + Weapon.sisterweapon "StaffPowered"; + Obituary "$OB_MPSTAFF"; + Tag "$TAG_STAFF"; + } + + + States + { + Ready: + STFF A 1 A_WeaponReady; + Loop; + Deselect: + STFF A 1 A_Lower; + Loop; + Select: + STFF A 1 A_Raise; + Loop; + Fire: + STFF B 6; + STFF C 8 A_StaffAttack(random[StaffAttack](5, 20), "StaffPuff"); + STFF B 8 A_ReFire; + Goto Ready; + } + + //---------------------------------------------------------------------------- + // + // PROC A_StaffAttackPL1 + // + //---------------------------------------------------------------------------- + + action void A_StaffAttack (int damage, class puff) + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + double ang = angle + Random2[StaffAtk]() * (5.625 / 256); + double slope = AimLineAttack (ang, MELEERANGE); + LineAttack (ang, MELEERANGE, slope, damage, 'Melee', puff, true, t); + if (t.linetarget) + { + //S_StartSound(player.mo, sfx_stfhit); + // turn to face target + angle = t.angleFromSource; + } + } +} + +class StaffPowered : Staff +{ + Default + { + Weapon.sisterweapon "Staff"; + Weapon.ReadySound "weapons/staffcrackle"; + +WEAPON.POWERED_UP + +WEAPON.READYSNDHALF + +WEAPON.STAFF2_KICKBACK + Obituary "$OB_MPPSTAFF"; + Tag "$TAG_STAFFP"; + } + + States + { + Ready: + STFF DEF 4 A_WeaponReady; + Loop; + Deselect: + STFF D 1 A_Lower; + Loop; + Select: + STFF D 1 A_Raise; + Loop; + Fire: + STFF G 6; + STFF H 8 A_StaffAttack(random[StaffAttack](18, 81), "StaffPuff2"); + STFF G 8 A_ReFire; + Goto Ready; + } +} + + +// Staff puff --------------------------------------------------------------- + +class StaffPuff : Actor +{ + Default + { + RenderStyle "Translucent"; + Alpha 0.4; + VSpeed 1; + +NOBLOCKMAP + +NOGRAVITY + +PUFFONACTORS + AttackSound "weapons/staffhit"; + } + + States + { + Spawn: + PUF3 A 4 BRIGHT; + PUF3 BCD 4; + Stop; + } +} + +// Staff puff 2 ------------------------------------------------------------- + +class StaffPuff2 : Actor +{ + Default + { + RenderStyle "Add"; + +NOBLOCKMAP + +NOGRAVITY + +PUFFONACTORS + AttackSound "weapons/staffpowerhit"; + } + + States + { + Spawn: + PUF4 ABCDEF 4 BRIGHT; + Stop; + } +} + + + diff --git a/wadsrc/static/zscript/heretic/weaponwand.txt b/wadsrc/static/zscript/heretic/weaponwand.txt new file mode 100644 index 0000000000..9516aa76c1 --- /dev/null +++ b/wadsrc/static/zscript/heretic/weaponwand.txt @@ -0,0 +1,217 @@ +// Gold wand ---------------------------------------------------------------- + +class GoldWand : HereticWeapon +{ + Default + { + +BLOODSPLATTER + Weapon.SelectionOrder 2000; + Weapon.AmmoGive 25; + Weapon.AmmoUse 1; + Weapon.AmmoType "GoldWandAmmo"; + Weapon.SisterWeapon "GoldWandPowered"; + Weapon.YAdjust 5; + Inventory.PickupMessage "$TXT_WPNGOLDWAND"; + Obituary "$OB_MPGOLDWAND"; + Tag "$TAG_GOLDWAND"; + } + + States + { + Spawn: + GWAN A -1; + Stop; + Ready: + GWND A 1 A_WeaponReady; + Loop; + Deselect: + GWND A 1 A_Lower; + Loop; + Select: + GWND A 1 A_Raise; + Loop; + Fire: + GWND B 3; + GWND C 5 A_FireGoldWandPL1; + GWND D 3; + GWND D 0 A_ReFire; + Goto Ready; + } + + + //---------------------------------------------------------------------------- + // + // PROC A_FireGoldWandPL1 + // + //---------------------------------------------------------------------------- + + action void A_FireGoldWandPL1 () + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + double pitch = BulletSlope(); + int damage = 7 + (random[FireGoldWand]() & 7); + double ang = angle; + if (player.refire) + { + ang += Random2[FireGoldWand]() * (5.625 / 256); + } + LineAttack(ang, PLAYERMISSILERANGE, pitch, damage, 'Hitscan', "GoldWandPuff1"); + A_PlaySound("weapons/wandhit", CHAN_WEAPON); + } + +} + +class GoldWandPowered : GoldWand +{ + Default + { + +WEAPON.POWERED_UP + Weapon.AmmoGive 0; + Weapon.SisterWeapon "GoldWand"; + Obituary "$OB_MPPGOLDWAND"; + Tag "$TAG_GOLDWANDP"; + } + + States + { + Fire: + GWND B 3; + GWND C 4 A_FireGoldWandPL2; + GWND D 3; + GWND D 0 A_ReFire; + Goto Ready; + } + + //---------------------------------------------------------------------------- + // + // PROC A_FireGoldWandPL2 + // + //---------------------------------------------------------------------------- + + action void A_FireGoldWandPL2 () + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + double pitch = BulletSlope(); + + double vz = -GetDefaultByType("GoldWandFX2").Speed * clamp(tan(pitch), -5, 5); + SpawnMissileAngle("GoldWandFX2", angle - (45. / 8), vz); + SpawnMissileAngle("GoldWandFX2", angle + (45. / 8), vz); + double ang = angle - (45. / 8); + for(int i = 0; i < 5; i++) + { + int damage = random[FireGoldWand](1, 8); + LineAttack (ang, PLAYERMISSILERANGE, pitch, damage, 'Hitscan', "GoldWandPuff2"); + ang += ((45. / 8) * 2) / 4; + } + A_PlaySound("weapons/wandhit", CHAN_WEAPON); + } + + +} + + +// Gold wand FX1 ------------------------------------------------------------ + +class GoldWandFX1 : Actor +{ + Default + { + Radius 10; + Height 6; + Speed 22; + Damage 2; + Projectile; + RenderStyle "Add"; + DeathSound "weapons/wandhit"; + Obituary "$OB_MPPGOLDWAND"; + } + + States + { + Spawn: + FX01 AB 6 BRIGHT; + Loop; + Death: + FX01 EFGH 3 BRIGHT; + Stop; + } +} + +// Gold wand FX2 ------------------------------------------------------------ + +class GoldWandFX2 : GoldWandFX1 +{ + Default + { + Speed 18; + Damage 1; + DeathSound ""; + } + + States + { + Spawn: + FX01 CD 6 BRIGHT; + Loop; + } +} + +// Gold wand puff 1 --------------------------------------------------------- + +class GoldWandPuff1 : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + +PUFFONACTORS + RenderStyle "Add"; + } + + States + { + Spawn: + PUF2 ABCDE 3 BRIGHT; + Stop; + } +} + +// Gold wand puff 2 --------------------------------------------------------- + +class GoldWandPuff2 : GoldWandFX1 +{ + Default + { + Skip_Super; + +NOBLOCKMAP + +NOGRAVITY + +PUFFONACTORS + } + + States + { + Spawn: + Goto Super::Death; + } +} + diff --git a/wadsrc/static/zscript/heretic/wizard.txt b/wadsrc/static/zscript/heretic/wizard.txt new file mode 100644 index 0000000000..d146ae2203 --- /dev/null +++ b/wadsrc/static/zscript/heretic/wizard.txt @@ -0,0 +1,162 @@ + +// Wizard -------------------------------------------------------- + +class Wizard : Actor +{ + Default + { + Health 180; + Radius 16; + Height 68; + Mass 100; + Speed 12; + Painchance 64; + Monster; + +FLOAT + +NOGRAVITY + +DONTOVERLAP + SeeSound "wizard/sight"; + AttackSound "wizard/attack"; + PainSound "wizard/pain"; + DeathSound "wizard/death"; + ActiveSound "wizard/active"; + Obituary "$OB_WIZARD"; + HitObituary "$OB_WIZARDHIT"; + DropItem "BlasterAmmo", 84, 10; + DropItem "ArtiTomeOfPower", 4, 0; + } + + States + { + Spawn: + WZRD AB 10 A_Look; + Loop; + See: + WZRD A 3 A_Chase; + WZRD A 4 A_Chase; + WZRD A 3 A_Chase; + WZRD A 4 A_Chase; + WZRD B 3 A_Chase; + WZRD B 4 A_Chase; + WZRD B 3 A_Chase; + WZRD B 4 A_Chase; + Loop; + Missile: + WZRD C 4 A_WizAtk1; + WZRD C 4 A_WizAtk2; + WZRD C 4 A_WizAtk1; + WZRD C 4 A_WizAtk2; + WZRD C 4 A_WizAtk1; + WZRD C 4 A_WizAtk2; + WZRD C 4 A_WizAtk1; + WZRD C 4 A_WizAtk2; + WZRD D 12 A_WizAtk3; + Goto See; + Pain: + WZRD E 3 A_GhostOff; + WZRD E 3 A_Pain; + Goto See; + Death: + WZRD F 6 A_GhostOff; + WZRD G 6 A_Scream; + WZRD HI 6; + WZRD J 6 A_NoBlocking; + WZRD KL 6; + WZRD M -1 A_SetFloorClip; + Stop; + } + + //---------------------------------------------------------------------------- + // + // PROC A_GhostOff + // + //---------------------------------------------------------------------------- + + void A_GhostOff () + { + A_SetRenderStyle(1.0, STYLE_Normal); + bGhost = false; + } + + //---------------------------------------------------------------------------- + // + // PROC A_WizAtk1 + // + //---------------------------------------------------------------------------- + + void A_WizAtk1 () + { + A_FaceTarget (); + A_GhostOff(); + } + + //---------------------------------------------------------------------------- + // + // PROC A_WizAtk2 + // + //---------------------------------------------------------------------------- + + void A_WizAtk2 () + { + A_FaceTarget (); + A_SetRenderStyle(HR_SHADOW, STYLE_Translucent); + bGhost = true; + } + + //---------------------------------------------------------------------------- + // + // PROC A_WizAtk3 + // + //---------------------------------------------------------------------------- + + void A_WizAtk3 () + { + A_GhostOff(); + if (!target) return; + A_PlaySound (AttackSound, CHAN_WEAPON); + if (CheckMeleeRange()) + { + int damage = random[WizAtk3](1, 8) * 4; + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + return; + } + Actor mo = SpawnMissile (target, "WizardFX1"); + if (mo != null) + { + SpawnMissileAngle("WizardFX1", mo.Angle - 45. / 8, mo.Vel.Z); + SpawnMissileAngle("WizardFX1", mo.Angle + 45. / 8, mo.Vel.Z); + } + } + +} + +// Projectile -------------------------------------------------------- + +class WizardFX1 : Actor +{ + Default + { + Radius 10; + Height 6; + Speed 18; + FastSpeed 24; + Damage 3; + Projectile; + -ACTIVATEIMPACT + -ACTIVATEPCROSS + RenderStyle "Add"; + } + + States + { + Spawn: + FX11 AB 6 BRIGHT; + Loop; + Death: + FX11 CDEFG 5 BRIGHT; + Stop; + } +} + + diff --git a/wadsrc/static/zscript/hexen/baseweapons.txt b/wadsrc/static/zscript/hexen/baseweapons.txt new file mode 100644 index 0000000000..f087946485 --- /dev/null +++ b/wadsrc/static/zscript/hexen/baseweapons.txt @@ -0,0 +1,80 @@ +// The Doom and Heretic players are not excluded from pickup in case +// somebody wants to use these weapons with either of those games. + +class FighterWeapon : Weapon +{ + Default + { + Weapon.Kickback 150; + Inventory.ForbiddenTo "ClericPlayer", "MagePlayer"; + } +} + +class ClericWeapon : Weapon +{ + Default + { + Weapon.Kickback 150; + Inventory.ForbiddenTo "FighterPlayer", "MagePlayer"; + } +} + +class MageWeapon : Weapon +{ + Default + { + Weapon.Kickback 150; + Inventory.ForbiddenTo "FighterPlayer", "ClericPlayer"; + } +} + +extend class Actor +{ + //============================================================================ + // + // AdjustPlayerAngle + // + //============================================================================ + + const MAX_ANGLE_ADJUST = (5.); + + void AdjustPlayerAngle(FTranslatedLineTarget t) + { + double difference = t.angleFromSource; + if (abs(difference) > MAX_ANGLE_ADJUST) + { + if (difference > 0) + { + angle += MAX_ANGLE_ADJUST; + } + else + { + angle -= MAX_ANGLE_ADJUST; + } + } + else + { + angle = t.angleFromSource; + } + } + + //============================================================================ + // + // A_DropQuietusPieces + // + //============================================================================ + + void A_DropWeaponPieces(class p1, class p2, class p3) + { + for (int i = 0, j = 0; i < 3; ++i) + { + Actor piece = Spawn (j == 0 ? p1 : j == 1 ? p2 : p3, Pos, ALLOW_REPLACE); + if (piece != null) + { + piece.Vel = self.Vel + AngleToVector(i * 120., 1); + piece.bDropped = true; + j = (j == 0) ? (random[PieceDrop]() & 1) + 1 : 3-j; + } + } + } +} \ No newline at end of file diff --git a/wadsrc/static/zscript/hexen/bats.txt b/wadsrc/static/zscript/hexen/bats.txt new file mode 100644 index 0000000000..aaefaaeb70 --- /dev/null +++ b/wadsrc/static/zscript/hexen/bats.txt @@ -0,0 +1,125 @@ + +// Bat Spawner -------------------------------------------------------------- + +class BatSpawner : SwitchableDecoration +{ + Default + { + +NOBLOCKMAP +NOSECTOR +NOGRAVITY + RenderStyle "None"; + } + + States + { + Spawn: + Active: + TNT1 A 2; + TNT1 A 2 A_BatSpawnInit; + TNT1 A 2 A_BatSpawn; + Wait; + Inactive: + TNT1 A -1; + Stop; + } + + //=========================================================================== + // 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) + //=========================================================================== + + void A_BatSpawnInit() + { + special1 = 0; // Frequency count + } + + void A_BatSpawn() + { + // Countdown until next spawn + if (special1-- > 0) return; + special1 = args[0]; // Reset frequency count + + int delta = args[1]; + if (delta == 0) delta = 1; + + double ang = Angle + (((random[BatSpawn]() % delta) - (delta >> 1)) * (360 / 256.)); + + Actor mo = SpawnMissileAngle ("Bat", ang, 0); + if (mo) + { + mo.args[0] = random[BatSpawn]() & 63; // floatbob index + mo.args[4] = args[4]; // turn degrees + mo.special2 = args[3] << 3; // Set lifetime + mo.target = self; + } + } + +} + +// Bat ---------------------------------------------------------------------- + +class Bat : Actor +{ + Default + { + Speed 5; + Radius 3; + Height 3; + +NOBLOCKMAP +NOGRAVITY +MISSILE + +NOTELEPORT +CANPASS + } + + States + { + Spawn: + ABAT ABC 2 A_BatMove; + Loop; + Death: + ABAT A 2; + Stop; + } + + void A_BatMove() + { + if (special2 < 0) + { + SetStateLabel ("Death"); + } + special2 -= 2; // Called every 2 tics + + double newangle; + if (random[BatMove]() < 128) + { + newangle = Angle + args[4]; + } + else + { + newangle = Angle - args[4]; + } + + // Adjust velocity vector to new direction + VelFromAngle(Speed, newangle); + + if (random[BatMove]() < 15) + { + A_PlaySound ("BatScream", CHAN_VOICE, 1, false, ATTN_IDLE); + } + + // Handle Z movement + SetZ(target.pos.Z + 2 * BobSin(args[0])); + args[0] = (args[0] + 3) & 63; + } +} + + + + diff --git a/wadsrc/static/zscript/hexen/bishop.txt b/wadsrc/static/zscript/hexen/bishop.txt new file mode 100644 index 0000000000..32f0f3e633 --- /dev/null +++ b/wadsrc/static/zscript/hexen/bishop.txt @@ -0,0 +1,328 @@ + +// Bishop ------------------------------------------------------------------- + +class Bishop : Actor +{ + int missilecount; + int bobstate; + + Default + { + Health 130; + Radius 22; + Height 65; + Speed 10; + PainChance 110; + Monster; + +FLOAT +NOGRAVITY +NOBLOOD + +TELESTOMP + +DONTOVERLAP + +NOTARGETSWITCH + SeeSound "BishopSight"; + AttackSound "BishopAttack"; + PainSound "BishopPain"; + DeathSound "BishopDeath"; + ActiveSound "BishopActiveSounds"; + Obituary"$OB_BISHOP"; + } + + States + { + Spawn: + BISH A 10 A_Look; + Loop; + See: + BISH A 2 A_Chase; + BISH A 2 A_BishopChase; + BISH A 2; + BISH B 2 A_BishopChase; + BISH B 2 A_Chase; + BISH B 2 A_BishopChase; + BISH A 1 A_BishopDecide; + Loop; + Blur: + BISH A 2 A_BishopDoBlur; + BISH A 4 A_BishopSpawnBlur; + Wait; + Pain: + BISH C 6 A_Pain; + BISH CCC 6 A_BishopPainBlur; + BISH C 0; + Goto See; + Missile: + BISH A 3 A_FaceTarget; + BISH DE 3 A_FaceTarget; + BISH F 3 A_BishopAttack; + BISH F 5 A_BishopAttack2; + Wait; + Death: + BISH G 6; + BISH H 6 Bright A_Scream; + BISH I 5 Bright A_NoBlocking; + BISH J 5 BRIGHT A_Explode(random[BishopBoom](25,40)); + BISH K 5 Bright; + BISH LM 4 Bright; + BISH N 4 A_SpawnItemEx("BishopPuff", 0,0,40, 0,0,-0.5); + BISH O 4 A_QueueCorpse; + BISH P -1; + Stop; + Ice: + BISH X 5 A_FreezeDeath; + BISH X 1 A_FreezeDeathChunks; + Wait; + } + + + + //============================================================================ + // + // A_BishopAttack + // + //============================================================================ + + void A_BishopAttack() + { + if (!target) + { + return; + } + A_PlaySound (AttackSound, CHAN_BODY); + if (CheckMeleeRange()) + { + int damage = random[BishopAttack](1, 8) * 4; + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + return; + } + missilecount = (random[BishopAttack]() & 3) + 5; + } + + //============================================================================ + // + // A_BishopAttack2 + // + // Spawns one of a string of bishop missiles + //============================================================================ + + void A_BishopAttack2() + { + if (!target || !missilecount) + { + missilecount = 0; + SetState (SeeState); + return; + } + Actor mo = SpawnMissile (target, "BishopFX"); + if (mo != null) + { + mo.tracer = target; + } + missilecount--; + return; + } + + //============================================================================ + // + // A_BishopDecide + // + //============================================================================ + + void A_BishopDecide() + { + if (random[BishopDecide]() >= 220) + { + SetStateLabel ("Blur"); + } + } + + //============================================================================ + // + // A_BishopDoBlur + // + //============================================================================ + + void A_BishopDoBlur() + { + missilecount = (random[BishopDoBlur]() & 3) + 3; // Random number of blurs + if (random[BishopDoBlur]() < 120) + { + Thrust(11, Angle + 90); + } + else if (random[BishopDoBlur]() > 125) + { + Thrust(11, Angle - 90); + } + else + { // Thrust forward + Thrust(11); + } + A_PlaySound ("BishopBlur", CHAN_BODY); + } + + //============================================================================ + // + // A_BishopSpawnBlur + // + //============================================================================ + + void A_BishopSpawnBlur() + { + if (!--missilecount) + { + Vel.XY = (0,0);// = Vel.Y = 0; + if (random[BishopSpawnBlur]() > 96) + { + SetState (SeeState); + } + else + { + SetState (MissileState); + } + } + Actor mo = Spawn ("BishopBlur", Pos, ALLOW_REPLACE); + if (mo) + { + mo.angle = angle; + } + } + + //============================================================================ + // + // A_BishopChase + // + //============================================================================ + + void A_BishopChase() + { + double newz = pos.z - BobSin(bobstate) / 2.; + bobstate = (bobstate + 4) & 63; + newz += BobSin(bobstate) / 2.; + SetZ(newz); + } + + //============================================================================ + // + // A_BishopPainBlur + // + //============================================================================ + + void A_BishopPainBlur() + { + if (random[BishopPainBlur]() < 64) + { + SetStateLabel ("Blur"); + return; + } + double xo = random2[BishopPainBlur]() / 16.; + double yo = random2[BishopPainBlue]() / 16.; + double zo = random2[BishopPainBlue]() / 32.; + Actor mo = Spawn ("BishopPainBlur", Vec3Offset(xo, yo, zo), ALLOW_REPLACE); + if (mo) + { + mo.angle = angle; + } + } + +} + +extend class Actor +{ + //============================================================================ + // + // A_BishopMissileWeave (this function must be in Actor) + // + //============================================================================ + + void A_BishopMissileWeave() + { + A_Weave(2, 2, 2., 1.); + } +} + +// Bishop puff -------------------------------------------------------------- + +class BishopPuff : Actor +{ + Default + { + +NOBLOCKMAP +NOGRAVITY + RenderStyle "Translucent"; + Alpha 0.6; + } + States + { + Spawn: + BISH QRST 5; + BISH UV 6; + BISH W 5; + Stop; + } +} + +// Bishop pain blur --------------------------------------------------------- + +class BishopPainBlur : Actor +{ + Default + { + +NOBLOCKMAP +NOGRAVITY + RenderStyle "Translucent"; + Alpha 0.6; + } + States + { + Spawn: + BISH C 8; + Stop; + } +} + +// Bishop FX ---------------------------------------------------------------- + +class BishopFX : Actor +{ + Default + { + Radius 10; + Height 6; + Speed 10; + Damage 1; + Projectile; + +SEEKERMISSILE + -ACTIVATEIMPACT -ACTIVATEPCROSS + +STRIFEDAMAGE + RenderStyle "Add"; + DeathSound "BishopMissileExplode"; + } + States + { + Spawn: + BPFX ABAB 1 Bright A_BishopMissileWeave; + BPFX B 0 Bright A_SeekerMissile(2,3); + Loop; + Death: + BPFX CDEF 4 Bright; + BPFX GH 3 Bright; + Stop; + } +} + +// Bishop blur -------------------------------------------------------------- + +class BishopBlur : Actor +{ + Default + { + +NOBLOCKMAP +NOGRAVITY + RenderStyle "Translucent"; + Alpha 0.6; + } + States + { + Spawn: + BISH A 16; + BISH A 8 A_SetTranslucent(0.4); + Stop; + } +} + diff --git a/wadsrc/static/zscript/hexen/blastradius.txt b/wadsrc/static/zscript/hexen/blastradius.txt new file mode 100644 index 0000000000..a9c631318a --- /dev/null +++ b/wadsrc/static/zscript/hexen/blastradius.txt @@ -0,0 +1,173 @@ + +class ArtiBlastRadius : CustomInventory +{ + Default + { + +FLOATBOB + Inventory.DefMaxAmount; + Inventory.PickupFlash "PickupFlash"; + +INVENTORY.INVBAR +INVENTORY.FANCYPICKUPSOUND + Inventory.Icon "ARTIBLST"; + Inventory.PickupSound "misc/p_pkup"; + Inventory.PickupMessage "$TXT_ARTIBLASTRADIUS"; + Tag "$TAG_ARTIBLASTRADIUS"; + } + States + { + Spawn: + BLST ABCDEFGH 4 Bright; + Loop; + Use: + TNT1 A 0 A_Blast; + } + +} + +//========================================================================== +// +// A_Blast is public to Actor +// +//========================================================================== + +extend class Actor +{ + /* For reference, the default values: + #define BLAST_RADIUS_DIST 255.0 + #define BLAST_SPEED 20.0 + #define BLAST_FULLSTRENGTH 255 + */ + + //========================================================================== + // + // AArtiBlastRadius :: BlastActor + // + //========================================================================== + + private void BlastActor (Actor victim, double strength, double speed, Class blasteffect, bool dontdamage) + { + if (!victim.SpecialBlastHandling (self, strength)) + { + return; + } + + double ang = AngleTo(victim); + Vector2 move = AngleToVector(ang, speed); + victim.Vel.XY = move; + + // Spawn blast puff + ang -= 180.; + Vector3 spawnpos = victim.Vec3Offset( + (victim.radius + 1) * cos(ang), + (victim.radius + 1) * sin(ang), + (victim.Height / 2) - victim.Floorclip); + Actor mo = Spawn (blasteffect, spawnpos, ALLOW_REPLACE); + if (mo) + { + mo.Vel.XY = victim.Vel.XY; + } + if (victim.bMissile) + { + // [RH] Floor and ceiling huggers should not be blasted vertically. + if (!victim.bFloorHugger && !victim.bCeilingHugger) + { + mo.Vel.Z = victim.Vel.Z = 8; + } + } + else + { + victim.Vel.Z = 1000. / victim.Mass; + } + if (victim.player) + { + // Players handled automatically + } + else if (!dontdamage) + { + victim.bBlasted = true; + } + if (victim.bTouchy) + { // Touchy objects die when blasted + victim.bArmed = false; // Disarm + victim.DamageMobj(self, self, victim.health, 'Melee', DMG_FORCED); + } + } + + //========================================================================== + // + // AArtiBlastRadius :: Activate + // + // Blast all actors away + // + //========================================================================== + + action void A_Blast(int blastflags = 0, double strength = 255, double radius = 255, double speed = 20, class blasteffect = "BlastEffect", sound blastsound = "BlastRadius") + { + + Weapon weapon = player.ReadyWeapon; + if (player && (blastflags & BF_USEAMMO) && invoker == weapon && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + + { + if (weapon != null && !weapon.DepleteAmmo(weapon.bAltFire)) + { + return; + } + } + + A_PlaySound (blastsound, CHAN_AUTO); + + if (!(blastflags & BF_DONTWARN)) + { + NoiseAlert (self); + } + ThinkerIterator it = ThinkerIterator.Create("Actor"); + Actor mo; + while ( (mo = Actor(it.Next ())) ) + { + if (mo == self || (mo.bBoss && !(blastflags & BF_AFFECTBOSSES)) || mo.bDormant || mo.bDontBlast) + { // Not a valid monster: originator, boss, dormant, or otherwise protected + continue; + } + if (mo.bIceCorpse || mo.bCanBlast) + { + // Let these special cases go + } + else if (mo.bIsMonster && mo.health <= 0) + { + continue; + } + else if (!mo.player && !mo.bMissile && !mo.bIsMonster && !mo.bCanBlast && !mo.bTouchy && !mo.bVulnerable) + { // Must be monster, player, missile, touchy or vulnerable + continue; + } + if (Distance2D(mo) > radius) + { // Out of range + continue; + } + if (mo.CurSector.PortalGroup != CurSector.PortalGroup && !CheckSight(mo)) + { + // in another region and cannot be seen. + continue; + } + BlastActor (mo, strength, speed, blasteffect, !!(blastflags & BF_NOIMPACTDAMAGE)); + } + } +} + +// Blast Effect ------------------------------------------------------------- + +class BlastEffect : Actor +{ + Default + { + +NOBLOCKMAP +NOGRAVITY +NOCLIP + +NOTELEPORT + RenderStyle "Translucent"; + Alpha 0.666; + } + States + { + Spawn: + RADE ABCDEFGHI 4; + Stop; + } +} diff --git a/wadsrc/static/zscript/hexen/boostarmor.txt b/wadsrc/static/zscript/hexen/boostarmor.txt new file mode 100644 index 0000000000..f8c797c99c --- /dev/null +++ b/wadsrc/static/zscript/hexen/boostarmor.txt @@ -0,0 +1,69 @@ + +// Boost Armor Artifact (Dragonskin Bracers) -------------------------------- + +class ArtiBoostArmor : Inventory +{ + Default + { + +COUNTITEM + +FLOATBOB + Inventory.DefMaxAmount; + Inventory.PickupFlash "PickupFlash"; + +INVENTORY.INVBAR +INVENTORY.FANCYPICKUPSOUND + Inventory.Icon "ARTIBRAC"; + Inventory.PickupSound "misc/p_pkup"; + Inventory.PickupMessage "$TXT_ARTIBOOSTARMOR"; + Tag "$TAG_ARTIBOOSTARMOR"; + } + States + { + Spawn: + BRAC ABCDEFGH 4 Bright; + Loop; + } + + override bool Use (bool pickup) + { + int count = 0; + + if (gametype() == GAME_Hexen) + { + HexenArmor armor; + + for (int i = 0; i < 4; ++i) + { + armor = HexenArmor(Spawn("HexenArmor")); + armor.bDropped = true; + armor.health = i; + armor.Amount = 1; + if (!armor.CallTryPickup (Owner)) + { + armor.Destroy (); + } + else + { + count++; + } + } + return count != 0; + } + else + { + BasicArmorBonus armor = BasicArmorBonus(Spawn("BasicArmorBonus")); + armor.bDropped = true; + armor.SaveAmount = 50; + armor.MaxSaveAmount = 300; + if (!armor.CallTryPickup (Owner)) + { + armor.Destroy (); + return false; + } + else + { + return true; + } + } + } + + +} diff --git a/wadsrc/static/zscript/hexen/centaur.txt b/wadsrc/static/zscript/hexen/centaur.txt new file mode 100644 index 0000000000..f8c8e2c3d3 --- /dev/null +++ b/wadsrc/static/zscript/hexen/centaur.txt @@ -0,0 +1,223 @@ +// Centaur ------------------------------------------------------------------ + +class Centaur : Actor +{ + Default + { + Health 200; + Painchance 135; + Speed 13; + Height 64; + Mass 120; + Monster; + +FLOORCLIP + +TELESTOMP + +SHIELDREFLECT + SeeSound "CentaurSight"; + AttackSound "CentaurAttack"; + PainSound "CentaurPain"; + DeathSound "CentaurDeath"; + ActiveSound "CentaurActive"; + HowlSound "PuppyBeat"; + Obituary "$OB_CENTAUR"; + DamageFactor "Electric", 3; + } + States + { + Spawn: + CENT AB 10 A_Look; + Loop; + See: + CENT ABCD 4 A_Chase; + Loop; + Pain: + CENT G 6 A_Pain; + CENT G 6 A_SetReflectiveInvulnerable; + CENT EEE 15 A_CentaurDefend; + CENT E 1 A_UnsetReflectiveInvulnerable; + Goto See; + Melee: + CENT H 5 A_FaceTarget; + CENT I 4 A_FaceTarget; + CENT J 7 A_CustomMeleeAttack(random[CentaurAttack](3,9)); + Goto See; + Death: + CENT K 4; + CENT L 4 A_Scream; + CENT MN 4; + CENT O 4 A_NoBlocking; + CENT PQ 4; + CENT R 4 A_QueueCorpse; + CENT S 4; + CENT T -1; + Stop; + XDeath: + CTXD A 4; + CTXD B 4 A_NoBlocking; + CTXD C 4 + { + A_SpawnItemEx("CentaurSword", 0, 0, 45, + 1 + random[CentaurDrop](-128,127)*0.03125, + 1 + random[CentaurDrop](-128,127)*0.03125, + 8 + random[CentaurDrop](0,255)*0.015625, 270); + A_SpawnItemEx("CentaurShield", 0, 0, 45, + 1 + random[CentaurDrop](-128,127)*0.03125, + 1 + random[CentaurDrop](-128,127)*0.03125, + 8 + random[CentaurDrop](0,255)*0.015625, 90); + } + CTXD D 3 A_Scream; + CTXD E 4 A_QueueCorpse; + CTXD F 3; + CTXD G 4; + CTXD H 3; + CTXD I 4; + CTXD J 3; + CTXD K -1; + Ice: + CENT U 5 A_FreezeDeath; + CENT U 1 A_FreezeDeathChunks; + Wait; + } +} + +extend class Actor +{ + void A_CentaurDefend() + { + A_FaceTarget (); + if (CheckMeleeRange() && random[CentaurDefend]() < 32) + { + // This should unset REFLECTIVE as well + // (unless you want the Centaur to reflect projectiles forever!) + bReflective = false; + bInvulnerable = false; + SetState(MeleeState); + } + } +} + +// Centaur Leader ----------------------------------------------------------- + +class CentaurLeader : Centaur +{ + Default + { + Health 250; + PainChance 96; + Speed 10; + Obituary "$OB_SLAUGHTAUR"; + HitObituary "$OB_SLAUGHTAURHIT"; + } + States + { + Missile: + CENT E 10 A_FaceTarget; + CENT F 8 Bright A_CustomMissile("CentaurFX", 45, 0, 0, CMF_AIMOFFSET); + CENT E 10 A_FaceTarget; + CENT F 8 Bright A_CustomMissile("CentaurFX", 45, 0, 0, CMF_AIMOFFSET); + Goto See; + } +} + +// Mashed centaur ----------------------------------------------------------- +// +// The mashed centaur is only placed through ACS. Nowhere in the game source +// is it ever referenced. + +class CentaurMash : Centaur +{ + Default + { + +NOBLOOD + +BLASTED + -TELESTOMP + +NOICEDEATH + RenderStyle "Translucent"; + Alpha 0.4; + } + States + { + Death: + XDeath: + Ice: + Stop; + } +} + +// Centaur projectile ------------------------------------------------------- + +class CentaurFX : Actor +{ + Default + { + Speed 20; + Damage 4; + Projectile; + +SPAWNSOUNDSOURCE + RenderStyle "Add"; + SeeSound "CentaurLeaderAttack"; + DeathSound "CentaurMissileExplode"; + } + States + { + Spawn: + CTFX A -1 Bright; + Stop; + Death: + CTFX B 4 Bright; + CTFX C 3 Bright; + CTFX D 4 Bright; + CTFX E 3 Bright; + CTFX F 2 Bright; + Stop; + } +} + +// Centaur shield (debris) -------------------------------------------------- + +class CentaurShield : Actor +{ + Default + { + +DROPOFF + +CORPSE + +NOTELEPORT + } + States + { + Spawn: + CTDP ABCDEF 3; + Goto Spawn+2; + Crash: + CTDP G 4; + CTDP H 4 A_QueueCorpse; + CTDP I 4; + CTDP J -1; + Stop; + } +} + +// Centaur sword (debris) --------------------------------------------------- + +class CentaurSword : Actor +{ + Default + { + +DROPOFF + +CORPSE + +NOTELEPORT + } + States + { + Spawn: + CTDP KLMNOPQ 3; + Goto Spawn+2; + Crash: + CTDP R 4; + CTDP S 4 A_QueueCorpse; + CTDP T -1; + Stop; + } +} + + diff --git a/wadsrc/static/zscript/hexen/clericboss.txt b/wadsrc/static/zscript/hexen/clericboss.txt new file mode 100644 index 0000000000..4bf2235171 --- /dev/null +++ b/wadsrc/static/zscript/hexen/clericboss.txt @@ -0,0 +1,95 @@ + +// Cleric Boss (Traductus) -------------------------------------------------- + +class ClericBoss : Actor +{ + Default + { + Health 800; + PainChance 50; + Speed 25; + Radius 16; + Height 64; + Monster; + +FLOORCLIP +TELESTOMP + +DONTMORPH + PainSound "PlayerClericPain"; + DeathSound "PlayerClericCrazyDeath"; + Obituary "$OBCBOSS"; + } + + States + { + Spawn: + CLER A 2; + CLER A 3 A_ClassBossHealth; + CLER A 5 A_Look; + Wait; + See: + CLER ABCD 4 A_FastChase; + Loop; + Pain: + CLER H 4; + CLER H 4 A_Pain; + Goto See; + Melee: + Missile: + CLER EF 8 A_FaceTarget; + CLER G 10 A_ClericAttack; + Goto See; + Death: + CLER I 6; + CLER K 6 A_Scream; + CLER LL 6; + CLER M 6 A_NoBlocking; + CLER NOP 6; + CLER Q -1; + Stop; + XDeath: + CLER R 5 A_Scream; + CLER S 5; + CLER T 5 A_NoBlocking; + CLER UVWXYZ 5; + CLER [ -1; + Stop; + Ice: + CLER \ 5 A_FreezeDeath; + CLER \ 1 A_FreezeDeathChunks; + Wait; + Burn: + CLER C 5 Bright A_PlaySound("PlayerClericBurnDeath"); + FDTH D 4 Bright ; + FDTH G 5 Bright ; + FDTH H 4 Bright A_Scream; + FDTH I 5 Bright ; + FDTH J 4 Bright ; + FDTH K 5 Bright ; + FDTH L 4 Bright ; + FDTH M 5 Bright ; + FDTH N 4 Bright ; + FDTH O 5 Bright ; + FDTH P 4 Bright ; + FDTH Q 5 Bright ; + FDTH R 4 Bright ; + FDTH S 5 Bright A_NoBlocking; + FDTH T 4 Bright ; + FDTH U 5 Bright ; + FDTH V 4 Bright ; + Stop; + } + + //============================================================================ + // + // A_ClericAttack + // + //============================================================================ + + void A_ClericAttack() + { + if (!target) return; + + Actor missile = SpawnMissileZ (pos.z + 40., target, "HolyMissile"); + if (missile != null) missile.tracer = null; // No initial target + A_PlaySound ("HolySymbolFire", CHAN_WEAPON); + } +} diff --git a/wadsrc/static/zscript/hexen/clericflame.txt b/wadsrc/static/zscript/hexen/clericflame.txt new file mode 100644 index 0000000000..d222a07db3 --- /dev/null +++ b/wadsrc/static/zscript/hexen/clericflame.txt @@ -0,0 +1,322 @@ + +// The Cleric's Flame Strike ------------------------------------------------ + +class CWeapFlame : ClericWeapon +{ + Default + { + +NOGRAVITY + Weapon.SelectionOrder 1000; + Weapon.AmmoUse 4; + Weapon.AmmoGive 25; + Weapon.KickBack 150; + Weapon.YAdjust 10; + Weapon.AmmoType1 "Mana2"; + Inventory.PickupMessage "$TXT_WEAPON_C3"; + Tag "$TAG_CWEAPFLAME"; + } + + States + { + Spawn: + WCFM ABCDEFGH 4 Bright; + Loop; + Select: + CFLM A 1 A_Raise; + Loop; + Deselect: + CFLM A 1 A_Lower; + Loop; + Ready: + CFLM AAAABBBBCCCC 1 A_WeaponReady; + Loop; + Fire: + CFLM A 2 Offset (0, 40); + CFLM D 2 Offset (0, 50); + CFLM D 2 Offset (0, 36); + CFLM E 4 Bright; + CFLM F 4 Bright A_CFlameAttack; + CFLM E 4 Bright; + CFLM G 2 Offset (0, 40); + CFLM G 2; + Goto Ready; + } + + //============================================================================ + // + // A_CFlameAttack + // + //============================================================================ + + action void A_CFlameAttack() + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + SpawnPlayerMissile ("CFlameMissile"); + A_PlaySound ("ClericFlameFire", CHAN_WEAPON); + } +} + +// Floor Flame -------------------------------------------------------------- + +class CFlameFloor : Actor +{ + Default + { + +NOBLOCKMAP +NOGRAVITY + RenderStyle "Add"; + } + States + { + Spawn: + CFFX N 5 Bright; + CFFX O 4 Bright; + CFFX P 3 Bright; + Stop; + } +} + +// Flame Puff --------------------------------------------------------------- + +class FlamePuff : Actor +{ + Default + { + Radius 1; + Height 1; + +NOBLOCKMAP +NOGRAVITY + RenderStyle "Add";; + SeeSound "ClericFlameExplode"; + AttackSound "ClericFlameExplode"; + } + States + { + Spawn: + CFFX ABC 3 Bright; + CFFX D 4 Bright; + CFFX E 3 Bright; + CFFX F 4 Bright; + CFFX G 3 Bright; + CFFX H 4 Bright; + CFFX I 3 Bright; + CFFX J 4 Bright; + CFFX K 3 Bright; + CFFX L 4 Bright; + CFFX M 3 Bright; + Stop; + } +} + +// Flame Puff 2 ------------------------------------------------------------- + +class FlamePuff2 : FlamePuff +{ + States + { + Spawn: + CFFX ABC 3 Bright; + CFFX D 4 Bright; + CFFX E 3 Bright; + CFFX F 4 Bright; + CFFX G 3 Bright; + CFFX H 4 Bright; + CFFX IC 3 Bright; + CFFX D 4 Bright; + CFFX E 3 Bright; + CFFX F 4 Bright; + CFFX G 3 Bright; + CFFX H 4 Bright; + CFFX I 3 Bright; + CFFX J 4 Bright; + CFFX K 3 Bright; + CFFX L 4 Bright; + CFFX M 3 Bright; + Stop; + } +} + +// Circle Flame ------------------------------------------------------------- + +class CircleFlame : Actor +{ + const FLAMESPEED = 0.45; + const FLAMEROTSPEED = 2.; + + Default + { + Radius 6; + Damage 2; + DamageType "Fire"; + Projectile; + -ACTIVATEIMPACT + -ACTIVATEPCROSS + RenderStyle "Add"; + DeathSound "ClericFlameCircle"; + Obituary "$OB_MPCWEAPFLAME"; + } + + States + { + Spawn: + CFCF A 4 Bright; + CFCF B 2 Bright A_CFlameRotate; + CFCF C 2 Bright; + CFCF D 1 Bright; + CFCF E 2 Bright; + CFCF F 2 Bright A_CFlameRotate; + CFCF G 1 Bright; + CFCF HI 2 Bright; + CFCF J 1 Bright A_CFlameRotate; + CFCF K 2 Bright; + CFCF LM 3 Bright; + CFCF N 2 Bright A_CFlameRotate; + CFCF O 3 Bright; + CFCF P 2 Bright; + Stop; + Death: + CFCF QR 3 Bright; + CFCF S 3 Bright A_Explode(20, 20, 0); + CFCF TUVWXYZ 3 Bright; + Stop; + } + + //============================================================================ + // + // A_CFlameRotate + // + //============================================================================ + + void A_CFlameRotate() + { + double an = Angle + 90.; + VelFromAngle(FLAMEROTSPEED, an); + Vel.XY += (specialf1, specialf2); + Angle += 6; + } +} + +// Flame Missile ------------------------------------------------------------ + +class CFlameMissile : FastProjectile +{ + Default + { + Speed 200; + Radius 14; + Height 8; + Damage 8; + DamageType "Fire"; + +INVISIBLE + RenderStyle "Add"; + Obituary "$OB_MPCWEAPFLAME"; + } + + States + { + Spawn: + CFFX A 4 Bright; + CFFX A 1 A_CFlamePuff; + Goto Death + 1; + Death: + CFFX A 1 Bright A_CFlameMissile; + CFFX ABC 3 Bright; + CFFX D 4 Bright; + CFFX E 3 Bright; + CFFX F 4 Bright; + CFFX G 3 Bright; + CFFX H 4 Bright; + CFFX I 3 Bright; + CFFX J 4 Bright; + CFFX K 3 Bright; + CFFX L 4 Bright; + CFFX M 3 Bright; + Stop; + } + + override void BeginPlay () + { + special1 = 2; + } + + override void Effect () + { + if (!--special1) + { + special1 = 4; + double newz = pos.z - 12; + if (newz < floorz) + { + newz = floorz; + } + Actor mo = Spawn ("CFlameFloor", (pos.xy, newz), ALLOW_REPLACE); + if (mo) + { + mo.angle = angle; + } + } + } + + //============================================================================ + // + // A_CFlamePuff + // + //============================================================================ + + void A_CFlamePuff() + { + bInvisible = false; + Vel = (0,0,0); + A_PlaySound ("ClericFlameExplode", CHAN_BODY); + } + + //============================================================================ + // + // A_CFlameMissile + // + //============================================================================ + + void A_CFlameMissile() + { + bInvisible = false; + A_PlaySound ("ClericFlameExplode", CHAN_BODY); + if (BlockingMobj && BlockingMobj.bShootable) + { // Hit something, so spawn the flame circle around the thing + double dist = BlockingMobj.radius + 18; + for (int i = 0; i < 4; i++) + { + double an = i*45.; + Actor mo = Spawn ("CircleFlame", BlockingMobj.Vec3Angle(dist, an, 5), ALLOW_REPLACE); + if (mo) + { + mo.angle = an; + mo.target = target; + mo.VelFromAngle(CircleFlame.FLAMESPEED); + mo.specialf1 = mo.Vel.X; + mo.specialf2 = mo.Vel.Y; + mo.tics -= random[FlameMissile]()&3; + } + an += 180; + mo = Spawn("CircleFlame", BlockingMobj.Vec3Angle(dist, an, 5), ALLOW_REPLACE); + if(mo) + { + mo.angle = an; + mo.target = target; + mo.VelFromAngle(-CircleFlame.FLAMESPEED); + mo.specialf1 = mo.Vel.X; + mo.specialf2 = mo.Vel.Y; + mo.tics -= random[FlameMissile]()&3; + } + } + SetState (SpawnState); + } + } +} diff --git a/wadsrc/static/zscript/hexen/clericholy.txt b/wadsrc/static/zscript/hexen/clericholy.txt new file mode 100644 index 0000000000..33b69bf25a --- /dev/null +++ b/wadsrc/static/zscript/hexen/clericholy.txt @@ -0,0 +1,673 @@ + +// Cleric Weapon Piece ------------------------------------------------------ + +class ClericWeaponPiece : WeaponPiece +{ + Default + { + Inventory.PickupSound "misc/w_pkup"; + Inventory.PickupMessage "$TXT_WRAITHVERGE_PIECE"; + Inventory.ForbiddenTo "FighterPlayer", "MagePlayer"; + WeaponPiece.Weapon "CWeapWraithverge"; + +FLOATBOB + } +} + +// Cleric Weapon Piece 1 ---------------------------------------------------- + +class CWeaponPiece1 : ClericWeaponPiece +{ + Default + { + WeaponPiece.Number 1; + } + States + { + Spawn: + WCH1 A -1; + Stop; + } +} + +// Cleric Weapon Piece 2 ---------------------------------------------------- + +class CWeaponPiece2 : ClericWeaponPiece +{ + Default + { + WeaponPiece.Number 2; + } + States + { + Spawn: + WCH2 A -1; + Stop; + } +} + +// Cleric Weapon Piece 3 ---------------------------------------------------- + +class CWeaponPiece3 : ClericWeaponPiece +{ + Default + { + WeaponPiece.Number 3; + } + States + { + Spawn: + WCH3 A -1; + Stop; + } +} + +// Wraithverge Drop --------------------------------------------------------- + +class WraithvergeDrop : Actor +{ + States + { + Spawn: + TNT1 A 1; + TNT1 A 1 A_DropWeaponPieces("CWeaponPiece1", "CWeaponPiece2", "CWeaponPiece3"); + Stop; + } +} + +// Cleric's Wraithverge (Holy Symbol?) -------------------------------------- + +class CWeapWraithverge : ClericWeapon +{ + int CHolyCount; + + Default + { + Health 3; + Weapon.SelectionOrder 3000; + +WEAPON.PRIMARY_USES_BOTH; + +Inventory.NoAttenPickupSound + Weapon.AmmoUse1 18; + Weapon.AmmoUse2 18; + Weapon.AmmoGive1 20; + Weapon.AmmoGive2 20; + Weapon.KickBack 150; + Weapon.AmmoType1 "Mana1"; + Weapon.AmmoType2 "Mana2"; + Inventory.PickupMessage "$TXT_WEAPON_C4"; + Tag "$TAG_CWEAPWRAITHVERGE"; + Inventory.PickupSound "WeaponBuild"; + } + + + States + { + Spawn: + TNT1 A -1; + Stop; + Ready: + CHLY A 1 A_WeaponReady; + Loop; + Select: + CHLY A 1 A_Raise; + Loop; + Deselect: + CHLY A 1 A_Lower; + Loop; + Fire: + CHLY AB 1 Bright Offset (0, 40); + CHLY CD 2 Bright Offset (0, 43); + CHLY E 2 Bright Offset (0, 45); + CHLY F 6 Bright Offset (0, 48) A_CHolyAttack; + CHLY GG 2 Bright Offset (0, 40) A_CHolyPalette; + CHLY G 2 Offset (0, 36) A_CHolyPalette; + Goto Ready; + } + + override color GetBlend () + { + if (paletteflash & PF_HEXENWEAPONS) + { + if (CHolyCount == 3) + return Color(128, 70, 70, 70); + else if (CHolyCount == 2) + return Color(128, 100, 100, 100); + else if (CHolyCount == 1) + return Color(128, 130, 130, 130); + else + return Color(0, 0, 0, 0); + } + else + { + return Color(CHolyCount * 128 / 3, 131, 131, 131); + } + } + + //============================================================================ + // + // A_CHolyAttack + // + //============================================================================ + + action void A_CHolyAttack() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + Actor missile = SpawnPlayerMissile ("HolyMissile", angle, pLineTarget:t); + if (missile != null && !t.unlinked) + { + missile.tracer = t.linetarget; + } + + invoker.CHolyCount = 3; + A_PlaySound ("HolySymbolFire", CHAN_WEAPON); + } + + //============================================================================ + // + // A_CHolyPalette + // + //============================================================================ + + action void A_CHolyPalette() + { + if (invoker.CHolyCount > 0) invoker.CHolyCount--; + } +} + +// Holy Missile ------------------------------------------------------------- + +class HolyMissile : Actor +{ + Default + { + Speed 30; + Radius 15; + Height 8; + Damage 4; + Projectile; + -ACTIVATEIMPACT -ACTIVATEPCROSS + +EXTREMEDEATH + } + + States + { + Spawn: + SPIR PPPP 3 Bright A_SpawnItemEx("HolyMissilePuff"); + Death: + SPIR P 1 Bright A_CHolyAttack2; + Stop; + } + + //============================================================================ + // + // A_CHolyAttack2 + // + // Spawns the spirits + //============================================================================ + + void A_CHolyAttack2() + { + for (int j = 0; j < 4; j++) + { + Actor mo = Spawn("HolySpirit", Pos, ALLOW_REPLACE); + if (!mo) + { + continue; + } + switch (j) + { // float bob index + + case 0: + mo.WeaveIndexZ = random[HolyAtk2]() & 7; // upper-left + break; + case 1: + mo.WeaveIndexZ = 32 + (random[HolyAtk2]() & 7); // upper-right + break; + case 2: + mo.WeaveIndexXY = 32 + (random[HolyAtk2]() & 7); // lower-left + break; + case 3: + mo.WeaveIndexXY = 32 + (random[HolyAtk2]() & 7); + mo.WeaveIndexZ = 32 + (random[HolyAtk2]() & 7); + break; + } + mo.SetZ(pos.z); + mo.angle = angle + 67.5 - 45.*j; + mo.Thrust(); + mo.target = 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 (tracer) + { + mo.tracer = tracer; + mo.bNoClip = true; + mo.bSkullFly = true; + mo.bMissile = false; + } + HolyTail.SpawnSpiritTail (mo); + } + } +} + +// Holy Missile Puff -------------------------------------------------------- + +class HolyMissilePuff : Actor +{ + Default + { + Radius 4; + Height 8; + +NOBLOCKMAP +NOGRAVITY +DROPOFF + +NOTELEPORT + RenderStyle "Translucent"; + Alpha 0.4; + } + States + { + Spawn: + SPIR QRSTU 3; + Stop; + } +} + +// Holy Puff ---------------------------------------------------------------- + +class HolyPuff : Actor +{ + Default + { + +NOBLOCKMAP +NOGRAVITY + RenderStyle "Translucent"; + Alpha 0.6; + } + States + { + Spawn: + SPIR KLMNO 3; + Stop; + } +} + +// Holy Spirit -------------------------------------------------------------- + +class HolySpirit : Actor +{ + Default + { + Health 105; + Speed 12; + Radius 10; + Height 6; + Damage 3; + Projectile; + +RIPPER +SEEKERMISSILE + +FOILINVUL +SKYEXPLODE +NOEXPLODEFLOOR +CANBLAST + +EXTREMEDEATH +NOSHIELDREFLECT + RenderStyle "Translucent"; + Alpha 0.4; + DeathSound "SpiritDie"; + Obituary "$OB_MPCWEAPWRAITHVERGE"; + } + + States + { + Spawn: + SPIR AAB 2 A_CHolySeek; + SPIR B 2 A_CHolyCheckScream; + Loop; + Death: + SPIR D 4; + SPIR E 4 A_Scream; + SPIR FGHI 4; + Stop; + } + + //============================================================================ + // + // + // + //============================================================================ + + override bool Slam(Actor thing) + { + if (thing.bShootable && thing != target) + { + if (multiplayer && !deathmatch && thing.player && target.player) + { // don't attack other co-op players + return true; + } + if (thing.bReflective && (thing.player || thing.bBoss)) + { + tracer = target; + target = thing; + return true; + } + if (thing.bIsMonster || thing.player) + { + tracer = thing; + } + if (random[SpiritSlam]() < 96) + { + int dam = 12; + if (thing.player || thing.bBoss) + { + dam = 3; + // ghost burns out faster when attacking players/bosses + health -= 6; + } + thing.DamageMobj(self, target, dam, 'Melee'); + if (random[SpiritSlam]() < 128) + { + Spawn("HolyPuff", Pos, ALLOW_REPLACE); + A_PlaySound("SpiritAttack", CHAN_WEAPON); + if (thing.bIsMonster && random[SpiritSlam]() < 128) + { + thing.Howl(); + } + } + } + if (thing.health <= 0) + { + tracer = null; + } + } + return true; + } + + override bool SpecialBlastHandling (Actor source, double strength) + { + if (tracer == source) + { + tracer = target; + target = source; + } + return true; + } + + //============================================================================ + // + // CHolyFindTarget + // + //============================================================================ + + private void CHolyFindTarget () + { + Actor target; + + if ( (target = RoughMonsterSearch (6, true)) ) + { + tracer = target; + bNoClip = true; + bSkullFly = true; + bMissile = false; + } + } + + //============================================================================ + // + // CHolySeekerMissile + // + // Similar to P_SeekerMissile, but seeks to a random Z on the target + //============================================================================ + + private void CHolySeekerMissile (double thresh, double turnMax) + { + Actor target = tracer; + if (target == NULL) + { + return; + } + if (!target.bShootable || (!target.bIsMonster && !target.player)) + { // Target died/target isn't a player or creature + tracer = null; + bNoClip = false; + bSkullFly = false; + bMissile = true; + CHolyFindTarget(); + return; + } + double ang = deltaangle(angle, AngleTo(target)); + double delta = abs(ang); + + if (delta > thresh) + { + delta /= 2; + if (delta > turnMax) + { + delta = turnMax; + } + } + if (ang > 0) + { // Turn clockwise + angle += delta; + } + else + { // Turn counter clockwise + angle -= delta; + } + VelFromAngle(); + + if (!(level.time&15) + || pos.z > target.pos.z + target.height + || pos.z + height < target.pos.z) + { + double newZ = target.pos.z + ((random[HolySeeker]()*target.Height) / 256.); + double deltaZ = newZ - pos.z; + if (abs(deltaZ) > 15) + { + if (deltaZ > 0) + { + deltaZ = 15; + } + else + { + deltaZ = -15; + } + } + Vel.Z = deltaZ / DistanceBySpeed(target, Speed); + } + } + + //============================================================================ + // + // A_CHolySeek + // + //============================================================================ + + void A_CHolySeek() + { + health--; + if (health <= 0) + { + Vel.X /= 4; + Vel.Y /= 4; + Vel.Z = 0; + SetStateLabel ("Death"); + tics -= random[HolySeeker]()&3; + return; + } + if (tracer) + { + CHolySeekerMissile (args[0], args[0]*2.); + if (!((level.time+7)&15)) + { + args[0] = 5+(random[HolySeeker]()/20); + } + } + + int xyspeed = (random[HolySeeker]() % 5); + int zspeed = (random[HolySeeker]() % 5); + A_Weave(xyspeed, zspeed, 4., 2.); + } + + //============================================================================ + // + // A_CHolyCheckScream + // + //============================================================================ + + void A_CHolyCheckScream() + { + A_CHolySeek(); + if (random[HolyScream]() < 20) + { + A_PlaySound ("SpiritActive", CHAN_VOICE); + } + if (!tracer) + { + CHolyFindTarget(); + } + } +} + +// Holy Tail ---------------------------------------------------------------- + +class HolyTail : Actor +{ + Default + { + Radius 1; + Height 1; + +NOBLOCKMAP +NOGRAVITY +DROPOFF +NOCLIP + +NOTELEPORT + RenderStyle "Translucent"; + Alpha 0.6; + } + + States + { + Spawn: + SPIR C 1 A_CHolyTail; + Loop; + TailTrail: + SPIR D -1; + Stop; + } + + //============================================================================ + // + // SpawnSpiritTail + // + //============================================================================ + + static void SpawnSpiritTail (Actor spirit) + { + Actor tail = Spawn ("HolyTail", spirit.Pos, ALLOW_REPLACE); + tail.target = spirit; // parent + for (int i = 1; i < 3; i++) + { + Actor next = Spawn ("HolyTailTrail", spirit.Pos, ALLOW_REPLACE); + tail.tracer = next; + tail = next; + } + tail.tracer = null; // last tail bit + } + + //============================================================================ + // + // CHolyTailFollow + // + //============================================================================ + + private void CHolyTailFollow(double dist) + { + Actor mo = self; + while (mo) + { + Actor child = mo.tracer; + if (child) + { + double an = mo.AngleTo(child); + double oldDistance = child.Distance2D(mo); + if (child.TryMove(mo.Pos.XY + AngleToVector(an, dist), true)) + { + double newDistance = child.Distance2D(mo) - 1; + if (oldDistance < 1) + { + if (child.pos.z < mo.pos.z) + { + child.SetZ(mo.pos.z - dist); + } + else + { + child.SetZ(mo.pos.z + dist); + } + } + else + { + child.SetZ(mo.pos.z + (newDistance * (child.pos.z - mo.pos.z) / oldDistance)); + } + } + } + mo = child; + dist -= 1; + } + } + + //============================================================================ + // + // CHolyTailRemove + // + //============================================================================ + + private void CHolyTailRemove () + { + Actor mo = self; + while (mo) + { + Actor next = mo.tracer; + mo.Destroy (); + mo = next; + } + } + + //============================================================================ + // + // A_CHolyTail + // + //============================================================================ + + void A_CHolyTail() + { + Actor parent = 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 (); + return; + } + else + { + if (TryMove(parent.Vec2Angle(14., parent.Angle, true), true)) + { + SetZ(parent.pos.z - 5.); + } + CHolyTailFollow(10); + } + } +} + +// Holy Tail Trail --------------------------------------------------------- + +class HolyTailTrail : HolyTail +{ + States + { + Spawn: + Goto TailTrail; + } +} diff --git a/wadsrc/static/zscript/hexen/clericmace.txt b/wadsrc/static/zscript/hexen/clericmace.txt new file mode 100644 index 0000000000..b6f42c7e46 --- /dev/null +++ b/wadsrc/static/zscript/hexen/clericmace.txt @@ -0,0 +1,87 @@ + +// The Cleric's Mace -------------------------------------------------------- + +class CWeapMace : ClericWeapon +{ + Default + { + Weapon.SelectionOrder 3500; + Weapon.KickBack 150; + Weapon.YAdjust -8; + +BLOODSPLATTER + Obituary "$OB_MPCWEAPMACE"; + Tag "$TAG_CWEAPMACE"; + } + + States + { + Select: + CMCE A 1 A_Raise; + Loop; + Deselect: + CMCE A 1 A_Lower; + Loop; + Ready: + CMCE A 1 A_WeaponReady; + Loop; + Fire: + CMCE B 2 Offset (60, 20); + CMCE B 1 Offset (30, 33); + CMCE B 2 Offset (8, 45); + CMCE C 1 Offset (8, 45); + CMCE D 1 Offset (8, 45); + CMCE E 1 Offset (8, 45); + CMCE E 1 Offset (-11, 58) A_CMaceAttack; + CMCE F 1 Offset (8, 45); + CMCE F 2 Offset (-8, 74); + CMCE F 1 Offset (-20, 96); + CMCE F 8 Offset (-33, 160); + CMCE A 2 Offset (8, 75) A_ReFire; + CMCE A 1 Offset (8, 65); + CMCE A 2 Offset (8, 60); + CMCE A 1 Offset (8, 55); + CMCE A 2 Offset (8, 50); + CMCE A 1 Offset (8, 45); + Goto Ready; + } + + //=========================================================================== + // + // A_CMaceAttack + // + //=========================================================================== + + action void A_CMaceAttack() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + int damage = 25+(random[MaceAtk]()&15); + for (int i = 0; i < 16; i++) + { + for (int j = 1; j >= -1; j -= 2) + { + double ang = angle + j*i*(45. / 16); + double slope = AimLineAttack(ang, 2 * MELEERANGE, t); + if (t.linetarget) + { + LineAttack(ang, 2 * MELEERANGE, slope, damage, 'Melee', "HammerPuff", true, t); + if (t.linetarget != null) + { + AdjustPlayerAngle(t); + return; + } + } + } + } + // didn't find any creatures, so try to strike any walls + weaponspecial = 0; + + double slope = AimLineAttack (angle, MELEERANGE); + LineAttack (angle, MELEERANGE, slope, damage, 'Melee', "HammerPuff"); + } +} diff --git a/wadsrc/static/zscript/hexen/clericplayer.txt b/wadsrc/static/zscript/hexen/clericplayer.txt new file mode 100644 index 0000000000..1b47ad3f56 --- /dev/null +++ b/wadsrc/static/zscript/hexen/clericplayer.txt @@ -0,0 +1,106 @@ +// The cleric --------------------------------------------------------------- + +class ClericPlayer : PlayerPawn +{ + Default + { + Health 100; + ReactionTime 0; + PainChance 255; + Radius 16; + Height 64; + Speed 1; + +NOSKIN + +NODAMAGETHRUST + +PLAYERPAWN.NOTHRUSTWHENINVUL + PainSound "PlayerClericPain"; + RadiusDamageFactor 0.25; + Player.JumpZ 9; + Player.Viewheight 48; + Player.SpawnClass "Cleric"; + Player.DisplayName "Cleric"; + Player.SoundClass "cleric"; + Player.ScoreIcon "CLERFACE"; + Player.InvulnerabilityMode "Ghost"; + Player.HealRadiusType "Health"; + Player.Hexenarmor 10, 10, 25, 5, 20; + Player.StartItem "CWeapMace"; + Player.Portrait "P_CWALK1"; + Player.WeaponSlot 1, "CWeapMace"; + Player.WeaponSlot 2, "CWeapStaff"; + Player.WeaponSlot 3, "CWeapFlame"; + Player.WeaponSlot 4, "CWeapWraithverge"; + Player.FlechetteType "ArtiPoisonBag1"; + + Player.ColorRange 146, 163; + Player.Colorset 0, "Blue", 146, 163, 161; + Player.ColorsetFile 1, "Red", "TRANTBL7", 0xB3; + Player.ColorsetFile 2, "Gold", "TRANTBL8", 0x8C; + Player.ColorsetFile 3, "Dull Green", "TRANTBL9", 0x41; + Player.ColorsetFile 4, "Green", "TRANTBLA", 0xC9; + Player.ColorsetFile 5, "Gray", "TRANTBLB", 0x30; + Player.ColorsetFile 6, "Brown", "TRANTBLC", 0x72; + Player.ColorsetFile 7, "Purple", "TRANTBLD", 0xEE; + } + + States + { + Spawn: + CLER A -1; + Stop; + See: + CLER ABCD 4; + Loop; + Pain: + CLER H 4; + CLER H 4 A_Pain; + Goto Spawn; + Missile: + Melee: + CLER EFG 6; + Goto Spawn; + Death: + CLER I 6; + CLER J 6 A_PlayerScream; + CLER KL 6; + CLER M 6 A_NoBlocking; + CLER NOP 6; + CLER Q -1; + Stop; + XDeath: + CLER R 5 A_PlayerScream; + CLER S 5; + CLER T 5 A_NoBlocking; + CLER UVWXYZ 5; + CLER [ -1; + Stop; + Ice: + CLER \ 5 A_FreezeDeath; + CLER \ 1 A_FreezeDeathChunks; + Wait; + Burn: + FDTH C 5 BRIGHT A_PlaySound("*burndeath"); + FDTH D 4 BRIGHT; + FDTH G 5 BRIGHT; + FDTH H 4 BRIGHT A_PlayerScream; + FDTH I 5 BRIGHT; + FDTH J 4 BRIGHT; + FDTH K 5 BRIGHT; + FDTH L 4 BRIGHT; + FDTH M 5 BRIGHT; + FDTH N 4 BRIGHT; + FDTH O 5 BRIGHT; + FDTH P 4 BRIGHT; + FDTH Q 5 BRIGHT; + FDTH R 4 BRIGHT; + FDTH S 5 BRIGHT A_NoBlocking; + FDTH T 4 BRIGHT; + FDTH U 5 BRIGHT; + FDTH V 4 BRIGHT; + ACLO E 35 A_CheckPlayerDone; + Wait; + ACLO E 8; + Stop; + } +} + diff --git a/wadsrc/static/zscript/hexen/clericstaff.txt b/wadsrc/static/zscript/hexen/clericstaff.txt new file mode 100644 index 0000000000..0d7ca0a99c --- /dev/null +++ b/wadsrc/static/zscript/hexen/clericstaff.txt @@ -0,0 +1,249 @@ + +// The Cleric's Serpent Staff ----------------------------------------------- + +class CWeapStaff : ClericWeapon +{ + Default + { + Weapon.SelectionOrder 1600; + Weapon.AmmoUse1 1; + Weapon.AmmoGive1 25; + Weapon.KickBack 150; + Weapon.YAdjust 10; + Weapon.AmmoType1 "Mana1"; + Inventory.PickupMessage "$TXT_WEAPON_C2"; + Obituary "$OB_MPCWEAPSTAFFM"; + Tag "$TAG_CWEAPSTAFF"; + } + + States + { + Spawn: + WCSS A -1; + Stop; + Select: + CSSF C 1 A_Raise; + Loop; + Deselect: + CSSF B 3; + CSSF C 4; + CSSF C 1 A_Lower; + Wait; + Ready: + CSSF C 4; + CSSF B 3 A_CStaffInitBlink; + CSSF AAAAAAA 1 A_WeaponReady; + CSSF A 1 A_CStaffCheckBlink; + Goto Ready + 2; + Fire: + CSSF A 1 Offset (0, 45) A_CStaffCheck; + CSSF J 1 Offset (0, 50) A_CStaffAttack; + CSSF J 2 Offset (0, 50); + CSSF J 2 Offset (0, 45); + CSSF A 2 Offset (0, 40); + CSSF A 2 Offset (0, 36); + Goto Ready + 2; + Blink: + CSSF BBBCCCCCBBB 1 A_WeaponReady; + Goto Ready + 2; + Drain: + CSSF K 10 Offset (0, 36); + Goto Ready + 2; + } + + //============================================================================ + // + // A_CStaffCheck + // + //============================================================================ + + action void A_CStaffCheck() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + Weapon weapon = player.ReadyWeapon; + + int damage = 20 + (random[StaffCheck]() & 15); + int max = player.mo.GetMaxHealth(); + for (int i = 0; i < 3; i++) + { + for (int j = 1; j >= -1; j -= 2) + { + double ang = angle + j*i*(45. / 16); + double slope = AimLineAttack(ang, 1.5 * MELEERANGE, t, 0., ALF_CHECK3D); + if (t.linetarget) + { + LineAttack(ang, 1.5 * MELEERANGE, slope, damage, 'Melee', "CStaffPuff", false, t); + if (t.linetarget != null) + { + angle = t.angleFromSource; + if (((t.linetarget.player && (!t.linetarget.IsTeammate(self) || level.teamdamage != 0)) || t.linetarget.bIsMonster) + && (!t.linetarget.bDormant && !bInvulnerable)) + { + int newLife = player.health + (damage >> 3); + newLife = newLife > max ? max : newLife; + if (newLife > player.health) + { + health = player.health = newLife; + } + if (weapon != null) + { + State newstate = weapon.FindState("Drain"); + if (newstate != null) player.SetPsprite(PSP_WEAPON, newstate); + } + } + if (weapon != null) + { + weapon.DepleteAmmo(weapon.bAltFire, false); + } + } + return; + } + } + } + } + + //============================================================================ + // + // A_CStaffAttack + // + //============================================================================ + + action void A_CStaffAttack() + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + Actor mo = SpawnPlayerMissile ("CStaffMissile", angle - 3.0); + if (mo) + { + mo.WeaveIndexXY = 32; + } + mo = SpawnPlayerMissile ("CStaffMissile", angle + 3.0); + if (mo) + { + mo.WeaveIndexXY = 0; + } + A_PlaySound ("ClericCStaffFire", CHAN_WEAPON); + } + + //============================================================================ + // + // A_CStaffInitBlink + // + //============================================================================ + + action void A_CStaffInitBlink() + { + weaponspecial = (random[CStaffBlink]() >> 1) + 20; + } + + //============================================================================ + // + // A_CStaffCheckBlink + // + //============================================================================ + + action void A_CStaffCheckBlink() + { + if (player && player.ReadyWeapon) + { + if (!--weaponspecial) + { + player.SetPsprite(PSP_WEAPON, player.ReadyWeapon.FindState ("Blink")); + weaponspecial = (random[CStaffBlink]() + 50) >> 2; + } + else + { + A_WeaponReady(); + } + } + } +} + +// Serpent Staff Missile ---------------------------------------------------- + +class CStaffMissile : Actor +{ + Default + { + Speed 22; + Radius 12; + Height 10; + Damage 5; + RenderStyle "Add"; + Projectile; + DeathSound "ClericCStaffExplode"; + Obituary "$OB_MPCWEAPSTAFFR"; + } + States + { + Spawn: + CSSF DDEE 1 Bright A_CStaffMissileSlither; + Loop; + Death: + CSSF FG 4 Bright; + CSSF HI 3 Bright; + Stop; + } + + override int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + // Cleric Serpent Staff does poison damage + if (target.player) + { + target.player.PoisonPlayer (self, self.target, 20); + damage >>= 1; + } + return damage; + } + +} + +extend class Actor +{ + + //============================================================================ + // + // A_CStaffMissileSlither + // + //============================================================================ + + void A_CStaffMissileSlither() + { + A_Weave(3, 0, 1., 0.); + } + +} + +// Serpent Staff Puff ------------------------------------------------------- + +class CStaffPuff : Actor +{ + Default + { + +NOBLOCKMAP +NOGRAVITY + +PUFFONACTORS + RenderStyle "Translucent"; + Alpha 0.6; + SeeSound "ClericCStaffHitThing"; + } + States + { + Spawn: + FHFX STUVW 4; + Stop; + } +} diff --git a/wadsrc/static/zscript/hexen/demons.txt b/wadsrc/static/zscript/hexen/demons.txt new file mode 100644 index 0000000000..25e078509b --- /dev/null +++ b/wadsrc/static/zscript/hexen/demons.txt @@ -0,0 +1,410 @@ + +// Demon, type 1 (green, like D'Sparil's) ----------------------------------- + +class Demon1 : Actor +{ + Default + { + Health 250; + Painchance 50; + Speed 13; + Radius 32; + Height 64; + Mass 220; + Monster; + +TELESTOMP + +FLOORCLIP + SeeSound "DemonSight"; + AttackSound "DemonAttack"; + PainSound "DemonPain"; + DeathSound "DemonDeath"; + ActiveSound "DemonActive"; + Obituary "$OB_DEMON1"; + } + + const ChunkFlags = SXF_TRANSFERTRANSLATION | SXF_ABSOLUTEVELOCITY; + + States + { + Spawn: + DEMN AA 10 A_Look; + Loop; + See: + DEMN ABCD 4 A_Chase; + Loop; + Pain: + DEMN E 4; + DEMN E 4 A_Pain; + Goto See; + Melee: + DEMN E 6 A_FaceTarget; + DEMN F 8 A_FaceTarget; + DEMN G 6 A_CustomMeleeAttack(random[DemonAttack1](1,8)*2); + Goto See; + Missile: + DEMN E 5 A_FaceTarget; + DEMN F 6 A_FaceTarget; + DEMN G 5 A_CustomMissile("Demon1FX1", 62, 0); + Goto See; + Death: + DEMN HI 6; + DEMN J 6 A_Scream; + DEMN K 6 A_NoBlocking; + DEMN L 6 A_QueueCorpse; + DEMN MNO 6; + DEMN P -1; + Stop; + XDeath: + DEMN H 6; + DEMN I 6 + { + static const class chunks[] = { "Demon1Chunk1", "Demon1Chunk2", "Demon1Chunk3", "Demon1Chunk4", "Demon1Chunk5" }; + for(int i = 0; i < 5; i++) + A_SpawnItemEx(chunks[i], 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle+90), frandom[DemonChunks](1,4.984375)*sin(Angle+90), 8, 90, ChunkFlags); + } + Goto Death+2; + Ice: + DEMN Q 5 A_FreezeDeath; + DEMN Q 1 A_FreezeDeathChunks; + Wait; + } +} + +// Demon, type 1, mashed ---------------------------------------------------- + +class Demon1Mash : Demon1 +{ + Default + { + +NOBLOOD + +BLASTED + -TELESTOMP + +NOICEDEATH + RenderStyle "Translucent"; + Alpha 0.4; + } + States + { + Death: + XDeath: + Ice: + Stop; + } +} + +// Demon chunk, base class -------------------------------------------------- + +class DemonChunk : Actor +{ + Default + { + Radius 5; + Height 5; + +NOBLOCKMAP + +DROPOFF + +MISSILE + +CORPSE + +FLOORCLIP + +NOTELEPORT + } +} + +// Demon, type 1, chunk 1 --------------------------------------------------- + +class Demon1Chunk1 : DemonChunk +{ + States + { + Spawn: + DEMA A 4; + DEMA A 10 A_QueueCorpse; + DEMA A 20; + Wait; + Death: + DEMA A -1; + Stop; + } +} + +// Demon, type 1, chunk 2 --------------------------------------------------- + +class Demon1Chunk2 : DemonChunk +{ + States + { + Spawn: + DEMB A 4; + DEMB A 10 A_QueueCorpse; + DEMB A 20; + Wait; + Death: + DEMB A -1; + Stop; + } +} + +class Demon1Chunk3 : DemonChunk +{ + States + { + Spawn: + DEMC A 4; + DEMC A 10 A_QueueCorpse; + DEMC A 20; + Wait; + Death: + DEMC A -1; + Stop; + } +} + +// Demon, type 1, chunk 4 --------------------------------------------------- + +class Demon1Chunk4 : DemonChunk +{ + States + { + Spawn: + DEMD A 4; + DEMD A 10 A_QueueCorpse; + DEMD A 20; + Wait; + Death: + DEMD A -1; + Stop; + } +} + +// Demon, type 1, chunk 5 --------------------------------------------------- + +class Demon1Chunk5 : DemonChunk +{ + States + { + Spawn: + DEME A 4; + DEME A 10 A_QueueCorpse; + DEME A 20; + Wait; + Death: + DEME A -1; + Stop; + } +} + +// Demon, type 1, projectile ------------------------------------------------ + +class Demon1FX1 : Actor +{ + Default + { + Speed 15; + Radius 10; + Height 6; + Damage 5; + DamageType "Fire"; + Projectile; + +SPAWNSOUNDSOURCE + RenderStyle "Add"; + SeeSound "DemonMissileFire"; + DeathSound "DemonMissileExplode"; + } + States + { + Spawn: + DMFX ABC 4 Bright; + Loop; + Death: + DMFX DE 4 Bright; + DMFX FGH 3 Bright; + Stop; + } +} + +// Demon, type 2 (brown) ---------------------------------------------------- + +class Demon2 : Demon1 +{ + Default + { + Obituary "$OB_DEMON2"; + Species "Demon2"; + } + States + { + Spawn: + DEM2 AA 10 A_Look; + Loop; + See: + DEM2 ABCD 4 A_Chase; + Loop; + Pain: + DEM2 E 4; + DEM2 E 4 A_Pain; + Goto See; + Melee: + DEM2 E 6 A_FaceTarget; + DEM2 F 8 A_FaceTarget; + DEM2 G 6 A_CustomMeleeAttack(random[DemonAttack1](1,8)*2); + Goto See; + Missile: + DEM2 E 5 A_FaceTarget; + DEM2 F 6 A_FaceTarget; + DEM2 G 5 A_CustomMissile("Demon2FX1", 62, 0); + Goto See; + Death: + DEM2 HI 6; + DEM2 J 6 A_Scream; + DEM2 K 6 A_NoBlocking; + DEM2 L 6 A_QueueCorpse; + DEM2 MNO 6; + DEM2 P -1; + Stop; + XDeath: + DEM2 H 6; + DEM2 I 6 + { + static const class chunks[] = { "Demon2Chunk1", "Demon2Chunk2", "Demon2Chunk3", "Demon2Chunk4", "Demon2Chunk5" }; + for(int i = 0; i < 5; i++) + A_SpawnItemEx(chunks[i], 0,0,45, frandom[DemonChunks](1,4.984375)*cos(Angle+90), frandom[DemonChunks](1,4.984375)*sin(Angle+90), 8, 90, ChunkFlags); + } + Goto Death+2; + } +} + +// Demon, type 2, mashed ---------------------------------------------------- + +class Demon2Mash : Demon2 +{ + Default + { + +NOBLOOD + +BLASTED + -TELESTOMP + +NOICEDEATH + RenderStyle "Translucent"; + Alpha 0.4; + } + States + { + Death: + XDeath: + Ice: + Stop; + } +} + +// Demon, type 2, chunk 1 --------------------------------------------------- + +class Demon2Chunk1 : DemonChunk +{ + States + { + Spawn: + DMBA A 4; + DMBA A 10 A_QueueCorpse; + DMBA A 20; + Wait; + Death: + DMBA A -1; + Stop; + } +} + +// Demon, type 2, chunk 2 --------------------------------------------------- + +class Demon2Chunk2 : DemonChunk +{ + States + { + Spawn: + DMBB A 4; + DMBB A 10 A_QueueCorpse; + DMBB A 20; + Wait; + Death: + DMBB A -1; + Stop; + } +} + +// Demon, type 2, chunk 3 --------------------------------------------------- + +class Demon2Chunk3 : DemonChunk +{ + States + { + Spawn: + DMBC A 4; + DMBC A 10 A_QueueCorpse; + DMBC A 20; + Wait; + Death: + DMBC A -1; + Stop; + } +} + +// Demon, type 2, chunk 4 --------------------------------------------------- + +class Demon2Chunk4 : DemonChunk +{ + States + { + Spawn: + DMBD A 4; + DMBD A 10 A_QueueCorpse; + DMBD A 20; + Wait; + Death: + DMBD A -1; + Stop; + } +} + +// Demon, type 2, chunk 5 --------------------------------------------------- + +class Demon2Chunk5 : DemonChunk +{ + States + { + Spawn: + DMBE A 4; + DMBE A 10 A_QueueCorpse; + DMBE A 20; + Wait; + Death: + DMBE A -1; + Stop; + } +} + +// Demon, type 2, projectile ------------------------------------------------ + +class Demon2FX1 : Actor +{ + Default + { + Speed 15; + Radius 10; + Height 6; + Damage 5; + DamageType "Fire"; + Projectile; + +SPAWNSOUNDSOURCE + RenderStyle "Add"; + SeeSound "DemonMissileFire"; + DeathSound "DemonMissileExplode"; + } + States + { + Spawn: + D2FX ABCDEF 4 Bright; + Loop; + Death: + D2FX GHIJ 4 Bright; + D2FX KL 3 Bright; + Stop; + } +} + diff --git a/wadsrc/static/zscript/hexen/dragon.txt b/wadsrc/static/zscript/hexen/dragon.txt new file mode 100644 index 0000000000..6082d1c61c --- /dev/null +++ b/wadsrc/static/zscript/hexen/dragon.txt @@ -0,0 +1,386 @@ +// Dragon ------------------------------------------------------------------- +class Dragon : Actor +{ + Default + { + Health 640; + PainChance 128; + Speed 10; + Height 65; + Mass 0x7fffffff; + Monster; + +NOGRAVITY +FLOAT +NOBLOOD + +BOSS + +DONTMORPH +NOTARGET + +NOICEDEATH + SeeSound "DragonSight"; + AttackSound "DragonAttack"; + PainSound "DragonPain"; + DeathSound "DragonDeath"; + ActiveSound "DragonActive"; + Obituary "$OB_DRAGON"; + } + + States + { + Spawn: + DRAG D 10 A_Look; + Loop; + See: + DRAG CB 5; + DRAG A 5 A_DragonInitFlight; + DRAG B 3 A_DragonFlap; + DRAG BCCDDCCBBAA 3 A_DragonFlight; + Goto See + 3; + Pain: + DRAG F 10 A_DragonPain; + Goto See + 3; + Missile: + DRAG E 8 A_DragonAttack; + Goto See + 3; + Death: + DRAG G 5 A_Scream; + DRAG H 4 A_NoBlocking; + DRAG I 4; + DRAG J 4 A_DragonCheckCrash; + Wait; + Crash: + DRAG KL 5; + DRAG M -1; + Stop; + } + + //============================================================================ + // + // DragonSeek + // + //============================================================================ + + private void DragonSeek (double thresh, double turnMax) + { + double dist; + double delta; + Actor targ; + int i; + double bestAngle; + double angleToSpot, angleToTarget; + Actor mo; + + targ = tracer; + if(targ == null) + { + return; + } + + double diff = deltaangle(angle, AngleTo(targ)); + delta = abs(diff); + + if (delta > thresh) + { + delta /= 2; + if (delta > turnMax) + { + delta = turnMax; + } + } + if (diff > 0) + { // Turn clockwise + angle = angle + delta; + } + else + { // Turn counter clockwise + angle = angle - delta; + } + VelFromAngle(); + + dist = DistanceBySpeed(targ, Speed); + if (pos.z + height < targ.pos.z || targ.pos.z + targ.height < pos.z) + { + Vel.Z = (targ.pos.z - pos.z) / dist; + } + if (targ.bShootable && random[DragonSeek]() < 64) + { // attack the destination mobj if it's attackable + Actor oldTarget; + + if (absangle(angle, AngleTo(targ)) < 22.5) + { + oldTarget = target; + target = targ; + if (CheckMeleeRange ()) + { + int damage = random[DragonSeek](1, 8) * 10; + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + A_PlaySound (AttackSound, CHAN_WEAPON); + } + else if (random[DragonSeek]() < 128 && CheckMissileRange()) + { + SpawnMissile(targ, "DragonFireball"); + A_PlaySound (AttackSound, CHAN_WEAPON); + } + target = oldTarget; + } + } + if (dist < 4) + { // Hit the target thing + if (target && random[DragonSeek]() < 200) + { + Actor bestActor = null; + bestAngle = 360.; + angleToTarget = AngleTo(target); + for (i = 0; i < 5; i++) + { + if (!targ.args[i]) + { + continue; + } + ActorIterator iter = ActorIterator.Create(targ.args[i]); + mo = iter.Next (); + if (mo == null) + { + continue; + } + angleToSpot = AngleTo(mo); + double diff = absangle(angleToSpot, angleToTarget); + if (diff < bestAngle) + { + bestAngle = diff; + bestActor = mo; + } + } + if (bestActor != null) + { + tracer = bestActor; + } + } + else + { + // [RH] Don't lock up if the dragon doesn't have any + // targs defined + for (i = 0; i < 5; ++i) + { + if (targ.args[i] != 0) + { + break; + } + } + if (i < 5) + { + do + { + i = (random[DragonSeek]() >> 2) % 5; + } while(!targ.args[i]); + ActorIterator iter = ActorIterator.Create(targ.args[i]); + tracer = iter.Next (); + } + } + } + } + + //============================================================================ + // + // A_DragonInitFlight + // + //============================================================================ + + void A_DragonInitFlight() + { + ActorIterator iter = ActorIterator.Create(tid); + + do + { // find the first tid identical to the dragon's tid + tracer = iter.Next (); + if (tracer == null) + { + SetState (SpawnState); + return; + } + } while (tracer == self); + RemoveFromHash (); + } + + //============================================================================ + // + // A_DragonFlight + // + //============================================================================ + + void A_DragonFlight() + { + double ang; + + DragonSeek (4., 8.); + if (target) + { + if(!target.bShootable) + { // target died + target = null; + return; + } + ang = absangle(angle, AngleTo(target)); + if (ang <22.5 && CheckMeleeRange()) + { + int damage = random[DragonFlight](1, 8) * 8; + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + A_PlaySound (AttackSound, CHAN_WEAPON); + } + else if (ang <= 20) + { + SetState (MissileState); + A_PlaySound (AttackSound, CHAN_WEAPON); + } + } + else + { + LookForPlayers (true); + } + } + + //============================================================================ + // + // A_DragonFlap + // + //============================================================================ + + void A_DragonFlap() + { + A_DragonFlight(); + if (random[DragonFlight]() < 240) + { + A_PlaySound ("DragonWingflap", CHAN_BODY); + } + else + { + PlayActiveSound (); + } + } + + //============================================================================ + // + // A_DragonAttack + // + //============================================================================ + + void A_DragonAttack() + { + SpawnMissile (target, "DragonFireball"); + } + + + //============================================================================ + // + // A_DragonPain + // + //============================================================================ + + void A_DragonPain() + { + A_Pain(); + if (!tracer) + { // no destination spot yet + SetState (SeeState); + } + } + + //============================================================================ + // + // A_DragonCheckCrash + // + //============================================================================ + + void A_DragonCheckCrash() + { + if (pos.z <= floorz) + { + SetStateLabel ("Crash"); + } + } +} + +// Dragon Fireball ---------------------------------------------------------- + +class DragonFireball : Actor +{ + Default + { + Speed 24; + Radius 12; + Height 10; + Damage 6; + DamageType "Fire"; + Projectile; + -ACTIVATEIMPACT -ACTIVATEPCROSS + RenderStyle "Add"; + DeathSound "DragonFireballExplode"; + } + + States + { + Spawn: + DRFX ABCDEF 4 Bright; + Loop; + Death: + DRFX GHI 4 Bright; + DRFX J 4 Bright A_DragonFX2; + DRFX KL 3 Bright; + Stop; + } + + //============================================================================ + // + // A_DragonFX2 + // + //============================================================================ + + void A_DragonFX2() + { + int delay = 16+(random[DragonFX2]()>>3); + for (int i = random[DragonFX2](1, 4); i; i--) + { + double xo = (random[DragonFX2]() - 128) / 4.; + double yo = (random[DragonFX2]() - 128) / 4.; + double zo = (random[DragonFX2]() - 128) / 16.; + + Actor mo = Spawn ("DragonExplosion", Vec3Offset(xo, yo, zo), ALLOW_REPLACE); + if (mo) + { + mo.tics = delay + (random[DragonFX2](0, 3)) * i*2; + mo.target = target; + } + } + } +} + +// Dragon Fireball Secondary Explosion -------------------------------------- + +class DragonExplosion : Actor +{ + Default + { + Radius 8; + Height 8; + DamageType "Fire"; + +NOBLOCKMAP + +NOTELEPORT + +INVISIBLE + RenderStyle "Add"; + DeathSound "DragonFireballExplode"; + } + States + { + Spawn: + CFCF Q 1 Bright; + CFCF Q 4 Bright A_UnHideThing; + CFCF R 3 Bright A_Scream; + CFCF S 4 Bright; + CFCF T 3 Bright A_Explode (80, 128, 0); + CFCF U 4 Bright; + CFCF V 3 Bright; + CFCF W 4 Bright; + CFCF X 3 Bright; + CFCF Y 4 Bright; + CFCF Z 3 Bright; + Stop; + } +} diff --git a/wadsrc/static/zscript/hexen/ettin.txt b/wadsrc/static/zscript/hexen/ettin.txt new file mode 100644 index 0000000000..8ddf9e7d2c --- /dev/null +++ b/wadsrc/static/zscript/hexen/ettin.txt @@ -0,0 +1,115 @@ + +// Ettin -------------------------------------------------------------------- + +class Ettin : Actor +{ + Default + { + Health 175; + Radius 25; + Height 68; + Mass 175; + Speed 13; + Damage 3; + Painchance 60; + Monster; + +FLOORCLIP + +TELESTOMP + SeeSound "EttinSight"; + AttackSound "EttinAttack"; + PainSound "EttinPain"; + DeathSound "EttinDeath"; + ActiveSound "EttinActive"; + HowlSound "PuppyBeat"; + Obituary "$OB_ETTIN"; + } + States + { + Spawn: + ETTN AA 10 A_Look; + Loop; + See: + ETTN ABCD 5 A_Chase; + Loop; + Pain: + ETTN H 7 A_Pain; + Goto See; + Melee: + ETTN EF 6 A_FaceTarget; + ETTN G 8 A_CustomMeleeAttack(random[EttinAttack](1,8)*2); + Goto See; + Death: + ETTN IJ 4; + ETTN K 4 A_Scream; + ETTN L 4 A_NoBlocking; + ETTN M 4 A_QueueCorpse; + ETTN NOP 4; + ETTN Q -1; + Stop; + XDeath: + ETTB A 4; + ETTB B 4 A_NoBlocking; + ETTB C 4 A_SpawnItemEx("EttinMace", 0,0,8.5, + random[DropMace](-128,127) * 0.03125, + random[DropMace](-128,127) * 0.03125, + 10 + random[DropMace](0,255) * 0.015625, 0, SXF_ABSOLUTEVELOCITY); + ETTB D 4 A_Scream; + ETTB E 4 A_QueueCorpse; + ETTB FGHIJK 4; + ETTB L -1; + Stop; + Ice: + ETTN R 5 A_FreezeDeath; + ETTN R 1 A_FreezeDeathChunks; + Wait; + } +} + +// Ettin mace --------------------------------------------------------------- + +class EttinMace : Actor +{ + Default + { + Radius 5; + Height 5; + +DROPOFF + +CORPSE + +NOTELEPORT + +FLOORCLIP + } + States + { + Spawn: + ETTB MNOP 5; + Loop; + Crash: + ETTB Q 5; + ETTB R 5 A_QueueCorpse; + ETTB S -1; + Stop; + } +} + +// Ettin mash --------------------------------------------------------------- + +class EttinMash : Ettin +{ + Default + { + +NOBLOOD + +NOICEDEATH + RenderStyle "Translucent"; + Alpha 0.4; + } + States + { + Death: + XDeath: + Ice: + Stop; + } +} + + + diff --git a/wadsrc/static/zscript/hexen/fighteraxe.txt b/wadsrc/static/zscript/hexen/fighteraxe.txt new file mode 100644 index 0000000000..1ff44a52f6 --- /dev/null +++ b/wadsrc/static/zscript/hexen/fighteraxe.txt @@ -0,0 +1,319 @@ + +// The Fighter's Axe -------------------------------------------------------- + +class FWeapAxe : FighterWeapon +{ + const AXERANGE = (2.25 * MELEERANGE); + + Default + { + Weapon.SelectionOrder 1500; + +WEAPON.AXEBLOOD +WEAPON.AMMO_OPTIONAL +WEAPON.MELEEWEAPON + Weapon.AmmoUse1 2; + Weapon.AmmoGive1 25; + Weapon.KickBack 150; + Weapon.YAdjust -12; + Weapon.AmmoType1 "Mana1"; + Inventory.PickupMessage "$TXT_WEAPON_F2"; + Obituary "$OB_MPFWEAPAXE"; + Tag "$TAG_FWEAPAXE"; + } + + States + { + Spawn: + WFAX A -1; + Stop; + Select: + FAXE A 1 A_FAxeCheckUp; + Loop; + Deselect: + FAXE A 1 A_Lower; + Loop; + Ready: + FAXE A 1 A_FAxeCheckReady; + Loop; + Fire: + FAXE B 4 Offset (15, 32) A_FAxeCheckAtk; + FAXE C 3 Offset (15, 32); + FAXE D 2 Offset (15, 32); + FAXE D 1 Offset (-5, 70) A_FAxeAttack; + FAXE D 2 Offset (-25, 90); + FAXE E 1 Offset (15, 32); + EndAttack: + FAXE E 2 Offset (10, 54); + FAXE E 7 Offset (10, 150); + FAXE A 1 Offset (0, 60) A_ReFire; + FAXE A 1 Offset (0, 52); + FAXE A 1 Offset (0, 44); + FAXE A 1 Offset (0, 36); + FAXE A 1; + Goto Ready; + SelectGlow: + FAXE L 1 A_FAxeCheckUpG; + Loop; + DeselectGlow: + FAXE L 1 A_Lower; + Loop; + ReadyGlow: + FAXE LLL 1 A_FAxeCheckReadyG; + FAXE MMM 1 A_FAxeCheckReadyG; + Loop; + FireGlow: + FAXE N 4 Offset (15, 32); + FAXE O 3 Offset (15, 32); + FAXE P 2 Offset (15, 32); + FAXE P 1 Offset (-5, 70) A_FAxeAttack; + FAXE P 2 Offset (-25, 90); + FAXE Q 1 Offset (15, 32); + FAXE Q 2 Offset (10, 54); + FAXE Q 7 Offset (10, 150); + FAXE A 1 Offset (0, 60) A_ReFire; + FAXE A 1 Offset (0, 52); + FAXE A 1 Offset (0, 44); + FAXE A 1 Offset (0, 36); + FAXE A 1; + Goto ReadyGlow; + } + + override State GetUpState () + { + return Ammo1.Amount ? FindState ("SelectGlow") : Super.GetUpState(); + } + + override State GetDownState () + { + return Ammo1.Amount ? FindState ("DeselectGlow") : Super.GetDownState(); + } + + override State GetReadyState () + { + return Ammo1.Amount ? FindState ("ReadyGlow") : Super.GetReadyState(); + } + + override State GetAtkState (bool hold) + { + return Ammo1.Amount ? FindState ("FireGlow") : Super.GetAtkState(hold); + } + + + + //============================================================================ + // + // A_FAxeCheckReady + // + //============================================================================ + + action void A_FAxeCheckReady() + { + if (player == null) + { + return; + } + Weapon w = player.ReadyWeapon; + if (w.Ammo1 && w.Ammo1.Amount > 0) + { + player.SetPsprite(PSP_WEAPON, w.FindState("ReadyGlow")); + } + else + { + A_WeaponReady(); + } + } + + //============================================================================ + // + // A_FAxeCheckReadyG + // + //============================================================================ + + action void A_FAxeCheckReadyG() + { + if (player == null) + { + return; + } + Weapon w = player.ReadyWeapon; + if (!w.Ammo1 || w.Ammo1.Amount <= 0) + { + player.SetPsprite(PSP_WEAPON, w.FindState("Ready")); + } + else + { + A_WeaponReady(); + } + } + + //============================================================================ + // + // A_FAxeCheckUp + // + //============================================================================ + + action void A_FAxeCheckUp() + { + if (player == null) + { + return; + } + Weapon w = player.ReadyWeapon; + if (w.Ammo1 && w.Ammo1.Amount > 0) + { + player.SetPsprite(PSP_WEAPON, w.FindState("SelectGlow")); + } + else + { + A_Raise(); + } + } + + //============================================================================ + // + // A_FAxeCheckUpG + // + //============================================================================ + + action void A_FAxeCheckUpG() + { + if (player == null) + { + return; + } + Weapon w = player.ReadyWeapon; + if (!w.Ammo1 || w.Ammo1.Amount <= 0) + { + player.SetPsprite(PSP_WEAPON, w.FindState("Select")); + } + else + { + A_Raise(); + } + } + + //============================================================================ + // + // A_FAxeCheckAtk + // + //============================================================================ + + action void A_FAxeCheckAtk() + { + if (player == null) + { + return; + } + Weapon w = player.ReadyWeapon; + if (w.Ammo1 && w.Ammo1.Amount > 0) + { + player.SetPsprite(PSP_WEAPON, w.FindState("FireGlow")); + } + } + + //============================================================================ + // + // A_FAxeAttack + // + //============================================================================ + + action void A_FAxeAttack() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + int damage = 40+(random[AxeAtk]() & 15); + damage += random[AxeAtk]() & 7; + int power = 0; + Weapon weapon = player.ReadyWeapon; + class pufftype; + int usemana; + if ((usemana = (weapon.Ammo1 && weapon.Ammo1.Amount > 0))) + { + damage <<= 1; + power = 6; + pufftype = "AxePuffGlow"; + } + else + { + pufftype = "AxePuff"; + } + for (int i = 0; i < 16; i++) + { + for (int j = 1; j >= -1; j -= 2) + { + double ang = angle + j*i*(45. / 16); + double slope = AimLineAttack(ang, AXERANGE, t); + if (t.linetarget) + { + LineAttack(ang, AXERANGE, slope, damage, 'Melee', pufftype, true, t); + if (t.linetarget != null) + { + if (t.linetarget.bIsMonster || t.linetarget.player) + { + t.linetarget.Thrust(power, t.attackAngleFromSource); + } + AdjustPlayerAngle(t); + + weapon.DepleteAmmo (weapon.bAltFire, false); + + if ((weapon.Ammo1 == null || weapon.Ammo1.Amount == 0) && + (!(weapon.bPrimary_Uses_Both) || + weapon.Ammo2 == null || weapon.Ammo2.Amount == 0)) + { + player.SetPsprite(PSP_WEAPON, weapon.FindState("EndAttack")); + } + return; + } + } + } + } + // didn't find any creatures, so try to strike any walls + self.weaponspecial = 0; + + double slope = AimLineAttack (angle, MELEERANGE); + LineAttack (angle, MELEERANGE, slope, damage, 'Melee', pufftype, true); + } +} + +// Axe Puff ----------------------------------------------------------------- + +class AxePuff : Actor +{ + Default + { + +NOBLOCKMAP +NOGRAVITY + +PUFFONACTORS + RenderStyle "Translucent"; + Alpha 0.6; + SeeSound "FighterAxeHitThing"; + AttackSound "FighterHammerHitWall"; + ActiveSound "FighterHammerMiss"; + } + States + { + Spawn: + FHFX STUVW 4; + Stop; + } +} + +// Glowing Axe Puff --------------------------------------------------------- + +class AxePuffGlow : AxePuff +{ + Default + { + +PUFFONACTORS + RenderStyle "Add"; + Alpha 1; + } + States + { + Spawn: + FAXE RSTUVWX 4 Bright; + Stop; + } +} diff --git a/wadsrc/static/zscript/hexen/fighterboss.txt b/wadsrc/static/zscript/hexen/fighterboss.txt new file mode 100644 index 0000000000..9871cf5717 --- /dev/null +++ b/wadsrc/static/zscript/hexen/fighterboss.txt @@ -0,0 +1,99 @@ + +// Fighter Boss (Zedek) ----------------------------------------------------- + +class FighterBoss : Actor +{ + Default + { + health 800; + PainChance 50; + Speed 25; + Radius 16; + Height 64; + Monster; + +FLOORCLIP + +TELESTOMP + +DONTMORPH + PainSound "PlayerFighterPain"; + DeathSound "PlayerFighterCrazyDeath"; + Obituary "$OB_FBOSS"; + } + + States + { + Spawn: + PLAY A 2; + PLAY A 3 A_ClassBossHealth; + PLAY A 5 A_Look; + Wait; + See: + PLAY ABCD 4 A_FastChase; + Loop; + Pain: + PLAY G 4; + PLAY G 4 A_Pain; + Goto See; + Melee: + Missile: + PLAY E 8 A_FaceTarget; + PLAY F 8 A_FighterAttack; + Goto See; + Death: + PLAY H 6; + PLAY I 6 A_Scream; + PLAY JK 6; + PLAY L 6 A_NoBlocking; + PLAY M 6; + PLAY N -1; + Stop; + XDeath: + PLAY O 5 A_Scream; + PLAY P 5 A_SkullPop; + PLAY R 5 A_NoBlocking; + PLAY STUV 5; + PLAY W -1; + Stop; + Ice: + PLAY X 5 A_FreezeDeath; + PLAY X 1 A_FreezeDeathChunks; + Wait; + Burn: + FDTH A 5 Bright A_PlaySound("PlayerFighterBurnDeath"); + FDTH B 4 Bright; + FDTH G 5 Bright; + FDTH H 4 Bright A_Scream; + FDTH I 5 Bright; + FDTH J 4 Bright; + FDTH K 5 Bright; + FDTH L 4 Bright; + FDTH M 5 Bright; + FDTH N 4 Bright; + FDTH O 5 Bright; + FDTH P 4 Bright; + FDTH Q 5 Bright; + FDTH R 4 Bright; + FDTH S 5 Bright A_NoBlocking; + FDTH T 4 Bright; + FDTH U 5 Bright; + FDTH V 4 Bright; + Stop; + } + + //============================================================================ + // + // A_FighterAttack + // + //============================================================================ + + void A_FighterAttack() + { + if (!target) return; + + SpawnMissileAngle("FSwordMissile", Angle + (45. / 4), 0); + SpawnMissileAngle("FSwordMissile", Angle + (45. / 8), 0); + SpawnMissileAngle("FSwordMissile", Angle, 0); + SpawnMissileAngle("FSwordMissile", Angle - (45. / 8), 0); + SpawnMissileAngle("FSwordMissile", Angle - (45. / 4), 0); + A_PlaySound ("FighterSwordFire", CHAN_WEAPON); + } +} diff --git a/wadsrc/static/zscript/hexen/fighterfist.txt b/wadsrc/static/zscript/hexen/fighterfist.txt new file mode 100644 index 0000000000..2898227896 --- /dev/null +++ b/wadsrc/static/zscript/hexen/fighterfist.txt @@ -0,0 +1,147 @@ + +// Fist (first weapon) ------------------------------------------------------ + +class FWeapFist : FighterWeapon +{ + Default + { + +BLOODSPLATTER + Weapon.SelectionOrder 3400; + +WEAPON.MELEEWEAPON + Weapon.KickBack 150; + Obituary "$OB_MPFWEAPFIST"; + Tag "$TAG_FWEAPFIST"; + } + + States + { + Select: + FPCH A 1 A_Raise; + Loop; + Deselect: + FPCH A 1 A_Lower; + Loop; + Ready: + FPCH A 1 A_WeaponReady; + Loop; + Fire: + FPCH B 5 Offset (5, 40); + FPCH C 4 Offset (5, 40); + FPCH D 4 Offset (5, 40) A_FPunchAttack; + FPCH C 4 Offset (5, 40); + FPCH B 5 Offset (5, 40) A_ReFire; + Goto Ready; + Fire2: + FPCH DE 4 Offset (5, 40); + FPCH E 1 Offset (15, 50); + FPCH E 1 Offset (25, 60); + FPCH E 1 Offset (35, 70); + FPCH E 1 Offset (45, 80); + FPCH E 1 Offset (55, 90); + FPCH E 1 Offset (65, 90); + FPCH E 10 Offset (0, 150); + Goto Ready; + } + + //============================================================================ + // + // TryPunch + // + // Returns true if an actor was punched, false if not. + // + //============================================================================ + + private action bool TryPunch(double angle, int damage, int power) + { + Class pufftype; + FTranslatedLineTarget t; + + double slope = AimLineAttack (angle, 2*MELEERANGE, t); + if (t.linetarget != null) + { + if (++weaponspecial >= 3) + { + damage <<= 1; + power *= 3; + pufftype = "HammerPuff"; + } + else + { + pufftype = "PunchPuff"; + } + LineAttack (angle, 2*MELEERANGE, slope, damage, 'Melee', pufftype, true, t); + if (t.linetarget != null) + { + // The mass threshold has been changed to CommanderKeen's value which has been used most often for 'unmovable' stuff. + if (t.linetarget.player != null || + (t.linetarget.Mass < 10000000 && (t.linetarget.bIsMonster))) + { + if (!t.linetarget.bDontThrust) + t.linetarget.Thrust(power, t.attackAngleFromSource); + } + AdjustPlayerAngle(t); + return true; + } + } + return false; + } + + //============================================================================ + // + // A_FPunchAttack + // + //============================================================================ + + action void A_FPunchAttack() + { + if (player == null) + { + return; + } + + int damage = 40 + (random[FighterAtk]() & 15); + for (int i = 0; i < 16; i++) + { + if (TryPunch(angle + i*(45./16), damage, 2) || + TryPunch(angle - i*(45./16), damage, 2)) + { // hit something + if (weaponspecial >= 3) + { + weaponspecial = 0; + player.SetPsprite(PSP_WEAPON, player.ReadyWeapon.FindState("Fire2")); + A_PlaySound ("*fistgrunt", CHAN_VOICE); + } + return; + } + } + // didn't find any creatures, so try to strike any walls + weaponspecial = 0; + + double slope = AimLineAttack (angle, MELEERANGE); + LineAttack (angle, MELEERANGE, slope, damage, 'Melee', "PunchPuff", true); + } + +} + +// Punch puff --------------------------------------------------------------- + +class PunchPuff : Actor +{ + Default + { + +NOBLOCKMAP +NOGRAVITY + +PUFFONACTORS + RenderStyle "Translucent"; + Alpha 0.6; + SeeSound "FighterPunchHitThing"; + AttackSound "FighterPunchHitWall"; + ActiveSound "FighterPunchMiss"; + VSpeed 1; + } + States + { + Spawn: + FHFX STUVW 4; + Stop; + } +} diff --git a/wadsrc/static/zscript/hexen/fighterhammer.txt b/wadsrc/static/zscript/hexen/fighterhammer.txt new file mode 100644 index 0000000000..f1b06b75ce --- /dev/null +++ b/wadsrc/static/zscript/hexen/fighterhammer.txt @@ -0,0 +1,190 @@ + +// The Fighter's Hammer ----------------------------------------------------- + +class FWeapHammer : FighterWeapon +{ + const HAMMER_RANGE = 1.5 * MELEERANGE; + + Default + { + +BLOODSPLATTER + Weapon.SelectionOrder 900; + +WEAPON.AMMO_OPTIONAL +WEAPON.MELEEWEAPON + Weapon.AmmoUse1 3; + Weapon.AmmoGive1 25; + Weapon.KickBack 150; + Weapon.YAdjust -10; + Weapon.AmmoType1 "Mana2"; + Inventory.PickupMessage "$TXT_WEAPON_F3"; + Obituary "$OB_MPFWEAPHAMMERM"; + Tag "$TAG_FWEAPHAMMER"; + } + + States + { + Spawn: + WFHM A -1; + Stop; + Select: + FHMR A 1 A_Raise; + Loop; + Deselect: + FHMR A 1 A_Lower; + Loop; + Ready: + FHMR A 1 A_WeaponReady; + Loop; + Fire: + FHMR B 6 Offset (5, 0); + FHMR C 3 Offset (5, 0) A_FHammerAttack; + FHMR D 3 Offset (5, 0); + FHMR E 2 Offset (5, 0); + FHMR E 10 Offset (5, 150) A_FHammerThrow; + FHMR A 1 Offset (0, 60); + FHMR A 1 Offset (0, 55); + FHMR A 1 Offset (0, 50); + FHMR A 1 Offset (0, 45); + FHMR A 1 Offset (0, 40); + FHMR A 1 Offset (0, 35); + FHMR A 1; + Goto Ready; + } + + //============================================================================ + // + // A_FHammerAttack + // + //============================================================================ + + action void A_FHammerAttack() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + int damage = 60+(random[HammerAtk]() & 63); + for (int i = 0; i < 16; i++) + { + for (int j = 1; j >= -1; j -= 2) + { + double ang = angle + j*i*(45. / 32); + double slope = AimLineAttack(ang, HAMMER_RANGE, t, 0., ALF_CHECK3D); + if (t.linetarget != null) + { + LineAttack(ang, HAMMER_RANGE, slope, damage, 'Melee', "HammerPuff", true, t); + if (t.linetarget != null) + { + AdjustPlayerAngle(t); + if (t.linetarget.bIsMonster || t.linetarget.player) + { + t.linetarget.Thrust(10, t.attackAngleFromSource); + } + weaponspecial = false; // Don't throw a hammer + return; + } + } + } + } + // didn't find any targets in meleerange, so set to throw out a hammer + double slope = AimLineAttack (angle, HAMMER_RANGE, null, 0., ALF_CHECK3D); + weaponspecial = (LineAttack (angle, HAMMER_RANGE, slope, damage, 'Melee', "HammerPuff", true) == null); + + // Don't spawn a hammer if the player doesn't have enough mana + if (player.ReadyWeapon == null || + !player.ReadyWeapon.CheckAmmo (player.ReadyWeapon.bAltFire ? + Weapon.AltFire : Weapon.PrimaryFire, false, true)) + { + weaponspecial = false; + } + } + + //============================================================================ + // + // A_FHammerThrow + // + //============================================================================ + + action void A_FHammerThrow() + { + if (player == null) + { + return; + } + + if (!weaponspecial) + { + return; + } + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire, false)) + return; + } + Actor mo = SpawnPlayerMissile ("HammerMissile"); + if (mo) + { + mo.special1 = 0; + } + } +} + +// Hammer Missile ----------------------------------------------------------- + +class HammerMissile : Actor +{ + Default + { + Speed 25; + Radius 14; + Height 20; + Damage 10; + DamageType "Fire"; + Projectile; + DeathSound "FighterHammerExplode"; + Obituary "$OB_MPFWEAPHAMMERR"; + } + + States + { + Spawn: + FHFX A 2 Bright; + FHFX B 2 Bright A_PlaySound ("FighterHammerContinuous"); + FHFX CDEFGH 2 Bright; + Loop; + Death: + FHFX I 3 Bright A_SetRenderStyle(1, STYLE_Add); + FHFX J 3 Bright; + FHFX K 3 Bright A_Explode (128, 128, 0); + FHFX LM 3 Bright; + FHFX N 3; + FHFX OPQR 3 Bright; + Stop; + } +} + +// Hammer Puff (also used by fist) ------------------------------------------ + +class HammerPuff : Actor +{ + Default + { + +NOBLOCKMAP +NOGRAVITY + +PUFFONACTORS + RenderStyle "Translucent"; + Alpha 0.6; + VSpeed 0.8; + SeeSound "FighterHammerHitThing"; + AttackSound "FighterHammerHitWall"; + ActiveSound "FighterHammerMiss"; + } + States + { + Spawn: + FHFX STUVW 4; + Stop; + } +} diff --git a/wadsrc/static/zscript/hexen/fighterplayer.txt b/wadsrc/static/zscript/hexen/fighterplayer.txt new file mode 100644 index 0000000000..3aa5607d33 --- /dev/null +++ b/wadsrc/static/zscript/hexen/fighterplayer.txt @@ -0,0 +1,133 @@ +// The fighter -------------------------------------------------------------- + +class FighterPlayer : PlayerPawn +{ + Default + { + Health 100; + PainChance 255; + Radius 16; + Height 64; + Speed 1; + +NOSKIN + +NODAMAGETHRUST + +PLAYERPAWN.NOTHRUSTWHENINVUL + PainSound "PlayerFighterPain"; + RadiusDamageFactor 0.25; + Player.JumpZ 9; + Player.Viewheight 48; + Player.SpawnClass "Fighter"; + Player.DisplayName "Fighter"; + Player.SoundClass "fighter"; + Player.ScoreIcon "FITEFACE"; + Player.HealRadiusType "Armor"; + Player.Hexenarmor 15, 25, 20, 15, 5; + Player.StartItem "FWeapFist"; + Player.ForwardMove 1.08, 1.2; + Player.SideMove 1.125, 1.475; + Player.Portrait "P_FWALK1"; + Player.WeaponSlot 1, "FWeapFist"; + Player.WeaponSlot 2, "FWeapAxe"; + Player.WeaponSlot 3, "FWeapHammer"; + Player.WeaponSlot 4, "FWeapQuietus"; + + Player.ColorRange 246, 254; + Player.Colorset 0, "Gold", 246, 254, 253; + Player.ColorsetFile 1, "Red", "TRANTBL0", 0xAC; + Player.ColorsetFile 2, "Blue", "TRANTBL1", 0x9D; + Player.ColorsetFile 3, "Dull Green", "TRANTBL2", 0x3E; + Player.ColorsetFile 4, "Green", "TRANTBL3", 0xC8; + Player.ColorsetFile 5, "Gray", "TRANTBL4", 0x2D; + Player.ColorsetFile 6, "Brown", "TRANTBL5", 0x6F; + Player.ColorsetFile 7, "Purple", "TRANTBL6", 0xEE; + } + + States + { + Spawn: + PLAY A -1; + Stop; + See: + PLAY ABCD 4; + Loop; + Missile: + Melee: + PLAY EF 8; + Goto Spawn; + Pain: + PLAY G 4; + PLAY G 4 A_Pain; + Goto Spawn; + Death: + PLAY H 6; + PLAY I 6 A_PlayerScream; + PLAY JK 6; + PLAY L 6 A_NoBlocking; + PLAY M 6; + PLAY N -1; + Stop; + XDeath: + PLAY O 5 A_PlayerScream; + PLAY P 5 A_SkullPop("BloodyFighterSkull"); + PLAY R 5 A_NoBlocking; + PLAY STUV 5; + PLAY W -1; + Stop; + Ice: + PLAY X 5 A_FreezeDeath; + PLAY X 1 A_FreezeDeathChunks; + Wait; + Burn: + FDTH A 5 BRIGHT A_PlaySound("*burndeath"); + FDTH B 4 BRIGHT; + FDTH G 5 BRIGHT; + FDTH H 4 BRIGHT A_PlayerScream; + FDTH I 5 BRIGHT; + FDTH J 4 BRIGHT; + FDTH K 5 BRIGHT; + FDTH L 4 BRIGHT; + FDTH M 5 BRIGHT; + FDTH N 4 BRIGHT; + FDTH O 5 BRIGHT; + FDTH P 4 BRIGHT; + FDTH Q 5 BRIGHT; + FDTH R 4 BRIGHT; + FDTH S 5 BRIGHT A_NoBlocking; + FDTH T 4 BRIGHT; + FDTH U 5 BRIGHT; + FDTH V 4 BRIGHT; + ACLO E 35 A_CheckPlayerDone; + Wait; + ACLO E 8; + Stop; + } +} + +// The fighter's bloody skull -------------------------------------------------------------- + +class BloodyFighterSkull : PlayerChunk +{ + Default + { + Radius 4; + Height 4; + Gravity 0.125; + +NOBLOCKMAP + +DROPOFF + +CANNOTPUSH + +SKYEXPLODE + +NOBLOCKMONST + +NOSKIN + } + + States + { + Spawn: + BSKL A 0; + BSKL ABCDFGH 5 A_CheckFloor("Hit"); + Goto Spawn+1; + Hit: + BSKL I 16 A_CheckPlayerDone; + Wait; + } +} diff --git a/wadsrc/static/zscript/hexen/fighterquietus.txt b/wadsrc/static/zscript/hexen/fighterquietus.txt new file mode 100644 index 0000000000..53388eece0 --- /dev/null +++ b/wadsrc/static/zscript/hexen/fighterquietus.txt @@ -0,0 +1,236 @@ + +// Fighter Weapon Piece ----------------------------------------------------- + +class FighterWeaponPiece : WeaponPiece +{ + Default + { + Inventory.PickupSound "misc/w_pkup"; + Inventory.PickupMessage "$TXT_QUIETUS_PIECE"; + Inventory.ForbiddenTo "ClericPlayer", "MagePlayer"; + WeaponPiece.Weapon "FWeapQuietus"; + +FLOATBOB + } +} + +// Fighter Weapon Piece 1 --------------------------------------------------- + +class FWeaponPiece1 : FighterWeaponPiece +{ + Default + { + WeaponPiece.Number 1; + } + States + { + Spawn: + WFR1 A -1 Bright; + Stop; + } +} + +// Fighter Weapon Piece 2 --------------------------------------------------- + +class FWeaponPiece2 : FighterWeaponPiece +{ + Default + { + WeaponPiece.Number 2; + } + States + { + Spawn: + WFR2 A -1 Bright; + Stop; + } +} + +// Fighter Weapon Piece 3 --------------------------------------------------- + +class FWeaponPiece3 : FighterWeaponPiece +{ + Default + { + WeaponPiece.Number 3; + } + States + { + Spawn: + WFR3 A -1 Bright; + Stop; + } +} + +// Quietus Drop ------------------------------------------------------------- + +class QuietusDrop : Actor +{ + States + { + Spawn: + TNT1 A 1; + TNT1 A 1 A_DropWeaponPieces("FWeaponPiece1", "FWeaponPiece2", "FWeaponPiece3"); + Stop; + } +} + +// The Fighter's Sword (Quietus) -------------------------------------------- + +class FWeapQuietus : FighterWeapon +{ + Default + { + Health 3; + Weapon.SelectionOrder 2900; + +WEAPON.PRIMARY_USES_BOTH; + +Inventory.NoAttenPickupSound + Weapon.AmmoUse1 14; + Weapon.AmmoUse2 14; + Weapon.AmmoGive1 20; + Weapon.AmmoGive2 20; + Weapon.KickBack 150; + Weapon.YAdjust 10; + Weapon.AmmoType1 "Mana1"; + Weapon.AmmoType2 "Mana2"; + Inventory.PickupMessage "$TXT_WEAPON_F4"; + Inventory.PickupSound "WeaponBuild"; + Tag "$TAG_FWEAPQUIETUS"; + } + + States + { + Spawn: + TNT1 A -1; + Stop; + Select: + FSRD A 1 Bright A_Raise; + Loop; + Deselect: + FSRD A 1 Bright A_Lower; + Loop; + Ready: + FSRD AAAABBBBCCCC 1 Bright A_WeaponReady; + Loop; + Fire: + FSRD DE 3 Bright Offset (5, 36); + FSRD F 2 Bright Offset (5, 36); + FSRD G 3 Bright Offset (5, 36) A_FSwordAttack; + FSRD H 2 Bright Offset (5, 36); + FSRD I 2 Bright Offset (5, 36); + FSRD I 10 Bright Offset (5, 150); + FSRD A 1 Bright Offset (5, 60); + FSRD B 1 Bright Offset (5, 55); + FSRD C 1 Bright Offset (5, 50); + FSRD A 1 Bright Offset (5, 45); + FSRD B 1 Bright Offset (5, 40); + Goto Ready; + } + + //============================================================================ + // + // A_FSwordAttack + // + //============================================================================ + + action void A_FSwordAttack() + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + SpawnPlayerMissile ("FSwordMissile", Angle + (45./4),0, 0, -10); + SpawnPlayerMissile ("FSwordMissile", Angle + (45./8),0, 0, -5); + SpawnPlayerMissile ("FSwordMissile", Angle ,0, 0, 0); + SpawnPlayerMissile ("FSwordMissile", Angle - (45./8),0, 0, 5); + SpawnPlayerMissile ("FSwordMissile", Angle - (45./4),0, 0, 10); + A_PlaySound ("FighterSwordFire", CHAN_WEAPON); + } + + +} + +// Fighter Sword Missile ---------------------------------------------------- + +class FSwordMissile : Actor +{ + Default + { + Speed 30; + Radius 16; + Height 8; + Damage 8; + Projectile; + +EXTREMEDEATH + RenderStyle "Add"; + DeathSound "FighterSwordExplode"; + Obituary "$OB_MPFWEAPQUIETUS"; + } + + States + { + Spawn: + FSFX ABC 3 Bright; + Loop; + Death: + FSFX D 4 Bright; + FSFX E 3 Bright A_FSwordFlames; + FSFX F 4 Bright A_Explode (64, 128, 0); + FSFX G 3 Bright; + FSFX H 4 Bright; + FSFX I 3 Bright; + FSFX J 4 Bright; + FSFX KLM 3 Bright; + Stop; + } + + override int DoSpecialDamage(Actor victim, int damage, Name damagetype) + { + if (victim.player) + { + damage -= damage >> 2; + } + return damage; + } + + //============================================================================ + // + // A_FSwordFlames + // + //============================================================================ + + void A_FSwordFlames() + { + for (int i = 1+(random[FSwordFlame]()&3); i; i--) + { + double xo = (random[FSwordFlame]() - 128) / 16.; + double yo = (random[FSwordFlame]() - 128) / 16.; + double zo = (random[FSwordFlame]() - 128) / 8.; + Spawn ("FSwordFlame", Vec3Offset(xo, yo, zo), ALLOW_REPLACE); + } + } +} + +// Fighter Sword Flame ------------------------------------------------------ + +class FSwordFlame : Actor +{ + Default + { + +NOBLOCKMAP +NOGRAVITY + RenderStyle "Translucent"; + Alpha 0.6; + } + States + { + Spawn: + FSFX NOPQRSTUVW 3 Bright; + Stop; + } +} diff --git a/wadsrc/static/zscript/hexen/firedemon.txt b/wadsrc/static/zscript/hexen/firedemon.txt new file mode 100644 index 0000000000..9ca12529f5 --- /dev/null +++ b/wadsrc/static/zscript/hexen/firedemon.txt @@ -0,0 +1,449 @@ + +// FireDemon ---------------------------------------------------------------- + +class FireDemon : Actor +{ + const FIREDEMON_ATTACK_RANGE = 64*8.; + int fdstrafecount; + + Default + { + Health 80; + ReactionTime 8; + PainChance 1; + Speed 13; + Radius 20; + Height 68; + Mass 75; + Damage 1; + Monster; + +DROPOFF +NOGRAVITY +FLOAT + +FLOORCLIP +INVULNERABLE +TELESTOMP + SeeSound "FireDemonSpawn"; + PainSound "FireDemonPain"; + DeathSound "FireDemonDeath"; + ActiveSound "FireDemonActive"; + Obituary "$OB_FIREDEMON"; + } + + States + { + Spawn: + FDMN X 5 Bright; + FDMN EFG 10 Bright A_Look; + Goto Spawn + 1; + See: + FDMN E 8 Bright; + FDMN F 6 Bright; + FDMN G 5 Bright; + FDMN F 8 Bright; + FDMN E 6 Bright; + FDMN G 7 Bright A_FiredRocks; + FDMN HI 5 Bright; + FDMN J 5 Bright A_UnSetInvulnerable; + Chase: + FDMN ABC 5 Bright A_FiredChase; + Loop; + Pain: + FDMN D 0 Bright A_UnSetInvulnerable; + FDMN D 6 Bright A_Pain; + Goto Chase; + Missile: + FDMN K 3 Bright A_FaceTarget; + FDMN KKK 5 Bright A_FiredAttack; + Goto Chase; + Crash: + XDeath: + FDMN M 5 A_FaceTarget; + FDMN N 5 A_NoBlocking; + FDMN O 5 A_FiredSplotch; + Stop; + Death: + FDMN D 4 Bright A_FaceTarget; + FDMN L 4 Bright A_Scream; + FDMN L 4 Bright A_NoBlocking; + FDMN L 200 Bright; + Stop; + Ice: + FDMN R 5 A_FreezeDeath; + FDMN R 1 A_FreezeDeathChunks; + Wait; + } + + + + + //============================================================================ + // Fire Demon AI + // + // special1 index into floatbob + // fdstrafecount whether strafing or not + //============================================================================ + + //============================================================================ + // + // A_FiredSpawnRock + // + //============================================================================ + + private void A_FiredSpawnRock () + { + Actor mo; + class rtype; + + switch (random[FireDemonRock](0, 4)) + { + case 0: + rtype = "FireDemonRock1"; + break; + case 1: + rtype = "FireDemonRock2"; + break; + case 2: + rtype = "FireDemonRock3"; + break; + case 3: + rtype = "FireDemonRock4"; + break; + case 4: + default: + rtype = "FireDemonRock5"; + break; + } + + double xo = (random[FireDemonRock]() - 128) / 16.; + double yo = (random[FireDemonRock]() - 128) / 16.; + double zo = random[FireDemonRock]() / 32.; + mo = Spawn (rtype, Vec3Offset(xo, yo, zo), ALLOW_REPLACE); + if (mo) + { + mo.target = self; + mo.Vel.X = (random[FireDemonRock]() - 128) / 64.; + mo.Vel.Y = (random[FireDemonRock]() - 128) / 64.; + mo.Vel.Z = (random[FireDemonRock]() / 64.); + mo.special1 = 2; // Number bounces + } + + // Initialize fire demon + fdstrafecount = 0; + bJustAttacked = false; + } + + //============================================================================ + // + // A_FiredRocks + // + //============================================================================ + void A_FiredRocks() + { + A_FiredSpawnRock (); + A_FiredSpawnRock (); + A_FiredSpawnRock (); + A_FiredSpawnRock (); + A_FiredSpawnRock (); + } + + //============================================================================ + // + // A_FiredAttack + // + //============================================================================ + + void A_FiredAttack() + { + if (target == null) return; + Actor mo = SpawnMissile (target, "FireDemonMissile"); + if (mo) A_PlaySound ("FireDemonAttack", CHAN_BODY); + } + + //============================================================================ + // + // A_FiredChase + // + //============================================================================ + + void A_FiredChase() + { + int weaveindex = special1; + double ang; + double dist; + + if (reactiontime) reactiontime--; + if (threshold) threshold--; + + // Float up and down + AddZ(BobSin(weaveindex)); + special1 = (weaveindex + 2) & 63; + + // Ensure it stays above certain height + if (pos.Z < floorz + 64) + { + AddZ(2); + } + + if(!target || !target.bShootable) + { // Invalid target + LookForPlayers (true); + return; + } + + // Strafe + if (fdstrafecount > 0) + { + fdstrafecount--; + } + else + { + fdstrafecount = 0; + Vel.X = Vel.Y = 0; + dist = Distance2D(target); + if (dist < FIREDEMON_ATTACK_RANGE) + { + if (random[FiredChase]() < 30) + { + ang = AngleTo(target); + if (random[FiredChase]() < 128) + ang += 90; + else + ang -= 90; + Thrust(8, ang); + fdstrafecount = 3; // strafe time + } + } + } + + FaceMovementDirection (); + + // Normal movement + if (!fdstrafecount) + { + if (--movecount<0 || !MonsterMove ()) + { + NewChaseDir (); + } + } + + // Do missile attack + if (!bJustAttacked) + { + if (CheckMissileRange () && (random[FiredChase]() < 20)) + { + SetState (MissileState); + bJustAttacked = true; + return; + } + } + else + { + bJustAttacked = false; + } + + // make active sound + if (random[FiredChase]() < 3) + { + PlayActiveSound (); + } + } + + //============================================================================ + // + // A_FiredSplotch + // + //============================================================================ + + void A_FiredSplotch() + { + Actor mo; + + mo = Spawn ("FireDemonSplotch1", Pos, ALLOW_REPLACE); + if (mo) + { + mo.Vel.X = (random[FireDemonSplotch]() - 128) / 32.; + mo.Vel.Y = (random[FireDemonSplotch]() - 128) / 32.; + mo.Vel.Z = (random[FireDemonSplotch]() / 64.) + 3; + } + mo = Spawn ("FireDemonSplotch2", Pos, ALLOW_REPLACE); + if (mo) + { + mo.Vel.X = (random[FireDemonSplotch]() - 128) / 32.; + mo.Vel.Y = (random[FireDemonSplotch]() - 128) / 32.; + mo.Vel.Z = (random[FireDemonSplotch]() / 64.) + 3; + } + } + +} + +// FireDemonSplotch1 ------------------------------------------------------- + +class FireDemonSplotch1 : Actor +{ + Default + { + ReactionTime 8; + Radius 3; + Height 16; + Mass 100; + +DROPOFF +CORPSE + +NOTELEPORT +FLOORCLIP + } + States + { + Spawn: + FDMN P 3; + FDMN P 6 A_QueueCorpse; + FDMN Y -1; + Stop; + } +} + +// FireDemonSplotch2 ------------------------------------------------------- + +class FireDemonSplotch2 : FireDemonSplotch1 +{ + States + { + Spawn: + FDMN Q 3; + FDMN Q 6 A_QueueCorpse; + FDMN Z -1; + Stop; + } +} + +// FireDemonRock1 ------------------------------------------------------------ + +class FireDemonRock1 : Actor +{ + Default + { + ReactionTime 8; + Radius 3; + Height 5; + Mass 16; + +NOBLOCKMAP +DROPOFF +MISSILE + +NOTELEPORT + } + + States + { + Spawn: + FDMN S 4; + Loop; + Death: + FDMN S 5 A_SmBounce; + XDeath: + FDMN S 200; + Stop; + } + + //============================================================================ + // + // A_SmBounce + // + //============================================================================ + + void A_SmBounce() + { + // give some more velocity (x,y,&z) + SetZ(floorz + 1); + Vel.Z = 2. + random[SMBounce]() / 64.; + Vel.X = random[SMBounce](0, 2); + Vel.Y = random[SMBounce](0, 2); + } +} + +// FireDemonRock2 ------------------------------------------------------------ + +class FireDemonRock2 : FireDemonRock1 +{ + States + { + Spawn: + FDMN T 4; + Loop; + Death: + FDMN T 5 A_SmBounce; + XDeath: + FDMN T 200; + Stop; + } +} + +// FireDemonRock3 ------------------------------------------------------------ + +class FireDemonRock3 : FireDemonRock1 +{ + States + { + Spawn: + FDMN U 4; + Loop; + Death: + FDMN U 5 A_SmBounce; + XDeath: + FDMN U 200; + Stop; + } +} + +// FireDemonRock4 ------------------------------------------------------------ + +class FireDemonRock4 : FireDemonRock1 +{ + States + { + Spawn: + FDMN V 4; + Loop; + Death: + FDMN V 5 A_SmBounce; + XDeath: + FDMN V 200; + Stop; + } +} + +// FireDemonRock5 ------------------------------------------------------------ + +class FireDemonRock5 : FireDemonRock1 +{ + States + { + Spawn: + FDMN W 4; + Loop; + Death: + FDMN W 5 A_SmBounce; + XDeath: + FDMN W 200; + Stop; + } +} + +// FireDemonMissile ----------------------------------------------------------- + +class FireDemonMissile : Actor +{ + Default + { + ReactionTime 8; + Speed 10; + Radius 10; + Height 6; + Mass 5; + Damage 1; + DamageType "Fire"; + Projectile; + RenderStyle "Add"; + DeathSound "FireDemonMissileHit"; + } + States + { + Spawn: + FDMB A 5 Bright; + Loop; + Death: + FDMB BCDE 5 Bright; + Stop; + } +} diff --git a/wadsrc/static/zscript/hexen/flame.txt b/wadsrc/static/zscript/hexen/flame.txt new file mode 100644 index 0000000000..4eab6c6d3f --- /dev/null +++ b/wadsrc/static/zscript/hexen/flame.txt @@ -0,0 +1,122 @@ +// Temp Small Flame -------------------------------------------------------- + +class FlameSmallTemp : Actor +{ + Default + { + +NOTELEPORT + RenderStyle "Add"; + } + + States + { + Spawn: + FFSM AB 3 Bright; + FFSM C 2 Bright A_CountdownArg(0); + FFSM C 2 Bright; + FFSM D 3 Bright; + FFSM E 3 Bright A_CountdownArg(0); + Loop; + } +} + + +// Temp Large Flame --------------------------------------------------------- + +class FlameLargeTemp : Actor +{ + Default + { + +NOTELEPORT + RenderStyle "Add"; + } + + States + { + Spawn: + FFLG A 4 Bright; + FFLG B 4 Bright A_CountdownArg(0); + FFLG C 4 Bright; + FFLG D 4 Bright A_CountdownArg(0); + FFLG E 4 Bright; + FFLG F 4 Bright A_CountdownArg(0); + FFLG G 4 Bright; + FFLG H 4 Bright A_CountdownArg(0); + FFLG I 4 Bright; + FFLG J 4 Bright A_CountdownArg(0); + FFLG K 4 Bright; + FFLG L 4 Bright A_CountdownArg(0); + FFLG M 4 Bright; + FFLG N 4 Bright A_CountdownArg(0); + FFLG O 4 Bright; + FFLG P 4 Bright A_CountdownArg(0); + Goto Spawn+4; + } +} + +// Small Flame -------------------------------------------------------------- + +class FlameSmall : SwitchableDecoration +{ + Default + { + +NOTELEPORT + +INVISIBLE + Radius 15; + RenderStyle "Add"; + } + + States + { + Active: + FFSM A 0 Bright A_PlaySound("Ignite"); + Spawn: + FFSM A 3 Bright; + FFSM A 3 Bright A_UnHideThing; + FFSM ABCDE 3 Bright; + Goto Spawn+2; + Inactive: + FFSM A 2; + FFSM B 2 A_HideThing; + FFSM C 200; + Wait; + } +} + +class FlameSmall2 : FlameSmall +{ +} + +// Large Flame -------------------------------------------------------------- + +class FlameLarge : SwitchableDecoration +{ + Default + { + +NOTELEPORT + +INVISIBLE + Radius 15; + RenderStyle "Add"; + } + + States + { + Active: + FFLG A 0 Bright A_PlaySound("Ignite"); + Spawn: + FFLG A 2 Bright; + FFLG A 2 Bright A_UnHideThing; + FFLG ABCDEFGHIJKLMNOP 4 Bright; + Goto Spawn+6; + Inactive: + FFLG DCB 2; + FFLG A 2 A_HideThing; + FFLG A 200; + Wait; + } +} + +class FlameLarge2 : FlameLarge +{ +} + diff --git a/wadsrc/static/zscript/hexen/flechette.txt b/wadsrc/static/zscript/hexen/flechette.txt new file mode 100644 index 0000000000..fc9268c5b0 --- /dev/null +++ b/wadsrc/static/zscript/hexen/flechette.txt @@ -0,0 +1,599 @@ + +// Poison Bag (Flechette used by Cleric) ------------------------------------ + +class PoisonBag : Actor +{ + Default + { + Radius 5; + Height 5; + +NOBLOCKMAP +NOGRAVITY + } + + States + { + Spawn: + PSBG A 18 Bright; + PSBG B 4 Bright; + PSBG C 3; + PSBG C 1 A_PoisonBagInit; + Stop; + } + + //=========================================================================== + // + // A_PoisonBagInit + // + //=========================================================================== + + void A_PoisonBagInit() + { + Actor mo = Spawn("PoisonCloud", pos + (0, 0, 28), ALLOW_REPLACE); + if (mo) + { + mo.target = target; + } + } +} + +// Fire Bomb (Flechette used by Mage) --------------------------------------- + +class FireBomb : Actor +{ + Default + { + DamageType "Fire"; + +NOGRAVITY + +FOILINVUL + RenderStyle "Translucent"; + Alpha 0.6; + DeathSound "FlechetteExplode"; + } + + States + { + Spawn: + PSBG A 20; + PSBG AA 10; + PSBG B 4; + PSBG C 4 A_Scream; + XPL1 A 4 Bright A_TimeBomb; + XPL1 BCDEF 4 Bright; + Stop; + } + + void A_TimeBomb() + { + AddZ(32, false); + A_SetRenderStyle(1., STYLE_Add); + A_Explode(); + } +} + +// Throwing Bomb (Flechette used by Fighter) -------------------------------- + +class ThrowingBomb : Actor +{ + Default + { + Health 48; + Speed 12; + Radius 8; + Height 10; + DamageType "Fire"; + +NOBLOCKMAP +DROPOFF +MISSILE + BounceType "HexenCompat"; + SeeSound "FlechetteBounce"; + DeathSound "FlechetteExplode"; + } + + States + { + Spawn: + THRW A 4 A_CheckThrowBomb; + THRW BCDE 3 A_CheckThrowBomb; + THRW F 3 A_CheckThrowBomb2; + Loop; + Tail: + THRW G 6 A_CheckThrowBomb; + THRW F 4 A_CheckThrowBomb; + THRW H 6 A_CheckThrowBomb; + THRW F 4 A_CheckThrowBomb; + THRW G 6 A_CheckThrowBomb; + THRW F 3 A_CheckThrowBomb; + Wait; + Death: + CFCF Q 4 Bright A_NoGravity; + CFCF R 3 Bright A_Scream; + CFCF S 4 Bright A_Explode; + CFCF T 3 Bright; + CFCF U 4 Bright; + CFCF W 3 Bright; + CFCF X 4 Bright; + CFCF Z 3 Bright; + Stop; + } + + //=========================================================================== + // + // A_CheckThrowBomb + // + //=========================================================================== + + void A_CheckThrowBomb() + { + if (--health <= 0) + { + SetStateLabel("Death"); + } + } + + //=========================================================================== + // + // A_CheckThrowBomb2 + // + //=========================================================================== + + void A_CheckThrowBomb2() + { + // [RH] Check using actual velocity, although the vel.z < 2 check still stands + if (Vel.Z < 2 && Vel.Length() < 1.5) + { + SetStateLabel("Tail"); + SetZ(floorz); + Vel.Z = 0; + ClearBounce(); + bMissile = false; + } + A_CheckThrowBomb(); + } + +} + +// Poison Bag Artifact (Flechette) ------------------------------------------ + +class ArtiPoisonBag : Inventory +{ + Default + { + +FLOATBOB + Inventory.DefMaxAmount; + Inventory.PickupFlash "PickupFlash"; + +INVENTORY.INVBAR +INVENTORY.FANCYPICKUPSOUND + Inventory.Icon "ARTIPSBG"; + Inventory.PickupSound "misc/p_pkup"; + Inventory.PickupMessage "$TXT_ARTIPOISONBAG"; + Tag "$TAG_ARTIPOISONBAG"; + } + States + { + Spawn: + PSBG A -1; + Stop; + } + + //============================================================================ + // + // AArtiPoisonBag :: BeginPlay + // + //============================================================================ + + override void BeginPlay () + { + Super.BeginPlay (); + // If a subclass's specific icon is not defined, let it use the base class's. + if (!Icon.isValid()) + { + Icon = GetDefaultByType("ArtiPoisonBag").Icon; + } + } + + //============================================================================ + // + // GetFlechetteType + // + //============================================================================ + + private class GetFlechetteType(Actor other) + { + class spawntype = null; + PlayerPawn pp = PlayerPawn(other); + if (pp) + { + spawntype = pp.FlechetteType; + } + if (spawntype == null) + { + // default fallback if nothing valid defined. + spawntype = "ArtiPoisonBag3"; + } + return spawntype; + } + + //============================================================================ + // + // AArtiPoisonBag :: HandlePickup + // + //============================================================================ + + override bool HandlePickup (Inventory item) + { + // Only do special handling when picking up the base class + if (item.GetClass() != "ArtiPoisonBag") + { + 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.bPickupGood = true; + } + return true; + } + return false; + } + + //============================================================================ + // + // AArtiPoisonBag :: CreateCopy + // + //============================================================================ + + override Inventory CreateCopy (Actor other) + { + // Only the base class gets special handling + if (GetClass() != "ArtiPoisonBag") + { + return Super.CreateCopy (other); + } + + class spawntype = GetFlechetteType(other); + Inventory copy = Inventory(Spawn (spawntype)); + copy.Amount = Amount; + copy.MaxAmount = MaxAmount; + GoAwayAndDie (); + return copy; + } +} + +// Poison Bag 1 (The Cleric's) ---------------------------------------------- + +class ArtiPoisonBag1 : ArtiPoisonBag +{ + Default + { + Inventory.Icon "ARTIPSB1"; + Tag "$TAG_ARTIPOISONBAG1"; + } + + override bool Use (bool pickup) + { + Actor mo = Spawn("PoisonBag", Owner.Vec3Offset( + 16 * cos(Owner.angle), + 24 * sin(Owner.angle), + -Owner.Floorclip + 8), ALLOW_REPLACE); + if (mo) + { + mo.target = Owner; + return true; + } + return false; + } + +} + +// Poison Bag 2 (The Mage's) ------------------------------------------------ + +class ArtiPoisonBag2 : ArtiPoisonBag +{ + Default + { + Inventory.Icon "ARTIPSB2"; + Tag "$TAG_ARTIPOISONBAG2"; + } + + override bool Use (bool pickup) + { + Actor mo = Spawn("FireBomb", Owner.Vec3Offset( + 16 * cos(Owner.angle), + 24 * sin(Owner.angle), + -Owner.Floorclip + 8), ALLOW_REPLACE); + if (mo) + { + mo.target = Owner; + return true; + } + return false; + } + +} + +// Poison Bag 3 (The Fighter's) --------------------------------------------- + +class ArtiPoisonBag3 : ArtiPoisonBag +{ + Default + { + Inventory.Icon "ARTIPSB3"; + Tag "$TAG_ARTIPOISONBAG3"; + } + + override bool Use (bool pickup) + { + Actor mo = Spawn("ThrowingBomb", Owner.Pos + (0,0,35. - Owner.Floorclip + (Owner.player? Owner.player.crouchoffset : 0)), ALLOW_REPLACE); + if (mo) + { + mo.angle = Owner.angle + (((random[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.ang, 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 self with a proper trajectory, we + // aim the projectile ~20 degrees higher than we're looking at and increase the + // speed we fire at accordingly. + double orgpitch = -Owner.Pitch; + double modpitch = clamp(-Owner.Pitch + 20, -89., 89.); + double ang = mo.angle; + double speed = (mo.Speed, 4.).Length(); + double xyscale = speed * cos(modpitch); + + mo.Vel.Z = speed * sin(modpitch); + mo.Vel.X = xyscale * cos(ang) + Owner.Vel.X / 2; + mo.Vel.Y = xyscale * sin(ang) + Owner.Vel.Y / 2; + mo.AddZ(mo.Speed * sin(modpitch)); + + mo.target = Owner; + mo.tics -= random[PoisonBag]()&3; + mo.CheckMissileSpawn(Owner.radius); + return true; + } + return false; + } + + +} + +// Poison Bag 4 (Custom Giver) ---------------------------------------------- + +class ArtiPoisonBagGiver : ArtiPoisonBag +{ + Default + { + Inventory.Icon "ARTIPSB4"; + } + + override bool Use (bool pickup) + { + Class missiletype = MissileName; + if (missiletype != null) + { + Actor mo = Spawn (missiletype, Owner.Pos, ALLOW_REPLACE); + if (mo != null) + { + Inventory inv = Inventory(mo); + if (inv && inv.CallTryPickup(Owner)) return true; + mo.Destroy(); // Destroy if not inventory or couldn't be picked up + } + } + return false; + } + +} + +// Poison Bag 5 (Custom Thrower) -------------------------------------------- + +class ArtiPoisonBagShooter : ArtiPoisonBag +{ + Default + { + Inventory.Icon "ARTIPSB5"; + } + + override bool Use (bool pickup) + { + Class missiletype = MissileName; + if (missiletype != null) + { + Actor mo = Owner.SpawnPlayerMissile(missiletype); + if (mo != null) + { + // automatic handling of seeker missiles + if (mo.bSeekerMissile) + { + mo.tracer = Owner.target; + } + return true; + } + } + return false; + } + +} + +// Poison Cloud ------------------------------------------------------------- + +class PoisonCloud : Actor +{ + Default + { + Radius 20; + Height 30; + Mass 0x7fffffff; + +NOBLOCKMAP +NOGRAVITY +DROPOFF + +NODAMAGETHRUST + +DONTSPLASH +FOILINVUL +CANBLAST +BLOODLESSIMPACT +BLOCKEDBYSOLIDACTORS + RenderStyle "Translucent"; + Alpha 0.6; + DeathSound "PoisonShroomDeath"; + DamageType "PoisonCloud"; + } + + States + { + Spawn: + PSBG D 1; + PSBG D 1 A_Scream; + PSBG DEEEFFFGGGHHHII 2 A_PoisonBagDamage; + PSBG I 2 A_PoisonBagCheck; + PSBG I 1 A_PoisonBagCheck; + Goto Spawn + 3; + Death: + PSBG HG 7; + PSBG FD 6; + Stop; + } + + //=========================================================================== + // + // + // + //=========================================================================== + + override void BeginPlay () + { + Vel.X = MinVel; // missile objects must move to impact other objects + special1 = 24+(random[PoisonCloud]() & 7); + special2 = 0; + } + + //=========================================================================== + // + // + // + //=========================================================================== + + override int DoSpecialDamage (Actor victim, int damage, Name 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) + { + damage = 15 + (random[PoisonCloud]() & 15); + if (mate) + { + damage = (int)(damage * level.teamdamage); + } + // Handle passive damage modifiers (e.g. PowerProtection) + damage = victim.GetModifiedDamage(damagetype, damage, true); + // Modify with damage factors + damage = victim.ApplyDamageFactor(damagetype, damage); + if (damage > 0) + { + victim.player.PoisonDamage (self, 15 + (random[PoisonCloud]() & 15), false); // Don't play painsound + + // If successful, play the poison sound. + if (victim.player.PoisonPlayer (self, self.target, 50)) + victim.A_PlaySound ("*poison", CHAN_VOICE); + } + } + return -1; + } + else if (!victim.bIsMonster) + { // only damage monsters/players with the poison cloud + return -1; + } + return damage; + } + + //=========================================================================== + // + // A_PoisonBagCheck + // + //=========================================================================== + + void A_PoisonBagCheck() + { + if (--special1 <= 0) + { + SetStateLabel("Death"); + } + } + + //=========================================================================== + // + // A_PoisonBagDamage + // + //=========================================================================== + + void A_PoisonBagDamage() + { + A_Explode(4, 40); + AddZ(BobSin(special2) / 16); + special2 = (special2 + 1) & 63; + } +} + +// Poison Shroom ------------------------------------------------------------ + +class ZPoisonShroom : PoisonBag +{ + Default + { + Radius 6; + Height 20; + PainChance 255; + Health 30; + Mass 0x7fffffff; + +SHOOTABLE + +SOLID + +NOBLOOD + +NOICEDEATH + -NOBLOCKMAP + -NOGRAVITY + PainSound "PoisonShroomPain"; + DeathSound "PoisonShroomDeath"; + } + + States + { + Spawn: + SHRM A 5 A_PoisonShroom; + Goto Pain+1; + Pain: + SHRM A 6; + SHRM B 8 A_Pain; + Goto Spawn; + Death: + SHRM CD 5; + SHRM E 5 A_PoisonBagInit; + SHRM F -1; + Stop; + } + + //=========================================================================== + // + // A_PoisonShroom + // + //=========================================================================== + + void A_PoisonShroom() + { + tics = 128 + (random[PoisonShroom]() << 1); + } +} + diff --git a/wadsrc/static/zscript/hexen/flies.txt b/wadsrc/static/zscript/hexen/flies.txt new file mode 100644 index 0000000000..d9800552ba --- /dev/null +++ b/wadsrc/static/zscript/hexen/flies.txt @@ -0,0 +1,130 @@ + +// Buzzy fly ---------------------------------------------------------------- + +class LittleFly : Actor +{ + Default + { + +NOBLOCKMAP +NOGRAVITY + +CANPASS + + Speed 6; + Radius 5; + Height 5; + Mass 2; + ActiveSound "FlyBuzz"; + } + + States + { + Spawn: + TNT1 A 20 A_FlySearch; // [RH] Invisible when not flying + Loop; + Buzz: + AFLY ABCD 3 A_FlyBuzz; + Loop; + } + + //=========================================================================== + // + // FindCorpse + // + // Finds a corpse to buzz around. We can't use a blockmap check because + // corpses generally aren't linked into the blockmap. + // + //=========================================================================== + + private Actor FindCorpse(sector sec, int recurselimit) + { + Actor fallback = null; + sec.validcount = validcount; + + // Search the current sector + for (Actor check = sec.thinglist; check != null; check = check.snext) + { + if (check == self) + continue; + if (!check.bCorpse) + continue; + if (!CheckSight(check)) + continue; + fallback = check; + if (random[Fly](0,1)) // 50% chance to try to pick a different corpse + continue; + return check; + } + if (--recurselimit <= 0 || (fallback != null && random[Fly](0,1))) + { + return fallback; + } + // Try neighboring sectors + for (int i = 0; i < sec.linecount; ++i) + { + line ln = sec.lines[i]; + sector sec2 = (ln.frontsector == sec) ? ln.backsector : ln.frontsector; + if (sec2 != null && sec2.validcount != validcount) + { + Actor neighbor = FindCorpse(sec2, recurselimit); + if (neighbor != null) + { + return neighbor; + } + } + } + return fallback; + } + + void 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. + validcount++; + Actor other = FindCorpse(CurSector, 5); + if (other != null) + { + target = other; + SetStateLabel("Buzz"); + } + } + + void A_FlyBuzz() + { + Actor targ = target; + + if (targ == null || !targ.bCorpse || random[Fly]() < 5) + { + SetIdle(); + return; + } + + Angle = AngleTo(targ); + args[0]++; + if (!TryMove(Pos.XY + AngleToVector(angle, 6), true)) + { + SetIdle(true); + return; + } + if (args[0] & 2) + { + Vel.X += (random[Fly]() - 128) / 512.; + Vel.Y += (random[Fly]() - 128) / 512.; + } + int zrand = random[Fly](); + if (targ.pos.Z + 5. < pos.z && zrand > 150) + { + zrand = -zrand; + } + Vel.Z = zrand / 512.; + if (random[Fly]() < 40) + { + A_PlaySound(ActiveSound, CHAN_VOICE, 0.5f, false, ATTN_STATIC); + } + } +} diff --git a/wadsrc/static/zscript/hexen/fog.txt b/wadsrc/static/zscript/hexen/fog.txt new file mode 100644 index 0000000000..276cf2d73c --- /dev/null +++ b/wadsrc/static/zscript/hexen/fog.txt @@ -0,0 +1,159 @@ +//========================================================================== +// 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 +// +//========================================================================== + +// Fog Spawner -------------------------------------------------------------- + +class FogSpawner : Actor +{ + Default + { + +NOSECTOR +NOBLOCKMAP + +FLOATBOB + +NOGRAVITY + +INVISIBLE + } + + + States + { + Spawn: + TNT1 A 20 A_FogSpawn; + Loop; + } + + //========================================================================== + // + // A_FogSpawn + // + //========================================================================== + + void A_FogSpawn() + { + if (special1-- > 0) + { + return; + } + special1 = args[2]; // Reset frequency count + + class fog; + switch (random[FogSpawn](0,2)) + { + default: + case 0: fog = "FogPatchSmall"; break; + case 1: fog = "FogPatchMedium"; break; + case 2: fog = "FogPatchLarge"; break; + } + Actor mo = Spawn (fog, Pos, ALLOW_REPLACE); + + if (mo) + { + int delta = args[1]; + if (delta == 0) delta = 1; + mo.angle = angle + (((random[FogSpawn]() % delta) - (delta >> 1)) * (360 / 256.)); + mo.target = self; + if (args[0] < 1) args[0] = 1; + mo.args[0] = (random[FogSpawn]() % (args[0]))+1; // Random speed + mo.args[3] = args[3]; // Set lifetime + mo.args[4] = 1; // Set to moving + mo.WeaveIndexZ = random[FogSpawn](0, 63); + } + } + +} + +// Small Fog Patch ---------------------------------------------------------- + +class FogPatchSmall : Actor +{ + Default + { + Speed 1; + +NOBLOCKMAP +NOGRAVITY +NOCLIP +FLOAT + +NOTELEPORT + RenderStyle "Translucent"; + Alpha 0.6; + } + + + States + { + Spawn: + FOGS ABCDE 7 A_FogMove; + Loop; + Death: + FOGS E 5; + Stop; + } + + //========================================================================== + // + // A_FogMove + // + //========================================================================== + + void A_FogMove() + { + double speed = args[0]; + int weaveindex; + + if (!args[4]) + { + return; + } + + if (args[3]-- <= 0) + { + SetStateLabel ('Death', true); + return; + } + + if ((args[3] % 4) == 0) + { + weaveindex = WeaveIndexZ; + AddZ(BobSin(weaveindex) / 2); + WeaveIndexZ = (weaveindex + 1) & 63; + } + VelFromAngle(speed); + } +} + +// Medium Fog Patch --------------------------------------------------------- + +class FogPatchMedium : FogPatchSmall +{ + States + { + Spawn: + FOGM ABCDE 7 A_FogMove; + Loop; + Death: + FOGS ABCDE 5; + Goto Super::Death; + } +} + +// Large Fog Patch ---------------------------------------------------------- + +class FogPatchLarge : FogPatchMedium +{ + States + { + Spawn: + FOGL ABCDE 7 A_FogMove; + Loop; + Death: + FOGM ABCDEF 4; + Goto Super::Death; + } +} + diff --git a/wadsrc/static/zscript/hexen/healingradius.txt b/wadsrc/static/zscript/hexen/healingradius.txt new file mode 100644 index 0000000000..52b87c15b8 --- /dev/null +++ b/wadsrc/static/zscript/hexen/healingradius.txt @@ -0,0 +1,92 @@ + +// Healing Radius Artifact -------------------------------------------------- + +class ArtiHealingRadius : Inventory +{ + const HEAL_RADIUS_DIST = 255.; + + Default + { + +COUNTITEM + +FLOATBOB + Inventory.DefMaxAmount; + +INVENTORY.INVBAR + +INVENTORY.FANCYPICKUPSOUND + Inventory.PickupFlash "PickupFlash"; + Inventory.Icon "ARTIHRAD"; + Inventory.PickupSound "misc/p_pkup"; + Inventory.PickupMessage "$TXT_ARTIHEALINGRADIUS"; + Tag "$TAG_ARTIHEALINGRADIUS"; + } + States + { + Spawn: + HRAD ABCDEFGHIJKLMNOP 4 Bright; + Loop; + } + + override bool Use (bool pickup) + { + bool effective = false; + Name mode = 'Health'; + + PlayerPawn pp = PlayerPawn(Owner); + if (pp) mode = pp.HealingRadiusType; + + for (int i = 0; i < MAXPLAYERS; ++i) + { + PlayerPawn mo = players[i].mo; + if (playeringame[i] && mo != null && mo.health > 0 && 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 'Armor': + for (int j = 0; j < 4; ++j) + { + HexenArmor armor = HexenArmor(Spawn("HexenArmor")); + armor.health = j; + armor.Amount = 1; + if (!armor.CallTryPickup (mo)) + { + armor.Destroy (); + } + else + { + gotsome = true; + } + } + break; + + case 'Mana': + { + int amount = 50 + (random[HealRadius]() % 50); + + if (mo.GiveAmmo ("Mana1", amount) || + mo.GiveAmmo ("Mana2", amount)) + { + gotsome = true; + } + break; + } + + default: + //case NAME_Health: + gotsome = mo.GiveBody (50 + (random[HealRadius]() % 50)); + break; + } + if (gotsome) + { + mo.A_PlaySound ("MysticIncant", CHAN_AUTO); + effective=true; + } + } + } + return effective; + + } + +} + diff --git a/wadsrc/static/zscript/hexen/heresiarch.txt b/wadsrc/static/zscript/hexen/heresiarch.txt new file mode 100644 index 0000000000..db4860c349 --- /dev/null +++ b/wadsrc/static/zscript/hexen/heresiarch.txt @@ -0,0 +1,1136 @@ + +// The Heresiarch him/itself ------------------------------------------------ + +//============================================================================ +// +// 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) +//============================================================================ + +class Heresiarch : Actor +{ + + const SORCBALL_INITIAL_SPEED = 7; + const SORCBALL_TERMINAL_SPEED = 25; + const SORCBALL_SPEED_ROTATIONS = 5; + const SORC_DEFENSE_TIME = 255; + const SORC_DEFENSE_HEIGHT = 45; + const BOUNCE_TIME_UNIT = (35/2); + const SORCFX4_RAPIDFIRE_TIME = (6*3); // 3 seconds + const SORCFX4_SPREAD_ANGLE = 20; + + enum ESorc + { + SORC_DECELERATE, + SORC_ACCELERATE, + SORC_STOPPING, + SORC_FIRESPELL, + SORC_STOPPED, + SORC_NORMAL, + SORC_FIRING_SPELL + } + + const BALL1_ANGLEOFFSET = 0.; + const BALL2_ANGLEOFFSET = 120.; + const BALL3_ANGLEOFFSET = 240.; + + double BallAngle; + class StopBall; + + Default + { + Health 5000; + Painchance 10; + Speed 16; + Radius 40; + Height 110; + Mass 500; + Damage 9; + Monster; + +FLOORCLIP + +BOSS + +DONTMORPH + +NOTARGET + +NOICEDEATH + +DEFLECT + +NOBLOOD + SeeSound "SorcererSight"; + PainSound "SorcererPain"; + DeathSound "SorcererDeathScream"; + ActiveSound "SorcererActive"; + Obituary "$OB_HERESIARCH"; + } + + States + { + Spawn: + SORC A 3; + SORC A 2 A_SorcSpinBalls; + Idle: + SORC A 10 A_Look; + Wait; + See: + SORC ABCD 5 A_Chase; + Loop; + Pain: + SORC G 8; + SORC G 8 A_Pain; + Goto See; + Missile: + SORC F 6 Bright A_FaceTarget; + SORC F 6 Bright A_SpeedBalls; + SORC F 6 Bright A_FaceTarget; + Wait; + Attack1: + SORC E 6 Bright; + SORC E 6 Bright A_SpawnFizzle; + SORC E 5 Bright A_FaceTarget; + Goto Attack1+1; + Attack2: + SORC E 2 Bright; + SORC E 2 Bright A_SorcBossAttack; + Goto See; + Death: + SORC H 5 Bright; + SORC I 5 Bright A_FaceTarget; + SORC J 5 Bright A_Scream; + SORC KLMNOPQRST 5 Bright; + SORC U 5 Bright A_NoBlocking; + SORC VWXY 5 Bright; + SORC Z -1 Bright; + Stop; + } + + void Die (Actor source, Actor 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) + { + ACS_Execute(script, 0); + } + } + + //============================================================================ + // + // A_StopBalls + // + // Instant stop when rotation gets to ball in special2 + // self is sorcerer + // + //============================================================================ + + void A_StopBalls() + { + int chance = random[Heresiarch](); + args[3] = SORC_STOPPING; // stopping mode + args[1] = 0; // Reset rotation counter + + if ((args[0] <= 0) && (chance < 200)) + { + StopBall = "SorcBall2"; // Blue + } + else if((health < (SpawnHealth() >> 1)) && (chance < 200)) + { + StopBall = "SorcBall3"; // Green + } + else + { + StopBall = "SorcBall1"; // Yellow + } + } + + //============================================================================ + // + // A_SorcSpinBalls + // + // Spawn spinning balls above head - actor is sorcerer + //============================================================================ + + void A_SorcSpinBalls() + { + A_SlowBalls(); + args[0] = 0; // Currently no defense + args[3] = SORC_NORMAL; + args[4] = SORCBALL_INITIAL_SPEED; // Initial orbit speed + BallAngle = 1.; + + Vector3 ballpos = (pos.xy, -Floorclip + Height); + + Actor 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; + } + + + //============================================================================ + // + // A_SpeedBalls + // + // Set balls to speed mode - self is sorcerer + // + //============================================================================ + + void A_SpeedBalls() + { + args[3] = SORC_ACCELERATE; // speed mode + args[2] = SORCBALL_TERMINAL_SPEED; // target speed + } + + + //============================================================================ + // + // A_SlowBalls + // + // Set balls to slow mode - actor is sorcerer + // + //============================================================================ + + void A_SlowBalls() + { + args[3] = SORC_DECELERATE; // slow mode + args[2] = SORCBALL_INITIAL_SPEED; // target speed + } + + //============================================================================ + // + // A_SorcBossAttack + // + // Resume ball spinning + // + //============================================================================ + + void A_SorcBossAttack() + { + args[3] = SORC_ACCELERATE; + args[2] = SORCBALL_INITIAL_SPEED; + } + + //============================================================================ + // + // A_SpawnFizzle + // + // spell cast magic fizzle + // + //============================================================================ + + void A_SpawnFizzle() + { + Vector3 pos = Vec3Angle(5., Angle, -Floorclip + Height / 2. ); + for (int ix=0; ix<5; ix++) + { + Actor mo = Spawn("SorcSpark1", pos, ALLOW_REPLACE); + if (mo) + { + double rangle = Angle + (random[Heresiarch]() % 5) * (4096 / 360.); + mo.Vel.X = (random[Heresiarch]() % speed) * cos(rangle); + mo.Vel.Y = (random[Heresiarch]() % speed) * sin(rangle); + mo.Vel.Z = 2; + } + } + } + + +} + +// Base class for the balls flying around the Heresiarch's head ------------- + +class SorcBall : Actor +{ + Default + { + Speed 10; + Radius 5; + Height 5; + Projectile; + -ACTIVATEIMPACT + -ACTIVATEPCROSS + +FULLVOLDEATH + +CANBOUNCEWATER + +NOWALLBOUNCESND + BounceType "HexenCompat"; + SeeSound "SorcererBallBounce"; + DeathSound "SorcererBigBallExplode"; + } + + double OldAngle, AngleOffset; + + //============================================================================ + // + // SorcBall::DoFireSpell + // + //============================================================================ + + virtual void DoFireSpell () + { + CastSorcererSpell (); + target.args[3] = Heresiarch.SORC_STOPPED; + } + + + virtual void SorcUpdateBallAngle () + { + } + + override bool SpecialBlastHandling (Actor source, double strength) + { // don't blast sorcerer balls + return false; + } + + //============================================================================ + // + // ASorcBall::CastSorcererSpell + // + // Make noise and change the parent sorcerer's animation + // + //============================================================================ + + virtual void CastSorcererSpell () + { + target.A_PlaySound ("SorcererSpellCast", CHAN_VOICE); + + // Put sorcerer into throw spell animation + if (target.health > 0) + target.SetStateLabel ("Attack2"); + } + + //============================================================================ + // + // A_SorcBallOrbit + // + // - actor is ball + //============================================================================ + + void A_SorcBallOrbit() + { + // [RH] If no parent, then die instead of crashing + if (target == null || target.health <= 0) + { + SetStateLabel ("Pain"); + return; + } + + int mode = target.args[3]; + Heresiarch parent = Heresiarch(target); + double dist = parent.radius - (radius*2); + + double prevangle = OldAngle; + double baseangle = parent.BallAngle; + double curangle = baseangle + AngleOffset; + + angle = curangle; + + switch (mode) + { + case Heresiarch.SORC_NORMAL: // Balls rotating normally + SorcUpdateBallAngle (); + break; + + case Heresiarch.SORC_DECELERATE: // Balls decelerating + A_DecelBalls(); + SorcUpdateBallAngle (); + break; + + case Heresiarch.SORC_ACCELERATE: // Balls accelerating + A_AccelBalls(); + SorcUpdateBallAngle (); + break; + + case Heresiarch.SORC_STOPPING: // Balls stopping + if ((parent.StopBall == GetClass()) && + (parent.args[1] > Heresiarch.SORCBALL_SPEED_ROTATIONS) && + absangle(curangle, parent.angle) < 42.1875) + { + // Can stop now + target.args[3] = Heresiarch.SORC_FIRESPELL; + target.args[4] = 0; + // Set angle so self angle == sorcerer angle + parent.BallAngle = parent.angle - AngleOffset; + } + else + { + SorcUpdateBallAngle (); + } + break; + + case Heresiarch.SORC_FIRESPELL: // Casting spell + if (parent.StopBall == GetClass()) + { + // Put sorcerer into special throw spell anim + if (parent.health > 0) + parent.SetStateLabel("Attack1"); + + DoFireSpell (); + } + break; + + case Heresiarch.SORC_FIRING_SPELL: + if (parent.StopBall == GetClass()) + { + if (special2-- <= 0) + { + // Done rapid firing + parent.args[3] = Heresiarch.SORC_STOPPED; + // Back to orbit balls + if (parent.health > 0) + parent.SetStateLabel("Attack2"); + } + else + { + // Do rapid fire spell + A_SorcOffense2(); + } + } + break; + + default: + break; + } + + // The comparison here depends on binary angle semantics and cannot be done in floating point. + // It also requires very exact conversion that must be done natively. + if (BAM(curangle) < BAM(prevangle) && (parent.args[4] == Heresiarch.SORCBALL_TERMINAL_SPEED)) + { + parent.args[1]++; // Bump rotation counter + // Completed full rotation - make woosh sound + A_PlaySound ("SorcererBallWoosh", CHAN_BODY); + } + OldAngle = curangle; // Set previous angle + + Vector3 pos = parent.Vec3Angle(dist, curangle, -parent.Floorclip + parent.Height); + SetOrigin (pos, true); + floorz = parent.floorz; + ceilingz = parent.ceilingz; + } + + //============================================================================ + // + // A_SorcOffense2 + // + // Actor is ball + // + //============================================================================ + + void A_SorcOffense2() + { + Actor parent = target; + Actor dest = parent.target; + + // [RH] If no enemy, then don't try to shoot. + if (dest == null) + { + return; + } + + int index = args[4]; + args[4] = (args[4] + 15) & 255; + double delta = sin(index * (360 / 256.f)) * Heresiarch.SORCFX4_SPREAD_ANGLE; + + double ang1 = Angle + delta; + Actor mo = parent.SpawnMissileAngle("SorcFX4", ang1, 0); + if (mo) + { + mo.special2 = 35*5/2; // 5 seconds + double dist = mo.DistanceBySpeed(dest, mo.Speed); + mo.Vel.Z = (dest.pos.z - mo.pos.z) / dist; + } + } + + //============================================================================ + // + // A_AccelBalls + // + // Increase ball orbit speed - actor is ball + // + //============================================================================ + + void A_AccelBalls() + { + Heresiarch sorc = Heresiarch(target); + + if (sorc.args[4] < sorc.args[2]) + { + sorc.args[4]++; + } + else + { + sorc.args[3] = Heresiarch.SORC_NORMAL; + if (sorc.args[4] >= Heresiarch.SORCBALL_TERMINAL_SPEED) + { + // Reached terminal velocity - stop balls + sorc.A_StopBalls(); + } + } + } + + //============================================================================ + // + // A_DecelBalls + // + // Decrease ball orbit speed - actor is ball + // + //============================================================================ + + void A_DecelBalls() + { + Actor sorc = target; + + if (sorc.args[4] > sorc.args[2]) + { + sorc.args[4]--; + } + else + { + sorc.args[3] = Heresiarch.SORC_NORMAL; + } + } + + + void A_SorcBallExplode() + { + bNoBounceSound = true; + A_Explode(255, 255); + } + + //============================================================================ + // + // A_SorcBallPop + // + // Ball death - bounce away in a random direction + // + //============================================================================ + + void A_SorcBallPop() + { + A_PlaySound ("SorcererBallPop", CHAN_BODY, 1, false, ATTN_NONE); + bNoGravity = false; + Gravity = 1. / 8; + + Vel.X = ((random[Heresiarch]()%10)-5); + Vel.Y = ((random[Heresiarch]()%10)-5); + Vel.Z = (2+(random[Heresiarch]()%3)); + args[4] = Heresiarch.BOUNCE_TIME_UNIT; // Bounce time unit + args[3] = 5; // Bounce time in seconds + } + + //============================================================================ + // + // A_BounceCheck + // + //============================================================================ + + void A_BounceCheck () + { + if (args[4]-- <= 0) + { + if (args[3]-- <= 0) + { + SetStateLabel("Death"); + A_PlaySound ("SorcererBigBallExplode", CHAN_BODY, 1, false, ATTN_NONE); + } + else + { + args[4] = Heresiarch.BOUNCE_TIME_UNIT; + } + } + } + +} + +// First ball (purple) - fires projectiles ---------------------------------- + +class SorcBall1 : SorcBall +{ + States + { + Spawn: + SBMP ABCDEFGHIJKLMNOP 2 A_SorcBallOrbit; + Loop; + Pain: + SBMP A 5 A_SorcBallPop; + SBMP B 2 A_BounceCheck; + Wait; + Death: + SBS4 D 5 A_SorcBallExplode; + SBS4 E 5; + SBS4 FGH 6; + Stop; + } + + override void BeginPlay () + { + Super.BeginPlay (); + AngleOffset = Heresiarch.BALL1_ANGLEOFFSET; + } + + //============================================================================ + // + // SorcBall1::CastSorcererSpell + // + // Offensive + // + //============================================================================ + + override void CastSorcererSpell () + { + Super.CastSorcererSpell (); + + Actor parent = target; + + double ang1 = Angle + 70; + double ang2 = Angle - 70; + Class cls = "SorcFX1"; + Actor mo = parent.SpawnMissileAngle (cls, ang1, 0); + if (mo) + { + mo.target = parent; + mo.tracer = parent.target; + mo.args[4] = Heresiarch.BOUNCE_TIME_UNIT; + mo.args[3] = 15; // Bounce time in seconds + } + mo = parent.SpawnMissileAngle (cls, ang2, 0); + if (mo) + { + mo.target = parent; + mo.tracer = parent.target; + mo.args[4] = Heresiarch.BOUNCE_TIME_UNIT; + mo.args[3] = 15; // Bounce time in seconds + } + } + + + //============================================================================ + // + // ASorcBall1::SorcUpdateBallAngle + // + // Update angle if first ball + //============================================================================ + + override void SorcUpdateBallAngle () + { + (Heresiarch(target)).BallAngle += target.args[4]; + } + + //============================================================================ + // + // SorcBall1::DoFireSpell + // + //============================================================================ + + override void DoFireSpell () + { + if (random[Heresiarch]() < 200) + { + target.A_PlaySound ("SorcererSpellCast", CHAN_VOICE, 1, false, ATTN_NONE); + special2 = Heresiarch.SORCFX4_RAPIDFIRE_TIME; + args[4] = 128; + target.args[3] = Heresiarch.SORC_FIRING_SPELL; + } + else + { + Super.DoFireSpell (); + } + } + + +} + + +// Second ball (blue) - generates the shield -------------------------------- + +class SorcBall2 : SorcBall +{ + States + { + Spawn: + SBMB ABCDEFGHIJKLMNOP 2 A_SorcBallOrbit; + Loop; + Pain: + SBMB A 5 A_SorcBallPop; + SBMB B 2 A_BounceCheck; + Wait; + Death: + SBS3 D 5 A_SorcBallExplode; + SBS3 E 5; + SBS3 FGH 6; + Stop; + } + + override void BeginPlay () + { + Super.BeginPlay (); + AngleOffset = Heresiarch.BALL2_ANGLEOFFSET; + } + + //============================================================================ + // + // ASorcBall2::CastSorcererSpell + // + // Defensive + // + //============================================================================ + + override void CastSorcererSpell () + { + Super.CastSorcererSpell (); + + Actor parent = target; + Actor mo = Spawn("SorcFX2", Pos + (0, 0, parent.Floorclip + Heresiarch.SORC_DEFENSE_HEIGHT), ALLOW_REPLACE); + bReflective = true; + bInvulnerable = true; + parent.args[0] = Heresiarch.SORC_DEFENSE_TIME; + if (mo) mo.target = parent; + } + + +} + +// Third ball (green) - summons Bishops ------------------------------------- + +class SorcBall3 : SorcBall +{ + States + { + Spawn: + SBMG ABCDEFGHIJKLMNOP 2 A_SorcBallOrbit; + Loop; + Pain: + SBMG A 5 A_SorcBallPop; + SBMG B 2 A_BounceCheck; + Wait; + Death: + SBS3 D 5 A_SorcBallExplode; + SBS3 E 5; + SBS3 FGH 6; + Stop; + } + + override void BeginPlay () + { + Super.BeginPlay (); + AngleOffset = Heresiarch.BALL3_ANGLEOFFSET; + } + + //============================================================================ + // + // ASorcBall3::CastSorcererSpell + // + // Reinforcements + // + //============================================================================ + + override void CastSorcererSpell () + { + Actor mo; + Super.CastSorcererSpell (); + Actor parent = target; + + double ang1 = Angle - 45; + double ang2 = Angle + 45; + Class cls = "SorcFX3"; + if (health < (SpawnHealth()/3)) + { // Spawn 2 at a time + mo = parent.SpawnMissileAngle(cls, ang1, 4.); + if (mo) mo.target = parent; + mo = parent.SpawnMissileAngle(cls, ang2, 4.); + if (mo) mo.target = parent; + } + else + { + if (random[Heresiarch]() < 128) ang1 = ang2; + mo = parent.SpawnMissileAngle(cls, ang1, 4.); + if (mo) mo.target = parent; + } + } + + +} + + +// Sorcerer spell 1 (The burning, bouncing head thing) ---------------------- + +class SorcFX1 : Actor +{ + Default + { + Speed 7; + Radius 5; + Height 5; + Projectile; + -ACTIVATEIMPACT + -ACTIVATEPCROSS + -NOGRAVITY + +FULLVOLDEATH + +CANBOUNCEWATER + +NOWALLBOUNCESND + BounceFactor 1.0; + BounceType "HexenCompat"; + SeeSound "SorcererBallBounce"; + DeathSound "SorcererHeadScream"; + } + + States + { + Spawn: + SBS1 A 2 Bright; + SBS1 BCD 3 Bright A_SorcFX1Seek; + Loop; + Death: + FHFX S 2 Bright A_Explode(30, 128); + FHFX SS 6 Bright; + Stop; + } + + //============================================================================ + // + // A_SorcFX1Seek + // + // Yellow spell - offense + // + //============================================================================ + + void A_SorcFX1Seek() + { + if (args[4]-- <= 0) + { + if (args[3]-- <= 0) + { + SetStateLabel("Death"); + A_PlaySound ("SorcererHeadScream", CHAN_BODY, 1, false, ATTN_NONE); + } + else + { + args[4] = Heresiarch.BOUNCE_TIME_UNIT; + } + } + A_SeekerMissile(2, 6); + } + +} + + +// Sorcerer spell 2 (The visible part of the shield) ------------------------ + +class SorcFX2 : Actor +{ + Default + { + Speed 15; + Radius 5; + Height 5; + +NOBLOCKMAP + +NOGRAVITY + +NOTELEPORT + } + + states + { + Spawn: + SBS2 A 3 Bright A_SorcFX2Split; + Loop; + Orbit: + SBS2 A 2 Bright; + SBS2 BCDEFGHIJKLMNOPA 2 Bright A_SorcFX2Orbit; + Goto Orbit+1; + Death: + SBS2 A 10; + Stop; + } + + //============================================================================ + // + // A_SorcFX2Split + // + // Blue spell - defense + // + //============================================================================ + // + // FX2 Variables + // specialf1 current angle + // special2 + // args[0] 0 = CW, 1 = CCW + // args[1] + //============================================================================ + + // Split ball in two + void A_SorcFX2Split() + { + Actor mo = Spawn(GetClass(), Pos, NO_REPLACE); + if (mo) + { + mo.target = target; + mo.args[0] = 0; // CW + mo.specialf1 = Angle; // Set angle + mo.SetStateLabel("Orbit"); + } + mo = Spawn(GetClass(), Pos, NO_REPLACE); + if (mo) + { + mo.target = target; + mo.args[0] = 1; // CCW + mo.specialf1 = Angle; // Set angle + mo.SetStateLabel("Orbit"); + } + Destroy (); + } + + //============================================================================ + // + // A_SorcFX2Orbit + // + // Orbit FX2 about sorcerer + // + //============================================================================ + + void A_SorcFX2Orbit () + { + Actor parent = target; + + // [RH] If no parent, then disappear + if (parent == null) + { + Destroy(); + return; + } + + double dist = parent.radius; + + if ((parent.health <= 0) || // Sorcerer is dead + (!parent.args[0])) // Time expired + { + SetStateLabel("Death"); + parent.args[0] = 0; + parent.bReflective = false; + parent.bInvulnerable = false; + } + + if (args[0] && (parent.args[0]-- <= 0)) // Time expired + { + SetStateLabel("Death"); + parent.args[0] = 0; + parent.bReflective = false; + } + + Vector3 posi; + // Move to new position based on angle + if (args[0]) // Counter clock-wise + { + specialf1 += 10; + angle = specialf1; + posi = parent.Vec3Angle(dist, angle, parent.Floorclip + Heresiarch.SORC_DEFENSE_HEIGHT); + posi.Z += 15 * cos(angle); + // Spawn trailer + Spawn("SorcFX2T1", pos, ALLOW_REPLACE); + } + else // Clock wise + { + specialf1 -= 10; + angle = specialf1; + posi = parent.Vec3Angle(dist, angle, parent.Floorclip + Heresiarch.SORC_DEFENSE_HEIGHT); + posi.Z += 20 * sin(angle); + // Spawn trailer + Spawn("SorcFX2T1", pos, ALLOW_REPLACE); + } + + SetOrigin (posi, true); + floorz = parent.floorz; + ceilingz = parent.ceilingz; + } +} + +// The translucent trail behind SorcFX2 ------------------------------------- + +class SorcFX2T1 : SorcFX2 +{ + Default + { + RenderStyle "Translucent"; + Alpha 0.4; + } + States + { + Spawn: + Goto Death; + } +} + + +// Sorcerer spell 3 (The Bishop spawner) ------------------------------------ + +class SorcFX3 : Actor +{ + Default + { + Speed 15; + Radius 22; + Height 65; + +NOBLOCKMAP + +MISSILE + +NOTELEPORT + SeeSound "SorcererBishopSpawn"; + } + + States + { + Spawn: + SBS3 ABC 2 Bright; + Loop; + Death: + SBS3 A 4 Bright; + BISH P 4 A_SorcererBishopEntry; + BISH ON 4; + BISH MLKJIH 3; + BISH G 3 A_SpawnBishop; + Stop; + } + + //============================================================================ + // + // A_SorcererBishopEntry + // + //============================================================================ + + void A_SorcererBishopEntry() + { + Spawn("SorcFX3Explosion", Pos, ALLOW_REPLACE); + A_PlaySound (SeeSound, CHAN_VOICE); + } + + //============================================================================ + // + // A_SpawnBishop + // + // Green spell - spawn bishops + // + //============================================================================ + + void A_SpawnBishop() + { + Actor mo = Spawn("Bishop", Pos, ALLOW_REPLACE); + if (mo) + { + if (!mo.TestMobjLocation()) + { + mo.ClearCounters(); + mo.Destroy (); + } + else if (target != null) + { // [RH] Make the new bishops inherit the Heriarch's target + mo.CopyFriendliness (target, true); + mo.master = target; + } + } + Destroy (); + } +} + + +// The Bishop spawner's explosion animation --------------------------------- + +class SorcFX3Explosion : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + +NOTELEPORT + RenderStyle "Translucent"; + Alpha 0.4; + } + States + { + Spawn: + SBS3 DEFGH 3; + Stop; + } +} + + +// Sorcerer spell 4 (The purple projectile) --------------------------------- + +class SorcFX4 : Actor +{ + Default + { + Speed 12; + Radius 10; + Height 10; + Projectile; + -ACTIVATEIMPACT + -ACTIVATEPCROSS + DeathSound "SorcererBallExplode"; + } + + States + { + Spawn: + SBS4 ABC 2 Bright A_SorcFX4Check; + Loop; + Death: + SBS4 D 2 Bright; + SBS4 E 2 Bright A_Explode(20, 128); + SBS4 FGH 2 Bright; + Stop; + } + + //============================================================================ + // + // A_SorcFX4Check + // + // FX4 - rapid fire balls + // + //============================================================================ + + void A_SorcFX4Check() + { + if (special2-- <= 0) + { + SetStateLabel ("Death"); + } + } +} + + +// Spark that appears when shooting SorcFX4 --------------------------------- + +class SorcSpark1 : Actor +{ + Default + { + Radius 5; + Height 5; + Gravity 0.125; + +NOBLOCKMAP + +DROPOFF + +NOTELEPORT + RenderStyle "Add"; + } + States + { + Spawn: + SBFX ABCDEFG 4 Bright; + Stop; + } +} diff --git a/wadsrc/static/zscript/hexen/hexenarmor.txt b/wadsrc/static/zscript/hexen/hexenarmor.txt new file mode 100644 index 0000000000..13b674fbf2 --- /dev/null +++ b/wadsrc/static/zscript/hexen/hexenarmor.txt @@ -0,0 +1,77 @@ + +// Mesh Armor (1) ----------------------------------------------------------- + +class MeshArmor : HexenArmor +{ + Default + { + +NOGRAVITY + Health 0; // Armor class + Inventory.Amount 0; + Inventory.PickupMessage "$TXT_ARMOR1"; + } + States + { + Spawn: + AR_1 A -1; + Stop; + } +} + +// Falcon Shield (2) -------------------------------------------------------- + +class FalconShield : HexenArmor +{ + Default + { + +NOGRAVITY + Health 1; // Armor class + Inventory.Amount 0; + Inventory.PickupMessage "$TXT_ARMOR2"; + } + States + { + Spawn: + AR_2 A -1; + Stop; + } +} + +// Platinum Helm (3) -------------------------------------------------------- + +class PlatinumHelm : HexenArmor +{ + Default + { + +NOGRAVITY + Health 2; // Armor class + Inventory.Amount 0; + Inventory.PickupMessage "$TXT_ARMOR3"; + } + States + { + Spawn: + AR_3 A -1; + Stop; + } +} + +// Amulet of Warding (4) ---------------------------------------------------- + +class AmuletOfWarding : HexenArmor +{ + Default + { + +NOGRAVITY + Health 3; // Armor class + Inventory.Amount 0; + Inventory.PickupMessage "$TXT_ARMOR4"; + } + States + { + Spawn: + AR_4 A -1; + Stop; + } +} + diff --git a/wadsrc/static/zscript/hexen/hexendecorations.txt b/wadsrc/static/zscript/hexen/hexendecorations.txt new file mode 100644 index 0000000000..937034bd88 --- /dev/null +++ b/wadsrc/static/zscript/hexen/hexendecorations.txt @@ -0,0 +1,1705 @@ +class ZWingedStatue : Actor +{ + Default + { + Radius 10; + Height 62; + +SOLID + } + States + { + Spawn: + STTW A -1; + Stop; + } +} + +class ZRock1 : Actor +{ + Default + { + Radius 20; + Height 16; + } + States + { + Spawn: + RCK1 A -1; + Stop; + } +} + +class ZRock2 : Actor +{ + Default + { + Radius 20; + Height 16; + } + States + { + Spawn: + RCK2 A -1; + Stop; + } +} + +class ZRock3 : Actor +{ + Default + { + Radius 20; + Height 16; + } + States + { + Spawn: + RCK3 A -1; + Stop; + } +} + +class ZRock4 : Actor +{ + Default + { + Radius 20; + Height 16; + } + States + { + Spawn: + RCK4 A -1; + Stop; + } +} + +class ZChandelier : Actor +{ + Default + { + Radius 20; + Height 60; + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + CDLR ABC 4; + Loop; + } +} + +class ZChandelierUnlit : Actor +{ + Default + { + Radius 20; + Height 60; + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + CDLR D -1; + Stop; + } +} + +class ZTreeDead : Actor +{ + Default + { + Radius 10; + Height 96; + +SOLID + } + States + { + Spawn: + ZTRE A -1; + Stop; + } +} + +class ZTree : Actor +{ + Default + { + Radius 15; + Height 128; + +SOLID + } + States + { + Spawn: + ZTRE A -1; + Stop; + } +} + +class ZTreeSwamp150 : Actor +{ + Default + { + Radius 10; + Height 150; + +SOLID + } + States + { + Spawn: + TRES A -1; + Stop; + } +} + +class ZTreeSwamp120 : Actor +{ + Default + { + Radius 10; + Height 120; + +SOLID + } + States + { + Spawn: + TRE3 A -1; + Stop; + } +} + +class ZStumpBurned : Actor +{ + Default + { + Radius 12; + Height 20; + +SOLID + } + States + { + Spawn: + STM1 A -1; + Stop; + } +} + +class ZStumpBare : Actor +{ + Default + { + Radius 12; + Height 20; + +SOLID + } + States + { + Spawn: + STM2 A -1; + Stop; + } +} + +class ZStumpSwamp1 : Actor +{ + Default + { + Radius 20; + Height 16; + } + States + { + Spawn: + STM3 A -1; + Stop; + } +} + +class ZStumpSwamp2 : Actor +{ + Default + { + Radius 20; + Height 16; + } + States + { + Spawn: + STM4 A -1; + Stop; + } +} + +class ZShroomLarge1 : Actor +{ + Default + { + Radius 20; + Height 16; + } + States + { + Spawn: + MSH1 A -1; + Stop; + } +} + +class ZShroomLarge2 : Actor +{ + Default + { + Radius 20; + Height 16; + } + States + { + Spawn: + MSH2 A -1; + Stop; + } +} + +class ZShroomLarge3 : Actor +{ + Default + { + Radius 20; + Height 16; + } + States + { + Spawn: + MSH3 A -1; + Stop; + } +} + +class ZShroomSmall1 : Actor +{ + Default + { + Radius 20; + Height 16; + } + States + { + Spawn: + MSH4 A -1; + Stop; + } +} + +class ZShroomSmall2 : Actor +{ + Default + { + Radius 20; + Height 16; + } + States + { + Spawn: + MSH5 A -1; + Stop; + } +} + +class ZShroomSmall3 : Actor +{ + Default + { + Radius 20; + Height 16; + } + States + { + Spawn: + MSH6 A -1; + Stop; + } +} + +class ZShroomSmall4 : Actor +{ + Default + { + Radius 20; + Height 16; + } + States + { + Spawn: + MSH7 A -1; + Stop; + } +} + +class ZShroomSmall5 : Actor +{ + Default + { + Radius 20; + Height 16; + } + States + { + Spawn: + MSH8 A -1; + Stop; + } +} + +class ZStalagmitePillar : Actor +{ + Default + { + Radius 8; + Height 138; + +SOLID + } + States + { + Spawn: + SGMP A -1; + Stop; + } +} + +class ZStalagmiteLarge : Actor +{ + Default + { + Radius 8; + Height 48; + +SOLID + } + States + { + Spawn: + SGM1 A -1; + Stop; + } +} + +class ZStalagmiteMedium : Actor +{ + Default + { + Radius 6; + Height 40; + +SOLID + } + States + { + Spawn: + SGM2 A -1; + Stop; + } +} + +class ZStalagmiteSmall : Actor +{ + Default + { + Radius 8; + Height 36; + +SOLID + } + States + { + Spawn: + SGM3 A -1; + Stop; + } +} + +class ZStalactiteLarge : Actor +{ + Default + { + Radius 8; + Height 66; + +SOLID + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + SLC1 A -1; + Stop; + } +} + +class ZStalactiteMedium : Actor +{ + Default + { + Radius 6; + Height 50; + +SOLID + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + SLC2 A -1; + Stop; + } +} + +class ZStalactiteSmall : Actor +{ + Default + { + Radius 8; + Height 40; + +SOLID + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + SLC3 A -1; + Stop; + } +} + +class ZMossCeiling1 : Actor +{ + Default + { + Radius 20; + Height 20; + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + MSS1 A -1; + Stop; + } +} + +class ZMossCeiling2 : Actor +{ + Default + { + Radius 20; + Height 24; + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + MSS2 A -1; + Stop; + } +} + +class ZSwampVine : Actor +{ + Default + { + Radius 8; + Height 52; + +SOLID + } + States + { + Spawn: + SWMV A -1; + Stop; + } +} + +class ZCorpseKabob : Actor +{ + Default + { + Radius 10; + Height 92; + +SOLID + } + States + { + Spawn: + CPS1 A -1; + Stop; + } +} + +class ZCorpseSleeping : Actor +{ + Default + { + Radius 20; + Height 16; + } + States + { + Spawn: + CPS2 A -1; + Stop; + } +} + +class ZTombstoneRIP : Actor +{ + Default + { + Radius 10; + Height 46; + +SOLID + } + States + { + Spawn: + TMS1 A -1; + Stop; + } +} + +class ZTombstoneShane : Actor +{ + Default + { + Radius 10; + Height 46; + +SOLID + } + States + { + Spawn: + TMS2 A -1; + Stop; + } +} + +class ZTombstoneBigCross : Actor +{ + Default + { + Radius 10; + Height 46; + +SOLID + } + States + { + Spawn: + TMS3 A -1; + Stop; + } +} + +class ZTombstoneBrianR : Actor +{ + Default + { + Radius 10; + Height 52; + +SOLID + } + States + { + Spawn: + TMS4 A -1; + Stop; + } +} + +class ZTombstoneCrossCircle : Actor +{ + Default + { + Radius 10; + Height 52; + +SOLID + } + States + { + Spawn: + TMS5 A -1; + Stop; + } +} + +class ZTombstoneSmallCross : Actor +{ + Default + { + Radius 8; + Height 46; + +SOLID + } + States + { + Spawn: + TMS6 A -1; + Stop; + } +} + +class ZTombstoneBrianP : Actor +{ + Default + { + Radius 8; + Height 46; + +SOLID + } + States + { + Spawn: + TMS7 A -1; + Stop; + } +} + +class ZCorpseHanging : Actor +{ + Default + { + Radius 6; + Height 75; + +SOLID + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + CPS3 A -1; + Stop; + } +} + +class ZStatueGargoyleGreenTall : Actor +{ + Default + { + Radius 14; + Height 108; + +SOLID + } + States + { + Spawn: + STT2 A -1; + Stop; + } +} + +class ZStatueGargoyleBlueTall : Actor +{ + Default + { + Radius 14; + Height 108; + +SOLID + } + States + { + Spawn: + STT3 A -1; + Stop; + } +} + +class ZStatueGargoyleGreenShort : Actor +{ + Default + { + Radius 14; + Height 62; + +SOLID + } + States + { + Spawn: + STT4 A -1; + Stop; + } +} + +class ZStatueGargoyleBlueShort : Actor +{ + Default + { + Radius 14; + Height 62; + +SOLID + } + States + { + Spawn: + STT5 A -1; + Stop; + } +} + +class ZStatueGargoyleStripeTall : Actor +{ + Default + { + Radius 14; + Height 108; + +SOLID + } + States + { + Spawn: + GAR1 A -1; + Stop; + } +} + +class ZStatueGargoyleDarkRedTall : Actor +{ + Default + { + Radius 14; + Height 108; + +SOLID + } + States + { + Spawn: + GAR2 A -1; + Stop; + } +} + +class ZStatueGargoyleRedTall : Actor +{ + Default + { + Radius 14; + Height 108; + +SOLID + } + States + { + Spawn: + GAR3 A -1; + Stop; + } +} + +class ZStatueGargoyleTanTall : Actor +{ + Default + { + Radius 14; + Height 108; + +SOLID + } + States + { + Spawn: + GAR4 A -1; + Stop; + } +} + +class ZStatueGargoyleRustTall : Actor +{ + Default + { + Radius 14; + Height 108; + +SOLID + } + States + { + Spawn: + GAR5 A -1; + Stop; + } +} + +class ZStatueGargoyleDarkRedShort : Actor +{ + Default + { + Radius 14; + Height 62; + +SOLID + } + States + { + Spawn: + GAR6 A -1; + Stop; + } +} + +class ZStatueGargoyleRedShort : Actor +{ + Default + { + Radius 14; + Height 62; + +SOLID + } + States + { + Spawn: + GAR7 A -1; + Stop; + } +} + +class ZStatueGargoyleTanShort : Actor +{ + Default + { + Radius 14; + Height 62; + +SOLID + } + States + { + Spawn: + GAR8 A -1; + Stop; + } +} + +class ZStatueGargoyleRustShort : Actor +{ + Default + { + Radius 14; + Height 62; + +SOLID + } + States + { + Spawn: + GAR9 A -1; + Stop; + } +} + +class ZBannerTattered : Actor +{ + Default + { + Radius 8; + Height 120; + +SOLID + } + States + { + Spawn: + BNR1 A -1; + Stop; + } +} + +class ZTreeLarge1 : Actor +{ + Default + { + Radius 15; + Height 180; + +SOLID + } + States + { + Spawn: + TRE4 A -1; + Stop; + } +} + +class ZTreeLarge2 : Actor +{ + Default + { + Radius 15; + Height 180; + +SOLID + } + States + { + Spawn: + TRE5 A -1; + Stop; + } +} + +class ZTreeGnarled1 : Actor +{ + Default + { + Radius 22; + Height 100; + +SOLID + } + States + { + Spawn: + TRE6 A -1; + Stop; + } +} + +class ZTreeGnarled2 : Actor +{ + Default + { + Radius 22; + Height 100; + +SOLID + } + States + { + Spawn: + TRE7 A -1; + Stop; + } +} + +class ZLog : Actor +{ + Default + { + Radius 20; + Height 25; + +SOLID + } + States + { + Spawn: + LOGG A -1; + Stop; + } +} + +class ZStalactiteIceLarge : Actor +{ + Default + { + Radius 8; + Height 66; + +SOLID + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + ICT1 A -1; + Stop; + } +} + +class ZStalactiteIceMedium : Actor +{ + Default + { + Radius 5; + Height 50; + +SOLID + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + ICT2 A -1; + Stop; + } +} + +class ZStalactiteIceSmall : Actor +{ + Default + { + Radius 4; + Height 32; + +SOLID + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + ICT3 A -1; + Stop; + } +} + +class ZStalactiteIceTiny : Actor +{ + Default + { + Radius 4; + Height 8; + +SOLID + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + ICT4 A -1; + Stop; + } +} + +class ZStalagmiteIceLarge : Actor +{ + Default + { + Radius 8; + Height 66; + +SOLID + } + States + { + Spawn: + ICM1 A -1; + Stop; + } +} + +class ZStalagmiteIceMedium : Actor +{ + Default + { + Radius 5; + Height 50; + +SOLID + } + States + { + Spawn: + ICM2 A -1; + Stop; + } +} + +class ZStalagmiteIceSmall : Actor +{ + Default + { + Radius 4; + Height 32; + +SOLID + } + States + { + Spawn: + ICM3 A -1; + Stop; + } +} + +class ZStalagmiteIceTiny : Actor +{ + Default + { + Radius 4; + Height 8; + +SOLID + } + States + { + Spawn: + ICM4 A -1; + Stop; + } +} + +class ZRockBrown1 : Actor +{ + Default + { + Radius 17; + Height 72; + +SOLID + } + States + { + Spawn: + RKBL A -1; + Stop; + } +} + +class ZRockBrown2 : Actor +{ + Default + { + Radius 15; + Height 50; + +SOLID + } + States + { + Spawn: + RKBS A -1; + Stop; + } +} + +class ZRockBlack : Actor +{ + Default + { + Radius 20; + Height 40; + +SOLID + } + States + { + Spawn: + RKBK A -1; + Stop; + } +} + +class ZRubble1 : Actor +{ + Default + { + Radius 20; + Height 16; + } + States + { + Spawn: + RBL1 A -1; + Stop; + } +} + +class ZRubble2 : Actor +{ + Default + { + Radius 20; + Height 16; + } + States + { + Spawn: + RBL2 A -1; + Stop; + } +} + +class ZRubble3 : Actor +{ + Default + { + Radius 20; + Height 16; + } + States + { + Spawn: + RBL3 A -1; + Stop; + } +} + +class ZVasePillar : Actor +{ + Default + { + Radius 12; + Height 54; + +SOLID + } + States + { + Spawn: + VASE A -1; + Stop; + } +} + +class ZCorpseLynched : Actor +{ + Default + { + Radius 11; + Height 95; + +SOLID + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + CPS4 A -1; + Stop; + } +} + +class ZCandle : Actor +{ + Default + { + Radius 20; + Height 16; + +NOGRAVITY + +NOBLOCKMAP + } + States + { + Spawn: + CNDL ABC 4 Bright; + Loop; + } +} + +class ZBarrel : Actor +{ + Default + { + Radius 15; + Height 32; + +SOLID + } + States + { + Spawn: + ZBAR A -1; + Stop; + } +} + +class ZBucket : Actor +{ + Default + { + Radius 8; + Height 72; + +SOLID + +SPAWNCEILING + +NOGRAVITY + } + States + { + Spawn: + BCKT A -1; + Stop; + } +} + +class FireThing : Actor +{ + Default + { + Radius 5; + Height 10; + +SOLID + } + States + { + Spawn: + FSKL A 4 Bright; + FSKL B 3 Bright; + FSKL C 4 Bright; + FSKL D 3 Bright; + FSKL E 4 Bright; + FSKL F 3 Bright; + FSKL G 4 Bright; + FSKL H 3 Bright; + FSKL I 4 Bright; + Loop; + } +} + +class BrassTorch : Actor +{ + Default + { + Radius 6; + Height 35; + +SOLID + } + States + { + Spawn: + BRTR ABCDEFGHIJKLM 4 Bright; + Loop; + } +} + +class ZBlueCandle : Actor +{ + Default + { + Radius 20; + Height 16; + +NOBLOCKMAP + } + States + { + Spawn: + BCAN ABCDE 5 Bright; + Loop; + } +} + +class ZIronMaiden : Actor +{ + Default + { + Radius 12; + Height 60; + +SOLID + } + States + { + Spawn: + IRON A -1; + Stop; + } +} + +class ZChainBit32 : Actor +{ + Default + { + Radius 4; + Height 32; + +SPAWNCEILING + +NOGRAVITY + +NOBLOCKMAP + } + States + { + Spawn: + CHNS A -1; + Stop; + } +} + +class ZChainBit64 : Actor +{ + Default + { + Radius 4; + Height 64; + +SPAWNCEILING + +NOGRAVITY + +NOBLOCKMAP + } + States + { + Spawn: + CHNS B -1; + Stop; + } +} + +class ZChainEndHeart : Actor +{ + Default + { + Radius 4; + Height 32; + +SPAWNCEILING + +NOGRAVITY + +NOBLOCKMAP + } + States + { + Spawn: + CHNS C -1; + Stop; + } +} + +class ZChainEndHook1 : Actor +{ + Default + { + Radius 4; + Height 32; + +SPAWNCEILING + +NOGRAVITY + +NOBLOCKMAP + } + States + { + Spawn: + CHNS D -1; + Stop; + } +} + +class ZChainEndHook2 : Actor +{ + Default + { + Radius 4; + Height 32; + +SPAWNCEILING + +NOGRAVITY + +NOBLOCKMAP + } + States + { + Spawn: + CHNS E -1; + Stop; + } +} + +class ZChainEndSpike : Actor +{ + Default + { + Radius 4; + Height 32; + +SPAWNCEILING + +NOGRAVITY + +NOBLOCKMAP + } + States + { + Spawn: + CHNS F -1; + Stop; + } +} + +class ZChainEndSkull : Actor +{ + Default + { + Radius 4; + Height 32; + +SPAWNCEILING + +NOGRAVITY + +NOBLOCKMAP + } + States + { + Spawn: + CHNS G -1; + Stop; + } +} + +class TableShit1 : Actor +{ + Default + { + Radius 20; + Height 16; + +NOBLOCKMAP + } + States + { + Spawn: + TST1 A -1; + Stop; + } +} + +class TableShit2 : Actor +{ + Default + { + Radius 20; + Height 16; + +NOBLOCKMAP + } + States + { + Spawn: + TST2 A -1; + Stop; + } +} + +class TableShit3 : Actor +{ + Default + { + Radius 20; + Height 16; + +NOBLOCKMAP + } + States + { + Spawn: + TST3 A -1; + Stop; + } +} + +class TableShit4 : Actor +{ + Default + { + Radius 20; + Height 16; + +NOBLOCKMAP + } + States + { + Spawn: + TST4 A -1; + Stop; + } +} + +class TableShit5 : Actor +{ + Default + { + Radius 20; + Height 16; + +NOBLOCKMAP + } + States + { + Spawn: + TST5 A -1; + Stop; + } +} + +class TableShit6 : Actor +{ + Default + { + Radius 20; + Height 16; + +NOBLOCKMAP + } + States + { + Spawn: + TST6 A -1; + Stop; + } +} + +class TableShit7 : Actor +{ + Default + { + Radius 20; + Height 16; + +NOBLOCKMAP + } + States + { + Spawn: + TST7 A -1; + Stop; + } +} + +class TableShit8 : Actor +{ + Default + { + Radius 20; + Height 16; + +NOBLOCKMAP + } + States + { + Spawn: + TST8 A -1; + Stop; + } +} + +class TableShit9 : Actor +{ + Default + { + Radius 20; + Height 16; + +NOBLOCKMAP + } + States + { + Spawn: + TST9 A -1; + Stop; + } +} + +class TableShit10 : Actor +{ + Default + { + Radius 20; + Height 16; + +NOBLOCKMAP + } + States + { + Spawn: + TST0 A -1; + Stop; + } +} + +class TeleSmoke : Actor +{ + Default + { + Radius 20; + Height 16; + +NOGRAVITY + +NOBLOCKMAP + RenderStyle "Translucent"; + Alpha 0.6; + } + States + { + Spawn: + TSMK A 4; + TSMK B 3; + TSMK C 4; + TSMK D 3; + TSMK E 4; + TSMK F 3; + TSMK G 4; + TSMK H 3; + TSMK I 4; + TSMK J 3; + TSMK K 4; + TSMK L 3; + TSMK M 4; + TSMK N 3; + TSMK O 4; + TSMK P 3; + TSMK Q 4; + TSMK R 3; + TSMK S 4; + TSMK T 3; + TSMK U 4; + TSMK V 3; + TSMK W 4; + TSMK X 3; + TSMK Y 4; + TSMK Z 3; + Loop; + } +} + diff --git a/wadsrc/static/zscript/hexen/hexenkeys.txt b/wadsrc/static/zscript/hexen/hexenkeys.txt new file mode 100644 index 0000000000..9bf9f426c7 --- /dev/null +++ b/wadsrc/static/zscript/hexen/hexenkeys.txt @@ -0,0 +1,175 @@ + +class HexenKey : Key +{ + Default + { + Radius 8; + Height 20; + } +} + +class KeySteel : HexenKey +{ + Default + { + Inventory.Icon "KEYSLOT1"; + Inventory.PickupMessage "$TXT_KEY_STEEL"; + } + States + { + Spawn: + KEY1 A -1; + Stop; + } +} + +class KeyCave : HexenKey +{ + Default + { + Inventory.Icon "KEYSLOT2"; + Inventory.PickupMessage "$TXT_KEY_CAVE"; + } + States + { + Spawn: + KEY2 A -1; + Stop; + } +} + +class KeyAxe : HexenKey +{ + Default + { + Inventory.Icon "KEYSLOT3"; + Inventory.PickupMessage "$TXT_KEY_AXE"; + } + States + { + Spawn: + KEY3 A -1; + Stop; + } +} + +class KeyFire : HexenKey +{ + Default + { + Inventory.Icon "KEYSLOT4"; + Inventory.PickupMessage "$TXT_KEY_FIRE"; + } + States + { + Spawn: + KEY4 A -1; + Stop; + } +} + +class KeyEmerald : HexenKey +{ + Default + { + Inventory.Icon "KEYSLOT5"; + Inventory.PickupMessage "$TXT_KEY_EMERALD"; + } + States + { + Spawn: + KEY5 A -1; + Stop; + } +} + +class KeyDungeon : HexenKey +{ + Default + { + Inventory.Icon "KEYSLOT6"; + Inventory.PickupMessage "$TXT_KEY_DUNGEON"; + } + States + { + Spawn: + KEY6 A -1; + Stop; + } +} + +class KeySilver : HexenKey +{ + Default + { + Inventory.Icon "KEYSLOT7"; + Inventory.PickupMessage "$TXT_KEY_SILVER"; + } + States + { + Spawn: + KEY7 A -1; + Stop; + } +} + +class KeyRusted : HexenKey +{ + Default + { + Inventory.Icon "KEYSLOT8"; + Inventory.PickupMessage "$TXT_KEY_RUSTED"; + } + States + { + Spawn: + KEY8 A -1; + Stop; + } +} + +class KeyHorn : HexenKey +{ + Default + { + Inventory.Icon "KEYSLOT9"; + Inventory.PickupMessage "$TXT_KEY_HORN"; + } + States + { + Spawn: + KEY9 A -1; + Stop; + } +} + +class KeySwamp : HexenKey +{ + Default + { + Inventory.Icon "KEYSLOTA"; + Inventory.PickupMessage "$TXT_KEY_SWAMP"; + } + States + { + Spawn: + KEYA A -1; + Stop; + } +} + +class KeyCastle : HexenKey +{ + Default + { + Inventory.Icon "KEYSLOTB"; + Inventory.PickupMessage "$TXT_KEY_CASTLE"; + } + States + { + Spawn: + KEYB A -1; + Stop; + } +} + diff --git a/wadsrc/static/zscript/hexen/hexenspecialdecs.txt b/wadsrc/static/zscript/hexen/hexenspecialdecs.txt new file mode 100644 index 0000000000..feebf515f1 --- /dev/null +++ b/wadsrc/static/zscript/hexen/hexenspecialdecs.txt @@ -0,0 +1,1009 @@ + +// Winged Statue (no skull) ------------------------------------------------- + +class ZWingedStatueNoSkull : SwitchingDecoration +{ + Default + { + Radius 10; + Height 62; + +SOLID + } + States + { + Spawn: + STWN A -1; + Stop; + Active: + STWN B -1; + Stop; + } +} + + +// Gem pedestal ------------------------------------------------------------- + +class ZGemPedestal : SwitchingDecoration +{ + Default + { + Radius 10; + Height 40; + +SOLID + } + States + { + Spawn: + GMPD A -1; + Stop; + Active: + GMPD B -1; + Stop; + } +} + + +// Tree (destructible) ------------------------------------------------------ + +class TreeDestructible : Actor +{ + Default + { + Health 70; + Radius 15; + Height 180; + DeathHeight 24; + Mass 0x7fffffff; + PainSound "TreeExplode"; + DeathSound "TreeBreak"; + +SOLID +SHOOTABLE +NOBLOOD +NOICEDEATH + } + States + { + Spawn: + TRDT A -1; + Stop; + Death: + TRDT B 5; + TRDT C 5 A_Scream; + TRDT DEF 5; + TRDT G -1; + Stop; + Burn: + TRDT H 5 Bright A_Pain; + TRDT IJKL 5 Bright; + TRDT M 5 Bright A_Explode(10, 128); + TRDT N 5 Bright; + TRDT OP 5; + TRDT Q -1; + Stop; + } +} + + +// Pottery1 ------------------------------------------------------------------ + +class Pottery1 : Actor +{ + Default + { + Health 15; + Speed 10; + Height 32; + +SOLID +SHOOTABLE +NOBLOOD +DROPOFF +SMASHABLE + +SLIDESONWALLS +PUSHABLE +TELESTOMP +CANPASS + +NOICEDEATH + } + + + States + { + Spawn: + POT1 A -1; + Loop; + Death: + POT1 A 0 A_PotteryExplode; + Stop; + } + + //============================================================================ + // + // A_PotteryExplode + // + //============================================================================ + + void A_PotteryExplode() + { + Actor mo = null; + int i; + + for(i = (random[Pottery]()&3)+3; i; i--) + { + mo = Spawn ("PotteryBit", Pos, ALLOW_REPLACE); + if (mo) + { + mo.SetState (mo.SpawnState + (random[Pottery]()%5)); + mo.Vel.X = random2[Pottery]() / 64.; + mo.Vel.Y = random2[Pottery]() / 64.; + mo.Vel.Z = ((random[Pottery]() & 7) + 5) * 0.75; + } + } + mo.A_PlaySound ("PotteryExplode", CHAN_BODY); + // Spawn an item? + Class type = GetSpawnableType(args[0]); + if (type != null) + { + if (!(level.nomonsters || sv_nomonsters) || !(GetDefaultByType (type).bIsMonster)) + { // Only spawn monsters if not -nomonsters + Spawn (type, Pos, ALLOW_REPLACE); + } + } + } +} + +// Pottery2 ----------------------------------------------------------------- + +class Pottery2 : Pottery1 +{ + Default + { + Height 25; + } + States + { + Spawn: + POT2 A -1; + Stop; + } +} + +// Pottery3 ----------------------------------------------------------------- + +class Pottery3 : Pottery1 +{ + Default + { + Height 25; + } + States + { + Spawn: + POT3 A -1; + Stop; + } +} + +// Pottery Bit -------------------------------------------------------------- + +class PotteryBit : Actor +{ + State LoopState; + + Default + { + Radius 5; + Height 5; + +MISSILE + +NOTELEPORT + +NOICEDEATH + } + + States + { + Spawn: + PBIT ABCDE -1; + Stop; + Death: + PBIT F 0 A_PotteryChooseBit; + Stop; + Pottery1: + PBIT F 140; + PBIT F 1 A_PotteryCheck; + Stop; + Pottery2: + PBIT G 140; + PBIT G 1 A_PotteryCheck; + Stop; + Pottery3: + PBIT H 140; + PBIT H 1 A_PotteryCheck; + Stop; + Pottery4: + PBIT I 140; + PBIT I 1 A_PotteryCheck; + Stop; + Pottery5: + PBIT J 140; + PBIT J 1 A_PotteryCheck; + Stop; + } + + //============================================================================ + // + // A_PotteryChooseBit + // + //============================================================================ + + void A_PotteryChooseBit() + { + static const statelabel bits[] = { "Pottery1", "Pottery2", "Pottery3", "Pottery4", "Pottery5" }; + LoopState = FindState(bits[random[PotteryBit]() % 5]); // Save the state for jumping back to. + SetState (LoopState); + tics = 256 + (random[PotteryBit]() << 1); + } + + //============================================================================ + // + // A_PotteryCheck + // + //============================================================================ + + void A_PotteryCheck() + { + for(int i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i]) + { + Actor pmo = players[i].mo; + if (CheckSight (pmo) && (absangle(pmo.AngleTo(self), pmo.Angle) <= 45)) + { // jump back to previpusly set state. + SetState (LoopState); + return; + } + } + } + } +} + + +// Blood pool --------------------------------------------------------------- + +class BloodPool : Actor +{ + States + { + Spawn: + BDPL A -1; + Stop; + } +} + + +// Lynched corpse (no heart) ------------------------------------------------ + +class ZCorpseLynchedNoHeart : Actor +{ + Default + { + Radius 10; + Height 100; + +SOLID +SPAWNCEILING +NOGRAVITY + } + + States + { + Spawn: + CPS5 A 140 A_CorpseBloodDrip; + Loop; + } + + override void PostBeginPlay () + { + Super.PostBeginPlay (); + Spawn ("BloodPool", (pos.xy, floorz), ALLOW_REPLACE); + } + + //============================================================================ + // + // A_CorpseBloodDrip + // + //============================================================================ + + void A_CorpseBloodDrip() + { + if (random[CorpseDrip]() <= 128) + { + Spawn ("CorpseBloodDrip", pos + (0, 0, Height / 2), ALLOW_REPLACE); + } + } +} + + +// CorpseBloodDrip ---------------------------------------------------------- + +class CorpseBloodDrip : Actor +{ + Default + { + Radius 1; + Height 4; + Gravity 0.125; + +MISSILE + +NOICEDEATH + DeathSound "Drip"; + } + States + { + Spawn: + BDRP A -1; + Stop; + Death: + BDSH AB 3; + BDSH CD 2; + Stop; + } +} + + +// Corpse bit --------------------------------------------------------------- + +class CorpseBit : Actor +{ + Default + { + Radius 5; + Height 5; + +NOBLOCKMAP + +TELESTOMP + } + States + { + Spawn: + CPB1 A -1; + Stop; + CPB2 A -1; + Stop; + CPB3 A -1; + Stop; + CPB4 A -1; + Stop; + } +} + + +// Corpse (sitting, splatterable) ------------------------------------------- + +class ZCorpseSitting : Actor +{ + Default + { + Health 30; + Radius 15; + Height 35; + +SOLID +SHOOTABLE +NOBLOOD + +NOICEDEATH + DeathSound "FireDemonDeath"; + } + + States + { + Spawn: + CPS6 A -1; + Stop; + Death: + CPS6 A 1 A_CorpseExplode; + Stop; + } + + //============================================================================ + // + // A_CorpseExplode + // + //============================================================================ + + void A_CorpseExplode() + { + Actor mo; + + for (int i = (random[CorpseExplode]() & 3) + 3; i; i--) + { + mo = Spawn ("CorpseBit", Pos, ALLOW_REPLACE); + if (mo) + { + mo.SetState (mo.SpawnState + (random[CorpseExplode]() % 3)); + mo.Vel.X = random2[CorpseExplode]() / 64.; + mo.Vel.Y = random2[CorpseExplode]() / 64.; + mo.Vel.Z = ((random[CorpseExplode]() & 7) + 5) * 0.75; + } + } + // Spawn a skull + mo = Spawn ("CorpseBit", Pos, ALLOW_REPLACE); + if (mo) + { + mo.SetState (mo.SpawnState + 3); + mo.Vel.X = random2[CorpseExplode]() / 64.; + mo.Vel.Y = random2[CorpseExplode]() / 64.; + mo.Vel.Z = ((random[CorpseExplode]() & 7) + 5) * 0.75; + } + A_PlaySound (DeathSound, CHAN_BODY); + Destroy (); + } +} + + +// Leaf Spawner ------------------------------------------------------------- + +class LeafSpawner : Actor +{ + Default + { + +NOBLOCKMAP +NOSECTOR + +INVISIBLE + } + + + States + { + Spawn: + TNT1 A 20 A_LeafSpawn; + Loop; + } + + //============================================================================ + // + // A_LeafSpawn + // + //============================================================================ + + void A_LeafSpawn() + { + static const class leaves[] = { "Leaf1", "Leaf2" }; + + for (int i = (random[LeafSpawn]() & 3) + 1; i; i--) + { + double xo = random2[LeafSpawn]() / 4.; + double yo = random2[LeafSpawn]() / 4.; + double zo = random[LeafSpawn]() / 4.; + Actor mo = Spawn (leaves[random[LeafSpawn]()&1], Vec3Offset(xo, yo, zo), ALLOW_REPLACE); + + if (mo) + { + mo.Thrust(random[LeafSpawn]() / 128. + 3); + mo.target = self; + mo.special1 = 0; + } + } + } +} + + +// Leaf 1 ------------------------------------------------------------------- + +class Leaf1 : Actor +{ + Default + { + Radius 2; + Height 4; + Gravity 0.125; + +NOBLOCKMAP +MISSILE + +NOTELEPORT +DONTSPLASH + +NOICEDEATH + } + + States + { + Spawn: + LEF1 ABC 4; + LEF1 D 4 A_LeafThrust; + LEF1 EFG 4; + Looping: + LEF1 H 4 A_LeafThrust; + LEF1 I 4; + LEF1 AB 4; + LEF1 C 4 A_LeafThrust; + LEF1 DEF 4; + LEF1 G 4 A_LeafThrust; + LEF1 HI 4; + Stop; + Death: + LEF3 D 10 A_LeafCheck; + Wait; + } + + //============================================================================ + // + // A_LeafThrust + // + //============================================================================ + + void A_LeafThrust() + { + if (random[LeafThrust]() <= 96) + { + Vel.Z += random[LeafThrust]() / 128. + 1; + } + } + + //============================================================================ + // + // A_LeafCheck + // + //============================================================================ + + void A_LeafCheck() + { + special1++; + if (special1 >= 20) + { + Destroy(); + return; + } + double ang = target ? target.angle : angle; + if (random[LeafCheck]() > 64) + { + if (Vel.X == 0 && Vel.Y == 0) + { + Thrust(random[LeafCheck]() / 128. + 1, ang); + } + return; + } + SetStateLabel ("Looping"); + Vel.Z = random[LeafCheck]() / 128. + 1; + Thrust(random[LeafCheck]() / 128. + 2, ang); + bMissile = true; + } +} + + +// Leaf 2 ------------------------------------------------------------------- + +class Leaf2 : Leaf1 +{ + States + { + Spawn: + LEF2 ABC 4; + LEF2 D 4 A_LeafThrust; + LEF2 EFG 4; + LEF2 H 4 A_LeafThrust; + LEF2 I 4; + LEF2 AB 4; + LEF2 C 4 A_LeafThrust; + LEF2 DEF 4; + LEF2 G 4 A_LeafThrust; + LEF2 HI 4; + Stop; + } +} + + +// Twined torch ------------------------------------------------------------- + +class ZTwinedTorch : SwitchableDecoration +{ + Default + { + Radius 10; + Height 64; + +SOLID + } + States + { + Active: + TWTR A 0 Bright A_PlaySound("Ignite"); + Spawn: + TWTR ABCDEFGH 4 Bright; + Loop; + Inactive: + TWTR I -1; + Stop; + } +} + +class ZTwinedTorchUnlit : ZTwinedTorch +{ + States + { + Spawn: + Goto Super::Inactive; + } +} + + +// Wall torch --------------------------------------------------------------- + +class ZWallTorch : SwitchableDecoration +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + +FIXMAPTHINGPOS + Radius 6.5; + } + States + { + Active: + WLTR A 0 Bright A_PlaySound("Ignite"); + Spawn: + WLTR ABCDEFGH 5 Bright; + Loop; + Inactive: + WLTR I -1; + Stop; + } +} + +class ZWallTorchUnlit : ZWallTorch +{ + States + { + Spawn: + Goto Super::Inactive; + } +} + + +// Shrub1 ------------------------------------------------------------------- + +class ZShrub1 : Actor +{ + Default + { + Radius 8; + Height 24; + Health 20; + Mass 0x7fffffff; + +SOLID +SHOOTABLE +NOBLOOD +NOICEDEATH + DeathSound "TreeExplode"; + } + States + { + Spawn: + SHB1 A -1; + Stop; + Burn: + SHB1 B 7 Bright; + SHB1 C 6 Bright A_Scream; + SHB1 D 5 Bright; + Stop; + } +} + + +// Shrub2 ------------------------------------------------------------------- + +class ZShrub2 : Actor +{ + Default + { + Radius 16; + Height 40; + Health 20; + Mass 0x7fffffff; + +SOLID +SHOOTABLE +NOBLOOD +NOICEDEATH + DeathSound "TreeExplode"; + } + States + { + Spawn: + SHB2 A -1; + Stop; + Burn: + SHB2 B 7 Bright; + SHB2 C 6 Bright A_Scream; + SHB2 D 5 Bright A_Explode(30, 64); + SHB2 E 5 Bright; + Stop; + } +} + + +// Fire Bull ---------------------------------------------------------------- + +class ZFireBull : SwitchableDecoration +{ + Default + { + Radius 20; + Height 80; + +SOLID + } + States + { + Active: + FBUL I 4 Bright A_PlaySound("Ignite"); + FBUL J 4 Bright; + Spawn: + FBUL ABCDEFG 4 Bright; + Loop; + Inactive: + FBUL JI 4 Bright; + FBUL H -1; + Stop; + } +} + +class ZFireBullUnlit : ZFireBull +{ + States + { + Spawn: + Goto Super::Inactive+2; + } +} + + +// Suit of armor ------------------------------------------------------------ + +class ZSuitOfArmor : Actor +{ + Default + { + Health 60; + Radius 16; + Height 72; + Mass 0x7fffffff; + +SOLID +SHOOTABLE +NOBLOOD + +NOICEDEATH + DeathSound "SuitofArmorBreak"; + } + + States + { + Spawn: + ZSUI A -1; + Stop; + Death: + ZSUI A 1 A_SoAExplode; + Stop; + } + + //=========================================================================== + // + // A_SoAExplode - Suit of Armor Explode + // + //=========================================================================== + + void A_SoAExplode() + { + for (int i = 0; i < 10; i++) + { + double xo = (random[SoAExplode]() - 128) / 16.; + double yo = (random[SoAExplode]() - 128) / 16.; + double zo = random[SoAExplode]() * Height / 256.; + Actor mo = Spawn ("ZArmorChunk", Vec3Offset(xo, yo, zo), ALLOW_REPLACE); + if (mo) + { + mo.SetState (mo.SpawnState + i); + mo.Vel.X = random2[SoAExplode]() / 64.; + mo.Vel.Y = random2[SoAExplode]() / 64.; + mo.Vel.Z = (random[SoAExplode]() & 7) + 5; + } + } + // Spawn an item? + Class type = GetSpawnableType(args[0]); + if (type != null) + { + if (!(level.nomonsters || sv_nomonsters) || !(GetDefaultByType (type).bIsMonster)) + { // Only spawn monsters if not -nomonsters + Spawn (type, Pos, ALLOW_REPLACE); + } + } + A_PlaySound (DeathSound, CHAN_BODY); + Destroy (); + } +} + + +// Armor chunk -------------------------------------------------------------- + +class ZArmorChunk : Actor +{ + Default + { + Radius 4; + Height 8; + } + States + { + Spawn: + ZSUI B -1; + Stop; + ZSUI C -1; + Stop; + ZSUI D -1; + Stop; + ZSUI E -1; + Stop; + ZSUI F -1; + Stop; + ZSUI G -1; + Stop; + ZSUI H -1; + Stop; + ZSUI I -1; + Stop; + ZSUI J -1; + Stop; + ZSUI K -1; + Stop; + } +} + + +// Bell --------------------------------------------------------------------- + +class ZBell : Actor +{ + Default + { + Health 5; + Radius 56; + Height 120; + Mass 0x7fffffff; + +SOLID +SHOOTABLE +NOBLOOD +NOGRAVITY +SPAWNCEILING + +NOICEDEATH + DeathSound "BellRing"; + } + + States + { + Spawn: + BBLL F -1; + Stop; + Death: + BBLL A 4 A_BellReset1; + BBLL BC 4; + BBLL D 5 A_Scream; + BBLL CB 4; + BBLL A 3; + BBLL E 4; + BBLL F 5; + BBLL G 6 A_Scream; + BBLL F 5; + BBLL EA 4; + BBLL BC 5; + BBLL D 6 A_Scream; + BBLL CB 5; + BBLL A 4; + BBLL EF 5; + BBLL G 7 A_Scream; + BBLL FEA 5; + BBLL B 6; + BBLL C 6; + BBLL D 7 A_Scream; + BBLL CB 6; + BBLL A 5; + BBLL EF 6; + BBLL G 7 A_Scream; + BBLL FEABC 6; + BBLL B 7; + BBLL A 8; + BBLL E 12; + BBLL A 10; + BBLL B 12; + BBLL A 12; + BBLL E 14; + BBLL A 1 A_BellReset2; + Goto Spawn; + } + + override void Activate (Actor activator) + { + if (health > 0) A_Die(); + { + DamageMobj (activator, activator, 10, 'Melee', DMG_THRUSTLESS); // 'ring' the bell + } + } + + //=========================================================================== + // + // A_BellReset1 + // + //=========================================================================== + + void A_BellReset1() + { + bNoGravity = true; + Height = Default.Height; + if (special) + { // Initiate death action + A_CallSpecial(special, args[0], args[1], args[2], args[3], args[4]); + special = 0; + } + } + + //=========================================================================== + // + // A_BellReset2 + // + //=========================================================================== + + void A_BellReset2() + { + bShootable = true; + bCorpse = false; + bKilled = false; + health = 5; + } +} + + +// "Christmas" Tree --------------------------------------------------------- + +class ZXmasTree : Actor +{ + Default + { + Radius 11; + Height 130; + Health 20; + Mass 0x7fffffff; + +SOLID +SHOOTABLE +NOBLOOD +NOICEDEATH + DeathSound "TreeExplode"; + } + States + { + Spawn: + XMAS A -1; + Stop; + Burn: + XMAS B 6 Bright; + XMAS C 6 Bright A_Scream; + XMAS D 5 Bright; + XMAS E 5 Bright A_Explode(30, 64); + XMAS F 5 Bright; + XMAS G 4 Bright; + XMAS H 5; + XMAS I 4 A_NoBlocking; + XMAS J 4; + XMAS K -1; + Stop; + } +} + +// Cauldron ----------------------------------------------------------------- + +class ZCauldron : SwitchableDecoration +{ + Default + { + Radius 12; + Height 26; + +SOLID + } + States + { + Active: + CDRN B 0 Bright A_PlaySound("Ignite"); + Spawn: + CDRN BCDEFGH 4 Bright; + Loop; + Inactive: + CDRN A -1; + Stop; + } +} + +class ZCauldronUnlit : ZCauldron +{ + States + { + Spawn: + Goto Super::Inactive; + } +} + + +// Water Drip --------------------------------------------------------------- + +class HWaterDrip : Actor +{ + Default + { + +MISSILE + +NOTELEPORT + Gravity 0.125; + Mass 1; + DeathSound "Drip"; + } + States + { + Spawn: + HWAT A -1; + Stop; + } +} + diff --git a/wadsrc/static/zscript/hexen/iceguy.txt b/wadsrc/static/zscript/hexen/iceguy.txt new file mode 100644 index 0000000000..41105b728e --- /dev/null +++ b/wadsrc/static/zscript/hexen/iceguy.txt @@ -0,0 +1,278 @@ + +// Ice Guy ------------------------------------------------------------------ + +class IceGuy : Actor +{ + Default + { + Health 120; + PainChance 144; + Speed 14; + Radius 22; + Height 75; + Mass 150; + DamageType "Ice"; + Monster; + +NOBLOOD + +TELESTOMP + +NOICEDEATH + SeeSound "IceGuySight"; + AttackSound "IceGuyAttack"; + ActiveSound "IceGuyActive"; + Obituary "$OB_ICEGUY"; + } + + + States + { + Spawn: + ICEY A 10 A_IceGuyLook; + Loop; + See: + ICEY A 4 A_Chase; + ICEY B 4 A_IceGuyChase; + ICEY CD 4 A_Chase; + Loop; + Pain: + ICEY A 1 A_Pain; + Goto See; + Missile: + ICEY EF 3 A_FaceTarget; + ICEY G 8 Bright A_IceGuyAttack; + ICEY F 4 A_FaceTarget; + Goto See; + Death: + ICEY A 1 A_IceGuyDie; + Stop; + Inactive: + ICEY A -1; + Goto See; + } + + //============================================================================ + // + // SpawnWisp + // + //============================================================================ + + private void SpawnWisp() + { + static const class WispTypes[] = { "IceGuyWisp1", "IceGuyWisp2" }; + + double dist = (random[IceGuyLook]() - 128) * radius / 128.; + double an = angle + 90; + Actor mo = Spawn(WispTypes[random[IceGuyLook]() & 1], Vec3Angle(dist, an, 60.), ALLOW_REPLACE); + if (mo) + { + mo.Vel = Vel; + mo.target = self; + } + } + + //============================================================================ + // + // A_IceGuyLook + // + //============================================================================ + + void A_IceGuyLook() + { + A_Look(); + if (random[IceGuyLook]() < 64) SpawnWisp(); + } + + //============================================================================ + // + // A_IceGuyChase + // + //============================================================================ + + void A_IceGuyChase() + { + A_Chase(); + if (random[IceGuyLook]() < 128) SpawnWisp(); + } + + //============================================================================ + // + // A_IceGuyAttack + // + //============================================================================ + + void A_IceGuyAttack() + { + if(!target) + { + return; + } + SpawnMissileXYZ(Vec3Angle(radius / 2, angle + 90, 40.), target, "IceGuyFX"); + SpawnMissileXYZ(Vec3Angle(radius / 2, angle - 90, 40.), target, "IceGuyFX"); + A_PlaySound (AttackSound, CHAN_WEAPON); + } +} + +extend class Actor +{ + //============================================================================ + // + // A_IceGuyDie (globally accessible) + // + //============================================================================ + + void A_IceGuyDie() + { + Vel = (0,0,0); + Height = Default.Height; + A_FreezeDeathChunks(); + } + +} + +// Ice Guy Projectile ------------------------------------------------------- + +class IceGuyFX : Actor +{ + Default + { + Speed 14; + Radius 8; + Height 10; + Damage 1; + DamageType "Ice"; + Projectile; + -ACTIVATEIMPACT -ACTIVATEPCROSS + DeathSound "IceGuyMissileExplode"; + } + + States + { + Spawn: + ICPR ABC 3 Bright A_SpawnItemEx("IceFXPuff", 0,0,2); + Loop; + Death: + ICPR D 4 Bright; + ICPR E 4 Bright A_IceGuyMissileExplode; + ICPR FG 4 Bright; + ICPR H 3 Bright; + Stop; + } + + + //============================================================================ + // + // A_IceGuyMissileExplode + // + //============================================================================ + + void A_IceGuyMissileExplode() + { + for (int i = 0; i < 8; i++) + { + Actor mo = SpawnMissileAngleZ (pos.z+3, "IceGuyFX2", i*45., -0.3); + if (mo) + { + mo.target = target; + } + } + } +} + +// Ice Guy Projectile's Puff ------------------------------------------------ + +class IceFXPuff : Actor +{ + Default + { + Radius 1; + Height 1; + +NOBLOCKMAP +NOGRAVITY +DROPOFF +SHADOW + +NOTELEPORT + RenderStyle "Translucent"; + Alpha 0.4; + } + States + { + Spawn: + ICPR IJK 3; + ICPR LM 2; + Stop; + } +} + +// Secondary Ice Guy Projectile (ejected by the primary projectile) --------- + +class IceGuyFX2 : Actor +{ + Default + { + Speed 10; + Radius 4; + Height 4; + Damage 1; + DamageType "Ice"; + Gravity 0.125; + +NOBLOCKMAP +DROPOFF +MISSILE + +NOTELEPORT + +STRIFEDAMAGE + } + States + { + Spawn: + ICPR NOP 3 Bright; + Loop; + } +} + +// Ice Guy Bit -------------------------------------------------------------- + +class IceGuyBit : Actor +{ + Default + { + Radius 1; + Height 1; + Gravity 0.125; + +NOBLOCKMAP +DROPOFF + +NOTELEPORT + } + States + { + Spawn: + ICPR Q 50 Bright; + Stop; + ICPR R 50 Bright; + Stop; + } +} + +// Ice Guy Wisp 1 ----------------------------------------------------------- + +class IceGuyWisp1 : Actor +{ + Default + { + +NOBLOCKMAP +NOGRAVITY +DROPOFF +MISSILE + +NOTELEPORT + RenderStyle "Translucent"; + Alpha 0.4; + } + States + { + Spawn: + ICWS ABCDEFGHI 2; + Stop; + } +} + +// Ice Guy Wisp 2 ----------------------------------------------------------- + +class IceGuyWisp2 : IceGuyWisp1 +{ + States + { + Spawn: + ICWS JKLMNOPQR 2; + Stop; + } +} + diff --git a/wadsrc/static/zscript/hexen/korax.txt b/wadsrc/static/zscript/hexen/korax.txt new file mode 100644 index 0000000000..1c1f31712f --- /dev/null +++ b/wadsrc/static/zscript/hexen/korax.txt @@ -0,0 +1,531 @@ +//=========================================================================== +// 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) +//=========================================================================== + +class Korax : Actor +{ + const KORAX_ARM_EXTENSION_SHORT = 40; + const KORAX_ARM_EXTENSION_LONG = 55; + + const KORAX_ARM1_HEIGHT = 108; + const KORAX_ARM2_HEIGHT = 82; + const KORAX_ARM3_HEIGHT = 54; + const KORAX_ARM4_HEIGHT = 104; + const KORAX_ARM5_HEIGHT = 86; + const KORAX_ARM6_HEIGHT = 53; + + const KORAX_FIRST_TELEPORT_TID = 248; + const KORAX_TELEPORT_TID = 249; + + const KORAX_DELTAANGLE = 85; + + const KORAX_COMMAND_HEIGHT = 120; + const KORAX_COMMAND_OFFSET = 27; + + const KORAX_SPIRIT_LIFETIME = 5*TICRATE/5; // 5 seconds + + Default + { + Health 5000; + Painchance 20; + Speed 10; + Radius 65; + Height 115; + Mass 2000; + Damage 15; + Monster; + +BOSS + +FLOORCLIP + +TELESTOMP + +DONTMORPH + +NOTARGET + +NOICEDEATH + SeeSound "KoraxSight"; + AttackSound "KoraxAttack"; + PainSound "KoraxPain"; + DeathSound "KoraxDeath"; + ActiveSound "KoraxActive"; + Obituary "$OB_KORAX"; + } + + States + { + Spawn: + KORX A 5 A_Look; + Loop; + See: + KORX AAA 3 A_KoraxChase; + KORX B 3 A_Chase; + KORX BBB 3 A_KoraxChase; + KORX C 3 A_KoraxStep; + KORX CCC 3 A_KoraxChase; + KORX D 3 A_Chase; + KORX DDD 3 A_KoraxChase; + KORX A 3 A_KoraxStep; + Loop; + Pain: + KORX H 5 A_Pain; + KORX H 5; + Goto See; + Missile: + KORX E 2 Bright A_FaceTarget; + KORX E 5 Bright A_KoraxDecide; + Wait; + Death: + KORX I 5; + KORX J 5 A_FaceTarget; + KORX K 5 A_Scream; + KORX LMNOP 5; + KORX Q 10; + KORX R 5 A_KoraxBonePop; + KORX S 5 A_NoBlocking; + KORX TU 5; + KORX V -1; + Stop; + Attack: + KORX E 4 Bright A_FaceTarget; + KORX F 8 Bright A_KoraxMissile; + KORX E 8 Bright; + Goto See; + Command: + KORX E 5 Bright A_FaceTarget; + KORX W 10 Bright A_FaceTarget; + KORX G 15 Bright A_KoraxCommand; + KORX W 10 Bright; + KORX E 5 Bright; + Goto See; + } + + + void A_KoraxStep() + { + A_PlaySound("KoraxStep"); + A_Chase(); + } + + //============================================================================ + // + // A_KoraxChase + // + //============================================================================ + + + void A_KoraxChase() + { + if ((!special2) && (health <= (SpawnHealth()/2))) + { + ActorIterator it = ActorIterator.Create(KORAX_FIRST_TELEPORT_TID); + Actor spot = it.Next (); + if (spot != null) + { + Teleport ((spot.pos.xy, ONFLOORZ), spot.angle, TELF_SOURCEFOG | TELF_DESTFOG); + } + ACS_Execute(249, 0); + special2 = 1; // Don't run again + return; + } + + if (target == null) + { + return; + } + if (random[KoraxChase]() < 30) + { + SetState (MissileState); + } + else if (random[KoraxChase]() < 30) + { + A_PlaySound("KoraxActive", CHAN_VOICE, 1, false, ATTN_NONE); + } + + // Teleport away + if (health < (SpawnHealth() >> 1)) + { + if (random[KoraxChase]() < 10) + { + ActorIterator it = ActorIterator.Create(KORAX_TELEPORT_TID); + Actor spot; + + if (tracer != null) + { // Find the previous teleport destination + do + { + spot = it.Next (); + } while (spot != null && spot != tracer); + } + + // Go to the next teleport destination + spot = it.Next (); + tracer = spot; + if (spot) + { + Teleport ((spot.pos.xy, ONFLOORZ), spot.angle, TELF_SOURCEFOG | TELF_DESTFOG); + } + } + } + } + + //============================================================================ + // + // A_KoraxDecide + // + //============================================================================ + + void A_KoraxDecide() + { + if (random[KoraxDecide]() < 220) + { + SetStateLabel ("Attack"); + } + else + { + SetStateLabel ("Command"); + } + } + + //============================================================================ + // + // A_KoraxBonePop + // + //============================================================================ + + void A_KoraxBonePop() + { + // Spawn 6 spirits equalangularly + for (int i = 0; i < 6; ++i) + { + Actor mo = SpawnMissileAngle ("KoraxSpirit", 60.*i, 5.); + if (mo) + { + KSpiritInit (mo); + } + } + ACS_Execute(255, 0); + } + + //============================================================================ + // + // KSpiritInit + // + //============================================================================ + + private void KSpiritInit (Actor spirit) + { + spirit.health = KORAX_SPIRIT_LIFETIME; + + spirit.tracer = self; // Swarm around korax + spirit.WeaveIndexZ = 32 + (random[Kspiritnit]() & 7); // Float bob index + spirit.args[0] = 10; // initial turn value + spirit.args[1] = 0; // initial look angle + + // Spawn a tail for spirit + HolyTail.SpawnSpiritTail (spirit); + } + + //============================================================================ + // + // A_KoraxMissile + // + //============================================================================ + + void A_KoraxMissile() + { + static const class choices[] = + { + "WraithFX1", "Demon1FX1", "Demon2FX1", "FireDemonMissile", "CentaurFX", "SerpentFX" + }; + static const sound sounds[] = + { + "WraithMissileFire", "DemonMissileFire", "DemonMissileFire", "FireDemonAttack", "CentaurLeaderAttack", "SerpentLeaderAttack" + }; + int type = random[KoraxMissile]() % 6; + + A_PlaySound("KoraxAttack", CHAN_VOICE); + + // Fire all 6 missiles at once + A_PlaySound(sounds[type], CHAN_WEAPON, 1, false, ATTN_NONE); + class info = choices[type]; + for (int i = 0; i < 6; ++i) + { + KoraxFire(info, i); + } + } + + //============================================================================ + // + // 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 (Class type, int arm) + { + static const int extension[] = + { + 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[] = + { + KORAX_ARM1_HEIGHT, + KORAX_ARM2_HEIGHT, + KORAX_ARM3_HEIGHT, + KORAX_ARM4_HEIGHT, + KORAX_ARM5_HEIGHT, + KORAX_ARM6_HEIGHT + }; + + double ang = angle + (arm < 3 ? -KORAX_DELTAANGLE : KORAX_DELTAANGLE); + Vector3 pos = Vec3Angle(extension[arm], ang, armheight[arm] - Floorclip); + SpawnKoraxMissile (pos, target, type); + } + + //============================================================================ + // + // P_SpawnKoraxMissile + // + //============================================================================ + + private void SpawnKoraxMissile (Vector3 pos, Actor dest, Class type) + { + Actor th = Spawn (type, pos, ALLOW_REPLACE); + th.target = self; // Originator + double an = th.AngleTo(dest); + if (dest.bShadow) + { // Invisible target + an += Random2[KoraxMissile]() * (45/256.); + } + th.angle = an; + th.VelFromAngle(); + double dist = dest.DistanceBySpeed(th, th.Speed); + th.Vel.Z = (dest.pos.z - pos.Z + 30) / dist; + th.CheckMissileSpawn(radius); + } + + //============================================================================ + // + // A_KoraxCommand + // + // Call action code scripts (250-254) + // + //============================================================================ + + void A_KoraxCommand() + { + int numcommands; + + A_PlaySound("KoraxCommand", CHAN_VOICE); + + // Shoot stream of lightning to ceiling + double ang = angle - 90; + Vector3 pos = Vec3Angle(KORAX_COMMAND_OFFSET, ang, KORAX_COMMAND_HEIGHT); + Spawn("KoraxBolt", pos, ALLOW_REPLACE); + + if (health <= (SpawnHealth() >> 1)) + { + numcommands = 5; + } + else + { + numcommands = 4; + } + + ACS_Execute(250 + (random[KoraxCommand]()%numcommands), 0); + } +} + +class KoraxSpirit : Actor +{ + Default + { + Speed 8; + Projectile; + +NOCLIP + -ACTIVATEPCROSS + -ACTIVATEIMPACT + RenderStyle "Translucent"; + Alpha 0.4; + } + + States + { + Spawn: + SPIR AB 5 A_KSpiritRoam; + Loop; + Death: + SPIR DEFGHI 5; + Stop; + } + + //============================================================================ + // + // A_KSpiritSeeker + // + //============================================================================ + + private void KSpiritSeeker (double thresh, double turnMax) + { + Actor target = tracer; + if (target == null) + { + return; + } + double dir = deltaangle(angle, AngleTo(target)); + double delta = abs(dir); + if (delta > thresh) + { + delta /= 2; + if(delta > turnMax) + { + delta = turnMax; + } + } + if(dir > 0) + { // Turn clockwise + angle += delta; + } + else + { // Turn counter clockwise + angle -= delta; + } + VelFromAngle(); + + if (!(level.time&15) + || pos.z > target.pos.z + target.Default.Height + || pos.z + height < target.pos.z) + { + double newZ = target.pos.z + random[KoraxRoam]() * target.Default.Height / 256; + double deltaZ = newZ - pos.z; + + if (abs(deltaZ) > 15) + { + if(deltaZ > 0) + { + deltaZ = 15; + } + else + { + deltaZ = -15; + } + } + Vel.Z = deltaZ + DistanceBySpeed(target, Speed); + } + } + + //============================================================================ + // + // A_KSpiritRoam + // + //============================================================================ + + void A_KSpiritRoam() + { + if (health-- <= 0) + { + A_PlaySound("SpiritDie", CHAN_VOICE); + SetStateLabel ("Death"); + } + else + { + if (tracer) + { + KSpiritSeeker(args[0], args[0] * 2.); + } + int xyspeed = (random[KoraxRoam]() % 5); + int zspeed = (random[KoraxRoam]() % 5); + A_Weave(xyspeed, zspeed, 4., 2.); + + if (random[KoraxRoam]() < 50) + { + A_PlaySound("SpiritActive", CHAN_VOICE, 1, false, ATTN_NONE); + } + } + } +} + +class KoraxBolt : Actor +{ + const KORAX_BOLT_HEIGHT = 48.; + const KORAX_BOLT_LIFETIME = 3; + + Default + { + Radius 15; + Height 35; + Projectile; + -ACTIVATEPCROSS + -ACTIVATEIMPACT + RenderStyle "Add"; + } + + States + { + Spawn: + MLFX I 2 Bright; + MLFX J 2 Bright A_KBoltRaise; + MLFX IJKLM 2 Bright A_KBolt; + Stop; + } + + //============================================================================ + // + // A_KBolt + // + //============================================================================ + + void A_KBolt() + { + // Countdown lifetime + if (special1-- <= 0) + { + Destroy (); + } + } + + //============================================================================ + // + // A_KBoltRaise + // + //============================================================================ + + void A_KBoltRaise() + { + // Spawn a child upward + double z = pos.z + KORAX_BOLT_HEIGHT; + + if ((z + KORAX_BOLT_HEIGHT) < ceilingz) + { + Actor mo = Spawn("KoraxBolt", (pos.xy, z), ALLOW_REPLACE); + if (mo) + { + mo.special1 = KORAX_BOLT_LIFETIME; + } + } + } +} diff --git a/wadsrc/static/zscript/hexen/mageboss.txt b/wadsrc/static/zscript/hexen/mageboss.txt new file mode 100644 index 0000000000..0c081d786d --- /dev/null +++ b/wadsrc/static/zscript/hexen/mageboss.txt @@ -0,0 +1,119 @@ + +// Mage Boss (Menelkir) ----------------------------------------------------- + +class MageBoss : Actor +{ + Default + { + Health 800; + PainChance 50; + Speed 25; + Radius 16; + Height 64; + Monster; + +FLOORCLIP +TELESTOMP + +DONTMORPH + PainSound "PlayerMagePain"; + DeathSound "PlayerMageCrazyDeath"; + Obituary "$OB_MBOSS"; + } + + States + { + Spawn: + MAGE A 2; + MAGE A 3 A_ClassBossHealth; + MAGE A 5 A_Look; + Wait; + See: + MAGE ABCD 4 A_FastChase; + Loop; + Pain: + MAGE G 4; + MAGE G 4 A_Pain; + Goto See; + Melee: + Missile: + MAGE E 8 A_FaceTarget; + MAGE F 8 Bright A_MageAttack; + Goto See; + Death: + MAGE H 6; + MAGE I 6 A_Scream; + MAGE JK 6; + MAGE L 6 A_NoBlocking; + MAGE M 6; + MAGE N -1; + Stop; + XDeath: + MAGE O 5 A_Scream; + MAGE P 5; + MAGE R 5 A_NoBlocking; + MAGE S 5; + MAGE T 5; + MAGE U 5; + MAGE V 5; + MAGE W 5; + MAGE X -1; + Stop; + Ice: + MAGE Y 5 A_FreezeDeath; + MAGE Y 1 A_FreezeDeathChunks; + Wait; + Burn: + FDTH E 5 Bright A_PlaySound("PlayerMageBurnDeath"); + FDTH F 4 Bright; + FDTH G 5 Bright; + FDTH H 4 Bright A_Scream; + FDTH I 5 Bright; + FDTH J 4 Bright; + FDTH K 5 Bright; + FDTH L 4 Bright; + FDTH M 5 Bright; + FDTH N 4 Bright; + FDTH O 5 Bright; + FDTH P 4 Bright; + FDTH Q 5 Bright; + FDTH R 4 Bright; + FDTH S 5 Bright A_NoBlocking; + FDTH T 4 Bright; + FDTH U 5 Bright; + FDTH V 4 Bright; + Stop; + } + + //============================================================================ + // + // MStaffSpawn2 - for use by mage class boss + // + //============================================================================ + + void MStaffSpawn2 (double angle) + { + Actor mo = SpawnMissileAngleZ (pos.z + 40, "MageStaffFX2", angle, 0.); + if (mo) + { + mo.target = self; + mo.tracer = RoughMonsterSearch(10, true, true); + } + } + + //============================================================================ + // + // A_MStaffAttack2 - for use by mage class boss + // + //============================================================================ + + void A_MageAttack() + { + if (target == NULL) + { + return; + } + MStaffSpawn2(angle); + MStaffSpawn2(angle - 5); + MStaffSpawn2(angle + 5); + A_PlaySound("MageStaffFire", CHAN_WEAPON); + } + +} diff --git a/wadsrc/static/zscript/hexen/magecone.txt b/wadsrc/static/zscript/hexen/magecone.txt new file mode 100644 index 0000000000..2bbd58f3d7 --- /dev/null +++ b/wadsrc/static/zscript/hexen/magecone.txt @@ -0,0 +1,232 @@ + +// The Mage's Frost Cone ---------------------------------------------------- + +class MWeapFrost : MageWeapon +{ + Default + { + +BLOODSPLATTER + Weapon.SelectionOrder 1700; + Weapon.AmmoUse1 3; + Weapon.AmmoGive1 25; + Weapon.KickBack 150; + Weapon.YAdjust 20; + Weapon.AmmoType1 "Mana1"; + Inventory.PickupMessage "$TXT_WEAPON_M2"; + Obituary "$OB_MPMWEAPFROST"; + Tag "$TAG_MWEAPFROST"; + } + + States + { + Spawn: + WMCS ABC 8 Bright; + Loop; + Select: + CONE A 1 A_Raise; + Loop; + Deselect: + CONE A 1 A_Lower; + Loop; + Ready: + CONE A 1 A_WeaponReady; + Loop; + Fire: + CONE B 3; + CONE C 4; + Hold: + CONE D 3; + CONE E 5; + CONE F 3 A_FireConePL1; + CONE G 3; + CONE A 9; + CONE A 10 A_ReFire; + Goto Ready; + } + + //============================================================================ + // + // A_FireConePL1 + // + //============================================================================ + + action void A_FireConePL1() + { + bool conedone=false; + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + A_PlaySound ("MageShardsFire", CHAN_WEAPON); + + int damage = 90+(random[MageCone]() & 15); + for (int i = 0; i < 16; i++) + { + double ang = angle + i*(45./16); + double slope = AimLineAttack (ang, MELEERANGE, t, 0., ALF_CHECK3D); + if (t.linetarget) + { + t.linetarget.DamageMobj (self, self, damage, 'Ice', DMG_USEANGLE, t.angleFromSource); + conedone = true; + break; + } + } + + // didn't find any creatures, so fire projectiles + if (!conedone) + { + Actor mo = SpawnPlayerMissile ("FrostMissile"); + if (mo) + { + mo.special1 = FrostMissile.SHARDSPAWN_LEFT|FrostMissile.SHARDSPAWN_DOWN|FrostMissile.SHARDSPAWN_UP|FrostMissile.SHARDSPAWN_RIGHT; + mo.special2 = 3; // Set sperm count (levels of reproductivity) + mo.target = self; + mo.args[0] = 3; // Mark Initial shard as super damage + } + } + } +} + +// Frost Missile ------------------------------------------------------------ + +class FrostMissile : Actor +{ + const SHARDSPAWN_LEFT = 1; + const SHARDSPAWN_RIGHT = 2; + const SHARDSPAWN_UP = 4; + const SHARDSPAWN_DOWN = 8; + + Default + { + Speed 25; + Radius 13; + Height 8; + Damage 1; + DamageType "Ice"; + Projectile; + DeathSound "MageShardsExplode"; + Obituary "$OB_MPMWEAPFROST"; + } + + States + { + Spawn: + SHRD A 2 Bright; + SHRD A 3 Bright A_ShedShard; + SHRD B 3 Bright; + SHRD C 3 Bright; + Loop; + Death: + SHEX ABCDE 5 Bright; + Stop; + } + + override int DoSpecialDamage (Actor victim, int damage, Name damagetype) + { + if (special2 > 0) + { + damage <<= special2; + } + return damage; + } + + //============================================================================ + // + // A_ShedShard + // + //============================================================================ + + void A_ShedShard() + { + int spawndir = special1; + int spermcount = special2; + Actor mo; + + if (spermcount <= 0) + { + return; // No sperm left + } + special2 = 0; + spermcount--; + + // every so many calls, spawn a new missile in its set directions + if (spawndir & SHARDSPAWN_LEFT) + { + mo = SpawnMissileAngleZSpeed(pos.z, "FrostMissile", angle + 5, 0, (20. + 2 * spermcount), target); + if (mo) + { + mo.special1 = SHARDSPAWN_LEFT; + mo.special2 = spermcount; + mo.Vel.Z = Vel.Z; + mo.args[0] = (spermcount==3)?2:0; + } + } + if (spawndir & SHARDSPAWN_RIGHT) + { + mo = SpawnMissileAngleZSpeed(pos.z, "FrostMissile", angle - 5, 0, (20. + 2 * spermcount), target); + if (mo) + { + mo.special1 = SHARDSPAWN_RIGHT; + mo.special2 = spermcount; + mo.Vel.Z = Vel.Z; + mo.args[0] = (spermcount==3)?2:0; + } + } + if (spawndir & SHARDSPAWN_UP) + { + mo = SpawnMissileAngleZSpeed(pos.z + 8., "FrostMissile", angle, 0, (15. + 2 * spermcount), target); + if (mo) + { + mo.Vel.Z = 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 = SpawnMissileAngleZSpeed(pos.z - 4., "FrostMissile", angle, 0, (15. + 2 * spermcount), target); + if (mo) + { + mo.Vel.Z = 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 = target; + mo.args[0] = (spermcount==3)?2:0; + } + } + } +} + +// Ice Shard ---------------------------------------------------------------- + +class IceShard : FrostMissile +{ + Default + { + DamageType "Ice"; + -ACTIVATEIMPACT + -ACTIVATEPCROSS + } + States + { + Spawn: + SHRD ABC 3 Bright; + Loop; + } +} diff --git a/wadsrc/static/zscript/hexen/magelightning.txt b/wadsrc/static/zscript/hexen/magelightning.txt new file mode 100644 index 0000000000..343c960120 --- /dev/null +++ b/wadsrc/static/zscript/hexen/magelightning.txt @@ -0,0 +1,444 @@ + +// The Mage's Lightning Arc of Death ---------------------------------------- + +class MWeapLightning : MageWeapon +{ + Default + { + +NOGRAVITY + Weapon.SelectionOrder 1100; + Weapon.AmmoUse1 5; + Weapon.AmmoGive1 25; + Weapon.KickBack 0; + Weapon.YAdjust 20; + Weapon.AmmoType1 "Mana2"; + Inventory.PickupMessage "$TXT_WEAPON_M3"; + Tag "$TAG_MWEAPLIGHTNING"; + } + + States + { + Spawn: + WMLG ABCDEFGH 4 Bright; + Loop; + Select: + MLNG A 1 Bright A_Raise; + Loop; + Deselect: + MLNG A 1 Bright A_Lower; + Loop; + Ready: + MLNG AAAAA 1 Bright A_WeaponReady; + MLNG A 1 Bright A_LightningReady; + MLNG BBBBBB 1 Bright A_WeaponReady; + MLNG CCCCC 1 Bright A_WeaponReady; + MLNG C 1 Bright A_LightningReady; + MLNG BBBBBB 1 Bright A_WeaponReady; + Loop; + Fire: + MLNG DE 3 Bright; + MLNG F 4 Bright A_MLightningAttack; + MLNG G 4 Bright; + MLNG HI 3 Bright; + MLNG I 6 Bright Offset (0, 199); + MLNG C 2 Bright Offset (0, 55); + MLNG B 2 Bright Offset (0, 50); + MLNG B 2 Bright Offset (0, 45); + MLNG B 2 Bright Offset (0, 40); + Goto Ready; + } + + //============================================================================ + // + // A_LightningReady + // + //============================================================================ + + action void A_LightningReady() + { + A_WeaponReady(); + if (random[LightningReady]() < 160) + { + A_PlaySound ("MageLightningReady", CHAN_WEAPON); + } + } + + //============================================================================ + // + // A_MLightningAttack + // + //============================================================================ + + action void A_MLightningAttack(class floor = "LightningFloor", class ceiling = "LightningCeiling") + { + LightningFloor fmo = LightningFloor(SpawnPlayerMissile (floor)); + LightningCeiling cmo = LightningCeiling(SpawnPlayerMissile (ceiling)); + if (fmo) + { + fmo.special1 = 0; + fmo.lastenemy = cmo; + fmo.A_LightningZap(); + } + if (cmo) + { + cmo.tracer = NULL; + cmo.lastenemy = fmo; + cmo.A_LightningZap(); + } + A_PlaySound ("MageLightningFire", CHAN_BODY); + + if (player != NULL) + { + Weapon weapon = player.ReadyWeapon; + if (weapon != NULL) + { + weapon.DepleteAmmo (weapon.bAltFire); + } + } + } + + +} + +// Ceiling Lightning -------------------------------------------------------- + +class Lightning : Actor +{ + Default + { + MissileType "LightningZap"; + AttackSound "MageLightningZap"; + ActiveSound "MageLightningContinuous"; + Obituary "$OB_MPMWEAPLIGHTNING"; + } + + override int SpecialMissileHit (Actor thing) + { + if (thing.bShootable && thing != target) + { + if (thing.Mass < LARGE_MASS) + { + thing.Vel.X += Vel.X / 16; + thing.Vel.Y += Vel.Y / 16; + } + if ((!thing.player && !thing.bBoss) || !(level.time&1)) + { + thing.DamageMobj(self, target, 3, 'Electric'); + A_PlaySound(AttackSound, CHAN_WEAPON, 1, true); + if (thing.bIsMonster && random[LightningHit]() < 64) + { + thing.Howl (); + } + } + health--; + if (health <= 0 || thing.health <= 0) + { + return 0; + } + if (bFloorHugger) + { + if (lastenemy && ! lastenemy.tracer) + { + lastenemy.tracer = thing; + } + } + else if (!tracer) + { + tracer = thing; + } + } + return 1; // lightning zaps through all sprites + } + +} + +class LightningCeiling : Lightning +{ + const ZAGSPEED = 1; + + Default + { + Health 144; + Speed 25; + Radius 16; + Height 40; + Damage 8; + Projectile; + +CEILINGHUGGER + RenderStyle "Add"; + } + + States + { + Spawn: + MLFX A 2 Bright A_LightningZap; + MLFX BCD 2 Bright A_LightningClip; + Loop; + Death: + MLF2 A 2 Bright A_LightningRemove; + MLF2 BCDEKLM 3 Bright; + ACLO E 35; + MLF2 NO 3 Bright; + MLF2 P 4 Bright; + MLF2 QP 3 Bright; + MLF2 Q 4 Bright; + MLF2 P 3 Bright; + MLF2 O 3 Bright; + MLF2 P 3 Bright; + MLF2 P 1 Bright A_HideThing; + ACLO E 1050; + Stop; + } + + //============================================================================ + // + // A_LightningClip + // + //============================================================================ + + void A_LightningClip() + { + Actor cMo; + Actor target = NULL; + int zigZag; + + if (bFloorHugger) + { + if (lastenemy == NULL) + { + return; + } + SetZ(floorz); + target = lastenemy.tracer; + } + else if (bCeilingHugger) + { + SetZ(ceilingz - Height); + target = tracer; + } + if (bFloorHugger) + { // floor lightning zig-zags, and forces the ceiling lightning to mimic + cMo = lastenemy; + zigZag = random[LightningClip](); + if((zigZag > 128 && special1 < 2) || special1 < -2) + { + Thrust(ZAGSPEED, angle + 90); + if(cMo) + { + cMo.Thrust(ZAGSPEED, angle + 90); + } + special1++; + } + else + { + Thrust(ZAGSPEED,angle - 90); + if(cMo) + { + cMo.Thrust(ZAGSPEED, angle - 90); + } + special1--; + } + } + if(target) + { + if(target.health <= 0) + { + ExplodeMissile(); + } + else + { + angle = AngleTo(target); + VelFromAngle(Speed / 2); + } + } + } + + + //============================================================================ + // + // A_LightningZap + // + //============================================================================ + + void A_LightningZap() + { + Class lightning = MissileName; + if (lightning == NULL) lightning = "LightningZap"; + + A_LightningClip(); + + health -= 8; + if (health <= 0) + { + SetStateLabel ("Death"); + return; + } + double deltaX = (random[LightningZap]() - 128) * radius / 256; + double deltaY = (random[LightningZap]() - 128) * radius / 256; + double deltaZ = (bFloorHugger) ? 10 : -10; + + Actor mo = Spawn(lightning, Vec3Offset(deltaX, deltaY, deltaZ), ALLOW_REPLACE); + if (mo) + { + mo.lastenemy = self; + mo.Vel.X = Vel.X; + mo.Vel.Y = Vel.Y; + mo.Vel.Z = (bFloorHugger) ? 20 : -20; + mo.target = target; + } + if (bFloorHugger && random[LightningZap]() < 160) + { + A_PlaySound (ActiveSound, CHAN_BODY); + } + } + + //============================================================================ + // + // A_LightningRemove + // + //============================================================================ + + void A_LightningRemove() + { + Actor mo = lastenemy; + if (mo) + { + bNoTarget = true; // tell A_ZapMimic that we are dead. The original code did a state pointer compare which is not safe. + mo.lastenemy = NULL; + mo.ExplodeMissile (); + } + } + +} + +// Floor Lightning ---------------------------------------------------------- + +class LightningFloor : LightningCeiling +{ + Default + { + -CEILINGHUGGER + +FLOORHUGGER + RenderStyle "Add"; + } + + States + { + Spawn: + MLFX E 2 Bright A_LightningZap; + MLFX FGH 2 Bright A_LightningClip; + Loop; + Death: + MLF2 F 2 Bright A_LightningRemove; + MLF2 GHIJKLM 3 Bright; + ACLO E 20; + MLF2 NO 3 Bright; + MLF2 P 4 Bright; + MLF2 QP 3 Bright; + MLF2 Q 4 Bright A_LastZap; + MLF2 POP 3 Bright; + MLF2 P 1 Bright A_HideThing; + Goto Super::Death + 19; + } + + //============================================================================ + // + // A_LastZap + // + //============================================================================ + + void A_LastZap() + { + Class lightning = MissileName; + if (lightning == NULL) lightning = "LightningZap"; + + Actor mo = Spawn(lightning, self.Pos, ALLOW_REPLACE); + if (mo) + { + mo.SetStateLabel ("Death"); + mo.Vel.Z = 40; + mo.SetDamage(0); + } + } +} + +// Lightning Zap ------------------------------------------------------------ + +class LightningZap : Actor +{ + Default + { + Radius 15; + Height 35; + Damage 2; + Projectile; + -ACTIVATEIMPACT + -ACTIVATEPCROSS + RenderStyle "Add"; + Obituary "$OB_MPMWEAPLIGHTNING"; + } + + States + { + Spawn: + MLFX IJKLM 2 Bright A_ZapMimic; + Loop; + Death: + MLFX NOPQRSTU 2 Bright; + Stop; + } + + override int SpecialMissileHit (Actor thing) + { + Actor lmo; + + if (thing.bShootable && thing != target) + { + lmo = lastenemy; + if (lmo) + { + if (lmo.bFloorHugger) + { + 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_ZapMimic + // + //============================================================================ + + void A_ZapMimic() + { + Actor mo = lastenemy; + if (mo) + { + if (mo.bNoTarget) + { + ExplodeMissile (); + } + else + { + Vel.X = mo.Vel.X; + Vel.Y = mo.Vel.Y; + } + } + } + + +} diff --git a/wadsrc/static/zscript/hexen/mageplayer.txt b/wadsrc/static/zscript/hexen/mageplayer.txt new file mode 100644 index 0000000000..33b34633ea --- /dev/null +++ b/wadsrc/static/zscript/hexen/mageplayer.txt @@ -0,0 +1,107 @@ +// The mage ----------------------------------------------------------------- + +class MagePlayer : PlayerPawn +{ + Default + { + Health 100; + ReactionTime 0; + PainChance 255; + Radius 16; + Height 64; + Speed 1; + +NOSKIN + +NODAMAGETHRUST + +PLAYERPAWN.NOTHRUSTWHENINVUL + PainSound "PlayerMagePain"; + RadiusDamageFactor 0.25; + Player.JumpZ 9; + Player.Viewheight 48; + Player.SpawnClass "Mage"; + Player.DisplayName "Mage"; + Player.SoundClass "mage"; + Player.ScoreIcon "MAGEFACE"; + Player.InvulnerabilityMode "Reflective"; + Player.HealRadiusType "Mana"; + Player.Hexenarmor 5, 5, 15, 10, 25; + Player.StartItem "MWeapWand"; + Player.ForwardMove 0.88, 0.92; + Player.SideMove 0.875, 0.925; + Player.Portrait "P_MWALK1"; + Player.WeaponSlot 1, "MWeapWand"; + Player.WeaponSlot 2, "MWeapFrost"; + Player.WeaponSlot 3, "MWeapLightning"; + Player.WeaponSlot 4, "MWeapBloodscourge"; + Player.FlechetteType "ArtiPoisonBag2"; + + Player.ColorRange 146, 163; + Player.Colorset 0, "Blue", 146, 163, 161; + Player.ColorsetFile 1, "Red", "TRANTBL7", 0xB3; + Player.ColorsetFile 2, "Gold", "TRANTBL8", 0x8C; + Player.ColorsetFile 3, "Dull Green", "TRANTBL9", 0x41; + Player.ColorsetFile 4, "Green", "TRANTBLA", 0xC9; + Player.ColorsetFile 5, "Gray", "TRANTBLB", 0x30; + Player.ColorsetFile 6, "Brown", "TRANTBLC", 0x72; + Player.ColorsetFile 7, "Purple", "TRANTBLD", 0xEE; + } + + States + { + Spawn: + MAGE A -1; + Stop; + See: + MAGE ABCD 4; + Loop; + Missile: + Melee: + MAGE EF 8; + Goto Spawn; + Pain: + MAGE G 4; + MAGE G 4 A_Pain; + Goto Spawn; + Death: + MAGE H 6; + MAGE I 6 A_PlayerScream; + MAGE JK 6; + MAGE L 6 A_NoBlocking; + MAGE M 6; + MAGE N -1; + Stop; + XDeath: + MAGE O 5 A_PlayerScream; + MAGE P 5; + MAGE R 5 A_NoBlocking; + MAGE STUVW 5; + MAGE X -1; + Stop; + Ice: + MAGE Y 5 A_FreezeDeath; + MAGE Y 1 A_FreezeDeathChunks; + Wait; + Burn: + FDTH E 5 BRIGHT A_PlaySound("*burndeath"); + FDTH F 4 BRIGHT; + FDTH G 5 BRIGHT; + FDTH H 4 BRIGHT A_PlayerScream; + FDTH I 5 BRIGHT; + FDTH J 4 BRIGHT; + FDTH K 5 BRIGHT; + FDTH L 4 BRIGHT; + FDTH M 5 BRIGHT; + FDTH N 4 BRIGHT; + FDTH O 5 BRIGHT; + FDTH P 4 BRIGHT; + FDTH Q 5 BRIGHT; + FDTH R 4 BRIGHT; + FDTH S 5 BRIGHT A_NoBlocking; + FDTH T 4 BRIGHT; + FDTH U 5 BRIGHT; + FDTH V 4 BRIGHT; + ACLO E 35 A_CheckPlayerDone; + Wait; + ACLO E 8; + Stop; + } +} diff --git a/wadsrc/static/zscript/hexen/magestaff.txt b/wadsrc/static/zscript/hexen/magestaff.txt new file mode 100644 index 0000000000..e450952404 --- /dev/null +++ b/wadsrc/static/zscript/hexen/magestaff.txt @@ -0,0 +1,290 @@ + +// Mage Weapon Piece -------------------------------------------------------- + +class MageWeaponPiece : WeaponPiece +{ + Default + { + Inventory.PickupSound "misc/w_pkup"; + Inventory.PickupMessage "$TXT_BLOODSCOURGE_PIECE"; + Inventory.ForbiddenTo "FighterPlayer", "ClericPlayer"; + WeaponPiece.Weapon "MWeapBloodscourge"; + +FLOATBOB + } +} + +// Mage Weapon Piece 1 ------------------------------------------------------ + +class MWeaponPiece1 : MageWeaponPiece +{ + Default + { + WeaponPiece.Number 1; + } + States + { + Spawn: + WMS1 A -1 Bright; + Stop; + } +} + +// Mage Weapon Piece 2 ------------------------------------------------------ + +class MWeaponPiece2 : MageWeaponPiece +{ + Default + { + WeaponPiece.Number 2; + } + States + { + Spawn: + WMS2 A -1 Bright; + Stop; + } +} + +// Mage Weapon Piece 3 ------------------------------------------------------ + +class MWeaponPiece3 : MageWeaponPiece +{ + Default + { + WeaponPiece.Number 3; + } + States + { + Spawn: + WMS3 A -1 Bright; + Stop; + } +} + +// Bloodscourge Drop -------------------------------------------------------- + +class BloodscourgeDrop : Actor +{ + States + { + Spawn: + TNT1 A 1; + TNT1 A 1 A_DropWeaponPieces("MWeaponPiece1", "MWeaponPiece2", "MWeaponPiece3"); + Stop; + } +} + +// The Mages's Staff (Bloodscourge) ----------------------------------------- + +class MWeapBloodscourge : MageWeapon +{ + int MStaffCount; + + Default + { + Health 3; + Weapon.SelectionOrder 3100; + Weapon.AmmoUse1 15; + Weapon.AmmoUse2 15; + Weapon.AmmoGive1 20; + Weapon.AmmoGive2 20; + Weapon.KickBack 150; + Weapon.YAdjust 20; + Weapon.AmmoType1 "Mana1"; + Weapon.AmmoType2 "Mana2"; + +WEAPON.PRIMARY_USES_BOTH; + +Inventory.NoAttenPickupSound + Inventory.PickupMessage "$TXT_WEAPON_M4"; + Inventory.PickupSound "WeaponBuild"; + Tag "$TAG_MWEAPBLOODSCOURGE"; + } + + States + { + Spawn: + TNT1 A -1; + Stop; + Select: + MSTF A 1 A_Raise; + Loop; + Deselect: + MSTF A 1 A_Lower; + Loop; + Ready: + MSTF AAAAAABBBBBBCCCCCCDDDDDDEEEEEEFFFFF 1 A_WeaponReady; + Loop; + Fire: + MSTF G 4 Offset (0, 40); + MSTF H 4 Bright Offset (0, 48) A_MStaffAttack; + MSTF H 2 Bright Offset (0, 48) A_MStaffPalette; + MSTF II 2 Offset (0, 48) A_MStaffPalette; + MSTF I 1 Offset (0, 40); + MSTF J 5 Offset (0, 36); + Goto Ready; + } + + //============================================================================ + // + // + // + //============================================================================ + + override Color GetBlend () + { + if (paletteflash & PF_HEXENWEAPONS) + { + if (MStaffCount == 3) + return Color(128, 100, 73, 0); + else if (MStaffCount == 2) + return Color(128, 125, 92, 0); + else if (MStaffCount == 1) + return Color(128, 150, 110, 0); + else + return Color(0, 0, 0, 0); + } + else + { + return Color (MStaffCount * 128 / 3, 151, 110, 0); + } + } + + //============================================================================ + // + // MStaffSpawn + // + //============================================================================ + + private action void MStaffSpawn (double angle, Actor alttarget) + { + FTranslatedLineTarget t; + + Actor mo = SpawnPlayerMissile ("MageStaffFX2", angle, pLineTarget:t); + if (mo) + { + mo.target = self; + if (t.linetarget && !t.unlinked) + mo.tracer = t.linetarget; + else + mo.tracer = alttarget; + } + } + + //============================================================================ + // + // A_MStaffAttack + // + //============================================================================ + + action void A_MStaffAttack() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != NULL) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + + // [RH] Let's try and actually track what the player aimed at + AimLineAttack (angle, PLAYERMISSILERANGE, t, 32.); + if (t.linetarget == NULL) + { + t.linetarget = RoughMonsterSearch(10, true, true); + } + MStaffSpawn (angle, t.linetarget); + MStaffSpawn (angle-5, t.linetarget); + MStaffSpawn (angle+5, t.linetarget); + A_PlaySound ("MageStaffFire", CHAN_WEAPON); + invoker.MStaffCount = 3; + } + + //============================================================================ + // + // A_MStaffPalette + // + //============================================================================ + + action void A_MStaffPalette() + { + if (invoker.MStaffCount > 0) invoker.MStaffCount--; + } +} + + +// Mage Staff FX2 (Bloodscourge) -------------------------------------------- + +class MageStaffFX2 : Actor +{ + Default + { + Speed 17; + Height 8; + Damage 4; + DamageType "Fire"; + Projectile; + +SEEKERMISSILE + +SCREENSEEKER + +EXTREMEDEATH + DeathSound "MageStaffExplode"; + Obituary "$OB_MPMWEAPBLOODSCOURGE"; + } + + + States + { + Spawn: + MSP2 ABCD 2 Bright A_MStaffTrack; + Loop; + Death: + MSP2 E 4 Bright A_SetTranslucent(1,1); + MSP2 F 5 Bright A_Explode (80, 192, 0); + MSP2 GH 5 Bright; + MSP2 I 4 Bright; + Stop; + } + + //============================================================================ + // + // + // + //============================================================================ + + override int SpecialMissileHit (Actor victim) + { + if (victim != target && !victim.player && !victim.bBoss) + { + victim.DamageMobj (self, target, 10, 'Fire'); + return 1; // Keep going + } + return -1; + } + + override bool SpecialBlastHandling (Actor source, double strength) + { + // Reflect to originator + tracer = target; + target = source; + return true; + } + + //============================================================================ + // + // A_MStaffTrack + // + //============================================================================ + + void A_MStaffTrack() + { + if (tracer == null && random[MStaffTrack]() < 50) + { + tracer = RoughMonsterSearch (10, true); + } + A_SeekerMissile(2, 10); + } +} diff --git a/wadsrc/static/zscript/hexen/magewand.txt b/wadsrc/static/zscript/hexen/magewand.txt new file mode 100644 index 0000000000..3feb96ae16 --- /dev/null +++ b/wadsrc/static/zscript/hexen/magewand.txt @@ -0,0 +1,81 @@ + +// The Mage's Wand ---------------------------------------------------------- + +class MWeapWand : MageWeapon +{ + Default + { + Weapon.SelectionOrder 3600; + Weapon.KickBack 0; + Weapon.YAdjust 9; + Tag "$TAG_MWEAPWAND"; + } + States + { + Select: + MWND A 1 A_Raise; + Loop; + Deselect: + MWND A 1 A_Lower; + Loop; + Ready: + MWND A 1 A_WeaponReady; + Loop; + Fire: + MWND A 6; + MWND B 6 Bright Offset (0, 48) A_FireCustomMissile ("MageWandMissile"); + MWND A 3 Offset (0, 40); + MWND A 3 Offset (0, 36) A_ReFire; + Goto Ready; + } +} + +// Wand Smoke --------------------------------------------------------------- + +class MageWandSmoke : Actor +{ + Default + { + +NOBLOCKMAP +NOGRAVITY +SHADOW + +NOTELEPORT +CANNOTPUSH +NODAMAGETHRUST + RenderStyle "Translucent"; + Alpha 0.6; + } + States + { + Spawn: + MWND CDCD 4; + Stop; + } +} + +// Wand Missile ------------------------------------------------------------- + +class MageWandMissile : FastProjectile +{ + Default + { + Speed 184; + Radius 12; + Height 8; + Damage 2; + +RIPPER +CANNOTPUSH +NODAMAGETHRUST + +SPAWNSOUNDSOURCE + MissileType "MageWandSmoke"; + SeeSound "MageWandFire"; + Obituary "$OB_MPMWEAPWAND"; + } + States + { + Spawn: + MWND CD 4 Bright; + Loop; + Death: + MWND E 4 Bright; + MWND F 3 Bright; + MWND G 4 Bright; + MWND H 3 Bright; + MWND I 4 Bright; + Stop; + } +} diff --git a/wadsrc/static/zscript/hexen/mana.txt b/wadsrc/static/zscript/hexen/mana.txt new file mode 100644 index 0000000000..0a43a21ddd --- /dev/null +++ b/wadsrc/static/zscript/hexen/mana.txt @@ -0,0 +1,99 @@ +// Blue mana ---------------------------------------------------------------- + +class Mana1 : Ammo +{ + Default + { + Inventory.Amount 15; + Inventory.MaxAmount 200; + Ammo.BackpackAmount 15; + Ammo.BackpackMaxAmount 200; + Radius 8; + Height 8; + +FLOATBOB + Inventory.Icon "MAN1I0"; + Inventory.PickupMessage "$TXT_MANA_1"; + } + States + { + Spawn: + MAN1 ABCDEFGHI 4 Bright; + Loop; + } +} + +// Green mana --------------------------------------------------------------- + +class Mana2 : Ammo +{ + Default + { + Inventory.Amount 15; + Inventory.MaxAmount 200; + Ammo.BackpackAmount 15; + Ammo.BackpackMaxAmount 200; + Radius 8; + Height 8; + +FLOATBOB + Inventory.Icon "MAN2G0"; + Inventory.PickupMessage "$TXT_MANA_2"; + } + States + { + Spawn: + MAN2 ABCDEFGHIJKLMNOP 4 Bright; + Loop; + } +} + +// Combined mana ------------------------------------------------------------ + +class Mana3 : CustomInventory +{ + Default + { + Radius 8; + Height 8; + +FLOATBOB + Inventory.PickupMessage "$TXT_MANA_BOTH"; + } + States + { + Spawn: + MAN3 ABCDEFGHIJKLMNOP 4 Bright; + Loop; + Pickup: + TNT1 A 0 A_GiveInventory("Mana1", 20); + TNT1 A 0 A_GiveInventory("Mana2", 20); + Stop; + } +} + +// Boost Mana Artifact Krater of Might ------------------------------------ + +class ArtiBoostMana : CustomInventory +{ + Default + { + +FLOATBOB + +COUNTITEM + +INVENTORY.INVBAR + +INVENTORY.FANCYPICKUPSOUND + Inventory.PickupFlash "PickupFlash"; + Inventory.DefMaxAmount; + Inventory.Icon "ARTIBMAN"; + Inventory.PickupSound "misc/p_pkup"; + Inventory.PickupMessage "$TXT_ARTIBOOSTMANA"; + Tag "$TAG_ARTIBOOSTMANA"; + } + States + { + Spawn: + BMAN A -1; + Stop; + Use: + TNT1 A 0 A_GiveInventory("Mana1", 200); + TNT1 A 0 A_GiveInventory("Mana2", 200); + Stop; + } +} diff --git a/wadsrc/static/zscript/hexen/pig.txt b/wadsrc/static/zscript/hexen/pig.txt new file mode 100644 index 0000000000..9f62e661ea --- /dev/null +++ b/wadsrc/static/zscript/hexen/pig.txt @@ -0,0 +1,241 @@ + + +// Snout puff --------------------------------------------------------------- + +class SnoutPuff : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + Renderstyle "Translucent"; + Alpha 0.6; + } + + States + { + Spawn: + FHFX STUVW 4; + Stop; + } +} + + +// Snout -------------------------------------------------------------------- + +class Snout : Weapon +{ + Default + { + Weapon.SelectionOrder 10000; + +WEAPON.DONTBOB + +WEAPON.MELEEWEAPON + Weapon.Kickback 150; + Weapon.YAdjust 10; + } + + States + { + Ready: + WPIG A 1 A_WeaponReady; + Loop; + Deselect: + WPIG A 1 A_Lower; + Loop; + Select: + WPIG A 1 A_Raise; + Fire: + WPIG A 4 A_SnoutAttack; + WPIG B 8 A_SnoutAttack; + Goto Ready; + Grunt: + WPIG B 8; + Goto Ready; + } + + //============================================================================ + // + // A_SnoutAttack + // + //============================================================================ + + action void A_SnoutAttack () + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + int damage = random[SnoutAttack](3, 6); + double ang = angle; + double slope = AimLineAttack(ang, MELEERANGE); + Actor puff = LineAttack(ang, MELEERANGE, slope, damage, 'Melee', "SnoutPuff", true, t); + A_PlaySound("PigActive", CHAN_VOICE); + if(t.linetarget) + { + AdjustPlayerAngle(t); + if(puff != null) + { // Bit something + A_PlaySound("PigAttack", CHAN_VOICE); + } + } + } + +} + + +// Pig player --------------------------------------------------------------- + +class PigPlayer : PlayerPawn +{ + Default + { + Health 30; + ReactionTime 0; + PainChance 255; + Radius 16; + Height 24; + Speed 1; + +WINDTHRUST + +NOSKIN + -PICKUP + PainSound "PigPain"; + DeathSound "PigDeath"; + Player.JumpZ 6; + Player.Viewheight 28; + Player.ForwardMove 0.96, 0.98; + Player.SideMove 0.95833333, 0.975; + Player.SpawnClass "Pig"; + Player.SoundClass "Pig"; + Player.DisplayName "Pig"; + Player.MorphWeapon "Snout"; + } + + States + { + Spawn: + PIGY A -1; + Stop; + See: + PIGY ABCD 3; + Loop; + Pain: + PIGY D 4 A_PigPain; + Goto Spawn; + Melee: + Missile: + PIGY A 12; + Goto Spawn; + Death: + PIGY E 4 A_Scream; + PIGY F 3 A_NoBlocking; + PIGY G 4; + PIGY H 3; + PIGY IJK 4; + PIGY L -1; + Stop; + Ice: + PIGY M 5 A_FreezeDeath; + PIGY M 1 A_FreezeDeathChunks; + Wait; + } + + + override void MorphPlayerThink () + { + if (player.morphTics & 15) + { + return; + } + if(Vel.X == 0 && Vel.Y == 0 && random[PigPlayerThink]() < 64) + { // Snout sniff + if (player.ReadyWeapon != null) + { + player.SetPsprite(PSP_WEAPON, player.ReadyWeapon.FindState('Grunt')); + } + A_PlaySound ("PigActive1", CHAN_VOICE); // snort + return; + } + if (random[PigPlayerThink]() < 48) + { + A_PlaySound ("PigActive", CHAN_VOICE); // snort + } + } + + +} + + + +// Pig (non-player) --------------------------------------------------------- + +class Pig : MorphedMonster +{ + Default + { + Health 25; + Painchance 128; + Speed 10; + Radius 12; + Height 22; + Mass 60; + Monster; + -COUNTKILL + +WINDTHRUST + +DONTMORPH + SeeSound "PigActive1"; + PainSound "PigPain"; + DeathSound "PigDeath"; + ActiveSound "PigActive1"; + } + + States + { + Spawn: + PIGY B 10 A_Look; + Loop; + See: + PIGY ABCD 3 A_Chase; + Loop; + Pain: + PIGY D 4 A_PigPain; + Goto See; + Melee: + PIGY A 5 A_FaceTarget; + PIGY A 10 A_CustomMeleeAttack(random[PigAttack](2,3), "PigAttack"); + Goto See; + Death: + PIGY E 4 A_Scream; + PIGY F 3 A_NoBlocking; + PIGY G 4 A_QueueCorpse; + PIGY H 3; + PIGY IJK 4; + PIGY L -1; + Stop; + Ice: + PIGY M 5 A_FreezeDeath; + PIGY M 1 A_FreezeDeathChunks; + Wait; + } +} + + +extend class Actor +{ + //============================================================================ + // + // A_PigPain + // + //============================================================================ + + void A_PigPain () + { + A_Pain(); + if (pos.z <= floorz) + { + Vel.Z = 3.5; + } + } +} \ No newline at end of file diff --git a/wadsrc/static/zscript/hexen/puzzleitems.txt b/wadsrc/static/zscript/hexen/puzzleitems.txt new file mode 100644 index 0000000000..f502664d75 --- /dev/null +++ b/wadsrc/static/zscript/hexen/puzzleitems.txt @@ -0,0 +1,338 @@ + +// Yorick's Skull ----------------------------------------------------------- + +class PuzzSkull : PuzzleItem +{ + Default + { + PuzzleItem.Number 0; + Inventory.Icon "ARTISKLL"; + Inventory.PickupMessage "$TXT_ARTIPUZZSKULL"; + Tag "$TAG_ARTIPUZZSKULL"; + } + States + { + Spawn: + ASKU A -1; + Stop; + } +} + + +// Heart of D'Sparil -------------------------------------------------------- + +class PuzzGemBig : PuzzleItem +{ + Default + { + PuzzleItem.Number 1; + Inventory.Icon "ARTIBGEM"; + Inventory.PickupMessage "$TXT_ARTIPUZZGEMBIG"; + Tag "$TAG_ARTIPUZZGEMBIG"; + } + States + { + Spawn: + ABGM A -1; + Stop; + } +} + +// Red Gem (Ruby Planet) ---------------------------------------------------- + +class PuzzGemRed : PuzzleItem +{ + Default + { + PuzzleItem.Number 2; + Inventory.Icon "ARTIGEMR"; + Inventory.PickupMessage "$TXT_ARTIPUZZGEMRED"; + Tag "$TAG_ARTIPUZZGEMRED"; + } + States + { + Spawn: + AGMR A -1; + Stop; + } +} + + +// Green Gem 1 (Emerald Planet) --------------------------------------------- + +class PuzzGemGreen1 : PuzzleItem +{ + Default + { + PuzzleItem.Number 3; + Inventory.Icon "ARTIGEMG"; + Inventory.PickupMessage "$TXT_ARTIPUZZGEMGREEN1"; + Tag "$TAG_ARTIPUZZGEMGREEN1"; + } + States + { + Spawn: + AGMG A -1; + Stop; + } +} + + +// Green Gem 2 (Emerald Planet) --------------------------------------------- + +class PuzzGemGreen2 : PuzzleItem +{ + Default + { + PuzzleItem.Number 4; + Inventory.Icon "ARTIGMG2"; + Inventory.PickupMessage "$TXT_ARTIPUZZGEMGREEN2"; + Tag "$TAG_ARTIPUZZGEMGREEN2"; + } + States + { + Spawn: + AGG2 A -1; + Stop; + } +} + + +// Blue Gem 1 (Sapphire Planet) --------------------------------------------- + +class PuzzGemBlue1 : PuzzleItem +{ + Default + { + PuzzleItem.Number 5; + Inventory.Icon "ARTIGEMB"; + Inventory.PickupMessage "$TXT_ARTIPUZZGEMBLUE1"; + Tag "$TAG_ARTIPUZZGEMBLUE1"; + } + States + { + Spawn: + AGMB A -1; + Stop; + } +} + + +// Blue Gem 2 (Sapphire Planet) --------------------------------------------- + +class PuzzGemBlue2 : PuzzleItem +{ + Default + { + PuzzleItem.Number 6; + Inventory.Icon "ARTIGMB2"; + Inventory.PickupMessage "$TXT_ARTIPUZZGEMBLUE2"; + Tag "$TAG_ARTIPUZZGEMBLUE2"; + } + States + { + Spawn: + AGB2 A -1; + Stop; + } +} + + +// Book 1 (Daemon Codex) ---------------------------------------------------- + +class PuzzBook1 : PuzzleItem +{ + Default + { + PuzzleItem.Number 7; + Inventory.Icon "ARTIBOK1"; + Inventory.PickupMessage "$TXT_ARTIPUZZBOOK1"; + Tag "$TAG_ARTIPUZZBOOK1"; + } + States + { + Spawn: + ABK1 A -1; + Stop; + } +} + + +// Book 2 (Liber Oscura) ---------------------------------------------------- + +class PuzzBook2 : PuzzleItem +{ + Default + { + PuzzleItem.Number 8; + Inventory.Icon "ARTIBOK2"; + Inventory.PickupMessage "$TXT_ARTIPUZZBOOK2"; + Tag "$TAG_ARTIPUZZBOOK2"; + } + States + { + Spawn: + ABK2 A -1; + Stop; + } +} + + +// Flame Mask --------------------------------------------------------------- + + +class PuzzFlameMask : PuzzleItem +{ + Default + { + PuzzleItem.Number 9; + Inventory.Icon "ARTISKL2"; + Inventory.PickupMessage "$TXT_ARTIPUZZSKULL2"; + Tag "$TAG_ARTIPUZZSKULL2"; + } + States + { + Spawn: + ASK2 A -1; + Stop; + } +} + +// Fighter Weapon (Glaive Seal) --------------------------------------------- + +class PuzzFWeapon : PuzzleItem +{ + Default + { + PuzzleItem.Number 10; + Inventory.Icon "ARTIFWEP"; + Inventory.PickupMessage "$TXT_ARTIPUZZFWEAPON"; + Tag "$TAG_ARTIPUZZFWEAPON"; + } + States + { + Spawn: + AFWP A -1; + Stop; + } +} + + +// Cleric Weapon (Holy Relic) ----------------------------------------------- + +class PuzzCWeapon : PuzzleItem +{ + Default + { + PuzzleItem.Number 11; + Inventory.Icon "ARTICWEP"; + Inventory.PickupMessage "$TXT_ARTIPUZZCWEAPON"; + Tag "$TAG_ARTIPUZZCWEAPON"; + } + States + { + Spawn: + ACWP A -1; + Stop; + } +} + + +// Mage Weapon (Sigil of the Magus) ----------------------------------------- + +class PuzzMWeapon : PuzzleItem +{ + Default + { + PuzzleItem.Number 12; + Inventory.Icon "ARTIMWEP"; + Inventory.PickupMessage "$TXT_ARTIPUZZMWEAPON"; + Tag "$TAG_ARTIPUZZMWEAPON"; + } + States + { + Spawn: + AMWP A -1; + Stop; + } +} + +// Clock Gear 1 ------------------------------------------------------------- + +class PuzzGear1 : PuzzleItem +{ + Default + { + PuzzleItem.Number 13; + Inventory.Icon "ARTIGEAR"; + Inventory.PickupMessage "$TXT_ARTIPUZZGEAR"; + Tag "$TAG_ARTIPUZZGEAR1"; + } + States + { + Spawn: + AGER ABCDEFGH 4 Bright; + Loop; + } +} + + +// Clock Gear 2 ------------------------------------------------------------- + +class PuzzGear2 : PuzzleItem +{ + Default + { + PuzzleItem.Number 14; + Inventory.Icon "ARTIGER2"; + Inventory.PickupMessage "$TXT_ARTIPUZZGEAR"; + Tag "$TAG_ARTIPUZZGEAR2"; + } + States + { + Spawn: + AGR2 ABCDEFGH 4 Bright; + Loop; + } +} + + +// Clock Gear 3 ------------------------------------------------------------- + +class PuzzGear3 : PuzzleItem +{ + Default + { + PuzzleItem.Number 15; + Inventory.Icon "ARTIGER3"; + Inventory.PickupMessage "$TXT_ARTIPUZZGEAR"; + Tag "$TAG_ARTIPUZZGEAR3"; + } + States + { + Spawn: + AGR3 ABCDEFGH 4 Bright; + Loop; + } +} + + +// Clock Gear 4 ------------------------------------------------------------- + +class PuzzGear4 : PuzzleItem +{ + Default + { + PuzzleItem.Number 16; + Inventory.Icon "ARTIGER4"; + Inventory.PickupMessage "$TXT_ARTIPUZZGEAR"; + Tag "$TAG_ARTIPUZZGEAR4"; + } + States + { + Spawn: + AGR4 ABCDEFGH 4 Bright; + Loop; + } +} + diff --git a/wadsrc/static/zscript/hexen/scriptprojectiles.txt b/wadsrc/static/zscript/hexen/scriptprojectiles.txt new file mode 100644 index 0000000000..5bf3f254ff --- /dev/null +++ b/wadsrc/static/zscript/hexen/scriptprojectiles.txt @@ -0,0 +1,141 @@ +// Fire Ball ---------------------------------------------------------------- + +class FireBall : Actor +{ + Default + { + Speed 2; + Radius 8; + Height 8; + Damage 4; + DamageType "Fire"; + +NOBLOCKMAP +NOGRAVITY +DROPOFF +MISSILE + +NOTELEPORT + RenderStyle "Add"; + DeathSound "Fireball"; + } + States + { + Spawn: + FBL1 AB 4 Bright; + Loop; + Death: + XPL1 ABCDEF 4 Bright; + Stop; + } +} + +// Arrow -------------------------------------------------------------------- + +class Arrow : Actor +{ + Default + { + Speed 6; + Radius 8; + Height 4; + Damage 4; + +NOBLOCKMAP +NOGRAVITY +DROPOFF +MISSILE + +NOTELEPORT + } + States + { + Spawn: + ARRW A -1; + Stop; + Death: + ARRW A 1; + Stop; + } +} + +// Dart --------------------------------------------------------------------- + +class Dart : Actor +{ + Default + { + Speed 6; + Radius 8; + Height 4; + Damage 2; + +NOBLOCKMAP +NOGRAVITY +DROPOFF +MISSILE + +NOTELEPORT + } + States + { + Spawn: + DART A -1; + Stop; + Death: + DART A 1; + Stop; + } +} + +// Poison Dart -------------------------------------------------------------- + +class PoisonDart : Dart +{ + Default + { + PoisonDamage 20; + } +} + +// Ripper Ball -------------------------------------------------------------- + +class RipperBall : Actor +{ + Default + { + Speed 6; + Radius 8; + Damage 2; + +NOBLOCKMAP +NOGRAVITY +DROPOFF +MISSILE + +NOTELEPORT +RIPPER + } + States + { + Spawn: + RIPP ABC 3; + Loop; + Death: + CFCF Q 4 Bright; + CFCF R 3 Bright; + CFCF S 4 Bright; + CFCF T 3 Bright; + CFCF U 4 Bright; + CFCF V 3 Bright; + CFCF W 4 Bright; + CFCF X 3 Bright; + CFCF Y 4 Bright; + CFCF Z 3 Bright; + Stop; + } +} + +// Projectile Blade --------------------------------------------------------- + +class ProjectileBlade : Actor +{ + Default + { + Speed 6; + Radius 6; + Height 6; + Damage 3; + +NOBLOCKMAP +NOGRAVITY +DROPOFF +MISSILE + +NOTELEPORT + } + States + { + Spawn: + BLAD A -1; + Stop; + Death: + BLAD A 1; + Stop; + } +} + diff --git a/wadsrc/static/zscript/hexen/serpent.txt b/wadsrc/static/zscript/hexen/serpent.txt new file mode 100644 index 0000000000..6eaafcfd1f --- /dev/null +++ b/wadsrc/static/zscript/hexen/serpent.txt @@ -0,0 +1,476 @@ + +// Serpent ------------------------------------------------------------------ + +class Serpent : Actor +{ + Default + { + Health 90; + PainChance 96; + Speed 12; + Radius 32; + Height 70; + Mass 0x7fffffff; + Monster; + -SHOOTABLE + +NOBLOOD + +CANTLEAVEFLOORPIC +NONSHOOTABLE + +STAYMORPHED +DONTBLAST +NOTELEOTHER + +INVISIBLE + SeeSound "SerpentSight"; + AttackSound "SerpentAttack"; + PainSound "SerpentPain"; + DeathSound "SerpentDeath"; + HitObituary "$OB_SERPENTHIT"; + } + + States + { + Spawn: + SSPT H 10 A_Look; + Loop; + See: + SSPT HH 1 A_Chase("Melee", null, CHF_NIGHTMAREFAST|CHF_NOPLAYACTIVE); + SSPT H 2 A_SerpentHumpDecide; + Loop; + Pain: + SSPT L 5; + SSPT L 5 A_Pain; + Dive: + SSDV ABC 4; + SSDV D 4 A_UnSetShootable; + SSDV E 3 A_PlaySound("SerpentActive", CHAN_BODY); + SSDV F 3; + SSDV GH 4; + SSDV I 3; + SSDV J 3 A_SerpentHide; + Goto See; + Melee: + SSPT A 1 A_UnHideThing; + SSPT A 1 A_PlaySound("SerpentBirth", CHAN_BODY); + SSPT B 3 A_SetShootable; + SSPT C 3; + SSPT D 4 A_SerpentCheckForAttack; + Goto Dive; + Death: + SSPT O 4; + SSPT P 4 A_Scream; + SSPT Q 4 A_NoBlocking; + SSPT RSTUVWXYZ 4; + Stop; + XDeath: + SSXD A 4; + SSXD B 4 A_SpawnItemEx("SerpentHead", 0, 0, 45); + SSXD C 4 A_NoBlocking; + SSXD DE 4; + SSXD FG 3; + SSXD H 3 A_SerpentSpawnGibs; + Stop; + Ice: + SSPT [ 5 A_FreezeDeath; + SSPT [ 1 A_FreezeDeathChunks; + Wait; + Walk: + SSPT IJI 5 A_Chase("Attack", null, CHF_NIGHTMAREFAST); + SSPT J 5 A_SerpentCheckForAttack; + Goto Dive; + Hump: + SSPT H 3 A_SerpentUnHide; + SSPT EFGEF 3 A_SerpentRaiseHump; + SSPT GEF 3; + SSPT GEFGE 3 A_SerpentLowerHump; + SSPT F 3 A_SerpentHide; + Goto See; + Attack: + SSPT K 6 A_FaceTarget; + SSPT L 5 A_SerpentChooseAttack; + Goto MeleeAttack; + MeleeAttack: + SSPT N 5 A_SerpentMeleeAttack; + Goto Dive; + } + + //============================================================================ + // + // A_SerpentUnHide + // + //============================================================================ + + void A_SerpentUnHide() + { + bInvisible = false; + Floorclip = 24; + } + + //============================================================================ + // + // A_SerpentHide + // + //============================================================================ + + void A_SerpentHide() + { + bInvisible = true; + Floorclip = 0; + } + + //============================================================================ + // + // A_SerpentRaiseHump + // + // Raises the hump above the surface by raising the floorclip level + //============================================================================ + + void A_SerpentRaiseHump() + { + Floorclip -= 4; + } + + //============================================================================ + // + // A_SerpentLowerHump + // + //============================================================================ + + void A_SerpentLowerHump() + { + Floorclip += 4; + } + + //============================================================================ + // + // A_SerpentHumpDecide + // + // Decided whether to hump up, or if the mobj is a serpent leader, + // to missile attack + //============================================================================ + + void A_SerpentHumpDecide() + { + if (MissileState != NULL) + { + if (random[SerpentHump]() > 30) + { + return; + } + else if (random[SerpentHump]() < 40) + { // Missile attack + SetState (MeleeState); + return; + } + } + else if (random[SerpentHump]() > 3) + { + return; + } + if (!CheckMeleeRange ()) + { // The hump shouldn't occur when within melee range + if (MissileState != NULL && random[SerpentHump]() < 128) + { + SetState (MeleeState); + } + else + { + SetStateLabel("Hump"); + A_PlaySound ("SerpentActive", CHAN_BODY); + } + } + } + + //============================================================================ + // + // A_SerpentCheckForAttack + // + //============================================================================ + + void A_SerpentCheckForAttack() + { + if (!target) + { + return; + } + if (MissileState != NULL) + { + if (!CheckMeleeRange ()) + { + SetStateLabel ("Attack"); + return; + } + } + if (CheckMeleeRange2 ()) + { + SetStateLabel ("Walk"); + } + else if (CheckMeleeRange ()) + { + if (random[SerpentAttack]() < 32) + { + SetStateLabel ("Walk"); + } + else + { + SetStateLabel ("Attack"); + } + } + } + + //============================================================================ + // + // A_SerpentChooseAttack + // + //============================================================================ + + void A_SerpentChooseAttack() + { + if (!target || CheckMeleeRange()) + { + return; + } + if (MissileState != NULL) + { + SetState (MissileState); + } + } + + //============================================================================ + // + // A_SerpentMeleeAttack + // + //============================================================================ + + void A_SerpentMeleeAttack() + { + if (!target) + { + return; + } + if (CheckMeleeRange ()) + { + int damage = random[SerpentAttack](1, 8) * 5; + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + A_PlaySound ("SerpentMeleeHit", CHAN_BODY); + } + if (random[SerpentAttack]() < 96) + { + A_SerpentCheckForAttack(); + } + } + + //============================================================================ + // + // A_SerpentSpawnGibs + // + //============================================================================ + + void A_SerpentSpawnGibs() + { + static const class GibTypes[] = + { + "SerpentGib3", + "SerpentGib2", + "SerpentGib1" + }; + + for (int i = 2; i >= 0; --i) + { + double x = (random[SerpentGibs]() - 128) / 16.; + double y = (random[SerpentGibs]() - 128) / 16.; + + Actor mo = Spawn (GibTypes[i], Vec2OffsetZ(x, y, floorz + 1), ALLOW_REPLACE); + if (mo) + { + mo.Vel.X = (random[SerpentGibs]() - 128) / 1024.f; + mo.Vel.Y = (random[SerpentGibs]() - 128) / 1024.f; + mo.Floorclip = 6; + } + } + } +} + +// Serpent Leader ----------------------------------------------------------- + +class SerpentLeader : Serpent +{ + Default + { + Mass 200; + Obituary "$OB_SERPENT"; + } + States + { + Missile: + SSPT N 5 A_CustomMissile("SerpentFX", 32, 0); + Goto Dive; + } +} + +// Serpent Missile Ball ----------------------------------------------------- + +class SerpentFX : Actor +{ + Default + { + Speed 15; + Radius 8; + Height 10; + Damage 4; + Projectile; + -ACTIVATEIMPACT -ACTIVATEPCROSS + RenderStyle "Add"; + DeathSound "SerpentFXHit"; + } + States + { + Spawn: + SSFX A 0; + SSFX A 3 Bright A_PlaySound("SerpentFXContinuous", CHAN_BODY, 1.0, 1); + SSFX BAB 3 Bright; + Goto Spawn+1; + Death: + SSFX C 4 Bright A_StopSound(CHAN_BODY); + SSFX DEFGH 4 Bright; + Stop; + } +} + +// Serpent Head ------------------------------------------------------------- + +class SerpentHead : Actor +{ + Default + { + Radius 5; + Height 10; + Gravity 0.125; + +NOBLOCKMAP + } + + States + { + Spawn: + SSXD IJKLMNOP 4 A_SerpentHeadCheck; + Loop; + Death: + SSXD S -1; + Loop; + } + + //============================================================================ + // + // A_SerpentHeadCheck + // + //============================================================================ + + void A_SerpentHeadCheck() + { + if (pos.z <= floorz) + { + if (GetFloorTerrain().IsLiquid) + { + HitFloor (); + Destroy(); + } + else + { + SetStateLabel ("NAME_Death"); + } + } + } +} + +// Serpent Gib 1 ------------------------------------------------------------ + +class SerpentGib1 : Actor +{ + Default + { + Radius 3; + Height 3; + +NOBLOCKMAP +NOGRAVITY + } + + States + { + Spawn: + SSXD Q 6; + SSXD Q 6 A_FloatGib; + SSXD QQ 8 A_FloatGib; + SSXD QQ 12 A_FloatGib; + SSXD Q 232 A_DelayGib; + SSXD QQ 12 A_SinkGib; + SSXD QQQ 8 A_SinkGib; + Stop; + } + + //============================================================================ + // + // A_FloatGib + // + //============================================================================ + + void A_FloatGib() + { + Floorclip -= 1; + } + + //============================================================================ + // + // A_SinkGib + // + //============================================================================ + + void A_SinkGib() + { + Floorclip += 1; + } + + //============================================================================ + // + // A_DelayGib + // + //============================================================================ + + void A_DelayGib() + { + tics -= random[DelayGib]() >> 2; + } + + +} + +// Serpent Gib 2 ------------------------------------------------------------ + +class SerpentGib2 : SerpentGib1 +{ + States + { + Spawn: + SSXD R 6; + SSXD R 6 A_FloatGib; + SSXD RR 8 A_FloatGib; + SSXD RR 12 A_FloatGib; + SSXD R 232 A_DelayGib; + SSXD RR 12 A_SinkGib; + SSXD RRR 8 A_SinkGib; + Stop; + } +} + +// Serpent Gib 3 ------------------------------------------------------------ + +class SerpentGib3 : SerpentGib1 +{ + States + { + Spawn: + SSXD T 6; + SSXD T 6 A_FloatGib; + SSXD TT 8 A_FloatGib; + SSXD TT 12 A_FloatGib; + SSXD T 232 A_DelayGib; + SSXD TT 12 A_SinkGib; + SSXD TTT 8 A_SinkGib; + Stop; + } +} diff --git a/wadsrc/static/zscript/hexen/speedboots.txt b/wadsrc/static/zscript/hexen/speedboots.txt new file mode 100644 index 0000000000..e5a0364eca --- /dev/null +++ b/wadsrc/static/zscript/hexen/speedboots.txt @@ -0,0 +1,21 @@ + + +class ArtiSpeedBoots : PowerupGiver +{ + Default + { + +FLOATBOB + +COUNTITEM + Inventory.PickupFlash "PickupFlash"; + Inventory.Icon "ARTISPED"; + Inventory.PickupMessage "$TXT_ARTISPEED"; + Tag "$TAG_ARTISPEED"; + Powerup.Type "PowerSpeed"; + } + States + { + Spawn: + SPED ABCDEFGH 3 Bright; + Loop; + } +} diff --git a/wadsrc/static/zscript/hexen/spike.txt b/wadsrc/static/zscript/hexen/spike.txt new file mode 100644 index 0000000000..248c957264 --- /dev/null +++ b/wadsrc/static/zscript/hexen/spike.txt @@ -0,0 +1,235 @@ + +// Dirt clump (spawned by spike) -------------------------------------------- + +class DirtClump : Actor +{ + Default + { + +NOBLOCKMAP + +NOTELEPORT + } + States + { + Spawn: + TSPK C 20; + Loop; + } +} + +// Spike (thrust floor) ----------------------------------------------------- + +class ThrustFloor : Actor +{ + Default + { + Radius 20; + Height 128; + } + + States + { + ThrustRaising: + TSPK A 2 A_ThrustRaise; + Loop; + BloodThrustRaising: + TSPK B 2 A_ThrustRaise; + Loop; + ThrustLower: + TSPK A 2 A_ThrustLower; + Loop; + BloodThrustLower: + TSPK B 2 A_ThrustLower; + Loop; + ThrustInit1: + TSPK A 3; + TSPK A 4 A_ThrustInitDn; + TSPK A -1; + Loop; + BloodThrustInit1: + TSPK B 3; + TSPK B 4 A_ThrustInitDn; + TSPK B -1; + Loop; + ThrustInit2: + TSPK A 3; + TSPK A 4 A_ThrustInitUp; + TSPK A 10; + Loop; + BloodThrustInit2: + TSPK B 3; + TSPK B 4 A_ThrustInitUp; + TSPK B 10; + Loop; + ThrustRaise: + TSPK A 8 A_ThrustRaise; + TSPK A 6 A_ThrustRaise; + TSPK A 4 A_ThrustRaise; + TSPK A 3 A_SetSolid; + TSPK A 2 A_ThrustImpale; + Loop; + BloodThrustRaise: + TSPK B 8 A_ThrustRaise; + TSPK B 6 A_ThrustRaise; + TSPK B 4 A_ThrustRaise; + TSPK B 3 A_SetSolid; + TSPK B 2 A_ThrustImpale; + Loop; + } + + override void Activate (Actor activator) + { + if (args[0] == 0) + { + A_PlaySound ("ThrustSpikeLower", CHAN_BODY); + bInvisible = false; + if (args[1]) + SetStateLabel("BloodThrustRaise"); + else + SetStateLabel("ThrustRaise"); + } + } + + override void Deactivate (Actor activator) + { + if (args[0] == 1) + { + A_PlaySound ("ThrustSpikeRaise", CHAN_BODY); + if (args[1]) + SetStateLabel("BloodThrustLower"); + else + SetStateLabel("ThrustLower"); + } + } + + //=========================================================================== + // + // Thrust floor stuff + // + // Thrust Spike Variables + // master pointer to dirt clump actor + // special2 speed of raise + // args[0] 0 = lowered, 1 = raised + // args[1] 0 = normal, 1 = bloody + //=========================================================================== + + void A_ThrustInitUp() + { + special2 = 5; // Raise speed + args[0] = 1; // Mark as up + Floorclip = 0; + bSolid = true; + bNoTeleport = true; + bFloorClip = true; + special1 = 0; + } + + void A_ThrustInitDn() + { + special2 = 5; // Raise speed + args[0] = 0; // Mark as down + Floorclip = Default.Height; + bSolid = false; + bNoTeleport = true; + bFloorClip = true; + bInvisible = true; + master = Spawn("DirtClump", Pos, ALLOW_REPLACE); + } + + + void A_ThrustRaise() + { + if (RaiseMobj (special2)) + { // Reached it's target height + args[0] = 1; + if (args[1]) + SetStateLabel ("BloodThrustInit2", true); + else + SetStateLabel ("ThrustInit2", true); + } + + // Lose the dirt clump + if ((Floorclip < Height) && master) + { + master.Destroy (); + master = null; + } + + // Spawn some dirt + if (random[Thrustraise]()<40) + SpawnDirt (radius); + special2++; // Increase raise speed + } + + void A_ThrustLower() + { + if (SinkMobj (6)) + { + args[0] = 0; + if (args[1]) + SetStateLabel ("BloodThrustInit1", true); + else + SetStateLabel ("ThrustInit1", true); + } + } + + + void A_ThrustImpale() + { + BlockThingsIterator it = BlockThingsIterator.Create(self); + while (it.Next()) + { + double blockdist = radius + it.thing.radius; + if (abs(it.thing.pos.x - it.Position.X) >= blockdist || abs(it.thing.pos.y - it.Position.Y) >= blockdist) + continue; + + // Q: Make this z-aware for everything? It never was before. + if (it.thing.pos.z + it.thing.height < pos.z || it.thing.pos.z > pos.z + height) + { + if (CurSector.PortalGroup != it.thing.CurSector.PortalGroup) + continue; + } + + if (!it.thing.bShootable) + continue; + + if (it.thing == self) + continue; // don't clip against self + + int newdam = it.thing.DamageMobj (self, self, 10001, 'Crush'); + it.thing.TraceBleed (newdam > 0 ? newdam : 10001, null); + args[1] = 1; // Mark thrust thing as bloody + } + } +} + +// Spike up ----------------------------------------------------------------- + +class ThrustFloorUp : ThrustFloor +{ + Default + { + +SOLID + +NOTELEPORT +FLOORCLIP + } + States + { + Spawn: + Goto ThrustInit2; + } +} + +// Spike down --------------------------------------------------------------- + +class ThrustFloorDown : ThrustFloor +{ + Default + { + +NOTELEPORT +FLOORCLIP + +INVISIBLE + } + States + { + Spawn: + Goto ThrustInit1; + } +} diff --git a/wadsrc/static/zscript/hexen/summon.txt b/wadsrc/static/zscript/hexen/summon.txt new file mode 100644 index 0000000000..c9e9b9295e --- /dev/null +++ b/wadsrc/static/zscript/hexen/summon.txt @@ -0,0 +1,133 @@ + +// Dark Servant Artifact ---------------------------------------------------- + +class ArtiDarkServant : Inventory +{ + Default + { + +COUNTITEM + +FLOATBOB + Inventory.RespawnTics 4230; + Inventory.DefMaxAmount; + Inventory.PickupFlash "PickupFlash"; + +INVENTORY.INVBAR + +INVENTORY.FANCYPICKUPSOUND + Inventory.Icon "ARTISUMN"; + Inventory.PickupSound "misc/p_pkup"; + Inventory.PickupMessage "$TXT_ARTISUMMON"; + Tag "$TAG_ARTISUMMON"; + } + States + { + Spawn: + SUMN A 350; + Loop; + } + + //============================================================================ + // + // Activate the summoning artifact + // + //============================================================================ + + override bool Use (bool pickup) + { + Actor mo = Owner.SpawnPlayerMissile ("SummoningDoll"); + if (mo) + { + mo.target = Owner; + mo.tracer = Owner; + mo.Vel.Z = 5; + } + return true; + } + + +} + +// Summoning Doll ----------------------------------------------------------- + +class SummoningDoll : Actor +{ + Default + { + Speed 20; + +NOBLOCKMAP +DROPOFF +MISSILE + +NOTELEPORT + } + + States + { + Spawn: + SUMN A 4; + Loop; + Death: + SUMN AA 4; + SUMN A 4 A_Summon; + Stop; + } + + //============================================================================ + // + // A_Summon + // + //============================================================================ + + void A_Summon() + { + Actor mo = Spawn("MinotaurFriend", pos, ALLOW_REPLACE); + if (mo) + { + if (mo.TestMobjLocation() == false || !tracer) + { // Didn't fit - change back to artifact + mo.Destroy(); + Actor arti = Spawn("ArtiDarkServant", Pos, ALLOW_REPLACE); + if (arti) arti.bDropped = true; + return; + } + + // Careful! The Minotaur might have been replaced + // so only set the time if we got a genuine one. + MinotaurFriend m = MinotaurFriend(mo); + if (m) m.StartTime = level.maptime; + + if (tracer.bCorpse) + { // Master dead + mo.tracer = null; // No master + } + else + { + mo.tracer = tracer; // Pointer to master + Inventory power = Inventory(Spawn("PowerMinotaur")); + power.CallTryPickup(tracer); + mo.SetFriendPlayer(tracer.player); + } + + // Make smoke puff + Spawn("MinotaurSmoke", Pos, ALLOW_REPLACE); + A_PlaySound(mo.ActiveSound, CHAN_VOICE); + } + } + +} + +// Minotaur Smoke ----------------------------------------------------------- + +class MinotaurSmoke : Actor +{ + Default + { + +NOBLOCKMAP +NOGRAVITY + +NOTELEPORT + RenderStyle "Translucent"; + Alpha 0.6; + + } + States + { + Spawn: + MNSM ABCDEFGHIJKLMNOPQ 3; + Stop; + } +} + diff --git a/wadsrc/static/zscript/hexen/teleportother.txt b/wadsrc/static/zscript/hexen/teleportother.txt new file mode 100644 index 0000000000..f7be0ebff7 --- /dev/null +++ b/wadsrc/static/zscript/hexen/teleportother.txt @@ -0,0 +1,250 @@ + +// Teleport Other Artifact -------------------------------------------------- + +class ArtiTeleportOther : Inventory +{ + Default + { + +COUNTITEM + +FLOATBOB + +INVENTORY.INVBAR + +INVENTORY.FANCYPICKUPSOUND + Inventory.PickupFlash "PickupFlash"; + Inventory.DefMaxAmount; + Inventory.Icon "ARTITELO"; + Inventory.PickupSound "misc/p_pkup"; + Inventory.PickupMessage "$TXT_ARTITELEPORTOTHER"; + Tag "$TAG_ARTITELEPORTOTHER"; + } + States + { + Spawn: + TELO ABCD 5; + Loop; + } + + //=========================================================================== + // + // Activate Teleport Other + // + //=========================================================================== + + override bool Use (bool pickup) + { + Owner.SpawnPlayerMissile ("TelOtherFX1"); + return true; + } + + +} + + +// Teleport Other FX -------------------------------------------------------- + +class TelOtherFX1 : Actor +{ + const TELEPORT_LIFE = 1; + + Default + { + Damage 10001; + Projectile; + -ACTIVATEIMPACT + -ACTIVATEPCROSS + +BLOODLESSIMPACT + Radius 16; + Height 16; + Speed 20; + } + + + States + { + Spawn: + TRNG E 5 Bright; + TRNG D 4 Bright; + TRNG C 3 Bright A_TeloSpawnC; + TRNG B 3 Bright A_TeloSpawnB; + TRNG A 3 Bright A_TeloSpawnA; + TRNG B 3 Bright A_TeloSpawnB; + TRNG C 3 Bright A_TeloSpawnC; + TRNG D 3 Bright A_TeloSpawnD; + Goto Spawn+2; + Death: + TRNG E 3 Bright; + Stop; + } + + private void TeloSpawn (class type) + { + Actor fx = Spawn (type, pos, ALLOW_REPLACE); + if (fx) + { + fx.special1 = TELEPORT_LIFE; // Lifetime countdown + fx.angle = angle; + fx.target = target; + fx.Vel = Vel / 2; + } + } + + void A_TeloSpawnA() + { + TeloSpawn ("TelOtherFX2"); + } + + void A_TeloSpawnB() + { + TeloSpawn ("TelOtherFX3"); + } + + void A_TeloSpawnC() + { + TeloSpawn ("TelOtherFX4"); + } + + void A_TeloSpawnD() + { + TeloSpawn ("TelOtherFX5"); + } + + void A_CheckTeleRing () + { + if (self.special1-- <= 0) + { + self.SetStateLabel("Death"); + } + } + + //=========================================================================== + // + // Perform Teleport Other + // + //=========================================================================== + + override int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + if ((target.bIsMonster || target.player != NULL) && + !target.bBoss && !target.bNoTeleOther) + { + if (target.player) + { + if (deathmatch) + P_TeleportToDeathmatchStarts (target); + else + P_TeleportToPlayerStarts (target); + } + else + { + // If death action, run it upon teleport + if (target.bIsMonster && target.special) + { + target.RemoveFromHash (); + Actor caller = level.ActOwnSpecial? target : self.target; + caller.A_CallSpecial(target.special, 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 + // + //=========================================================================== + + private static void P_TeleportToPlayerStarts (Actor victim) + { + Vector3 dest; + double destAngle; + + [dest, destAngle] = G_PickPlayerStart(0, PPS_FORCERANDOM | PPS_NOBLOCKINGCHECK); + dest.Z = ONFLOORZ; + victim.Teleport ((dest.xy, ONFLOORZ), destangle, TELF_SOURCEFOG | TELF_DESTFOG); + } + + //=========================================================================== + // + // P_TeleportToDeathmatchStarts + // + //=========================================================================== + + private void P_TeleportToDeathmatchStarts (Actor victim) + { + Vector3 dest; + double destAngle; + + [dest, destAngle] = G_PickDeathmatchStart(); + if (destAngle < 65536) victim.Teleport((dest.xy, ONFLOORZ), destangle, TELF_SOURCEFOG | TELF_DESTFOG); + else P_TeleportToPlayerStarts(victim); + } + +} + + +class TelOtherFX2 : TelOtherFX1 +{ + Default + { + Speed 16; + } + States + { + Spawn: + TRNG BCDCB 4 Bright; + TRNG A 4 Bright A_CheckTeleRing; + Loop; + } +} + +class TelOtherFX3 : TelOtherFX1 +{ + Default + { + Speed 16; + } + States + { + Spawn: + TRNG CDCBA 4 Bright; + TRNG B 4 Bright A_CheckTeleRing; + Loop; + } +} + +class TelOtherFX4 : TelOtherFX1 +{ + Default + { + Speed 16; + } + States + { + Spawn: + TRNG DCBAB 4 Bright; + TRNG C 4 Bright A_CheckTeleRing; + Loop; + } + +} + +class TelOtherFX5 : TelOtherFX1 +{ + Default + { + Speed 16; + } + States + { + Spawn: + TRNG CBABC 4 Bright; + TRNG D 4 Bright A_CheckTeleRing; + Loop; + } +} + + diff --git a/wadsrc/static/zscript/hexen/wraith.txt b/wadsrc/static/zscript/hexen/wraith.txt new file mode 100644 index 0000000000..42a81ae6c5 --- /dev/null +++ b/wadsrc/static/zscript/hexen/wraith.txt @@ -0,0 +1,443 @@ + +// Wraith ------------------------------------------------------------------- + +class Wraith : Actor +{ + Default + { + Health 150; + PainChance 25; + Speed 11; + Height 55; + Mass 75; + Damage 10; + Monster; + +NOGRAVITY +DROPOFF +FLOAT + +FLOORCLIP +TELESTOMP + SeeSound "WraithSight"; + AttackSound "WraithAttack"; + PainSound "WraithPain"; + DeathSound "WraithDeath"; + ActiveSound "WraithActive"; + HitObituary "$OB_WRAITHHIT"; + Obituary "$OB_WRAITH"; + } + + States + { + Spawn: + WRTH A 10; + WRTH B 5 A_WraithInit; + Goto Look; + Look: + WRTH AB 15 A_Look; + Loop; + See: + WRTH ABCD 4 A_WraithChase; + Loop; + Pain: + WRTH A 2; + WRTH H 6 A_Pain; + Goto See; + Melee: + WRTH E 6 A_FaceTarget; + WRTH F 6 A_WraithFX3; + WRTH G 6 A_WraithMelee; + Goto See; + Missile: + WRTH E 6 A_FaceTarget; + WRTH F 6; + WRTH G 6 A_CustomMissile("WraithFX1"); + Goto See; + Death: + WRTH I 4; + WRTH J 4 A_Scream; + WRTH KL 4; + WRTH M 4 A_NoBlocking; + WRTH N 4 A_QueueCorpse; + WRTH O 4; + WRTH PQ 5; + WRTH R -1; + Stop; + XDeath: + WRT2 A 5; + WRT2 B 5 A_Scream; + WRT2 CD 5; + WRT2 E 5 A_NoBlocking; + WRT2 F 5 A_QueueCorpse; + WRT2 G 5; + WRT2 H -1; + Stop; + Ice: + WRT2 I 5 A_FreezeDeath; + WRT2 I 1 A_FreezeDeathChunks; + Wait; + } + + //============================================================================ + // + // A_WraithInit + // + //============================================================================ + + void A_WraithInit() + { + AddZ(48); + + // [RH] Make sure the wraith didn't go into the ceiling + if (pos.z + height > ceilingz) + { + SetZ(ceilingz - Height); + } + + WeaveIndexZ = 0; // index into floatbob + } + + + //============================================================================ + // + // A_WraithChase + // + //============================================================================ + + void A_WraithChase() + { + int weaveindex = WeaveIndexZ; + AddZ(BobSin(weaveindex)); + WeaveIndexZ = (weaveindex + 2) & 63; + A_Chase (); + A_WraithFX4 (); + } + + //============================================================================ + // + // A_WraithFX3 + // + // Spawn an FX3 around the wraith during attacks + // + //============================================================================ + + void A_WraithFX3() + { + int numdropped = random[WraithFX3](0,14); + + while (numdropped-- > 0) + { + double xo = (random[WraithFX3]() - 128) / 32.; + double yo = (random[WraithFX3]() - 128) / 32.; + double zo = random[WraithFX3]() / 64.; + + Actor mo = Spawn("WraithFX3", Vec3Offset(xo, yo, zo), ALLOW_REPLACE); + if (mo) + { + mo.floorz = floorz; + mo.ceilingz = ceilingz; + mo.target = self; + } + } + } + + //============================================================================ + // + // A_WraithFX4 + // + // Spawn an FX4 during movement + // + //============================================================================ + + void A_WraithFX4 () + { + int chance = random[WraithFX4](); + bool spawn4, spawn5; + + if (chance < 10) + { + spawn4 = true; + spawn5 = false; + } + else if (chance < 20) + { + spawn4 = false; + spawn5 = true; + } + else if (chance < 25) + { + spawn4 = true; + spawn5 = true; + } + else + { + spawn4 = false; + spawn5 = false; + } + + if (spawn4) + { + double xo = (random[WraithFX4]() - 128) / 16.; + double yo = (random[WraithFX4]() - 128) / 16.; + double zo = (random[WraithFX4]() / 64.); + + Actor mo = Spawn ("WraithFX4", Vec3Offset(xo, yo, zo), ALLOW_REPLACE); + if (mo) + { + mo.floorz = floorz; + mo.ceilingz = ceilingz; + mo.target = self; + } + } + if (spawn5) + { + double xo = (random[WraithFX4]() - 128) / 32.; + double yo = (random[WraithFX4]() - 128) / 32.; + double zo = (random[WraithFX4]() / 64.); + + Actor mo = Spawn ("WraithFX5", Vec3Offset(xo, yo, zo), ALLOW_REPLACE); + if (mo) + { + mo.floorz = floorz; + mo.ceilingz = ceilingz; + mo.target = self; + } + } + } + + //============================================================================ + // + // A_WraithMelee + // + //============================================================================ + + void A_WraithMelee() + { + // Steal health from target and give to self + if (CheckMeleeRange() && (random[StealHealth]()<220)) + { + int amount = random[StealHealth](1, 8) * 2; + target.DamageMobj (self, self, amount, 'Melee'); + health += amount; + } + } +} + +// Buried wraith ------------------------------------------------------------ + +class WraithBuried : Wraith +{ + Default + { + Height 68; + -SHOOTABLE + -SOLID + +DONTMORPH + +DONTBLAST + +SPECIALFLOORCLIP + +STAYMORPHED + +INVISIBLE + PainChance 0; + } + + + States + { + Spawn: + Goto Super::Look; + See: + WRTH A 2 A_WraithRaiseInit; + WRTH A 2 A_WraithRaise; + WRTH A 2 A_FaceTarget; + WRTH BB 2 A_WraithRaise; + Goto See + 1; + Chase: + Goto Super::See; + } + + //============================================================================ + // + // A_WraithRaiseInit + // + //============================================================================ + + void A_WraithRaiseInit() + { + bInvisible = false; + bNonShootable = false; + bDontBlast = false; + bShootable = true; + bSolid = true; + Floorclip = Height; + } + + //============================================================================ + // + // A_WraithRaise + // + //============================================================================ + + void A_WraithRaise() + { + if (RaiseMobj (2)) + { + // Reached it's target height + // [RH] Once a buried wraith is fully raised, it should be + // morphable, right? + bDontMorph = false; + bSpecialFloorClip = false; + SetStateLabel ("Chase"); + // [RH] Reset PainChance to a normal wraith's. + PainChance = GetDefaultByType("Wraith").PainChance; + } + + SpawnDirt (radius); + } + + +} + +// Wraith FX 1 -------------------------------------------------------------- + +class WraithFX1 : Actor +{ + Default + { + Speed 14; + Radius 10; + Height 6; + Mass 5; + Damage 5; + DamageType "Fire"; + Projectile; + +FLOORCLIP + SeeSound "WraithMissileFire"; + DeathSound "WraithMissileExplode"; + } + + + States + { + Spawn: + WRBL A 3 Bright; + WRBL B 3 Bright A_WraithFX2; + WRBL C 3 Bright; + Loop; + Death: + WRBL D 4 Bright; + WRBL E 4 Bright A_WraithFX2; + WRBL F 4 Bright; + WRBL GH 3 Bright A_WraithFX2; + WRBL I 3 Bright; + Stop; + } + + //============================================================================ + // + // A_WraithFX2 - spawns sparkle tail of missile + // + //============================================================================ + + void A_WraithFX2() + { + for (int i = 2; i; --i) + { + Actor mo = Spawn ("WraithFX2", Pos, ALLOW_REPLACE); + if(mo) + { + double newangle = random[WraithFX2]() * (360 / 1024.f); + if (random[WraithFX2]() >= 128) + { + newangle = -newangle; + } + newangle += angle; + mo.Vel.X = ((random[WraithFX2]() / 512.) + 1) * cos(newangle); + mo.Vel.Y = ((random[WraithFX2]() / 512.) + 1) * sin(newangle); + mo.Vel.Z = 0; + mo.target = self; + mo.Floorclip = 10; + } + } + } + + +} + +// Wraith FX 2 -------------------------------------------------------------- + +class WraithFX2 : Actor +{ + Default + { + Radius 2; + Height 5; + Mass 5; + +NOBLOCKMAP +DROPOFF + +FLOORCLIP +NOTELEPORT + } + States + { + Spawn: + WRBL JKLMNOP 4 Bright; + Stop; + } +} + +// Wraith FX 3 -------------------------------------------------------------- + +class WraithFX3 : Actor +{ + Default + { + Radius 2; + Height 5; + Mass 5; + +NOBLOCKMAP +DROPOFF +MISSILE + +FLOORCLIP +NOTELEPORT + DeathSound "Drip"; + } + States + { + Spawn: + WRBL QRS 4 Bright; + Loop; + Death: + WRBL S 4 Bright; + Stop; + } +} + +// Wraith FX 4 -------------------------------------------------------------- + +class WraithFX4 : Actor +{ + Default + { + Radius 2; + Height 5; + Mass 5; + +NOBLOCKMAP +DROPOFF +MISSILE + +NOTELEPORT + DeathSound "Drip"; + } + States + { + Spawn: + WRBL TUVW 4; + Loop; + Death: + WRBL W 10; + Stop; + } +} + +// Wraith FX 5 -------------------------------------------------------------- + +class WraithFX5 : WraithFX4 +{ + States + { + Spawn: + WRBL XYZ 7; + Loop; + Death: + WRBL Z 35; + Stop; + } +} diff --git a/wadsrc/static/zscript/raven/artiegg.txt b/wadsrc/static/zscript/raven/artiegg.txt new file mode 100644 index 0000000000..f0287048ec --- /dev/null +++ b/wadsrc/static/zscript/raven/artiegg.txt @@ -0,0 +1,112 @@ + +// Egg missile -------------------------------------------------------------- + +class EggFX : MorphProjectile +{ + Default + { + Radius 8; + Height 8; + Speed 18; + MorphProjectile.PlayerClass "ChickenPlayer"; + MorphProjectile.MonsterClass "Chicken"; + MorphProjectile.MorphStyle MRF_UNDOBYTOMEOFPOWER; + } + States + { + Spawn: + EGGM ABCDE 4; + Loop; + Death: + FX01 FFGH 3 Bright; + Stop; + } +} + + +// Morph Ovum ---------------------------------------------------------------- + +class ArtiEgg : CustomInventory +{ + Default + { + +COUNTITEM + +FLOATBOB + +INVENTORY.INVBAR + Inventory.PickupFlash "PickupFlash"; + +INVENTORY.FANCYPICKUPSOUND + Inventory.Icon "ARTIEGGC"; + Inventory.PickupSound "misc/p_pkup"; + Inventory.PickupMessage "$TXT_ARTIEGG"; + Inventory.DefMaxAmount; + Tag "$TAG_ARTIEGG"; + } + States + { + Spawn: + EGGC ABCB 6; + Loop; + Use: + TNT1 A 0 + { + for (double i = -15; i <= 15; i += 7.5) A_FireCustomMissile("EggFX", i, 0, 0, 0, 1); + } + Stop; + } +} + +// Pork missile -------------------------------------------------------------- + +class PorkFX : MorphProjectile +{ + Default + { + Radius 8; + Height 8; + Speed 18; + MorphProjectile.PlayerClass "PigPlayer"; + MorphProjectile.MonsterClass "Pig"; + MorphProjectile.MorphStyle MRF_UNDOBYTOMEOFPOWER|MRF_UNDOBYCHAOSDEVICE; + } + States + { + Spawn: + PRKM ABCDE 4; + Loop; + Death: + FHFX IJKL 3 Bright; + Stop; + } +} + +// Porkalator --------------------------------------------------------------- + +class ArtiPork : CustomInventory +{ + Default + { + +COUNTITEM + +FLOATBOB + +INVENTORY.INVBAR + Inventory.PickupFlash "PickupFlash"; + +INVENTORY.FANCYPICKUPSOUND + Inventory.Icon "ARTIPORK"; + Inventory.PickupSound "misc/p_pkup"; + Inventory.PickupMessage "$TXT_ARTIEGG2"; + Inventory.DefMaxAmount; + Tag "$TAG_ARTIPORK"; + } + States + { + Spawn: + PORK ABCDEFGH 5; + Loop; + Use: + TNT1 A 0 + { + for (double i = -15; i <= 15; i += 7.5) A_FireCustomMissile("PorkFX", i, 0, 0, 0, 1); + } + Stop; + } +} + diff --git a/wadsrc/static/zscript/raven/artitele.txt b/wadsrc/static/zscript/raven/artitele.txt new file mode 100644 index 0000000000..3242db92e6 --- /dev/null +++ b/wadsrc/static/zscript/raven/artitele.txt @@ -0,0 +1,59 @@ + +// Teleport (self) ---------------------------------------------------------- + +class ArtiTeleport : Inventory +{ + Default + { + +COUNTITEM + +FLOATBOB + +INVENTORY.INVBAR + Inventory.PickupFlash "PickupFlash"; + +INVENTORY.FANCYPICKUPSOUND + Inventory.DefMaxAmount; + Inventory.Icon "ARTIATLP"; + Inventory.PickupSound "misc/p_pkup"; + Inventory.PickupMessage "$TXT_ARTITELEPORT"; + Tag "$TAG_ARTITELEPORT"; + } + States + { + Spawn: + ATLP ABCB 4; + Loop; + } + + override bool Use (bool pickup) + { + Vector3 dest; + int destAngle; + + if (deathmatch) + { + [dest, destAngle] = G_PickDeathmatchStart(); + } + else + { + [dest, destAngle] = G_PickPlayerStart(Owner.PlayerNumber()); + } + dest.Z = ONFLOORZ; + Owner.Teleport (dest, destAngle, TELF_SOURCEFOG | TELF_DESTFOG); + bool canlaugh = true; + Playerinfo p = Owner.player; + if (p && p.morphTics && (p.MorphStyle & MRF_UNDOBYCHAOSDEVICE)) + { // Teleporting away will undo any morph effects (pig) + if (!p.UndoPlayerMorph (p, MRF_UNDOBYCHAOSDEVICE) && (p.MorphStyle & MRF_FAILNOLAUGH)) + { + canlaugh = false; + } + } + if (canlaugh) + { // Full volume laugh + A_PlaySound ("*evillaugh", CHAN_VOICE, 1, false, ATTN_NONE); + } + return true; + } + +} + + diff --git a/wadsrc/static/zscript/raven/minotaur.txt b/wadsrc/static/zscript/raven/minotaur.txt new file mode 100644 index 0000000000..01cd635410 --- /dev/null +++ b/wadsrc/static/zscript/raven/minotaur.txt @@ -0,0 +1,806 @@ +class Minotaur : Actor +{ + const MAULATORTICS = 25 * TICRATE; + const MNTR_CHARGE_SPEED =13.; + const MINOTAUR_LOOK_DIST = 16*54.; + + Default + { + Health 3000; + Radius 28; + Height 100; + Mass 800; + Speed 16; + Damage 7; + Painchance 25; + Monster; + +DROPOFF + +FLOORCLIP + +BOSS + +NORADIUSDMG + +DONTMORPH + +NOTARGET + +BOSSDEATH + SeeSound "minotaur/sight"; + AttackSound "minotaur/attack1"; + PainSound "minotaur/pain"; + DeathSound "minotaur/death"; + ActiveSound "minotaur/active"; + DropItem "ArtiSuperHealth", 51; + DropItem "PhoenixRodAmmo", 84, 10; + } + + States + { + Spawn: + MNTR AB 10 A_MinotaurLook; + Loop; + Roam: + MNTR ABCD 5 A_MinotaurRoam; + Loop; + See: + MNTR ABCD 5 A_MinotaurChase; + Loop; + Melee: + MNTR V 10 A_FaceTarget; + MNTR W 7 A_FaceTarget; + MNTR X 12 A_MinotaurAtk1; + Goto See; + Missile: + MNTR V 10 A_MinotaurDecide; + MNTR Y 4 A_FaceTarget; + MNTR Z 9 A_MinotaurAtk2; + Goto See; + Hammer: + MNTR V 10 A_FaceTarget; + MNTR W 7 A_FaceTarget; + MNTR X 12 A_MinotaurAtk3; + Goto See; + HammerLoop: + MNTR X 12; + Goto Hammer; + Charge: + MNTR U 2 A_MinotaurCharge; + Loop; + Pain: + MNTR E 3; + MNTR E 6 A_Pain; + Goto See; + Death: + MNTR F 6 A_MinotaurDeath; + MNTR G 5; + MNTR H 6 A_Scream; + MNTR I 5; + MNTR J 6; + MNTR K 5; + MNTR L 6; + MNTR M 5 A_NoBlocking; + MNTR N 6; + MNTR O 5; + MNTR P 6; + MNTR Q 5; + MNTR R 6; + MNTR S 5; + MNTR T -1 A_BossDeath; + Stop; + FadeOut: + MNTR E 6; + MNTR E 2 A_Scream; + MNTR E 5 A_SpawnItemEx("MinotaurSmokeExit"); + MNTR E 5; + MNTR E 5 A_NoBlocking; + MNTR E 5; + MNTR E 5 A_SetTranslucent(0.66, 0); + MNTR E 5 A_SetTranslucent(0.33, 0); + MNTR E 10 A_BossDeath; + Stop; + } + + //--------------------------------------------------------------------------- + // + // FUNC P_MinotaurSlam + // + //--------------------------------------------------------------------------- + + void MinotaurSlam (Actor target) + { + double ang = AngleTo(target); + double thrust = 16 + random[MinotaurSlam]() / 64.; + target.VelFromAngle(ang, thrust); + int damage = random[MinotaurSlam](1, 8) * (bSummonedMonster? 4 : 6); + int newdam = target.DamageMobj (null, null, damage, 'Melee'); + target.TraceBleedAngle (newdam > 0 ? newdam : damage, ang, 0.); + if (target.player) + { + target.reactiontime = random[MinotaurSlam](14, 21); + } + } + + + //---------------------------------------------------------------------------- + // + // + // + //---------------------------------------------------------------------------- + + override void Tick () + { + Super.Tick (); + + // The unfriendly Minotaur (Heretic's) is invulnerable while charging + if (!bSummonedMonster) + { + bInvulnerable = bSkullFly; + } + } + + override bool Slam (Actor thing) + { + // Slamming minotaurs shouldn't move non-creatures + if (!thing.bIsMonster && !thing.player) + { + return false; + } + return Super.Slam (thing); + } + + override int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + damage = Super.DoSpecialDamage (target, damage, damagetype); + if (damage != -1 && bSkullFly) + { // Slam only when in charge mode + MinotaurSlam (target); + return -1; + } + return damage; + } + + //---------------------------------------------------------------------------- + // + // PROC A_MinotaurAtk1 + // + // Melee attack. + // + //---------------------------------------------------------------------------- + + void A_MinotaurAtk1() + { + if (!target) + { + return; + } + A_PlaySound ("minotaur/melee", CHAN_WEAPON); + if (CheckMeleeRange()) + { + int damage = random[MinotaurAtk1](1, 8) * 4; + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + PlayerInfo player = target.player; + if (player != null && player.mo == target) + { // Squish the player + player.deltaviewheight = -16; + } + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_MinotaurDecide + // + // Choose a missile attack. + // + //---------------------------------------------------------------------------- + + void A_MinotaurDecide() + { + bool friendly = bSummonedMonster; + + if (!target) + { + return; + } + if (!friendly) + { + A_PlaySound ("minotaur/sight", CHAN_WEAPON); + } + double dist = Distance2D(target); + if (target.pos.z + target.height > pos.z + && target.pos.z + target.height < pos.z + height + && dist < (friendly ? 16*64. : 8*64.) + && dist > 1*64. + && random[MinotaurDecide]() < 150) + { // Charge attack + // Don't call the state function right away + SetStateLabel("Charge", true); + bSkullFly = true; + if (!friendly) + { // Heretic's Minotaur is invulnerable during charge attack + bInvulnerable = true; + } + A_FaceTarget (); + VelFromAngle(MNTR_CHARGE_SPEED); + special1 = TICRATE/2; // Charge duration + } + else if (target.pos.z == target.floorz + && dist < 9*64. + && random[MinotaurDecide]() < (friendly ? 100 : 220)) + { // Floor fire attack + SetStateLabel("Hammer"); + special2 = 0; + } + else + { // Swing attack + A_FaceTarget (); + // Don't need to call P_SetMobjState because the current state + // falls through to the swing attack + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_MinotaurCharge + // + //---------------------------------------------------------------------------- + + void A_MinotaurCharge() + { + if (target == null) + { + return; + } + if (special1 > 0) + { + Class type; + + //if (gameinfo.gametype == GAME_Heretic) + if (gametype() == GAME_Heretic) + { + type = "PhoenixPuff"; + } + else + { + type = "PunchPuff"; + } + Actor puff = Spawn (type, Pos, ALLOW_REPLACE); + puff.Vel.Z = 2; + special1--; + } + else + { + bSkullFly = false; + bInvulnerable = false; + SetState (SeeState); + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_MinotaurAtk2 + // + // Swing attack. + // + //---------------------------------------------------------------------------- + + void A_MinotaurAtk2() + { + bool friendly = bSummonedMonster; + + if (target == null) + { + return; + } + A_PlaySound ("minotaur/attack2", CHAN_WEAPON); + if (CheckMeleeRange()) + { + int damage = random[MinotaurAtk2](1, 8) * (friendly ? 3 : 5); + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + return; + } + double z = pos.z + 40; + Class fx = "MinotaurFX1"; + Actor mo = SpawnMissileZ (z, target, fx); + if (mo != null) + { +// S_Sound (mo, CHAN_WEAPON, "minotaur/attack2", 1, ATTN_NORM); + double vz = mo.Vel.Z; + double ang = mo.angle; + SpawnMissileAngleZ (z, fx, ang-(45./8), vz); + SpawnMissileAngleZ (z, fx, ang+(45./8), vz); + SpawnMissileAngleZ (z, fx, ang-(45./16), vz); + SpawnMissileAngleZ (z, fx, ang+(45./16), vz); + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_MinotaurAtk3 + // + // Floor fire attack. + // + //---------------------------------------------------------------------------- + + void A_MinotaurAtk3() + { + bool friendly = bSummonedMonster; + + if (!target) + { + return; + } + A_PlaySound ("minotaur/attack3", CHAN_VOICE); + if (CheckMeleeRange()) + { + int damage = random[MinotaurAtk3](1, 8) * (friendly ? 3 : 5); + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + PlayerInfo player = target.player; + if (player != null && player.mo == target) + { // Squish the player + player.deltaviewheight = -16; + } + } + else + { + if (Floorclip > 0 && compat_minotaur) + { + // only play the sound. + A_PlaySound ("minotaur/fx2hit", CHAN_WEAPON); + } + else + { + Actor mo = SpawnMissile (target, "MinotaurFX2"); + if (mo != null) + { + mo.A_PlaySound ("minotaur/attack1", CHAN_WEAPON); + } + } + } + if (random[MinotaurAtk3]() < 192 && special2 == 0) + { + SetStateLabel ("HammerLoop"); + special2 = 1; + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_MinotaurDeath + // + //---------------------------------------------------------------------------- + + void A_MinotaurDeath() + { + if (Wads.CheckNumForName ("MNTRF1", Wads.ns_sprites) < 0 && + Wads.CheckNumForName ("MNTRF0", Wads.ns_sprites) < 0) + SetStateLabel("FadeOut"); + } + + + //---------------------------------------------------------------------------- + // + // A_MinotaurRoam + // + //---------------------------------------------------------------------------- + + void A_MinotaurRoam() + { + // In case pain caused him to skip his fade in. + A_SetRenderStyle(1, STYLE_Normal); + + let mf = MinotaurFriend(self); + if (mf) + { + if (mf.StartTime >= 0 && (level.maptime - mf.StartTime) >= MAULATORTICS) + { + DamageMobj (null, null, TELEFRAG_DAMAGE, 'None'); + return; + } + } + + if (random[MinotaurRoam]() < 30) + A_MinotaurLook(); // adjust to closest target + + if (random[MinotaurRoam]() < 6) + { + //Choose new direction + movedir = random[MinotaurRoam]() % 8; + FaceMovementDirection (); + } + if (!MonsterMove()) + { + // Turn + if (random[MinotaurRoam]() & 1) + movedir = (movedir + 1) % 8; + else + movedir = (movedir + 7) % 8; + FaceMovementDirection (); + } + } + + + //---------------------------------------------------------------------------- + // + // PROC A_MinotaurLook + // + // Look for enemy of player + //---------------------------------------------------------------------------- + + void A_MinotaurLook() + { + if (!(self is "MinotaurFriend")) + { + A_Look(); + return; + } + + Actor mo = null; + PlayerInfo player; + double dist; + Actor master = tracer; + + target = null; + if (deathmatch) // Quick search for players + { + for (int i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) continue; + player = players[i]; + mo = player.mo; + if (mo == master) continue; + if (mo.health <= 0) continue; + dist = Distance2D(mo); + if (dist > MINOTAUR_LOOK_DIST) continue; + target = mo; + break; + } + } + + if (!target) // Near player monster search + { + if (master && (master.health > 0) && (master.player)) + mo = master.RoughMonsterSearch(20); + else + mo = RoughMonsterSearch(20); + target = mo; + } + + if (!target) // Normal monster search + { + ThinkerIterator it = ThinkerIterator.Create("Actor"); + + while ((mo = Actor(it.Next())) != null) + { + if (!mo.bIsMonster) continue; + if (mo.health <= 0) continue; + if (!mo.bShootable) continue; + dist = Distance2D(mo); + if (dist > MINOTAUR_LOOK_DIST) continue; + if (mo == master || mo == self) continue; + if (mo.bSummonedMonster && mo.tracer == master) continue; + target = mo; + break; // Found actor to attack + } + } + + if (target) + { + SetState (SeeState, true); + } + else + { + SetStateLabel ("Roam", true); + } + } + + //---------------------------------------------------------------------------- + // + // PROC A_MinotaurChase + // + //---------------------------------------------------------------------------- + + void A_MinotaurChase() + { + let mf = MinotaurFriend(self); + if (!mf) + { + A_Chase(); + return; + } + + + // In case pain caused him to skip his fade in. + A_SetRenderStyle(1, STYLE_Normal); + + if (mf.StartTime >= 0 && (level.maptime - mf.StartTime) >= MAULATORTICS) + { + DamageMobj (null, null, TELEFRAG_DAMAGE, 'None'); + return; + } + + if (random[MinotaurChase]() < 30) + A_MinotaurLook(); // adjust to closest target + + if (!target || (target.health <= 0) || !target.bShootable) + { // look for a new target + SetIdle(); + return; + } + + FaceMovementDirection (); + reactiontime = 0; + + // Melee attack + if (MeleeState && CheckMeleeRange ()) + { + if (AttackSound) + { + A_PlaySound (AttackSound, CHAN_WEAPON); + } + SetState (MeleeState); + return; + } + + // Missile attack + if (MissileState && CheckMissileRange()) + { + SetState (MissileState); + return; + } + + // chase towards target + if (!MonsterMove ()) + { + NewChaseDir (); + FaceMovementDirection (); + } + + // Active sound + if (random[MinotaurChase]() < 6) + { + PlayActiveSound (); + } + } +} + +class MinotaurFriend : Minotaur +{ + int StartTime; + + Default + { + Health 2500; + -DROPOFF + -BOSS + -DONTMORPH + +FRIENDLY + +NOTARGETSWITCH + +STAYMORPHED + +TELESTOMP + +SUMMONEDMONSTER + RenderStyle "Translucent"; + Alpha 0.3333; + DropItem "None"; + } + States + { + Spawn: + MNTR A 15; + MNTR A 15 A_SetTranslucent(0.66, 0); + MNTR A 3 A_SetTranslucent(1, 0); + Goto Super::Spawn; + Idle: + Goto Super::Spawn; + Death: + Goto FadeOut; + } + + //---------------------------------------------------------------------------- + // + // + // + //---------------------------------------------------------------------------- + + override void BeginPlay () + { + Super.BeginPlay (); + StartTime = -1; + } + + override void Die (Actor source, Actor inflictor, int dmgflags) + { + Super.Die (source, inflictor, dmgflags); + + if (tracer && tracer.health > 0 && tracer.player) + { + // Search thinker list for minotaur + ThinkerIterator it = ThinkerIterator.Create("MinotaurFriend"); + MinotaurFriend mo; + + while ((mo = MinotaurFriend(it.Next())) != null) + { + if (mo.health <= 0) continue; + // [RH] Minotaurs can't be morphed, so this isn't needed + //if (!(mo.flags&MF_COUNTKILL)) continue; // for morphed minotaurs + if (mo.bCorpse) continue; + if (mo.StartTime >= 0 && (level.maptime - StartTime) >= MAULATORTICS) continue; + if (mo.tracer != null && mo.tracer.player == tracer.player) break; + } + + if (mo == null) + { + Inventory power = tracer.FindInventory("PowerMinotaur"); + if (power != null) + { + power.Destroy (); + } + } + } + } + + +} + +// Minotaur FX 1 ------------------------------------------------------------ + +class MinotaurFX1 : Actor +{ + Default + { + Radius 10; + Height 6; + Speed 20; + FastSpeed 26; + Damage 3; + DamageType "Fire"; + Projectile; + -ACTIVATEIMPACT + -ACTIVATEPCROSS + RenderStyle "Add"; + } + States + { + Spawn: + FX12 AB 6 Bright; + Loop; + Death: + FX12 CDEFGH 5 Bright; + Stop; + } +} + + +// Minotaur FX 2 ------------------------------------------------------------ + +class MinotaurFX2 : MinotaurFX1 +{ + Default + { + Radius 5; + Height 12; + Speed 14; + FastSpeed 20; + Damage 4; + +FLOORHUGGER + ExplosionDamage 24; + DeathSound "minotaur/fx2hit"; + } + + states + { + Spawn: + FX13 A 2 Bright A_MntrFloorFire; + Loop; + Death: + FX13 I 4 Bright A_Explode; + FX13 JKLM 4 Bright; + Stop; + } + + //---------------------------------------------------------------------------- + // + // PROC A_MntrFloorFire + // + //---------------------------------------------------------------------------- + + void A_MntrFloorFire() + { + SetZ(floorz); + double x = Random2[MntrFloorFire]() / 64.; + double y = Random2[MntrFloorFire]() / 64.; + + Actor mo = Spawn("MinotaurFX3", Vec2OffsetZ(x, y, floorz), ALLOW_REPLACE); + mo.target = target; + mo.Vel.X = MinVel; // Force block checking + mo.CheckMissileSpawn (radius); + } +} + +// Minotaur FX 3 ------------------------------------------------------------ + +class MinotaurFX3 : MinotaurFX2 +{ + Default + { + Radius 8; + Height 16; + Speed 0; + DeathSound "minotaur/fx3hit"; + ExplosionDamage 128; + } + States + { + Spawn: + FX13 DC 4 Bright; + FX13 BCDE 5 Bright; + FX13 FGH 4 Bright; + Stop; + } +} + +// Minotaur Smoke Exit ------------------------------------------------------ + +class MinotaurSmokeExit : Actor +{ + Default + { + +NOBLOCKMAP + +NOTELEPORT + RenderStyle "Translucent"; + Alpha 0.4; + } + States + { + Spawn: + MNSM ABCDEFGHIJIHGFEDCBA 3; + Stop; + } +} + +extend class Actor +{ + enum dirtype_t + { + DI_EAST, + DI_NORTHEAST, + DI_NORTH, + DI_NORTHWEST, + DI_WEST, + DI_SOUTHWEST, + DI_SOUTH, + DI_SOUTHEAST, + DI_NODIR, + NUMDIRS + }; + + void FaceMovementDirection() + { + switch (movedir) + { + case DI_EAST: + angle = 0.; + break; + case DI_NORTHEAST: + angle = 45.; + break; + case DI_NORTH: + angle = 90.; + break; + case DI_NORTHWEST: + angle = 135.; + break; + case DI_WEST: + angle = 180.; + break; + case DI_SOUTHWEST: + angle = 225.; + break; + case DI_SOUTH: + angle = 270.; + break; + case DI_SOUTHEAST: + angle = 315.; + break; + } + } +} \ No newline at end of file diff --git a/wadsrc/static/zscript/raven/ravenambient.txt b/wadsrc/static/zscript/raven/ravenambient.txt new file mode 100644 index 0000000000..e0cff04d32 --- /dev/null +++ b/wadsrc/static/zscript/raven/ravenambient.txt @@ -0,0 +1,42 @@ + + +// Wind --------------------------------------------------------------------- + +class SoundWind : Actor +{ + Default + { + +NOBLOCKMAP + +NOSECTOR + +DONTSPLASH + } + States + { + Spawn: + TNT1 A 2 A_PlaySound("world/wind", CHAN_6, 1, true); + Loop; + } +} + +class SoundWindHexen : SoundWind +{ +} + + +// Waterfall ---------------------------------------------------------------- + +class SoundWaterfall : Actor +{ + Default + { + +NOBLOCKMAP + +NOSECTOR + +DONTSPLASH + } + States + { + Spawn: + TNT1 A 2 A_PlaySound("world/waterfall", CHAN_6, 1, true); + Loop; + } +} diff --git a/wadsrc/static/zscript/raven/ravenartifacts.txt b/wadsrc/static/zscript/raven/ravenartifacts.txt new file mode 100644 index 0000000000..443816788e --- /dev/null +++ b/wadsrc/static/zscript/raven/ravenartifacts.txt @@ -0,0 +1,143 @@ + +// Health ------------------------------------------------------------------- + +class ArtiHealth : HealthPickup +{ + Default + { + Health 25; + +COUNTITEM + +FLOATBOB + Inventory.PickupFlash "PickupFlash"; + +INVENTORY.FANCYPICKUPSOUND + Inventory.Icon "ARTIPTN2"; + Inventory.PickupSound "misc/p_pkup"; + Inventory.PickupMessage "$TXT_ARTIHEALTH"; + Tag "$TAG_ARTIHEALTH"; + HealthPickup.Autouse 1; + } + States + { + Spawn: + PTN2 ABC 4; + Loop; + } +} + +// Super health ------------------------------------------------------------- + +class ArtiSuperHealth : HealthPickup +{ + Default + { + Health 100; + +COUNTITEM + +FLOATBOB + Inventory.PickupFlash "PickupFlash"; + +INVENTORY.FANCYPICKUPSOUND + Inventory.Icon "ARTISPHL"; + Inventory.PickupSound "misc/p_pkup"; + Inventory.PickupMessage "$TXT_ARTISUPERHEALTH"; + Tag "$TAG_ARTISUPERHEALTH"; + HealthPickup.Autouse 2; + } + States + { + Spawn: + SPHL A 350; + Loop; + } +} + +// Flight ------------------------------------------------------------------- + +class ArtiFly : PowerupGiver +{ + Default + { + +COUNTITEM + +FLOATBOB + Inventory.PickupFlash "PickupFlash"; + Inventory.InterHubAmount 0; + Inventory.RespawnTics 4230; + Inventory.Icon "ARTISOAR"; + Inventory.PickupMessage "$TXT_ARTIFLY"; + Tag "$TAG_ARTIFLY"; + Powerup.Type "PowerFlight"; + } + States + { + Spawn: + SOAR ABCB 5; + Loop; + } +} + +// Invulnerability Heretic (Ring of invincibility) -------------------------- + +class ArtiInvulnerability : PowerupGiver +{ + Default + { + +COUNTITEM + +FLOATBOB + Inventory.PickupFlash "PickupFlash"; + Inventory.RespawnTics 4230; + Inventory.Icon "ARTIINVU"; + Inventory.PickupMessage "$TXT_ARTIINVULNERABILITY"; + Tag "$TAG_ARTIINVULNERABILITY"; + Powerup.Type "PowerInvulnerable"; + Powerup.Color "GoldMap"; + } + States + { + Spawn: + INVU ABCD 3; + Loop; + } +} + +// Invulnerability Hexen (Icon of the defender) ----------------------------- + +class ArtiInvulnerability2 : PowerupGiver +{ + Default + { + +COUNTITEM + +FLOATBOB + Inventory.PickupFlash "PickupFlash"; + Inventory.RespawnTics 4230; + Inventory.Icon "ARTIDEFN"; + Inventory.PickupMessage "$TXT_ARTIINVULNERABILITY2"; + Powerup.Type "PowerInvulnerable"; + Tag "$TAG_ARTIDEFENDER"; + } + States + { + Spawn: + DEFN ABCD 3; + Loop; + } +} + +// Torch -------------------------------------------------------------------- + +class ArtiTorch : PowerupGiver +{ + Default + { + +COUNTITEM + +FLOATBOB + Inventory.PickupFlash "PickupFlash"; + Inventory.Icon "ARTITRCH"; + Inventory.PickupMessage "$TXT_ARTITORCH"; + Tag "$TAG_ARTITORCH"; + Powerup.Type "PowerTorch"; + } + States + { + Spawn: + TRCH ABC 3 Bright; + Loop; + } +} diff --git a/wadsrc/static/zscript/raven/ravenhealth.txt b/wadsrc/static/zscript/raven/ravenhealth.txt new file mode 100644 index 0000000000..cf7c79d0a7 --- /dev/null +++ b/wadsrc/static/zscript/raven/ravenhealth.txt @@ -0,0 +1,16 @@ +class CrystalVial : Health +{ + Default + { + +FLOATBOB + Inventory.Amount 10; + Inventory.PickupMessage "$TXT_ITEMHEALTH"; + } + States + { + Spawn: + PTN1 ABC 3; + Loop; + } +} + diff --git a/wadsrc/static/zscript/shared/armor.txt b/wadsrc/static/zscript/shared/armor.txt new file mode 100644 index 0000000000..3e7f57e21c --- /dev/null +++ b/wadsrc/static/zscript/shared/armor.txt @@ -0,0 +1,72 @@ +class Armor : Inventory native +{ + Default + { + Inventory.PickupSound "misc/armor_pkup"; + } +} + +class BasicArmor : Armor native +{ + + native int AbsorbCount; + native double SavePercent; + native int MaxAbsorb; + native int MaxFullAbsorb; + native int BonusCount; + native Name ArmorType; + native int ActualSaveAmount; + + Default + { + +Inventory.KEEPDEPLETED + } +} + +class BasicArmorBonus : Armor native +{ + native double SavePercent; // The default, for when you don't already have armor + native int MaxSaveAmount; + native int MaxAbsorb; + native int MaxFullAbsorb; + native int SaveAmount; + native int BonusCount; + native int BonusMax; + + Default + { + +Inventory.AUTOACTIVATE + +Inventory.ALWAYSPICKUP + Inventory.MaxAmount 0; + Armor.SavePercent 33.335; + } +} + +class BasicArmorPickup : Armor native +{ + + native double SavePercent; + native int MaxAbsorb; + native int MaxFullAbsorb; + native int SaveAmount; + + Default + { + +Inventory.AUTOACTIVATE; + Inventory.MaxAmount 0; + } +} + +class HexenArmor : Armor native +{ + + native double Slots[5]; + native double SlotsIncrement[4]; + + Default + { + +Inventory.KEEPDEPLETED + +Inventory.UNDROPPABLE + } +} + diff --git a/wadsrc/static/zscript/shared/blood.txt b/wadsrc/static/zscript/shared/blood.txt new file mode 100644 index 0000000000..e5f05de05b --- /dev/null +++ b/wadsrc/static/zscript/shared/blood.txt @@ -0,0 +1,78 @@ + +// Blood sprite ------------------------------------------------------------ + +class Blood : Actor +{ + Default + { + Mass 5; + +NOBLOCKMAP + +NOTELEPORT + +ALLOWPARTICLES + } + States + { + Spawn: + BLUD CBA 8; + Stop; + Spray: + SPRY ABCDEF 3; + SPRY G 2; + Stop; + } +} + +// Blood splatter ----------------------------------------------------------- + +class BloodSplatter : Actor +{ + Default + { + Radius 2; + Height 4; + +NOBLOCKMAP + +MISSILE + +DROPOFF + +NOTELEPORT + +CANNOTPUSH + +ALLOWPARTICLES + Mass 5; + } + States + { + Spawn: + BLUD CBA 8; + Stop; + Death: + BLUD A 6; + Stop; + } +} + +// Axe Blood ---------------------------------------------------------------- + +class AxeBlood : Actor +{ + Default + { + Radius 2; + Height 4; + +NOBLOCKMAP + +NOGRAVITY + +DROPOFF + +NOTELEPORT + +CANNOTPUSH + +ALLOWPARTICLES + Mass 5; + } + States + { + Spawn: + FAXE FGHIJ 3; + Death: + FAXE K 3; + Stop; + } +} + + \ No newline at end of file diff --git a/wadsrc/static/zscript/shared/botstuff.txt b/wadsrc/static/zscript/shared/botstuff.txt new file mode 100644 index 0000000000..3ae2d18894 --- /dev/null +++ b/wadsrc/static/zscript/shared/botstuff.txt @@ -0,0 +1,29 @@ + +class CajunBodyNode : Actor +{ + Default + { + +NOSECTOR + +NOGRAVITY + +INVISIBLE + } +} + +class CajunTrace : Actor +{ + Default + { + Speed 12; + Radius 6; + Height 8; + +NOBLOCKMAP + +DROPOFF + +MISSILE + +NOGRAVITY + +NOTELEPORT + } +} + +struct Bot native +{ +} diff --git a/wadsrc/static/zscript/shared/bridge.txt b/wadsrc/static/zscript/shared/bridge.txt new file mode 100644 index 0000000000..ea38796a70 --- /dev/null +++ b/wadsrc/static/zscript/shared/bridge.txt @@ -0,0 +1,129 @@ +// Bridge ball ------------------------------------------------------------- + +class BridgeBall : Actor +{ + default + { + +NOBLOCKMAP + +NOTELEPORT + +NOGRAVITY + } + + native void A_BridgeOrbit(); + + States + { + Spawn: + TLGL A 2 Bright; + TLGL A 1 Bright A_BridgeOrbit; + Wait; + } + +} + +// The bridge itself ------------------------------------------------------- + +class CustomBridge : Actor native +{ + default + { + +SOLID + +NOGRAVITY + +NOLIFTDROP + +ACTLIKEBRIDGE + Radius 32; + Height 2; + RenderStyle "None"; + } + + native void A_BridgeInit(class balltype = "BridgeBall"); + + states + { + Spawn: + TLGL ABCDE 3 Bright; + Loop; + See: + TLGL A 2; + TLGL A 2 A_BridgeInit; + TLGL A -1; + Stop; + Death: + TLGL A 2; + TLGL A 300; + Stop; + } +} + +// The Hexen bridge ------------------------------------------------------- + +class Bridge : CustomBridge +{ + default + { + RenderStyle "None"; + Args 32, 2, 3, 0; + } +} + +// The ZDoom bridge ------------------------------------------------------- + +class ZBridge : CustomBridge +{ + default + { + Args 36, 4, 0, 0; + } +} + + +// Invisible bridge -------------------------------------------------------- + +class InvisibleBridge : Actor native +{ + default + { + RenderStyle "None"; + Radius 32; + Height 4; + +SOLID + +NOGRAVITY + +NOLIFTDROP + +ACTLIKEBRIDGE + } + States + { + Spawn: + TNT1 A -1; + Stop; + } +} + +// And some invisible bridges from Skull Tag ------------------------------- + +class InvisibleBridge32 : InvisibleBridge +{ + default + { + Radius 32; + Height 8; + } +} + +class InvisibleBridge16 : InvisibleBridge +{ + default + { + Radius 16; + Height 8; + } +} + +class InvisibleBridge8 : InvisibleBridge +{ + default + { + Radius 8; + Height 8; + } +} diff --git a/wadsrc/static/zscript/shared/camera.txt b/wadsrc/static/zscript/shared/camera.txt new file mode 100644 index 0000000000..abb394745e --- /dev/null +++ b/wadsrc/static/zscript/shared/camera.txt @@ -0,0 +1,126 @@ +class DoomBuilderCamera : Actor +{ + States + { + Spawn: + TNT1 A 1; + Stop; + } +} + + +class SecurityCamera : Actor +{ + default + { + +NOBLOCKMAP + +NOGRAVITY + +DONTSPLASH + RenderStyle "None"; + CameraHeight 0; + } + + double Center; + double Acc; + double Delta; + double Range; + + override void PostBeginPlay () + { + Super.PostBeginPlay (); + Center = Angle; + if (args[2]) + Delta = 360. / (args[2] * TICRATE / 8); + else + Delta = 0.; + if (args[1]) + Delta /= 2; + Acc = 0.; + Pitch = clamp(args[0], -89, 89); + Range = args[1]; + } + + override void Tick () + { + Acc += Delta; + if (Range != 0) + Angle = Center + Range * sin(Acc); + else if (Delta != 0) + Angle = Acc; + } + + +} + +class AimingCamera : SecurityCamera +{ + double MaxPitchChange; + + override void PostBeginPlay () + { + int changepitch = args[2]; + + args[2] = 0; + Super.PostBeginPlay (); + MaxPitchChange = double(changepitch / TICRATE); + Range /= TICRATE; + + ActorIterator it = ActorIterator.Create(args[3]); + tracer = it.Next (); + if (tracer == NULL) + { + //Printf ("AimingCamera %d: Can't find TID %d\n", tid, args[3]); + } + else + { // Don't try for a new target upon losing this one. + args[3] = 0; + } + } + + override void Tick () + { + if (tracer == NULL && args[3] != 0) + { // Recheck, in case something with this TID was created since the last time. + ActorIterator it = ActorIterator.Create(args[3]); + tracer = it.Next (); + } + if (tracer != NULL) + { + double dir = deltaangle(angle, AngleTo(tracer)); + double delta = abs(dir); + if (delta > Range) + { + delta = Range; + } + if (dir > 0) + { + Angle += delta; + } + else + { + Angle -= delta; + } + if (MaxPitchChange != 0) + { // Aim camera's pitch; use floats for precision + Vector2 vect = tracer.Vec2To(self); + double dz = pos.z - tracer.pos.z - tracer.Height/2; + double dist = vect.Length(); + double desiredPitch = dist != 0.f ? VectorAngle(dist, dz) : 0.; + double diff = deltaangle(pitch, desiredPitch); + if (abs (diff) < MaxPitchChange) + { + pitch = desiredPitch; + } + else if (diff < 0) + { + pitch -= MaxPitchChange; + } + else + { + pitch += MaxPitchChange; + } + } + } + } + +} diff --git a/wadsrc/static/zscript/shared/debris.txt b/wadsrc/static/zscript/shared/debris.txt new file mode 100644 index 0000000000..3ffcea057a --- /dev/null +++ b/wadsrc/static/zscript/shared/debris.txt @@ -0,0 +1,374 @@ + +// Rocks -------------------------------------------------------------------- + +class Rock1 : Actor +{ + Default + { + +NOBLOCKMAP + +DROPOFF + +MISSILE + +NOTELEPORT + } + States + { + Spawn: + ROKK A 20; + Loop; + Death: + ROKK A 10; + Stop; + } +} + +class Rock2 : Actor +{ + Default + { + +NOBLOCKMAP + +DROPOFF + +MISSILE + +NOTELEPORT + } + States + { + Spawn: + ROKK B 20; + Loop; + Death: + ROKK B 10; + Stop; + } +} + + +class Rock3 : Actor +{ + Default + { + +NOBLOCKMAP + +DROPOFF + +MISSILE + +NOTELEPORT + } + States + { + Spawn: + ROKK C 20; + Loop; + Death: + ROKK C 10; + Stop; + } +} + + +// Dirt -------------------------------------------------------------------- + +class Dirt1 : Actor +{ + Default + { + +NOBLOCKMAP + +DROPOFF + +MISSILE + +NOTELEPORT + } + States + { + Spawn: + ROKK D 20; + Loop; + Death: + ROKK D 10; + Stop; + } +} + +class Dirt2 : Actor +{ + Default + { + +NOBLOCKMAP + +DROPOFF + +MISSILE + +NOTELEPORT + } + States + { + Spawn: + ROKK E 20; + Loop; + Death: + ROKK E 10; + Stop; + } +} + +class Dirt3 : Actor +{ + Default + { + +NOBLOCKMAP + +DROPOFF + +MISSILE + +NOTELEPORT + } + States + { + Spawn: + ROKK F 20; + Loop; + Death: + ROKK F 10; + Stop; + } +} + +class Dirt4 : Actor +{ + Default + { + +NOBLOCKMAP + +DROPOFF + +MISSILE + +NOTELEPORT + } + States + { + Spawn: + ROKK G 20; + Loop; + Death: + ROKK G 10; + Stop; + } +} + +class Dirt5 : Actor +{ + Default + { + +NOBLOCKMAP + +DROPOFF + +MISSILE + +NOTELEPORT + } + States + { + Spawn: + ROKK H 20; + Loop; + Death: + ROKK H 10; + Stop; + } +} + +class Dirt6 : Actor +{ + Default + { + +NOBLOCKMAP + +DROPOFF + +MISSILE + +NOTELEPORT + } + States + { + Spawn: + ROKK I 20; + Loop; + Death: + ROKK I 10; + Stop; + } +} + +// Stained glass ------------------------------------------------------------ + +class GlassShard : Actor +{ + Default + { + Radius 5; + Mass 5; + Projectile; + -ACTIVATEPCROSS + -ACTIVATEIMPACT + BounceType "HexenCompat"; + BounceFactor 0.3; + } + + override void Tick() + { + Super.Tick(); + if (Vel.Z > 0 && Vel.Z < 0.5 && pos.z < floorz + 1) + { + Destroy (); + } + } + +} + +class SGShard1 : GlassShard +{ + States + { + Spawn: + SGSA ABCDE 4; + Loop; + Death: + SGSA E 30; + Stop; + } +} + +class SGShard2 : GlassShard +{ + States + { + Spawn: + SGSA FGHIJ 4; + Loop; + Death: + SGSA J 30; + Stop; + } +} + +class SGShard3 : GlassShard +{ + States + { + Spawn: + SGSA KLMNO 4; + Loop; + Death: + SGSA O 30; + Stop; + } +} + +class SGShard4 : GlassShard +{ + States + { + Spawn: + SGSA PQRST 4; + Loop; + Death: + SGSA T 30; + Stop; + } +} + +class SGShard5 : GlassShard +{ + States + { + Spawn: + SGSA UVWXY 4; + Loop; + Death: + SGSA Y 30; + Stop; + } +} + +class SGShard6 : GlassShard +{ + States + { + Spawn: + SGSB A 4; + Loop; + Death: + SGSB A 30; + Stop; + } +} + +class SGShard7 : GlassShard +{ + States + { + Spawn: + SGSB B 4; + Loop; + Death: + SGSB B 30; + Stop; + } +} + +class SGShard8 : GlassShard +{ + States + { + Spawn: + SGSB C 4; + Loop; + Death: + SGSB C 30; + Stop; + } +} + +class SGShard9 : GlassShard +{ + States + { + Spawn: + SGSB D 4; + Loop; + Death: + SGSB D 30; + Stop; + } +} + +class SGShard0 : GlassShard +{ + States + { + Spawn: + SGSB E 4; + Loop; + Death: + SGSB E 30; + Stop; + } +} + +class GlassJunk : Actor +{ + Default + { + +NOCLIP + +NOBLOCKMAP + RenderStyle "Translucent"; + Alpha 0.4; + Health 3; // Number of different shards + } + States + { + // Are the first three frames used anywhere? + SHAR A 128; + Goto Death; + SHAR B 128; + Goto Death; + SHAR C 128; + Goto Death; + Spawn: + SHAR D 128; + Goto Death; + SHAR E 128; + Goto Death; + SHAR F 128; + Goto Death; + Death: + "----" A 1 A_FadeOut(0.03); + Wait; + } +} diff --git a/wadsrc/static/zscript/shared/decal.txt b/wadsrc/static/zscript/shared/decal.txt new file mode 100644 index 0000000000..0614f6235c --- /dev/null +++ b/wadsrc/static/zscript/shared/decal.txt @@ -0,0 +1,3 @@ +class Decal : Actor native +{ +} diff --git a/wadsrc/static/zscript/shared/dog.txt b/wadsrc/static/zscript/shared/dog.txt new file mode 100644 index 0000000000..663dd6b980 --- /dev/null +++ b/wadsrc/static/zscript/shared/dog.txt @@ -0,0 +1,47 @@ +class MBFHelperDog : Actor +{ + default + { + Health 500; + Speed 10; + PainChance 180; + Radius 12; + Height 28; + Mass 100; + Monster; + +JUMPDOWN + ActiveSound "dog/active"; + AttackSound "dog/attack"; + DeathSound "dog/death"; + PainSound "dog/pain"; + SeeSound "dog/sight"; + Obituary "$OB_DOG"; + } + States + { + Spawn: + DOGS AB 10 A_Look; + Loop; + See: + DOGS AABBCCDD 2 A_Chase; + Loop; + Melee: + DOGS EF 8 A_FaceTarget; + DOGS G 8 A_SargAttack; + Goto See; + Pain: + DOGS H 2; + DOGS H 2 A_Pain; + Goto See; + Death: + DOGS I 8; + DOGS J 8 A_Scream; + DOGS K 4; + DOGS L 4 A_Fall; + DOGS M 4; + DOGS N -1; + Raise: + DOGS NMLKJI 5; + Goto See; + } +} diff --git a/wadsrc/static/zscript/shared/dynlights.txt b/wadsrc/static/zscript/shared/dynlights.txt new file mode 100644 index 0000000000..55698f079c --- /dev/null +++ b/wadsrc/static/zscript/shared/dynlights.txt @@ -0,0 +1,159 @@ +class DynamicLight : Actor native +{ + Default + { + Height 0; + Radius 0.1; + FloatBobPhase 0; + +NOBLOCKMAP + +NOGRAVITY + +FIXMAPTHINGPOS + +INVISIBLE + } +} + + +class PointLight : DynamicLight +{ + Default + { + DynamicLight.Type "Point"; + } +} + +class PointLightPulse : PointLight +{ + Default + { + DynamicLight.Type "Pulse"; + } +} + +class PointLightFlicker : PointLight +{ + Default + { + DynamicLight.Type "Flicker"; + } +} + +class SectorPointLight : PointLight +{ + Default + { + DynamicLight.Type "Sector"; + } +} + +class PointLightFlickerRandom : PointLight +{ + Default + { + DynamicLight.Type "RandomFlicker"; + } +} + +// MISSILEMORE and MISSILEEVENMORE are used by the lights for additive and subtractive lights + +class PointLightAdditive : PointLight +{ + Default + { + +MISSILEMORE + } +} + +class PointLightPulseAdditive : PointLightPulse +{ + Default + { + +MISSILEMORE + } +} + +class PointLightFlickerAdditive : PointLightFlicker +{ + Default + { + +MISSILEMORE + } +} + +class SectorPointLightAdditive : SectorPointLight +{ + Default + { + +MISSILEMORE + } +} + +class PointLightFlickerRandomAdditive :PointLightFlickerRandom +{ + Default + { + +MISSILEMORE + } +} + +class PointLightSubtractive : PointLight +{ + Default + { + +MISSILEEVENMORE + } +} + +class PointLightPulseSubtractive : PointLightPulse +{ + Default + { + +MISSILEEVENMORE + } +} + +class PointLightFlickerSubtractive : PointLightFlicker +{ + Default + { + +MISSILEEVENMORE + } +} + +class SectorPointLightSubtractive : SectorPointLight +{ + Default + { + +MISSILEEVENMORE + } +} + +class PointLightFlickerRandomSubtractive : PointLightFlickerRandom +{ + Default + { + +MISSILEEVENMORE + } +} + + +class VavoomLight : DynamicLight native +{ + Default + { + } +} + +class VavoomLightWhite : VavoomLight native +{ + Default + { + } +} + +class VavoomLightColor : VavoomLight native +{ + Default + { + } +} + diff --git a/wadsrc/static/zscript/shared/fastprojectile.txt b/wadsrc/static/zscript/shared/fastprojectile.txt new file mode 100644 index 0000000000..b1d5090738 --- /dev/null +++ b/wadsrc/static/zscript/shared/fastprojectile.txt @@ -0,0 +1,41 @@ +// Fast projectiles -------------------------------------------------------- + +class FastProjectile : Actor native +{ + Default + { + Projectile; + MissileHeight 0; + } + + + virtual void Effect() + { + class trail = MissileName; + if (trail != null) + { + double hitz = pos.z - 8; + + if (hitz < floorz) + { + hitz = floorz; + } + // Do not clip this offset to the floor. + hitz += MissileHeight; + + Actor act = Spawn (trail, (pos.xy, hitz), ALLOW_REPLACE); + if (act != null) + { + if (bGetOwner && target != null) + act.target = target; + else + act.target = self; + + act.angle = angle; + act.pitch = pitch; + } + } + } + +} + diff --git a/wadsrc/static/zscript/shared/fountain.txt b/wadsrc/static/zscript/shared/fountain.txt new file mode 100644 index 0000000000..60129a8c59 --- /dev/null +++ b/wadsrc/static/zscript/shared/fountain.txt @@ -0,0 +1,66 @@ +class ParticleFountain : Actor native +{ + default + { + Height 0; + +NOBLOCKMAP + +NOGRAVITY + +INVISIBLE + } +} + +class RedParticleFountain : ParticleFountain +{ + default + { + Health 1; + } +} + +class GreenParticleFountain : ParticleFountain +{ + default + { + Health 2; + } +} + +class BlueParticleFountain : ParticleFountain +{ + default + { + Health 3; + } +} + +class YellowParticleFountain : ParticleFountain +{ + default + { + Health 4; + } +} + +class PurpleParticleFountain : ParticleFountain +{ + default + { + Health 5; + } +} + +class BlackParticleFountain : ParticleFountain +{ + default + { + Health 6; + } +} + +class WhiteParticleFountain : ParticleFountain +{ + default + { + Health 7; + } +} diff --git a/wadsrc/static/zscript/shared/hatetarget.txt b/wadsrc/static/zscript/shared/hatetarget.txt new file mode 100644 index 0000000000..e90abcdbb8 --- /dev/null +++ b/wadsrc/static/zscript/shared/hatetarget.txt @@ -0,0 +1,50 @@ + + +// Hate Target -------------------------------------------------------------- + +class HateTarget : Actor +{ + default + { + Radius 20; + Height 56; + +SHOOTABLE + +NOGRAVITY + +NOBLOOD + +DONTSPLASH + Mass 0x7fffffff; + } + States + { + Spawn: + TNT1 A -1; + } + + override void BeginPlay() + { + Super.BeginPlay(); + if (SpawnAngle != 0) + { // Each degree translates into 10 units of health + health = SpawnAngle * 10; + } + else + { + special2 = 1; + health = 1000001; + } + } + + override int TakeSpecialDamage(Actor inflictor, Actor source, int damage, Name damagetype) + { + if (special2 != 0) + { + return 0; + } + else + { + return damage; + } + } + + +} \ No newline at end of file diff --git a/wadsrc/static/zscript/shared/ice.txt b/wadsrc/static/zscript/shared/ice.txt new file mode 100644 index 0000000000..9b72e2455d --- /dev/null +++ b/wadsrc/static/zscript/shared/ice.txt @@ -0,0 +1,73 @@ + + +//========================================================================== +// +// Ice chunk +// +//========================================================================== + +class IceChunk : Actor +{ + Default + { + Radius 3; + Height 4; + Mass 5; + Gravity 0.125; + +DROPOFF + +CANNOTPUSH + +FLOORCLIP + +NOTELEPORT + +NOBLOCKMAP + +MOVEWITHSECTOR + } + + void A_IceSetTics () + { + tics = 70 + (random[IceTics]() & 63); + Name dtype = GetFloorTerrain().DamageMOD; + if (dtype == 'Fire') + { + tics >>= 2; + } + else if (dtype == 'Ice') + { + tics <<= 1; + } + } + + States + { + Spawn: + ICEC ABCD 10 A_IceSetTics; + Stop; + } +} + +//========================================================================== +// +// A chunk of ice that is also a player +// +//========================================================================== + +class IceChunkHead : PlayerChunk +{ + Default + { + Radius 3; + Height 4; + Mass 5; + Gravity 0.125; + DamageType "Ice"; + +DROPOFF + +CANNOTPUSH + } + States + { + Spawn: + ICEC A 0; + ICEC A 10 A_CheckPlayerDone; + wait; + } +} + diff --git a/wadsrc/static/zscript/shared/inv_misc.txt b/wadsrc/static/zscript/shared/inv_misc.txt new file mode 100644 index 0000000000..032c9e8266 --- /dev/null +++ b/wadsrc/static/zscript/shared/inv_misc.txt @@ -0,0 +1,87 @@ +class ScoreItem : Inventory +{ + Default + { + Height 10; + +COUNTITEM + Inventory.Amount 1; + +Inventory.ALWAYSPICKUP + } + + override bool TryPickup (in out Actor toucher) + { + toucher.Score += Amount; + GoAwayAndDie(); + return true; + } +} + +class Health : Inventory native +{ + native int PrevHealth; + + Default + { + Inventory.Amount 1; + Inventory.MaxAmount 0; + Inventory.PickupSound "misc/health_pkup"; + } +} + +class HealthPickup : Inventory native +{ + native int autousemode; + + Default + { + Inventory.DefMaxAmount; + +INVENTORY.INVBAR + } +} + +class Key : Inventory native +{ + native uint8 KeyNumber; + + Default + { + +DONTGIB; // Don't disappear due to a crusher + Inventory.InterHubAmount 0; + Inventory.PickupSound "misc/k_pkup"; + } +} + +class MapRevealer : Inventory +{ + //=========================================================================== + // + // AMapRevealer :: TryPickup + // + // A MapRevealer reveals the whole map for the player who picks it up. + // The MapRevealer doesn't actually go in your inventory. Instead, it sets + // a flag on the level. + // + //=========================================================================== + + override bool TryPickup (in out Actor toucher) + { + level.allmap = true; + GoAwayAndDie (); + return true; + } +} + +class PuzzleItem : Inventory native +{ + native int PuzzleItemNumber; + + Default + { + +NOGRAVITY + +INVENTORY.INVBAR + Inventory.DefMaxAmount; + Inventory.UseSound "PuzzleSuccess"; + Inventory.PickupSound "misc/i_pkup"; + } +} + diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt new file mode 100644 index 0000000000..06e4d75525 --- /dev/null +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -0,0 +1,116 @@ +class Inventory : Actor native +{ + + native Actor Owner; // Who owns this item? NULL if it's still a pickup. + native int Amount; // Amount of item this instance has + native int MaxAmount; // Max amount of item this instance can have + native int InterHubAmount; // Amount of item that can be kept between hubs or levels + native int RespawnTics; // Tics from pickup time to respawn time + native TextureID Icon; // Icon to show on status bar or HUD + native int DropTime; // Countdown after dropping + native Class SpawnPointClass; // For respawning like Heretic's mace + native Class PickupFlash; // actor to spawn as pickup flash + native Sound PickupSound; + native bool bPickupGood; + native bool bCreateCopyMoved; + native bool bInitEffectFailed; + + Default + { + Inventory.Amount 1; + Inventory.MaxAmount 1; + Inventory.InterHubAmount 1; + Inventory.UseSound "misc/invuse"; + Inventory.PickupSound "misc/i_pkup"; + Inventory.PickupMessage "$TXT_DEFAULTPICKUPMSG"; + } + + virtual native bool Use (bool pickup); + virtual native color GetBlend (); + virtual native bool HandlePickup(Inventory item); + virtual native Inventory CreateCopy(Actor other); + virtual native Inventory CreateTossable(); + virtual native bool SpecialDropAction (Actor dropper); + virtual native String PickupMessage(); + virtual native bool ShouldStay(); + virtual native void DoEffect(); + virtual native void PlayPickupSound(Actor user); + virtual native void AttachToOwner(Actor user); + virtual native void DetachFromOwner(); + + virtual double GetSpeedFactor() { return 1; } + virtual bool GetNoTeleportFreeze() { return false; } + + native void GoAwayAndDie(); + native void BecomeItem(); + native void BecomePickup(); + + // These are regular functions for the item itself. + private native void A_RestoreSpecialDoomThing(); + private native void A_RestoreSpecialThing1(); + private native void A_RestoreSpecialThing2(); + + // In this case the caller function is more than a simple wrapper around the virtual method and + // is what must be actually called to pick up an item. + virtual protected native bool TryPickup(in out Actor toucher); + virtual protected native bool TryPickupRestricted(in out Actor toucher); + native bool, Actor CallTryPickup(Actor toucher); + + States(Actor, Overlay, Weapon, Item) + { + HideDoomish: + TNT1 A 1050; + TNT1 A 0 A_RestoreSpecialPosition; + TNT1 A 1 A_RestoreSpecialDoomThing; + Stop; + HideSpecial: + ACLO E 1400; + ACLO A 0 A_RestoreSpecialPosition; + ACLO A 4 A_RestoreSpecialThing1; + ACLO BABCBCDC 4; + ACLO D 4 A_RestoreSpecialThing2; + Stop; + Held: + TNT1 A -1; + Stop; + HoldAndDestroy: + TNT1 A 1; + Stop; + } +} + +class StateProvider : Inventory native +{ + action native state A_JumpIfNoAmmo(statelabel label); + action native void A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class pufftype = "BulletPuff", double range = 0, double lifesteal = 0, int lifestealmax = 0, class armorbonustype = "ArmorBonus", sound MeleeSound = 0, sound MissSound = ""); + action native void A_FireBullets(double spread_xy, double spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", int flags = 1, double range = 0, class missile = null, double Spawnheight = 32, double Spawnofs_xy = 0); + action native void A_FireCustomMissile(class missiletype, double angle = 0, bool useammo = true, double spawnofs_xy = 0, double spawnheight = 0, int flags = 0, double pitch = 0); + action native void A_RailAttack(int damage, int spawnofs_xy = 0, bool useammo = true, color color1 = 0, color color2 = 0, int flags = 0, double maxdiff = 0, class pufftype = "BulletPuff", double spread_xy = 0, double spread_z = 0, double range = 0, int duration = 0, double sparsity = 1.0, double driftspeed = 1.0, class spawnclass = "none", double spawnofs_z = 0, int spiraloffset = 270, int limit = 0); + action native void A_WeaponReady(int flags = 0); + action native void A_Lower(); + action native void A_Raise(); + + action native void A_ReFire(statelabel flash = null); + action native void A_ClearReFire(); + action native void A_CheckReload(); + action native void A_GunFlash(statelabel flash = null, int flags = 0); + action native state A_CheckForReload(int counter, statelabel label, bool dontincrement = false); + action native void A_ResetReloadCounter(); +} + +class DehackedPickup : Inventory native +{ +} + +class FakeInventory : Inventory native +{ + native bool Respawnable; +} + +class CustomInventory : StateProvider native +{ + Default + { + DefaultStateUsage SUF_ACTOR|SUF_OVERLAY|SUF_ITEM; + } +} diff --git a/wadsrc/static/actors/shared/pickups.txt b/wadsrc/static/zscript/shared/itemeffects.txt similarity index 65% rename from wadsrc/static/actors/shared/pickups.txt rename to wadsrc/static/zscript/shared/itemeffects.txt index a9ee0b2d7f..8e1e88233d 100644 --- a/wadsrc/static/actors/shared/pickups.txt +++ b/wadsrc/static/zscript/shared/itemeffects.txt @@ -4,28 +4,34 @@ // /***************************************************************************/ -ACTOR ItemFog +class ItemFog : Actor { - +NOBLOCKMAP - +NOGRAVITY + default + { + +NOBLOCKMAP + +NOGRAVITY + } States { Spawn: - IFOG ABABCDE 6 BRIGHT - Stop + IFOG ABABCDE 6 BRIGHT; + Stop; } } // Pickup flash ------------------------------------------------------------- -ACTOR PickupFlash +class PickupFlash : Actor { - +NOGRAVITY + default + { + +NOGRAVITY + } States { Spawn: - ACLO DCDCBCBABA 3 - Stop + ACLO DCDCBCBABA 3; + Stop; } } diff --git a/wadsrc/static/zscript/shared/mapmarker.txt b/wadsrc/static/zscript/shared/mapmarker.txt new file mode 100644 index 0000000000..25e1973077 --- /dev/null +++ b/wadsrc/static/zscript/shared/mapmarker.txt @@ -0,0 +1,49 @@ +// Map Marker -------------------------------------------------------------- +// +// This class uses the following argument: +// args[0] == 0, shows the sprite at this actor +// != 0, shows the sprite for all actors whose TIDs match instead +// +// args[1] == 0, show the sprite always +// == 1, show the sprite only after its sector has been drawn +// +// To enable display of the sprite, activate it. To turn off the sprite, +// deactivate it. +// +// All the code to display it is in am_map.cpp. +// +//-------------------------------------------------------------------------- + +class MapMarker : Actor +{ + default + { + +NOBLOCKMAP + +NOGRAVITY + +DONTSPLASH + +INVISIBLE + Scale 0.5; + } + States + { + Spawn: + AMRK A -1; + Stop; + } + + override void BeginPlay () + { + ChangeStatNum (STAT_MAPMARKER); + } + + override void Activate (Actor activator) + { + bDormant = true; + } + + override void Deactivate (Actor activator) + { + bDormant = false; + } + +} diff --git a/wadsrc/static/zscript/shared/morph.txt b/wadsrc/static/zscript/shared/morph.txt new file mode 100644 index 0000000000..c5c2cbe0a7 --- /dev/null +++ b/wadsrc/static/zscript/shared/morph.txt @@ -0,0 +1,30 @@ +class MorphProjectile : Actor native +{ + + native Class PlayerClass; + native Class MonsterClass, MorphFlash, UnMorphFlash; + native int Duration, MorphStyle; + + Default + { + Damage 1; + Projectile; + -ACTIVATEIMPACT + -ACTIVATEPCROSS + } +} + +class MorphedMonster : Actor native +{ + native Actor UnmorphedMe; + native int UnmorphTime, MorphStyle; + native Class MorphExitFlash; + + Default + { + Monster; + -COUNTKILL + +FLOORCLIP + } +} + diff --git a/wadsrc/static/zscript/shared/movingcamera.txt b/wadsrc/static/zscript/shared/movingcamera.txt new file mode 100644 index 0000000000..c5b8534db4 --- /dev/null +++ b/wadsrc/static/zscript/shared/movingcamera.txt @@ -0,0 +1,46 @@ +class InterpolationPoint : Actor native +{ + default + { + +NOBLOCKMAP + +NOGRAVITY + +DONTSPLASH + RenderStyle "None"; + } +} + +class InterpolationSpecial : Actor native +{ + default + { + +NOBLOCKMAP + +NOSECTOR + +NOGRAVITY + +DONTSPLASH + } +} + +class PathFollower : Actor native +{ + default + { + +NOBLOCKMAP + +NOSECTOR + +NOGRAVITY + +DONTSPLASH + } +} + +class ActorMover : PathFollower native +{ +} + +class MovingCamera : PathFollower native +{ + default + { + CameraHeight 0; + } +} + + diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt new file mode 100644 index 0000000000..2f6dc4bc19 --- /dev/null +++ b/wadsrc/static/zscript/shared/player.txt @@ -0,0 +1,264 @@ +class PlayerPawn : Actor native +{ + + native int crouchsprite; + native int MaxHealth; + native int MugShotMaxHealth; + native int RunHealth; + native int PlayerFlags; + native Inventory InvFirst; // first inventory item displayed on inventory bar + native Inventory InvSel; // selected inventory item + native meta String DisplayName; // Display name (used in menus, etc.) + native meta String SoundClass; // Sound class + native meta String Face; // Doom status bar face (when used) + native meta String Portrait; + native meta String Slot[10]; + native meta Name InvulMode; + native meta Name HealingRadiusType; + native meta double HexenArmor[5]; + native meta uint8 ColorRangeStart; // Skin color range + native meta uint8 ColorRangeEnd; + //FPlayerColorSetMap ColorSets; + //PainFlashList PainFlashes; + + // [GRB] Player class properties + native double JumpZ; + native double GruntSpeed; + native double FallingScreamMinSpeed, FallingScreamMaxSpeed; + native double ViewHeight; + native double ForwardMove1, ForwardMove2; + native double SideMove1, SideMove2; + native TextureID ScoreIcon; + native int SpawnMask; + native Name MorphWeapon; + native double AttackZOffset; // attack height, relative to player center + native double UseRange; // [NS] Distance at which player can +use + native double AirCapacity; // Multiplier for air supply underwater. + native Class FlechetteType; + native color DamageFade; // [CW] Fades for when you are being damaged. + native double ViewBob; // [SP] ViewBob Multiplier + + Default + { + Health 100; + Radius 16; + Height 56; + Mass 100; + Painchance 255; + Speed 1; + +SOLID + +SHOOTABLE + +DROPOFF + +PICKUP + +NOTDMATCH + +FRIENDLY + +SLIDESONWALLS + +CANPASS + +CANPUSHWALLS + +FLOORCLIP + +WINDTHRUST + +TELESTOMP + +NOBLOCKMONST + Player.AttackZOffset 8; + Player.JumpZ 8; + Player.GruntSpeed 12; + Player.FallingScreamSpeed 35,40; + Player.ViewHeight 41; + Player.UseRange 64; + Player.ForwardMove 1,1; + Player.SideMove 1,1; + Player.ColorRange 0,0; + Player.SoundClass "player"; + Player.DamageScreenColor "ff 00 00"; + Player.MugShotMaxHealth 0; + Player.FlechetteType "ArtiPoisonBag3"; + Player.AirCapacity 1; + Player.ViewBob 1; + Obituary "$OB_MPDEFAULT"; + } + + virtual void PlayIdle () + { + if (InStateSequence(CurState, SeeState)) + SetState (SpawnState); + } + + virtual void PlayRunning () + { + if (InStateSequence(CurState, SpawnState) && SeeState != NULL) + SetState (SeeState); + } + + virtual void PlayAttacking () + { + if (MissileState != null) SetState (MissileState); + } + + virtual void PlayAttacking2 () + { + if (MeleeState != null) SetState (MeleeState); + } + + virtual void MorphPlayerThink() + { + } + + native int GetMaxHealth(); + native bool ResetAirSupply (bool playgasp = false); +} + +class PlayerChunk : PlayerPawn native +{ + Default + { + +NOSKIN + -SOLID + -SHOOTABLE + -PICKUP + -NOTDMATCH + -FRIENDLY + -SLIDESONWALLS + -CANPUSHWALLS + -FLOORCLIP + -WINDTHRUST + -TELESTOMP + } +} + +class PSprite : Object native +{ + native readonly State CurState; + native readonly Actor Caller; + native readonly PSprite Next; + native readonly PlayerInfo Owner; + native SpriteID Sprite; + native int Frame; + native readonly int ID; + native Bool processPending; + native double x; + native double y; + native double oldx; + native double oldy; + native Bool firstTic; + native int Tics; + native bool bAddWeapon; + native bool bAddBob; + native bool bPowDouble; + native bool bCVarFast; + native bool bFlip; + + native void SetState(State newstate, bool pending = false); + +} + +enum EPlayerState +{ + PST_LIVE, // Playing or camping. + PST_DEAD, // Dead on the ground, view follows killer. + PST_REBORN, // Ready to restart/respawn??? + PST_ENTER, // [BC] Entered the game + PST_GONE // Player has left the game +} + +struct PlayerInfo native // this is what internally is known as player_t +{ + native readonly PlayerPawn mo; + native uint8 playerstate; + native uint original_oldbuttons; + native readonly Class cls; + native float DesiredFOV; + native readonly float FOV; + native double viewz; + native double viewheight; + native double deltaviewheight; + native double bob; + native vector2 vel; + native bool centering; + native uint8 turnticks; + native bool attackdown; + native bool usedown; + native uint oldbuttons; + native int health; + native int inventorytics; + native uint8 CurrentPlayerClass; + native int frags[MAXPLAYERS]; + native int fragcount; + native int lastkilltime; + native uint8 multicount; + native uint8 spreecount; + native uint16 WeaponState; + native Weapon ReadyWeapon; + native Weapon PendingWeapon; + native PSprite psprites; + native int cheats; + native int timefreezer; + native int16 refire; + native int16 inconsistent; + native bool waiting; + native int killcount; + native int itemcount; + native int secretcount; + native int damagecount; + native int bonuscount; + native int hazardcount; + native int hazardinterval; + native Name hazardtype; + native int poisoncount; + native Name poisontype; + native Name poisonpaintype; + native Actor poisoner; + native Actor attacker; + native int extralight; + native int16 fixedcolormap; + native int16 fixedlightlevel; + native int morphtics; + native ClassMorphedPlayerClass; + native int MorphStyle; + native Class MorphExitFlash; + native Class PremorphWeapon; + native int chickenPeck; + native int jumpTics; + native bool onground; + native int respawn_time; + native Actor camera; + native int air_finished; + native Name LastDamageType; + native Actor MUSINFOactor; + native int8 MUSINFOtics; + native bool settings_controller; + native int8 crouching; + native int8 crouchdir; + native Bot bot; + native float BlendR; + native float BlendG; + native float BlendB; + native float BlendA; + native String LogText; + native double MinPitch; + native double MaxPitch; + native double crouchfactor; + native double crouchoffset; + native double crouchviewdelta; + native Actor ConversationNPC; + native Actor ConversationPC; + native double ConversationNPCAngle; + native bool ConversationFaceTalker; +/* these are not doable yet +ticcmd_t cmd; +usercmd_t original_cmd; +userinfo_t userinfo; // [RH] who is this? +FWeaponSlots weapons; +*/ + + + native bool UndoPlayerMorph(playerinfo player, int unmorphflag = 0, bool force = false); + native bool PoisonPlayer(Actor poisoner, Actor source, int poison); + native void PoisonDamage(Actor source, int damage, bool playPainSound); + native void SetPsprite(int id, State stat, bool pending = false); + native void SetSafeFlash(Weapon weap, State flashstate, int index); + native PSprite GetPSprite(int id); + native PSprite FindPSprite(int id); + native void SetLogNumber (int text); + native void SetLogText (String text); + +} diff --git a/wadsrc/static/zscript/shared/powerups.txt b/wadsrc/static/zscript/shared/powerups.txt new file mode 100644 index 0000000000..d28799ff23 --- /dev/null +++ b/wadsrc/static/zscript/shared/powerups.txt @@ -0,0 +1,288 @@ +class PowerupGiver : Inventory native +{ + + native Class PowerupType; + native int EffectTics; // Non-0 to override the powerup's default tics + native color BlendColor; // Non-0 to override the powerup's default blend + native Name Mode; // Meaning depends on powerup - used for Invulnerability and Invisibility + native double Strength; // Meaning depends on powerup - currently used only by Invisibility + + Default + { + Inventory.DefMaxAmount; + +INVENTORY.INVBAR + +INVENTORY.FANCYPICKUPSOUND + Inventory.PickupSound "misc/p_pkup"; + } +} + +class Powerup : Inventory native +{ + native int EffectTics; + native color BlendColor; + native Name Mode; // Meaning depends on powerup - used for Invulnerability and Invisibility + native double Strength; // Meaning depends on powerup - currently used only by Invisibility + + // Note, that while this is an inventory flag, it only has meaning on an active powerup. + override bool GetNoTeleportFreeze() { return bNoTeleportFreeze; } + +} + +class PowerInvulnerable : Powerup native +{ + Default + { + Powerup.Duration -30; + inventory.icon "SPSHLD0"; + } +} + +class PowerStrength : Powerup native +{ + Default + { + Powerup.Duration 1; + Powerup.Color "ff 00 00", 0.5; + +INVENTORY.HUBPOWER + } +} + +class PowerInvisibility : Powerup native +{ + Default + { + +SHADOW; + Powerup.Duration -60; + Powerup.Strength 80; + Powerup.Mode "Fuzzy"; + } +} + +class PowerGhost : PowerInvisibility +{ + Default + { + +GHOST; + Powerup.Duration -60; + Powerup.Strength 60; + Powerup.Mode "None"; + } +} + +class PowerShadow : PowerInvisibility +{ + Default + { + +INVENTORY.HUBPOWER + Powerup.Duration -55; + Powerup.Strength 75; + Powerup.Mode "Cumulative"; + } +} + +class PowerIronFeet : Powerup native +{ + Default + { + Powerup.Duration -60; + Powerup.Color "00 ff 00", 0.125; + } +} + +class PowerMask : PowerIronFeet native +{ + Default + { + Powerup.Duration -80; + Powerup.Color "00 00 00", 0; + +INVENTORY.HUBPOWER + Inventory.Icon "I_MASK"; + } +} + +class PowerLightAmp : Powerup native +{ + Default + { + Powerup.Duration -120; + } +} + +class PowerTorch : PowerLightAmp native {} + +class PowerFlight : Powerup native +{ + Default + { + Powerup.Duration -60; + +INVENTORY.HUBPOWER + } +} + +class PowerWeaponLevel2 : Powerup native +{ + Default + { + Powerup.Duration -40; + Inventory.Icon "SPINBK0"; + +INVENTORY.NOTELEPORTFREEZE + } +} + +class PowerSpeed : Powerup native +{ + native int SpeedFlags; + + Default + { + Powerup.Duration -45; + Speed 1.5; + Inventory.Icon "SPBOOT0"; + +INVENTORY.NOTELEPORTFREEZE + } + + override double GetSpeedFactor() { return Speed; } +} + +// Player Speed Trail (used by the Speed Powerup) ---------------------------- + +class PlayerSpeedTrail : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + Alpha 0.6; + RenderStyle "Translucent"; + } + + override void Tick() + { + Alpha -= .6 / 8; + if (Alpha <= 0) + { + Destroy (); + } + } +} + +class PowerMinotaur : Powerup native +{ + Default + { + Powerup.Duration -25; + Inventory.Icon "SPMINO0"; + } +} + +class PowerTargeter : Powerup native +{ + Default + { + Powerup.Duration -160; + +INVENTORY.HUBPOWER + } + States + { + Targeter: + TRGT A -1; + Stop; + TRGT B -1; + Stop; + TRGT C -1; + Stop; + } +} + +class PowerFrightener : Powerup native +{ + Default + { + Powerup.Duration -60; + } +} + +class PowerBuddha : Powerup native +{ + Default + { + Powerup.Duration -60; + } +} + +class PowerScanner : Powerup native +{ + Default + { + Powerup.Duration -80; + +INVENTORY.HUBPOWER + } +} + +class PowerTimeFreezer : Powerup native +{ + Default + { + Powerup.Duration -12; + } +} + +class PowerDamage : Powerup native +{ + Default + { + Powerup.Duration -25; + } +} + +class PowerProtection : Powerup native +{ + Default + { + Powerup.Duration -25; + } +} + +class PowerDrain : Powerup native +{ + Default + { + Powerup.Duration -60; + } +} + +class PowerRegeneration : Powerup native +{ + Default + { + Powerup.Duration -120; + Powerup.Strength 5; + } +} + +class PowerHighJump : Powerup native {} + +class PowerDoubleFiringSpeed : Powerup native {} + +class PowerMorph : Powerup native +{ + native Class PlayerClass; + native Class MorphFlash, UnMorphFlash; + native int MorphStyle; + native PlayerInfo MorphedPlayer; + native bool bInUndoMorph; + + Default + { + Powerup.Duration -40; + } +} + +class PowerInfiniteAmmo : Powerup native +{ + Default + { + Powerup.Duration -30; + } +} + diff --git a/wadsrc/static/zscript/shared/secrettrigger.txt b/wadsrc/static/zscript/shared/secrettrigger.txt new file mode 100644 index 0000000000..c60399600d --- /dev/null +++ b/wadsrc/static/zscript/shared/secrettrigger.txt @@ -0,0 +1,26 @@ + +class SecretTrigger : Actor +{ + default + { + +NOBLOCKMAP + +NOSECTOR + +NOGRAVITY + +DONTSPLASH + } + + override void PostBeginPlay () + { + Super.PostBeginPlay (); + level.total_secrets++; + } + + override void Activate (Actor activator) + { + activator.GiveSecret(args[0] <= 1, (args[0] == 0 || args[0] == 2)); + Destroy (); + } + + +} + diff --git a/wadsrc/static/actors/shared/sectoraction.txt b/wadsrc/static/zscript/shared/sectoraction.txt similarity index 61% rename from wadsrc/static/actors/shared/sectoraction.txt rename to wadsrc/static/zscript/shared/sectoraction.txt index f8db34323f..03278f2d30 100644 --- a/wadsrc/static/actors/shared/sectoraction.txt +++ b/wadsrc/static/zscript/shared/sectoraction.txt @@ -1,81 +1,84 @@ -ACTOR SectorAction native +class SectorAction : Actor native { - +NOBLOCKMAP - +NOSECTOR - +NOGRAVITY - +DONTSPLASH + default + { + +NOBLOCKMAP + +NOSECTOR + +NOGRAVITY + +DONTSPLASH + } } // Triggered when entering sector ------------------------------------------- -ACTOR SecActEnter : SectorAction native +class SecActEnter : SectorAction native { } // Triggered when leaving sector -------------------------------------------- -ACTOR SecActExit : SectorAction native +class SecActExit : SectorAction native { } // Triggered when hitting sector's floor ------------------------------------ -ACTOR SecActHitFloor : SectorAction native +class SecActHitFloor : SectorAction native { } // Triggered when hitting sector's ceiling ---------------------------------- -ACTOR SecActHitCeil : SectorAction native +class SecActHitCeil : SectorAction native { } // Triggered when using inside sector --------------------------------------- -ACTOR SecActUse : SectorAction native +class SecActUse : SectorAction native { } // Triggered when using a sector's wall ------------------------------------- -ACTOR SecActUseWall : SectorAction native +class SecActUseWall : SectorAction native { } // Triggered when eyes go below fake floor ---------------------------------- -ACTOR SecActEyesDive : SectorAction native +class SecActEyesDive : SectorAction native { } // Triggered when eyes go above fake floor ---------------------------------- -ACTOR SecActEyesSurface : SectorAction native +class SecActEyesSurface : SectorAction native { } // Triggered when eyes go below fake floor ---------------------------------- -ACTOR SecActEyesBelowC : SectorAction native +class SecActEyesBelowC : SectorAction native { } // Triggered when eyes go above fake floor ---------------------------------- -ACTOR SecActEyesAboveC : SectorAction native +class SecActEyesAboveC : SectorAction native { } // Triggered when eyes go below fake floor ---------------------------------- -ACTOR SecActHitFakeFloor : SectorAction native +class SecActHitFakeFloor : SectorAction native { } // Music changer ---------------------------------- -ACTOR MusicChanger : SectorAction native +class MusicChanger : SectorAction native { } diff --git a/wadsrc/static/zscript/shared/setcolor.txt b/wadsrc/static/zscript/shared/setcolor.txt new file mode 100644 index 0000000000..18105ef543 --- /dev/null +++ b/wadsrc/static/zscript/shared/setcolor.txt @@ -0,0 +1,39 @@ +class ColorSetter : Actor +{ + default + { + +NOBLOCKMAP + +NOGRAVITY + +DONTSPLASH + RenderStyle "None"; + } + + override void PostBeginPlay() + { + Super.PostBeginPlay(); + CurSector.SetColor(color(args[0], args[1], args[2]), args[3]); + Destroy(); + } + +} + + +class FadeSetter : Actor +{ + default + { + +NOBLOCKMAP + +NOGRAVITY + +DONTSPLASH + RenderStyle "None"; + } + + void PostBeginPlay() + { + Super.PostBeginPlay(); + CurSector.SetFade(color(args[0], args[1], args[2])); + Destroy(); + } + + +} diff --git a/wadsrc/static/zscript/shared/sharedmisc.txt b/wadsrc/static/zscript/shared/sharedmisc.txt new file mode 100644 index 0000000000..1b5ad4ee98 --- /dev/null +++ b/wadsrc/static/zscript/shared/sharedmisc.txt @@ -0,0 +1,227 @@ + +// Default class for unregistered doomednums ------------------------------- + +class Unknown : Actor +{ + Default + { + Radius 32; + Height 56; + +NOGRAVITY + +NOBLOCKMAP + +DONTSPLASH + } + States + { + Spawn: + UNKN A -1; + Stop; + } +} + +// Route node for monster patrols ------------------------------------------- + +class PatrolPoint : Actor +{ + Default + { + Radius 8; + Height 8; + Mass 10; + +NOGRAVITY + +NOBLOCKMAP + +DONTSPLASH + RenderStyle "None"; + } +} + +// A special to execute when a monster reaches a matching patrol point ------ + +class PatrolSpecial : Actor +{ + Default + { + Radius 8; + Height 8; + Mass 10; + +NOGRAVITY + +NOBLOCKMAP + +DONTSPLASH + RenderStyle "None"; + } +} + +// Map spot ---------------------------------------------------------------- + +class MapSpot : Actor +{ + Default + { + +NOBLOCKMAP + +NOSECTOR + +NOGRAVITY + +DONTSPLASH + RenderStyle "None"; + CameraHeight 0; + } +} + +// same with different editor number for Legacy maps ----------------------- + +class FS_Mapspot : Mapspot +{ +} + +// Map spot with gravity --------------------------------------------------- + +class MapSpotGravity : MapSpot +{ + Default + { + -NOBLOCKMAP + -NOSECTOR + -NOGRAVITY + } +} + +// Point Pushers ----------------------------------------------------------- + +class PointPusher : Actor +{ + Default + { + +NOBLOCKMAP + +INVISIBLE + +NOCLIP + } +} + +class PointPuller : Actor +{ + Default + { + +NOBLOCKMAP + +INVISIBLE + +NOCLIP + } +} + +// Bloody gibs ------------------------------------------------------------- + +class RealGibs : Actor +{ + Default + { + +DROPOFF + +CORPSE + +NOTELEPORT + +DONTGIB + } + States + { + Spawn: + goto GenericCrush; + } +} + +// Gibs that can be placed on a map. --------------------------------------- +// +// These need to be a separate class from the above, in case someone uses +// a deh patch to change the gibs, since ZDoom actually creates a gib class +// for actors that get crushed instead of changing their state as Doom did. + +class Gibs : RealGibs +{ + Default + { + ClearFlags; + } +} + +// Needed for loading Build maps ------------------------------------------- + +class CustomSprite : Actor native +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + } + States + { + Spawn: + TNT1 A -1; + Stop; + } +} + +// SwitchableDecoration: Activate and Deactivate change state -------------- + +class SwitchableDecoration : Actor +{ + override void Activate (Actor activator) + { + SetStateLabel("Active"); + } + + override void Deactivate (Actor activator) + { + SetStateLabel("Inactive"); + } + +} + +class SwitchingDecoration : SwitchableDecoration +{ + override void Deactivate (Actor activator) + { + } +} + +// Random spawner ---------------------------------------------------------- + +class RandomSpawner : Actor native +{ + Default + { + +NOBLOCKMAP + +NOSECTOR + +NOGRAVITY + +THRUACTORS + } +} + +// Sector flag setter ------------------------------------------------------ + +class SectorFlagSetter : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + +DONTSPLASH + RenderStyle "None"; + } + + override void BeginPlay () + { + Super.BeginPlay (); + CurSector.Flags |= args[0]; + } +} + +// Marker for sounds : Actor ------------------------------------------------------- + +class SpeakerIcon : Unknown +{ + States + { + Spawn: + SPKR A -1 BRIGHT; + Stop; + } + Default + { + Scale 0.125; + } +} diff --git a/wadsrc/static/zscript/shared/skies.txt b/wadsrc/static/zscript/shared/skies.txt new file mode 100644 index 0000000000..35077ee5c6 --- /dev/null +++ b/wadsrc/static/zscript/shared/skies.txt @@ -0,0 +1,49 @@ +class SkyViewpoint : Actor native +{ + default + { + +NOSECTOR + +NOBLOCKMAP + +NOGRAVITY + +DONTSPLASH + } +} + +class SkyPicker : Actor native +{ + default + { + +NOSECTOR + +NOBLOCKMAP + +NOGRAVITY + +DONTSPLASH + } +} + +class SkyCamCompat : SkyViewpoint native +{ +} + +class StackPoint : SkyViewpoint native +{ +} + +class UpperStackLookOnly : StackPoint +{ +} + +class LowerStackLookOnly : StackPoint +{ +} + + +class SectorSilencer native +{ + default + { + +NOBLOCKMAP + +NOGRAVITY + +DONTSPLASH + RenderStyle "None"; + } +} diff --git a/wadsrc/static/zscript/shared/soundenvironment.txt b/wadsrc/static/zscript/shared/soundenvironment.txt new file mode 100644 index 0000000000..2a4d66adb5 --- /dev/null +++ b/wadsrc/static/zscript/shared/soundenvironment.txt @@ -0,0 +1,12 @@ + +class SoundEnvironment : Actor native +{ + default + { + +NOSECTOR + +NOBLOCKMAP + +NOGRAVITY + +DONTSPLASH + } +} + diff --git a/wadsrc/static/zscript/shared/soundsequence.txt b/wadsrc/static/zscript/shared/soundsequence.txt new file mode 100644 index 0000000000..97ff8e9aa8 --- /dev/null +++ b/wadsrc/static/zscript/shared/soundsequence.txt @@ -0,0 +1,121 @@ + +class AmbientSound : Actor native +{ + default + { + +NOBLOCKMAP + +NOSECTOR + +DONTSPLASH + } +} + +class AmbientSoundNoGravity : AmbientSound +{ + default + { + +NOGRAVITY + } +} + +class SoundSequenceSlot : Actor native +{ + default + { + +NOSECTOR + +NOBLOCKMAP + +DONTSPLASH + } +} + +class SoundSequence : Actor native +{ + default + { + +NOSECTOR + +NOBLOCKMAP + +DONTSPLASH + } +} + +// Heretic Sound sequences ----------------------------------------------------------- + +class HereticSoundSequence1 : SoundSequence +{ + default + { + Args 0; + } +} + +class HereticSoundSequence2 : SoundSequence +{ + default + { + Args 1; + } +} + +class HereticSoundSequence3 : SoundSequence +{ + default + { + Args 2; + } +} + +class HereticSoundSequence4 : SoundSequence +{ + default + { + Args 3; + } +} + +class HereticSoundSequence5 : SoundSequence +{ + default + { + Args 4; + } +} + +class HereticSoundSequence6 : SoundSequence +{ + default + { + Args 5; + } +} + +class HereticSoundSequence7 : SoundSequence +{ + default + { + Args 6; + } +} + +class HereticSoundSequence8 : SoundSequence +{ + default + { + Args 7; + } +} + +class HereticSoundSequence9 : SoundSequence +{ + default + { + Args 8; + } +} + +class HereticSoundSequence10 : SoundSequence +{ + default + { + Args 9; + } +} + diff --git a/wadsrc/static/zscript/shared/spark.txt b/wadsrc/static/zscript/shared/spark.txt new file mode 100644 index 0000000000..c5ae6a455c --- /dev/null +++ b/wadsrc/static/zscript/shared/spark.txt @@ -0,0 +1,19 @@ + +class Spark : Actor +{ + default + { + +NOSECTOR + +NOBLOCKMAP + +NOGRAVITY + +DONTSPLASH + } + + override void Activate (Actor activator) + { + Super.Activate (activator); + DrawSplash (args[0] ? args[0] : 32, Angle, 1); + A_PlaySound ("world/spark", CHAN_AUTO, 1, false, ATTN_STATIC); + } + +} \ No newline at end of file diff --git a/wadsrc/static/zscript/shared/specialspot.txt b/wadsrc/static/zscript/shared/specialspot.txt new file mode 100644 index 0000000000..c0bf84de56 --- /dev/null +++ b/wadsrc/static/zscript/shared/specialspot.txt @@ -0,0 +1,5 @@ + +class SpecialSpot : Actor native +{ + native void A_SpawnSingleItem(class type, int fail_sp = 0, int fail_co = 0, int fail_dm = 0); +} diff --git a/wadsrc/static/zscript/shared/splashes.txt b/wadsrc/static/zscript/shared/splashes.txt new file mode 100644 index 0000000000..8b16d85b86 --- /dev/null +++ b/wadsrc/static/zscript/shared/splashes.txt @@ -0,0 +1,273 @@ + +// Water -------------------------------------------------------------------- + +class WaterSplash : Actor +{ + default + { + Radius 2; + Height 4; + Gravity 0.125; + +NOBLOCKMAP + +MISSILE + +DROPOFF + +NOTELEPORT + +CANNOTPUSH + +DONTSPLASH + +DONTBLAST + } + States + { + Spawn: + SPSH ABC 8; + SPSH D 16; + Stop; + Death: + SPSH D 10; + Stop; + } +} + + +class WaterSplashBase : Actor +{ + default + { + +NOBLOCKMAP + +NOCLIP + +NOGRAVITY + +DONTSPLASH + +DONTBLAST + } + States + { + Spawn: + SPSH EFGHIJK 5; + Stop; + } +} + +// Lava --------------------------------------------------------------------- + +class LavaSplash : Actor +{ + default + { + +NOBLOCKMAP + +NOCLIP + +NOGRAVITY + +DONTSPLASH + +DONTBLAST + } + States + { + Spawn: + LVAS ABCDEF 5 Bright; + Stop; + } +} + +class LavaSmoke : Actor +{ + default + { + +NOBLOCKMAP + +NOCLIP + +NOGRAVITY + +DONTSPLASH + RenderStyle "Translucent"; + DefaultAlpha; + } + States + { + Spawn: + LVAS GHIJK 5 Bright; + Stop; + } +} + +// Sludge ------------------------------------------------------------------- + +class SludgeChunk : Actor +{ + default + { + Radius 2; + Height 4; + Gravity 0.125; + +NOBLOCKMAP + +MISSILE + +DROPOFF + +NOTELEPORT + +CANNOTPUSH + +DONTSPLASH + } + States + { + Spawn: + SLDG ABCD 8; + Stop; + Death: + SLDG D 6; + Stop; + } +} + +class SludgeSplash : Actor +{ + default + { + +NOBLOCKMAP + +NOCLIP + +NOGRAVITY + +DONTSPLASH + } + States + { + Spawn: + SLDG EFGH 6; + Stop; + } +} + +/* + * These next four classes are not used by me anywhere. + * They are for people who want to use them in a TERRAIN lump. + */ + +// Blood (water with a different sprite) ------------------------------------ + +class BloodSplash : Actor +{ + default + { + Radius 2; + Height 4; + Gravity 0.125; + +NOBLOCKMAP + +MISSILE + +DROPOFF + +NOTELEPORT + +CANNOTPUSH + +DONTSPLASH + +DONTBLAST + } + States + { + Spawn: + BSPH ABC 8; + BSPH D 16; + Stop; + Death: + BSPH D 10; + Stop; + } +} + + +class BloodSplashBase : Actor +{ + default + { + +NOBLOCKMAP + +NOCLIP + +NOGRAVITY + +DONTSPLASH + +DONTBLAST + } + States + { + Spawn: + BSPH EFGHIJK 5; + Stop; + } +} + +// Slime (sludge with a different sprite) ----------------------------------- + +class SlimeChunk : Actor +{ + default + { + Radius 2; + Height 4; + Gravity 0.125; + +NOBLOCKMAP + +MISSILE + +DROPOFF + +NOTELEPORT + +CANNOTPUSH + +DONTSPLASH + } + States + { + Spawn: + SLIM ABCD 8; + Stop; + Death: + SLIM D 6; + Stop; + } +} + +class SlimeSplash : Actor +{ + default + { + +NOBLOCKMAP + +NOCLIP + +NOGRAVITY + +DONTSPLASH + } + States + { + Spawn: + SLIM EFGH 6; + Stop; + } +} + +// Smoke trail for rocket ----------------------------------- + +class RocketSmokeTrail : Actor +{ + default + { + RenderStyle "Translucent"; + Alpha 0.4; + VSpeed 1; + +NOBLOCKMAP + +NOCLIP + +NOGRAVITY + +DONTSPLASH + +NOTELEPORT + } + States + { + Spawn: + RSMK ABCDE 5; + Stop; + } +} + +class GrenadeSmokeTrail : Actor +{ + default + { + RenderStyle "Translucent"; + Alpha 0.4; + +NOBLOCKMAP + +NOCLIP + +DONTSPLASH + +NOTELEPORT + Gravity 0.1; + VSpeed 0.5; + Scale 0.6; + } + States + { + Spawn: + RSMK ABCDE 4; + Stop; + } +} diff --git a/wadsrc/static/zscript/shared/teleport.txt b/wadsrc/static/zscript/shared/teleport.txt new file mode 100644 index 0000000000..55308415fe --- /dev/null +++ b/wadsrc/static/zscript/shared/teleport.txt @@ -0,0 +1,54 @@ + +class TeleportFog : Actor native +{ + default + { + +NOBLOCKMAP + +NOTELEPORT + +NOGRAVITY + RenderStyle "Add"; + } + States + { + Spawn: + TFOG ABABCDEFGHIJ 6 Bright; + Stop; + + Raven: + TELE ABCDEFGHGFEDC 6 Bright; + Stop; + + Strife: + TFOG ABCDEFEDCB 6 Bright; + Stop; + } +} + + + +class TeleportDest : Actor +{ + default + { + +NOBLOCKMAP + +NOSECTOR + +DONTSPLASH + } +} + +class TeleportDest2 : TeleportDest +{ + default + { + +NOGRAVITY + } +} + +class TeleportDest3 : TeleportDest2 +{ + default + { + -NOGRAVITY + } +} + diff --git a/wadsrc/static/zscript/shared/waterzone.txt b/wadsrc/static/zscript/shared/waterzone.txt new file mode 100644 index 0000000000..49d950b00d --- /dev/null +++ b/wadsrc/static/zscript/shared/waterzone.txt @@ -0,0 +1,19 @@ +class WaterZone : Actor +{ + default + { + +NOSECTOR + +NOBLOCKMAP + +NOGRAVITY + +DONTSPLASH + } + + override void PostBeginPlay () + { + Super.PostBeginPlay (); + CurSector.MoreFlags |= Sector.SECMF_UNDERWATER; + Destroy (); + } + + +} diff --git a/wadsrc/static/zscript/shared/weapons.txt b/wadsrc/static/zscript/shared/weapons.txt new file mode 100644 index 0000000000..c3ebf299dd --- /dev/null +++ b/wadsrc/static/zscript/shared/weapons.txt @@ -0,0 +1,144 @@ +class Weapon : StateProvider native +{ + enum EFireMode + { + PrimaryFire, + AltFire, + EitherFire + }; + + native uint WeaponFlags; + native class AmmoType1, AmmoType2; // Types of ammo used by this weapon + native int AmmoGive1, AmmoGive2; // Amount of each ammo to get when picking up weapon + native int MinAmmo1, MinAmmo2; // Minimum ammo needed to switch to this weapon + native int AmmoUse1, AmmoUse2; // How much ammo to use with each shot + native int Kickback; + native float YAdjust; // For viewing the weapon fullscreen (visual only so no need to be a double) + native sound UpSound, ReadySound; // Sounds when coming up and idle + native class SisterWeaponType; // Another weapon to pick up with this one + native class ProjectileType; // Projectile used by primary attack + native class AltProjectileType; // Projectile used by alternate attack + native int SelectionOrder; // Lower-numbered weapons get picked first + native int MinSelAmmo1, MinSelAmmo2; // Ignore in BestWeapon() if inadequate ammo + native double MoveCombatDist; // Used by bots, but do they *really* need it? + native int ReloadCounter; // For A_CheckForReload + native int BobStyle; // [XA] Bobbing style. Defines type of bobbing (e.g. Normal, Alpha) (visual only so no need to be a double) + native float BobSpeed; // [XA] Bobbing speed. Defines how quickly a weapon bobs. + native float BobRangeX, BobRangeY; // [XA] Bobbing range. Defines how far a weapon bobs in either direction. + native Ammo Ammo1, Ammo2; // In-inventory instance variables + native Weapon SisterWeapon; + native float FOVScale; + native int Crosshair; // 0 to use player's crosshair + native bool GivenAsMorphWeapon; + native bool bAltFire; // Set when this weapon's alternate fire is used. + native readonly bool bDehAmmo; + + Default + { + Inventory.PickupSound "misc/w_pkup"; + Weapon.DefaultKickback; + Weapon.BobSpeed 1.0; + Weapon.BobRangeX 1.0; + Weapon.BobRangeY 1.0; + +WEAPONSPAWN + DefaultStateUsage SUF_ACTOR|SUF_OVERLAY|SUF_WEAPON; + } + States + { + LightDone: + SHTG E 0 A_Light0; + Stop; + } + + native bool CheckAmmo(int fireMode, bool autoSwitch, bool requireAmmo = false, int ammocount = -1); + native bool DepleteAmmo(bool altFire, bool checkEnough = true, int ammouse = -1); + native virtual void EndPowerup(); + + virtual State GetReadyState () + { + return FindState('Ready'); + } + + virtual State GetUpState () + { + return FindState('Select'); + } + + virtual State GetDownState () + { + return FindState('Deselect'); + } + + virtual State GetAtkState (bool hold) + { + State s = null; + if (hold) s = FindState('Hold'); + if (s == null) s = FindState('Fire'); + return s; + } + + virtual State GetAltAtkState (bool hold) + { + State s = null; + if (hold) s = FindState('AltHold'); + if (s == null) s = FindState('AltFire'); + return s; + } + + native action void A_ZoomFactor(double scale = 1, int flags = 0); + native action void A_SetCrosshair(int xhair); + const ZOOM_INSTANT = 1; + const ZOOM_NOSCALETURNING = 2; + +} + +class WeaponGiver : Weapon native +{ + + native double DropAmmoFactor; + + Default + { + Weapon.AmmoGive1 -1; + Weapon.AmmoGive2 -1; + } +} + +class WeaponHolder : Inventory native +{ + native int PieceMask; + native Class PieceWeapon; + + Default + { + +NOBLOCKMAP + +NOSECTOR + +INVENTORY.UNDROPPABLE + } +} + +class WeaponPiece : Inventory native +{ + Default + { + +WEAPONSPAWN; + } +} + +class Ammo : Inventory native +{ + native int BackpackAmount; + native int BackpackMaxAmount; + + Default + { + +INVENTORY.KEEPDEPLETED + Inventory.PickupSound "misc/ammo_pkup"; + } +} + +class BackpackItem : Inventory native +{ + native bool bDepleted; +} + diff --git a/wadsrc/static/zscript/strife/acolyte.txt b/wadsrc/static/zscript/strife/acolyte.txt new file mode 100644 index 0000000000..e5a019ea8c --- /dev/null +++ b/wadsrc/static/zscript/strife/acolyte.txt @@ -0,0 +1,308 @@ + +// Base class for the acolytes ---------------------------------------------- + +class Acolyte : StrifeHumanoid +{ + Default + { + Health 70; + PainChance 150; + Speed 7; + Radius 24; + Height 64; + Mass 400; + Monster; + +SEESDAGGERS + +NOSPLASHALERT + +FLOORCLIP + +NEVERRESPAWN + MinMissileChance 150; + Tag "$TAG_ACOLYTE"; + SeeSound "acolyte/sight"; + PainSound "acolyte/pain"; + AttackSound "acolyte/rifle"; + DeathSound "acolyte/death"; + ActiveSound "acolyte/active"; + Obituary "$OB_ACOLYTE"; + } + + States + { + Spawn: + AGRD A 5 A_Look2; + Wait; + AGRD B 8 A_ClearShadow; + Loop; + AGRD D 8; + Loop; + AGRD ABCDABCD 5 A_Wander; + Loop; + See: + AGRD A 6 Fast Slow A_AcolyteBits; + AGRD BCD 6 Fast Slow A_Chase; + Loop; + Missile: + AGRD E 8 Fast Slow A_FaceTarget; + AGRD FE 4 Fast Slow A_ShootGun; + AGRD F 6 Fast Slow A_ShootGun; + Goto See; + Pain: + AGRD O 8 Fast Slow A_Pain; + Goto See; + Death: + AGRD G 4; + AGRD H 4 A_Scream; + AGRD I 4; + AGRD J 3; + AGRD K 3 A_NoBlocking; + AGRD L 3; + AGRD M 3 A_AcolyteDie; + AGRD N -1; + Stop; + XDeath: + GIBS A 5 A_NoBlocking; + GIBS BC 5 A_TossGib; + GIBS D 4 A_TossGib; + GIBS E 4 A_XScream; + GIBS F 4 A_TossGib; + GIBS GH 4; + GIBS I 5; + GIBS J 5 A_AcolyteDie; + GIBS K 5; + GIBS L 1400; + Stop; + } + + //============================================================================ + // + // A_AcolyteDie + // + //============================================================================ + + void A_AcolyteDie () + { + // [RH] Disable translucency here. + A_SetRenderStyle(1, STYLE_Normal); + + // Only the Blue Acolyte does extra stuff on death. + if (self is "AcolyteBlue") + { + int i; + // Make sure somebody is still alive + for (i = 0; i < MAXPLAYERS; ++i) + { + if (playeringame[i] && players[i].health > 0) + break; + } + if (i == MAXPLAYERS) + return; + + // Make sure all the other blue acolytes are dead, but do this only once in case of simultaneous kills. + if (CheckBossDeath() && !players[i].mo.FindInventory("QuestItem7")) + { + players[i].mo.GiveInventoryType ("QuestItem7"); + players[i].SetLogNumber (14); + A_StopSound (CHAN_VOICE); + A_PlaySound ("svox/voc14", CHAN_VOICE); + } + } + } + + //============================================================================ + // + // A_BeShadowyFoe + // + //============================================================================ + + void A_BeShadowyFoe() + { + A_SetRenderStyle(HR_SHADOW, STYLE_Translucent); + bFriendly = false; + } + + //============================================================================ + // + // A_AcolyteBits + // + //============================================================================ + + void A_AcolyteBits() + { + if (SpawnFlags & MTF_SHADOW) + { + A_BeShadowyFoe(); + } + if (SpawnFlags & MTF_ALTSHADOW) + { + if (bShadow) + { + // I dunno. + } + else + { + A_SetRenderStyle(0, STYLE_None); + } + } + } + +} + + +// Acolyte 1 ---------------------------------------------------------------- + +class AcolyteTan : Acolyte +{ + Default + { + +MISSILEMORE +MISSILEEVENMORE + DropItem "ClipOfBullets"; + } +} + +// Acolyte 2 ---------------------------------------------------------------- + +class AcolyteRed : Acolyte +{ + Default + { + +MISSILEMORE +MISSILEEVENMORE + Translation 0; + } +} + +// Acolyte 3 ---------------------------------------------------------------- + +class AcolyteRust : Acolyte +{ + Default + { + +MISSILEMORE +MISSILEEVENMORE + Translation 1; + } +} + +// Acolyte 4 ---------------------------------------------------------------- + +class AcolyteGray : Acolyte +{ + Default + { + +MISSILEMORE +MISSILEEVENMORE + Translation 2; + } +} + +// Acolyte 5 ---------------------------------------------------------------- + +class AcolyteDGreen : Acolyte +{ + Default + { + +MISSILEMORE +MISSILEEVENMORE + Translation 3; + } +} + +// Acolyte 6 ---------------------------------------------------------------- + +class AcolyteGold : Acolyte +{ + Default + { + +MISSILEMORE +MISSILEEVENMORE + Translation 4; + } +} + +// Acolyte 7 ---------------------------------------------------------------- + +class AcolyteLGreen : Acolyte +{ + Default + { + Health 60; + Translation 5; + } +} + +// Acolyte 8 ---------------------------------------------------------------- + +class AcolyteBlue : Acolyte +{ + Default + { + Health 60; + Translation 6; + } +} + +// Shadow Acolyte ----------------------------------------------------------- + +class AcolyteShadow : Acolyte +{ + Default + { + +MISSILEMORE + DropItem "ClipOfBullets"; + } + States + { + See: + AGRD A 6 A_BeShadowyFoe; + Goto Super::See+1; + Pain: + AGRD O 0 Fast Slow A_SetShadow; + AGRD O 8 Fast Slow A_Pain; + Goto See; + } +} + +// Some guy turning into an acolyte ----------------------------------------- + +class AcolyteToBe : Acolyte +{ + Default + { + Health 61; + Radius 20; + Height 56; + DeathSound "becoming/death"; + -COUNTKILL + -ISMONSTER + } + + States + { + Spawn: + ARMR A -1; + Stop; + Pain: + ARMR A -1 A_HideDecepticon; + Stop; + Death: + Goto XDeath; + } + + //============================================================================ + // + // A_HideDecepticon + // + // Hide the Acolyte-to-be -> + // Hide the guy transforming into an Acolyte -> + // Hide the transformer -> + // Transformers are Autobots and Decepticons, and + // Decepticons are the bad guys, so... -> + // + // Hide the Decepticon! + // + //============================================================================ + + void A_HideDecepticon () + { + Door_Close(999, 64); + if (target != null && target.player != null) + { + NoiseAlert (target); + } + } +} diff --git a/wadsrc/static/zscript/strife/alienspectres.txt b/wadsrc/static/zscript/strife/alienspectres.txt new file mode 100644 index 0000000000..39cbc83315 --- /dev/null +++ b/wadsrc/static/zscript/strife/alienspectres.txt @@ -0,0 +1,331 @@ + +// Alien Spectre 1 ----------------------------------------------------------- + +class AlienSpectre1 : SpectralMonster +{ + Default + { + Health 1000; + Painchance 250; + Speed 12; + Radius 64; + Height 64; + FloatSpeed 5; + Mass 1000; + MinMissileChance 150; + RenderStyle "Translucent"; + Alpha 0.666; + SeeSound "alienspectre/sight"; + AttackSound "alienspectre/blade"; + PainSound "alienspectre/pain"; + DeathSound "alienspectre/death"; + ActiveSound "alienspectre/active"; + Obituary "$OB_ALIENSPECTRE"; + +NOGRAVITY + +FLOAT + +SHADOW + +NOTDMATCH + +DONTMORPH + +NOBLOCKMONST + +INCOMBAT + +LOOKALLAROUND + +NOICEDEATH + } + + States + { + Spawn: + ALN1 A 10 A_Look; + ALN1 B 10 A_SentinelBob; + Loop; + See: + ALN1 AB 4 Bright A_Chase; + ALN1 C 4 Bright A_SentinelBob; + ALN1 DEF 4 Bright A_Chase; + ALN1 G 4 Bright A_SentinelBob; + ALN1 HIJ 4 Bright A_Chase; + ALN1 K 4 Bright A_SentinelBob; + Loop; + Melee: + ALN1 J 4 Bright A_FaceTarget; + ALN1 I 4 Bright A_CustomMeleeAttack((random[SpectreMelee](0,255)&9)*5); + ALN1 H 4 Bright; + Goto See; + Missile: + ALN1 J 4 Bright A_FaceTarget; + ALN1 I 4 Bright A_SpotLightning; + ALN1 H 4 Bright; + Goto See+10; + Pain: + ALN1 J 2 A_Pain; + Goto See+6; + Death: + AL1P A 6 Bright A_SpectreChunkSmall; + AL1P B 6 Bright A_Scream; + AL1P C 6 Bright A_SpectreChunkSmall; + AL1P DE 6 Bright; + AL1P F 6 Bright A_SpectreChunkSmall; + AL1P G 6 Bright; + AL1P H 6 Bright A_SpectreChunkSmall; + AL1P IJK 6 Bright; + AL1P LM 5 Bright; + AL1P N 5 Bright A_SpectreChunkLarge; + AL1P OPQ 5 Bright; + AL1P R 5 Bright A_AlienSpectreDeath; + Stop; + } + + //============================================================================ + + void A_AlienSpectreDeath () + { + PlayerPawn player = null; + int log = 0; + + A_NoBlocking(); // [RH] Need this for Sigil rewarding + if (!CheckBossDeath ()) + { + return; + } + for (int i = 0; i < MAXPLAYERS; ++i) + { + if (playeringame[i] && players[i].health > 0) + { + player = players[i].mo; + break; + } + } + if (player == null) + { + return; + } + + class cls = GetClass(); + if (cls == "AlienSpectre1") + { + Floor_LowerToLowest(999, 8); + log = 95; + } + else if (cls == "AlienSpectre2") + { + C_MidPrint("SmallFont", "$TXT_KILLED_BISHOP"); + log = 74; + player.GiveInventoryType ("QuestItem21"); + } + else if (cls == "AlienSpectre3") + { + C_MidPrint("SmallFont", "$TXT_KILLED_ORACLE"); + // If there are any Oracles still alive, kill them. + ThinkerIterator it = ThinkerIterator.Create("Oracle"); + Actor oracle; + + while ( (oracle = Actor(it.Next())) != null) + { + if (oracle.health > 0) + { + oracle.health = 0; + oracle.Die (self, self); + } + } + player.GiveInventoryType ("QuestItem23"); + if (player.FindInventory ("QuestItem21")) + { // If the Bishop is dead, set quest item 22 + player.GiveInventoryType ("QuestItem22"); + } + if (player.FindInventory ("QuestItem24") == null) + { // Macil is calling us back... + log = 87; + } + else + { // You wield the power of the complete Sigil. + log = 85; + } + Door_Open(222, 64); + } + else if (cls == "AlienSpectre4") + { + C_MidPrint("SmallFont", "$TXT_KILLED_MACIL"); + player.GiveInventoryType ("QuestItem24"); + if (player.FindInventory ("QuestItem25") == null) + { // Richter has taken over. Macil is a snake. + log = 79; + } + else + { // Back to the factory for another Sigil! + log = 106; + } + } + else if (cls == "AlienSpectre5") + { + C_MidPrint("SmallFont", "$TXT_KILLED_LOREMASTER"); + + player.GiveInventoryType ("QuestItem26"); + if (!multiplayer) + { + player.GiveInventoryType ("UpgradeStamina"); + player.GiveInventoryType ("UpgradeAccuracy"); + } + Sigil sigl = Sigil(player.FindInventory("Sigil")); + if (sigl != null /*&& sigl.NumPieces == 5*/) + { // You wield the power of the complete Sigil. + log = 85; + } + else + { // Another Sigil piece. Woohoo! + log = 83; + } + Floor_LowerToLowest(666, 8); + } + if (log > 0) + { + String voc = "svox/voc" .. log; + A_PlaySound(voc, CHAN_VOICE); + player.player.SetLogNumber (log); + } + } + +} + + +// Alien Spectre 2 ----------------------------------------------------------- + +class AlienSpectre2 : AlienSpectre1 +{ + Default + { + Health 1200; + Painchance 50; + Radius 24; + DropItem "Sigil2"; + } + States + { + Missile: + ALN1 F 4 A_FaceTarget; + ALN1 I 4 A_CustomMissile("SpectralLightningH3", 32, 0); + ALN1 E 4; + Goto See+10; + } +} + +// Alien Spectre 3 ---------------------------------------------------------- +// This is the Oracle's personal spectre, so it's a little different. + +class AlienSpectre3 : AlienSpectre1 +{ + Default + { + Health 1500; + Painchance 50; + Radius 24; + +SPAWNCEILING + DropItem "Sigil3"; + DamageFactor "SpectralLow", 0; + } + States + { + Spawn: + ALN1 ABCDEFGHIJK 5; + Loop; + See: + ALN1 AB 5 A_Chase; + ALN1 C 5 A_SentinelBob; + ALN1 DEF 5 A_Chase; + ALN1 G 5 A_SentinelBob; + ALN1 HIJ 5 A_Chase; + ALN1 K 5 A_SentinelBob; + Loop; + Melee: + ALN1 J 4 A_FaceTarget; + ALN1 I 4 A_CustomMeleeAttack((random[SpectreMelee](0,255)&9)*5); + ALN1 C 4; + Goto See+2; + Missile: + ALN1 F 4 A_FaceTarget; + ALN1 I 4 A_Spectre3Attack; + ALN1 E 4; + Goto See+10; + Pain: + ALN1 J 2 A_Pain; + Goto See+6; + } +} + + +// Alien Spectre 4 ----------------------------------------------------------- + +class AlienSpectre4 : AlienSpectre1 +{ + Default + { + Health 1700; + Painchance 50; + Radius 24; + DropItem "Sigil4"; + } + States + { + Missile: + ALN1 F 4 A_FaceTarget; + ALN1 I 4 A_CustomMissile("SpectralLightningBigV2", 32, 0); + ALN1 E 4; + Goto See+10; + } +} + + +// Alien Spectre 5 ----------------------------------------------------------- + +class AlienSpectre5 : AlienSpectre1 +{ + Default + { + Health 2000; + Painchance 50; + Radius 24; + DropItem "Sigil5"; + } + States + { + Missile: + ALN1 F 4 A_FaceTarget; + ALN1 I 4 A_CustomMissile("SpectralLightningBigBall2", 32, 0); + ALN1 E 4; + Goto See+10; + } +} + +// Small Alien Chunk -------------------------------------------------------- + +class AlienChunkSmall : Actor +{ + Default + { + +NOBLOCKMAP + +NOCLIP + } + States + { + Spawn: + NODE ABCDEFG 6 Bright; + Stop; + } +} + +// Large Alien Chunk -------------------------------------------------------- + +class AlienChunkLarge : Actor +{ + Default + { + +NOBLOCKMAP + +NOCLIP + } + States + { + Spawn: + MTHD ABCDEFGHIJK 5 Bright; + Stop; + } +} + diff --git a/wadsrc/static/zscript/strife/beggars.txt b/wadsrc/static/zscript/strife/beggars.txt new file mode 100644 index 0000000000..e70a3a8e76 --- /dev/null +++ b/wadsrc/static/zscript/strife/beggars.txt @@ -0,0 +1,90 @@ + +// Base class for the beggars --------------------------------------------- + +class Beggar : StrifeHumanoid +{ + Default + { + Health 20; + PainChance 250; + Speed 3; + Radius 20; + Height 56; + Monster; + +JUSTHIT + -COUNTKILL + +NOSPLASHALERT + MinMissileChance 150; + Tag "$TAG_BEGGAR"; + MaxStepHeight 16; + MaxDropoffHeight 32; + HitObituary "$OB_BEGGAR"; + + AttackSound "beggar/attack"; + PainSound "beggar/pain"; + DeathSound "beggar/death"; + } + States + { + Spawn: + BEGR A 10 A_Look; + Loop; + See: + BEGR AABBCC 4 A_Wander; + Loop; + Melee: + BEGR D 8; + BEGR D 8 A_CustomMeleeAttack(2*random[PeasantAttack](1,5)+2); + BEGR E 1 A_Chase; + BEGR D 8 A_SentinelRefire; + Loop; + Pain: + BEGR A 3 A_Pain; + BEGR A 3 A_Chase; + Goto Melee; + Death: + BEGR F 4; + BEGR G 4 A_Scream; + BEGR H 4; + BEGR I 4 A_NoBlocking; + BEGR JKLM 4; + BEGR N -1; + Stop; + XDeath: + BEGR F 5 A_TossGib; + GIBS M 5 A_TossGib; + GIBS N 5 A_XScream; + GIBS O 5 A_NoBlocking; + GIBS PQRST 4 A_TossGib; + GIBS U 5; + GIBS V 1400; + Stop; + } +} + + +// Beggars ----------------------------------------------------------------- + +class Beggar1 : Beggar +{ +} + + +class Beggar2 : Beggar +{ +} + + +class Beggar3 : Beggar +{ +} + + +class Beggar4 : Beggar +{ +} + + +class Beggar5 : Beggar +{ +} diff --git a/wadsrc/static/zscript/strife/coin.txt b/wadsrc/static/zscript/strife/coin.txt new file mode 100644 index 0000000000..b94a3f1d13 --- /dev/null +++ b/wadsrc/static/zscript/strife/coin.txt @@ -0,0 +1,201 @@ + +// Coin --------------------------------------------------------------------- + +class Coin : Inventory +{ + Default + { + +DROPPED + +NOTDMATCH + +FLOORCLIP + Inventory.MaxAmount 0x7fffffff; + +INVENTORY.INVBAR + Tag "$TAG_COIN"; + Inventory.Icon "I_COIN"; + Inventory.PickupMessage "$TXT_COIN"; + } + States + { + Spawn: + COIN A -1; + Stop; + } + + // Coin --------------------------------------------------------------------- + + override String PickupMessage () + { + if (Amount == 1) + { + return Super.PickupMessage(); + } + else + { + String msg = StringTable.Localize("TXT_XGOLD"); + msg.Replace("%d", "" .. Amount); + return msg; + } + } + + override bool HandlePickup (Inventory item) + { + if (item is "Coin") + { + if (Amount < MaxAmount) + { + if (MaxAmount - Amount < item.Amount) + { + Amount = MaxAmount; + } + else + { + Amount += item.Amount; + } + item.bPickupGood = true; + } + return true; + } + return false; + } + + override Inventory CreateCopy (Actor other) + { + if (GetClass() == "Coin") + { + return Super.CreateCopy (other); + } + Inventory copy = Inventory(Spawn("Coin")); + copy.Amount = Amount; + copy.BecomeItem (); + GoAwayAndDie (); + return copy; + } + + //=========================================================================== + // + // ACoin :: CreateTossable + // + // Gold drops in increments of 50 if you have that much, less if you don't. + // + //=========================================================================== + + override Inventory CreateTossable () + { + Coin tossed; + + if (bUndroppable || Owner == NULL || Amount <= 0) + { + return NULL; + } + if (Amount >= 50) + { + Amount -= 50; + tossed = Coin(Spawn("Gold50")); + } + else if (Amount >= 25) + { + Amount -= 25; + tossed = Coin(Spawn("Gold25")); + } + else if (Amount >= 10) + { + Amount -= 10; + tossed = Coin(Spawn("Gold10")); + } + else if (Amount > 1 || bKeepDepleted) + { + Amount -= 1; + tossed = Coin(Spawn("Coin")); + } + else // Amount == 1 && !(ItemFlags & IF_KEEPDEPLETED) + { + BecomePickup (); + tossed = self; + } + tossed.bSpecial = false; + tossed.bSolid = false; + tossed.DropTime = 30; + if (tossed != self && Amount <= 0) + { + Destroy (); + } + return tossed; + } + +} + + +// 10 Gold ------------------------------------------------------------------ + +class Gold10 : Coin +{ + Default + { + Inventory.Amount 10; + Tag "$TAG_10GOLD"; + Inventory.PickupMessage "$TXT_10GOLD"; + } + States + { + Spawn: + CRED A -1; + Stop; + } +} + +// 25 Gold ------------------------------------------------------------------ + +class Gold25 : Coin +{ + Default + { + Inventory.Amount 25; + Tag "$TAG_25GOLD"; + Inventory.PickupMessage "$TXT_25GOLD"; + } + States + { + Spawn: + SACK A -1; + Stop; + } +} + +// 50 Gold ------------------------------------------------------------------ + +class Gold50 : Coin +{ + Default + { + Inventory.Amount 50; + Tag "$TAG_50GOLD"; + Inventory.PickupMessage "$TXT_50GOLD"; + } + States + { + Spawn: + CHST A -1; + Stop; + } +} + +// 300 Gold ------------------------------------------------------------------ + +class Gold300 : Coin +{ + Default + { + Inventory.Amount 300; + Tag "$TAG_300GOLD"; + Inventory.PickupMessage "$TXT_300GOLD"; + Inventory.GiveQuest 3; + +INVENTORY.ALWAYSPICKUP + } + States + { + Spawn: + TOKN A -1; + Stop; + } +} + diff --git a/wadsrc/static/zscript/strife/crusader.txt b/wadsrc/static/zscript/strife/crusader.txt new file mode 100644 index 0000000000..ce2ba6ef8b --- /dev/null +++ b/wadsrc/static/zscript/strife/crusader.txt @@ -0,0 +1,202 @@ + +// Crusader ----------------------------------------------------------------- + +class Crusader : Actor +{ + Default + { + Speed 8; + Radius 40; + Height 56; + Mass 400; + Health 400; + Painchance 128; + Monster; + +FLOORCLIP + +DONTMORPH + +MISSILEMORE + +INCOMBAT + +NOICEDEATH + +NOBLOOD + MinMissileChance 120; + MaxDropoffHeight 32; + DropItem "EnergyPod", 256, 20; + SeeSound "crusader/sight"; + PainSound "crusader/pain"; + DeathSound "crusader/death"; + ActiveSound "crusader/active"; + Obituary "$OB_CRUSADER"; + } + + States + { + Spawn: + ROB2 Q 10 A_Look; + Loop; + See: + ROB2 AABBCCDD 3 A_Chase; + Loop; + Missile: + ROB2 E 3 Slow A_FaceTarget; + ROB2 F 2 Slow Bright A_CrusaderChoose; + ROB2 E 2 Slow Bright A_CrusaderSweepLeft; + ROB2 F 3 Slow Bright A_CrusaderSweepLeft; + ROB2 EF 2 Slow Bright A_CrusaderSweepLeft; + ROB2 EFE 2 Slow Bright A_CrusaderSweepRight; + ROB2 F 2 Slow A_CrusaderRefire; + Loop; + Pain: + ROB2 D 1 Slow A_Pain; + Goto See; + Death: + ROB2 G 3 A_Scream; + ROB2 H 5 A_TossGib; + ROB2 I 4 Bright A_TossGib; + ROB2 J 4 Bright A_Explode(64, 64, alert:true); + ROB2 K 4 Bright A_Fall; + ROB2 L 4 A_Explode(64, 64, alert:true); + ROB2 MN 4 A_TossGib; + ROB2 O 4 A_Explode(64, 64, alert:true); + ROB2 P -1 A_CrusaderDeath; + Stop; + } + +// Crusader ----------------------------------------------------------------- + + private bool CrusaderCheckRange () + { + if (reactiontime == 0 && CheckSight (target)) + { + return Distance2D (target) < 264.; + } + return false; + } + + void A_CrusaderChoose () + { + if (target == null) + return; + + if (CrusaderCheckRange ()) + { + A_FaceTarget (); + angle -= 180./16; + SpawnMissileZAimed (pos.z + 40, target, "FastFlameMissile"); + } + else + { + if (CheckMissileRange ()) + { + A_FaceTarget (); + SpawnMissileZAimed (pos.z + 56, target, "CrusaderMissile"); + angle -= 45./32; + SpawnMissileZAimed (pos.z + 40, target, "CrusaderMissile"); + angle += 45./16; + SpawnMissileZAimed (pos.z + 40, target, "CrusaderMissile"); + angle -= 45./16; + reactiontime += 15; + } + SetState (SeeState); + } + } + + void A_CrusaderSweepLeft () + { + angle += 90./16; + Actor misl = SpawnMissileZAimed (pos.z + 48, target, "FastFlameMissile"); + if (misl != null) + { + misl.Vel.Z += 1; + } + } + + void A_CrusaderSweepRight () + { + angle -= 90./16; + Actor misl = SpawnMissileZAimed (pos.z + 48, target, "FastFlameMissile"); + if (misl != null) + { + misl.Vel.Z += 1; + } + } + + void A_CrusaderRefire () + { + if (target == null || + target.health <= 0 || + !CheckSight (target)) + { + SetState (SeeState); + } + } + + void A_CrusaderDeath () + { + if (CheckBossDeath ()) + { + Floor_LowerToLowest(667, 8); + } + } +} + + +// Fast Flame Projectile (used by Crusader) --------------------------------- + +class FastFlameMissile : FlameMissile +{ + Default + { + Mass 50; + Damage 1; + Speed 35; + } +} + +// Crusader Missile --------------------------------------------------------- +// This is just like the mini missile the player shoots, except it doesn't +// explode when it dies, and it does slightly less damage for a direct hit. + +class CrusaderMissile : Actor +{ + Default + { + Speed 20; + Radius 10; + Height 14; + Damage 7; + Projectile; + +STRIFEDAMAGE + MaxStepHeight 4; + SeeSound "crusader/misl"; + DeathSound "crusader/mislx"; + } + States + { + Spawn: + MICR A 6 Bright A_RocketInFlight; + Loop; + Death: + SMIS A 0 Bright A_SetRenderStyle(1, STYLE_Normal); + SMIS A 5 Bright; + SMIS B 5 Bright; + SMIS C 4 Bright; + SMIS DEFG 2 Bright; + Stop; + } +} + + +// Dead Crusader ------------------------------------------------------------ + +class DeadCrusader : Actor +{ + States + { + Spawn: + ROB2 N 4; + ROB2 O 4; + ROB2 P -1; + Stop; + } +} + diff --git a/wadsrc/static/zscript/strife/entityboss.txt b/wadsrc/static/zscript/strife/entityboss.txt new file mode 100644 index 0000000000..daf1a78ee2 --- /dev/null +++ b/wadsrc/static/zscript/strife/entityboss.txt @@ -0,0 +1,298 @@ + +// Entity Nest -------------------------------------------------------------- + +class EntityNest : Actor +{ + Default + { + Radius 84; + Height 47; + +SOLID + +NOTDMATCH + +FLOORCLIP + } + States + { + Spawn: + NEST A -1; + Stop; + } +} + +// Entity Pod --------------------------------------------------------------- + +class EntityPod : Actor +{ + Default + { + Radius 25; + Height 91; + +SOLID + +NOTDMATCH + SeeSound "misc/gibbed"; + } + + + States + { + Spawn: + PODD A 60 A_Look; + Loop; + See: + PODD A 360; + PODD B 9 A_NoBlocking; + PODD C 9; + PODD D 9 A_SpawnEntity; + PODD E -1; + Stop; + } + + void A_SpawnEntity () + { + Actor entity = Spawn("EntityBoss", pos + (0,0,70), ALLOW_REPLACE); + if (entity != null) + { + entity.Angle = self.Angle; + entity.CopyFriendliness(self, true); + entity.Vel.Z = 5; + entity.tracer = self; + } + } + +} + + +// -------------------------------------------------------------- + +class EntityBoss : SpectralMonster +{ + Default + { + Health 2500; + Painchance 255; + Speed 13; + Radius 130; + Height 200; + FloatSpeed 5; + Mass 1000; + Monster; + +SPECIAL + +NOGRAVITY + +FLOAT + +SHADOW + +NOTDMATCH + +DONTMORPH + +NOTARGET + +NOBLOCKMONST + +INCOMBAT + +LOOKALLAROUND + +SPECTRAL + +NOICEDEATH + MinMissileChance 150; + RenderStyle "Translucent"; + Alpha 0.5; + SeeSound "entity/sight"; + AttackSound "entity/melee"; + PainSound "entity/pain"; + DeathSound "entity/death"; + ActiveSound "entity/active"; + Obituary "$OB_ENTITY"; + } + + States + { + Spawn: + MNAM A 100; + MNAM B 60 Bright; + MNAM CDEFGHIJKL 4 Bright; + MNAL A 4 Bright A_Look; + MNAL B 4 Bright A_SentinelBob; + Goto Spawn+12; + See: + MNAL AB 4 Bright A_Chase; + MNAL C 4 Bright A_SentinelBob; + MNAL DEF 4 Bright A_Chase; + MNAL G 4 Bright A_SentinelBob; + MNAL HIJ 4 Bright A_Chase; + MNAL K 4 Bright A_SentinelBob; + Loop; + Melee: + MNAL J 4 Bright A_FaceTarget; + MNAL I 4 Bright A_CustomMeleeAttack((random[SpectreMelee](0,255)&9)*5); + MNAL C 4 Bright; + Goto See+2; + Missile: + MNAL F 4 Bright A_FaceTarget; + MNAL I 4 Bright A_EntityAttack; + MNAL E 4 Bright; + Goto See+10; + Pain: + MNAL J 2 Bright A_Pain; + Goto See+6; + Death: + MNAL L 7 Bright A_SpectreChunkSmall; + MNAL M 7 Bright A_Scream; + MNAL NO 7 Bright A_SpectreChunkSmall; + MNAL P 7 Bright A_SpectreChunkLarge; + MNAL Q 64 Bright A_SpectreChunkSmall; + MNAL Q 6 Bright A_EntityDeath; + Stop; + } + + // -------------------------------------------------------------- + + private void A_SpectralMissile (class missilename) + { + if (target != null) + { + Actor missile = SpawnMissileXYZ (Pos + (0,0,32), target, missilename, false); + if (missile != null) + { + missile.tracer = target; + missile.CheckMissileSpawn(radius); + } + } + } + + // -------------------------------------------------------------- + + void A_EntityAttack() + { + // Apparent Strife bug: Case 5 was unreachable because they used % 5 instead of % 6. + // I've fixed that by making case 1 duplicate it, since case 1 did nothing. + switch (random[Entity]() % 5) + { + case 0: + A_SpotLightning(); + break; + + case 2: + A_SpectralMissile ("SpectralLightningH3"); + break; + + case 3: + A_Spectre3Attack(); + break; + + case 4: + A_SpectralMissile ("SpectralLightningBigV2"); + break; + + default: + A_SpectralMissile ("SpectralLightningBigBall2"); + break; + } + } + + // -------------------------------------------------------------- + + void A_EntityDeath() + { + Actor second; + double secondRadius = GetDefaultByType("EntitySecond").radius * 2; + + static const double turns[] = { 0, 90, -90 }; + + Actor spot = tracer; + if (spot == null) spot = self; + + for (int i = 0; i < 3; i++) + { + double an = Angle + turns[i]; + Vector3 pos = spot.Vec3Angle(secondRadius, an, tracer ? 70. : 0.); + + second = Spawn("EntitySecond", pos, ALLOW_REPLACE); + second.CopyFriendliness(self, true); + second.A_FaceTarget(); + second.VelFromAngle(i == 0? 4.8828125 : secondRadius * 4., an); + } + } + +} + +// Second Entity Boss ------------------------------------------------------- + +class EntitySecond : SpectralMonster +{ + Default + { + Health 990; + Painchance 255; + Speed 14; + Radius 130; + Height 200; + FloatSpeed 5; + Mass 1000; + Monster; + +SPECIAL + +NOGRAVITY + +FLOAT + +SHADOW + +NOTDMATCH + +DONTMORPH + +NOBLOCKMONST + +INCOMBAT + +LOOKALLAROUND + +SPECTRAL + +NOICEDEATH + MinMissileChance 150; + RenderStyle "Translucent"; + Alpha 0.25; + SeeSound "alienspectre/sight"; + AttackSound "alienspectre/blade"; + PainSound "alienspectre/pain"; + DeathSound "alienspectre/death"; + ActiveSound "alienspectre/active"; + Obituary "$OB_ENTITY"; + } + + States + { + Spawn: + MNAL R 10 Bright A_Look; + Loop; + See: + MNAL R 5 Bright A_SentinelBob; + MNAL ST 5 Bright A_Chase; + MNAL U 5 Bright A_SentinelBob; + MNAL V 5 Bright A_Chase; + MNAL W 5 Bright A_SentinelBob; + Loop; + Melee: + MNAL S 4 Bright A_FaceTarget; + MNAL R 4 Bright A_CustomMeleeAttack((random[SpectreMelee](0,255)&9)*5); + MNAL T 4 Bright A_SentinelBob; + Goto See+1; + Missile: + MNAL W 4 Bright A_FaceTarget; + MNAL U 4 Bright A_CustomMissile("SpectralLightningH3",32,0); + MNAL V 4 Bright A_SentinelBob; + Goto See+4; + Pain: + MNAL R 2 Bright A_Pain; + Goto See; + Death: + MDTH A 3 Bright A_Scream; + MDTH B 3 Bright A_TossGib; + MDTH C 3 Bright A_NoBlocking; + MDTH DEFGHIJKLMN 3 Bright A_TossGib; + MDTH O 3 Bright A_SubEntityDeath; + Stop; + } + + // -------------------------------------------------------------- + + void A_SubEntityDeath () + { + if (CheckBossDeath ()) + { + Exit_Normal(0); + } + } +} + + + + + + diff --git a/wadsrc/static/zscript/strife/inquisitor.txt b/wadsrc/static/zscript/strife/inquisitor.txt new file mode 100644 index 0000000000..6d3c5bc7f7 --- /dev/null +++ b/wadsrc/static/zscript/strife/inquisitor.txt @@ -0,0 +1,245 @@ + +// Inquisitor --------------------------------------------------------------- + +class Inquisitor : Actor +{ + Default + { + Health 1000; + Speed 12; + Radius 40; + Height 110; + Mass 0x7fffffff; + Monster; + +DROPOFF + +NOBLOOD + +BOSS + +FLOORCLIP + +DONTMORPH + +NORADIUSDMG + MaxDropOffHeight 32; + MinMissileChance 150; + SeeSound "inquisitor/sight"; + DeathSound "inquisitor/death"; + ActiveSound "inquisitor/active"; + Obituary "$OB_INQUISITOR"; + } + + States + { + Spawn: + ROB3 AB 10 A_Look; + Loop; + See: + ROB3 B 3 A_InquisitorWalk; + ROB3 B 3 A_Chase; + ROB3 CCDD 4 A_Chase; + ROB3 E 3 A_InquisitorWalk; + ROB3 E 3 A_InquisitorDecide; + Loop; + Missile: + ROB3 A 2 A_InquisitorDecide; + ROB3 F 6 A_FaceTarget; + ROB3 G 8 Bright A_ReaverRanged; + ROB3 G 8 A_ReaverRanged; + Goto See; + Grenade: + ROB3 K 12 A_FaceTarget; + ROB3 J 6 Bright A_InquisitorAttack; + ROB3 K 12; + Goto See; + Jump: + ROB3 H 8 Bright A_InquisitorJump; + ROB3 I 4 Bright A_InquisitorCheckLand; + ROB3 H 4 Bright A_InquisitorCheckLand; + Goto Jump+1; + Death: + ROB3 L 0 A_StopSound(CHAN_ITEM); + ROB3 L 4 A_TossGib; + ROB3 M 4 A_Scream; + ROB3 N 4 A_TossGib; + ROB3 O 4 Bright A_Explode(128, 128, alert:true); + ROB3 P 4 Bright A_TossGib; + ROB3 Q 4 Bright A_NoBlocking; + ROB3 RSTUV 4 A_TossGib; + ROB3 W 4 Bright A_Explode(128, 128, alert:true); + ROB3 XY 4 Bright A_TossGib; + ROB3 Z 4 A_TossGib; + ROB3 [ 4 A_TossGib; + ROB3 \ 3 A_TossGib; + ROB3 ] 3 Bright A_Explode(128, 128, alert:true); + RBB3 A 3 Bright A_TossArm; + RBB3 B 3 Bright A_TossGib; + RBB3 CD 3 A_TossGib; + RBB3 E -1; + Stop; + } + + + // Inquisitor --------------------------------------------------------------- + + void A_InquisitorWalk () + { + A_PlaySound ("inquisitor/walk", CHAN_BODY); + A_Chase (); + } + + private bool InquisitorCheckDistance () + { + if (reactiontime == 0 && CheckSight (target)) + { + return Distance2D (target) < 264.; + } + return false; + } + + void A_InquisitorDecide () + { + if (target == null) + return; + + A_FaceTarget (); + if (!InquisitorCheckDistance ()) + { + SetStateLabel("Grenade"); + } + if (target.pos.z != pos.z) + { + if (pos.z + height + 54 < ceilingz) + { + SetStateLabel("Jump"); + } + } + } + + void A_InquisitorAttack () + { + if (target == null) + return; + + A_FaceTarget (); + + AddZ(32); + angle -= 45./32; + Actor proj = SpawnMissileZAimed (pos.z, target, "InquisitorShot"); + if (proj != null) + { + proj.Vel.Z += 9; + } + angle += 45./16; + proj = SpawnMissileZAimed (pos.z, target, "InquisitorShot"); + if (proj != null) + { + proj.Vel.Z += 16; + } + AddZ(-32); + } + + void A_InquisitorJump () + { + if (target == null) + return; + + A_PlaySound ("inquisitor/jump", CHAN_ITEM, 1, true); + AddZ(64); + A_FaceTarget (); + speed = Speed * (2./3); + VelFromAngle(speed); + double dist = DistanceBySpeed(target, speed); + Vel.Z = (target.pos.z - pos.z) / dist; + reactiontime = 60; + bNoGravity = true; + } + + void A_InquisitorCheckLand () + { + reactiontime--; + if (reactiontime < 0 || + Vel.X == 0 || + Vel.Y == 0 || + pos.z <= floorz) + { + SetState (SeeState); + reactiontime = 0; + bNoGravity = false; + A_StopSound (CHAN_ITEM); + return; + } + A_PlaySound ("inquisitor/jump", CHAN_ITEM, 1, true); + } + + void A_TossArm () + { + Actor foo = Spawn("InquisitorArm", Pos + (0,0,24), ALLOW_REPLACE); + foo.angle = angle - 90. + Random2[Inquisitor]() * (360./1024.); + foo.VelFromAngle(foo.Speed / 8); + foo.Vel.Z = random[Inquisitor]() / 64.; + } + + +} + +// Inquisitor Shot ---------------------------------------------------------- + +class InquisitorShot : Actor +{ + Default + { + ReactionTime 15; + Speed 25; + Radius 13; + Height 13; + Mass 15; + Projectile; + -ACTIVATEIMPACT + -ACTIVATEPCROSS + -NOGRAVITY + +STRIFEDAMAGE + MaxStepHeight 4; + SeeSound "inquisitor/attack"; + DeathSound "inquisitor/atkexplode"; + } + States + { + Spawn: + UBAM AB 3 A_Countdown; + Loop; + Death: + BNG2 A 0 Bright A_SetRenderStyle(1, STYLE_Normal); + BNG2 A 4 Bright A_Explode(192, 192, alert:true); + BNG2 B 4 Bright; + BNG2 C 4 Bright; + BNG2 D 4 Bright; + BNG2 E 4 Bright; + BNG2 F 4 Bright; + BNG2 G 4 Bright; + BNG2 H 4 Bright; + BNG2 I 4 Bright; + Stop; + } + +} + + +// The Dead Inquisitor's Detached Arm --------------------------------------- + +class InquisitorArm : Actor +{ + Default + { + Speed 25; + +NOBLOCKMAP + +NOCLIP + +NOBLOOD + } + States + { + Spawn: + RBB3 FG 5 Bright; + RBB3 H -1; + Stop; + } +} + + + diff --git a/wadsrc/static/zscript/strife/klaxon.txt b/wadsrc/static/zscript/strife/klaxon.txt new file mode 100644 index 0000000000..51c4d7df2d --- /dev/null +++ b/wadsrc/static/zscript/strife/klaxon.txt @@ -0,0 +1,125 @@ +// Klaxon Warning Light ----------------------------------------------------- + +class KlaxonWarningLight : Actor +{ + Default + { + ReactionTime 60; + Radius 5; + +NOBLOCKMAP +AMBUSH + +SPAWNCEILING +NOGRAVITY + +FIXMAPTHINGPOS +NOSPLASHALERT + +SYNCHRONIZED + } + States + { + Spawn: + KLAX A 5 A_TurretLook; + Loop; + See: + KLAX B 6 A_KlaxonBlare; + KLAX C 60; + Loop; + } + +} + +// CeilingTurret ------------------------------------------------------------ + +class CeilingTurret : Actor +{ + Default + { + Health 125; + Speed 0; + Painchance 0; + Mass 10000000; + Monster; + -SOLID + -CANPASS + +AMBUSH + +SPAWNCEILING + +NOGRAVITY + +NOBLOOD + +NOSPLASHALERT + +DONTFALL + MinMissileChance 150; + DeathSound "turret/death"; + } + States + { + Spawn: + TURT A 5 A_TurretLook; + Loop; + See: + TURT A 2 A_Chase; + Loop; + Missile: + Pain: + TURT B 4 Slow A_ShootGun; + TURT D 3 Slow A_SentinelRefire; + TURT A 4 A_SentinelRefire; + Loop; + Death: + BALL A 6 Bright A_Scream; + BALL BCDE 6 Bright; + TURT C -1; + Stop; + } +} + + +extend class Actor +{ + void A_TurretLook() + { + if (bInConversation) + return; + + threshold = 0; + Actor targ = LastHeard; + if (targ != NULL && targ.health > 0 && targ.bShootable && !IsFriend(targ)) + { + target = targ; + if (bAmbush && !CheckSight (targ)) + { + return; + } + if (SeeSound != 0) + { + A_PlaySound (SeeSound, CHAN_VOICE); + } + LastHeard = NULL; + threshold = 10; + SetState (SeeState); + } + } + + void A_KlaxonBlare() + { + if (--reactiontime < 0) + { + target = NULL; + reactiontime = Default.reactiontime; + A_TurretLook(); + if (target == NULL) + { + SetIdle(); + } + else + { + reactiontime = 50; + } + } + if (reactiontime == 2) + { + // [RH] Unalert monsters near the alarm and not just those in the same sector as it. + NoiseAlert (NULL, false); + } + else if (reactiontime > 50) + { + A_PlaySound ("misc/alarm", CHAN_VOICE); + } + } + +} \ No newline at end of file diff --git a/wadsrc/static/zscript/strife/loremaster.txt b/wadsrc/static/zscript/strife/loremaster.txt new file mode 100644 index 0000000000..14571f91c8 --- /dev/null +++ b/wadsrc/static/zscript/strife/loremaster.txt @@ -0,0 +1,141 @@ + +// Loremaster (aka Priest) -------------------------------------------------- + +class Loremaster : Actor +{ + Default + { + Health 800; + Speed 10; + Radius 15; + Height 56; + FloatSpeed 5; + Monster; + +FLOAT + +NOBLOOD + +NOGRAVITY + +NOTDMATCH + +FLOORCLIP + +NOBLOCKMONST + +INCOMBAT + +LOOKALLAROUND + +NOICEDEATH + +NEVERRESPAWN + DamageFactor "Fire", 0.5; + MinMissileChance 150; + Tag "$TAG_PRIEST"; + SeeSound "loremaster/sight"; + AttackSound "loremaster/attack"; + PainSound "loremaster/pain"; + DeathSound "loremaster/death"; + ActiveSound "loremaster/active"; + Obituary "$OB_LOREMASTER"; + DropItem "Junk"; + } + States + { + Spawn: + PRST A 10 A_Look; + PRST B 10 A_SentinelBob; + Loop; + See: + PRST A 4 A_Chase; + PRST A 4 A_SentinelBob; + PRST B 4 A_Chase; + PRST B 4 A_SentinelBob; + PRST C 4 A_Chase; + PRST C 4 A_SentinelBob; + PRST D 4 A_Chase; + PRST D 4 A_SentinelBob; + Loop; + Melee: + PRST E 4 A_FaceTarget; + PRST F 4 A_CustomMeleeAttack((random[SpectreMelee](0,255)&9)*5); + PRST E 4 A_SentinelBob; + Goto See; + Missile: + PRST E 4 A_FaceTarget; + PRST F 4 A_CustomMissile("LoreShot", 32, 0); + PRST E 4 A_SentinelBob; + Goto See; + Death: + PDED A 6; + PDED B 6 A_Scream; + PDED C 6; + PDED D 6 A_Fall; + PDED E 6; + PDED FGHIJIJIJKL 5; + PDED MNOP 4; + PDED Q 4 A_SpawnItemEx("AlienSpectre5", 0, 0, 0, 0, 0, random[spectrespawn](0,255)*0.0078125, 0, SXF_NOCHECKPOSITION); + PDED RS 4; + PDED T -1; + Stop; + } +} + + +// Loremaster Projectile ---------------------------------------------------- + +class LoreShot : Actor +{ + Default + { + Speed 20; + Height 14; + Radius 10; + Projectile; + +STRIFEDAMAGE + Damage 2; + MaxStepHeight 4; + SeeSound "loremaster/chain"; + ActiveSound "loremaster/swish"; + } + + States + { + Spawn: + OCLW A 2 A_LoremasterChain; + Loop; + Death: + OCLW A 6; + Stop; + } + + override int DoSpecialDamage (Actor victim, int damage, Name damagetype) + { + + if (victim != NULL && target != NULL && !victim.bDontThrust) + { + Vector3 thrust = victim.Vec3To(target); + victim.Vel += thrust.Unit() * (255. * 50 / max(victim.Mass, 1)); + } + return damage; + } + + void A_LoremasterChain () + { + A_PlaySound ("loremaster/active", CHAN_BODY); + Spawn("LoreShot2", Pos, ALLOW_REPLACE); + Spawn("LoreShot2", Vec3Offset(-Vel.x/2., -Vel.y/2., -Vel.z/2.), ALLOW_REPLACE); + Spawn("LoreShot2", Vec3Offset(-Vel.x, -Vel.y, -Vel.z), ALLOW_REPLACE); + } + +} + +// Loremaster Subprojectile ------------------------------------------------- + +class LoreShot2 : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + } + States + { + Spawn: + TEND A 20; + Stop; + } +} + diff --git a/wadsrc/static/zscript/strife/macil.txt b/wadsrc/static/zscript/strife/macil.txt new file mode 100644 index 0000000000..870f0db359 --- /dev/null +++ b/wadsrc/static/zscript/strife/macil.txt @@ -0,0 +1,95 @@ + +// Macil (version 1) --------------------------------------------------------- + +class Macil1 : Actor +{ + Default + { + Health 95; + Radius 20; + Height 56; + Speed 8; + Painchance 250; + Monster; + -COUNTKILL + +NOTDMATCH + +NOICEDEATH + +NOSPLASHALERT + +NODAMAGE + +NEVERRESPAWN + DamageFactor "Fire", 0.5; + MinMissileChance 150; + SeeSound "macil/sight"; + PainSound "macil/pain"; + ActiveSound "macil/active"; + CrushPainSound "misc/pcrush"; + Tag "$TAG_MACIL1"; + Obituary "$OB_MACIL"; + DropItem "BoxOfBullets"; + MaxStepHeight 16; + MaxDropoffHeight 32; + } + States + { + Spawn: + LEDR C 5 A_Look2; + Loop; + LEDR A 8; + Loop; + LEDR B 8; + Loop; + LEAD ABCD 6 A_Wander; + Loop; + See: + LEAD AABBCCDD 3 A_Chase; + Loop; + Missile: + Death: + LEAD E 2 A_FaceTarget; + LEAD F 2 BRIGHT A_ShootGun; + LEAD E 1 A_SentinelRefire; + Loop; + Pain: + LEAD Y 3; + LEAD Y 3 A_Pain; + Goto See; + } +} + + +// Macil (version 2) --------------------------------------------------------- + +class Macil2 : Macil1 +{ + Default + { + Painchance 200; + +COUNTKILL + +SPECTRAL + -NODAMAGE + Tag "$TAG_MACIL2"; + DeathSound "macil/slop"; + DropItem "None"; + DamageFactor "SpectralLow", 0; + } + States + { + Missile: + LEAD E 4 A_FaceTarget; + LEAD F 4 BRIGHT A_ShootGun; + LEAD E 2 A_SentinelRefire; + Loop; + Death: + LEAD G 5; + LEAD H 5 A_Scream; + LEAD IJ 4; + LEAD K 3; + LEAD L 3 A_NoBlocking; + LEAD MNOPQRSTUV 3; + LEAD W 3 A_SpawnItemEx("AlienSpectre4", 0, 0, 0, 0, 0, random[spectrespawn](0,255)*0.0078125, 0, SXF_NOCHECKPOSITION); + LEAD X -1; + Stop; + } +} + + diff --git a/wadsrc/static/zscript/strife/merchants.txt b/wadsrc/static/zscript/strife/merchants.txt new file mode 100644 index 0000000000..71b7976391 --- /dev/null +++ b/wadsrc/static/zscript/strife/merchants.txt @@ -0,0 +1,108 @@ +// Base class for the merchants --------------------------------------------- + +class Merchant : Actor +{ + Default + { + Health 10000000; + PainChance 256; // a merchant should always enter the pain state when getting hurt + Radius 20; + Height 56; + Mass 5000; + CrushPainSound "misc/pcrush"; + +SOLID + +SHOOTABLE + +NOTDMATCH + +NOSPLASHALERT + +NODAMAGE + } + States + { + Spawn: + MRST A 10 A_Look2; + Loop; + MRLK A 30 A_ActiveSound; + Loop; + MRLK B 30; + Loop; + MRBD ABCDEDCB 4; + MRBD A 5; + MRBD F 6; + Loop; + See: + Pain: + MRPN A 1; + MRPN A 2 A_AlertMonsters; + MRPN B 3 A_Pain; + MRPN C 3; + MRPN D 9 Door_CloseWaitOpen(999, 64, 960); + MRPN C 4; + MRPN B 3; + MRPN A 3 A_ClearSoundTarget; + Goto Spawn; + Yes: + MRYS A 20; + // Fall through + Greetings: + MRGT ABCDEFGHI 5; + Goto Spawn; + No: + MRNO AB 6; + MRNO C 10; + MRNO BA 6; + Goto Greetings; + } +} + + +// Weapon Smith ------------------------------------------------------------- + +class WeaponSmith : Merchant +{ + Default + { + PainSound "smith/pain"; + Tag "$TAG_WEAPONSMITH"; + } +} + + +// Bar Keep ----------------------------------------------------------------- + +class BarKeep : Merchant +{ + Default + { + Translation 4; + PainSound "barkeep/pain"; + ActiveSound "barkeep/active"; + Tag "$TAG_BARKEEP"; + } +} + + +// Armorer ------------------------------------------------------------------ + +class Armorer : Merchant +{ + Default + { + Translation 5; + PainSound "armorer/pain"; + Tag "$TAG_ARMORER"; + } +} + + +// Medic -------------------------------------------------------------------- + +class Medic : Merchant +{ + Default + { + Translation 6; + PainSound "medic/pain"; + Tag "$TAG_MEDIC"; + } +} + diff --git a/wadsrc/static/zscript/strife/oracle.txt b/wadsrc/static/zscript/strife/oracle.txt new file mode 100644 index 0000000000..740a7b69a3 --- /dev/null +++ b/wadsrc/static/zscript/strife/oracle.txt @@ -0,0 +1,51 @@ + +// Oracle ------------------------------------------------------------------- + +class Oracle : Actor +{ + Default + { + Health 1; + Radius 15; + Height 56; + Monster; + +NOTDMATCH + +NOBLOOD + +NEVERRESPAWN + DamageFactor "Fire", 0.5; + DamageFactor "SpectralLow", 0; + MaxDropoffHeight 32; + Tag "$TAG_ORACLE"; + DropItem "Meat"; + } + + States + { + Spawn: + ORCL A -1; + Stop; + Death: + ORCL BCDEFGHIJK 5; + ORCL L 5 A_NoBlocking; + ORCL M 5; + ORCL N 5 A_WakeOracleSpectre; + ORCL OP 5; + ORCL Q -1; + Stop; + } + + void A_WakeOracleSpectre () + { + ThinkerIterator it = ThinkerIterator.Create("AlienSpectre3"); + Actor spectre = Actor(it.Next()); + + if (spectre != NULL && spectre.health > 0 && self.target != spectre) + { + spectre.CurSector.SoundTarget = spectre.LastHeard = self.LastHeard; + spectre.target = self.target; + spectre.SetState (spectre.SeeState); + } + } + + +} diff --git a/wadsrc/static/zscript/strife/peasants.txt b/wadsrc/static/zscript/strife/peasants.txt new file mode 100644 index 0000000000..6645c69fa6 --- /dev/null +++ b/wadsrc/static/zscript/strife/peasants.txt @@ -0,0 +1,251 @@ + +// Peasant Base Class ------------------------------------------------------- + +class Peasant : StrifeHumanoid +{ + Default + { + Health 31; + PainChance 200; + Speed 8; + Radius 20; + Height 56; + Monster; + +NEVERTARGET + -COUNTKILL + +NOSPLASHALERT + +FLOORCLIP + +JUSTHIT + MinMissileChance 150; + MaxStepHeight 16; + MaxDropoffHeight 32; + SeeSound "peasant/sight"; + AttackSound "peasant/attack"; + PainSound "peasant/pain"; + DeathSound "peasant/death"; + HitObituary "$OB_PEASANT"; + } + States + { + Spawn: + PEAS A 10 A_Look2; + Loop; + See: + PEAS AABBCCDD 5 A_Wander; + Goto Spawn; + Melee: + PEAS E 10 A_FaceTarget; + PEAS F 8 A_CustomMeleeAttack(2*random[PeasantAttack](1,5)+2); + PEAS E 8; + Goto See; + Pain: + PEAS O 3; + PEAS O 3 A_Pain; + Goto Melee; + Wound: + PEAS G 5; + PEAS H 10 A_GetHurt; + PEAS I 6; + Goto Wound+1; + Death: + PEAS G 5; + PEAS H 5 A_Scream; + PEAS I 6; + PEAS J 5 A_NoBlocking; + PEAS K 5; + PEAS L 6; + PEAS M 8; + PEAS N 1400; + GIBS U 5; + GIBS V 1400; + Stop; + XDeath: + GIBS M 5 A_TossGib; + GIBS N 5 A_XScream; + GIBS O 5 A_NoBlocking; + GIBS PQRS 4 A_TossGib; + Goto Death+8; + } +} + +// Peasant Variant 1 -------------------------------------------------------- + +class Peasant1 : Peasant +{ + Default + { + Speed 4; + } +} + +class Peasant2 : Peasant +{ + Default + { + Speed 5; + } +} + +class Peasant3 : Peasant +{ + Default + { + Speed 5; + } +} + +class Peasant4 : Peasant +{ + Default + { + Translation 0; + Speed 7; + } +} + +class Peasant5 : Peasant +{ + Default + { + Translation 0; + Speed 7; + } +} + +class Peasant6 : Peasant +{ + Default + { + Translation 0; + Speed 7; + } +} + +class Peasant7 : Peasant +{ + Default + { + Translation 2; + } +} + +class Peasant8 : Peasant +{ + Default + { + Translation 2; + } +} + +class Peasant9 : Peasant +{ + Default + { + Translation 2; + } +} + +class Peasant10 : Peasant +{ + Default + { + Translation 1; + } +} + +class Peasant11 : Peasant +{ + Default + { + Translation 1; + } +} + +class Peasant12 : Peasant +{ + Default + { + Translation 1; + } +} + +class Peasant13 : Peasant +{ + Default + { + Translation 3; + } +} + +class Peasant14 : Peasant +{ + Default + { + Translation 3; + } +} + +class Peasant15 : Peasant +{ + Default + { + Translation 3; + } +} + +class Peasant16 : Peasant +{ + Default + { + Translation 5; + } +} + +class Peasant17 : Peasant +{ + Default + { + Translation 5; + } +} + +class Peasant18 : Peasant +{ + Default + { + Translation 5; + } +} + +class Peasant19 : Peasant +{ + Default + { + Translation 4; + } +} + +class Peasant20 : Peasant +{ + Default + { + Translation 4; + } +} + +class Peasant21 : Peasant +{ + Default + { + Translation 4; + } +} + +class Peasant22 : Peasant +{ + Default + { + Translation 6; + } +} + diff --git a/wadsrc/static/zscript/strife/programmer.txt b/wadsrc/static/zscript/strife/programmer.txt new file mode 100644 index 0000000000..3fa34b6595 --- /dev/null +++ b/wadsrc/static/zscript/strife/programmer.txt @@ -0,0 +1,237 @@ + +// Programmer --------------------------------------------------------------- + +class Programmer : Actor +{ + Default + { + Health 1100; + PainChance 50; + Speed 26; + FloatSpeed 5; + Radius 45; + Height 60; + Mass 800; + Damage 4; + Monster; + +NOGRAVITY + +FLOAT + +NOBLOOD + +NOTDMATCH + +DONTMORPH + +NOBLOCKMONST + +LOOKALLAROUND + +NOICEDEATH + +NOTARGETSWITCH + DamageFactor "Fire", 0.5; + MinMissileChance 150; + AttackSound "programmer/attack"; + PainSound "programmer/pain"; + DeathSound "programmer/death"; + ActiveSound "programmer/active"; + Obituary "$OB_PROGRAMMER"; + DropItem "Sigil1"; + } + + States + { + Spawn: + PRGR A 5 A_Look; + PRGR A 1 A_SentinelBob; + Loop; + See: + PRGR A 160 A_SentinelBob; + PRGR BCD 5 A_SentinelBob; + PRGR EF 2 A_SentinelBob; + PRGR EF 3 A_Chase; + Goto See+4; + Melee: + PRGR E 2 A_SentinelBob; + PRGR F 3 A_SentinelBob; + PRGR E 3 A_FaceTarget; + PRGR F 4 A_ProgrammerMelee; + Goto See+4; + Missile: + PRGR G 5 A_FaceTarget; + PRGR H 5 A_SentinelBob; + PRGR I 5 Bright A_FaceTarget; + PRGR J 5 Bright A_SpotLightning; + Goto See+4; + Pain: + PRGR K 5 A_Pain; + PRGR L 5 A_SentinelBob; + Goto See+4; + Death: + PRGR L 7 Bright A_TossGib; + PRGR M 7 Bright A_Scream; + PRGR N 7 Bright A_TossGib; + PRGR O 7 Bright A_NoBlocking; + PRGR P 7 Bright A_TossGib; + PRGR Q 7 Bright A_SpawnProgrammerBase; + PRGR R 7 Bright; + PRGR S 6 Bright; + PRGR TUVW 5 Bright; + PRGR X 32 Bright; + PRGR X -1 Bright A_ProgrammerDeath; + Stop; + } + + //============================================================================ + // + // A_ProgrammerMelee + // + //============================================================================ + + void A_ProgrammerMelee () + { + if (target == null) + return; + + A_FaceTarget (); + + if (!CheckMeleeRange ()) + return; + + A_PlaySound("programmer/clank", CHAN_WEAPON); + + int damage = ((random[Programmer]() % 10) + 1) * 6; + int newdam = DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + } + + //============================================================================ + // + // A_SpawnProgrammerBase + // + //============================================================================ + + void A_SpawnProgrammerBase () + { + Actor foo = Spawn("ProgrammerBase", Pos + (0,0,24), ALLOW_REPLACE); + if (foo != null) + { + foo.Angle = Angle + 180. + Random2[Programmer]() * (360. / 1024.); + foo.VelFromAngle(); + foo.Vel.Z = random[Programmer]() / 128.; + } + } + + //============================================================================ + // + // A_ProgrammerDeath + // + //============================================================================ + + void A_ProgrammerDeath () + { + if (!CheckBossDeath ()) + return; + + for (int i = 0; i < MAXPLAYERS; ++i) + { + if (playeringame[i] && players[i].health > 0) + { + players[i].mo.GiveInventoryType ("ProgLevelEnder"); + break; + } + } + // the sky change scripts are now done as special actions in MAPINFO + A_BossDeath(); + } + + //============================================================================ + // + // A_SpotLightning + // + //============================================================================ + + void A_SpotLightning() + { + if (target == null) return; + + Actor spot = Spawn("SpectralLightningSpot", (target.pos.xy, target.floorz), ALLOW_REPLACE); + if (spot != null) + { + spot.threshold = 25; + spot.target = self; + spot.FriendPlayer = 0; + spot.tracer = target; + } + } + +} + + +// The Programmer's base for when he dies ----------------------------------- + +class ProgrammerBase : Actor +{ + Default + { + +NOBLOCKMAP + +NOCLIP + +NOBLOOD + } + States + { + Spawn: + BASE A 5 Bright A_Explode(32,32,1,1); + BASE BCD 5 Bright; + BASE EFG 5; + BASE H -1; + Stop; + } +} + + +// The Programmer level ending thing ---------------------------------------- + +class ProgLevelEnder : Inventory +{ + Default + { + +INVENTORY.UNDROPPABLE + } + + + //============================================================================ + // + // AProgLevelEnder :: Tick + // + // Fade to black, end the level, then unfade. + // + //============================================================================ + + override void Tick () + { + if (special2 == 0) + { // fade out over .66 second + special1 += 255 / (TICRATE*2/3); + if (++special1 >= 255) + { + special1 = 255; + special2 = 1; + Exit_Normal(0); + } + } + else + { // fade in over two seconds + special1 -= 255 / (TICRATE*2); + if (special1 <= 0) + { + Destroy (); + } + } + } + + //============================================================================ + // + // AProgLevelEnder :: GetBlend + // + //============================================================================ + + override Color GetBlend () + { + return Color(special1, 0, 0, 0); + } +} diff --git a/wadsrc/static/actors/strife/questitems.txt b/wadsrc/static/zscript/strife/questitems.txt similarity index 51% rename from wadsrc/static/actors/strife/questitems.txt rename to wadsrc/static/zscript/strife/questitems.txt index 11da7c90f1..4946f0414f 100644 --- a/wadsrc/static/actors/strife/questitems.txt +++ b/wadsrc/static/zscript/strife/questitems.txt @@ -16,11 +16,11 @@ * 13 You've freed the prisoners! * 14 You've Blown Up the Crystal * 15 You got the guard uniform - * 16 You've Blown Up the Gates (/Piston) - * 17 You watched the Sigil slideshow on map10 + * 16 You've Blown Up the Gates (/Piston); + * 17 You watched the Sigil slideshow on map10; * 18 You got the Oracle pass * 19 You met Quincy and talked to him about the Bishop - * 20 + * 20; * 21 You Killed the Bishop! * 22 The Oracle has told you to kill Macil * 23 You've Killed The Oracle! @@ -30,146 +30,155 @@ * 27 You've Blown Up the Computer * 28 You got the catacomb key * 29 You destroyed the mind control device in the mines - * 30 - * 31 + * 30; + * 31; */ -ACTOR QuestItem : Inventory +class QuestItem : Inventory { States { Spawn: - TOKN A -1 - Stop + TOKN A -1; + Stop; } } // Quest Items ------------------------------------------------------------- -ACTOR QuestItem1 : QuestItem +class QuestItem1 : QuestItem { } -ACTOR QuestItem2 : QuestItem +class QuestItem2 : QuestItem { } -ACTOR QuestItem3 : QuestItem +class QuestItem3 : QuestItem { } -ACTOR QuestItem4 : QuestItem +class QuestItem4 : QuestItem { - Tag "$TAG_QUEST4" + Default + { + Tag "$TAG_QUEST4"; + } } -ACTOR QuestItem5 : QuestItem +class QuestItem5 : QuestItem { - Tag "$TAG_QUEST5" + Default + { + Tag "$TAG_QUEST5"; + } } -ACTOR QuestItem6 : QuestItem +class QuestItem6 : QuestItem { - Tag "TAG_QUEST6" + Default + { + Tag "TAG_QUEST6"; + } } -ACTOR QuestItem7 : QuestItem +class QuestItem7 : QuestItem { } -ACTOR QuestItem8 : QuestItem +class QuestItem8 : QuestItem { } -ACTOR QuestItem9 : QuestItem +class QuestItem9 : QuestItem { } -ACTOR QuestItem10 : QuestItem +class QuestItem10 : QuestItem { } -ACTOR QuestItem11 : QuestItem +class QuestItem11 : QuestItem { } -ACTOR QuestItem12 : QuestItem +class QuestItem12 : QuestItem { } -ACTOR QuestItem13 : QuestItem +class QuestItem13 : QuestItem { } -ACTOR QuestItem14 : QuestItem +class QuestItem14 : QuestItem { } -ACTOR QuestItem15 : QuestItem +class QuestItem15 : QuestItem { } -ACTOR QuestItem16 : QuestItem +class QuestItem16 : QuestItem { } -ACTOR QuestItem17 : QuestItem +class QuestItem17 : QuestItem { } -ACTOR QuestItem18 : QuestItem +class QuestItem18 : QuestItem { } -ACTOR QuestItem19 : QuestItem +class QuestItem19 : QuestItem { } -ACTOR QuestItem20 : QuestItem +class QuestItem20 : QuestItem { } -ACTOR QuestItem21 : QuestItem +class QuestItem21 : QuestItem { } -ACTOR QuestItem22 : QuestItem +class QuestItem22 : QuestItem { } -ACTOR QuestItem23 : QuestItem +class QuestItem23 : QuestItem { } -ACTOR QuestItem24 : QuestItem +class QuestItem24 : QuestItem { } -ACTOR QuestItem25 : QuestItem +class QuestItem25 : QuestItem { } -ACTOR QuestItem26 : QuestItem +class QuestItem26 : QuestItem { } -ACTOR QuestItem27 : QuestItem +class QuestItem27 : QuestItem { } -ACTOR QuestItem28 : QuestItem +class QuestItem28 : QuestItem { } -ACTOR QuestItem29 : QuestItem +class QuestItem29 : QuestItem { } -ACTOR QuestItem30 : QuestItem +class QuestItem30 : QuestItem { } -ACTOR QuestItem31 : QuestItem +class QuestItem31 : QuestItem { } diff --git a/wadsrc/static/zscript/strife/ratbuddy.txt b/wadsrc/static/zscript/strife/ratbuddy.txt new file mode 100644 index 0000000000..fc0c9c63e0 --- /dev/null +++ b/wadsrc/static/zscript/strife/ratbuddy.txt @@ -0,0 +1,37 @@ + +class RatBuddy : Actor +{ + Default + { + Health 5; + Speed 13; + Radius 10; + Height 16; + +NOBLOOD +FLOORCLIP +CANPASS + +ISMONSTER +INCOMBAT + MinMissileChance 150; + MaxStepHeight 16; + MaxDropoffHeight 32; + Tag "$TAG_RATBUDDY"; + SeeSound "rat/sight"; + DeathSound "rat/death"; + ActiveSound "rat/active"; + } + States + { + Spawn: + RATT A 10 A_Look; + Loop; + See: + RATT AABB 4 A_Chase; + Loop; + Melee: + RATT A 8 A_Wander; + RATT B 4 A_Wander; + Goto See; + Death: + MEAT Q 700; + Stop; + } +} + diff --git a/wadsrc/static/zscript/strife/reaver.txt b/wadsrc/static/zscript/strife/reaver.txt new file mode 100644 index 0000000000..6ebcd47e23 --- /dev/null +++ b/wadsrc/static/zscript/strife/reaver.txt @@ -0,0 +1,88 @@ + +class Reaver : Actor +{ + Default + { + Health 150; + Painchance 128; + Speed 12; + Radius 20; + Height 60; + Monster; + +NOBLOOD + +INCOMBAT + MinMissileChance 150; + MaxDropoffHeight 32; + Mass 500; + SeeSound "reaver/sight"; + PainSound "reaver/pain"; + DeathSound "reaver/death"; + ActiveSound "reaver/active"; + HitObituary "$OB_REAVERHIT"; + Obituary "$OB_REAVER"; + } + + States + { + Spawn: + ROB1 A 10 A_Look; + Loop; + See: + ROB1 BBCCDDEE 3 A_Chase; + Loop; + Melee: + ROB1 H 6 Slow A_FaceTarget; + ROB1 I 8 Slow A_CustomMeleeAttack(random[ReaverMelee](1,8)*3, "reaver/blade"); + ROB1 H 6 Slow; + Goto See; + Missile: + ROB1 F 8 Slow A_FaceTarget; + ROB1 G 11 Slow BRIGHT A_ReaverRanged; + Goto See; + Pain: + ROB1 A 2 Slow; + ROB1 A 2 A_Pain; + Goto See; + Death: + ROB1 J 6; + ROB1 K 6 A_Scream; + ROB1 L 5; + ROB1 M 5 A_NoBlocking; + ROB1 NOP 5; + ROB1 Q 6 A_Explode(32, 32, alert:true); + ROB1 R -1; + Stop; + XDeath: + ROB1 L 5 A_TossGib; + ROB1 M 5 A_Scream; + ROB1 N 5 A_TossGib; + ROB1 O 5 A_NoBlocking; + ROB1 P 5 A_TossGib; + Goto Death+7; + } + +} + +extend class Actor +{ + // The Inquisitor also uses this function + + void A_ReaverRanged () + { + if (target != null) + { + A_FaceTarget (); + A_PlaySound ("reaver/attack", CHAN_WEAPON); + double bangle = Angle; + double pitch = AimLineAttack (bangle, MISSILERANGE); + + for (int i = 0; i < 3; ++i) + { + double ang = bangle + Random2[ReaverAttack]() * (22.5 / 256); + int damage = ((random[ReaverAttack]() & 7) + 1) * 3; + LineAttack (ang, MISSILERANGE, pitch, damage, 'Hitscan', "StrifePuff"); + } + } + } + +} \ No newline at end of file diff --git a/wadsrc/static/zscript/strife/rebels.txt b/wadsrc/static/zscript/strife/rebels.txt new file mode 100644 index 0000000000..24deea25b1 --- /dev/null +++ b/wadsrc/static/zscript/strife/rebels.txt @@ -0,0 +1,207 @@ + + +// Base class for the rebels ------------------------------------------------ + +class Rebel : StrifeHumanoid +{ + Default + { + Health 60; + Painchance 250; + Speed 8; + Radius 20; + Height 56; + Monster; + +FRIENDLY + -COUNTKILL + +NOSPLASHALERT + MinMissileChance 150; + Tag "$TAG_REBEL"; + SeeSound "rebel/sight"; + PainSound "rebel/pain"; + DeathSound "rebel/death"; + ActiveSound "rebel/active"; + Obituary "$OB_REBEL"; + } + States + { + Spawn: + HMN1 P 5 A_Look2; + Loop; + HMN1 Q 8; + Loop; + HMN1 R 8; + Loop; + HMN1 ABCDABCD 6 A_Wander; + Loop; + See: + HMN1 AABBCCDD 3 A_Chase; + Loop; + Missile: + HMN1 E 10 A_FaceTarget; + HMN1 F 10 BRIGHT A_ShootGun; + HMN1 E 10 A_ShootGun; + Goto See; + Pain: + HMN1 O 3; + HMN1 O 3 A_Pain; + Goto See; + Death: + HMN1 G 5; + HMN1 H 5 A_Scream; + HMN1 I 3 A_NoBlocking; + HMN1 J 4; + HMN1 KLM 3; + HMN1 N -1; + Stop; + XDeath: + RGIB A 4 A_TossGib; + RGIB B 4 A_XScream; + RGIB C 3 A_NoBlocking; + RGIB DEF 3 A_TossGib; + RGIB G 3; + RGIB H 1400; + Stop; + } +} + +// Rebel 1 ------------------------------------------------------------------ + +class Rebel1 : Rebel +{ + Default + { + DropItem "ClipOfBullets"; + } +} + +// Rebel 2 ------------------------------------------------------------------ + +class Rebel2 : Rebel +{ +} + +// Rebel 3 ------------------------------------------------------------------ + +class Rebel3 : Rebel +{ +} + +// Rebel 4 ------------------------------------------------------------------ + +class Rebel4 : Rebel +{ +} + +// Rebel 5 ------------------------------------------------------------------ + +class Rebel5 : Rebel +{ +} + +// Rebel 6 ------------------------------------------------------------------ + +class Rebel6 : Rebel +{ +} + +// Teleporter Beacon -------------------------------------------------------- + +class TeleporterBeacon : Inventory +{ + Default + { + Health 5; + Radius 16; + Height 16; + Inventory.MaxAmount 3; + +DROPPED + +INVENTORY.INVBAR + Inventory.Icon "I_BEAC"; + Tag "$TAG_TELEPORTERBEACON"; + Inventory.PickupMessage "$TXT_BEACON"; + } + + States + { + Spawn: + BEAC A -1; + Stop; + Drop: + BEAC A 30; + BEAC A 160 A_Beacon; + Wait; + Death: + BEAC A 1 A_FadeOut(0.015); + Loop; + } + + // Teleporter Beacon -------------------------------------------------------- + + override bool Use (bool pickup) + { + // Increase the amount by one so that when DropInventory decrements it, + // the actor will have the same number of beacons that he started with. + // When we return to UseInventory, it will take care of decrementing + // Amount again and disposing of self item if there are no more. + Amount++; + Inventory drop = Owner.DropInventory (self); + if (drop == null) + { + Amount--; + return false; + } + else + { + drop.SetStateLabel("Drop"); + drop.target = Owner; + return true; + } + } + + void A_Beacon() + { + Actor owner = target; + Actor rebel = Spawn("Rebel1", (pos.xy, floorz), ALLOW_REPLACE); + if (!rebel.TryMove (rebel.Pos.xy, true)) + { + rebel.Destroy (); + return; + } + // Once the rebels start teleporting in, you can't pick up the beacon anymore. + bSpecial = false; + Inventory(self).DropTime = 0; + // Set up the new rebel. + rebel.threshold = rebel.DefThreshold; + rebel.target = null; + rebel.bInCombat = true; + rebel.LastHeard = owner; // Make sure the rebels look for targets + if (deathmatch) + { + rebel.health *= 2; + } + if (owner != null) + { + // Rebels are the same color as their owner (but only in multiplayer) + if (multiplayer) + { + rebel.Translation = owner.Translation; + } + rebel.SetFriendPlayer(owner.player); + // Set the rebel's target to whatever last hurt the player, so long as it's not + // one of the player's other rebels. + if (owner.target != null && !rebel.IsFriend (owner.target)) + { + rebel.target = owner.target; + } + } + + rebel.SetState (rebel.SeeState); + rebel.Angle = Angle; + rebel.SpawnTeleportFog(rebel.Vec3Angle(20., Angle, 0), false, true); + if (--health < 0) + { + SetStateLabel("Death"); + } + } +} \ No newline at end of file diff --git a/wadsrc/static/zscript/strife/sentinel.txt b/wadsrc/static/zscript/strife/sentinel.txt new file mode 100644 index 0000000000..e9e6255d4d --- /dev/null +++ b/wadsrc/static/zscript/strife/sentinel.txt @@ -0,0 +1,179 @@ + +// Sentinel ----------------------------------------------------------------- + +class Sentinel : Actor +{ + Default + { + Health 100; + Painchance 255; + Speed 7; + Radius 23; + Height 53; + Mass 300; + Monster; + +SPAWNCEILING + +NOGRAVITY + +DROPOFF + +NOBLOOD + +NOBLOCKMONST + +INCOMBAT + +MISSILEMORE + +LOOKALLAROUND + +NEVERRESPAWN + MinMissileChance 150; + SeeSound "sentinel/sight"; + DeathSound "sentinel/death"; + ActiveSound "sentinel/active"; + Obituary "$OB_SENTINEL"; + } + + States + { + Spawn: + SEWR A 10 A_Look; + Loop; + See: + SEWR A 6 A_SentinelBob; + SEWR A 6 A_Chase; + Loop; + Missile: + SEWR B 4 A_FaceTarget; + SEWR C 8 Bright A_SentinelAttack; + SEWR C 4 Bright A_SentinelRefire; + Goto Missile+1; + Pain: + SEWR D 5 A_Pain; + Goto Missile+2; + Death: + SEWR D 7 A_Fall; + SEWR E 8 Bright A_TossGib; + SEWR F 5 Bright A_Scream; + SEWR GH 4 Bright A_TossGib; + SEWR I 4; + SEWR J 5; + Stop; + } + + void A_SentinelAttack () + { + // [BB] Without a target the P_SpawnMissileZAimed call will crash. + if (!target) + { + return; + } + + Actor missile = SpawnMissileZAimed (pos.z + 32, target, "SentinelFX2"); + + if (missile != NULL && (missile.Vel.X != 0 || missile.Vel.Y != 0)) + { + for (int i = 8; i > 1; --i) + { + Actor trail = Spawn("SentinelFX1", Vec3Angle(missile.radius*i, missile.angle, 32 + missile.Vel.Z / 4 * i), ALLOW_REPLACE); + if (trail != NULL) + { + trail.target = self; + trail.Vel = missile.Vel; + trail.CheckMissileSpawn (radius); + } + } + missile.AddZ(missile.Vel.Z / 4); + } + } + + +} + +// Sentinel FX 1 ------------------------------------------------------------ + +class SentinelFX1 : Actor +{ + Default + { + Speed 40; + Radius 10; + Height 8; + Damage 0; + DamageType "Disintegrate"; + Projectile; + +STRIFEDAMAGE + MaxStepHeight 4; + RenderStyle "Add"; + } + States + { + Spawn: + SHT1 AB 4; + Loop; + Death: + POW1 J 4; + Stop; + } +} + +// Sentinel FX 2 ------------------------------------------------------------ + +class SentinelFX2 : SentinelFX1 +{ + Default + { + SeeSound "sentinel/plasma"; + Damage 1; + } + States + { + Death: + POW1 FGHI 4; + Goto Super::Death; + } +} + + +extend class Actor +{ + // These are used elsewhere, too. + void A_SentinelBob() + { + if (bInFloat) + { + Vel.Z = 0; + return; + } + if (threshold != 0) + return; + + double maxz = ceilingz - Height - 16; + double minz = floorz + 96; + if (minz > maxz) + { + minz = maxz; + } + if (minz < pos.z) + { + Vel.Z -= 1; + } + else + { + Vel.Z += 1; + } + reactiontime = (minz >= pos.z) ? 4 : 0; + } + + void A_SentinelRefire() + { + A_FaceTarget (); + + if (random[SentinelRefire]() >= 30) + { + if (target == NULL || + target.health <= 0 || + !CheckSight (target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES) || + HitFriend() || + (MissileState == NULL && !CheckMeleeRange()) || + random[SentinelRefire]() < 40) + { + SetState (SeeState); + } + } + } +} \ No newline at end of file diff --git a/wadsrc/static/zscript/strife/sigil.txt b/wadsrc/static/zscript/strife/sigil.txt new file mode 100644 index 0000000000..096915ccf2 --- /dev/null +++ b/wadsrc/static/zscript/strife/sigil.txt @@ -0,0 +1,520 @@ + +// The Almighty Sigil! ------------------------------------------------------ + +class Sigil : Weapon +{ + // NUmPieces gets stored in 'health', so that it can be quickly accessed by ACS's GetSigilPieces function. + int downpieces; + + Default + { + Weapon.Kickback 100; + Weapon.SelectionOrder 4000; + Health 1; + +FLOORCLIP + +WEAPON.CHEATNOTWEAPON + Inventory.PickupSound "weapons/sigilcharge"; + Tag "$TAG_SIGIL"; + Inventory.Icon "I_SGL1"; + Inventory.PickupMessage "$TXT_SIGIL"; + } + + States(Actor) + { + Spawn: + SIGL A 1; + SIGL A -1 A_SelectPiece; + Stop; + SIGL B -1; + Stop; + SIGL C -1; + Stop; + SIGL D -1; + Stop; + SIGL E -1; + Stop; + } + States(Weapon) + { + Ready: + SIGH A 0 Bright A_SelectSigilView; + Wait; + SIGH A 1 Bright A_WeaponReady; + Wait; + SIGH B 1 Bright A_WeaponReady; + Wait; + SIGH C 1 Bright A_WeaponReady; + Wait; + SIGH D 1 Bright A_WeaponReady; + Wait; + SIGH E 1 Bright A_WeaponReady; + Wait; + Deselect: + SIGH A 1 Bright A_SelectSigilDown; + Wait; + SIGH A 1 Bright A_Lower; + Wait; + SIGH B 1 Bright A_Lower; + Wait; + SIGH C 1 Bright A_Lower; + Wait; + SIGH D 1 Bright A_Lower; + Wait; + SIGH E 1 Bright A_Lower; + Wait; + Select: + SIGH A 1 Bright A_SelectSigilView; + Wait; + SIGH A 1 Bright A_Raise; + Wait; + SIGH B 1 Bright A_Raise; + Wait; + SIGH C 1 Bright A_Raise; + Wait; + SIGH D 1 Bright A_Raise; + Wait; + SIGH E 1 Bright A_Raise; + Wait; + + Fire: + SIGH A 0 Bright A_SelectSigilAttack; + + SIGH A 18 Bright A_SigilCharge; + SIGH A 3 Bright A_GunFlash; + SIGH A 10 A_FireSigil1; + SIGH A 5; + Goto Ready; + + SIGH B 18 Bright A_SigilCharge; + SIGH B 3 Bright A_GunFlash; + SIGH B 10 A_FireSigil2; + SIGH B 5; + Goto Ready; + + SIGH C 18 Bright A_SigilCharge; + SIGH C 3 Bright A_GunFlash; + SIGH C 10 A_FireSigil3; + SIGH C 5; + Goto Ready; + + SIGH D 18 Bright A_SigilCharge; + SIGH D 3 Bright A_GunFlash; + SIGH D 10 A_FireSigil4; + SIGH D 5; + Goto Ready; + + SIGH E 18 Bright A_SigilCharge; + SIGH E 3 Bright A_GunFlash; + SIGH E 10 A_FireSigil5; + SIGH E 5; + Goto Ready; + Flash: + SIGF A 4 Bright A_Light2; + SIGF B 6 Bright A_LightInverse; + SIGF C 4 Bright A_Light1; + SIGF C 0 Bright A_Light0; + Stop; + } + + + //============================================================================ + // + // ASigil :: HandlePickup + // + //============================================================================ + + override bool HandlePickup (Inventory item) + { + if (item is "Sigil") + { + int otherPieces = item.health; + if (otherPieces > health) + { + item.bPickupGood = true; + Icon = item.Icon; + // If the player is holding the Sigil right now, drop it and bring + // it back with the new piece(s) in view. + if (Owner.player != null && Owner.player.ReadyWeapon == self) + { + DownPieces = health; + Owner.player.PendingWeapon = self; + } + health = otherPieces; + } + return true; + } + return false; + } + + //============================================================================ + // + // ASigil :: CreateCopy + // + //============================================================================ + + override Inventory CreateCopy (Actor other) + { + Sigil copy = Sigil(Spawn("Sigil")); + copy.Amount = Amount; + copy.MaxAmount = MaxAmount; + copy.health = health; + copy.Icon = Icon; + GoAwayAndDie (); + return copy; + } + + //============================================================================ + // + // A_SelectPiece + // + // Decide which sprite frame self Sigil should use as an item, based on how + // many pieces it represents. + // + //============================================================================ + + void A_SelectPiece () + { + int pieces = min (health, 5); + + if (pieces > 1) + { + SetState (FindState("Spawn") + pieces); + } + } + + //============================================================================ + // + // A_SelectSigilView + // + // Decide which first-person frame self Sigil should show, based on how many + // pieces it represents. Strife did self by selecting a flash that looked like + // the Sigil whenever you switched to it and at the end of an attack. I have + // chosen to make the weapon sprite choose the correct frame and let the flash + // be a regular flash. It means I need to use more states, but I think it's + // worth it. + // + //============================================================================ + + action void A_SelectSigilView () + { + if (player == null) + { + return; + } + PSprite pspr = player.GetPSprite(PSP_WEAPON); + pspr.SetState(pspr.CurState + invoker.health); + } + + //============================================================================ + // + // A_SelectSigilDown + // + // Same as A_SelectSigilView, except it uses DownPieces. self is so that when + // you pick up a Sigil, the old one will drop and *then* change to the new + // one. + // + //============================================================================ + + action void A_SelectSigilDown () + { + if (player == null) + { + return; + } + PSprite pspr = player.GetPSprite(PSP_WEAPON); + int pieces = invoker.downpieces; + if (pieces < 1 || pieces > 5) pieces = invoker.health; + pspr.SetState(pspr.CurState + pieces); + } + + //============================================================================ + // + // A_SelectSigilAttack + // + // Same as A_SelectSigilView, but used just before attacking. + // + //============================================================================ + + action void A_SelectSigilAttack () + { + if (player == null) + { + return; + } + PSprite pspr = player.GetPSprite(PSP_WEAPON); + pspr.SetState(pspr.CurState + (4 * invoker.health - 3)); + } + + //============================================================================ + // + // A_SigilCharge + // + //============================================================================ + + action void A_SigilCharge () + { + A_PlaySound ("weapons/sigilcharge", CHAN_WEAPON); + if (player != null) + { + player.extralight = 2; + } + } + + //============================================================================ + // + // A_FireSigil1 + // + //============================================================================ + + action void A_FireSigil1 () + { + Actor spot; + FTranslatedLineTarget t; + + if (player == null || player.ReadyWeapon == null) + return; + + DamageMobj (self, null, 1*4, 'Sigil', DMG_NO_ARMOR); + A_PlaySound ("weapons/sigilcharge", CHAN_WEAPON); + + BulletSlope (t, ALF_PORTALRESTRICT); + if (t.linetarget != null) + { + spot = Spawn("SpectralLightningSpot", (t.linetarget.pos.xy, t.linetarget.floorz), ALLOW_REPLACE); + if (spot != null) + { + spot.tracer = t.linetarget; + } + } + else + { + spot = Spawn("SpectralLightningSpot", Pos, ALLOW_REPLACE); + if (spot != null) + { + spot.VelFromAngle(28., angle); + } + } + if (spot != null) + { + spot.SetFriendPlayer(player); + spot.target = self; + } + } + + //============================================================================ + // + // A_FireSigil2 + // + //============================================================================ + + action void A_FireSigil2 () + { + if (player == null || player.ReadyWeapon == null) + return; + + DamageMobj (self, null, 2*4, 'Sigil', DMG_NO_ARMOR); + A_PlaySound ("weapons/sigilcharge", CHAN_WEAPON); + SpawnPlayerMissile ("SpectralLightningH1"); + } + + //============================================================================ + // + // A_FireSigil3 + // + //============================================================================ + + action void A_FireSigil3 () + { + if (player == null || player.ReadyWeapon == null) + return; + + DamageMobj (self, null, 3*4, 'Sigil', DMG_NO_ARMOR); + A_PlaySound ("weapons/sigilcharge", CHAN_WEAPON); + + angle -= 90.; + for (int i = 0; i < 20; ++i) + { + angle += 9.; + Actor spot = SpawnSubMissile ("SpectralLightningBall1", self); + if (spot != null) + { + spot.SetZ(pos.z + 32); + } + } + angle -= 90.; + } + + //============================================================================ + // + // A_FireSigil4 + // + //============================================================================ + + action void A_FireSigil4 () + { + FTranslatedLineTarget t; + + if (player == null || player.ReadyWeapon == null) + return; + + DamageMobj (self, null, 4*4, 'Sigil', DMG_NO_ARMOR); + A_PlaySound ("weapons/sigilcharge", CHAN_WEAPON); + + BulletSlope (t, ALF_PORTALRESTRICT); + if (t.linetarget != null) + { + Actor spot = SpawnPlayerMissile ("SpectralLightningBigV1", angle, pLineTarget: t, aimFlags: ALF_PORTALRESTRICT); + if (spot != null) + { + spot.tracer = t.linetarget; + } + } + else + { + Actor spot = SpawnPlayerMissile ("SpectralLightningBigV1"); + if (spot != null) + { + spot.VelFromAngle(spot.Speed, angle); + } + } + } + + //============================================================================ + // + // A_FireSigil5 + // + //============================================================================ + + action void A_FireSigil5 () + { + if (player == null || player.ReadyWeapon == null) + return; + + DamageMobj (self, null, 5*4, 'Sigil', DMG_NO_ARMOR); + A_PlaySound ("weapons/sigilcharge", CHAN_WEAPON); + + SpawnPlayerMissile ("SpectralLightningBigBall1"); + } + + //============================================================================ + // + // ASigil :: SpecialDropAction + // + // Monsters don't drop Sigil pieces. The Sigil pieces grab hold of the person + // who killed the dropper and automatically enter their inventory. That's the + // way it works if you believe Macil, anyway... + // + //============================================================================ + + override bool SpecialDropAction (Actor dropper) + { + // Give a Sigil piece to every player in the game + for (int i = 0; i < MAXPLAYERS; ++i) + { + if (playeringame[i] && players[i].mo != null) + { + GiveSigilPiece (players[i].mo); + Destroy (); + } + } + return true; + } + + //============================================================================ + // + // ASigil :: GiveSigilPiece + // + // Gives the actor another Sigil piece, up to 5. Returns the number of Sigil + // pieces the actor previously held. + // + //============================================================================ + + static int GiveSigilPiece (Actor receiver) + { + Sigil sigl = Sigil(receiver.FindInventory("Sigil")); + if (sigl == null) + { + sigl = Sigil(Spawn("Sigil1")); + if (!sigl.CallTryPickup (receiver)) + { + sigl.Destroy (); + } + return 0; + } + else if (sigl.health < 5) + { + ++sigl.health; + static const class sigils[] = + { + "Sigil1", "Sigil2", "Sigil3", "Sigil4", "Sigil5" + }; + sigl.Icon = GetDefaultByType(sigils[clamp(sigl.health, 1, 5)-1]).Icon; + // If the player has the Sigil out, drop it and bring it back up. + if (sigl.Owner.player != null && sigl.Owner.player.ReadyWeapon == sigl) + { + sigl.Owner.player.PendingWeapon = sigl; + sigl.DownPieces = sigl.health - 1; + } + return sigl.health - 1; + } + else + { + return 5; + } + } +} + +// Sigil 1 ------------------------------------------------------------------ + +class Sigil1 : Sigil +{ + Default + { + Inventory.Icon "I_SGL1"; + Health 1; + } +} + +// Sigil 2 ------------------------------------------------------------------ + +class Sigil2 : Sigil +{ + Default + { + Inventory.Icon "I_SGL2"; + Health 2; + } +} + +// Sigil 3 ------------------------------------------------------------------ + +class Sigil3 : Sigil +{ + Default + { + Inventory.Icon "I_SGL3"; + Health 3; + } +} + +// Sigil 4 ------------------------------------------------------------------ + +class Sigil4 : Sigil +{ + Default + { + Inventory.Icon "I_SGL4"; + Health 4; + } +} + +// Sigil 5 ------------------------------------------------------------------ + +class Sigil5 : Sigil +{ + Default + { + Inventory.Icon "I_SGL5"; + Health 5; + } +} diff --git a/wadsrc/static/zscript/strife/spectral.txt b/wadsrc/static/zscript/strife/spectral.txt new file mode 100644 index 0000000000..0878cff948 --- /dev/null +++ b/wadsrc/static/zscript/strife/spectral.txt @@ -0,0 +1,431 @@ + + +// base for all spectral monsters which hurt when being touched-------------- + +class SpectralMonster : Actor +{ + Default + { + Monster; + +SPECIAL + +SPECTRAL + +NOICEDEATH + } + + override void Touch (Actor toucher) + { + toucher.DamageMobj (self, self, 5, 'Melee'); + } + + + //============================================================================ + + void A_SpectreChunkSmall () + { + Actor foo = Spawn("AlienChunkSmall", pos + (0, 0, 10), ALLOW_REPLACE); + + if (foo != null) + { + int t; + + t = random[SpectreChunk]() & 15; + foo.Vel.X = (t - (random[SpectreChunk]() & 7)); + + t = random[SpectreChunk]() & 15; + foo.Vel.Y = (t - (random[SpectreChunk]() & 7)); + + foo.Vel.Z = (random[SpectreChunk]() & 15); + } + } + + void A_SpectreChunkLarge () + { + Actor foo = Spawn("AlienChunkLarge", pos + (0, 0, 10), ALLOW_REPLACE); + + if (foo != null) + { + int t; + + t = random[SpectreChunk]() & 7; + foo.Vel.X = (t - (random[SpectreChunk]() & 15)); + + t = random[SpectreChunk]() & 7; + foo.Vel.Y = (t - (random[SpectreChunk]() & 15)); + + foo.Vel.Z = (random[SpectreChunk]() & 7); + } + } + + void A_Spectre3Attack () + { + if (target == null) + return; + + Actor foo = Spawn("SpectralLightningV2", Pos + (0, 0, 32), ALLOW_REPLACE); + + foo.Vel.Z = -12; + foo.target = self; + foo.FriendPlayer = 0; + foo.tracer = target; + + Angle -= 90.; + for (int i = 0; i < 20; ++i) + { + Angle += 9.; + SpawnSubMissile ("SpectralLightningBall2", self); + } + Angle -= 90.; + } + + //============================================================================ + // + // A_SpotLightning + // + //============================================================================ + + void A_SpotLightning() + { + if (target == null) return; + + Actor spot = Spawn("SpectralLightningSpot", (target.pos.xy, target.floorz), ALLOW_REPLACE); + if (spot != null) + { + spot.threshold = 25; + spot.target = self; + spot.FriendPlayer = 0; + spot.tracer = target; + } + } + +} + + +// Container for all spectral lightning deaths ------------------------------ + +class SpectralLightningBase : Actor +{ + Default + { + +NOTELEPORT + +ACTIVATEIMPACT + +ACTIVATEPCROSS + +STRIFEDAMAGE + MaxStepHeight 4; + RenderStyle "Add"; + SeeSound "weapons/sigil"; + DeathSound "weapons/sigilhit"; + } + States + { + Death: + ZAP1 B 3 A_Explode(32,32); + ZAP1 A 3 A_AlertMonsters; + ZAP1 BCDEFE 3; + ZAP1 DCB 2; + ZAP1 A 1; + Stop; + } +} + +// Spectral Lightning death that does not explode --------------------------- + +class SpectralLightningDeath1 : SpectralLightningBase +{ + States + { + Death: + Goto Super::Death+1; + } +} + +// Spectral Lightning death that does not alert monsters -------------------- + +class SpectralLightningDeath2 : SpectralLightningBase +{ + States + { + Death: + Goto Super::Death+2; + } +} + +// Spectral Lightning death that is shorter than the rest ------------------- + +class SpectralLightningDeathShort : SpectralLightningBase +{ + States + { + Death: + Goto Super::Death+6; + } +} + +// Spectral Lightning (Ball Shaped #1) -------------------------------------- + +class SpectralLightningBall1 : SpectralLightningBase +{ + Default + { + Speed 30; + Radius 8; + Height 16; + Damage 70; + Projectile; + +SPECTRAL + } + States + { + Spawn: + ZOT3 ABCDE 4 Bright; + Loop; + } +} + +// Spectral Lightning (Ball Shaped #2) -------------------------------------- + +class SpectralLightningBall2 : SpectralLightningBall1 +{ + Default + { + Damage 20; + } +} + +// Spectral Lightning (Horizontal #1) --------------------------------------- + +class SpectralLightningH1 : SpectralLightningBase +{ + Default + { + Speed 30; + Radius 8; + Height 16; + Damage 70; + Projectile; + +SPECTRAL + } + + + States + { + Spawn: + ZAP6 A 4 Bright; + ZAP6 BC 4 Bright A_SpectralLightningTail; + Loop; + } + + void A_SpectralLightningTail () + { + Actor foo = Spawn("SpectralLightningHTail", Vec3Offset(-Vel.X, -Vel.Y, 0.), ALLOW_REPLACE); + + foo.Angle = Angle; + foo.FriendPlayer = FriendPlayer; + } +} + + +// Spectral Lightning (Horizontal #2) ------------------------------------- + +class SpectralLightningH2 : SpectralLightningH1 +{ + Default + { + Damage 20; + } +} + +// Spectral Lightning (Horizontal #3) ------------------------------------- + +class SpectralLightningH3 : SpectralLightningH1 +{ + Default + { + Damage 10; + } +} + +// ASpectralLightningHTail -------------------------------------------------- + +class SpectralLightningHTail : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + +DROPOFF + RenderStyle "Add"; + } + States + { + Spawn: + ZAP6 ABC 5 Bright; + Stop; + } +} + +// Spectral Lightning (Big Ball #1) ----------------------------------------- + +class SpectralLightningBigBall1 : SpectralLightningDeath2 +{ + Default + { + Speed 18; + Radius 20; + Height 40; + Damage 130; + Projectile; + +SPECTRAL + } + + States + { + Spawn: + ZAP7 AB 4 Bright A_SpectralBigBallLightning; + ZAP7 CDE 6 Bright A_SpectralBigBallLightning; + Loop; + } + + void A_SpectralBigBallLightning () + { + Class cls = "SpectralLightningH3"; + if (cls) + { + angle += 90.; + SpawnSubMissile (cls, target); + angle += 180.; + SpawnSubMissile (cls, target); + angle -= 270.; + SpawnSubMissile (cls, target); + } + } + +} + + +// Spectral Lightning (Big Ball #2 - less damaging) ------------------------- + +class SpectralLightningBigBall2 : SpectralLightningBigBall1 +{ + Default + { + Damage 30; + } +} + +// Sigil Lightning (Vertical #1) -------------------------------------------- + +class SpectralLightningV1 : SpectralLightningDeathShort +{ + Default + { + Speed 22; + Radius 8; + Height 24; + Damage 100; + Projectile; + DamageType "SpectralLow"; + +SPECTRAL + } + States + { + Spawn: + ZOT1 AB 4 Bright; + ZOT1 CDE 6 Bright; + Loop; + } +} + +// Sigil Lightning (Vertical #2 - less damaging) ---------------------------- + +class SpectralLightningV2 : SpectralLightningV1 +{ + Default + { + Damage 50; + } +} + +// Sigil Lightning Spot (roams around dropping lightning from above) -------- + +class SpectralLightningSpot : SpectralLightningDeath1 +{ + Default + { + Speed 18; + ReactionTime 70; + +NOBLOCKMAP + +NOBLOCKMONST + +NODROPOFF + RenderStyle "Translucent"; + Alpha 0.6; + } + + States + { + Spawn: + ZAP5 A 4 Bright A_Countdown; + ZAP5 B 4 Bright A_SpectralLightning; + ZAP5 CD 4 Bright A_Countdown; + Loop; + } + + void A_SpectralLightning () + { + if (threshold != 0) + --threshold; + + Vel.X += random2[Zap5](3); + Vel.Y += random2[Zap5](3); + + double xo = random2[Zap5](3) * 50.; + double yo = random2[Zap5](3) * 50.; + + class cls; + if (threshold > 25) cls = "SpectralLightningV2"; + else cls = "SpectralLightningV1"; + + Actor flash = Spawn (cls, Vec2OffsetZ(xo, yo, ONCEILINGZ), ALLOW_REPLACE); + + flash.target = target; + flash.Vel.Z = -18; + flash.FriendPlayer = FriendPlayer; + + flash = Spawn("SpectralLightningV2", (pos.xy, ONCEILINGZ), ALLOW_REPLACE); + + flash.target = target; + flash.Vel.Z = -18; + flash.FriendPlayer = FriendPlayer; + } + +} + +// Sigil Lightning (Big Vertical #1) ---------------------------------------- + +class SpectralLightningBigV1 : SpectralLightningDeath1 +{ + Default + { + Speed 28; + Radius 8; + Height 16; + Damage 120; + Projectile; + +SPECTRAL + } + States + { + Spawn: + ZOT2 ABCDE 4 Bright A_Tracer2; + Loop; + } +} + +// Actor 90 ----------------------------------------------------------------- + +class SpectralLightningBigV2 : SpectralLightningBigV1 +{ + Default + { + Damage 60; + } +} diff --git a/wadsrc/static/zscript/strife/stalker.txt b/wadsrc/static/zscript/strife/stalker.txt new file mode 100644 index 0000000000..cede9cae12 --- /dev/null +++ b/wadsrc/static/zscript/strife/stalker.txt @@ -0,0 +1,135 @@ + + +// Stalker ------------------------------------------------------------------ + +class Stalker : Actor +{ + Default + { + Health 80; + Painchance 40; + Speed 16; + Radius 31; + Height 25; + Monster; + +NOGRAVITY + +DROPOFF + +NOBLOOD + +SPAWNCEILING + +INCOMBAT + +NOVERTICALMELEERANGE + MaxDropOffHeight 32; + MinMissileChance 150; + SeeSound "stalker/sight"; + AttackSound "stalker/attack"; + PainSound "stalker/pain"; + DeathSound "stalker/death"; + ActiveSound "stalker/active"; + HitObituary "$OB_STALKER"; + } + + States + { + Spawn: + STLK A 1 A_StalkerLookInit; + Loop; + LookCeiling: + STLK A 10 A_Look; + Loop; + LookFloor: + STLK J 10 A_Look; + Loop; + See: + STLK A 1 Slow A_StalkerChaseDecide; + STLK ABB 3 Slow A_Chase; + STLK C 3 Slow A_StalkerWalk; + STLK C 3 Slow A_Chase; + Loop; + Melee: + STLK J 3 Slow A_FaceTarget; + STLK K 3 Slow A_StalkerAttack; + SeeFloor: + STLK J 3 A_StalkerWalk; + STLK KK 3 A_Chase; + STLK L 3 A_StalkerWalk; + STLK L 3 A_Chase; + Loop; + Pain: + STLK L 1 A_Pain; + Goto See; + Drop: + STLK C 2 A_StalkerDrop; + STLK IHGFED 3; + Goto SeeFloor; + Death: + STLK O 4; + STLK P 4 A_Scream; + STLK QRST 4; + STLK U 4 A_NoBlocking; + STLK VW 4; + STLK "XYZ[" 4 Bright; + Stop; + } + + void A_StalkerChaseDecide () + { + if (!bNoGravity) + { + SetStateLabel("SeeFloor"); + } + else if (ceilingz > pos.z + height) + { + SetStateLabel("Drop"); + } + } + + void A_StalkerLookInit () + { + State st; + if (!bNoGravity) + { + st = FindState("LookCeiling"); + } + else + { + st = FindState("LookFloor"); + } + if (st.NextState != st) + { + SetState (st); + } + } + + void A_StalkerDrop () + { + bNoVerticalMeleeRange = false; + bNoGravity = false; + } + + void A_StalkerAttack () + { + if (bNoGravity) + { + SetStateLabel("Drop"); + } + else if (target != null) + { + A_FaceTarget (); + if (CheckMeleeRange ()) + { + int damage = (random[Stalker]() & 7) * 2 + 2; + + int newdam = target.DamageMobj (self, self, damage, 'Melee'); + target.TraceBleed (newdam > 0 ? newdam : damage, self); + } + } + } + + void A_StalkerWalk () + { + A_PlaySound ("stalker/walk", CHAN_BODY); + A_Chase (); + } + + +} diff --git a/wadsrc/static/zscript/strife/strifeammo.txt b/wadsrc/static/zscript/strife/strifeammo.txt new file mode 100644 index 0000000000..dcc31b2c71 --- /dev/null +++ b/wadsrc/static/zscript/strife/strifeammo.txt @@ -0,0 +1,235 @@ +// HE-Grenade Rounds -------------------------------------------------------- + +class HEGrenadeRounds : Ammo +{ + Default + { + +FLOORCLIP + Inventory.Amount 6; + Inventory.MaxAmount 30; + Ammo.BackpackAmount 6; + Ammo.BackpackMaxAmount 60; + Inventory.Icon "I_GRN1"; + Tag "$TAG_HEGRENADES"; + Inventory.PickupMessage "$TXT_HEGRENADES"; + } + States + { + Spawn: + GRN1 A -1; + Stop; + } +} + +// Phosphorus-Grenade Rounds ------------------------------------------------ + +class PhosphorusGrenadeRounds : Ammo +{ + Default + { + +FLOORCLIP + Inventory.Amount 4; + Inventory.MaxAmount 16; + Ammo.BackpackAmount 4; + Ammo.BackpackMaxAmount 32; + Inventory.Icon "I_GRN2"; + Tag "$TAG_PHGRENADES"; + Inventory.PickupMessage "$TXT_PHGRENADES"; + } + States + { + Spawn: + GRN2 A -1; + Stop; + } +} + +// Clip of Bullets ---------------------------------------------------------- + +class ClipOfBullets : Ammo +{ + Default + { + +FLOORCLIP + Inventory.Amount 10; + Inventory.MaxAmount 250; + Ammo.BackpackAmount 10; + Ammo.BackpackMaxAmount 500; + Inventory.Icon "I_BLIT"; + Tag "$TAG_CLIPOFBULLETS"; + Inventory.PickupMessage "$TXT_CLIPOFBULLETS"; + } + States + { + Spawn: + BLIT A -1; + Stop; + } +} + +// Box of Bullets ----------------------------------------------------------- + +class BoxOfBullets : ClipOfBullets +{ + Default + { + Inventory.Amount 50; + Tag "$TAG_BOXOFBULLETS"; + Inventory.PickupMessage "$TXT_BOXOFBULLETS"; + } + States + { + Spawn: + BBOX A -1; + Stop; + } +} + +// Mini Missiles ------------------------------------------------------------ + +class MiniMissiles : Ammo +{ + Default + { + +FLOORCLIP + Inventory.Amount 4; + Inventory.MaxAmount 100; + Ammo.BackpackAmount 4; + Ammo.BackpackMaxAmount 200; + Inventory.Icon "I_ROKT"; + Tag "$TAG_MINIMISSILES"; + Inventory.PickupMessage "$TXT_MINIMISSILES"; + } + States + { + Spawn: + MSSL A -1; + Stop; + } +} + +// Crate of Missiles -------------------------------------------------------- + +class CrateOfMissiles : MiniMissiles +{ + Default + { + Inventory.Amount 20; + Tag "$TAG_CRATEOFMISSILES"; + Inventory.PickupMessage "$TXT_CRATEOFMISSILES"; + } + States + { + Spawn: + ROKT A -1; + Stop; + } +} + +// Energy Pod --------------------------------------------------------------- + +class EnergyPod : Ammo +{ + Default + { + +FLOORCLIP + Inventory.Amount 20; + Inventory.MaxAmount 400; + Ammo.BackpackAmount 20; + Ammo.BackpackMaxAmount 800; + Ammo.DropAmount 20; + Inventory.Icon "I_BRY1"; + Tag "$TAG_ENERGYPOD"; + Inventory.PickupMessage "$TXT_ENERGYPOD"; + } + States + { + Spawn: + BRY1 AB 6; + Loop; + } +} + +// Energy pack --------------------------------------------------------------- + +class EnergyPack : EnergyPod +{ + Default + { + Inventory.Amount 100; + Tag "$TAG_ENERGYPACK"; + Inventory.PickupMessage "$TXT_ENERGYPACK"; + } + States + { + Spawn: + CPAC AB 6; + Loop; + } +} + +// Poison Bolt Quiver ------------------------------------------------------- + +class PoisonBolts : Ammo +{ + Default + { + +FLOORCLIP + Inventory.Amount 10; + Inventory.MaxAmount 25; + Ammo.BackpackAmount 2; + Ammo.BackpackMaxAmount 50; + Inventory.Icon "I_PQRL"; + Tag "$TAG_POISONBOLTS"; + Inventory.PickupMessage "$TXT_POISONBOLTS"; + } + States + { + Spawn: + PQRL A -1; + Stop; + } +} + +// Electric Bolt Quiver ------------------------------------------------------- + +class ElectricBolts : Ammo +{ + Default + { + +FLOORCLIP + Inventory.Amount 20; + Inventory.MaxAmount 50; + Ammo.BackpackAmount 4; + Ammo.BackpackMaxAmount 100; + Inventory.Icon "I_XQRL"; + Tag "$TAG_ELECTRICBOLTS"; + Inventory.PickupMessage "$TXT_ELECTRICBOLTS"; + } + States + { + Spawn: + XQRL A -1; + Stop; + } +} + +// Ammo Satchel ------------------------------------------------------------- + +class AmmoSatchel : BackpackItem +{ + Default + { + +FLOORCLIP + Inventory.Icon "I_BKPK"; + Tag "$TAG_AMMOSATCHEL"; + Inventory.PickupMessage "$TXT_AMMOSATCHEL"; + } + States + { + Spawn: + BKPK A -1; + Stop; + } +} + diff --git a/wadsrc/static/zscript/strife/strifearmor.txt b/wadsrc/static/zscript/strife/strifearmor.txt new file mode 100644 index 0000000000..8d2c7fad52 --- /dev/null +++ b/wadsrc/static/zscript/strife/strifearmor.txt @@ -0,0 +1,49 @@ + +class MetalArmor : BasicArmorPickup +{ + Default + { + Radius 20; + Height 16; + +FLOORCLIP + +INVENTORY.AUTOACTIVATE + +INVENTORY.INVBAR + Inventory.MaxAmount 3; + Inventory.Icon "I_ARM1"; + Inventory.PickupMessage "$TXT_METALARMOR"; + Armor.SaveAmount 200; + Armor.SavePercent 50; + Tag "$TAG_METALARMOR"; + } + States + { + Spawn: + ARM3 A -1; + Stop; + } +} + +class LeatherArmor : BasicArmorPickup +{ + Default + { + Radius 20; + Height 16; + +FLOORCLIP + +INVENTORY.AUTOACTIVATE + +INVENTORY.INVBAR + Inventory.MaxAmount 5; + Inventory.Icon "I_ARM2"; + Inventory.PickupMessage "$TXT_LEATHERARMOR"; + Armor.SaveAmount 100; + Armor.SavePercent 33.335; + Tag "$TAG_LEATHER"; + } + States + { + Spawn: + ARM4 A -1; + Stop; + } +} + diff --git a/wadsrc/static/zscript/strife/strifebishop.txt b/wadsrc/static/zscript/strife/strifebishop.txt new file mode 100644 index 0000000000..b7de186a27 --- /dev/null +++ b/wadsrc/static/zscript/strife/strifebishop.txt @@ -0,0 +1,99 @@ + +// Bishop ------------------------------------------------------------------- + +class StrifeBishop : Actor +{ + Default + { + Health 500; + Painchance 128; + Speed 8; + Radius 40; + Height 56; + Mass 500; + Monster; + +NOBLOOD + +NOTDMATCH + +FLOORCLIP + +INCOMBAT + +NOICEDEATH + +NEVERRESPAWN + DamageFactor "Fire", 0.5; + MinMissileChance 150; + MaxDropoffHeight 32; + SeeSound "bishop/sight"; + PainSound "bishop/pain"; + DeathSound "bishop/death"; + ActiveSound "bishop/active"; + DropItem "CrateOfMissiles", 256, 20; + Obituary "$OB_STFBISHOP"; + } + States + { + Spawn: + MLDR A 10 A_Look; + Loop; + See: + MLDR AABBCCDD 3 A_Chase; + Loop; + Missile: + MLDR E 3 A_FaceTarget; + MLDR F 2 Bright A_CustomMissile("BishopMissile", 64, 0, 0, CMF_AIMOFFSET); + Goto See; + Pain: + MLDR D 1 A_Pain; + Goto See; + Death: + MLDR G 3 Bright; + MLDR H 5 Bright A_Scream; + MLDR I 4 Bright A_TossGib; + MLDR J 4 Bright A_Explode(64, 64, alert:true); + MLDR KL 3 Bright; + MLDR M 4 Bright A_NoBlocking; + MLDR N 4 Bright; + MLDR O 4 Bright A_TossGib; + MLDR P 4 Bright; + MLDR Q 4 Bright A_TossGib; + MLDR R 4 Bright; + MLDR S 4 Bright A_TossGib; + MLDR T 4 Bright; + MLDR U 4 Bright A_TossGib; + MLDR V 4 Bright A_SpawnItemEx("AlienSpectre2", 0, 0, 0, 0, 0, random[spectrespawn](0,255)*0.0078125, 0, SXF_NOCHECKPOSITION); + Stop; + } +} + + +// The Bishop's missile ----------------------------------------------------- + +class BishopMissile : Actor +{ + Default + { + Speed 20; + Radius 10; + Height 14; + Damage 10; + Projectile; + +SEEKERMISSILE + +STRIFEDAMAGE + MaxStepHeight 4; + SeeSound "bishop/misl"; + DeathSound "bishop/mislx"; + } + States + { + Spawn: + MISS A 4 Bright A_RocketInFlight; + MISS B 3 Bright A_Tracer2; + Loop; + Death: + SMIS A 0 Bright A_SetRenderStyle(1, STYLE_Normal); + SMIS A 5 Bright A_Explode(64, 64, alert:true); + SMIS B 5 Bright; + SMIS C 4 Bright; + SMIS DEFG 2 Bright; + Stop; + } +} + diff --git a/wadsrc/static/zscript/strife/strifefunctions.txt b/wadsrc/static/zscript/strife/strifefunctions.txt new file mode 100644 index 0000000000..7cfdf39746 --- /dev/null +++ b/wadsrc/static/zscript/strife/strifefunctions.txt @@ -0,0 +1,198 @@ +// common Strife action functions that are used by multiple different actors + +extend class Actor +{ + + //============================================================================ + + void A_FLoopActiveSound() + { + if (ActiveSound != 0 && !(level.time & 7)) + { + A_PlaySound (ActiveSound, CHAN_VOICE); + } + } + + void A_LoopActiveSound() + { + A_PlaySound(ActiveSound, CHAN_VOICE, 1, true); + } + + //============================================================================ + // + // + // + //============================================================================ + + void A_Countdown() + { + if (--reactiontime <= 0) + { + ExplodeMissile (); + bSkullFly = false; + } + } + + //============================================================================ + // + // A_ClearSoundTarget + // + //============================================================================ + + void A_ClearSoundTarget() + { + CurSector.SoundTarget = null; + for (Actor mo = CurSector.thinglist; mo != null; mo = mo.snext) + { + mo.LastHeard = null; + } + } + + //========================================================================== + // + // A_TossGib + // + //========================================================================== + + void A_TossGib() + { + class gibtype; + if (bNoBlood) gibtype = "Junk"; + else gibtype = "Meat"; + Actor gib = Spawn (gibtype, pos + (0,0,24), ALLOW_REPLACE); + + if (gib == null) + { + return; + } + + gib.Angle = random[GibTosser]() * (360 / 256.f); + gib.VelFromAngle(random[GibTosser]() & 15); + gib.Vel.Z = random[GibTosser]() & 15; + } + + //========================================================================== + // + // + // + //========================================================================== + + void A_ShootGun() + { + if (!target) return; + A_PlaySound ("monsters/rifle", CHAN_WEAPON); + A_FaceTarget (); + double pitch = AimLineAttack (angle, MISSILERANGE); + LineAttack (Angle + Random2[ShootGun]() * (11.25 / 256), MISSILERANGE, pitch, 3*(random[ShootGun]() % 5 + 1), 'Hitscan', "StrifePuff"); + } + + //========================================================================== + // + // + // + //========================================================================== + + void A_SetShadow() + { + bShadow = true; + A_SetRenderStyle(HR_SHADOW, STYLE_Translucent); + } + + void A_ClearShadow() + { + bShadow = false; + A_SetRenderStyle(1, STYLE_Normal); + } + + //========================================================================== + // + // + // + //========================================================================== + + void A_GetHurt() + { + bInCombat = true; + if ((random[HurtMe]() % 5) == 0) + { + A_PlaySound (PainSound, CHAN_VOICE); + health--; + } + if (health <= 0) + { + Die (target, target); + } + } + + //========================================================================== + // + // + // + //========================================================================== + + void A_DropFire() + { + Actor drop = Spawn("FireDroplet", pos + (0,0,24), ALLOW_REPLACE); + drop.Vel.Z = -1.; + A_Explode(64, 64, XF_NOSPLASH, damagetype: 'Fire'); + } + + //========================================================================== + // + // + // + //========================================================================== + + void A_RemoveForceField() + { + bSpecial = false; + CurSector.RemoveForceField(); + } + + //========================================================================== + // + // + // + //========================================================================== + + void A_AlertMonsters(double maxdist = 0, int flags = 0) + { + Actor target = null; + Actor emitter = self; + + if (player != null || (Flags & AMF_TARGETEMITTER)) + { + target = self; + } + else if (target != null && (self.target.player != null || (Flags & AMF_TARGETNONPLAYER))) + { + target = self.target; + } + + if (Flags & AMF_EMITFROMTARGET) emitter = target; + + if (target != null && emitter != null) + { + emitter.NoiseAlert(target, false, maxdist); + } + } + + //============================================================================ + // + // A_RocketInFlight + // + //============================================================================ + + void A_RocketInFlight() + { + A_PlaySound ("misc/missileinflight", CHAN_VOICE); + SpawnPuff ("MiniMissilePuff", Pos, Angle - 180, Angle - 180, 2, PF_HITTHING); + Actor trail = Spawn("RocketTrail", Vec3Offset(-Vel.X, -Vel.Y, 0.), ALLOW_REPLACE); + if (trail != null) + { + trail.Vel.Z = 1; + } + } + + +} diff --git a/wadsrc/static/zscript/strife/strifehumanoid.txt b/wadsrc/static/zscript/strife/strifehumanoid.txt new file mode 100644 index 0000000000..26709cd936 --- /dev/null +++ b/wadsrc/static/zscript/strife/strifehumanoid.txt @@ -0,0 +1,56 @@ + +// Humanoid Base Class ------------------------------------------------------ + + +class StrifeHumanoid : Actor +{ + Default + { + MaxStepHeight 16; + MaxDropoffHeight 32; + CrushPainSound "misc/pcrush"; + } + States + { + Burn: + BURN A 3 Bright A_PlaySound("human/imonfire", CHAN_VOICE); + BURN B 3 Bright A_DropFire; + BURN C 3 Bright A_Wander; + BURN D 3 Bright A_NoBlocking; + BURN E 5 Bright A_DropFire; + BURN FGH 5 Bright A_Wander; + BURN I 5 Bright A_DropFire; + BURN JKL 5 Bright A_Wander; + BURN M 5 Bright A_DropFire; + BURN N 5 Bright; + BURN OPQPQ 5 Bright; + BURN RSTU 7 Bright; + BURN V -1; + Stop; + Disintegrate: + DISR A 5 A_PlaySound("misc/disruptordeath", CHAN_VOICE); + DISR BC 5; + DISR D 5 A_NoBlocking; + DISR EF 5; + DISR GHIJ 4; + MEAT D 700; + Stop; + } +} + +// Fire Droplet ------------------------------------------------------------- + +class FireDroplet : Actor +{ + Default + { + +NOBLOCKMAP + +NOCLIP + } + States + { + Spawn: + FFOT ABCD 9 Bright; + Stop; + } +} diff --git a/wadsrc/static/zscript/strife/strifeitems.txt b/wadsrc/static/zscript/strife/strifeitems.txt new file mode 100644 index 0000000000..6d80377714 --- /dev/null +++ b/wadsrc/static/zscript/strife/strifeitems.txt @@ -0,0 +1,821 @@ +// Med patch ----------------------------------------------------------------- + +class MedPatch : HealthPickup +{ + Default + { + Health 10; + +FLOORCLIP + +INVENTORY.INVBAR + Inventory.MaxAmount 20; + Tag "$TAG_MEDPATCH"; + Inventory.Icon "I_STMP"; + Inventory.PickupMessage "$TXT_MEDPATCH"; + HealthPickup.Autouse 3; + } + States + { + Spawn: + STMP A -1; + Stop; + } +} + + +// Medical Kit --------------------------------------------------------------- + +class MedicalKit : HealthPickup +{ + Default + { + Health 25; + +FLOORCLIP + +INVENTORY.INVBAR + Inventory.MaxAmount 15; + Tag "$TAG_MEDICALKIT"; + Inventory.Icon "I_MDKT"; + Inventory.PickupMessage "$TXT_MEDICALKIT"; + HealthPickup.Autouse 3; + } + States + { + Spawn: + MDKT A -1; + Stop; + } +} + + +// Surgery Kit -------------------------------------------------------------- + +class SurgeryKit : HealthPickup +{ + Default + { + +FLOORCLIP + +INVENTORY.INVBAR + Health -100; + Inventory.MaxAmount 5; + Tag "$TAG_SURGERYKIT"; + Inventory.Icon "I_FULL"; + Inventory.PickupMessage "$TXT_SURGERYKIT"; + } + States + { + Spawn: + FULL AB 35; + Loop; + } +} + + +// StrifeMap ---------------------------------------------------------------- + +class StrifeMap : MapRevealer +{ + Default + { + +FLOORCLIP + Inventory.PickupSound "misc/p_pkup"; + Inventory.PickupMessage "$TXT_STRIFEMAP"; + } + States + { + Spawn: + SMAP AB 6 Bright; + Loop; + } +} + + +// Beldin's Ring ------------------------------------------------------------ + +class BeldinsRing : Inventory +{ + Default + { + +NOTDMATCH + +FLOORCLIP + +INVENTORY.INVBAR + Tag "$TAG_BELDINSRING"; + Inventory.Icon "I_RING"; + Inventory.GiveQuest 1; + Inventory.PickupMessage "$TXT_BELDINSRING"; + } + States + { + Spawn: + RING A -1; + Stop; + } +} + + +// Offering Chalice --------------------------------------------------------- + +class OfferingChalice : Inventory +{ + Default + { + +DROPPED + +FLOORCLIP + +INVENTORY.INVBAR + Radius 10; + Height 16; + Tag "$TAG_OFFERINGCHALICE"; + Inventory.Icon "I_RELC"; + Inventory.PickupMessage "$TXT_OFFERINGCHALICE"; + Inventory.GiveQuest 2; + } + States + { + Spawn: + RELC A -1; + Stop; + } +} + + +// Ear ---------------------------------------------------------------------- + +class Ear : Inventory +{ + Default + { + +FLOORCLIP + +INVENTORY.INVBAR + Tag "$TAG_EAR"; + Inventory.Icon "I_EARS"; + Inventory.PickupMessage "$TXT_EAR"; + Inventory.GiveQuest 9; + } + States + { + Spawn: + EARS A -1; + Stop; + } +} + + +// Broken Power Coupling ---------------------------------------------------- + +class BrokenPowerCoupling : Inventory +{ + Default + { + Health 40; + +DROPPED + +FLOORCLIP + +INVENTORY.INVBAR + Radius 16; + Height 16; + Tag "$TAG_BROKENCOUPLING"; + Inventory.MaxAmount 1; + Inventory.Icon "I_COUP"; + Inventory.PickupMessage "$TXT_BROKENCOUPLING"; + Inventory.GiveQuest 8; + } + States + { + Spawn: + COUP C -1; + Stop; + } +} + + +// Shadow Armor ------------------------------------------------------------- + +class ShadowArmor : PowerupGiver +{ + Default + { + +FLOORCLIP + +VISIBILITYPULSE + +INVENTORY.INVBAR + -INVENTORY.FANCYPICKUPSOUND + RenderStyle "Translucent"; + Tag "$TAG_SHADOWARMOR"; + Inventory.MaxAmount 2; + Powerup.Type "PowerShadow"; + Inventory.Icon "I_SHD1"; + Inventory.PickupSound "misc/i_pkup"; + Inventory.PickupMessage "$TXT_SHADOWARMOR"; + } + States + { + Spawn: + SHD1 A -1 Bright; + Stop; + } +} + + +// Environmental suit ------------------------------------------------------- + +class EnvironmentalSuit : PowerupGiver +{ + Default + { + +FLOORCLIP + +INVENTORY.INVBAR + -INVENTORY.FANCYPICKUPSOUND + Inventory.MaxAmount 5; + Powerup.Type "PowerMask"; + Tag "$TAG_ENVSUIT"; + Inventory.Icon "I_MASK"; + Inventory.PickupSound "misc/i_pkup"; + Inventory.PickupMessage "$TXT_ENVSUIT"; + } + States + { + Spawn: + MASK A -1; + Stop; + } +} + + +// Guard Uniform ------------------------------------------------------------ + +class GuardUniform : Inventory +{ + Default + { + +FLOORCLIP + +INVENTORY.INVBAR + Tag "$TAG_GUARDUNIFORM"; + Inventory.Icon "I_UNIF"; + Inventory.PickupMessage "$TXT_GUARDUNIFORM"; + Inventory.GiveQuest 15; + } + States + { + Spawn: + UNIF A -1; + Stop; + } +} + + +// Officer's Uniform -------------------------------------------------------- + +class OfficersUniform : Inventory +{ + Default + { + +FLOORCLIP + +INVENTORY.INVBAR + Tag "$TAG_OFFICERSUNIFORM"; + Inventory.Icon "I_OFIC"; + Inventory.PickupMessage "$TXT_OFFICERSUNIFORM"; + } + States + { + Spawn: + OFIC A -1; + Stop; + } +} + + +// Flame Thrower Parts ------------------------------------------------------ + +class FlameThrowerParts : Inventory +{ + Default + { + +FLOORCLIP + +INVENTORY.INVBAR + Inventory.Icon "I_BFLM"; + Tag "$TAG_FTHROWERPARTS"; + Inventory.PickupMessage "$TXT_FTHROWERPARTS"; + } + States + { + Spawn: + BFLM A -1; + Stop; + } +} + +// InterrogatorReport ------------------------------------------------------- +// SCRIPT32 in strife0.wad has an Acolyte that drops this, but I couldn't +// find that Acolyte in the map. It seems to be totally unused in the +// final game. + +class InterrogatorReport : Inventory +{ + Default + { + +FLOORCLIP + Tag "$TAG_REPORT"; + Inventory.PickupMessage "$TXT_REPORT"; + } + States + { + Spawn: + TOKN A -1; + Stop; + } +} + + +// Info --------------------------------------------------------------------- + +class Info : Inventory +{ + Default + { + +FLOORCLIP + +INVENTORY.INVBAR + Tag "$TAG_INFO"; + Inventory.Icon "I_TOKN"; + Inventory.PickupMessage "$TXT_INFO"; + } + States + { + Spawn: + TOKN A -1; + Stop; + } +} + + +// Targeter ----------------------------------------------------------------- + +class Targeter : PowerupGiver +{ + Default + { + +FLOORCLIP + +INVENTORY.INVBAR + -INVENTORY.FANCYPICKUPSOUND + Tag "$TAG_TARGETER"; + Powerup.Type "PowerTargeter"; + Inventory.MaxAmount 5; + Inventory.Icon "I_TARG"; + Inventory.PickupSound "misc/i_pkup"; + Inventory.PickupMessage "$TXT_TARGETER"; + } + States + { + Spawn: + TARG A -1; + Stop; + } +} + +// Communicator ----------------------------------------------------------------- + +class Communicator : Inventory +{ + Default + { + +NOTDMATCH + Tag "$TAG_COMMUNICATOR"; + Inventory.Icon "I_COMM"; + Inventory.PickupSound "misc/p_pkup"; + Inventory.PickupMessage "$TXT_COMMUNICATOR"; + } + States + { + Spawn: + COMM A -1; + Stop; + } +} + +// Degnin Ore --------------------------------------------------------------- + +class DegninOre : Inventory +{ + Default + { + Health 10; + Radius 16; + Height 16; + Inventory.MaxAmount 10; + +SOLID + +SHOOTABLE + +NOBLOOD + +FLOORCLIP + +INCOMBAT + +INVENTORY.INVBAR + Tag "$TAG_DEGNINORE"; + DeathSound "ore/explode"; + Inventory.Icon "I_XPRK"; + Inventory.PickupMessage "$TXT_DEGNINORE"; + } + States + { + Spawn: + XPRK A -1; + Stop; + Death: + XPRK A 1 A_RemoveForceField; + BNG3 A 0 A_SetRenderStyle(1, STYLE_Normal); + BNG3 A 0 A_Scream; + BNG3 A 3 Bright A_Explode(192, 192, alert:true); + BNG3 BCDEFGH 3 Bright; + Stop; + } + + override bool Use (bool pickup) + { + if (pickup) + { + return false; + } + else + { + Inventory drop; + + // Increase the amount by one so that when DropInventory decrements it, + // the actor will have the same number of beacons that he started with. + // When we return to UseInventory, it will take care of decrementing + // Amount again and disposing of this item if there are no more. + Amount++; + drop = Owner.DropInventory (self); + if (drop == NULL) + { + Amount--; + return false; + } + return true; + } + } + +} + +// Gun Training ------------------------------------------------------------- + +class GunTraining : Inventory +{ + Default + { + +FLOORCLIP + +INVENTORY.INVBAR + +INVENTORY.UNDROPPABLE + Inventory.MaxAmount 100; + Tag "$TAG_GUNTRAINING"; + Inventory.Icon "I_GUNT"; + } + States + { + Spawn: + GUNT A -1; + Stop; + } +} + +// Health Training ---------------------------------------------------------- + +class HealthTraining : Inventory +{ + Default + { + +FLOORCLIP + +INVENTORY.INVBAR + +INVENTORY.UNDROPPABLE + Inventory.MaxAmount 100; + Tag "$TAG_HEALTHTRAINING"; + Inventory.Icon "I_HELT"; + } + States + { + Spawn: + HELT A -1; + Stop; + } + + override bool TryPickup (in out Actor toucher) + { + if (Super.TryPickup(toucher)) + { + toucher.GiveInventoryType ("GunTraining"); + toucher.A_GiveInventory("Coin", toucher.player.mo.accuracy*5 + 300); + return true; + } + return false; + } + +} + +// Scanner ------------------------------------------------------------------ + +class Scanner : PowerupGiver +{ + Default + { + +FLOORCLIP + +INVENTORY.FANCYPICKUPSOUND + Inventory.MaxAmount 1; + Tag "$TAG_SCANNER"; + Inventory.Icon "I_PMUP"; + Powerup.Type "PowerScanner"; + Inventory.PickupSound "misc/i_pkup"; + Inventory.PickupMessage "$TXT_SCANNER"; + } + States + { + Spawn: + PMUP AB 6; + Loop; + } + + override bool Use (bool pickup) + { + if (!level.AllMap) + { + if (Owner.CheckLocalView (consoleplayer)) + { + C_MidPrint("SmallFont", "$TXT_NEEDMAP"); + } + return false; + } + return Super.Use (pickup); + } + +} + +// Prison Pass -------------------------------------------------------------- + +class PrisonPass : Key +{ + Default + { + Inventory.Icon "I_TOKN"; + Tag "$TAG_PRISONPASS"; + Inventory.PickupMessage "$TXT_PRISONPASS"; + } + States + { + Spawn: + TOKN A -1; + Stop; + } + + override bool TryPickup (in out Actor toucher) + { + Super.TryPickup (toucher); + Door_Open(223, 16); + toucher.GiveInventoryType ("QuestItem10"); + return true; + } + + //============================================================================ + // + // APrisonPass :: SpecialDropAction + // + // Trying to make a monster that drops a prison pass turns it into an + // OpenDoor223 item instead. That means the only way to get it in Strife + // is through dialog, which is why it doesn't have its own sprite. + // + //============================================================================ + + override bool SpecialDropAction (Actor dropper) + { + Door_Open(223, 16); + Destroy (); + return true; + } + +} + +//--------------------------------------------------------------------------- +// Dummy items. They are just used by Strife to perform --------------------- +// actions and cannot be held. ---------------------------------------------- +//--------------------------------------------------------------------------- + +class DummyStrifeItem : Inventory +{ + States + { + Spawn: + TOKN A -1; + Stop; + } +} + +// Sound the alarm! --------------------------------------------------------- + +class RaiseAlarm : DummyStrifeItem +{ + Default + { + Tag "$TAG_ALARM"; + } + + override bool TryPickup (in out Actor toucher) + { + toucher.NoiseAlert (toucher); + + ThinkerIterator it = ThinkerIterator.Create("AlienSpectre3"); + Actor spectre = Actor(it.Next()); + + if (spectre != NULL && spectre.health > 0 && toucher != spectre) + { + spectre.CurSector.SoundTarget = spectre.LastHeard = toucher; + spectre.target = toucher; + spectre.SetState (spectre.SeeState); + } + GoAwayAndDie (); + return true; + } + + override bool SpecialDropAction (Actor dropper) + { + if (dropper.target != null) + { + dropper.target.NoiseAlert(dropper.target); + if (dropper.target.CheckLocalView(consoleplayer)) + { + A_Log("You Fool! You've set off the alarm."); + } + } + Destroy (); + return true; + } + +} + +// Open door tag 222 -------------------------------------------------------- + +class OpenDoor222 : DummyStrifeItem +{ + override bool TryPickup (in out Actor toucher) + { + Door_Open(222, 16); + GoAwayAndDie (); + return true; + } + +} + +// Close door tag 222 ------------------------------------------------------- + +class CloseDoor222 : DummyStrifeItem +{ + override bool TryPickup (in out Actor toucher) + { + Door_Close(222, 16); + GoAwayAndDie (); + return true; + } + + override bool SpecialDropAction (Actor dropper) + { + Door_Close(222, 16); + if (dropper.target != null) + { + if (dropper.target.CheckLocalView(consoleplayer)) + { + A_Log("You're dead! You set off the alarm."); + } + dropper.target.NoiseAlert(dropper.target); + } + Destroy (); + return true; + } + +} + +// Open door tag 224 -------------------------------------------------------- + +class OpenDoor224 : DummyStrifeItem +{ + override bool TryPickup (in out Actor toucher) + { + Door_Open(224, 16); + GoAwayAndDie (); + return true; + } + + override bool SpecialDropAction (Actor dropper) + { + Door_Open(224, 16); + Destroy (); + return true; + } + +} + +// Ammo --------------------------------------------------------------------- + +class AmmoFillup : DummyStrifeItem +{ + Default + { + Tag "$TAG_AMMOFILLUP"; + } + + override bool TryPickup (in out Actor toucher) + { + Inventory item = toucher.FindInventory("ClipOfBullets"); + if (item == NULL) + { + item = toucher.GiveInventoryType ("ClipOfBullets"); + if (item != NULL) + { + item.Amount = 50; + } + } + else if (item.Amount < 50) + { + item.Amount = 50; + } + else + { + return false; + } + GoAwayAndDie (); + return true; + } + +} + +// Health ------------------------------------------------------------------- + +class HealthFillup : DummyStrifeItem +{ + Default + { + Tag "$TAG_HEALTHFILLUP"; + } + + override bool TryPickup (in out Actor toucher) + { + static const int skillhealths[] = { -100, -75, -50, -50, -100 }; + + int index = clamp(skill, 0,4); + if (!toucher.GiveBody (skillhealths[index])) + { + return false; + } + GoAwayAndDie (); + return true; + } + +} + +// Upgrade Stamina ---------------------------------------------------------- + +class UpgradeStamina : DummyStrifeItem +{ + Default + { + Inventory.Amount 10; + Inventory.MaxAmount 100; + } + + override bool TryPickup (in out Actor toucher) + { + if (toucher.player == NULL) + return false; + + toucher.player.mo.stamina += Amount; + if (toucher.player.mo.stamina >= MaxAmount) + toucher.player.mo.stamina = MaxAmount; + + toucher.GiveBody (-100); + GoAwayAndDie (); + return true; + } + +} + +// Upgrade Accuracy --------------------------------------------------------- + +class UpgradeAccuracy : DummyStrifeItem +{ + override bool TryPickup (in out Actor toucher) + { + if (toucher.player == NULL || toucher.player.mo.accuracy >= 100) + return false; + toucher.player.mo.accuracy += 10; + GoAwayAndDie (); + return true; + } + +} + +// Start a slideshow -------------------------------------------------------- + +class SlideshowStarter : DummyStrifeItem +{ + override bool TryPickup (in out Actor toucher) + { + gameaction = ga_slideshow; + if (level.levelnum == 10) + { + toucher.GiveInventoryType ("QuestItem17"); + } + GoAwayAndDie (); + return true; + } + +} + + diff --git a/wadsrc/static/zscript/strife/strifekeys.txt b/wadsrc/static/zscript/strife/strifekeys.txt new file mode 100644 index 0000000000..0241443847 --- /dev/null +++ b/wadsrc/static/zscript/strife/strifekeys.txt @@ -0,0 +1,547 @@ +class StrifeKey : Key +{ + Default + { + Radius 20; + Height 16; + +NOTDMATCH + +FLOORCLIP + } +} + +// Base Key ----------------------------------------------------------------- + +class BaseKey : StrifeKey +{ + Default + { + Inventory.Icon "I_FUSL"; + Tag "$TAG_BASEKEY"; + Inventory.PickupMessage "$TXT_BASEKEY"; + } + States + { + Spawn: + FUSL A -1; + Stop; + } +} + + +// Govs Key ----------------------------------------------------------------- + +class GovsKey : StrifeKey +{ + Default + { + Inventory.Icon "I_REBL"; + Tag "$TAG_GOVSKEY"; + Inventory.PickupMessage "$TXT_GOVSKEY"; + } + States + { + Spawn: + REBL A -1; + Stop; + } +} + + +// Passcard ----------------------------------------------------------------- + +class Passcard : StrifeKey +{ + Default + { + Inventory.Icon "I_TPAS"; + Tag "$TAG_PASSCARD"; + Inventory.PickupMessage "$TXT_PASSCARD"; + } + States + { + Spawn: + TPAS A -1; + Stop; + } +} + + +// ID Badge ----------------------------------------------------------------- + +class IDBadge : StrifeKey +{ + Default + { + Inventory.Icon "I_CRD1"; + Tag "$TAG_IDBADGE"; + Inventory.PickupMessage "$TXT_IDBADGE"; + } + States + { + Spawn: + CRD1 A -1; + Stop; + } +} + + +// Prison Key --------------------------------------------------------------- + +class PrisonKey : StrifeKey +{ + Default + { + Inventory.Icon "I_PRIS"; + Tag "$TAG_PRISONKEY"; + Inventory.GiveQuest 11; + Inventory.PickupMessage "$TXT_PRISONKEY"; + } + States + { + Spawn: + PRIS A -1; + Stop; + } +} + + +// Severed Hand ------------------------------------------------------------- + +class SeveredHand : StrifeKey +{ + Default + { + Inventory.Icon "I_HAND"; + Tag "$TAG_SEVEREDHAND"; + Inventory.GiveQuest 12; + Inventory.PickupMessage "$TXT_SEVEREDHAND"; + } + States + { + Spawn: + HAND A -1; + Stop; + } +} + + +// Power1 Key --------------------------------------------------------------- + +class Power1Key : StrifeKey +{ + Default + { + Inventory.Icon "I_PWR1"; + Tag "$TAG_POWER1KEY"; + Inventory.PickupMessage "$TXT_POWER1KEY"; + } + States + { + Spawn: + PWR1 A -1; + Stop; + } +} + + +// Power2 Key --------------------------------------------------------------- + +class Power2Key : StrifeKey +{ + Default + { + Inventory.Icon "I_PWR2"; + Tag "$TAG_POWER2KEY"; + Inventory.PickupMessage "$TXT_POWER2KEY"; + } + States + { + Spawn: + PWR2 A -1; + Stop; + } +} + + +// Power3 Key --------------------------------------------------------------- + +class Power3Key : StrifeKey +{ + Default + { + Inventory.Icon "I_PWR3"; + Tag "$TAG_POWER3KEY"; + Inventory.PickupMessage "$TXT_POWER3KEY"; + } + States + { + Spawn: + PWR3 A -1; + Stop; + } +} + + +// Gold Key ----------------------------------------------------------------- + +class GoldKey : StrifeKey +{ + Default + { + Inventory.Icon "I_KY1G"; + Tag "$TAG_GOLDKEY"; + Inventory.PickupMessage "$TXT_GOLDKEY"; + } + States + { + Spawn: + KY1G A -1; + Stop; + } +} + + +// ID Card ------------------------------------------------------------------ + +class IDCard : StrifeKey +{ + Default + { + Inventory.Icon "I_CRD2"; + Tag "$TAG_IDCARD"; + Inventory.PickupMessage "$TXT_IDCARD"; + } + States + { + Spawn: + CRD2 A -1; + Stop; + } +} + + +// Silver Key --------------------------------------------------------------- + +class SilverKey : StrifeKey +{ + Default + { + Inventory.Icon "I_KY2S"; + Tag "$TAG_SILVERKEY"; + Inventory.PickupMessage "$TXT_SILVERKEY"; + } + States + { + Spawn: + KY2S A -1; + Stop; + } +} + + +// Oracle Key --------------------------------------------------------------- + +class OracleKey : StrifeKey +{ + Default + { + Inventory.Icon "I_ORAC"; + Tag "$TAG_ORACLEKEY"; + Inventory.PickupMessage "$TXT_ORACLEKEY"; + } + States + { + Spawn: + ORAC A -1; + Stop; + } +} + + +// Military ID -------------------------------------------------------------- + +class MilitaryID : StrifeKey +{ + Default + { + Inventory.Icon "I_GYID"; + Tag "$TAG_MILITARYID"; + Inventory.PickupMessage "$TXT_MILITARYID"; + } + States + { + Spawn: + GYID A -1; + Stop; + } +} + + +// Order Key ---------------------------------------------------------------- + +class OrderKey : StrifeKey +{ + Default + { + Inventory.Icon "I_FUBR"; + Tag "$TAG_ORDERKEY"; + Inventory.PickupMessage "$TXT_ORDERKEY"; + } + States + { + Spawn: + FUBR A -1; + Stop; + } +} + + +// Warehouse Key ------------------------------------------------------------ + +class WarehouseKey : StrifeKey +{ + Default + { + Inventory.Icon "I_WARE"; + Tag "$TAG_WAREHOUSEKEY"; + Inventory.PickupMessage "$TXT_WAREHOUSEKEY"; + } + States + { + Spawn: + WARE A -1; + Stop; + } +} + + +// Brass Key ---------------------------------------------------------------- + +class BrassKey : StrifeKey +{ + Default + { + Inventory.Icon "I_KY3B"; + Tag "$TAG_BRASSKEY"; + Inventory.PickupMessage "$TXT_BRASSKEY"; + } + States + { + Spawn: + KY3B A -1; + Stop; + } +} + + +// Red Crystal Key ---------------------------------------------------------- + +class RedCrystalKey : StrifeKey +{ + Default + { + Inventory.Icon "I_RCRY"; + Tag "$TAG_REDCRYSTALKEY"; + Inventory.PickupMessage "$TXT_REDCRYSTAL"; + } + States + { + Spawn: + RCRY A -1 Bright; + Stop; + } +} + + +// Blue Crystal Key --------------------------------------------------------- + +class BlueCrystalKey : StrifeKey +{ + Default + { + Inventory.Icon "I_BCRY"; + Tag "$TAG_BLUECRYSTALKEY"; + Inventory.PickupMessage "$TXT_BLUECRYSTAL"; + } + States + { + Spawn: + BCRY A -1 Bright; + Stop; + } +} + + +// Chapel Key --------------------------------------------------------------- + +class ChapelKey : StrifeKey +{ + Default + { + Inventory.Icon "I_CHAP"; + Tag "$TAG_CHAPELKEY"; + Inventory.PickupMessage "$TXT_CHAPELKEY"; + } + States + { + Spawn: + CHAP A -1; + Stop; + } +} + + +// Catacomb Key ------------------------------------------------------------- + +class CatacombKey : StrifeKey +{ + Default + { + Inventory.Icon "I_TUNL"; + Tag "$TAG_CATACOMBKEY"; + Inventory.GiveQuest 28; + Inventory.PickupMessage "$TXT_CATACOMBKEY"; + } + States + { + Spawn: + TUNL A -1; + Stop; + } +} + + +// Security Key ------------------------------------------------------------- + +class SecurityKey : StrifeKey +{ + Default + { + Inventory.Icon "I_SECK"; + Tag "$TAG_SECURITYKEY"; + Inventory.PickupMessage "$TXT_SECURITYKEY"; + } + States + { + Spawn: + SECK A -1; + Stop; + } +} + + +// Core Key ----------------------------------------------------------------- + +class CoreKey : StrifeKey +{ + Default + { + Inventory.Icon "I_GOID"; + Tag "$TAG_COREKEY"; + Inventory.PickupMessage "$TXT_COREKEY"; + } + States + { + Spawn: + GOID A -1; + Stop; + } +} + + +// Mauler Key --------------------------------------------------------------- + +class MaulerKey : StrifeKey +{ + Default + { + Inventory.Icon "I_BLTK"; + Tag "$TAG_MAULERKEY"; + Inventory.PickupMessage "$TXT_MAULERKEY"; + } + States + { + Spawn: + BLTK A -1; + Stop; + } +} + + +// Factory Key -------------------------------------------------------------- + +class FactoryKey : StrifeKey +{ + Default + { + Inventory.Icon "I_PROC"; + Tag "$TAG_FACTORYKEY"; + Inventory.PickupMessage "$TXT_FACTORYKEY"; + } + States + { + Spawn: + PROC A -1; + Stop; + } +} + + +// Mine Key ----------------------------------------------------------------- + +class MineKey : StrifeKey +{ + Default + { + Inventory.Icon "I_MINE"; + Tag "$TAG_MINEKEY"; + Inventory.PickupMessage "$TXT_MINEKEY"; + } + States + { + Spawn: + MINE A -1; + Stop; + } +} + + +// New Key5 ----------------------------------------------------------------- + +class NewKey5 : StrifeKey +{ + Default + { + Inventory.Icon "I_BLTK"; + Tag "$TAG_NEWKEY5"; + Inventory.PickupMessage "$TXT_NEWKEY5"; + } + States + { + Spawn: + BLTK A -1; + Stop; + } +} + + +// Oracle Pass -------------------------------------------------------------- + +class OraclePass : Inventory +{ + Default + { + +INVENTORY.INVBAR + Inventory.Icon "I_OTOK"; + Inventory.GiveQuest 18; + Inventory.PickupMessage "$TXT_ORACLEPASS"; + Tag "$TAG_ORACLEPASS"; + } + States + { + Spawn: + OTOK A -1; + Stop; + } +} + diff --git a/wadsrc/static/zscript/strife/strifeplayer.txt b/wadsrc/static/zscript/strife/strifeplayer.txt new file mode 100644 index 0000000000..2033fdb5e9 --- /dev/null +++ b/wadsrc/static/zscript/strife/strifeplayer.txt @@ -0,0 +1,165 @@ +// The player --------------------------------------------------------------- + +class StrifePlayer : PlayerPawn +{ + Default + { + Health 100; + Radius 18; + Height 56; + Mass 100; + PainChance 255; + Speed 1; + MaxStepHeight 16; + CrushPainSound "misc/pcrush"; + Player.DisplayName "Rebel"; + Player.StartItem "PunchDagger"; + Player.RunHealth 15; + Player.WeaponSlot 1, "PunchDagger"; + Player.WeaponSlot 2, "StrifeCrossbow2", "StrifeCrossbow"; + Player.WeaponSlot 3, "AssaultGun"; + Player.WeaponSlot 4, "MiniMissileLauncher"; + Player.WeaponSlot 5, "StrifeGrenadeLauncher2", "StrifeGrenadeLauncher"; + Player.WeaponSlot 6, "FlameThrower"; + Player.WeaponSlot 7, "Mauler2", "Mauler"; + Player.WeaponSlot 8, "Sigil"; + + Player.ColorRange 128, 143; + Player.Colorset 0, "Brown", 0x80, 0x8F, 0x82; + Player.Colorset 1, "Red", 0x40, 0x4F, 0x42, 0x20, 0x3F, 0x00, 0x1F, 0xF1, 0xF6, 0xE0, 0xE5, 0xF7, 0xFB, 0xF1, 0xF5; + Player.Colorset 2, "Rust", 0xB0, 0xBF, 0xB2, 0x20, 0x3F, 0x00, 0x1F; + Player.Colorset 3, "Gray", 0x10, 0x1F, 0x12, 0x20, 0x2F, 0xD0, 0xDF, 0x30, 0x3F, 0xD0, 0xDF; + Player.Colorset 4, "Dark Green", 0x30, 0x3F, 0x32, 0x20, 0x2F, 0xD0, 0xDF, 0x30, 0x3F, 0xD0, 0xDF; + + Player.Colorset 5, "Gold", 0x50, 0x5F, 0x52, 0x20, 0x3F, 0x00, 0x1F, 0x50, 0x5F, 0x80, 0x8F, 0xC0, 0xCF, 0xA0, 0xAF, 0xD0, 0xDF, 0xB0, 0xBF; + Player.Colorset 6, "Bright Green", 0x60, 0x6F, 0x62, 0x20, 0x3F, 0x00, 0x1F, 0x50, 0x5F, 0x10, 0x1F, 0xC0, 0xCF, 0x20, 0x2F, 0xD0, 0xDF, 0x30, 0x3F; + Player.Colorset 7, "Blue", 0x90, 0x9F, 0x92, 0x20, 0x3F, 0x00, 0x1F, 0x50, 0x5F, 0x40, 0x4F, 0xC1, 0xCF, 0x01, 0x0F, 0xC0,0xC0,1,1, 0xD0, 0xDF, 0x10, 0x1F; + } + + States + { + Spawn: + PLAY A -1; + stop; + See: + PLAY ABCD 4; + loop; + Missile: + PLAY E 12; + goto Spawn; + Melee: + PLAY F 6; + goto Missile; + Pain: + PLAY Q 4; + PLAY Q 4 A_Pain; + Goto Spawn; + Death: + PLAY H 3; + PLAY I 3 A_PlayerScream; + PLAY J 3 A_NoBlocking; + PLAY KLMNO 4; + PLAY P -1; + Stop; + XDeath: + RGIB A 5 A_TossGib; + RGIB B 5 A_XScream; + RGIB C 5 A_NoBlocking; + RGIB DEFG 5 A_TossGib; + RGIB H -1 A_TossGib; + Burn: + BURN A 3 Bright A_ItBurnsItBurns; + BURN B 3 Bright A_DropFire; + BURN C 3 Bright A_Wander; + BURN D 3 Bright A_NoBlocking; + BURN E 5 Bright A_DropFire; + BURN FGH 5 Bright A_Wander; + BURN I 5 Bright A_DropFire; + BURN JKL 5 Bright A_Wander; + BURN M 5 Bright A_DropFire; + BURN N 5 Bright A_CrispyPlayer; + BURN OPQPQ 5 Bright; + BURN RSTU 7 Bright; + BURN V -1; + Stop; + Disintegrate: + DISR A 5 A_PlaySound("misc/disruptordeath", CHAN_VOICE); + DISR BC 5; + DISR D 5 A_NoBlocking; + DISR EF 5; + DISR GHIJ 4; + MEAT D -1; + Stop; + Firehands: + WAVE ABCD 3; + Loop; + Firehandslower: + WAVE ABCD 3 A_HandLower; + Loop; + } + + void A_ItBurnsItBurns() + { + A_PlaySound ("human/imonfire", CHAN_VOICE); + + if (player != null && player.mo == self) + { + player.SetPsprite(PSP_STRIFEHANDS, FindState("FireHands")); + + player.ReadyWeapon = null; + player.PendingWeapon = WP_NOCHANGE; + player.playerstate = PST_LIVE; + player.extralight = 3; + } + } + + void A_CrispyPlayer() + { + if (player != null && player.mo == self) + { + PSprite psp = player.GetPSprite(PSP_STRIFEHANDS); + + State firehandslower = FindState("FireHandsLower"); + State firehands = FindState("FireHands"); + + if (psp.CurState != null && firehandslower != null && firehands != null) + { + // Calculate state to go to. + int dist = firehands.DistanceTo(psp.curState); + if (dist > 0) + { + player.playerstate = PST_DEAD; + psp.SetState(firehandslower + dist); + return; + } + } + player.playerstate = PST_DEAD; + psp.SetState(null); + } + } + + void A_HandLower() + { + if (player != null) + { + PSprite psp = player.GetPSprite(PSP_STRIFEHANDS); + + if (psp.CurState == null) + { + psp.SetState(null); + return; + } + + psp.y += 9; + if (psp.y > WEAPONBOTTOM*2) + { + psp.SetState(null); + } + + if (player.extralight > 0) player.extralight--; + } + return; + } + +} + diff --git a/wadsrc/static/zscript/strife/strifestuff.txt b/wadsrc/static/zscript/strife/strifestuff.txt new file mode 100644 index 0000000000..37918aa964 --- /dev/null +++ b/wadsrc/static/zscript/strife/strifestuff.txt @@ -0,0 +1,1983 @@ +// Notes so I don't forget them: +// +// When shooting missiles at something, if MF_SHADOW is set, the angle is adjusted with the formula: +// angle += pr_spawnmissile.Random2() << 21 +// When MF_STRIFEx4000000 is set, the angle is adjusted similarly: +// angle += pr_spawnmissile.Random2() << 22 +// Note that these numbers are different from those used by all the other Doom engine games. + + +// Tank 1 Huge ------------------------------------------------------------ + +class Tank1 : Actor +{ + Default + { + Radius 16; + Height 192; + +SOLID + } + States + { + Spawn: + TNK1 A 15; + TNK1 B 11; + TNK1 C 40; + Loop; + } +} + +// Tank 2 Huge ------------------------------------------------------------ + +class Tank2 : Actor +{ + Default + { + Radius 16; + Height 192; + +SOLID + } + States + { + Spawn: + TNK2 A 15; + TNK2 B 11; + TNK2 C 40; + Loop; + } +} + +// Tank 3 Huge ------------------------------------------------------------ + +class Tank3 : Actor +{ + Default + { + Radius 16; + Height 192; + +SOLID + } + States + { + Spawn: + TNK3 A 15; + TNK3 B 11; + TNK3 C 40; + Loop; + } +} + +// Tank 4 ------------------------------------------------------------------- + +class Tank4 : Actor +{ + Default + { + Radius 16; + Height 56; + +SOLID + } + States + { + Spawn: + TNK4 A 15; + TNK4 B 11; + TNK4 C 40; + Loop; + } +} + +// Tank 5 ------------------------------------------------------------------- + +class Tank5 : Actor +{ + Default + { + Radius 16; + Height 56; + +SOLID + } + States + { + Spawn: + TNK5 A 15; + TNK5 B 11; + TNK5 C 40; + Loop; + } +} + +// Tank 6 ------------------------------------------------------------------- + +class Tank6 : Actor +{ + Default + { + Radius 16; + Height 56; + +SOLID + } + States + { + Spawn: + TNK6 A 15; + TNK6 B 11; + TNK6 C 40; + Loop; + } +} + +// Water Bottle ------------------------------------------------------------- + +class WaterBottle : Actor +{ + States + { + Spawn: + WATR A -1; + Stop; + } +} + +// Mug ---------------------------------------------------------------------- + +class Mug : Actor +{ + States + { + Spawn: + MUGG A -1; + Stop; + } +} + +// Wooden Barrel ------------------------------------------------------------ + +class WoodenBarrel : Actor +{ + Default + { + Health 10; + Radius 10; + Height 32; + +SOLID +SHOOTABLE +NOBLOOD + +INCOMBAT + DeathSound "woodenbarrel/death"; + } + States + { + Spawn: + BARW A -1; + Stop; + Death: + BARW B 2 A_Scream; + BARW C 2; + BARW D 2 A_NoBlocking; + BARW EFG 2; + BARW H -1; + Stop; + } +} + +// Strife's explosive barrel ------------------------------------------------ + +class ExplosiveBarrel2 : Actor +{ + Default + { + Health 30; + Radius 10; + Height 32; + +SOLID +SHOOTABLE +NOBLOOD +OLDRADIUSDMG + DeathSound "world/barrelx"; + +INCOMBAT + } + States + { + Spawn: + BART A -1; + Stop; + Death: + BART B 2 Bright A_Scream; + BART CD 2 Bright; + BART E 2 Bright A_NoBlocking; + BART F 2 Bright A_Explode(64, 64, alert:true); + BART GHIJ 2 Bright; + BART K 3 Bright; + BART L -1; + Stop; + } +} + +// Light Silver, Fluorescent ---------------------------------------------- + +class LightSilverFluorescent : Actor +{ + Default + { + Radius 2.5; + Height 16; + +NOBLOCKMAP + +FIXMAPTHINGPOS + } + States + { + Spawn: + LITS A -1 Bright; + Stop; + } +} + +// Light Brown, Fluorescent ----------------------------------------------- + +class LightBrownFluorescent : Actor +{ + Default + { + Radius 2.5; + Height 16; + +NOBLOCKMAP + +FIXMAPTHINGPOS + } + States + { + Spawn: + LITB A -1 Bright; + Stop; + } +} + +// Light Gold, Fluorescent ------------------------------------------------ + +class LightGoldFluorescent : Actor +{ + Default + { + Radius 2.5; + Height 16; + +NOBLOCKMAP + +FIXMAPTHINGPOS + } + States + { + Spawn: + LITG A -1 Bright; + Stop; + } +} + +// Light Globe -------------------------------------------------------------- + +class LightGlobe : Actor +{ + Default + { + Radius 16; + Height 16; + +SOLID + } + States + { + Spawn: + LITE A -1 Bright; + Stop; + } +} + +// Techno Pillar ------------------------------------------------------------ + +class PillarTechno : Actor +{ + Default + { + Radius 20; + Height 128; + +SOLID + } + States + { + Spawn: + MONI A -1; + Stop; + } +} + +// Aztec Pillar ------------------------------------------------------------- + +class PillarAztec : Actor +{ + Default + { + Radius 16; + Height 128; + +SOLID + } + States + { + Spawn: + STEL A -1; + Stop; + } +} + +// Damaged Aztec Pillar ----------------------------------------------------- + +class PillarAztecDamaged : Actor +{ + Default + { + Radius 16; + Height 80; + +SOLID + } + States + { + Spawn: + STLA A -1; + Stop; + } +} + +// Ruined Aztec Pillar ------------------------------------------------------ + +class PillarAztecRuined : Actor +{ + Default + { + Radius 16; + Height 40; + +SOLID + } + States + { + Spawn: + STLE A -1; + Stop; + } +} + +// Huge Tech Pillar --------------------------------------------------------- + +class PillarHugeTech : Actor +{ + Default + { + Radius 24; + Height 192; + +SOLID + } + States + { + Spawn: + HUGE ABCD 4; + Loop; + } +} + +// Alien Power Crystal in a Pillar ------------------------------------------ + +class PillarAlienPower : Actor +{ + Default + { + Radius 24; + Height 192; + +SOLID + ActiveSound "ambient/alien2"; + } + States + { + Spawn: + APOW A 4 A_LoopActiveSound; + Loop; + } +} + +// SStalactiteBig ----------------------------------------------------------- + +class SStalactiteBig : Actor +{ + Default + { + Radius 16; + Height 54; + +SOLID +SPAWNCEILING +NOGRAVITY + } + States + { + Spawn: + STLG C -1; + Stop; + } +} + +// SStalactiteSmall --------------------------------------------------------- + +class SStalactiteSmall : Actor +{ + Default + { + Radius 16; + Height 40; + +SOLID +SPAWNCEILING +NOGRAVITY + } + States + { + Spawn: + STLG A -1; + Stop; + } +} + +// SStalagmiteBig ----------------------------------------------------------- + +class SStalagmiteBig : Actor +{ + Default + { + Radius 16; + Height 40; + +SOLID + } + States + { + Spawn: + STLG B -1; + Stop; + } +} + +// Cave Pillar Top ---------------------------------------------------------- + +class CavePillarTop : Actor +{ + Default + { + Radius 16; + Height 128; + +SOLID +SPAWNCEILING +NOGRAVITY + } + States + { + Spawn: + STLG D -1; + Stop; + } +} + +// Cave Pillar Bottom ------------------------------------------------------- + +class CavePillarBottom : Actor +{ + Default + { + Radius 16; + Height 128; + +SOLID + } + States + { + Spawn: + STLG E -1; + Stop; + } +} + +// SStalagmiteSmall --------------------------------------------------------- + +class SStalagmiteSmall : Actor +{ + Default + { + Radius 16; + Height 25; + +SOLID + } + States + { + Spawn: + STLG F -1; + Stop; + } +} + +// Candle ------------------------------------------------------------------- + +class Candle : Actor +{ + States + { + Spawn: + KNDL A -1 Bright; + Stop; + } +} + +// StrifeCandelabra --------------------------------------------------------- + +class StrifeCandelabra : Actor +{ + Default + { + Radius 16; + Height 40; + +SOLID + } + States + { + Spawn: + CLBR A -1; + Stop; + } +} + +// Floor Water Drop --------------------------------------------------------- + +class WaterDropOnFloor : Actor +{ + Default + { + +NOBLOCKMAP + ActiveSound "world/waterdrip"; + } + States + { + Spawn: + DRIP A 6 A_FLoopActiveSound; + DRIP BC 4; + DRIP D 4 A_FLoopActiveSound; + DRIP EF 4; + DRIP G 4 A_FLoopActiveSound; + DRIP H 4; + Loop; + } +} + +// Waterfall Splash --------------------------------------------------------- + +class WaterfallSplash : Actor +{ + Default + { + +NOBLOCKMAP + ActiveSound "world/waterfall"; + } + States + { + Spawn: + SPLH ABCDEFG 4; + SPLH H 4 A_LoopActiveSound; + Loop; + } +} + +// Ceiling Water Drip ------------------------------------------------------- + +class WaterDrip : Actor +{ + Default + { + Height 1; + +NOBLOCKMAP +SPAWNCEILING +NOGRAVITY + } + States + { + Spawn: + CDRP A 10; + CDRP BCD 8; + Loop; + } +} + +// WaterFountain ------------------------------------------------------------ + +class WaterFountain : Actor +{ + Default + { + +NOBLOCKMAP + ActiveSound "world/watersplash"; + } + States + { + Spawn: + WTFT ABC 4; + WTFT D 4 A_LoopActiveSound; + Loop; + } +} + +// Hearts in Tank ----------------------------------------------------------- + +class HeartsInTank : Actor +{ + Default + { + Radius 16; + Height 56; + +SOLID + } + States + { + Spawn: + HERT ABC 4 Bright; + Loop; + } +} + +// Teleport Swirl ----------------------------------------------------------- + +class TeleportSwirl : Actor +{ + Default + { + +NOBLOCKMAP + RenderStyle "Add"; + Alpha 0.25; + } + States + { + Spawn: + TELP ABCD 3 Bright; + Loop; + } +} + +// Dead Player -------------------------------------------------------------- +// Strife's disappeared. This one doesn't. + +class DeadStrifePlayer : Actor +{ + States + { + Spawn: + PLAY P 700; + RGIB H -1; + Stop; + } +} + +// Dead Peasant ------------------------------------------------------------- +// Unlike Strife's, this one does not turn into gibs and disappear. + +class DeadPeasant : Actor +{ + States + { + Spawn: + PEAS N -1; + Stop; + } +} + +// Dead Acolyte ------------------------------------------------------------- +// Unlike Strife's, this one does not turn into gibs and disappear. + +class DeadAcolyte : Actor +{ + States + { + Spawn: + AGRD N -1; + Stop; + } +} + +// Dead Reaver -------------------------------------------------------------- + +class DeadReaver : Actor +{ + States + { + Spawn: + ROB1 R -1; + Stop; + } +} + +// Dead Rebel --------------------------------------------------------------- + +class DeadRebel : Actor +{ + States + { + Spawn: + HMN1 N -1; + Stop; + } +} + +// Sacrificed Guy ----------------------------------------------------------- + +class SacrificedGuy : Actor +{ + States + { + Spawn: + SACR A -1; + Stop; + } +} + +// Pile of Guts ------------------------------------------------------------- + +class PileOfGuts : Actor +{ + // Strife used a doomednum, which is the same as the Aztec Pillar. Since + // the pillar came first in the mobjinfo list, you could not spawn this + // in a map. Pity. + States + { + Spawn: + DEAD A -1; + Stop; + } +} + +// Burning Barrel ----------------------------------------------------------- + +class StrifeBurningBarrel : Actor +{ + Default + { + Radius 16; + Height 48; + +SOLID + } + States + { + Spawn: + BBAR ABCD 4 Bright; + Loop; + } +} + +// Burning Bowl ----------------------------------------------------------- + +class BurningBowl : Actor +{ + Default + { + Radius 16; + Height 16; + +SOLID + ActiveSound "world/smallfire"; + } + States + { + Spawn: + BOWL ABCD 4 Bright; + Loop; + } +} + +// Burning Brazier ----------------------------------------------------------- + +class BurningBrazier : Actor +{ + Default + { + Radius 10; + Height 32; + +SOLID + ActiveSound "world/smallfire"; + } + States + { + Spawn: + BRAZ ABCD 4 Bright; + Loop; + } +} + +// Small Torch Lit -------------------------------------------------------- + +class SmallTorchLit : Actor +{ + Default + { + Radius 2.5; + Height 16; + +NOBLOCKMAP + +FIXMAPTHINGPOS + + // It doesn't have any action functions, so how does it use this sound? + ActiveSound "world/smallfire"; + } + States + { + Spawn: + TRHL ABCD 4 Bright; + Loop; + } +} + +// Small Torch Unlit -------------------------------------------------------- + +class SmallTorchUnlit : Actor +{ + Default + { + Radius 2.5; + Height 16; + +NOBLOCKMAP + +FIXMAPTHINGPOS + } + States + { + Spawn: + TRHO A -1; + Stop; + } +} + +// Ceiling Chain ------------------------------------------------------------ + +class CeilingChain : Actor +{ + Default + { + Radius 20; + Height 93; + +NOBLOCKMAP +SPAWNCEILING +NOGRAVITY + } + States + { + Spawn: + CHAN A -1; + Stop; + } +} + +// Cage Light --------------------------------------------------------------- + +class CageLight : Actor +{ + Default + { + // No, it's not bright even though it's a light. + Height 3; + +NOBLOCKMAP +SPAWNCEILING +NOGRAVITY + } + States + { + Spawn: + CAGE A -1; + Stop; + } +} + +// Statue ------------------------------------------------------------------- + +class Statue : Actor +{ + Default + { + Radius 20; + Height 64; + +SOLID + } + States + { + Spawn: + STAT A -1; + Stop; + } +} + +// Ruined Statue ------------------------------------------------------------ + +class StatueRuined : Actor +{ + Default + { + Radius 20; + Height 56; + +SOLID + } + States + { + Spawn: + DSTA A -1; + Stop; + } +} + +// Medium Torch ------------------------------------------------------------- + +class MediumTorch : Actor +{ + Default + { + Radius 4; + Height 72; + +SOLID + } + States + { + Spawn: + LTRH ABCD 4; + Loop; + } +} + +// Outside Lamp ------------------------------------------------------------- + +class OutsideLamp : Actor +{ + Default + { + // No, it's not bright. + Radius 3; + Height 80; + +SOLID + } + States + { + Spawn: + LAMP A -1; + Stop; + } +} + +// Pole Lantern ------------------------------------------------------------- + +class PoleLantern : Actor +{ + Default + { + // No, it's not bright. + Radius 3; + Height 80; + +SOLID + } + States + { + Spawn: + LANT A -1; + Stop; + } +} + +// Rock 1 ------------------------------------------------------------------- + +class SRock1 : Actor +{ + Default + { + +NOBLOCKMAP + } + States + { + Spawn: + ROK1 A -1; + Stop; + } +} + +// Rock 2 ------------------------------------------------------------------- + +class SRock2 : Actor +{ + Default + { + +NOBLOCKMAP + } + States + { + Spawn: + ROK2 A -1; + Stop; + } +} + +// Rock 3 ------------------------------------------------------------------- + +class SRock3 : Actor +{ + Default + { + +NOBLOCKMAP + } + States + { + Spawn: + ROK3 A -1; + Stop; + } +} + +// Rock 4 ------------------------------------------------------------------- + +class SRock4 : Actor +{ + Default + { + +NOBLOCKMAP + } + States + { + Spawn: + ROK4 A -1; + Stop; + } +} + +// Stick in Water ----------------------------------------------------------- + +class StickInWater : Actor +{ + Default + { + +NOBLOCKMAP + +FLOORCLIP + ActiveSound "world/river"; + } + States + { + Spawn: + LOGW ABCD 5 A_LoopActiveSound; + Loop; + } +} + +// Rubble 1 ----------------------------------------------------------------- + +class Rubble1 : Actor +{ + Default + { + +NOBLOCKMAP +NOCLIP + } + States + { + Spawn: + RUB1 A -1; + Stop; + } +} + +// Rubble 2 ----------------------------------------------------------------- + +class Rubble2 : Actor +{ + Default + { + +NOBLOCKMAP +NOCLIP + } + States + { + Spawn: + RUB2 A -1; + Stop; + } +} + +// Rubble 3 ----------------------------------------------------------------- + +class Rubble3 : Actor +{ + Default + { + +NOBLOCKMAP +NOCLIP + } + States + { + Spawn: + RUB3 A -1; + Stop; + } +} + +// Rubble 4 ----------------------------------------------------------------- + +class Rubble4 : Actor +{ + Default + { + +NOBLOCKMAP +NOCLIP + } + States + { + Spawn: + RUB4 A -1; + Stop; + } +} + +// Rubble 5 ----------------------------------------------------------------- + +class Rubble5 : Actor +{ + Default + { + +NOBLOCKMAP +NOCLIP + } + States + { + Spawn: + RUB5 A -1; + Stop; + } +} + +// Rubble 6 ----------------------------------------------------------------- + +class Rubble6 : Actor +{ + Default + { + +NOBLOCKMAP +NOCLIP + } + States + { + Spawn: + RUB6 A -1; + Stop; + } +} + +// Rubble 7 ----------------------------------------------------------------- + +class Rubble7 : Actor +{ + Default + { + +NOBLOCKMAP +NOCLIP + } + States + { + Spawn: + RUB7 A -1; + Stop; + } +} + +// Rubble 8 ----------------------------------------------------------------- + +class Rubble8 : Actor +{ + Default + { + +NOBLOCKMAP +NOCLIP + } + States + { + Spawn: + RUB8 A -1; + Stop; + } +} + +// Surgery Crab ------------------------------------------------------------- + +class SurgeryCrab : Actor +{ + Default + { + +SOLID +SPAWNCEILING +NOGRAVITY + Radius 20; + Height 16; + } + States + { + Spawn: + CRAB A -1; + Stop; + } +} + +// Large Torch -------------------------------------------------------------- + +class LargeTorch : Actor +{ + Default + { + Radius 10; + Height 72; + +SOLID + ActiveSound "world/smallfire"; + } + States + { + Spawn: + LMPC ABCD 4 Bright; + Loop; + } +} + +// Huge Torch -------------------------------------------------------------- + +class HugeTorch : Actor +{ + Default + { + Radius 10; + Height 80; + +SOLID + ActiveSound "world/smallfire"; + } + States + { + Spawn: + LOGS ABCD 4; + Loop; + } +} + +// Palm Tree ---------------------------------------------------------------- + +class PalmTree : Actor +{ + Default + { + Radius 15; + Height 109; + +SOLID + } + States + { + Spawn: + TREE A -1; + Stop; + } +} + +// Big Tree ---------------------------------------------------------------- + +class BigTree2 : Actor +{ + Default + { + Radius 15; + Height 109; + +SOLID + } + States + { + Spawn: + TREE B -1; + Stop; + } +} + +// Potted Tree ---------------------------------------------------------------- + +class PottedTree : Actor +{ + Default + { + Radius 15; + Height 64; + +SOLID + } + States + { + Spawn: + TREE C -1; + Stop; + } +} + +// Tree Stub ---------------------------------------------------------------- + +class TreeStub : Actor +{ + Default + { + Radius 15; + Height 80; + +SOLID + } + States + { + Spawn: + TRET A -1; + Stop; + } +} + +// Short Bush --------------------------------------------------------------- + +class ShortBush : Actor +{ + Default + { + Radius 15; + Height 40; + +SOLID + } + States + { + Spawn: + BUSH A -1; + Stop; + } +} + +// Tall Bush --------------------------------------------------------------- + +class TallBush : Actor +{ + Default + { + Radius 20; + Height 64; + +SOLID + } + States + { + Spawn: + SHRB A -1; + Stop; + } +} + +// Chimney Stack ------------------------------------------------------------ + +class ChimneyStack : Actor +{ + Default + { + Radius 20; + Height 64; // This height does not fit the sprite + +SOLID + } + States + { + Spawn: + STAK A -1; + Stop; + } +} + +// Barricade Column --------------------------------------------------------- + +class BarricadeColumn : Actor +{ + Default + { + Radius 16; + Height 128; + +SOLID + } + States + { + Spawn: + BARC A -1; + Stop; + } +} + +// Pot ---------------------------------------------------------------------- + +class Pot : Actor +{ + Default + { + Radius 12; + Height 24; + +SOLID + } + States + { + Spawn: + VAZE A -1; + Stop; + } +} + +// Pitcher ------------------------------------------------------------------ + +class Pitcher : Actor +{ + Default + { + Radius 12; + Height 32; + +SOLID + } + States + { + Spawn: + VAZE B -1; + Stop; + } +} + +// Stool -------------------------------------------------------------------- + +class Stool : Actor +{ + Default + { + Radius 6; + Height 24; + +SOLID + } + States + { + Spawn: + STOL A -1; + Stop; + } +} + +// Metal Pot ---------------------------------------------------------------- + +class MetalPot : Actor +{ + Default + { + +NOBLOCKMAP + } + States + { + Spawn: + MPOT A -1; + Stop; + } +} + +// Tub ---------------------------------------------------------------------- + +class Tub : Actor +{ + Default + { + +NOBLOCKMAP + } + States + { + Spawn: + TUB1 A -1; + Stop; + } +} + +// Anvil -------------------------------------------------------------------- + +class Anvil : Actor +{ + Default + { + Radius 16; + Height 32; + +SOLID + } + States + { + Spawn: + ANVL A -1; + Stop; + } +} + +// Silver Tech Lamp ---------------------------------------------------------- + +class TechLampSilver : Actor +{ + Default + { + Radius 11; + Height 64; + +SOLID + } + States + { + Spawn: + TECH A -1; + Stop; + } +} + +// Brass Tech Lamp ---------------------------------------------------------- + +class TechLampBrass : Actor +{ + Default + { + Radius 8; + Height 64; + +SOLID + } + States + { + Spawn: + TECH B -1; + Stop; + } +} + +// Tray -------------------------------------------------------------------- + +class Tray : Actor +{ + Default + { + Radius 24; + Height 40; + +SOLID + } + States + { + Spawn: + TRAY A -1; + Stop; + } +} + +// AmmoFiller --------------------------------------------------------------- + +class AmmoFiller : Actor +{ + Default + { + Radius 12; + Height 24; + +SOLID + } + States + { + Spawn: + AFED A -1; + Stop; + } +} + +// Sigil Banner ------------------------------------------------------------- + +class SigilBanner : Actor +{ + Default + { + Radius 24; + Height 96; + +NOBLOCKMAP // I take it this was once solid, yes? + } + States + { + Spawn: + SBAN A -1; + Stop; + } +} + +// RebelBoots --------------------------------------------------------------- + +class RebelBoots : Actor +{ + Default + { + +NOBLOCKMAP + } + States + { + Spawn: + BOTR A -1; + Stop; + } +} + +// RebelHelmet -------------------------------------------------------------- + +class RebelHelmet : Actor +{ + Default + { + +NOBLOCKMAP + } + States + { + Spawn: + HATR A -1; + Stop; + } +} + +// RebelShirt --------------------------------------------------------------- + +class RebelShirt : Actor +{ + Default + { + +NOBLOCKMAP + } + States + { + Spawn: + TOPR A -1; + Stop; + } +} + +// Alien Bubble Column ------------------------------------------------------ + +class AlienBubbleColumn : Actor +{ + Default + { + Radius 16; + Height 128; + +SOLID + ActiveSound "ambient/alien5"; + } + States + { + Spawn: + BUBB A 4 A_LoopActiveSound; + Loop; + } +} + +// Alien Floor Bubble ------------------------------------------------------- + +class AlienFloorBubble : Actor +{ + Default + { + Radius 16; + Height 72; + +SOLID + ActiveSound "ambient/alien6"; + } + States + { + Spawn: + BUBF A 4 A_LoopActiveSound; + Loop; + } +} + +// Alien Ceiling Bubble ----------------------------------------------------- + +class AlienCeilingBubble : Actor +{ + Default + { + Radius 16; + Height 72; + +SOLID +SPAWNCEILING +NOGRAVITY + ActiveSound "ambient/alien4"; + } + States + { + Spawn: + BUBC A 4 A_LoopActiveSound; + Loop; + } +} + +// Alien Asp Climber -------------------------------------------------------- + +class AlienAspClimber : Actor +{ + Default + { + Radius 16; + Height 128; + +SOLID + ActiveSound "ambient/alien3"; + } + States + { + Spawn: + ASPR A 4 A_LoopActiveSound; + Loop; + } +} + +// Alien Spider Light ------------------------------------------------------- + +class AlienSpiderLight : Actor +{ + Default + { + Radius 32; + Height 56; + +SOLID + ActiveSound "ambient/alien1"; + } + States + { + Spawn: + SPDL ABC 5 A_LoopActiveSound; + Loop; + } +} + +// Target Practice ----------------------------------------------------------- + +class TargetPractice : Actor +{ + Default + { + Health 99999999; + PainChance 255; + Radius 10; + Height 72; + Mass 9999999; + +SOLID +SHOOTABLE +NOBLOOD + +INCOMBAT +NODAMAGE + PainSound "misc/metalhit"; + } + States + { + Spawn: + HOGN A 2 A_CheckTerrain; + Loop; + Pain: + HOGN B 1 A_CheckTerrain; + HOGN C 1 A_Pain; + Goto Spawn; + } +} + +// Force Field Guard -------------------------------------------------------- + +class ForceFieldGuard : Actor +{ + Default + { + Health 10; + Radius 2; + Height 1; + Mass 10000; + +SHOOTABLE + +NOSECTOR + +NOBLOOD + +INCOMBAT + } + States + { + Spawn: + TNT1 A -1; + Stop; + Death: + TNT1 A 1 A_RemoveForceField; + Stop; + } + + override int TakeSpecialDamage (Actor inflictor, Actor source, int damage, Name damagetype) + { + if (inflictor == NULL || !(inflictor is "DegninOre")) + { + return -1; + } + return health; + } + +} + +// Kneeling Guy ------------------------------------------------------------- + +class KneelingGuy : Actor +{ + Default + { + Health 51; + Painchance 255; + Radius 6; + Height 17; + Mass 50000; + +SOLID + +SHOOTABLE + +NOBLOOD + +ISMONSTER + +INCOMBAT + PainSound "misc/static"; + DeathSound "misc/static"; + ActiveSound "misc/chant"; + } + States + { + Spawn: + See: + NEAL A 15 A_LoopActiveSound; + NEAL B 40 A_LoopActiveSound; + Loop; + Pain: + NEAL C 5 A_SetShadow; + NEAL B 4 A_Pain; + NEAL C 5 A_ClearShadow; + Goto Spawn; + Wound: + NEAL B 6; + NEAL C 13 A_GetHurt; + Loop; + Death: + NEAL D 5; + NEAL E 5 A_Scream; + NEAL F 6; + NEAL G 5 A_NoBlocking; + NEAL H 5; + NEAL I 6; + NEAL J -1; + Stop; + } +} + +// Power Coupling ----------------------------------------------------------- + +class PowerCoupling : Actor +{ + Default + { + Health 40; + Radius 17; + Height 64; + Mass 999999; + +SOLID + +SHOOTABLE + +DROPPED + +NOBLOOD + +NOTDMATCH + +INCOMBAT + } + States + { + Spawn: + COUP AB 5; + Loop; + } + + override void Die (Actor source, Actor inflictor, int dmgflags) + { + Super.Die (source, inflictor, dmgflags); + + int i; + + for (i = 0; i < MAXPLAYERS; ++i) + if (playeringame[i] && players[i].health > 0) + break; + + if (i == MAXPLAYERS) + return; + + // [RH] In case the player broke it with the dagger, alert the guards now. + if (LastHeard != source) + { + NoiseAlert (source); + } + Door_Close(225, 16); + Floor_LowerToHighestEE(44, 8); + players[i].mo.GiveInventoryType ("QuestItem6"); + S_Sound ("svox/voc13", CHAN_VOICE); + players[i].SetLogNumber (13); + A_DropItem ("BrokenPowerCoupling", -1, 256); + Destroy (); + } + +} + +// Gibs for things that bleed ----------------------------------------------- + +class Meat : Actor +{ + Default + { + +NOCLIP + } + States + { + Spawn: + MEAT A 700; + Stop; + MEAT B 700; + Stop; + MEAT C 700; + Stop; + MEAT D 700; + Stop; + MEAT E 700; + Stop; + MEAT F 700; + Stop; + MEAT G 700; + Stop; + MEAT H 700; + Stop; + MEAT I 700; + Stop; + MEAT J 700; + Stop; + MEAT K 700; + Stop; + MEAT L 700; + Stop; + MEAT M 700; + Stop; + MEAT N 700; + Stop; + MEAT O 700; + Stop; + MEAT P 700; + Stop; + MEAT Q 700; + Stop; + MEAT R 700; + Stop; + MEAT S 700; + Stop; + MEAT T 700; + Stop; + } + + override void BeginPlay () + { + // Strife used mod 19, but there are 20 states. Hmm. + SetState (SpawnState + random[GibTosser]() % 20); + } + +} + +// Gibs for things that don't bleed ----------------------------------------- + +class Junk : Meat +{ + States + { + Spawn: + JUNK A 700; + Stop; + JUNK B 700; + Stop; + JUNK C 700; + Stop; + JUNK D 700; + Stop; + JUNK E 700; + Stop; + JUNK F 700; + Stop; + JUNK G 700; + Stop; + JUNK H 700; + Stop; + JUNK I 700; + Stop; + JUNK J 700; + Stop; + JUNK K 700; + Stop; + JUNK L 700; + Stop; + JUNK M 700; + Stop; + JUNK N 700; + Stop; + JUNK O 700; + Stop; + JUNK P 700; + Stop; + JUNK Q 700; + Stop; + JUNK R 700; + Stop; + JUNK S 700; + Stop; + JUNK T 700; + Stop; + } +} + diff --git a/wadsrc/static/zscript/strife/strifeweapons.txt b/wadsrc/static/zscript/strife/strifeweapons.txt new file mode 100644 index 0000000000..5cb01342e1 --- /dev/null +++ b/wadsrc/static/zscript/strife/strifeweapons.txt @@ -0,0 +1,52 @@ + +class StrifeWeapon : Weapon +{ + Default + { + Weapon.Kickback 100; + } +} + +// Same as the bullet puff for Doom ----------------------------------------- + +class StrifePuff : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + +ALLOWPARTICLES + RenderStyle "Translucent"; + Alpha 0.25; + } + + States + { + Spawn: + POW3 ABCDEFGH 3; + Stop; + Crash: + PUFY A 4 Bright; + PUFY BCD 4; + Stop; + } +} + + +// A spark when you hit something that doesn't bleed ------------------------ +// Only used by the dagger. + +class StrifeSpark : StrifePuff +{ + Default + { + RenderStyle "Add"; + } + States + { + Crash: + POW2 ABCD 4; + Stop; + } +} + diff --git a/wadsrc/static/zscript/strife/templar.txt b/wadsrc/static/zscript/strife/templar.txt new file mode 100644 index 0000000000..23290011c9 --- /dev/null +++ b/wadsrc/static/zscript/strife/templar.txt @@ -0,0 +1,84 @@ + +class Templar : Actor +{ + Default + { + Health 300; + Painchance 100; + Speed 8; + Radius 20; + Height 60; + Mass 500; + Monster; + +NOBLOOD + +SEESDAGGERS + +NOSPLASHALERT + MaxdropoffHeight 32; + MinMissileChance 200; + SeeSound "templar/sight"; + PainSound "templar/pain"; + DeathSound "templar/death"; + ActiveSound "templar/active"; + CrushPainSound "misc/pcrush"; + Tag "$TAG_TEMPLAR"; + HitObituary "$OB_TEMPLARHIT"; + Obituary "$OB_TEMPLAR"; + DropItem "EnergyPod"; + } + + States + { + Spawn: + PGRD A 5 A_Look2; + Loop; + PGRD B 10; + Loop; + PGRD C 10; + Loop; + PGRD B 10 A_Wander; + Loop; + See: + PGRD AABBCCDD 3 A_Chase; + Loop; + Melee: + PGRD E 8 A_FaceTarget; + PGRD F 8 A_CustomMeleeAttack(random[ReaverMelee](1,8)*3, "reaver/blade"); + Goto See; + Missile: + PGRD G 8 BRIGHT A_FaceTarget; + PGRD H 8 BRIGHT A_TemplarAttack; + Goto See; + Pain: + PGRD A 2; + PGRD A 2 A_Pain; + Goto See; + Death: + PGRD I 4 A_TossGib; + PGRD J 4 A_Scream; + PGRD K 4 A_TossGib; + PGRD L 4 A_NoBlocking; + PGRD MN 4; + PGRD O 4 A_TossGib; + PGRD PQRSTUVWXYZ[ 4; + PGRD \ -1; + Stop; + } + + void A_TemplarAttack() + { + if (target != null) + { + A_PlaySound ("templar/shoot", CHAN_WEAPON); + A_FaceTarget (); + double pitch = AimLineAttack (angle, MISSILERANGE); + + for (int i = 0; i < 10; ++i) + { + int damage = (random[Templar]() & 4) * 2; + double ang = angle + random2[Templar]() * (11.25 / 256); + LineAttack (ang, MISSILERANGE+64., pitch + random2[Templar]() * (7.097 / 256), damage, 'Hitscan', "MaulerPuff"); + } + } + } +} + diff --git a/wadsrc/static/zscript/strife/thingstoblowup.txt b/wadsrc/static/zscript/strife/thingstoblowup.txt new file mode 100644 index 0000000000..5e5bfac210 --- /dev/null +++ b/wadsrc/static/zscript/strife/thingstoblowup.txt @@ -0,0 +1,231 @@ +extend class Actor +{ + + void A_Bang4Cloud() + { + double xo = (random[Bang4Cloud]() & 3) * (10. / 64); + double yo = (random[Bang4Cloud]() & 3) * (10. / 64); + Spawn("Bang4Cloud", Vec3Offset(xo, yo, 0.), ALLOW_REPLACE); + } + + void A_GiveQuestItem(int questitem) + { + // Give one of these quest items to every player in the game + if (questitem >= 0) + { + String itemname = "QuestItem" .. questitem; + class item = itemname; + if (item != null) + { + for (int i = 0; i < MAXPLAYERS; ++i) + { + if (playeringame[i]) + { + players[i].mo.GiveInventoryType(item); + } + } + } + } + + String msgid = "TXT_QUEST_" .. questitem; + String msg = StringTable.Localize(msgid); + + if (msg != msgid) // if both are identical there was no message of this name in the stringtable. + { + C_MidPrint ("SmallFont", msg); + } + } + +} + +// A Cloud used for varius explosions --------------------------------------- +// This actor has no direct equivalent in strife. To create this, Strife +// spawned a spark and then changed its state to that of this explosion +// cloud. Weird. + +class Bang4Cloud : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + RenderStyle "Add"; + VSpeed 1; + } + States + { + Spawn: + BNG4 BCDEFGHIJKLMN 3 Bright; + Stop; + } +} + +// Piston ------------------------------------------------------------------- + +class Piston : Actor +{ + Default + { + Health 100; + Speed 16; + Radius 20; + Height 76; + Mass 10000000; + +SOLID + +SHOOTABLE + +NOBLOOD + +FLOORCLIP + +INCOMBAT + DeathSound "misc/explosion"; + } + States + { + Spawn: + PSTN AB 8; + Loop; + Death: + PSTN A 4 Bright A_Scream; + PSTN B 4 Bright A_NoBlocking; + PSTN C 4 Bright A_GiveQuestItem(16); + PSTN D 4 Bright A_Bang4Cloud; + PSTN E 4 Bright A_TossGib; + PSTN F 4 Bright; + PSTN G 4 Bright A_Bang4Cloud; + PSTN H 4; + PSTN I -1; + Stop; + } + +} + +// Computer ----------------------------------------------------------------- + +class Computer : Actor +{ + Default + { + Health 80; + Speed 27; + Radius 26; + Height 128; + Mass 10000000; + +SOLID + +SHOOTABLE + +NOBLOOD + +FLOORCLIP + +INCOMBAT + DeathSound "misc/explosion"; + } + States + { + Spawn: + SECR ABCD 4 Bright; + Loop; + Death: + SECR E 5 Bright A_Bang4Cloud; + SECR F 5 Bright A_NoBlocking; + SECR G 5 Bright A_GiveQuestItem(27); + SECR H 5 Bright A_TossGib; + SECR I 5 Bright A_Bang4Cloud; + SECR J 5; + SECR K 5 A_Bang4Cloud; + SECR L 5; + SECR M 5 A_Bang4Cloud; + SECR N 5; + SECR O 5 A_Bang4Cloud; + SECR P -1; + Stop; + } +} + + +// Power Crystal ------------------------------------------------------------ + +class PowerCrystal : Actor +{ + Default + { + Health 50; + Speed 14; + Radius 20; + Height 16; + Mass 99999999; + +SOLID + +SHOOTABLE + +NOGRAVITY + +NOBLOOD + +FLOORCLIP + DeathSound "misc/explosion"; + ActiveSound "misc/reactor"; + } + + States + { + Spawn: + CRYS A 16 A_LoopActiveSound; + CRYS B 5 A_LoopActiveSound; + CRYS CDEF 4 A_LoopActiveSound; + Loop; + Death: + BOOM A 0 Bright A_Scream; + BOOM A 1 Bright A_Explode512; + BOOM B 3 Bright A_GiveQuestItem(14); + BOOM C 2 Bright A_LightGoesOut; + BOOM D 3 Bright A_Bang4Cloud; + BOOM EF 3 Bright; + BOOM G 3 Bright A_Bang4Cloud; + BOOM H 1 Bright A_Explode512; + BOOM I 3 Bright; + BOOM JKL 3 Bright A_Bang4Cloud; + BOOM MN 3 Bright; + BOOM O 3 Bright A_Bang4Cloud; + BOOM PQRST 3 Bright; + BOOM U 3 Bright A_ExtraLightOff; + BOOM VWXY 3 Bright; + Stop; + } + + // PowerCrystal ------------------------------------------------------------------- + + void A_ExtraLightOff() + { + if (target != NULL && target.player != NULL) + { + target.player.extralight = 0; + } + } + + void A_Explode512() + { + A_Explode(512, 512); + if (target != NULL && target.player != NULL) + { + target.player.extralight = 5; + } + A_SetRenderStyle(1, STYLE_Add); + } + + void A_LightGoesOut() + { + sector sec = CurSector; + + sec.Flags |= Sector.SECF_SILENTMOVE; + sec.lightlevel = 0; + // Do this right with proper checks instead of just hacking the floor height. + Floor.CreateFloor(sec, Floor.floorLowerToLowest, null, 65536.); + + + for (int i = 0; i < 8; ++i) + { + Actor foo = Spawn("Rubble1", Pos, ALLOW_REPLACE); + if (foo != NULL) + { + int t = random[LightOut]() & 15; + foo.Vel.X = t - (random[LightOut]() & 7); + foo.Vel.Y = random2[LightOut]() & 7; + foo.Vel.Z = 7 + (random[LightOut]() & 3); + } + } + } + +} diff --git a/wadsrc/static/zscript/strife/weaponassault.txt b/wadsrc/static/zscript/strife/weaponassault.txt new file mode 100644 index 0000000000..c382d8e848 --- /dev/null +++ b/wadsrc/static/zscript/strife/weaponassault.txt @@ -0,0 +1,94 @@ +// Assault Gun -------------------------------------------------------------- + +class AssaultGun : StrifeWeapon +{ + Default + { + +FLOORCLIP + Weapon.SelectionOrder 600; + Weapon.AmmoUse1 1; + Weapon.AmmoGive1 20; + Weapon.AmmoType1 "ClipOfBullets"; + Inventory.Icon "RIFLA0"; + Tag "$TAG_ASSAULTGUN"; + Inventory.PickupMessage "$TXT_ASSAULTGUN"; + Obituary "$OB_MPASSAULTGUN"; + } + States + { + Spawn: + RIFL A -1; + Stop; + Ready: + RIFG A 1 A_WeaponReady; + Loop; + Deselect: + RIFG B 1 A_Lower; + Loop; + Select: + RIFG A 1 A_Raise; + Loop; + Fire: + RIFF AB 3 A_FireAssaultGun; + RIFG D 3 A_FireAssaultGun; + RIFG C 0 A_ReFire; + RIFG B 2 A_Light0; + Goto Ready; + } +} + +extend class StateProvider +{ + //============================================================================ + // + // A_FireAssaultGun + // + //============================================================================ + + void A_FireAssaultGun() + { + if (player == null) + { + return; + } + + A_PlaySound ("weapons/assaultgun", CHAN_WEAPON); + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + player.mo.PlayAttacking2 (); + + int damage = 4*(random[StrifeGun]() % 3 + 1); + double ang = angle; + + if (player.refire) + { + ang += Random2[StrifeGun]() * (22.5 / 256) * AccuracyFactor(); + } + LineAttack (ang, PLAYERMISSILERANGE, BulletSlope (), damage, 'Hitscan', "StrifePuff"); + } +} + + +// Standing variant of the assault gun -------------------------------------- + +class AssaultGunStanding : WeaponGiver +{ + Default + { + DropItem "AssaultGun"; + Inventory.PickupMessage "$TXT_ASSAULTGUN"; + } + States + { + Spawn: + RIFL B -1; + Stop; + } +} + + diff --git a/wadsrc/static/zscript/strife/weaponcrossbow.txt b/wadsrc/static/zscript/strife/weaponcrossbow.txt new file mode 100644 index 0000000000..1617fbfcdb --- /dev/null +++ b/wadsrc/static/zscript/strife/weaponcrossbow.txt @@ -0,0 +1,227 @@ +// Strife's Crossbow -------------------------------------------------------- + +class StrifeCrossbow : StrifeWeapon +{ + Default + { + +FLOORCLIP + Weapon.SelectionOrder 1200; + +WEAPON.NOALERT + Weapon.AmmoUse1 1; + Weapon.AmmoGive1 8; + Weapon.AmmoType1 "ElectricBolts"; + Weapon.SisterWeapon "StrifeCrossbow2"; + Inventory.PickupMessage "$TXT_STRIFECROSSBOW"; + Tag "$TAG_STRIFECROSSBOW1"; + Inventory.Icon "CBOWA0"; + } + + States + { + Spawn: + CBOW A -1; + Stop; + Ready: + XBOW A 0 A_ShowElectricFlash; + XBOW A 1 A_WeaponReady; + Wait; + Deselect: + XBOW A 1 A_Lower; + Loop; + Select: + XBOW A 1 A_Raise; + Loop; + Fire: + XBOW A 3 A_ClearFlash; + XBOW B 6 A_FireArrow("ElectricBolt"); + XBOW C 4; + XBOW D 6; + XBOW E 3; + XBOW F 5; + XBOW G 0 A_ShowElectricFlash; + XBOW G 5 A_CheckReload; + Goto Ready+1; + Flash: + XBOW KLM 5; + Loop; + } + + //============================================================================ + // + // A_ClearFlash + // + //============================================================================ + + action void A_ClearFlash () + { + if (player == null) + return; + + player.SetPsprite (PSP_FLASH, null); + } + + //============================================================================ + // + // A_ShowElectricFlash + // + //============================================================================ + + action void A_ShowElectricFlash () + { + if (player != null) + { + player.SetPsprite (PSP_FLASH, player.ReadyWeapon.FindState('Flash')); + } + } + + //============================================================================ + // + // A_FireElectric + // + //============================================================================ + + action void A_FireArrow (class proj) + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + if (proj) + { + double savedangle = angle; + angle += Random2[Electric]() * (5.625/256) * AccuracyFactor(); + player.mo.PlayAttacking2 (); + SpawnPlayerMissile (proj); + angle = savedangle; + A_PlaySound ("weapons/xbowshoot", CHAN_WEAPON); + } + } +} + + +class StrifeCrossbow2 : StrifeCrossbow +{ + Default + { + Weapon.SelectionOrder 2700; + Weapon.AmmoUse1 1; + Weapon.AmmoGive1 0; + Weapon.AmmoType1 "PoisonBolts"; + Weapon.SisterWeapon "StrifeCrossbow"; + Tag "$TAG_STRIFECROSSBOW2"; + } + States + { + Ready: + XBOW H 1 A_WeaponReady; + Loop; + Deselect: + XBOW H 1 A_Lower; + Loop; + Select: + XBOW H 1 A_Raise; + Loop; + Fire: + XBOW H 3; + XBOW B 6 A_FireArrow("PoisonBolt"); + XBOW C 4; + XBOW D 6; + XBOW E 3; + XBOW I 5; + XBOW J 5 A_CheckReload; + Goto Ready; + Flash: + Stop; + } +} + +// Electric Bolt ------------------------------------------------------------ + +class ElectricBolt : Actor +{ + Default + { + Speed 30; + Radius 10; + Height 10; + Damage 10; + Projectile; + +STRIFEDAMAGE + +NOBLOCKMAP + +NOGRAVITY + +DROPOFF + MaxStepHeight 4; + SeeSound "misc/swish"; + ActiveSound "misc/swish"; + DeathSound "weapons/xbowhit"; + Obituary "$OB_MPELECTRICBOLT"; + } + States + { + Spawn: + AROW A 10 A_LoopActiveSound; + Loop; + Death: + ZAP1 A 3 A_AlertMonsters; + ZAP1 BCDEFE 3; + ZAP1 DCB 2; + ZAP1 A 1; + Stop; + } +} + + +// Poison Bolt -------------------------------------------------------------- + +class PoisonBolt : Actor +{ + Default + { + Speed 30; + Radius 10; + Height 10; + Damage 500; + Projectile; + +STRIFEDAMAGE + MaxStepHeight 4; + SeeSound "misc/swish"; + ActiveSound "misc/swish"; + Obituary "$OB_MPPOISONBOLT"; + } + States + { + Spawn: + ARWP A 10 A_LoopActiveSound; + Loop; + Death: + AROW A 1; + Stop; + } + + override int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + if (target.bNoBlood) + { + return -1; + } + if (target.health < 1000000) + { + if (!target.bBoss) + return target.health + 10; + else + return 50; + } + return 1; + } + + +} + + diff --git a/wadsrc/static/zscript/strife/weapondagger.txt b/wadsrc/static/zscript/strife/weapondagger.txt new file mode 100644 index 0000000000..24aef209b3 --- /dev/null +++ b/wadsrc/static/zscript/strife/weapondagger.txt @@ -0,0 +1,69 @@ + +// Punch Dagger ------------------------------------------------------------- + +class PunchDagger : StrifeWeapon +{ + Default + { + Weapon.SelectionOrder 3900; + +WEAPON.NOALERT + Obituary "$OB_MPPUNCHDAGGER"; + Tag "$TAG_PUNCHDAGGER"; + } + + States + { + Ready: + PNCH A 1 A_WeaponReady; + Loop; + Deselect: + PNCH A 1 A_Lower; + Loop; + Select: + PNCH A 1 A_Raise; + Loop; + Fire: + PNCH B 4; + PNCH C 4 A_JabDagger; + PNCH D 5; + PNCH C 4; + PNCH B 5 A_ReFire; + Goto Ready; + } + + //============================================================================ + // + // A_JabDagger + // + //============================================================================ + + action void A_JabDagger () + { + FTranslatedLineTarget t; + + int power = MIN(10, stamina / 10); + int damage = (random[JabDagger]() % (power + 8)) * (power + 2); + + if (FindInventory("PowerStrength")) + { + damage *= 10; + } + + double angle = angle + random2[JabDagger]() * (5.625 / 256); + double pitch = AimLineAttack (angle, 80.); + LineAttack (angle, 80., pitch, damage, 'Melee', "StrifeSpark", true, t); + + // turn to face target + if (t.linetarget) + { + S_Sound (t.linetarget.bNoBlood ? sound("misc/metalhit") : sound("misc/meathit"), CHAN_WEAPON); + angle = t.angleFromSource; + bJustAttacked = true; + t.linetarget.DaggerAlert (self); + } + else + { + A_PlaySound ("misc/swish", CHAN_WEAPON); + } + } +} diff --git a/wadsrc/static/zscript/strife/weaponflamer.txt b/wadsrc/static/zscript/strife/weaponflamer.txt new file mode 100644 index 0000000000..9a47bc2422 --- /dev/null +++ b/wadsrc/static/zscript/strife/weaponflamer.txt @@ -0,0 +1,118 @@ +// Flame Thrower ------------------------------------------------------------ + +class FlameThrower : StrifeWeapon +{ + Default + { + +FLOORCLIP + Weapon.SelectionOrder 2100; + Weapon.Kickback 0; + Weapon.AmmoUse1 1; + Weapon.AmmoGive1 100; + Weapon.UpSound "weapons/flameidle"; + Weapon.ReadySound "weapons/flameidle"; + Weapon.AmmoType1 "EnergyPod"; + Inventory.Icon "FLAMA0"; + Tag "$TAG_FLAMER"; + Inventory.PickupMessage "$TXT_FLAMER"; + } + + States + { + Spawn: + FLAM A -1; + Stop; + Ready: + FLMT AB 3 A_WeaponReady; + Loop; + Deselect: + FLMT A 1 A_Lower; + Loop; + Select: + FLMT A 1 A_Raise; + Loop; + Fire: + FLMF A 2 A_FireFlamer; + FLMF B 3 A_ReFire; + Goto Ready; + } + + //============================================================================ + // + // A_FireFlamer + // + //============================================================================ + + action void A_FireFlamer () + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + + player.mo.PlayAttacking2 (); + + Angle += Random2[Flamethrower]() * (5.625/256.); + Actor mo = SpawnPlayerMissile ("FlameMissile"); + if (mo != NULL) + { + mo.Vel.Z += 5; + } + } +} + + +// Flame Thrower Projectile ------------------------------------------------- + +class FlameMissile : Actor +{ + Default + { + Speed 15; + Height 11; + Radius 8; + Mass 10; + Damage 4; + DamageType "Fire"; + ReactionTime 8; + Projectile; + -NOGRAVITY + +STRIFEDAMAGE + MaxStepHeight 4; + RenderStyle "Add"; + SeeSound "weapons/flamethrower"; + Obituary "$OB_MPFLAMETHROWER"; + } + + States + { + Spawn: + FRBL AB 3 Bright; + FRBL C 3 Bright A_Countdown; + Loop; + Death: + FRBL D 5 Bright A_FlameDie; + FRBL EFGHI 5 Bright; + Stop; + } + + //============================================================================ + // + // A_FlameDie + // + //============================================================================ + + void A_FlameDie () + { + bNoGravity = true; + Vel.Z = random[FlameDie]() & 3; + } +} + diff --git a/wadsrc/static/zscript/strife/weapongrenade.txt b/wadsrc/static/zscript/strife/weapongrenade.txt new file mode 100644 index 0000000000..7a775c57ba --- /dev/null +++ b/wadsrc/static/zscript/strife/weapongrenade.txt @@ -0,0 +1,315 @@ +// High-Explosive Grenade Launcher ------------------------------------------ + +class StrifeGrenadeLauncher : StrifeWeapon +{ + Default + { + +FLOORCLIP + Weapon.SelectionOrder 2400; + Weapon.AmmoUse1 1; + Weapon.AmmoGive1 12; + Weapon.AmmoType1 "HEGrenadeRounds"; + Weapon.SisterWeapon "StrifeGrenadeLauncher2"; + Inventory.Icon "GRNDA0"; + Tag "$TAG_GLAUNCHER1"; + Inventory.PickupMessage "$TXT_GLAUNCHER"; + } + + States + { + Spawn: + GRND A -1; + Stop; + Ready: + GREN A 1 A_WeaponReady; + Loop; + Deselect: + GREN A 1 A_Lower; + Loop; + Select: + GREN A 1 A_Raise; + Loop; + Fire: + GREN A 5 A_FireGrenade("HEGrenade", -90, "Flash"); + GREN B 10; + GREN A 5 A_FireGrenade("HEGrenade", 90, "Flash2"); + GREN C 10; + GREN A 0 A_ReFire; + Goto Ready; + Flash: + GREF A 5 Bright A_Light1; + Goto LightDone; + Flash2: + GREF B 5 Bright A_Light2; + Goto LightDone; + } + + //============================================================================ + // + // A_FireGrenade + // + //============================================================================ + + action void A_FireGrenade (class grenadetype, double angleofs, statelabel flash) + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + + player.SetPsprite (PSP_FLASH, weapon.FindState(flash), true); + } + + if (grenadetype != null) + { + AddZ(32); + Actor grenade = SpawnSubMissile (grenadetype, self); + AddZ(-32); + if (grenade == null) + return; + + if (grenade.SeeSound != 0) + { + grenade.A_PlaySound (grenade.SeeSound, CHAN_VOICE); + } + + grenade.Vel.Z = (-clamp(tan(Pitch), -5, 5)) * grenade.Speed + 8; + + Vector2 offset = AngleToVector(angle, radius + grenade.radius); + double an = Angle + angleofs; + offset += AngleToVector(an, 15); + grenade.SetOrigin(grenade.Vec3Offset(offset.X, offset.Y, 0.), false); + } + } +} + +// White Phosphorous Grenade Launcher --------------------------------------- + +class StrifeGrenadeLauncher2 : StrifeGrenadeLauncher +{ + Default + { + Weapon.SelectionOrder 3200; + Weapon.AmmoUse1 1; + Weapon.AmmoGive1 0; + Weapon.AmmoType1 "PhosphorusGrenadeRounds"; + Weapon.SisterWeapon "StrifeGrenadeLauncher"; + Tag "$TAG_GLAUNCHER2"; + } + States + { + Ready: + GREN D 1 A_WeaponReady; + Loop; + Deselect: + GREN D 1 A_Lower; + Loop; + Select: + GREN D 1 A_Raise; + Loop; + Fire: + GREN D 5 A_FireGrenade("PhosphorousGrenade", -90, "Flash"); + GREN E 10; + GREN D 5 A_FireGrenade("PhosphorousGrenade", 90, "Flash2"); + GREN F 10; + GREN A 0 A_ReFire; + Goto Ready; + Flash: + GREF C 5 Bright A_Light1; + Goto LightDone; + Flash2: + GREF D 5 Bright A_Light2; + Goto LightDone; + } +} + +// High-Explosive Grenade --------------------------------------------------- + +class HEGrenade : Actor +{ + Default + { + Speed 15; + Radius 13; + Height 13; + Mass 20; + Damage 1; + Reactiontime 30; + Projectile; + -NOGRAVITY + +STRIFEDAMAGE + +BOUNCEONACTORS + +EXPLODEONWATER + MaxStepHeight 4; + BounceType "Doom"; + BounceFactor 0.5; + BounceCount 2; + SeeSound "weapons/hegrenadeshoot"; + DeathSound "weapons/hegrenadebang"; + Obituary "$OB_MPSTRIFEGRENADE"; + } + States + { + Spawn: + GRAP AB 3 A_Countdown; + Loop; + Death: + BNG4 A 0 Bright A_NoGravity; + BNG4 A 0 Bright A_SetRenderStyle(1, STYLE_Normal); + BNG4 A 2 Bright A_Explode(192, 192, alert:true); + BNG4 BCDEFGHIJKLMN 3 Bright; + Stop; + } +} + +// White Phosphorous Grenade ------------------------------------------------ + +class PhosphorousGrenade : Actor +{ + Default + { + Speed 15; + Radius 13; + Height 13; + Mass 20; + Damage 1; + Reactiontime 40; + Projectile; + -NOGRAVITY + +STRIFEDAMAGE + +BOUNCEONACTORS + +EXPLODEONWATER + BounceType "Doom"; + MaxStepHeight 4; + BounceFactor 0.5; + BounceCount 2; + SeeSound "weapons/phgrenadeshoot"; + DeathSound "weapons/phgrenadebang"; + Obituary "$OB_MPPHOSPHOROUSGRENADE"; + } + States + { + Spawn: + GRIN AB 3 A_Countdown; + Loop; + Death: + BNG3 A 2 A_SpawnItemEx("PhosphorousFire"); + Stop; + } +} + +// Fire from the Phoshorous Grenade ----------------------------------------- + +class PhosphorousFire : Actor +{ + Default + { + Reactiontime 120; + DamageType "Fire"; + +NOBLOCKMAP + +FLOORCLIP + +NOTELEPORT + +NODAMAGETHRUST + +DONTSPLASH + RenderStyle "Add"; + Obituary "$OB_MPPHOSPHOROUSGRENADE"; + } + + States + { + Spawn: + BNG3 B 2 Bright A_Burnarea; + BNG3 C 2 Bright A_Countdown; + FLBE A 2 Bright A_Burnination; + FLBE B 2 Bright A_Countdown; + FLBE C 2 Bright A_Burnarea; + FLBE D 3 Bright A_Countdown; + FLBE E 3 Bright A_Burnarea; + FLBE F 3 Bright A_Countdown; + FLBE G 3 Bright A_Burnination; + Goto Spawn+5; + Death: + FLBE H 2 Bright; + FLBE I 2 Bright A_Burnination; + FLBE JK 2 Bright; + Stop; + } + + int DoSpecialDamage (Actor target, int damage, Name damagetype) + { + if (target.bNoBlood) + { + return damage / 2; + } + return Super.DoSpecialDamage (target, damage, damagetype); + } + + // This function is mostly redundant and only kept in case some mod references it. + void A_Burnarea () + { + A_Explode(128, 128); + } + + void A_Burnination () + { + Vel.Z -= 8; + Vel.X += (random2[PHBurn] (3)); + Vel.Y += (random2[PHBurn] (3)); + A_PlaySound ("world/largefire", CHAN_VOICE); + + // Only the main fire spawns more. + if (!bDropped) + { + // Original x and y offsets seemed to be like this: + // x + (((pr_phburn() + 12) & 31) << F.RACBITS); + // + // But that creates a lop-sided burn because it won't use negative offsets. + int xofs, xrand = random[PHBurn](); + int yofs, yrand = random[PHBurn](); + + // Adding 12 is pointless if you're going to mask it afterward. + xofs = xrand & 31; + if (xrand & 128) + { + xofs = -xofs; + } + + yofs = yrand & 31; + if (yrand & 128) + { + yofs = -yofs; + } + + Vector2 newpos = Vec2Offset(xofs, yofs); + + Sector sec = Sector.PointInSector(newpos); + // Consider portals and 3D floors instead of just using the current sector's z. + double floorh = sec.NextLowestFloorAt(newpos.x, newpos.y, pos.z+4, 0, MaxStepHeight); + + // The sector's floor is too high so spawn the flame elsewhere. + if (floorh + MaxStepHeight) + { + newpos = Pos.xy; + } + + Actor drop = Spawn("PhosphorousFire", (newpos, pos.z + 4.), ALLOW_REPLACE); + if (drop != NULL) + { + drop.Vel.X = Vel.X + random2[PHBurn] (7); + drop.Vel.Y = Vel.Y + random2[PHBurn] (7); + drop.Vel.Z = Vel.Z - 1; + drop.reactiontime = (random[PHBurn]() & 3) + 2; + drop.bDropped = true; + } + } + } + + +} + diff --git a/wadsrc/static/zscript/strife/weaponmauler.txt b/wadsrc/static/zscript/strife/weaponmauler.txt new file mode 100644 index 0000000000..80f3afcdec --- /dev/null +++ b/wadsrc/static/zscript/strife/weaponmauler.txt @@ -0,0 +1,286 @@ +// Mauler ------------------------------------------------------------------- +// The scatter version + +class Mauler : StrifeWeapon +{ + Default + { + +FLOORCLIP + Weapon.SelectionOrder 300; + Weapon.AmmoUse1 20; + Weapon.AmmoGive1 40; + Weapon.AmmoType1 "EnergyPod"; + Weapon.SisterWeapon "Mauler2"; + Inventory.Icon "TRPDA0"; + Tag "$TAG_MAULER1"; + Inventory.PickupMessage "$TXT_MAULER"; + Obituary "$OB_MPMAULER1"; + } + + States + { + Ready: + MAUL FGHA 6 A_WeaponReady; + Loop; + Deselect: + MAUL A 1 A_Lower; + Loop; + Select: + MAUL A 1 A_Raise; + Loop; + Fire: + BLSF A 5 Bright A_FireMauler1; + MAUL B 3 Bright A_Light1; + MAUL C 2 A_Light2; + MAUL DE 2; + MAUL A 7 A_Light0; + MAUL H 7; + MAUL G 7 A_CheckReload; + Goto Ready; + Spawn: + TRPD A -1; + Stop; + } + + //============================================================================ + // + // A_FireMauler1 + // + // Hey! This is exactly the same as a super shotgun except for the sound + // and the bullet puffs and the disintegration death. + // + //============================================================================ + + action void A_FireMauler1() + { + if (player == null) + { + return; + } + + A_PlaySound ("weapons/mauler1", CHAN_WEAPON); + Weapon weap = player.ReadyWeapon; + if (weap != null) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 2)) + return; + + } + player.mo.PlayAttacking2 (); + + double pitch = BulletSlope (); + + for (int i = 0 ; i < 20 ; i++) + { + int damage = 5 * random[Mauler1](1, 3); + double ang = angle + Random2[Mauler1]() * (11.25 / 256); + + // Strife used a range of 2112 units for the mauler to signal that + // it should use a different puff. ZDoom's default range is longer + // than this, so let's not handicap it by being too faithful to the + // original. + + LineAttack (ang, PLAYERMISSILERANGE, pitch + Random2[Mauler1]() * (7.097 / 256), damage, 'Hitscan', "MaulerPuff"); + } + } +} + + +// Mauler Torpedo version --------------------------------------------------- + +class Mauler2 : Mauler +{ + Default + { + Weapon.SelectionOrder 3300; + Weapon.AmmoUse1 30; + Weapon.AmmoGive1 0; + Weapon.AmmoType1 "EnergyPod"; + Weapon.SisterWeapon "Mauler"; + Tag "$TAG_MAULER2"; + } + + States + { + Ready: + MAUL IJKL 7 A_WeaponReady; + Loop; + Deselect: + MAUL I 1 A_Lower; + Loop; + Select: + MAUL I 1 A_Raise; + Loop; + Fire: + MAUL I 20 A_FireMauler2Pre; + MAUL J 10 A_Light1; + BLSF A 10 Bright A_FireMauler2; + MAUL B 10 Bright A_Light2; + MAUL C 2; + MAUL D 2 A_Light0; + MAUL E 2 A_ReFire; + Goto Ready; + } + + //============================================================================ + // + // A_FireMauler2Pre + // + // Makes some noise and moves the psprite. + // + //============================================================================ + + action void A_FireMauler2Pre () + { + A_PlaySound ("weapons/mauler2charge", CHAN_WEAPON); + + if (player != null) + { + PSprite psp = player.GetPSprite(PSP_WEAPON); + psp.x += Random2[Mauler2]() / 64.; + psp.y += Random2[Mauler2]() / 64.; + } + } + + //============================================================================ + // + // A_FireMauler2Pre + // + // Fires the torpedo. + // + //============================================================================ + + action void A_FireMauler2 () + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + player.mo.PlayAttacking2 (); + + SpawnPlayerMissile ("MaulerTorpedo"); + DamageMobj (self, null, 20, 'Disintegrate'); + Thrust(7.8125, Angle+180.); + } +} + + +// Mauler "Bullet" Puff ----------------------------------------------------- + +class MaulerPuff : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + +PUFFONACTORS + RenderStyle "Add"; + DamageType "Disintegrate"; + } + States + { + Spawn: + MPUF AB 5; + POW1 ABCDE 4; + Stop; + } +} + +// The Mauler's Torpedo ----------------------------------------------------- + +class MaulerTorpedo : Actor +{ + Default + { + Speed 20; + Height 8; + Radius 13; + Damage 1; + DamageType "Disintegrate"; + Projectile; + +STRIFEDAMAGE + MaxStepHeight 4; + RenderStyle "Add"; + SeeSound "weapons/mauler2fire"; + DeathSound "weapons/mauler2hit"; + Obituary "$OB_MPMAULER"; + } + + States + { + Spawn: + TORP ABCD 4 Bright; + Loop; + Death: + THIT AB 8 Bright; + THIT C 8 Bright A_MaulerTorpedoWave; + THIT DE 8 Bright; + Stop; + } + + //============================================================================ + // + // A_MaulerTorpedoWave + // + // Launches lots of balls when the torpedo hits something. + // + //============================================================================ + + action void A_MaulerTorpedoWave() + { + readonly wavedef = GetDefaultByType("MaulerTorpedoWave"); + double savedz = pos.z; + angle += 180.; + + // If the torpedo hit the ceiling, it should still spawn the wave + if (wavedef && ceilingz < pos.z + wavedef.Height) + { + SetZ(ceilingz - wavedef.Height); + } + + for (int i = 0; i < 80; ++i) + { + Angle += 4.5; + SpawnSubMissile ("MaulerTorpedoWave", target); + } + SetZ(savedz); + } +} + + +// The mini torpedoes shot by the big torpedo -------------------------------- + +class MaulerTorpedoWave : Actor +{ + Default + { + Speed 35; + Radius 13; + Height 13; + Damage 10; + DamageType "Disintegrate"; + Projectile; + +STRIFEDAMAGE + MaxStepHeight 4; + RenderStyle "Add"; + Obituary "$OB_MPMAULER"; + } + States + { + Spawn: + TWAV AB 9 Bright; + Death: + TWAV C 9 Bright; + Stop; + } + +} + + diff --git a/wadsrc/static/zscript/strife/weaponmissile.txt b/wadsrc/static/zscript/strife/weaponmissile.txt new file mode 100644 index 0000000000..589f754939 --- /dev/null +++ b/wadsrc/static/zscript/strife/weaponmissile.txt @@ -0,0 +1,137 @@ +// Mini-Missile Launcher ---------------------------------------------------- + +class MiniMissileLauncher : StrifeWeapon +{ + Default + { + +FLOORCLIP + Weapon.SelectionOrder 1800; + Weapon.AmmoUse1 1; + Weapon.AmmoGive1 8; + Weapon.AmmoType1 "MiniMissiles"; + Inventory.Icon "MMSLA0"; + Tag "$TAG_MMLAUNCHER"; + Inventory.PickupMessage "$TXT_MMLAUNCHER"; + } + + States + { + Spawn: + MMSL A -1; + Stop; + Ready: + MMIS A 1 A_WeaponReady; + Loop; + Deselect: + MMIS A 1 A_Lower; + Loop; + Select: + MMIS A 1 A_Raise; + Loop; + Fire: + MMIS A 4 A_FireMiniMissile; + MMIS B 4 A_Light1; + MMIS C 5 Bright; + MMIS D 2 Bright A_Light2; + MMIS E 2 Bright; + MMIS F 2 Bright A_Light0; + MMIS F 0 A_ReFire; + Goto Ready; + } + + //============================================================================ + // + // A_FireMiniMissile + // + //============================================================================ + + action void A_FireMiniMissile () + { + if (player == null) + { + return; + } + + Weapon weapon = player.ReadyWeapon; + if (weapon != null) + { + if (!weapon.DepleteAmmo (weapon.bAltFire)) + return; + } + + double savedangle = angle; + angle += Random2[MiniMissile]() * (11.25 / 256) * AccuracyFactor(); + player.mo.PlayAttacking2 (); + SpawnPlayerMissile ("MiniMissile"); + angle = savedangle; + } +} + + +// Rocket Trail ------------------------------------------------------------- + +class RocketTrail : Actor +{ + Default + { + +NOBLOCKMAP + +NOGRAVITY + RenderStyle "Translucent"; + Alpha 0.25; + SeeSound "misc/missileinflight"; + } + States + { + Spawn: + PUFY BCBCD 4; + Stop; + } +} + +// Rocket Puff -------------------------------------------------------------- + +class MiniMissilePuff : StrifePuff +{ + Default + { + -ALLOWPARTICLES + } + States + { + Spawn: + Goto Crash; + } +} + +// Mini Missile ------------------------------------------------------------- + +class MiniMissile : Actor +{ + Default + { + Speed 20; + Radius 10; + Height 14; + Damage 10; + Projectile; + +STRIFEDAMAGE + MaxStepHeight 4; + SeeSound "weapons/minimissile"; + DeathSound "weapons/minimissilehit"; + Obituary "$OB_MPMINIMISSILELAUNCHER"; + } + States + { + Spawn: + MICR A 6 Bright A_RocketInFlight; + Loop; + Death: + SMIS A 0 Bright A_SetRenderStyle(1, STYLE_Normal); + SMIS A 5 Bright A_Explode(64, 64, alert:true); + SMIS B 5 Bright; + SMIS C 4 Bright; + SMIS DEFG 2 Bright; + Stop; + } +} + diff --git a/wadsrc/static/zscript/strife/zombie.txt b/wadsrc/static/zscript/strife/zombie.txt new file mode 100644 index 0000000000..c7a7cea593 --- /dev/null +++ b/wadsrc/static/zscript/strife/zombie.txt @@ -0,0 +1,64 @@ + +// Zombie ------------------------------------------------------------------- + +class Zombie : StrifeHumanoid +{ + Default + { + Health 31; + Radius 20; + Height 56; + PainChance 0; + +SOLID + +SHOOTABLE + +FLOORCLIP + +CANPASS + +CANPUSHWALLS + +ACTIVATEMCROSS + MinMissileChance 150; + MaxStepHeight 16; + MaxDropOffHeight 32; + Translation 0; + DeathSound "zombie/death"; + CrushPainSound "misc/pcrush"; + } + States + { + Spawn: + PEAS A 5 A_CheckTerrain; + Loop; + Pain: + AGRD A 5 A_CheckTerrain; + Loop; + Death: + GIBS M 5 A_TossGib; + GIBS N 5 A_XScream; + GIBS O 5 A_NoBlocking; + GIBS PQRST 4 A_TossGib; + GIBS U 5; + GIBS V -1; + Stop; + } +} + + +// Zombie Spawner ----------------------------------------------------------- + +class ZombieSpawner : Actor +{ + Default + { + Health 20; + +SHOOTABLE + +NOSECTOR + RenderStyle "None"; + ActiveSound "zombie/spawner"; // Does Strife use this somewhere else? + } + States + { + Spawn: + TNT1 A 175 A_SpawnItemEx("Zombie"); + Loop; + } +} +