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_Pain}, "A_PAIN"},
{{A_Fall}, "A_FALL"}, {{A_Fall}, "A_FALL"},
{{A_MonitorPop}, "A_MONITORPOP"}, {{A_MonitorPop}, "A_MONITORPOP"},
{{A_BigMonitorPop}, "A_BIGMONITORPOP"},
{{A_BigMonitorRestore}, "A_BIGMONITORRESTORE"},
{{A_BigMonitorSparkle}, "A_BIGMONITORSPARKLE"},
{{A_Look}, "A_LOOK"}, {{A_Look}, "A_LOOK"},
{{A_Chase}, "A_CHASE"}, {{A_Chase}, "A_CHASE"},
{{A_FaceStabChase}, "A_FACESTABCHASE"}, {{A_FaceStabChase}, "A_FACESTABCHASE"},
@ -4855,170 +4858,169 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_CANNONLAUNCHER2", "S_CANNONLAUNCHER2",
"S_CANNONLAUNCHER3", "S_CANNONLAUNCHER3",
// Super Ring Box // Monitor Miscellany
"S_SUPERRINGBOX", "S_BOXSPARKLE1",
"S_SUPERRINGBOX1", "S_BOXSPARKLE2",
"S_SUPERRINGBOX2", "S_BOXSPARKLE3",
"S_SUPERRINGBOX3",
"S_SUPERRINGBOX4",
"S_SUPERRINGBOX5",
"S_SUPERRINGBOX6",
// Red Team Ring Box "S_BOX_FLICKER",
"S_REDRINGBOX", "S_BOX_POP1",
"S_REDRINGBOX1", "S_BOX_POP2",
// Blue Team Ring Box "S_BIGBOX_FLICKER",
"S_BLUERINGBOX", "S_BIGBOX_OFF1",
"S_BLUERINGBOX1", "S_BIGBOX_OFF2",
"S_BIGBOX_OFF3",
"S_BIGBOX_OFF4",
"S_BIGBOX_OFF5",
"S_BIGBOX_OFF6",
"S_BIGBOX_OFF7",
// Super Sneakers Box // Monitor States (one per box)
"S_SHTV", "S_MYSTERY_BOX",
"S_SHTV1", "S_RING_BOX",
"S_SHTV2", "S_PITY_BOX",
"S_SHTV3", "S_ATTRACT_BOX",
"S_SHTV4", "S_FORCE_BOX",
"S_SHTV5", "S_ARMAGEDDON_BOX",
"S_SHTV6", "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 // Repeat Monitor States (one per box)
"S_PINV", "S_MYSTERY_BIGBOX",
"S_PINV1", "S_RING_BIGBOX",
"S_PINV2", "S_PITY_BIGBOX",
"S_PINV3", "S_ATTRACT_BIGBOX",
"S_PINV4", "S_FORCE_BIGBOX",
"S_PINV5", "S_ARMAGEDDON_BIGBOX",
"S_PINV6", "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 // Team Ring Boxes (these are special)
"S_PRUP", "S_RING_REDBOX1",
"S_PRUP1", "S_RING_REDBOX2",
"S_PRUP2", "S_REDBOX_POP1",
"S_PRUP3", "S_REDBOX_POP2",
"S_PRUP4",
"S_PRUP5",
"S_PRUP6",
// Ring Shield Box "S_RING_BLUEBOX1",
"S_YLTV", "S_RING_BLUEBOX2",
"S_YLTV1", "S_BLUEBOX_POP1",
"S_YLTV2", "S_BLUEBOX_POP2",
"S_YLTV3",
"S_YLTV4",
"S_YLTV5",
"S_YLTV6",
// Force Shield Box // Box Icons -- 5 states each, one for each part of the twirl
"S_BLTV1", "S_RING_ICON1",
"S_BLTV2", "S_RING_ICON2",
"S_BLTV3", "S_RING_ICON3",
"S_BLTV4", "S_RING_ICON4",
"S_BLTV5", "S_RING_ICON5",
"S_BLTV6",
"S_BLTV7",
// Bomb Shield Box "S_PITY_ICON1",
"S_BKTV1", "S_PITY_ICON2",
"S_BKTV2", "S_PITY_ICON3",
"S_BKTV3", "S_PITY_ICON4",
"S_BKTV4", "S_PITY_ICON5",
"S_BKTV5",
"S_BKTV6",
"S_BKTV7",
// Jump Shield Box "S_ATTRACT_ICON1",
"S_WHTV1", "S_ATTRACT_ICON2",
"S_WHTV2", "S_ATTRACT_ICON3",
"S_WHTV3", "S_ATTRACT_ICON4",
"S_WHTV4", "S_ATTRACT_ICON5",
"S_WHTV5",
"S_WHTV6",
"S_WHTV7",
// Water Shield Box "S_FORCE_ICON1",
"S_GRTV", "S_FORCE_ICON2",
"S_GRTV1", "S_FORCE_ICON3",
"S_GRTV2", "S_FORCE_ICON4",
"S_GRTV3", "S_FORCE_ICON5",
"S_GRTV4",
"S_GRTV5",
"S_GRTV6",
// Pity Shield Box "S_ARMAGEDDON_ICON1",
"S_PITV1", "S_ARMAGEDDON_ICON2",
"S_PITV2", "S_ARMAGEDDON_ICON3",
"S_PITV3", "S_ARMAGEDDON_ICON4",
"S_PITV4", "S_ARMAGEDDON_ICON5",
"S_PITV5",
"S_PITV6",
"S_PITV7",
// Eggman Box "S_WHIRLWIND_ICON1",
"S_EGGTV1", "S_WHIRLWIND_ICON2",
"S_EGGTV2", "S_WHIRLWIND_ICON3",
"S_EGGTV3", "S_WHIRLWIND_ICON4",
"S_EGGTV4", "S_WHIRLWIND_ICON5",
"S_EGGTV5",
"S_EGGTV6",
"S_EGGTV7",
// Teleport Box "S_ELEMENTAL_ICON1",
"S_MIXUPBOX1", "S_ELEMENTAL_ICON2",
"S_MIXUPBOX2", "S_ELEMENTAL_ICON3",
"S_MIXUPBOX3", "S_ELEMENTAL_ICON4",
"S_MIXUPBOX4", "S_ELEMENTAL_ICON5",
"S_MIXUPBOX5",
"S_MIXUPBOX6",
"S_MIXUPBOX7",
// Recycler Box "S_SNEAKERS_ICON1",
"S_RECYCLETV1", "S_SNEAKERS_ICON2",
"S_RECYCLETV2", "S_SNEAKERS_ICON3",
"S_RECYCLETV3", "S_SNEAKERS_ICON4",
"S_RECYCLETV4", "S_SNEAKERS_ICON5",
"S_RECYCLETV5",
"S_RECYCLETV6",
"S_RECYCLETV7",
// Question Box "S_INVULN_ICON1",
"S_RANDOMBOX1", "S_INVULN_ICON2",
"S_RANDOMBOX2", "S_INVULN_ICON3",
"S_RANDOMBOX3", "S_INVULN_ICON4",
"S_INVULN_ICON5",
// Gravity Boots Box "S_1UP_ICON1",
"S_GBTV1", "S_1UP_ICON2",
"S_GBTV2", "S_1UP_ICON3",
"S_GBTV3", "S_1UP_ICON4",
"S_GBTV4", "S_1UP_ICON5",
"S_GBTV5",
"S_GBTV6",
"S_GBTV7",
// Score boxes "S_EGGMAN_ICON1",
"S_SCORETVA1", "S_EGGMAN_ICON2",
"S_SCORETVA2", "S_EGGMAN_ICON3",
"S_SCORETVA3", "S_EGGMAN_ICON4",
"S_SCORETVA4", "S_EGGMAN_ICON5",
"S_SCORETVA5",
"S_SCORETVA6",
"S_SCORETVA7",
"S_SCORETVB1",
"S_SCORETVB2",
"S_SCORETVB3",
"S_SCORETVB4",
"S_SCORETVB5",
"S_SCORETVB6",
"S_SCORETVB7",
// Monitor Explosion "S_MIXUP_ICON1",
"S_MONITOREXPLOSION1", "S_MIXUP_ICON2",
"S_MONITOREXPLOSION2", "S_MIXUP_ICON3",
"S_MIXUP_ICON4",
"S_MIXUP_ICON5",
"S_REDMONITOREXPLOSION1", "S_GRAVITY_ICON1",
"S_REDMONITOREXPLOSION2", "S_GRAVITY_ICON2",
"S_GRAVITY_ICON3",
"S_GRAVITY_ICON4",
"S_GRAVITY_ICON5",
"S_BLUEMONITOREXPLOSION1", "S_RECYCLER_ICON1",
"S_BLUEMONITOREXPLOSION2", "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", "S_ROCKET",
@ -6760,47 +6762,68 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_BIGAIRMINE", "MT_BIGAIRMINE",
"MT_CANNONLAUNCHER", "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 // Monitor miscellany
"MT_MONITOREXPLOSION", "MT_BOXSPARKLE",
"MT_REDMONITOREXPLOSION",
"MT_BLUEMONITOREXPLOSION", // Monitor boxes -- regular
"MT_RINGICO", "MT_RING_BOX",
"MT_SHOESICO", "MT_PITY_BOX",
"MT_INVCICO", "MT_ATTRACT_BOX",
"MT_1UPICO", "MT_FORCE_BOX",
"MT_YSHIELDICO", "MT_ARMAGEDDON_BOX",
"MT_BSHIELDICO", "MT_WHIRLWIND_BOX",
"MT_KSHIELDICO", "MT_ELEMENTAL_BOX",
"MT_WSHIELDICO", "MT_SNEAKERS_BOX",
"MT_GSHIELDICO", "MT_INVULN_BOX",
"MT_PITYSHIELDICO", "MT_1UP_BOX",
"MT_EGGMANICO", "MT_EGGMAN_BOX",
"MT_MIXUPICO", "MT_MIXUP_BOX",
"MT_GRAVITYICO", "MT_MYSTERY_BOX",
"MT_SCOREICOSMALL", "MT_GRAVITY_BOX",
"MT_SCOREICOLARGE", "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 // Projectiles
"MT_ROCKET", "MT_ROCKET",

View File

@ -247,27 +247,30 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_BMNE &lspr[NOLIGHT], // SPR_BMNE
// Monitor Boxes // Monitor Boxes
&lspr[NOLIGHT], // SPR_SRBX &lspr[NOLIGHT], // SPR_MSTV
&lspr[NOLIGHT], // SPR_RRBX &lspr[NOLIGHT], // SPR_XLTV
&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
// Monitor Miscellany &lspr[NOLIGHT], // SPR_TRRI
&lspr[NOLIGHT], // SPR_MTEX &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 // Projectiles
&lspr[NOLIGHT], // SPR_MISL &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_Pain();
void A_Fall(); void A_Fall();
void A_MonitorPop(); void A_MonitorPop();
void A_BigMonitorPop();
void A_BigMonitorRestore();
void A_BigMonitorSparkle();
void A_Look(); void A_Look();
void A_Chase(); void A_Chase();
void A_FaceStabChase(); void A_FaceStabChase();
@ -324,27 +327,30 @@ typedef enum sprite
SPR_BMNE, // Big floating mine SPR_BMNE, // Big floating mine
// Monitor Boxes // Monitor Boxes
SPR_SRBX, SPR_MSTV, // MiSc TV sprites
SPR_RRBX, SPR_XLTV, // eXtra Large TV sprites
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
// Monitor Miscellany SPR_TRRI, // Red team: 10 RIngs
SPR_MTEX, // Exploding monitor 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 // Projectiles
SPR_MISL, SPR_MISL,
@ -1750,170 +1756,171 @@ typedef enum state
S_CANNONLAUNCHER2, S_CANNONLAUNCHER2,
S_CANNONLAUNCHER3, S_CANNONLAUNCHER3,
// Super Ring Box // Monitor Miscellany
S_SUPERRINGBOX, S_BOXSPARKLE1,
S_SUPERRINGBOX1, S_BOXSPARKLE2,
S_SUPERRINGBOX2, S_BOXSPARKLE3,
S_SUPERRINGBOX3,
S_SUPERRINGBOX4,
S_SUPERRINGBOX5,
S_SUPERRINGBOX6,
// Red Team Ring Box S_BOX_FLICKER,
S_REDRINGBOX, S_BOX_POP1,
S_REDRINGBOX1, S_BOX_POP2,
// Blue Team Ring Box S_BIGBOX_FLICKER,
S_BLUERINGBOX, S_BIGBOX_OFF1,
S_BLUERINGBOX1, S_BIGBOX_OFF2,
S_BIGBOX_OFF3,
S_BIGBOX_OFF4,
S_BIGBOX_OFF5,
S_BIGBOX_OFF6,
S_BIGBOX_OFF7,
// Super Sneakers Box // Monitor States (one per box)
S_SHTV, S_MYSTERY_BOX,
S_SHTV1, S_RING_BOX,
S_SHTV2, S_PITY_BOX,
S_SHTV3, S_ATTRACT_BOX,
S_SHTV4, S_FORCE_BOX,
S_SHTV5, S_ARMAGEDDON_BOX,
S_SHTV6, 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 // Repeat Monitor States (one per box)
S_PINV, S_MYSTERY_BIGBOX,
S_PINV1, S_RING_BIGBOX,
S_PINV2, S_PITY_BIGBOX,
S_PINV3, S_ATTRACT_BIGBOX,
S_PINV4, S_FORCE_BIGBOX,
S_PINV5, S_ARMAGEDDON_BIGBOX,
S_PINV6, 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 // Team Ring Boxes (these are special)
S_PRUP, S_RING_REDBOX1,
S_PRUP1, S_RING_REDBOX2,
S_PRUP2, S_REDBOX_POP1,
S_PRUP3, S_REDBOX_POP2,
S_PRUP4,
S_PRUP5,
S_PRUP6,
// Ring Shield Box S_RING_BLUEBOX1,
S_YLTV, S_RING_BLUEBOX2,
S_YLTV1, S_BLUEBOX_POP1,
S_YLTV2, S_BLUEBOX_POP2,
S_YLTV3,
S_YLTV4,
S_YLTV5,
S_YLTV6,
// Force Shield Box // Box Icons -- 5 states each, one for each part of the twirl
S_BLTV1, S_RING_ICON1,
S_BLTV2, S_RING_ICON2,
S_BLTV3, S_RING_ICON3,
S_BLTV4, S_RING_ICON4,
S_BLTV5, S_RING_ICON5,
S_BLTV6,
S_BLTV7,
// Bomb Shield Box S_PITY_ICON1,
S_BKTV1, S_PITY_ICON2,
S_BKTV2, S_PITY_ICON3,
S_BKTV3, S_PITY_ICON4,
S_BKTV4, S_PITY_ICON5,
S_BKTV5,
S_BKTV6,
S_BKTV7,
// Jump Shield Box S_ATTRACT_ICON1,
S_WHTV1, S_ATTRACT_ICON2,
S_WHTV2, S_ATTRACT_ICON3,
S_WHTV3, S_ATTRACT_ICON4,
S_WHTV4, S_ATTRACT_ICON5,
S_WHTV5,
S_WHTV6,
S_WHTV7,
// Water Shield Box S_FORCE_ICON1,
S_GRTV, S_FORCE_ICON2,
S_GRTV1, S_FORCE_ICON3,
S_GRTV2, S_FORCE_ICON4,
S_GRTV3, S_FORCE_ICON5,
S_GRTV4,
S_GRTV5,
S_GRTV6,
// Pity Shield Box S_ARMAGEDDON_ICON1,
S_PITV1, S_ARMAGEDDON_ICON2,
S_PITV2, S_ARMAGEDDON_ICON3,
S_PITV3, S_ARMAGEDDON_ICON4,
S_PITV4, S_ARMAGEDDON_ICON5,
S_PITV5,
S_PITV6,
S_PITV7,
// Eggman Box S_WHIRLWIND_ICON1,
S_EGGTV1, S_WHIRLWIND_ICON2,
S_EGGTV2, S_WHIRLWIND_ICON3,
S_EGGTV3, S_WHIRLWIND_ICON4,
S_EGGTV4, S_WHIRLWIND_ICON5,
S_EGGTV5,
S_EGGTV6,
S_EGGTV7,
// Teleport Box S_ELEMENTAL_ICON1,
S_MIXUPBOX1, S_ELEMENTAL_ICON2,
S_MIXUPBOX2, S_ELEMENTAL_ICON3,
S_MIXUPBOX3, S_ELEMENTAL_ICON4,
S_MIXUPBOX4, S_ELEMENTAL_ICON5,
S_MIXUPBOX5,
S_MIXUPBOX6,
S_MIXUPBOX7,
// Recycler Box S_SNEAKERS_ICON1,
S_RECYCLETV1, S_SNEAKERS_ICON2,
S_RECYCLETV2, S_SNEAKERS_ICON3,
S_RECYCLETV3, S_SNEAKERS_ICON4,
S_RECYCLETV4, S_SNEAKERS_ICON5,
S_RECYCLETV5,
S_RECYCLETV6,
S_RECYCLETV7,
// Question Box S_INVULN_ICON1,
S_RANDOMBOX1, S_INVULN_ICON2,
S_RANDOMBOX2, S_INVULN_ICON3,
S_RANDOMBOX3, S_INVULN_ICON4,
S_INVULN_ICON5,
// Gravity Boots Box S_1UP_ICON1,
S_GBTV1, S_1UP_ICON2,
S_GBTV2, S_1UP_ICON3,
S_GBTV3, S_1UP_ICON4,
S_GBTV4, S_1UP_ICON5,
S_GBTV5,
S_GBTV6,
S_GBTV7,
// Score boxes S_EGGMAN_ICON1,
S_SCORETVA1, S_EGGMAN_ICON2,
S_SCORETVA2, S_EGGMAN_ICON3,
S_SCORETVA3, S_EGGMAN_ICON4,
S_SCORETVA4, S_EGGMAN_ICON5,
S_SCORETVA5,
S_SCORETVA6,
S_SCORETVA7,
S_SCORETVB1,
S_SCORETVB2,
S_SCORETVB3,
S_SCORETVB4,
S_SCORETVB5,
S_SCORETVB6,
S_SCORETVB7,
// Monitor Explosion S_MIXUP_ICON1,
S_MONITOREXPLOSION1, S_MIXUP_ICON2,
S_MONITOREXPLOSION2, S_MIXUP_ICON3,
S_MIXUP_ICON4,
S_MIXUP_ICON5,
S_REDMONITOREXPLOSION1, S_GRAVITY_ICON1,
S_REDMONITOREXPLOSION2, S_GRAVITY_ICON2,
S_GRAVITY_ICON3,
S_GRAVITY_ICON4,
S_GRAVITY_ICON5,
S_BLUEMONITOREXPLOSION1, S_RECYCLER_ICON1,
S_BLUEMONITOREXPLOSION2, 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, S_ROCKET,
@ -3673,47 +3680,68 @@ typedef enum mobj_type
MT_BIGAIRMINE, MT_BIGAIRMINE,
MT_CANNONLAUNCHER, 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 // Monitor miscellany
MT_MONITOREXPLOSION, MT_BOXSPARKLE,
MT_REDMONITOREXPLOSION,
MT_BLUEMONITOREXPLOSION, // Monitor boxes -- regular
MT_RINGICO, MT_RING_BOX,
MT_SHOESICO, MT_PITY_BOX,
MT_INVCICO, MT_ATTRACT_BOX,
MT_1UPICO, MT_FORCE_BOX,
MT_YSHIELDICO, MT_ARMAGEDDON_BOX,
MT_BSHIELDICO, MT_WHIRLWIND_BOX,
MT_KSHIELDICO, MT_ELEMENTAL_BOX,
MT_WSHIELDICO, MT_SNEAKERS_BOX,
MT_GSHIELDICO, MT_INVULN_BOX,
MT_PITYSHIELDICO, MT_1UP_BOX,
MT_EGGMANICO, MT_EGGMAN_BOX,
MT_MIXUPICO, MT_MIXUP_BOX,
MT_GRAVITYICO, MT_MYSTERY_BOX,
MT_SCOREICOSMALL, MT_GRAVITY_BOX,
MT_SCOREICOLARGE, 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 // Projectiles
MT_ROCKET, MT_ROCKET,

View File

@ -818,6 +818,32 @@ static int P_RecycleCompare(const void *p1, const void *p2)
} }
#endif #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 // ACTION ROUTINES
// //
@ -2515,7 +2541,7 @@ void A_1upThinker(mobj_t *actor)
if (closestplayer == -1 || skins[players[closestplayer].skin].sprites[SPR2_LIFE].numframes == 0) 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. { // 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) { if (actor->tracer) {
P_RemoveMobj(actor->tracer); P_RemoveMobj(actor->tracer);
actor->tracer = NULL; actor->tracer = NULL;
@ -2543,139 +2569,194 @@ void A_1upThinker(mobj_t *actor)
// //
void A_MonitorPop(mobj_t *actor) void A_MonitorPop(mobj_t *actor)
{ {
mobj_t *remains;
mobjtype_t explode;
mobjtype_t item = 0; mobjtype_t item = 0;
mobjtype_t newbox; mobj_t *newmobj;
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
if (LUA_CallAction("A_MonitorPop", actor)) if (LUA_CallAction("A_MonitorPop", actor))
return; return;
#endif #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; actor->health = 0;
P_UnsetThingPosition(actor); P_UnsetThingPosition(actor);
actor->flags &= ~MF_SOLID; actor->flags &= ~MF_SOLID;
actor->flags |= MF_NOCLIP; actor->flags |= MF_NOCLIP;
P_SetThingPosition(actor); P_SetThingPosition(actor);
// Monitor explosion if (actor->info->damage == MT_UNKNOWN)
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)
{ {
remains->eflags |= MFE_VERTICALFLIP; // MT_UNKNOWN is random. Because it's unknown to us... get it?
remains->flags2 |= MF2_OBJECTFLIP; item = P_DoRandomBoxChances();
}
remains->destscale = actor->destscale;
P_SetScale(remains, actor->scale);
remains = P_SpawnMobj(actor->x, actor->y, if (item == MT_NULL)
((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!
{ {
mobjtype_t spawnchance[256]; CONS_Alert(CONS_WARNING, M_GetText("All monitors turned off.\n"));
INT32 numchoices = 0, i = 0; return;
#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);
}
} }
} }
else 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 // Function: A_Explode
@ -3160,8 +3241,8 @@ void A_ExtraLife(mobj_t *actor)
player = actor->target->player; player = actor->target->player;
if (actor->type == MT_1UPICO && !actor->tracer) if (actor->type == MT_1UP_ICON && !actor->tracer)
actor->frame -= 2; // No lives icon for this player, use the default. actor->sprite = SPR_TV1U; // No lives icon for this player, use the default.
if (ultimatemode) //I don't THINK so! 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) else switch (source->type)
{ {
case MT_EGGMANICO: case MT_EGGMAN_ICON:
case MT_EGGMANBOX:
str = M_GetText("%s was %s by Eggman's nefarious TV magic.\n"); str = M_GetText("%s was %s by Eggman's nefarious TV magic.\n");
break; break;
case MT_SPIKE: case MT_SPIKE:
@ -2766,10 +2765,10 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
if (!force) if (!force)
{ {
// Special case for team ring boxes // 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; return false;
if (target->type == MT_BLUERINGBOX && !(source->player->ctfteam == 2)) if (target->type == MT_RING_BLUEBOX && !(source->player->ctfteam == 2))
return false; 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_CheckDeathPitCollide(mobj_t *mo);
boolean P_CheckSolidLava(mobj_t *mo, ffloor_t *rover); 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_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_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); 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, // 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 // 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) 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 // z checking at last
// Treat noclip things as non-solid! // Treat noclip things as non-solid!

View File

@ -7258,9 +7258,60 @@ void P_MobjThinker(mobj_t *mobj)
mobj_t *flagmo, *newmobj; mobj_t *flagmo, *newmobj;
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
if (!LUAh_MobjFuse(mobj) && !P_MobjWasRemoved(mobj)) if (LUAh_MobjFuse(mobj) || P_MobjWasRemoved(mobj))
;
else
#endif #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 // gargoyle and snowman handled in P_PushableThinker, not here
case MT_THROWNGRENADE: case MT_THROWNGRENADE:
@ -7317,68 +7368,6 @@ void P_MobjThinker(mobj_t *mobj)
} }
P_RemoveMobj(mobj); P_RemoveMobj(mobj);
return; 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: case MT_METALSONIC_BATTLE:
break; // don't remove break; // don't remove
case MT_SPIKE: case MT_SPIKE:
@ -7395,6 +7384,7 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s
default: default:
P_SetMobjState(mobj, mobj->info->xdeathstate); // will remove the mobj if S_NULL. P_SetMobjState(mobj, mobj->info->xdeathstate); // will remove the mobj if S_NULL.
break; break;
// Looking for monitors? They moved to a special condition above.
} }
if (P_MobjWasRemoved(mobj)) if (P_MobjWasRemoved(mobj))
return; return;
@ -8805,9 +8795,9 @@ void P_SpawnMapThing(mapthing_t *mthing)
if ((mobjinfo[i].flags & MF_MONITOR) && cv_competitionboxes.value) // not Normal if ((mobjinfo[i].flags & MF_MONITOR) && cv_competitionboxes.value) // not Normal
{ {
if (cv_competitionboxes.value == 1) // Random if (cv_competitionboxes.value == 1) // Random
i = MT_QUESTIONBOX; i = MT_MYSTERY_BOX;
else if (cv_competitionboxes.value == 2) // Teleports else if (cv_competitionboxes.value == 2) // Teleports
i = MT_MIXUPBOX; i = MT_MIXUP_BOX;
else if (cv_competitionboxes.value == 3) // None else if (cv_competitionboxes.value == 3) // None
return; // Don't spawn! 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 ((mobjinfo[i].flags & MF_MONITOR) && cv_matchboxes.value) // not Normal
{ {
if (cv_matchboxes.value == 1) // Random if (cv_matchboxes.value == 1) // Random
i = MT_QUESTIONBOX; i = MT_MYSTERY_BOX;
else if (cv_matchboxes.value == 3) // Don't spawn else if (cv_matchboxes.value == 3) // Don't spawn
return; return;
else // cv_matchboxes.value == 2, Non-Random else // cv_matchboxes.value == 2, Non-Random
{ {
if (i == MT_QUESTIONBOX) if (i == MT_MYSTERY_BOX)
return; // don't spawn in Non-Random return; // don't spawn in Non-Random
mthing->options &= ~(MTF_AMBUSH|MTF_OBJECTSPECIAL); // no random respawning! 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) if (i == MT_BLUETEAMRING || i == MT_REDTEAMRING)
i = MT_RING; i = MT_RING;
else if (i == MT_BLUERINGBOX || i == MT_REDRINGBOX) else if (i == MT_RING_BLUEBOX || i == MT_RING_REDBOX)
i = MT_SUPERRINGBOX; i = MT_RING_BOX;
else if (i == MT_BLUEFLAG || i == MT_REDFLAG) else if (i == MT_BLUEFLAG || i == MT_REDFLAG)
return; // No flags in non-CTF modes! return; // No flags in non-CTF modes!
} }
@ -8864,23 +8854,27 @@ void P_SpawnMapThing(mapthing_t *mthing)
return; /// \todo return; /// \todo
// 1UPs -->> Score TVs // 1UPs -->> Score TVs
else if (i == MT_PRUP) // 1UP else if (i == MT_1UP_BOX) // 1UP
{ {
// Either or, doesn't matter which. // Either or, doesn't matter which.
if (mthing->options & (MTF_AMBUSH|MTF_OBJECTSPECIAL)) if (mthing->options & (MTF_AMBUSH|MTF_OBJECTSPECIAL))
i = MT_SCORETVLARGE; // 10,000 i = MT_SCORE10K_BOX; // 10,000
else else
i = MT_SCORETVSMALL; // 1,000 i = MT_SCORE1K_BOX; // 1,000
} }
} }
if (ultimatemode) 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 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) 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++))) 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. //count 10 ring boxes into the number of rings equation too.
if (i == MT_SUPERRINGBOX) if (i == MT_RING_BOX)
nummaprings += 10; nummaprings += 10;
if (i == MT_RING_BIGBOX) // Theoretically infinite
nummaprings += 10000;
if (i == MT_BIGTUMBLEWEED || i == MT_LITTLETUMBLEWEED) if (i == MT_BIGTUMBLEWEED || i == MT_LITTLETUMBLEWEED)
{ {
@ -9385,16 +9381,11 @@ ML_NOCLIMB : Direction not controllable
mobj->flags2 |= MF2_STANDONME; mobj->flags2 |= MF2_STANDONME;
} }
if (mobj->flags & MF_MONITOR) if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0)
{ {
// flag for strong/weak random boxes // flag for strong/weak random boxes
if (mthing->type == mobjinfo[MT_SUPERRINGBOX].doomednum || mthing->type == mobjinfo[MT_PRUP].doomednum || // any monitor with nonzero speed is allowed to respawn like this
mthing->type == mobjinfo[MT_SNEAKERTV].doomednum || mthing->type == mobjinfo[MT_INV].doomednum || mobj->flags |= MF_AMBUSH;
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;
} }
else if (mthing->type != mobjinfo[MT_AXIS].doomednum && else if (mthing->type != mobjinfo[MT_AXIS].doomednum &&
@ -9407,14 +9398,12 @@ ML_NOCLIMB : Direction not controllable
if (mthing->options & MTF_OBJECTSPECIAL) if (mthing->options & MTF_OBJECTSPECIAL)
{ {
// flag for strong/weak random boxes if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0)
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 || // flag for strong/weak random boxes
mthing->type == mobjinfo[MT_WHITETV].doomednum || mthing->type == mobjinfo[MT_GREENTV].doomednum || // any monitor with nonzero speed is allowed to respawn like this
mthing->type == mobjinfo[MT_YELLOWTV].doomednum || mthing->type == mobjinfo[MT_BLUETV].doomednum || mobj->flags2 |= MF2_STRONGBOX;
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;
// Requires you to be in bonus time to activate // Requires you to be in bonus time to activate
if (mobj->flags & MF_NIGHTSITEM) if (mobj->flags & MF_NIGHTSITEM)
@ -10411,3 +10400,35 @@ void P_FlashPal(player_t *pl, UINT16 type, UINT16 duration)
pl->flashcount = duration; pl->flashcount = duration;
pl->flashpal = type; 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 >= 3 || player->pity < 0) && player->powers[pw_shield] == SH_NONE)
{ {
if (player->pity > 0) 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->pity = 0;
player->powers[pw_shield] = SH_PITY; 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}, {"lvpass", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR},
{"mindig", false, 8, 64, -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}, {"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}, {"pogo" , false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR},
{"pop" , false, 78, 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}, {"rail1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR},

View File

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