rewrite of monitors to accomodate repeat use monitors.

It's a lot nicer in general, honestly. I think a couple bugs with custom monitors respawning got fixed in the process.
Note that a monitorgfx.wad is needed if you want to see things besides <!>s for monitors, due to graphic changes.
This commit is contained in:
Inuyasha 2015-12-31 08:38:23 -08:00
parent 79aaa00d14
commit 265a607b58
12 changed files with 2009 additions and 1450 deletions

View File

@ -1628,6 +1628,9 @@ static actionpointer_t actionpointers[] =
{{A_Pain}, "A_PAIN"},
{{A_Fall}, "A_FALL"},
{{A_MonitorPop}, "A_MONITORPOP"},
{{A_BigMonitorPop}, "A_BIGMONITORPOP"},
{{A_BigMonitorRestore}, "A_BIGMONITORRESTORE"},
{{A_BigMonitorSparkle}, "A_BIGMONITORSPARKLE"},
{{A_Look}, "A_LOOK"},
{{A_Chase}, "A_CHASE"},
{{A_FaceStabChase}, "A_FACESTABCHASE"},
@ -4855,170 +4858,169 @@ 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_BIGBOX_FLICKER",
"S_BIGBOX_OFF1",
"S_BIGBOX_OFF2",
"S_BIGBOX_OFF3",
"S_BIGBOX_OFF4",
"S_BIGBOX_OFF5",
"S_BIGBOX_OFF6",
"S_BIGBOX_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",
// Repeat Monitor States (one per box)
"S_MYSTERY_BIGBOX",
"S_RING_BIGBOX",
"S_PITY_BIGBOX",
"S_ATTRACT_BIGBOX",
"S_FORCE_BIGBOX",
"S_ARMAGEDDON_BIGBOX",
"S_WHIRLWIND_BIGBOX",
"S_ELEMENTAL_BIGBOX",
"S_SNEAKERS_BIGBOX",
"S_INVULN_BIGBOX",
"S_1UP_BIGBOX",
"S_EGGMAN_BIGBOX",
"S_MIXUP_BIGBOX",
"S_GRAVITY_BIGBOX",
"S_RECYCLER_BIGBOX",
"S_SCORE1K_BIGBOX",
"S_SCORE10K_BIGBOX",
// 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 -- 5 states each, one for each part of the twirl
"S_RING_ICON1",
"S_RING_ICON2",
"S_RING_ICON3",
"S_RING_ICON4",
"S_RING_ICON5",
// Bomb Shield Box
"S_BKTV1",
"S_BKTV2",
"S_BKTV3",
"S_BKTV4",
"S_BKTV5",
"S_BKTV6",
"S_BKTV7",
"S_PITY_ICON1",
"S_PITY_ICON2",
"S_PITY_ICON3",
"S_PITY_ICON4",
"S_PITY_ICON5",
// Jump Shield Box
"S_WHTV1",
"S_WHTV2",
"S_WHTV3",
"S_WHTV4",
"S_WHTV5",
"S_WHTV6",
"S_WHTV7",
"S_ATTRACT_ICON1",
"S_ATTRACT_ICON2",
"S_ATTRACT_ICON3",
"S_ATTRACT_ICON4",
"S_ATTRACT_ICON5",
// Water Shield Box
"S_GRTV",
"S_GRTV1",
"S_GRTV2",
"S_GRTV3",
"S_GRTV4",
"S_GRTV5",
"S_GRTV6",
"S_FORCE_ICON1",
"S_FORCE_ICON2",
"S_FORCE_ICON3",
"S_FORCE_ICON4",
"S_FORCE_ICON5",
// Pity Shield Box
"S_PITV1",
"S_PITV2",
"S_PITV3",
"S_PITV4",
"S_PITV5",
"S_PITV6",
"S_PITV7",
"S_ARMAGEDDON_ICON1",
"S_ARMAGEDDON_ICON2",
"S_ARMAGEDDON_ICON3",
"S_ARMAGEDDON_ICON4",
"S_ARMAGEDDON_ICON5",
// Eggman Box
"S_EGGTV1",
"S_EGGTV2",
"S_EGGTV3",
"S_EGGTV4",
"S_EGGTV5",
"S_EGGTV6",
"S_EGGTV7",
"S_WHIRLWIND_ICON1",
"S_WHIRLWIND_ICON2",
"S_WHIRLWIND_ICON3",
"S_WHIRLWIND_ICON4",
"S_WHIRLWIND_ICON5",
// Teleport Box
"S_MIXUPBOX1",
"S_MIXUPBOX2",
"S_MIXUPBOX3",
"S_MIXUPBOX4",
"S_MIXUPBOX5",
"S_MIXUPBOX6",
"S_MIXUPBOX7",
"S_ELEMENTAL_ICON1",
"S_ELEMENTAL_ICON2",
"S_ELEMENTAL_ICON3",
"S_ELEMENTAL_ICON4",
"S_ELEMENTAL_ICON5",
// Recycler Box
"S_RECYCLETV1",
"S_RECYCLETV2",
"S_RECYCLETV3",
"S_RECYCLETV4",
"S_RECYCLETV5",
"S_RECYCLETV6",
"S_RECYCLETV7",
"S_SNEAKERS_ICON1",
"S_SNEAKERS_ICON2",
"S_SNEAKERS_ICON3",
"S_SNEAKERS_ICON4",
"S_SNEAKERS_ICON5",
// Question Box
"S_RANDOMBOX1",
"S_RANDOMBOX2",
"S_RANDOMBOX3",
"S_INVULN_ICON1",
"S_INVULN_ICON2",
"S_INVULN_ICON3",
"S_INVULN_ICON4",
"S_INVULN_ICON5",
// Gravity Boots Box
"S_GBTV1",
"S_GBTV2",
"S_GBTV3",
"S_GBTV4",
"S_GBTV5",
"S_GBTV6",
"S_GBTV7",
"S_1UP_ICON1",
"S_1UP_ICON2",
"S_1UP_ICON3",
"S_1UP_ICON4",
"S_1UP_ICON5",
// 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",
"S_EGGMAN_ICON3",
"S_EGGMAN_ICON4",
"S_EGGMAN_ICON5",
// Monitor Explosion
"S_MONITOREXPLOSION1",
"S_MONITOREXPLOSION2",
"S_MIXUP_ICON1",
"S_MIXUP_ICON2",
"S_MIXUP_ICON3",
"S_MIXUP_ICON4",
"S_MIXUP_ICON5",
"S_REDMONITOREXPLOSION1",
"S_REDMONITOREXPLOSION2",
"S_GRAVITY_ICON1",
"S_GRAVITY_ICON2",
"S_GRAVITY_ICON3",
"S_GRAVITY_ICON4",
"S_GRAVITY_ICON5",
"S_BLUEMONITOREXPLOSION1",
"S_BLUEMONITOREXPLOSION2",
"S_RECYCLER_ICON1",
"S_RECYCLER_ICON2",
"S_RECYCLER_ICON3",
"S_RECYCLER_ICON4",
"S_RECYCLER_ICON5",
"S_SCORE1K_ICON1",
"S_SCORE1K_ICON2",
"S_SCORE1K_ICON3",
"S_SCORE1K_ICON4",
"S_SCORE1K_ICON5",
"S_SCORE10K_ICON1",
"S_SCORE10K_ICON2",
"S_SCORE10K_ICON3",
"S_SCORE10K_ICON4",
"S_SCORE10K_ICON5",
"S_ROCKET",
@ -6760,47 +6762,68 @@ 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_RING_BIGBOX",
"MT_PITY_BIGBOX",
"MT_ATTRACT_BIGBOX",
"MT_FORCE_BIGBOX",
"MT_ARMAGEDDON_BIGBOX",
"MT_WHIRLWIND_BIGBOX",
"MT_ELEMENTAL_BIGBOX",
"MT_SNEAKERS_BIGBOX",
"MT_INVULN_BIGBOX",
"MT_1UP_BIGBOX",
"MT_EGGMAN_BIGBOX",
"MT_MIXUP_BIGBOX",
"MT_MYSTERY_BIGBOX",
"MT_GRAVITY_BIGBOX",
"MT_RECYCLER_BIGBOX",
"MT_SCORE1K_BIGBOX",
"MT_SCORE10K_BIGBOX",
// 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

2056
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_BigMonitorPop();
void A_BigMonitorRestore();
void A_BigMonitorSparkle();
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,
@ -1750,170 +1756,171 @@ 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_BIGBOX_FLICKER,
S_BIGBOX_OFF1,
S_BIGBOX_OFF2,
S_BIGBOX_OFF3,
S_BIGBOX_OFF4,
S_BIGBOX_OFF5,
S_BIGBOX_OFF6,
S_BIGBOX_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,
// Repeat Monitor States (one per box)
S_MYSTERY_BIGBOX,
S_RING_BIGBOX,
S_PITY_BIGBOX,
S_ATTRACT_BIGBOX,
S_FORCE_BIGBOX,
S_ARMAGEDDON_BIGBOX,
S_WHIRLWIND_BIGBOX,
S_ELEMENTAL_BIGBOX,
S_SNEAKERS_BIGBOX,
S_INVULN_BIGBOX,
S_1UP_BIGBOX,
S_EGGMAN_BIGBOX,
S_MIXUP_BIGBOX,
S_GRAVITY_BIGBOX,
S_RECYCLER_BIGBOX,
S_SCORE1K_BIGBOX,
S_SCORE10K_BIGBOX,
// 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 -- 5 states each, one for each part of the twirl
S_RING_ICON1,
S_RING_ICON2,
S_RING_ICON3,
S_RING_ICON4,
S_RING_ICON5,
// Bomb Shield Box
S_BKTV1,
S_BKTV2,
S_BKTV3,
S_BKTV4,
S_BKTV5,
S_BKTV6,
S_BKTV7,
S_PITY_ICON1,
S_PITY_ICON2,
S_PITY_ICON3,
S_PITY_ICON4,
S_PITY_ICON5,
// Jump Shield Box
S_WHTV1,
S_WHTV2,
S_WHTV3,
S_WHTV4,
S_WHTV5,
S_WHTV6,
S_WHTV7,
S_ATTRACT_ICON1,
S_ATTRACT_ICON2,
S_ATTRACT_ICON3,
S_ATTRACT_ICON4,
S_ATTRACT_ICON5,
// Water Shield Box
S_GRTV,
S_GRTV1,
S_GRTV2,
S_GRTV3,
S_GRTV4,
S_GRTV5,
S_GRTV6,
S_FORCE_ICON1,
S_FORCE_ICON2,
S_FORCE_ICON3,
S_FORCE_ICON4,
S_FORCE_ICON5,
// Pity Shield Box
S_PITV1,
S_PITV2,
S_PITV3,
S_PITV4,
S_PITV5,
S_PITV6,
S_PITV7,
S_ARMAGEDDON_ICON1,
S_ARMAGEDDON_ICON2,
S_ARMAGEDDON_ICON3,
S_ARMAGEDDON_ICON4,
S_ARMAGEDDON_ICON5,
// Eggman Box
S_EGGTV1,
S_EGGTV2,
S_EGGTV3,
S_EGGTV4,
S_EGGTV5,
S_EGGTV6,
S_EGGTV7,
S_WHIRLWIND_ICON1,
S_WHIRLWIND_ICON2,
S_WHIRLWIND_ICON3,
S_WHIRLWIND_ICON4,
S_WHIRLWIND_ICON5,
// Teleport Box
S_MIXUPBOX1,
S_MIXUPBOX2,
S_MIXUPBOX3,
S_MIXUPBOX4,
S_MIXUPBOX5,
S_MIXUPBOX6,
S_MIXUPBOX7,
S_ELEMENTAL_ICON1,
S_ELEMENTAL_ICON2,
S_ELEMENTAL_ICON3,
S_ELEMENTAL_ICON4,
S_ELEMENTAL_ICON5,
// Recycler Box
S_RECYCLETV1,
S_RECYCLETV2,
S_RECYCLETV3,
S_RECYCLETV4,
S_RECYCLETV5,
S_RECYCLETV6,
S_RECYCLETV7,
S_SNEAKERS_ICON1,
S_SNEAKERS_ICON2,
S_SNEAKERS_ICON3,
S_SNEAKERS_ICON4,
S_SNEAKERS_ICON5,
// Question Box
S_RANDOMBOX1,
S_RANDOMBOX2,
S_RANDOMBOX3,
S_INVULN_ICON1,
S_INVULN_ICON2,
S_INVULN_ICON3,
S_INVULN_ICON4,
S_INVULN_ICON5,
// Gravity Boots Box
S_GBTV1,
S_GBTV2,
S_GBTV3,
S_GBTV4,
S_GBTV5,
S_GBTV6,
S_GBTV7,
S_1UP_ICON1,
S_1UP_ICON2,
S_1UP_ICON3,
S_1UP_ICON4,
S_1UP_ICON5,
// 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,
S_EGGMAN_ICON3,
S_EGGMAN_ICON4,
S_EGGMAN_ICON5,
// Monitor Explosion
S_MONITOREXPLOSION1,
S_MONITOREXPLOSION2,
S_MIXUP_ICON1,
S_MIXUP_ICON2,
S_MIXUP_ICON3,
S_MIXUP_ICON4,
S_MIXUP_ICON5,
S_REDMONITOREXPLOSION1,
S_REDMONITOREXPLOSION2,
S_GRAVITY_ICON1,
S_GRAVITY_ICON2,
S_GRAVITY_ICON3,
S_GRAVITY_ICON4,
S_GRAVITY_ICON5,
S_BLUEMONITOREXPLOSION1,
S_BLUEMONITOREXPLOSION2,
S_RECYCLER_ICON1,
S_RECYCLER_ICON2,
S_RECYCLER_ICON3,
S_RECYCLER_ICON4,
S_RECYCLER_ICON5,
S_SCORE1K_ICON1,
S_SCORE1K_ICON2,
S_SCORE1K_ICON3,
S_SCORE1K_ICON4,
S_SCORE1K_ICON5,
S_SCORE10K_ICON1,
S_SCORE10K_ICON2,
S_SCORE10K_ICON3,
S_SCORE10K_ICON4,
S_SCORE10K_ICON5,
// ---
S_ROCKET,
@ -3673,47 +3680,68 @@ 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_RING_BIGBOX,
MT_PITY_BIGBOX,
MT_ATTRACT_BIGBOX,
MT_FORCE_BIGBOX,
MT_ARMAGEDDON_BIGBOX,
MT_WHIRLWIND_BIGBOX,
MT_ELEMENTAL_BIGBOX,
MT_SNEAKERS_BIGBOX,
MT_INVULN_BIGBOX,
MT_1UP_BIGBOX,
MT_EGGMAN_BIGBOX,
MT_MIXUP_BIGBOX,
MT_MYSTERY_BIGBOX,
MT_GRAVITY_BIGBOX,
MT_RECYCLER_BIGBOX,
MT_SCORE1K_BIGBOX,
MT_SCORE10K_BIGBOX,
// 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
//
@ -2515,7 +2541,7 @@ 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;
actor->sprite = SPR_TV1U;
if (actor->tracer) {
P_RemoveMobj(actor->tracer);
actor->tracer = NULL;
@ -2543,139 +2569,194 @@ 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)
newmobj->sprite = SPR_TV1U; // 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);
}
}
}
// Function: A_BigMonitorPop
//
// Description: Used by repeating monitors when they turn off. They don't really pop, but, you know...
//
// var1 = unused
// var2 = unused
//
void A_BigMonitorPop(mobj_t *actor)
{
mobjtype_t item = 0;
mobj_t *newmobj;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_BigMonitorPop", 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_BigMonitorPop\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)
newmobj->sprite = SPR_TV1U; // 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);
}
}
}
// Function: A_BigMonitorRestore
//
// Description: A repeating monitor is coming back to life. Reset monitor flags, etc.
//
// var1 = unused
// var2 = unused
//
void A_BigMonitorRestore(mobj_t *actor)
{
#ifdef HAVE_BLUA
if (LUA_CallAction("A_BigMonitorRestore", actor))
return;
#endif
actor->flags |= MF_MONITOR|MF_SHOOTABLE;
actor->flags2 &= ~MF2_STANDONME;
actor->health = 1; // Just in case.
}
// Function: A_BigMonitorSparkle
//
// Description: Spawns the little sparkly effect around big monitors. Looks pretty, doesn't it?
//
// var1 = unused
// var2 = unused
//
void A_BigMonitorSparkle(mobj_t *actor)
{
fixed_t i, ngangle, xofs, yofs;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_BigMonitorSparkle", 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
@ -3160,8 +3241,8 @@ 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)
actor->sprite = SPR_TV1U; // No lives icon for this player, use the default.
if (ultimatemode) //I don't THINK so!
{

View File

@ -1568,8 +1568,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:
@ -2766,10 +2765,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

@ -238,6 +238,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

@ -955,7 +955,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
// Monitors are not treated as solid to players who are jumping, spinning or gliding,
// unless it's a CTF team monitor and you're on the wrong team
else if (thing->flags & MF_MONITOR && tmthing->player && tmthing->player->pflags & (PF_JUMPED|PF_SPINNING|PF_GLIDING)
&& !((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

@ -7258,9 +7258,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:
@ -7317,68 +7368,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:
@ -7395,6 +7384,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;
@ -8805,9 +8795,9 @@ void P_SpawnMapThing(mapthing_t *mthing)
if ((mobjinfo[i].flags & MF_MONITOR) && cv_competitionboxes.value) // not Normal
{
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!
}
@ -8819,12 +8809,12 @@ void P_SpawnMapThing(mapthing_t *mthing)
if ((mobjinfo[i].flags & MF_MONITOR) && cv_matchboxes.value) // not Normal
{
if (cv_matchboxes.value == 1) // Random
i = MT_QUESTIONBOX;
i = MT_MYSTERY_BOX;
else if (cv_matchboxes.value == 3) // Don't spawn
return;
else // 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!
@ -8836,8 +8826,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!
}
@ -8864,23 +8854,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 BIGBOXes (repeating monitors) 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++)))
@ -9306,8 +9300,10 @@ 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_RING_BIGBOX) // Theoretically infinite
nummaprings += 10000;
if (i == MT_BIGTUMBLEWEED || i == MT_LITTLETUMBLEWEED)
{
@ -9385,16 +9381,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 &&
@ -9407,14 +9398,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)
@ -10411,3 +10400,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

@ -8651,7 +8651,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

@ -1220,6 +1220,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

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