Merge branch 'repeat-monitors' into 'master'

Monitor reworking + infinite repeat use 'gold' monitors

All the monitor sprites, states, and objects are completely changed to be simpler. 'Gold' repeat use monitors are also introduced.

I'm gonna be keeping my playtest EXEs in !LSF from now on.

See merge request !20
This commit is contained in:
Inuyasha 2016-09-29 22:40:52 -04:00
commit 7997753d24
12 changed files with 2002 additions and 1471 deletions

View File

@ -1659,6 +1659,9 @@ static actionpointer_t actionpointers[] =
{{A_Pain}, "A_PAIN"},
{{A_Fall}, "A_FALL"},
{{A_MonitorPop}, "A_MONITORPOP"},
{{A_GoldMonitorPop}, "A_GOLDMONITORPOP"},
{{A_GoldMonitorRestore}, "A_GOLDMONITORRESTORE"},
{{A_GoldMonitorSparkle}, "A_GOLDMONITORSPARKLE"},
{{A_Look}, "A_LOOK"},
{{A_Chase}, "A_CHASE"},
{{A_FaceStabChase}, "A_FACESTABCHASE"},
@ -4869,170 +4872,114 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_CANNONLAUNCHER2",
"S_CANNONLAUNCHER3",
// Super Ring Box
"S_SUPERRINGBOX",
"S_SUPERRINGBOX1",
"S_SUPERRINGBOX2",
"S_SUPERRINGBOX3",
"S_SUPERRINGBOX4",
"S_SUPERRINGBOX5",
"S_SUPERRINGBOX6",
// Monitor Miscellany
"S_BOXSPARKLE1",
"S_BOXSPARKLE2",
"S_BOXSPARKLE3",
// Red Team Ring Box
"S_REDRINGBOX",
"S_REDRINGBOX1",
"S_BOX_FLICKER",
"S_BOX_POP1",
"S_BOX_POP2",
// Blue Team Ring Box
"S_BLUERINGBOX",
"S_BLUERINGBOX1",
"S_GOLDBOX_FLICKER",
"S_GOLDBOX_OFF1",
"S_GOLDBOX_OFF2",
"S_GOLDBOX_OFF3",
"S_GOLDBOX_OFF4",
"S_GOLDBOX_OFF5",
"S_GOLDBOX_OFF6",
"S_GOLDBOX_OFF7",
// Super Sneakers Box
"S_SHTV",
"S_SHTV1",
"S_SHTV2",
"S_SHTV3",
"S_SHTV4",
"S_SHTV5",
"S_SHTV6",
// Monitor States (one per box)
"S_MYSTERY_BOX",
"S_RING_BOX",
"S_PITY_BOX",
"S_ATTRACT_BOX",
"S_FORCE_BOX",
"S_ARMAGEDDON_BOX",
"S_WHIRLWIND_BOX",
"S_ELEMENTAL_BOX",
"S_SNEAKERS_BOX",
"S_INVULN_BOX",
"S_1UP_BOX",
"S_EGGMAN_BOX",
"S_MIXUP_BOX",
"S_GRAVITY_BOX",
"S_RECYCLER_BOX",
"S_SCORE1K_BOX",
"S_SCORE10K_BOX",
// Invincibility Box
"S_PINV",
"S_PINV1",
"S_PINV2",
"S_PINV3",
"S_PINV4",
"S_PINV5",
"S_PINV6",
// Gold Repeat Monitor States (one per box)
"S_PITY_GOLDBOX",
"S_ATTRACT_GOLDBOX",
"S_FORCE_GOLDBOX",
"S_ARMAGEDDON_GOLDBOX",
"S_WHIRLWIND_GOLDBOX",
"S_ELEMENTAL_GOLDBOX",
"S_SNEAKERS_GOLDBOX",
"S_INVULN_GOLDBOX",
"S_EGGMAN_GOLDBOX",
"S_GRAVITY_GOLDBOX",
// 1-Up Box
"S_PRUP",
"S_PRUP1",
"S_PRUP2",
"S_PRUP3",
"S_PRUP4",
"S_PRUP5",
"S_PRUP6",
// Team Ring Boxes (these are special)
"S_RING_REDBOX1",
"S_RING_REDBOX2",
"S_REDBOX_POP1",
"S_REDBOX_POP2",
// Ring Shield Box
"S_YLTV",
"S_YLTV1",
"S_YLTV2",
"S_YLTV3",
"S_YLTV4",
"S_YLTV5",
"S_YLTV6",
"S_RING_BLUEBOX1",
"S_RING_BLUEBOX2",
"S_BLUEBOX_POP1",
"S_BLUEBOX_POP2",
// Force Shield Box
"S_BLTV1",
"S_BLTV2",
"S_BLTV3",
"S_BLTV4",
"S_BLTV5",
"S_BLTV6",
"S_BLTV7",
// Box Icons -- 2 states each, animation and action
"S_RING_ICON1",
"S_RING_ICON2",
// Bomb Shield Box
"S_BKTV1",
"S_BKTV2",
"S_BKTV3",
"S_BKTV4",
"S_BKTV5",
"S_BKTV6",
"S_BKTV7",
"S_PITY_ICON1",
"S_PITY_ICON2",
// Jump Shield Box
"S_WHTV1",
"S_WHTV2",
"S_WHTV3",
"S_WHTV4",
"S_WHTV5",
"S_WHTV6",
"S_WHTV7",
"S_ATTRACT_ICON1",
"S_ATTRACT_ICON2",
// Water Shield Box
"S_GRTV",
"S_GRTV1",
"S_GRTV2",
"S_GRTV3",
"S_GRTV4",
"S_GRTV5",
"S_GRTV6",
"S_FORCE_ICON1",
"S_FORCE_ICON2",
// Pity Shield Box
"S_PITV1",
"S_PITV2",
"S_PITV3",
"S_PITV4",
"S_PITV5",
"S_PITV6",
"S_PITV7",
"S_ARMAGEDDON_ICON1",
"S_ARMAGEDDON_ICON2",
// Eggman Box
"S_EGGTV1",
"S_EGGTV2",
"S_EGGTV3",
"S_EGGTV4",
"S_EGGTV5",
"S_EGGTV6",
"S_EGGTV7",
"S_WHIRLWIND_ICON1",
"S_WHIRLWIND_ICON2",
// Teleport Box
"S_MIXUPBOX1",
"S_MIXUPBOX2",
"S_MIXUPBOX3",
"S_MIXUPBOX4",
"S_MIXUPBOX5",
"S_MIXUPBOX6",
"S_MIXUPBOX7",
"S_ELEMENTAL_ICON1",
"S_ELEMENTAL_ICON2",
// Recycler Box
"S_RECYCLETV1",
"S_RECYCLETV2",
"S_RECYCLETV3",
"S_RECYCLETV4",
"S_RECYCLETV5",
"S_RECYCLETV6",
"S_RECYCLETV7",
"S_SNEAKERS_ICON1",
"S_SNEAKERS_ICON2",
// Question Box
"S_RANDOMBOX1",
"S_RANDOMBOX2",
"S_RANDOMBOX3",
"S_INVULN_ICON1",
"S_INVULN_ICON2",
// Gravity Boots Box
"S_GBTV1",
"S_GBTV2",
"S_GBTV3",
"S_GBTV4",
"S_GBTV5",
"S_GBTV6",
"S_GBTV7",
"S_1UP_ICON1",
"S_1UP_ICON2",
// Score boxes
"S_SCORETVA1",
"S_SCORETVA2",
"S_SCORETVA3",
"S_SCORETVA4",
"S_SCORETVA5",
"S_SCORETVA6",
"S_SCORETVA7",
"S_SCORETVB1",
"S_SCORETVB2",
"S_SCORETVB3",
"S_SCORETVB4",
"S_SCORETVB5",
"S_SCORETVB6",
"S_SCORETVB7",
"S_EGGMAN_ICON1",
"S_EGGMAN_ICON2",
// Monitor Explosion
"S_MONITOREXPLOSION1",
"S_MONITOREXPLOSION2",
"S_MIXUP_ICON1",
"S_MIXUP_ICON2",
"S_REDMONITOREXPLOSION1",
"S_REDMONITOREXPLOSION2",
"S_GRAVITY_ICON1",
"S_GRAVITY_ICON2",
"S_BLUEMONITOREXPLOSION1",
"S_BLUEMONITOREXPLOSION2",
"S_RECYCLER_ICON1",
"S_RECYCLER_ICON2",
"S_SCORE1K_ICON1",
"S_SCORE1K_ICON2",
"S_SCORE10K_ICON1",
"S_SCORE10K_ICON2",
"S_ROCKET",
@ -6260,47 +6207,61 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_BIGAIRMINE",
"MT_CANNONLAUNCHER",
// Monitor Boxes
"MT_SUPERRINGBOX",
"MT_REDRINGBOX",
"MT_BLUERINGBOX",
"MT_SNEAKERTV",
"MT_INV",
"MT_PRUP", // 1up Box
"MT_YELLOWTV", // Attract shield TV
"MT_BLUETV", // Force shield TV
"MT_BLACKTV", // Bomb shield TV
"MT_WHITETV", // Jump shield TV
"MT_GREENTV", // Elemental shield TV
"MT_PITYTV", // Pity shield TV
"MT_EGGMANBOX",
"MT_MIXUPBOX",
"MT_RECYCLETV",
"MT_RECYCLEICO",
"MT_QUESTIONBOX",
"MT_GRAVITYBOX",
"MT_SCORETVSMALL",
"MT_SCORETVLARGE",
// Monitor miscellany
"MT_MONITOREXPLOSION",
"MT_REDMONITOREXPLOSION",
"MT_BLUEMONITOREXPLOSION",
"MT_RINGICO",
"MT_SHOESICO",
"MT_INVCICO",
"MT_1UPICO",
"MT_YSHIELDICO",
"MT_BSHIELDICO",
"MT_KSHIELDICO",
"MT_WSHIELDICO",
"MT_GSHIELDICO",
"MT_PITYSHIELDICO",
"MT_EGGMANICO",
"MT_MIXUPICO",
"MT_GRAVITYICO",
"MT_SCOREICOSMALL",
"MT_SCOREICOLARGE",
"MT_BOXSPARKLE",
// Monitor boxes -- regular
"MT_RING_BOX",
"MT_PITY_BOX",
"MT_ATTRACT_BOX",
"MT_FORCE_BOX",
"MT_ARMAGEDDON_BOX",
"MT_WHIRLWIND_BOX",
"MT_ELEMENTAL_BOX",
"MT_SNEAKERS_BOX",
"MT_INVULN_BOX",
"MT_1UP_BOX",
"MT_EGGMAN_BOX",
"MT_MIXUP_BOX",
"MT_MYSTERY_BOX",
"MT_GRAVITY_BOX",
"MT_RECYCLER_BOX",
"MT_SCORE1K_BOX",
"MT_SCORE10K_BOX",
// Monitor boxes -- repeating (big) boxes
"MT_PITY_GOLDBOX",
"MT_ATTRACT_GOLDBOX",
"MT_FORCE_GOLDBOX",
"MT_ARMAGEDDON_GOLDBOX",
"MT_WHIRLWIND_GOLDBOX",
"MT_ELEMENTAL_GOLDBOX",
"MT_SNEAKERS_GOLDBOX",
"MT_INVULN_GOLDBOX",
"MT_EGGMAN_GOLDBOX",
"MT_GRAVITY_GOLDBOX",
// Monitor boxes -- special
"MT_RING_REDBOX",
"MT_RING_BLUEBOX",
// Monitor icons
"MT_RING_ICON",
"MT_PITY_ICON",
"MT_ATTRACT_ICON",
"MT_FORCE_ICON",
"MT_ARMAGEDDON_ICON",
"MT_WHIRLWIND_ICON",
"MT_ELEMENTAL_ICON",
"MT_SNEAKERS_ICON",
"MT_INVULN_ICON",
"MT_1UP_ICON",
"MT_EGGMAN_ICON",
"MT_MIXUP_ICON",
"MT_GRAVITY_ICON",
"MT_RECYCLER_ICON",
"MT_SCORE1K_ICON",
"MT_SCORE10K_ICON",
// Projectiles
"MT_ROCKET",

View File

@ -247,27 +247,30 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_BMNE
// Monitor Boxes
&lspr[NOLIGHT], // SPR_SRBX
&lspr[NOLIGHT], // SPR_RRBX
&lspr[NOLIGHT], // SPR_BRBX
&lspr[NOLIGHT], // SPR_SHTV
&lspr[NOLIGHT], // SPR_PINV
&lspr[NOLIGHT], // SPR_YLTV
&lspr[NOLIGHT], // SPR_BLTV
&lspr[NOLIGHT], // SPR_BKTV
&lspr[NOLIGHT], // SPR_WHTV
&lspr[NOLIGHT], // SPR_GRTV
&lspr[NOLIGHT], // SPR_ELTV
&lspr[NOLIGHT], // SPR_EGGB
&lspr[NOLIGHT], // SPR_MIXU
&lspr[NOLIGHT], // SPR_RECY
&lspr[NOLIGHT], // SPR_QUES
&lspr[NOLIGHT], // SPR_GBTV
&lspr[NOLIGHT], // SPR_PRUP
&lspr[NOLIGHT], // SPR_PTTV
&lspr[NOLIGHT], // SPR_MSTV
&lspr[NOLIGHT], // SPR_XLTV
// Monitor Miscellany
&lspr[NOLIGHT], // SPR_MTEX
&lspr[NOLIGHT], // SPR_TRRI
&lspr[NOLIGHT], // SPR_TBRI
&lspr[NOLIGHT], // SPR_TVRI
&lspr[NOLIGHT], // SPR_TVPI
&lspr[NOLIGHT], // SPR_TVAT
&lspr[NOLIGHT], // SPR_TVFO
&lspr[NOLIGHT], // SPR_TVAR
&lspr[NOLIGHT], // SPR_TVWW
&lspr[NOLIGHT], // SPR_TVEL
&lspr[NOLIGHT], // SPR_TVSS
&lspr[NOLIGHT], // SPR_TVIV
&lspr[NOLIGHT], // SPR_TV1U
&lspr[NOLIGHT], // SPR_TV1P
&lspr[NOLIGHT], // SPR_TVEG
&lspr[NOLIGHT], // SPR_TVMX
&lspr[NOLIGHT], // SPR_TVMY
&lspr[NOLIGHT], // SPR_TVGV
&lspr[NOLIGHT], // SPR_TVRC
&lspr[NOLIGHT], // SPR_TV1K
&lspr[NOLIGHT], // SPR_TVTK
// Projectiles
&lspr[NOLIGHT], // SPR_MISL

2153
src/info.c

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,9 @@ void A_Explode();
void A_Pain();
void A_Fall();
void A_MonitorPop();
void A_GoldMonitorPop();
void A_GoldMonitorRestore();
void A_GoldMonitorSparkle();
void A_Look();
void A_Chase();
void A_FaceStabChase();
@ -324,27 +327,30 @@ typedef enum sprite
SPR_BMNE, // Big floating mine
// Monitor Boxes
SPR_SRBX,
SPR_RRBX,
SPR_BRBX,
SPR_SHTV,
SPR_PINV,
SPR_YLTV,
SPR_BLTV, // Force shield
SPR_BKTV, // Bomb shield TV
SPR_WHTV, // Jump shield TV
SPR_GRTV, // Pity shield TV
SPR_ELTV, // Elemental shield TV
SPR_EGGB, // Eggman box
SPR_MIXU, // Player mixing monitor
SPR_RECY, // Recycler (power mixing) monitor
SPR_QUES, // Random monitor
SPR_GBTV, // Gravity boots TV
SPR_PRUP, // 1up
SPR_PTTV, // Score TVs
SPR_MSTV, // MiSc TV sprites
SPR_XLTV, // eXtra Large TV sprites
// Monitor Miscellany
SPR_MTEX, // Exploding monitor
SPR_TRRI, // Red team: 10 RIngs
SPR_TBRI, // Blue team: 10 RIngs
SPR_TVRI, // 10 RIng
SPR_TVPI, // PIty shield
SPR_TVAT, // ATtraction shield
SPR_TVFO, // FOrce shield
SPR_TVAR, // ARmageddon shield
SPR_TVWW, // WhirlWind shield
SPR_TVEL, // ELemental shield
SPR_TVSS, // Super Sneakers
SPR_TVIV, // InVincibility
SPR_TV1U, // 1Up
SPR_TV1P, // 1uP (textless)
SPR_TVEG, // EGgman
SPR_TVMX, // MiXup
SPR_TVMY, // MYstery
SPR_TVGV, // GraVity boots
SPR_TVRC, // ReCycler
SPR_TV1K, // 1,000 points (1 K)
SPR_TVTK, // 10,000 points (Ten K)
// Projectiles
SPR_MISL,
@ -1772,170 +1778,116 @@ typedef enum state
S_CANNONLAUNCHER2,
S_CANNONLAUNCHER3,
// Super Ring Box
S_SUPERRINGBOX,
S_SUPERRINGBOX1,
S_SUPERRINGBOX2,
S_SUPERRINGBOX3,
S_SUPERRINGBOX4,
S_SUPERRINGBOX5,
S_SUPERRINGBOX6,
// Monitor Miscellany
S_BOXSPARKLE1,
S_BOXSPARKLE2,
S_BOXSPARKLE3,
// Red Team Ring Box
S_REDRINGBOX,
S_REDRINGBOX1,
S_BOX_FLICKER,
S_BOX_POP1,
S_BOX_POP2,
// Blue Team Ring Box
S_BLUERINGBOX,
S_BLUERINGBOX1,
S_GOLDBOX_FLICKER,
S_GOLDBOX_OFF1,
S_GOLDBOX_OFF2,
S_GOLDBOX_OFF3,
S_GOLDBOX_OFF4,
S_GOLDBOX_OFF5,
S_GOLDBOX_OFF6,
S_GOLDBOX_OFF7,
// Super Sneakers Box
S_SHTV,
S_SHTV1,
S_SHTV2,
S_SHTV3,
S_SHTV4,
S_SHTV5,
S_SHTV6,
// Monitor States (one per box)
S_MYSTERY_BOX,
S_RING_BOX,
S_PITY_BOX,
S_ATTRACT_BOX,
S_FORCE_BOX,
S_ARMAGEDDON_BOX,
S_WHIRLWIND_BOX,
S_ELEMENTAL_BOX,
S_SNEAKERS_BOX,
S_INVULN_BOX,
S_1UP_BOX,
S_EGGMAN_BOX,
S_MIXUP_BOX,
S_GRAVITY_BOX,
S_RECYCLER_BOX,
S_SCORE1K_BOX,
S_SCORE10K_BOX,
// Invincibility Box
S_PINV,
S_PINV1,
S_PINV2,
S_PINV3,
S_PINV4,
S_PINV5,
S_PINV6,
// Gold Repeat Monitor States (one per box)
S_PITY_GOLDBOX,
S_ATTRACT_GOLDBOX,
S_FORCE_GOLDBOX,
S_ARMAGEDDON_GOLDBOX,
S_WHIRLWIND_GOLDBOX,
S_ELEMENTAL_GOLDBOX,
S_SNEAKERS_GOLDBOX,
S_INVULN_GOLDBOX,
S_EGGMAN_GOLDBOX,
S_GRAVITY_GOLDBOX,
// 1up Box
S_PRUP,
S_PRUP1,
S_PRUP2,
S_PRUP3,
S_PRUP4,
S_PRUP5,
S_PRUP6,
// Team Ring Boxes (these are special)
S_RING_REDBOX1,
S_RING_REDBOX2,
S_REDBOX_POP1,
S_REDBOX_POP2,
// Ring Shield Box
S_YLTV,
S_YLTV1,
S_YLTV2,
S_YLTV3,
S_YLTV4,
S_YLTV5,
S_YLTV6,
S_RING_BLUEBOX1,
S_RING_BLUEBOX2,
S_BLUEBOX_POP1,
S_BLUEBOX_POP2,
// Force Shield Box
S_BLTV1,
S_BLTV2,
S_BLTV3,
S_BLTV4,
S_BLTV5,
S_BLTV6,
S_BLTV7,
// Box Icons -- 2 states each, animation and action
S_RING_ICON1,
S_RING_ICON2,
// Bomb Shield Box
S_BKTV1,
S_BKTV2,
S_BKTV3,
S_BKTV4,
S_BKTV5,
S_BKTV6,
S_BKTV7,
S_PITY_ICON1,
S_PITY_ICON2,
// Jump Shield Box
S_WHTV1,
S_WHTV2,
S_WHTV3,
S_WHTV4,
S_WHTV5,
S_WHTV6,
S_WHTV7,
S_ATTRACT_ICON1,
S_ATTRACT_ICON2,
// Water Shield Box
S_GRTV,
S_GRTV1,
S_GRTV2,
S_GRTV3,
S_GRTV4,
S_GRTV5,
S_GRTV6,
S_FORCE_ICON1,
S_FORCE_ICON2,
// Pity Shield Box
S_PITV1,
S_PITV2,
S_PITV3,
S_PITV4,
S_PITV5,
S_PITV6,
S_PITV7,
S_ARMAGEDDON_ICON1,
S_ARMAGEDDON_ICON2,
// Eggman Box
S_EGGTV1,
S_EGGTV2,
S_EGGTV3,
S_EGGTV4,
S_EGGTV5,
S_EGGTV6,
S_EGGTV7,
S_WHIRLWIND_ICON1,
S_WHIRLWIND_ICON2,
// Teleport Box
S_MIXUPBOX1,
S_MIXUPBOX2,
S_MIXUPBOX3,
S_MIXUPBOX4,
S_MIXUPBOX5,
S_MIXUPBOX6,
S_MIXUPBOX7,
S_ELEMENTAL_ICON1,
S_ELEMENTAL_ICON2,
// Recycler Box
S_RECYCLETV1,
S_RECYCLETV2,
S_RECYCLETV3,
S_RECYCLETV4,
S_RECYCLETV5,
S_RECYCLETV6,
S_RECYCLETV7,
S_SNEAKERS_ICON1,
S_SNEAKERS_ICON2,
// Question Box
S_RANDOMBOX1,
S_RANDOMBOX2,
S_RANDOMBOX3,
S_INVULN_ICON1,
S_INVULN_ICON2,
// Gravity Boots Box
S_GBTV1,
S_GBTV2,
S_GBTV3,
S_GBTV4,
S_GBTV5,
S_GBTV6,
S_GBTV7,
S_1UP_ICON1,
S_1UP_ICON2,
// Score boxes
S_SCORETVA1,
S_SCORETVA2,
S_SCORETVA3,
S_SCORETVA4,
S_SCORETVA5,
S_SCORETVA6,
S_SCORETVA7,
S_SCORETVB1,
S_SCORETVB2,
S_SCORETVB3,
S_SCORETVB4,
S_SCORETVB5,
S_SCORETVB6,
S_SCORETVB7,
S_EGGMAN_ICON1,
S_EGGMAN_ICON2,
// Monitor Explosion
S_MONITOREXPLOSION1,
S_MONITOREXPLOSION2,
S_MIXUP_ICON1,
S_MIXUP_ICON2,
S_REDMONITOREXPLOSION1,
S_REDMONITOREXPLOSION2,
S_GRAVITY_ICON1,
S_GRAVITY_ICON2,
S_BLUEMONITOREXPLOSION1,
S_BLUEMONITOREXPLOSION2,
S_RECYCLER_ICON1,
S_RECYCLER_ICON2,
S_SCORE1K_ICON1,
S_SCORE1K_ICON2,
S_SCORE10K_ICON1,
S_SCORE10K_ICON2,
// ---
S_ROCKET,
@ -3182,47 +3134,61 @@ typedef enum mobj_type
MT_BIGAIRMINE,
MT_CANNONLAUNCHER,
// Monitor Boxes
MT_SUPERRINGBOX,
MT_REDRINGBOX,
MT_BLUERINGBOX,
MT_SNEAKERTV,
MT_INV,
MT_PRUP, // 1up Box
MT_YELLOWTV,
MT_BLUETV,
MT_BLACKTV, // Bomb shield TV
MT_WHITETV, // Jump shield TV
MT_GREENTV,
MT_PITYTV, // Pity Shield TV
MT_EGGMANBOX,
MT_MIXUPBOX,
MT_RECYCLETV,
MT_RECYCLEICO,
MT_QUESTIONBOX,
MT_GRAVITYBOX,
MT_SCORETVSMALL,
MT_SCORETVLARGE,
// Monitor miscellany
MT_MONITOREXPLOSION,
MT_REDMONITOREXPLOSION,
MT_BLUEMONITOREXPLOSION,
MT_RINGICO,
MT_SHOESICO,
MT_INVCICO,
MT_1UPICO,
MT_YSHIELDICO,
MT_BSHIELDICO,
MT_KSHIELDICO,
MT_WSHIELDICO,
MT_GSHIELDICO,
MT_PITYSHIELDICO,
MT_EGGMANICO,
MT_MIXUPICO,
MT_GRAVITYICO,
MT_SCOREICOSMALL,
MT_SCOREICOLARGE,
MT_BOXSPARKLE,
// Monitor boxes -- regular
MT_RING_BOX,
MT_PITY_BOX,
MT_ATTRACT_BOX,
MT_FORCE_BOX,
MT_ARMAGEDDON_BOX,
MT_WHIRLWIND_BOX,
MT_ELEMENTAL_BOX,
MT_SNEAKERS_BOX,
MT_INVULN_BOX,
MT_1UP_BOX,
MT_EGGMAN_BOX,
MT_MIXUP_BOX,
MT_MYSTERY_BOX,
MT_GRAVITY_BOX,
MT_RECYCLER_BOX,
MT_SCORE1K_BOX,
MT_SCORE10K_BOX,
// Monitor boxes -- repeating (big) boxes
MT_PITY_GOLDBOX,
MT_ATTRACT_GOLDBOX,
MT_FORCE_GOLDBOX,
MT_ARMAGEDDON_GOLDBOX,
MT_WHIRLWIND_GOLDBOX,
MT_ELEMENTAL_GOLDBOX,
MT_SNEAKERS_GOLDBOX,
MT_INVULN_GOLDBOX,
MT_EGGMAN_GOLDBOX,
MT_GRAVITY_GOLDBOX,
// Monitor boxes -- special
MT_RING_REDBOX,
MT_RING_BLUEBOX,
// Monitor icons
MT_RING_ICON,
MT_PITY_ICON,
MT_ATTRACT_ICON,
MT_FORCE_ICON,
MT_ARMAGEDDON_ICON,
MT_WHIRLWIND_ICON,
MT_ELEMENTAL_ICON,
MT_SNEAKERS_ICON,
MT_INVULN_ICON,
MT_1UP_ICON,
MT_EGGMAN_ICON,
MT_MIXUP_ICON,
MT_GRAVITY_ICON,
MT_RECYCLER_ICON,
MT_SCORE1K_ICON,
MT_SCORE10K_ICON,
// Projectiles
MT_ROCKET,

View File

@ -818,6 +818,32 @@ static int P_RecycleCompare(const void *p1, const void *p2)
}
#endif
// Handles random monitor weights via console.
static mobjtype_t P_DoRandomBoxChances(void)
{
mobjtype_t spawnchance[256];
INT32 numchoices = 0, i = 0;
#define QUESTIONBOXCHANCES(type, cvar) \
for (i = cvar.value; i; --i) spawnchance[numchoices++] = type
QUESTIONBOXCHANCES(MT_RING_ICON, cv_superring);
QUESTIONBOXCHANCES(MT_SNEAKERS_ICON, cv_supersneakers);
QUESTIONBOXCHANCES(MT_INVULN_ICON, cv_invincibility);
QUESTIONBOXCHANCES(MT_WHIRLWIND_ICON, cv_jumpshield);
QUESTIONBOXCHANCES(MT_ELEMENTAL_ICON, cv_watershield);
QUESTIONBOXCHANCES(MT_ATTRACT_ICON, cv_ringshield);
QUESTIONBOXCHANCES(MT_FORCE_ICON, cv_forceshield);
QUESTIONBOXCHANCES(MT_ARMAGEDDON_ICON, cv_bombshield);
QUESTIONBOXCHANCES(MT_1UP_ICON, cv_1up);
QUESTIONBOXCHANCES(MT_EGGMAN_ICON, cv_eggmanbox);
QUESTIONBOXCHANCES(MT_MIXUP_ICON, cv_teleporters);
QUESTIONBOXCHANCES(MT_RECYCLER_ICON, cv_recycler);
#undef QUESTIONBOXCHANCES
if (numchoices == 0) return MT_NULL;
return spawnchance[P_RandomKey(numchoices)];
}
//
// ACTION ROUTINES
//
@ -2510,7 +2536,6 @@ void A_1upThinker(mobj_t *actor)
if (closestplayer == -1 || skins[players[closestplayer].skin].sprites[SPR2_LIFE].numframes == 0)
{ // Closest player not found (no players in game?? may be empty dedicated server!), or does not have correct sprite.
actor->frame = 0;
if (actor->tracer) {
P_RemoveMobj(actor->tracer);
actor->tracer = NULL;
@ -2518,11 +2543,19 @@ void A_1upThinker(mobj_t *actor)
return;
}
// We're using the overlay, so use the overlay 1up box (no text)
actor->sprite = SPR_TV1P;
if (!actor->tracer)
{
P_SetTarget(&actor->tracer, P_SpawnMobj(actor->x, actor->y, actor->z, MT_OVERLAY));
P_SetTarget(&actor->tracer->target, actor);
P_SetMobjState(actor->tracer, actor->info->seestate);
// The overlay is going to be one tic early turning off and on
// because it's going to get its thinker run the frame we spawned it.
// So make it take one tic longer if it just spawned.
++actor->tracer->tics;
}
actor->tracer->color = players[closestplayer].mo->color;
@ -2538,139 +2571,200 @@ void A_1upThinker(mobj_t *actor)
//
void A_MonitorPop(mobj_t *actor)
{
mobj_t *remains;
mobjtype_t explode;
mobjtype_t item = 0;
mobjtype_t newbox;
mobj_t *newmobj;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_MonitorPop", actor))
return;
#endif
// de-solidify
// Spawn the "pop" explosion.
if (actor->info->deathsound)
S_StartSound(actor, actor->info->deathsound);
P_SpawnMobjFromMobj(actor, 0, 0, actor->height/4, MT_EXPLODE);
// We're dead now. De-solidify.
actor->health = 0;
P_UnsetThingPosition(actor);
actor->flags &= ~MF_SOLID;
actor->flags |= MF_NOCLIP;
P_SetThingPosition(actor);
// Monitor explosion
explode = mobjinfo[actor->info->speed].mass;
remains = P_SpawnMobj(actor->x, actor->y,
((actor->eflags & MFE_VERTICALFLIP) ? (actor->z + 3*(actor->height/4) - FixedMul(mobjinfo[explode].height, actor->scale)) : (actor->z + actor->height/4)), explode);
if (actor->eflags & MFE_VERTICALFLIP)
if (actor->info->damage == MT_UNKNOWN)
{
remains->eflags |= MFE_VERTICALFLIP;
remains->flags2 |= MF2_OBJECTFLIP;
}
remains->destscale = actor->destscale;
P_SetScale(remains, actor->scale);
// MT_UNKNOWN is random. Because it's unknown to us... get it?
item = P_DoRandomBoxChances();
remains = P_SpawnMobj(actor->x, actor->y,
((actor->eflags & MFE_VERTICALFLIP) ? (actor->z + actor->height - FixedMul(mobjinfo[actor->info->speed].height, actor->scale)) : actor->z),
actor->info->speed);
remains->type = actor->type; // Transfer type information
P_UnsetThingPosition(remains);
if (sector_list)
{
P_DelSeclist(sector_list);
sector_list = NULL;
}
P_SetThingPosition(remains);
remains->destscale = actor->destscale;
P_SetScale(remains, actor->scale);
remains->flags = actor->flags; // Transfer flags
remains->flags2 = actor->flags2; // Transfer flags2
remains->fuse = actor->fuse; // Transfer respawn timer
remains->threshold = 68;
remains->skin = NULL;
P_SetTarget(&tmthing, remains);
if (actor->info->deathsound)
S_StartSound(remains, actor->info->deathsound);
switch (actor->type)
{
case MT_QUESTIONBOX: // Random!
if (item == MT_NULL)
{
mobjtype_t spawnchance[256];
INT32 numchoices = 0, i = 0;
#define QUESTIONBOXCHANCES(type, cvar) \
for (i = cvar.value; i; --i) spawnchance[numchoices++] = type
QUESTIONBOXCHANCES(MT_SUPERRINGBOX, cv_superring);
QUESTIONBOXCHANCES(MT_SNEAKERTV, cv_supersneakers);
QUESTIONBOXCHANCES(MT_INV, cv_invincibility);
QUESTIONBOXCHANCES(MT_WHITETV, cv_jumpshield);
QUESTIONBOXCHANCES(MT_GREENTV, cv_watershield);
QUESTIONBOXCHANCES(MT_YELLOWTV, cv_ringshield);
QUESTIONBOXCHANCES(MT_BLUETV, cv_forceshield);
QUESTIONBOXCHANCES(MT_BLACKTV, cv_bombshield);
QUESTIONBOXCHANCES(MT_PRUP, cv_1up);
QUESTIONBOXCHANCES(MT_EGGMANBOX, cv_eggmanbox);
QUESTIONBOXCHANCES(MT_MIXUPBOX, cv_teleporters);
QUESTIONBOXCHANCES(MT_RECYCLETV, cv_recycler);
#undef QUESTIONBOXCHANCES
if (numchoices == 0)
{
CONS_Alert(CONS_WARNING, M_GetText("All monitors turned off.\n"));
return;
}
newbox = spawnchance[P_RandomKey(numchoices)];
item = mobjinfo[newbox].damage;
remains->flags &= ~MF_AMBUSH;
break;
}
default:
item = actor->info->damage;
break;
}
if (item != 0)
{
mobj_t *newmobj;
if (actor->eflags & MFE_VERTICALFLIP)
{
newmobj = P_SpawnMobj(actor->x, actor->y, actor->z + actor->height - FixedMul(13*FRACUNIT + mobjinfo[item].height, actor->scale), item);
newmobj->eflags |= MFE_VERTICALFLIP;
}
else
newmobj = P_SpawnMobj(actor->x, actor->y, actor->z + FixedMul(13*FRACUNIT, actor->scale), item);
newmobj->destscale = actor->destscale;
P_SetScale(newmobj, actor->scale);
P_SetTarget(&newmobj->target, actor->target); // Transfer target
if (item == MT_1UPICO && newmobj->target->player)
{
if (actor->tracer) // Remove the old lives icon.
P_RemoveMobj(actor->tracer);
if (!newmobj->target->skin || ((skin_t *)newmobj->target->skin)->sprites[SPR2_LIFE].numframes == 0)
newmobj->frame -= 2; // No lives icon for this player, use the default.
else
{ // Spawn the lives icon.
remains = P_SpawnMobj(newmobj->x, newmobj->y, newmobj->z, MT_OVERLAY);
P_SetTarget(&remains->target, newmobj);
P_SetTarget(&newmobj->tracer, remains);
remains->color = newmobj->target->player->mo->color;
remains->skin = &skins[newmobj->target->player->skin];
P_SetMobjState(remains, newmobj->info->seestate);
}
CONS_Alert(CONS_WARNING, M_GetText("All monitors turned off.\n"));
return;
}
}
else
CONS_Debug(DBG_GAMELOGIC, "Powerup item not defined in 'damage' field for A_MonitorPop\n");
item = actor->info->damage;
P_RemoveMobj(actor);
if (item == 0)
{
CONS_Debug(DBG_GAMELOGIC, "Powerup item not defined in 'damage' field for A_MonitorPop\n");
return;
}
newmobj = P_SpawnMobjFromMobj(actor, 0, 0, 13*FRACUNIT, item);
P_SetTarget(&newmobj->target, actor->target); // Transfer target
if (item == MT_1UP_ICON)
{
if (actor->tracer) // Remove the old lives icon.
P_RemoveMobj(actor->tracer);
if (!newmobj->target
|| !newmobj->target->player
|| !newmobj->target->skin
|| ((skin_t *)newmobj->target->skin)->sprites[SPR2_LIFE].numframes == 0)
{} // No lives icon for this player, use the default.
else
{ // Spawn the lives icon.
mobj_t *livesico = P_SpawnMobjFromMobj(newmobj, 0, 0, 0, MT_OVERLAY);
P_SetTarget(&livesico->target, newmobj);
P_SetTarget(&newmobj->tracer, livesico);
livesico->color = newmobj->target->player->mo->color;
livesico->skin = &skins[newmobj->target->player->skin];
P_SetMobjState(livesico, newmobj->info->seestate);
// We're using the overlay, so use the overlay 1up sprite (no text)
newmobj->sprite = SPR_TV1P;
}
}
}
// Function: A_GoldMonitorPop
//
// Description: Used by repeating monitors when they turn off. They don't really pop, but, you know...
//
// var1 = unused
// var2 = unused
//
void A_GoldMonitorPop(mobj_t *actor)
{
mobjtype_t item = 0;
mobj_t *newmobj;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_GoldMonitorPop", actor))
return;
#endif
// Don't spawn the "pop" explosion, because the monitor isn't broken.
if (actor->info->deathsound)
S_StartSound(actor, actor->info->deathsound);
//P_SpawnMobjFromMobj(actor, 0, 0, actor.height/4, MT_EXPLODE);
// Remove our flags for a bit.
// Players can now stand on top of us.
P_UnsetThingPosition(actor);
actor->flags &= ~(MF_MONITOR|MF_SHOOTABLE);
actor->flags2 |= MF2_STANDONME;
P_SetThingPosition(actor);
// Don't count this box in statistics. Sorry.
if (actor->target && actor->target->player)
--actor->target->player->numboxes;
actor->fuse = 0; // Don't let the monitor code screw us up.
if (actor->info->damage == MT_UNKNOWN)
{
// MT_UNKNOWN is random. Because it's unknown to us... get it?
item = P_DoRandomBoxChances();
if (item == MT_NULL)
{
CONS_Alert(CONS_WARNING, M_GetText("All monitors turned off.\n"));
return;
}
}
else
item = actor->info->damage;
if (item == 0)
{
CONS_Debug(DBG_GAMELOGIC, "Powerup item not defined in 'damage' field for A_GoldMonitorPop\n");
return;
}
// Note: the icon spawns 1 fracunit higher
newmobj = P_SpawnMobjFromMobj(actor, 0, 0, 14*FRACUNIT, item);
P_SetTarget(&newmobj->target, actor->target); // Transfer target
if (item == MT_1UP_ICON)
{
if (actor->tracer) // Remove the old lives icon.
P_RemoveMobj(actor->tracer);
if (!newmobj->target
|| !newmobj->target->player
|| !newmobj->target->skin
|| ((skin_t *)newmobj->target->skin)->sprites[SPR2_LIFE].numframes == 0)
{} // No lives icon for this player, use the default.
else
{ // Spawn the lives icon.
mobj_t *livesico = P_SpawnMobjFromMobj(newmobj, 0, 0, 0, MT_OVERLAY);
P_SetTarget(&livesico->target, newmobj);
P_SetTarget(&newmobj->tracer, livesico);
livesico->color = newmobj->target->player->mo->color;
livesico->skin = &skins[newmobj->target->player->skin];
P_SetMobjState(livesico, newmobj->info->seestate);
// We're using the overlay, so use the overlay 1up sprite (no text)
newmobj->sprite = SPR_TV1P;
}
}
}
// Function: A_GoldMonitorRestore
//
// Description: A repeating monitor is coming back to life. Reset monitor flags, etc.
//
// var1 = unused
// var2 = unused
//
void A_GoldMonitorRestore(mobj_t *actor)
{
#ifdef HAVE_BLUA
if (LUA_CallAction("A_GoldMonitorRestore", actor))
return;
#endif
actor->flags |= MF_MONITOR|MF_SHOOTABLE;
actor->flags2 &= ~MF2_STANDONME;
actor->health = 1; // Just in case.
}
// Function: A_GoldMonitorSparkle
//
// Description: Spawns the little sparkly effect around big monitors. Looks pretty, doesn't it?
//
// var1 = unused
// var2 = unused
//
void A_GoldMonitorSparkle(mobj_t *actor)
{
fixed_t i, ngangle, xofs, yofs;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_GoldMonitorSparkle", actor))
return;
#endif
ngangle = FixedAngle(((leveltime * 21) % 360) << FRACBITS);
xofs = FINESINE((ngangle>>ANGLETOFINESHIFT) & FINEMASK) * (actor->radius>>FRACBITS);
yofs = FINECOSINE((ngangle>>ANGLETOFINESHIFT) & FINEMASK) * (actor->radius>>FRACBITS);
for (i = FRACUNIT*2; i <= FRACUNIT*3; i += FRACUNIT/2)
P_SetObjectMomZ(P_SpawnMobjFromMobj(actor, xofs, yofs, 0, MT_BOXSPARKLE), i, false);
}
// Function: A_Explode
@ -3151,8 +3245,11 @@ void A_ExtraLife(mobj_t *actor)
player = actor->target->player;
if (actor->type == MT_1UPICO && !actor->tracer)
actor->frame -= 2; // No lives icon for this player, use the default.
if (actor->type == MT_1UP_ICON && actor->tracer)
{
// We're using the overlay, so use the overlay 1up sprite (no text)
actor->sprite = SPR_TV1P;
}
if (ultimatemode) //I don't THINK so!
{

View File

@ -1592,8 +1592,7 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour
}
else switch (source->type)
{
case MT_EGGMANICO:
case MT_EGGMANBOX:
case MT_EGGMAN_ICON:
str = M_GetText("%s was %s by Eggman's nefarious TV magic.\n");
break;
case MT_SPIKE:
@ -2899,10 +2898,10 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
if (!force)
{
// Special case for team ring boxes
if (target->type == MT_REDRINGBOX && !(source->player->ctfteam == 1))
if (target->type == MT_RING_REDBOX && !(source->player->ctfteam == 1))
return false;
if (target->type == MT_BLUERINGBOX && !(source->player->ctfteam == 2))
if (target->type == MT_RING_BLUEBOX && !(source->player->ctfteam == 2))
return false;
}

View File

@ -241,6 +241,8 @@ boolean P_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover);
boolean P_CheckDeathPitCollide(mobj_t *mo);
boolean P_CheckSolidLava(mobj_t *mo, ffloor_t *rover);
mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zofs, mobjtype_t type);
mobj_t *P_SpawnMissile(mobj_t *source, mobj_t *dest, mobjtype_t type);
mobj_t *P_SpawnXYZMissile(mobj_t *source, mobj_t *dest, mobjtype_t type, fixed_t x, fixed_t y, fixed_t z);
mobj_t *P_SpawnPointMissile(mobj_t *source, fixed_t xa, fixed_t ya, fixed_t za, mobjtype_t type, fixed_t x, fixed_t y, fixed_t z);

View File

@ -1015,7 +1015,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
|| (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2)
|| ((tmthing->player->charflags & SF_STOMPDAMAGE)
&& (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0)))
&& !((thing->type == MT_REDRINGBOX && tmthing->player->ctfteam != 1) || (thing->type == MT_BLUERINGBOX && tmthing->player->ctfteam != 2)))
&& !((thing->type == MT_RING_REDBOX && tmthing->player->ctfteam != 1) || (thing->type == MT_RING_BLUEBOX && tmthing->player->ctfteam != 2)))
;
// z checking at last
// Treat noclip things as non-solid!

View File

@ -7588,9 +7588,60 @@ void P_MobjThinker(mobj_t *mobj)
mobj_t *flagmo, *newmobj;
#ifdef HAVE_BLUA
if (!LUAh_MobjFuse(mobj) && !P_MobjWasRemoved(mobj))
if (LUAh_MobjFuse(mobj) || P_MobjWasRemoved(mobj))
;
else
#endif
switch (mobj->type)
if (mobj->info->flags & MF_MONITOR)
{
// Special case for ALL monitors.
// If a box's speed is nonzero, it's allowed to respawn as a WRM/SRM.
if (mobj->info->speed != 0 && (mobj->flags & MF_AMBUSH || mobj->flags2 & MF2_STRONGBOX))
{
mobjtype_t spawnchance[64];
INT32 numchoices = 0, i = 0;
// This define should make it a lot easier to organize and change monitor weights
#define SETMONITORCHANCES(type, strongboxamt, weakboxamt) \
for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) spawnchance[numchoices++] = type
// Type SRM WRM
SETMONITORCHANCES(MT_SNEAKERS_BOX, 0, 10); // Super Sneakers
SETMONITORCHANCES(MT_INVULN_BOX, 2, 0); // Invincibility
SETMONITORCHANCES(MT_WHIRLWIND_BOX, 3, 8); // Whirlwind Shield
SETMONITORCHANCES(MT_ELEMENTAL_BOX, 3, 8); // Elemental Shield
SETMONITORCHANCES(MT_ATTRACT_BOX, 2, 0); // Attraction Shield
SETMONITORCHANCES(MT_FORCE_BOX, 3, 3); // Force Shield
SETMONITORCHANCES(MT_ARMAGEDDON_BOX, 2, 0); // Armageddon Shield
SETMONITORCHANCES(MT_MIXUP_BOX, 0, 1); // Teleporters
SETMONITORCHANCES(MT_RECYCLER_BOX, 0, 1); // Recycler
SETMONITORCHANCES(MT_1UP_BOX, 1, 1); // 1-Up
// =======================================
// Total 16 32
#undef SETMONITORCHANCES
i = P_RandomKey(numchoices); // Gotta love those random numbers!
newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, spawnchance[i]);
// If the monitor respawns randomly, transfer the flag.
if (mobj->flags & MF_AMBUSH)
newmobj->flags |= MF_AMBUSH;
// Transfer flags2 (strongbox, objectflip)
newmobj->flags2 = mobj->flags2;
}
else
{
newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->type);
// Transfer flags2 (strongbox, objectflip)
newmobj->flags2 = mobj->flags2;
}
P_RemoveMobj(mobj); // make sure they disappear
return;
}
else switch (mobj->type)
{
// gargoyle and snowman handled in P_PushableThinker, not here
case MT_THROWNGRENADE:
@ -7649,68 +7700,6 @@ void P_MobjThinker(mobj_t *mobj)
}
P_RemoveMobj(mobj);
return;
case MT_YELLOWTV: // Ring shield box
case MT_BLUETV: // Force shield box
case MT_GREENTV: // Water shield box
case MT_BLACKTV: // Bomb shield box
case MT_WHITETV: // Jump shield box
case MT_SNEAKERTV: // Super Sneaker box
case MT_SUPERRINGBOX: // 10-Ring box
case MT_REDRINGBOX: // Red Team 10-Ring box
case MT_BLUERINGBOX: // Blue Team 10-Ring box
case MT_INV: // Invincibility box
case MT_MIXUPBOX: // Teleporter Mixup box
case MT_RECYCLETV: // Recycler box
case MT_SCORETVSMALL:
case MT_SCORETVLARGE:
case MT_PRUP: // 1up!
case MT_EGGMANBOX: // Eggman box
case MT_GRAVITYBOX: // Gravity box
case MT_QUESTIONBOX:
if ((mobj->flags & MF_AMBUSH || mobj->flags2 & MF2_STRONGBOX) && mobj->type != MT_QUESTIONBOX)
{
mobjtype_t spawnchance[64];
INT32 numchoices = 0, i = 0;
// This define should make it a lot easier to organize and change monitor weights
#define SETMONITORCHANCES(type, strongboxamt, weakboxamt) \
for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) spawnchance[numchoices++] = type
// Type SRM WRM
SETMONITORCHANCES(MT_SNEAKERTV, 0, 10); // Super Sneakers
SETMONITORCHANCES(MT_INV, 2, 0); // Invincibility
SETMONITORCHANCES(MT_WHITETV, 3, 8); // Whirlwind Shield
SETMONITORCHANCES(MT_GREENTV, 3, 8); // Elemental Shield
SETMONITORCHANCES(MT_YELLOWTV, 2, 0); // Attraction Shield
SETMONITORCHANCES(MT_BLUETV, 3, 3); // Force Shield
SETMONITORCHANCES(MT_BLACKTV, 2, 0); // Armageddon Shield
SETMONITORCHANCES(MT_MIXUPBOX, 0, 1); // Teleporters
SETMONITORCHANCES(MT_RECYCLETV, 0, 1); // Recycler
SETMONITORCHANCES(MT_PRUP, 1, 1); // 1-Up
// ======================================
// Total 16 32
#undef SETMONITORCHANCES
i = P_RandomKey(numchoices); // Gotta love those random numbers!
newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, spawnchance[i]);
// If the monitor respawns randomly, transfer the flag.
if (mobj->flags & MF_AMBUSH)
newmobj->flags |= MF_AMBUSH;
// Transfer flags2 (strongbox, objectflip)
newmobj->flags2 = mobj->flags2;
}
else
{
newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->type);
// Transfer flags2 (strongbox, objectflip)
newmobj->flags2 = mobj->flags2;
}
P_RemoveMobj(mobj); // make sure they disappear
return;
case MT_METALSONIC_BATTLE:
break; // don't remove
case MT_SPIKE:
@ -7727,6 +7716,7 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s
default:
P_SetMobjState(mobj, mobj->info->xdeathstate); // will remove the mobj if S_NULL.
break;
// Looking for monitors? They moved to a special condition above.
}
if (P_MobjWasRemoved(mobj))
return;
@ -9177,36 +9167,37 @@ void P_SpawnMapThing(mapthing_t *mthing)
if ((mobjinfo[i].flags & MF_ENEMY) || (mobjinfo[i].flags & MF_BOSS))
return;
// Set powerup boxes to user settings for competition.
if (gametype == GT_COMPETITION)
// Altering monitor spawns via cvars
// If MF_GRENADEBOUNCE is set in the monitor's info,
// skip this step. (Used for gold monitors)
// Yeah, this is a dirty hack.
if ((mobjinfo[i].flags & (MF_MONITOR|MF_GRENADEBOUNCE)) == MF_MONITOR)
{
if ((mobjinfo[i].flags & MF_MONITOR) && cv_competitionboxes.value) // not Normal
if (gametype == GT_COMPETITION)
{
// Set powerup boxes to user settings for competition.
if (cv_competitionboxes.value == 1) // Random
i = MT_QUESTIONBOX;
i = MT_MYSTERY_BOX;
else if (cv_competitionboxes.value == 2) // Teleports
i = MT_MIXUPBOX;
i = MT_MIXUP_BOX;
else if (cv_competitionboxes.value == 3) // None
return; // Don't spawn!
// default case: normal
}
}
// Set powerup boxes to user settings for other netplay modes
else if (gametype != GT_COOP)
{
if ((mobjinfo[i].flags & MF_MONITOR) && cv_matchboxes.value) // not Normal
// Set powerup boxes to user settings for other netplay modes
else if (gametype != GT_COOP)
{
if (cv_matchboxes.value == 1) // Random
i = MT_QUESTIONBOX;
else if (cv_matchboxes.value == 3) // Don't spawn
return;
else // cv_matchboxes.value == 2, Non-Random
i = MT_MYSTERY_BOX;
else if (cv_matchboxes.value == 2) // Non-Random
{
if (i == MT_QUESTIONBOX)
if (i == MT_MYSTERY_BOX)
return; // don't spawn in Non-Random
mthing->options &= ~(MTF_AMBUSH|MTF_OBJECTSPECIAL); // no random respawning!
}
else if (cv_matchboxes.value == 3) // Don't spawn
return;
// default case: normal
}
}
@ -9214,8 +9205,8 @@ void P_SpawnMapThing(mapthing_t *mthing)
{
if (i == MT_BLUETEAMRING || i == MT_REDTEAMRING)
i = MT_RING;
else if (i == MT_BLUERINGBOX || i == MT_REDRINGBOX)
i = MT_SUPERRINGBOX;
else if (i == MT_RING_BLUEBOX || i == MT_RING_REDBOX)
i = MT_RING_BOX;
else if (i == MT_BLUEFLAG || i == MT_REDFLAG)
return; // No flags in non-CTF modes!
}
@ -9242,23 +9233,27 @@ void P_SpawnMapThing(mapthing_t *mthing)
return; /// \todo
// 1UPs -->> Score TVs
else if (i == MT_PRUP) // 1UP
else if (i == MT_1UP_BOX) // 1UP
{
// Either or, doesn't matter which.
if (mthing->options & (MTF_AMBUSH|MTF_OBJECTSPECIAL))
i = MT_SCORETVLARGE; // 10,000
i = MT_SCORE10K_BOX; // 10,000
else
i = MT_SCORETVSMALL; // 1,000
i = MT_SCORE1K_BOX; // 1,000
}
}
if (ultimatemode)
{
if (i == MT_PITYTV || i == MT_GREENTV || i == MT_YELLOWTV || i == MT_BLUETV || i == MT_BLACKTV || i == MT_WHITETV)
if (i == MT_PITY_BOX || i == MT_ELEMENTAL_BOX || i == MT_ATTRACT_BOX
|| i == MT_FORCE_BOX || i == MT_ARMAGEDDON_BOX || i == MT_WHIRLWIND_BOX)
return; // No shields in Ultimate mode
if (i == MT_SUPERRINGBOX && !G_IsSpecialStage(gamemap))
if (i == MT_RING_BOX && !G_IsSpecialStage(gamemap))
return; // No rings in Ultimate mode (except special stages)
// Don't include the gold repeating boxes here please.
// They're likely facets of the level's design and therefore required to progress.
}
if (i == MT_EMMY && (gametype != GT_COOP || ultimatemode || tokenbits == 30 || tokenlist & (1 << tokenbits++)))
@ -9681,7 +9676,7 @@ ML_NOCLIMB : Direction not controllable
}
//count 10 ring boxes into the number of rings equation too.
if (i == MT_SUPERRINGBOX)
if (i == MT_RING_BOX)
nummaprings += 10;
if (i == MT_BIGTUMBLEWEED || i == MT_LITTLETUMBLEWEED)
@ -9760,16 +9755,11 @@ ML_NOCLIMB : Direction not controllable
mobj->flags2 |= MF2_STANDONME;
}
if (mobj->flags & MF_MONITOR)
if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0)
{
// flag for strong/weak random boxes
if (mthing->type == mobjinfo[MT_SUPERRINGBOX].doomednum || mthing->type == mobjinfo[MT_PRUP].doomednum ||
mthing->type == mobjinfo[MT_SNEAKERTV].doomednum || mthing->type == mobjinfo[MT_INV].doomednum ||
mthing->type == mobjinfo[MT_WHITETV].doomednum || mthing->type == mobjinfo[MT_GREENTV].doomednum ||
mthing->type == mobjinfo[MT_YELLOWTV].doomednum || mthing->type == mobjinfo[MT_BLUETV].doomednum ||
mthing->type == mobjinfo[MT_BLACKTV].doomednum || mthing->type == mobjinfo[MT_PITYTV].doomednum ||
mthing->type == mobjinfo[MT_RECYCLETV].doomednum || mthing->type == mobjinfo[MT_MIXUPBOX].doomednum)
mobj->flags |= MF_AMBUSH;
// any monitor with nonzero speed is allowed to respawn like this
mobj->flags |= MF_AMBUSH;
}
else if (mthing->type != mobjinfo[MT_AXIS].doomednum &&
@ -9782,14 +9772,12 @@ ML_NOCLIMB : Direction not controllable
if (mthing->options & MTF_OBJECTSPECIAL)
{
// flag for strong/weak random boxes
if (mthing->type == mobjinfo[MT_SUPERRINGBOX].doomednum || mthing->type == mobjinfo[MT_PRUP].doomednum ||
mthing->type == mobjinfo[MT_SNEAKERTV].doomednum || mthing->type == mobjinfo[MT_INV].doomednum ||
mthing->type == mobjinfo[MT_WHITETV].doomednum || mthing->type == mobjinfo[MT_GREENTV].doomednum ||
mthing->type == mobjinfo[MT_YELLOWTV].doomednum || mthing->type == mobjinfo[MT_BLUETV].doomednum ||
mthing->type == mobjinfo[MT_BLACKTV].doomednum || mthing->type == mobjinfo[MT_PITYTV].doomednum ||
mthing->type == mobjinfo[MT_RECYCLETV].doomednum || mthing->type == mobjinfo[MT_MIXUPBOX].doomednum)
mobj->flags2 |= MF2_STRONGBOX;
if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0)
{
// flag for strong/weak random boxes
// any monitor with nonzero speed is allowed to respawn like this
mobj->flags2 |= MF2_STRONGBOX;
}
// Requires you to be in bonus time to activate
if (mobj->flags & MF_NIGHTSITEM)
@ -10778,3 +10766,35 @@ void P_FlashPal(player_t *pl, UINT16 type, UINT16 duration)
pl->flashcount = duration;
pl->flashpal = type;
}
//
// P_SpawnMobjFromMobj
// Spawns an object with offsets relative to the position of another object.
// Scale, gravity flip, etc. is taken into account automatically.
//
mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zofs, mobjtype_t type)
{
mobj_t *newmobj;
xofs = FixedMul(xofs, mobj->scale);
yofs = FixedMul(yofs, mobj->scale);
zofs = FixedMul(zofs, mobj->scale);
newmobj = P_SpawnMobj(mobj->x + xofs, mobj->y + yofs, mobj->z + zofs, type);
if (!newmobj)
return NULL;
if (mobj->eflags & MFE_VERTICALFLIP)
{
fixed_t elementheight = FixedMul(newmobj->info->height, mobj->scale);
newmobj->eflags |= MFE_VERTICALFLIP;
newmobj->flags2 |= MF2_OBJECTFLIP;
newmobj->z = mobj->z + mobj->height - zofs - elementheight;
}
newmobj->destscale = mobj->destscale;
P_SetScale(newmobj, mobj->scale);
return newmobj;
}

View File

@ -8627,7 +8627,7 @@ void P_DoPityCheck(player_t *player)
if ((player->pity >= 3 || player->pity < 0) && player->powers[pw_shield] == SH_NONE)
{
if (player->pity > 0)
S_StartSound(player->mo, mobjinfo[MT_PITYSHIELDICO].seesound);
S_StartSound(player->mo, mobjinfo[MT_PITY_ICON].seesound);
player->pity = 0;
player->powers[pw_shield] = SH_PITY;

View File

@ -159,6 +159,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"lvpass", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR},
{"mindig", false, 8, 64, -1, NULL, 0, -1, -1, LUMPERROR},
{"mixup", true, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR},
{"monton", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR},
{"pogo" , false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR},
{"pop" , false, 78, 0, -1, NULL, 0, -1, -1, LUMPERROR},
{"rail1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR},

View File

@ -222,6 +222,7 @@ typedef enum
sfx_lvpass,
sfx_mindig,
sfx_mixup,
sfx_monton,
sfx_pogo,
sfx_pop,
sfx_rail1,