diff --git a/src/d_player.h b/src/d_player.h index e68992e15..cdc899f5e 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -232,7 +232,8 @@ typedef enum // Specific level gimmicks. CR_ZOOMTUBE, CR_ROPEHANG, - CR_MACESPIN + CR_MACESPIN, + CR_MINECART } carrytype_t; // pw_carry // Player powers. (don't edit this comment) diff --git a/src/dehacked.c b/src/dehacked.c index 6d1f58990..f70615af6 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -2265,6 +2265,9 @@ static actionpointer_t actionpointers[] = {{A_CrushclawLaunch}, "A_CRUSHCLAWLAUNCH"}, {{A_VultureVtol}, "A_VULTUREVTOL"}, {{A_VultureCheck}, "A_VULTURECHECK"}, + {{A_VultureHover}, "A_VULTUREHOVER"}, + {{A_VultureBlast}, "A_VULTUREBLAST"}, + {{A_VultureFly}, "A_VULTUREFLY"}, {{A_SkimChase}, "A_SKIMCHASE"}, {{A_1upThinker}, "A_1UPTHINKER"}, {{A_SkullAttack}, "A_SKULLATTACK"}, @@ -2393,8 +2396,18 @@ static actionpointer_t actionpointers[] = {{A_Boss5MakeItRain}, "A_BOSS5MAKEITRAIN"}, {{A_LookForBetter}, "A_LOOKFORBETTER"}, {{A_Boss5BombExplode}, "A_BOSS5BOMBEXPLODE"}, - - {{NULL}, "NONE"}, + {{A_DustDevilThink}, "A_DUSTDEVILTHINK"}, + {{A_TNTExplode}, "A_TNTEXPLODE"}, + {{A_DebrisRandom}, "A_DEBRISRANDOM"}, + {{A_TrainCameo}, "A_TRAINCAMEO"}, + {{A_TrainCameo2}, "A_TRAINCAMEO2"}, + {{A_CanarivoreGas}, "A_CANARIVOREGAS"}, + {{A_KillSegments}, "A_KILLSEGMENTS"}, + {{A_SnapperSpawn}, "A_SNAPPERSPAWN"}, + {{A_SnapperThinker}, "A_SNAPPERTHINKER"}, + {{A_SaloonDoorSpawn}, "A_SALOONDOORSPAWN"}, + {{A_MinecartSparkThink}, "A_MINECARTSPARKTHINK"}, + {{NULL}, "NONE"}, // This NULL entry must be the last in the list {{NULL}, NULL}, @@ -4381,15 +4394,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // Vulture "S_VULTURE_STND", - "S_VULTURE_VTOL1", - "S_VULTURE_VTOL2", - "S_VULTURE_VTOL3", - "S_VULTURE_VTOL4", + "S_VULTURE_DRIFT", "S_VULTURE_ZOOM1", "S_VULTURE_ZOOM2", - "S_VULTURE_ZOOM3", - "S_VULTURE_ZOOM4", - "S_VULTURE_ZOOM5", + "S_VULTURE_STUNNED", // Pointy "S_POINTY1", @@ -4440,15 +4448,31 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_EGGSHIELDBREAK", // Green Snapper + "S_SNAPPER_SPAWN", + "S_SNAPPER_SPAWN2", "S_GSNAPPER_STND", "S_GSNAPPER1", "S_GSNAPPER2", "S_GSNAPPER3", "S_GSNAPPER4", + "S_SNAPPER_XPLD", + "S_SNAPPER_LEG", + "S_SNAPPER_LEGRAISE", + "S_SNAPPER_HEAD", // Minus + "S_MINUS_INIT", "S_MINUS_STND", - "S_MINUS_DIGGING", + "S_MINUS_DIGGING1", + "S_MINUS_DIGGING2", + "S_MINUS_DIGGING3", + "S_MINUS_DIGGING4", + "S_MINUS_BURST0", + "S_MINUS_BURST1", + "S_MINUS_BURST2", + "S_MINUS_BURST3", + "S_MINUS_BURST4", + "S_MINUS_BURST5", "S_MINUS_POPUP", "S_MINUS_UPWARD1", "S_MINUS_UPWARD2", @@ -4467,6 +4491,15 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_MINUS_DOWNWARD7", "S_MINUS_DOWNWARD8", + // Minus dirt + "S_MINUSDIRT1", + "S_MINUSDIRT2", + "S_MINUSDIRT3", + "S_MINUSDIRT4", + "S_MINUSDIRT5", + "S_MINUSDIRT6", + "S_MINUSDIRT7", + // Spring Shell "S_SSHELL_STND", "S_SSHELL_RUN1", @@ -4494,6 +4527,28 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_UNIDUS_RUN", "S_UNIDUS_BALL", + // Canarivore + "S_CANARIVORE_LOOK", + "S_CANARIVORE_AWAKEN1", + "S_CANARIVORE_AWAKEN2", + "S_CANARIVORE_AWAKEN3", + "S_CANARIVORE_GAS1", + "S_CANARIVORE_GAS2", + "S_CANARIVORE_GAS3", + "S_CANARIVORE_GAS4", + "S_CANARIVORE_GAS5", + "S_CANARIVORE_GASREPEAT", + "S_CANARIVORE_CLOSE1", + "S_CANARIVORE_CLOSE2", + "S_CANARIVOREGAS_1", + "S_CANARIVOREGAS_2", + "S_CANARIVOREGAS_3", + "S_CANARIVOREGAS_4", + "S_CANARIVOREGAS_5", + "S_CANARIVOREGAS_6", + "S_CANARIVOREGAS_7", + "S_CANARIVOREGAS_8", + // Boss Explosion "S_BOSSEXPLODE", @@ -5681,6 +5736,85 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_ARIDSIGN_CACTI", "S_ARIDSIGN_SHARPTURN", + // Oil lamp + "S_OILLAMP", + "S_OILLAMPFLARE", + + // TNT barrel + "S_TNTBARREL_STND1", + "S_TNTBARREL_EXPL1", + "S_TNTBARREL_EXPL2", + "S_TNTBARREL_EXPL3", + "S_TNTBARREL_EXPL4", + "S_TNTBARREL_EXPL5", + "S_TNTBARREL_EXPL6", + "S_TNTBARREL_FLYING", + + // TNT proximity shell + "S_PROXIMITY_TNT", + "S_PROXIMITY_TNT_TRIGGER1", + "S_PROXIMITY_TNT_TRIGGER2", + "S_PROXIMITY_TNT_TRIGGER3", + "S_PROXIMITY_TNT_TRIGGER4", + "S_PROXIMITY_TNT_TRIGGER5", + "S_PROXIMITY_TNT_TRIGGER6", + "S_PROXIMITY_TNT_TRIGGER7", + "S_PROXIMITY_TNT_TRIGGER8", + "S_PROXIMITY_TNT_TRIGGER9", + "S_PROXIMITY_TNT_TRIGGER10", + "S_PROXIMITY_TNT_TRIGGER11", + "S_PROXIMITY_TNT_TRIGGER12", + "S_PROXIMITY_TNT_TRIGGER13", + "S_PROXIMITY_TNT_TRIGGER14", + "S_PROXIMITY_TNT_TRIGGER15", + "S_PROXIMITY_TNT_TRIGGER16", + "S_PROXIMITY_TNT_TRIGGER17", + "S_PROXIMITY_TNT_TRIGGER18", + "S_PROXIMITY_TNT_TRIGGER19", + "S_PROXIMITY_TNT_TRIGGER20", + "S_PROXIMITY_TNT_TRIGGER21", + "S_PROXIMITY_TNT_TRIGGER22", + "S_PROXIMITY_TNT_TRIGGER23", + + // Dust devil + "S_DUSTDEVIL", + "S_DUSTLAYER1", + "S_DUSTLAYER2", + "S_DUSTLAYER3", + "S_DUSTLAYER4", + "S_DUSTLAYER5", + "S_ARIDDUST1", + "S_ARIDDUST2", + "S_ARIDDUST3", + + // Minecart + "S_MINECART_IDLE", + "S_MINECART_DTH1", + "S_MINECARTEND", + "S_MINECARTSEG_FRONT", + "S_MINECARTSEG_BACK", + "S_MINECARTSEG_LEFT", + "S_MINECARTSEG_RIGHT", + "S_MINECARTSIDEMARK1", + "S_MINECARTSIDEMARK2", + "S_MINECARTSPARK", + + // Saloon door + "S_SALOONDOOR", + "S_SALOONDOORTHINKER", + + // Train cameo + "S_TRAINCAMEOSPAWNER_1", + "S_TRAINCAMEOSPAWNER_2", + "S_TRAINCAMEOSPAWNER_3", + "S_TRAINCAMEOSPAWNER_4", + "S_TRAINCAMEOSPAWNER_5", + "S_TRAINPUFFMAKER", + + // Train + "S_TRAINDUST", + "S_TRAINSTEAM", + // Flame jet "S_FLAMEJETSTND", "S_FLAMEJETSTART", @@ -7003,6 +7137,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_DUST3", "S_DUST4", + "S_WOODDEBRIS", + "S_ROCKSPAWN", "S_ROCKCRUMBLEA", @@ -7066,11 +7202,16 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_EGGGUARD", // Egg Guard "MT_EGGSHIELD", // Egg Guard's shield "MT_GSNAPPER", // Green Snapper + "MT_SNAPPER_LEG", // Green Snapper leg + "MT_SNAPPER_HEAD", // Green Snapper head "MT_MINUS", // Minus + "MT_MINUSDIRT", // Minus dirt "MT_SPRINGSHELL", // Spring Shell "MT_YELLOWSHELL", // Spring Shell (yellow) "MT_UNIDUS", // Unidus "MT_UNIBALL", // Unidus Ball + "MT_CANARIVORE", // Canarivore + "MT_CANARIVORE_GAS", // Canarivore gas // Generic Boss Items "MT_BOSSEXPLODE", @@ -7369,6 +7510,26 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_ARIDSIGN_CAUTION", "MT_ARIDSIGN_CACTI", "MT_ARIDSIGN_SHARPTURN", + "MT_OILLAMP", + "MT_TNTBARREL", + "MT_PROXIMITYTNT", + "MT_DUSTDEVIL", + "MT_DUSTLAYER", + "MT_ARIDDUST", + "MT_MINECART", + "MT_MINECARTSEG", + "MT_MINECARTSPAWNER", + "MT_MINECARTEND", + "MT_MINECARTENDSOLID", + "MT_MINECARTSIDEMARK", + "MT_MINECARTSPARK", + "MT_SALOONDOOR", + "MT_SALOONDOORTHINKER", + "MT_TRAINCAMEOSPAWNER", + "MT_TRAINSEG", + "MT_TRAINDUSTSPAWNER", + "MT_TRAINSTEAMSPAWNER", + "MT_MINECARTSWITCHPOINT", // Red Volcano Scenery "MT_FLAMEJET", @@ -7691,6 +7852,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_EXPLODE", // Robot Explosion "MT_UWEXPLODE", // Underwater Explosion "MT_DUST", + "MT_WOODDEBRIS", "MT_ROCKSPAWNER", "MT_FALLINGROCK", "MT_ROCKCRUMBLE1", @@ -8366,6 +8528,7 @@ struct { {"CR_ZOOMTUBE",CR_ZOOMTUBE}, {"CR_ROPEHANG",CR_ROPEHANG}, {"CR_MACESPIN",CR_MACESPIN}, + {"CR_MINECART",CR_MINECART}, // Ring weapons (ringweapons_t) // Useful for A_GiveWeapon diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index 90d02fdf8..8baa547af 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -172,9 +172,14 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_SPSH &lspr[NOLIGHT], // SPR_ESHI &lspr[NOLIGHT], // SPR_GSNP + &lspr[NOLIGHT], // SPR_GSNL + &lspr[NOLIGHT], // SPR_GSNH &lspr[NOLIGHT], // SPR_MNUS + &lspr[NOLIGHT], // SPR_MNUD &lspr[NOLIGHT], // SPR_SSHL &lspr[NOLIGHT], // SPR_UNID + &lspr[NOLIGHT], // SPR_CANA + &lspr[NOLIGHT], // SPR_CANG // Generic Boos Items &lspr[JETLIGHT_L], // SPR_JETF // Boss jet fumes @@ -350,6 +355,19 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_WWSG &lspr[NOLIGHT], // SPR_WWS2 &lspr[NOLIGHT], // SPR_WWS3 + &lspr[NOLIGHT], // SPR_OILL + &lspr[NOLIGHT], // SPR_OILF + &lspr[NOLIGHT], // SPR_BARR + &lspr[NOLIGHT], // SPR_REMT + &lspr[NOLIGHT], // SPR_TAZD + &lspr[NOLIGHT], // SPR_ADST + &lspr[NOLIGHT], // SPR_MCRT + &lspr[NOLIGHT], // SPR_MCSP + &lspr[NOLIGHT], // SPR_NON2 + &lspr[NOLIGHT], // SPR_SALD + &lspr[NOLIGHT], // SPR_TRAE + &lspr[NOLIGHT], // SPR_TRAI + &lspr[NOLIGHT], // SPR_STEA // Red Volcano Scenery &lspr[REDBALL_L], // SPR_FLME @@ -542,6 +560,7 @@ light_t *t_lspr[NUMSPRITES] = &lspr[SUPERSPARK_L], // SPR_BOM3 &lspr[NOLIGHT], // SPR_BOM4 &lspr[REDBALL_L], // SPR_BMNB + &lspr[NOLIGHT], // SPR_WDDB // Crumbly rocks &lspr[NOLIGHT], // SPR_ROIA diff --git a/src/info.c b/src/info.c index e03b63a65..a585da74e 100644 --- a/src/info.c +++ b/src/info.c @@ -60,9 +60,14 @@ char sprnames[NUMSPRITES + 1][5] = "SPSH", // Egg Guard "ESHI", // Egg Guard's shield "GSNP", // Green Snapper + "GSNL", // Green Snapper leg + "GSNH", // Green Snapper head "MNUS", // Minus + "MNUD", // Minus dirt "SSHL", // Spring Shell "UNID", // Unidus + "CANA", // Canarivore + "CANG", // Canarivore gas // Generic Boss Items "JETF", // Boss jet fumes @@ -245,6 +250,19 @@ char sprnames[NUMSPRITES + 1][5] = "WWSG", // Caution Sign "WWS2", // Cacti Sign "WWS3", // Sharp Turn Sign + "OILL", // Oil lamp + "OILF", // Oil lamp flare + "BARR", // TNT barrel + "REMT", // TNT proximity shell + "TAZD", // Dust devil + "ADST", // Arid dust + "MCRT", // Minecart + "MCSP", // Minecart spark + "NON2", // Saloon door thinker + "SALD", // Saloon door + "TRAE", // Train cameo locomotive + "TRAI", // Train cameo wagon + "STEA", // Train steam // Red Volcano Scenery "FLME", // Flame jet @@ -437,6 +455,7 @@ char sprnames[NUMSPRITES + 1][5] = "BOM3", // Boss Explosion 2 "BOM4", // Underwater Explosion "BMNB", // Mine Explosion + "WDDB", // Wood Debris // Crumbly rocks "ROIA", @@ -984,16 +1003,11 @@ state_t states[NUMSTATES] = {SPR_SNLR, 0, 1, {A_SnailerThink}, 0, 0, S_SNAILER1}, // S_SNAILER1 // Vulture - {SPR_VLTR, 4, 35, {A_Look}, 1, 0, S_VULTURE_STND}, // S_VULTURE_STND - {SPR_VLTR, 4, 1, {A_VultureVtol}, 0, 0, S_VULTURE_VTOL2}, // S_VULTURE_VTOL1 - {SPR_VLTR, 5, 1, {A_VultureVtol}, 0, 0, S_VULTURE_VTOL3}, // S_VULTURE_VTOL2 - {SPR_VLTR, 6, 1, {A_VultureVtol}, 0, 0, S_VULTURE_VTOL4}, // S_VULTURE_VTOL3 - {SPR_VLTR, 7, 1, {A_VultureVtol}, 0, 0, S_VULTURE_VTOL1}, // S_VULTURE_VTOL4 - {SPR_VLTR, 0, 1, {A_Thrust}, 30, 1, S_VULTURE_ZOOM2}, // S_VULTURE_ZOOM1 - {SPR_VLTR, 0, 1, {A_VultureCheck}, 0, 0, S_VULTURE_ZOOM3}, // S_VULTURE_ZOOM2 - {SPR_VLTR, 1, 1, {A_VultureCheck}, 0, 0, S_VULTURE_ZOOM4}, // S_VULTURE_ZOOM3 - {SPR_VLTR, 2, 1, {A_VultureCheck}, 0, 0, S_VULTURE_ZOOM5}, // S_VULTURE_ZOOM4 - {SPR_VLTR, 3, 1, {A_VultureCheck}, 0, 0, S_VULTURE_ZOOM2}, // S_VULTURE_ZOOM5 + {SPR_VLTR, 4, 35, {A_Look}, 1, 0, S_VULTURE_STND}, // S_VULTURE_STND + {SPR_VLTR, 4, 3, {A_VultureHover}, 0, 0, S_VULTURE_DRIFT}, // S_VULTURE_DRIFT + {SPR_VLTR, 0, 6, {A_VultureBlast}, 0, 0, S_VULTURE_ZOOM2}, // S_VULTURE_ZOOM1 + {SPR_VLTR, 0, 3, {A_VultureFly}, 0, 0, S_VULTURE_ZOOM2}, // S_VULTURE_ZOOM2 + {SPR_VLTR, 0, 3*TICRATE, {NULL}, 0, 0, S_VULTURE_DRIFT}, // S_VULTURE_STUNNED // Pointy {SPR_PNTY, 0, 1, {A_PointyThink}, 0, 0, S_POINTY1}, // S_POINTY1 @@ -1046,15 +1060,31 @@ state_t states[NUMSTATES] = {SPR_ESHI, 0, TICRATE/2, {NULL}, 0, 0, S_NULL}, // S_EGGSHIELDBREAK // Green Snapper - {SPR_GSNP, 0, 1, {A_Look}, 0, 0, S_GSNAPPER_STND}, // S_GSNAPPER_STND - {SPR_GSNP, 0, 2, {A_Chase}, 0, 0, S_GSNAPPER2}, // S_GSNAPPER1 - {SPR_GSNP, 1, 2, {A_Chase}, 0, 0, S_GSNAPPER3}, // S_GSNAPPER2 - {SPR_GSNP, 2, 2, {A_Chase}, 0, 0, S_GSNAPPER4}, // S_GSNAPPER3 - {SPR_GSNP, 3, 2, {A_Chase}, 0, 0, S_GSNAPPER1}, // S_GSNAPPER4 + {SPR_GSNP, 0, TICRATE, {NULL}, 0, 0, S_SNAPPER_SPAWN2}, // S_SNAPPER_SPAWN + {SPR_GSNP, 0, 2, {A_SnapperSpawn}, MT_SNAPPER_LEG, MT_SNAPPER_HEAD, S_GSNAPPER_STND}, // S_SNAPPER_SPAWN2 + {SPR_GSNP, 0, 1, {A_SnapperThinker}, 0, 0, S_GSNAPPER_STND}, // S_GSNAPPER_STND + {SPR_GSNP, 0, 2, {A_Chase}, 0, 0, S_GSNAPPER2}, // S_GSNAPPER1 + {SPR_GSNP, 1, 2, {A_Chase}, 0, 0, S_GSNAPPER3}, // S_GSNAPPER2 + {SPR_GSNP, 2, 2, {A_Chase}, 0, 0, S_GSNAPPER4}, // S_GSNAPPER3 + {SPR_GSNP, 3, 2, {A_Chase}, 0, 0, S_GSNAPPER1}, // S_GSNAPPER4 + {SPR_GSNP, 0, 0, {A_KillSegments}, 0, 0, S_XPLD_FLICKY}, // S_SNAPPER_XPLD + {SPR_GSNL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SNAPPER_LEG + {SPR_GSNL, 1, -1, {NULL}, 0, 0, S_NULL}, // S_SNAPPER_LEGRAISE + {SPR_GSNH, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SNAPPER_HEAD // Minus - {SPR_NULL, 0, 1, {A_Look}, 0, 0, S_MINUS_STND}, // S_MINUS_STND - {SPR_MNUS, 16, 1, {A_MinusDigging}, 0, 0, S_MINUS_DIGGING}, // S_MINUS_DIGGING + {SPR_MNUD, 0, 1, {NULL}, 0, 0, S_MINUS_STND}, // S_MINUS_INIT (required for objectplace to work) + {SPR_NULL, 0, 10, {A_Look}, 0, 0, S_MINUS_STND}, // S_MINUS_STND + {SPR_NULL, 0, 1, {A_MinusDigging}, 1, 0, S_MINUS_DIGGING2}, // S_MINUS_DIGGING1 + {SPR_NULL, 0, 1, {A_MinusDigging}, 0, 0, S_MINUS_DIGGING3}, // S_MINUS_DIGGING2 + {SPR_NULL, 0, 1, {A_MinusDigging}, 0, 0, S_MINUS_DIGGING4}, // S_MINUS_DIGGING3 + {SPR_NULL, 0, 1, {A_MinusDigging}, 0, 0, S_MINUS_DIGGING1}, // S_MINUS_DIGGING4 + {SPR_NULL, 0, 25, {NULL}, 0, 0, S_MINUS_POPUP}, // S_MINUS_BURST0 + {SPR_MNUD, FF_ANIMATE, 5, {NULL}, 1, 2, S_MINUS_BURST2}, // S_MINUS_BURST1 + {SPR_MNUD, 1|FF_ANIMATE, 5, {NULL}, 1, 2, S_MINUS_BURST3}, // S_MINUS_BURST2 + {SPR_MNUD, 2|FF_ANIMATE, 5, {NULL}, 1, 2, S_MINUS_BURST4}, // S_MINUS_BURST3 + {SPR_MNUD, 3|FF_ANIMATE, 5, {NULL}, 1, 2, S_MINUS_BURST5}, // S_MINUS_BURST4 + {SPR_MNUD, 4|FF_ANIMATE, 5, {NULL}, 1, 2, S_MINUSDIRT2}, // S_MINUS_BURST5 {SPR_MNUS, 0, 1, {A_MinusPopup}, 0, 0, S_MINUS_UPWARD1}, // S_MINUS_POPUP {SPR_MNUS, 0, 1, {A_MinusCheck}, 0, 0, S_MINUS_UPWARD2}, // S_MINUS_UPWARD1 {SPR_MNUS, 1, 1, {A_MinusCheck}, 0, 0, S_MINUS_UPWARD3}, // S_MINUS_UPWARD2 @@ -1073,6 +1103,14 @@ state_t states[NUMSTATES] = {SPR_MNUS, 14, 1, {A_MinusCheck}, 0, 0, S_MINUS_DOWNWARD8}, // S_MINUS_DOWNWARD7 {SPR_MNUS, 15, 1, {A_MinusCheck}, 0, 0, S_MINUS_DOWNWARD1}, // S_MINUS_DOWNWARD8 + {SPR_MNUD, FF_ANIMATE, 6, {NULL}, 1, 5, S_MINUSDIRT2}, // S_MINUSDIRT1 + {SPR_MNUD, 5, 8, {NULL}, 3, 5, S_MINUSDIRT3}, // S_MINUSDIRT2 + {SPR_MNUD, 4, 8, {NULL}, 3, 5, S_MINUSDIRT4}, // S_MINUSDIRT3 + {SPR_MNUD, 3, 8, {NULL}, 3, 5, S_MINUSDIRT5}, // S_MINUSDIRT4 + {SPR_MNUD, 2, 8, {NULL}, 3, 5, S_MINUSDIRT6}, // S_MINUSDIRT5 + {SPR_MNUD, 1, 8, {NULL}, 3, 5, S_MINUSDIRT7}, // S_MINUSDIRT6 + {SPR_MNUD, 0, 8, {NULL}, 3, 5, S_NULL}, // S_MINUSDIRT7 + // Spring Shell {SPR_SSHL, 0, 4, {A_Look}, 0, 0, S_SSHELL_STND}, // S_SSHELL_STND {SPR_SSHL, 0, 4, {A_Chase}, 0, 0, S_SSHELL_RUN2}, // S_SSHELL_RUN1 @@ -1100,6 +1138,29 @@ state_t states[NUMSTATES] = {SPR_UNID, 0, 1, {A_Chase}, 0, 0, S_UNIDUS_RUN }, // S_UNIDUS_RUN {SPR_UNID, 1, 1, {A_UnidusBall}, 1, 0, S_UNIDUS_BALL}, // S_UNIDUS_BALL + // Canarivore + {SPR_CANA, 0, 5, {A_Look}, 1200*FRACUNIT+1, 1, S_CANARIVORE_LOOK}, // S_CANARIVORE_LOOK + {SPR_CANA, 0, 3, {A_PlaySound}, sfx_s3k76, 1, S_CANARIVORE_AWAKEN2}, // S_CANARIVORE_AWAKEN1 + {SPR_CANA, 1, 5, {NULL}, 0, 0, S_CANARIVORE_AWAKEN3}, // S_CANARIVORE_AWAKEN2 + {SPR_CANA, 2, 8, {NULL}, 0, 0, S_CANARIVORE_GAS1}, // S_CANARIVORE_AWAKEN3 + {SPR_CANA, 2, 15, {A_PlaySound}, sfx_s3k93, 1, S_CANARIVORE_GAS2}, // S_CANARIVORE_GAS1 + {SPR_CANA, 1, 4, {NULL}, 0, 0, S_CANARIVORE_GAS3}, // S_CANARIVORE_GAS2 + {SPR_CANA, 2, 0, {A_PlaySound}, sfx_s3k97, 1, S_CANARIVORE_GAS4}, // S_CANARIVORE_GAS3 + {SPR_CANA, 2, 5, {A_CanarivoreGas}, MT_CANARIVORE_GAS, 0, S_CANARIVORE_GAS5}, // S_CANARIVORE_GAS4 + {SPR_CANA, 1, 5, {NULL}, 0, 0, S_CANARIVORE_GASREPEAT}, // S_CANARIVORE_GAS5 + {SPR_CANA, 2, 0, {A_Repeat}, 6, S_CANARIVORE_GAS4, S_CANARIVORE_CLOSE1}, // S_CANARIVORE_GASREPEAT + {SPR_CANA, 1, 8, {NULL}, 0, 0, S_CANARIVORE_CLOSE2}, // S_CANARIVORE_CLOSE1 + {SPR_CANA, 0, 90, {NULL}, sfx_s3k5d, 1, S_CANARIVORE_LOOK}, // S_CANARIVORE_CLOSE2 + + {SPR_CANG, 0|FF_TRANS90, 2, {NULL}, 0, 0, S_CANARIVOREGAS_2}, // S_CANARIVOREGAS_1 + {SPR_CANG, 0|FF_TRANS30, 2*TICRATE, {A_SetRandomTics}, 2, TICRATE, S_CANARIVOREGAS_3}, // S_CANARIVOREGAS_2 + {SPR_CANG, 0|FF_TRANS40, 10, {NULL}, 0, 0, S_CANARIVOREGAS_4}, // S_CANARIVOREGAS_3 + {SPR_CANG, 0|FF_TRANS50, 10, {NULL}, 0, 0, S_CANARIVOREGAS_5}, // S_CANARIVOREGAS_4 + {SPR_CANG, 0|FF_TRANS60, 10, {NULL}, 0, 0, S_CANARIVOREGAS_6}, // S_CANARIVOREGAS_5 + {SPR_CANG, 0|FF_TRANS70, 10, {NULL}, 0, 0, S_CANARIVOREGAS_7}, // S_CANARIVOREGAS_6 + {SPR_CANG, 0|FF_TRANS80, 10, {NULL}, 0, 0, S_CANARIVOREGAS_8}, // S_CANARIVOREGAS_7 + {SPR_CANG, 0|FF_TRANS90, 10, {NULL}, 0, 0, S_NULL}, // S_CANARIVOREGAS_8 + // Boss Explosion {SPR_BOM2, FF_FULLBRIGHT|FF_ANIMATE, (5*7), {NULL}, 6, 5, S_NULL}, // S_BOSSEXPLODE @@ -2315,6 +2376,84 @@ state_t states[NUMSTATES] = {SPR_WWS2, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_ARIDSIGN_CACTI {SPR_WWS3, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_ARIDSIGN_SHARPTURN + // Oil lamp + {SPR_OILL, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_OILLAMP + {SPR_OILF, FF_TRANS90|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_OILLAMPFLARE + + // TNT barrel + {SPR_BARR, 0, -1, {NULL}, 0, 0, S_NULL}, // S_TNTBARREL_STND1 + {SPR_BARX, 0|FF_FULLBRIGHT, 3, {A_SetObjectFlags}, MF_NOCLIP|MF_NOGRAVITY|MF_NOBLOCKMAP, 0, S_TNTBARREL_EXPL2}, // S_TNTBARREL_EXPL1 + {SPR_BARX, 1|FF_FULLBRIGHT, 2, {A_TNTExplode}, MT_TNTDUST, 0, S_TNTBARREL_EXPL3}, // S_TNTBARREL_EXPL2 + {SPR_BARX, 1|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_TNTBARREL_EXPL4}, // S_TNTBARREL_EXPL3 + {SPR_BARX, 2|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_TNTBARREL_EXPL5}, // S_TNTBARREL_EXPL4 + {SPR_BARX, 3|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_TNTBARREL_EXPL6}, // S_TNTBARREL_EXPL5 + {SPR_NULL, 0, 35, {NULL}, 0, 0, S_NULL}, // S_TNTBARREL_EXPL6 + {SPR_BARR, 1|FF_ANIMATE, -1, {NULL}, 7, 2, S_NULL}, // S_TNTBARREL_FLYING + + // TNT proximity shell + {SPR_REMT, 0, 10, {A_Look}, 33554433, 0, S_PROXIMITY_TNT}, // S_PROXIMITY_TNT + {SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER2}, // S_PROXIMITY_TNT_TRIGGER1 + {SPR_REMT, 0, 16, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER3}, // S_PROXIMITY_TNT_TRIGGER2 + {SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER4}, // S_PROXIMITY_TNT_TRIGGER3 + {SPR_REMT, 0, 16, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER5}, // S_PROXIMITY_TNT_TRIGGER4 + {SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER6}, // S_PROXIMITY_TNT_TRIGGER5 + {SPR_REMT, 0, 4, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER7}, // S_PROXIMITY_TNT_TRIGGER6 + {SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER8}, // S_PROXIMITY_TNT_TRIGGER7 + {SPR_REMT, 0, 4, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER9}, // S_PROXIMITY_TNT_TRIGGER8 + {SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER10}, // S_PROXIMITY_TNT_TRIGGER9 + {SPR_REMT, 0, 4, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER11}, // S_PROXIMITY_TNT_TRIGGER10 + {SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER12}, // S_PROXIMITY_TNT_TRIGGER11 + {SPR_REMT, 0, 4, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER13}, // S_PROXIMITY_TNT_TRIGGER12 + {SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER14}, // S_PROXIMITY_TNT_TRIGGER13 + {SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER15}, // S_PROXIMITY_TNT_TRIGGER14 + {SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER16}, // S_PROXIMITY_TNT_TRIGGER15 + {SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER17}, // S_PROXIMITY_TNT_TRIGGER16 + {SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER18}, // S_PROXIMITY_TNT_TRIGGER17 + {SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER19}, // S_PROXIMITY_TNT_TRIGGER18 + {SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER20}, // S_PROXIMITY_TNT_TRIGGER19 + {SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER21}, // S_PROXIMITY_TNT_TRIGGER20 + {SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_PROXIMITY_TNT_TRIGGER22}, // S_PROXIMITY_TNT_TRIGGER21 + {SPR_REMT, 0, 2, {NULL}, 0, 0, S_PROXIMITY_TNT_TRIGGER23}, // S_PROXIMITY_TNT_TRIGGER22 + {SPR_REMT, 1|FF_FULLBRIGHT, 1, {A_PlayActiveSound}, 0, 0, S_TNTBARREL_EXPL1}, // S_PROXIMITY_TNT_TRIGGER23 + + // Dust devil + {SPR_NULL, 0, 1, {A_DustDevilThink}, 0, 0, S_DUSTDEVIL}, //S_DUSTDEVIL + {SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS70, 2 * TICRATE, {NULL}, 0, 0, S_DUSTLAYER2}, // S_DUSTLAYER1 + {SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS70, 5, {NULL}, 0, 0, S_DUSTLAYER3}, // S_DUSTLAYER2 + {SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS80, 5, {NULL}, 0, 0, S_DUSTLAYER4}, // S_DUSTLAYER3 + {SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS80, 5, {NULL}, 0, 0, S_DUSTLAYER5}, // S_DUSTLAYER4 + {SPR_TAZD, 1|FF_PAPERSPRITE|FF_TRANS90, 5, {NULL}, 0, 0, S_NULL}, // S_DUSTLAYER5 + {SPR_ADST, 0|FF_ANIMATE, 24, {NULL}, 3, 8, S_NULL}, // S_ARIDDUST1 + {SPR_ADST, 3|FF_ANIMATE, 24, {NULL}, 3, 8, S_NULL}, // S_ARIDDUST2 + {SPR_ADST, 6|FF_ANIMATE, 24, {NULL}, 3, 8, S_NULL}, // S_ARIDDUST3 + + // Minecart + {SPR_NULL, 0, 1, {NULL}, 0, 0, S_MINECART_IDLE}, // S_MINECART_IDLE + {SPR_NULL, 0, 0, {A_KillSegments}, 0, 0, S_TNTBARREL_EXPL3}, // S_MINECART_DTH1 + {SPR_MCRT, 8|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_MINECARTEND + {SPR_MCRT, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_MINECARTSEG_FRONT + {SPR_MCRT, 1|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_MINECARTSEG_BACK + {SPR_MCRT, 2|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL}, // S_MINECARTSEG_LEFT + {SPR_MCRT, 5|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL}, // S_MINECARTSEG_RIGHT + {SPR_LCKN, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_MINECARTSIDEMARK1 + {SPR_LCKN, 0|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_MINECARTSIDEMARK2 + {SPR_MCSP, FF_FULLBRIGHT, 1, {A_MinecartSparkThink}, 0, 0, S_MINECARTSPARK}, // S_MINECARTSPARK + + // Saloon door + {SPR_SALD, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_SALOONDOOR + {SPR_NON2, 0, -1, {A_SaloonDoorSpawn}, 0, 0, S_NULL}, // S_SALONDOORTHINKER + + // Train cameo + {SPR_NULL, 0, -1, {NULL}, 0, 0, S_TRAINCAMEOSPAWNER_2}, // S_TRAINCAMEOSPAWNER_1 + {SPR_NULL, 0, 14, {A_TrainCameo}, 20, 18, S_TRAINCAMEOSPAWNER_3}, // S_TRAINCAMEOSPAWNER_2 + {SPR_NULL, 0, 1, {A_Repeat}, 1, 0, S_TRAINCAMEOSPAWNER_4}, // S_TRAINCAMEOSPAWNER_3 + {SPR_NULL, 0, 18, {A_TrainCameo2}, 20, 44, S_TRAINCAMEOSPAWNER_5}, // S_TRAINCAMEOSPAWNER_4 + {SPR_NULL, 0, 1, {A_Repeat}, 5, S_TRAINCAMEOSPAWNER_4, S_NULL}, // S_TRAINCAMEOSPAWNER_5 + {SPR_NULL, 0, 2, {A_SmokeTrailer}, MT_SMOKE, 0, S_TRAINPUFFMAKER}, // S_TRAINPUFFMAKER + + {SPR_ADST, FF_TRANS50, -1, {NULL}, 0, 0, S_NULL}, // S_TRAINDUST + {SPR_STEA, FF_TRANS50, -1, {NULL}, 0, 0, S_NULL}, // S_TRAINSTEAM + // Flame jet {SPR_NULL, 0, 2*TICRATE, {NULL}, 0, 0, S_FLAMEJETSTART}, // S_FLAMEJETSTND {SPR_NULL, 0, 3*TICRATE, {A_ToggleFlameJet}, 0, 0, S_FLAMEJETSTOP}, // S_FLAMEJETSTART @@ -3701,6 +3840,8 @@ state_t states[NUMSTATES] = {SPR_DUST, 2|FF_TRANS60, 3, {NULL}, 0, 0, S_DUST4}, // S_DUST3 {SPR_DUST, 3|FF_TRANS70, 2, {NULL}, 0, 0, S_NULL}, // S_DUST4 + {SPR_WDDB, FF_ANIMATE, -1, {A_DebrisRandom}, 7, 2, S_NULL}, // S_WOODDEBRIS + {SPR_NULL, 0, 1, {A_RockSpawn}, 0, 0, S_ROCKSPAWN}, // S_ROCKSPAWN {SPR_ROIA, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEA @@ -4352,26 +4493,26 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 115, // doomednum S_VULTURE_STND, // spawnstate 1, // spawnhealth - S_VULTURE_VTOL1,// seestate + S_VULTURE_DRIFT,// seestate sfx_None, // seesound - 2, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate + TICRATE/2, // reactiontime + sfx_s3k60, // attacksound + S_VULTURE_STUNNED, // painstate S_NULL, // painchance - sfx_None, // painsound + sfx_s3k96, // painsound S_NULL, // meleestate S_VULTURE_ZOOM1,// missilestate S_XPLD_FLICKY, // deathstate S_NULL, // xdeathstate sfx_pop, // deathsound - 3, // speed + 5, // speed 12*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset TICRATE, // mass 0, // damage sfx_jet, // activesound - MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE|MF_NOGRAVITY, // flags + MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE|MF_NOGRAVITY|MF_SLIDEME, // flags S_NULL // raisestate }, @@ -4566,56 +4707,137 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_GSNAPPER 120, // doomednum - S_GSNAPPER_STND,// spawnstate + S_SNAPPER_SPAWN,// spawnstate 1, // spawnhealth S_GSNAPPER1, // seestate sfx_None, // seesound - 32, // reactiontime + 10, // reactiontime sfx_None, // attacksound S_NULL, // painstate 200, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_XPLD_FLICKY, // deathstate + S_SNAPPER_XPLD, // deathstate S_NULL, // xdeathstate sfx_pop, // deathsound - 3, // speed - 24*FRACUNIT, // radius - 24*FRACUNIT, // height - 0, // display offset - 100, // mass - 0, // damage - sfx_None, // activesound - MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE, // flags - S_NULL // raisestate - }, - - { // MT_MINUS - 121, // doomednum - S_MINUS_STND, // spawnstate - 1, // spawnhealth - S_MINUS_DIGGING,// seestate - sfx_None, // seesound - 32, // reactiontime - sfx_s3k82, // attacksound - S_NULL, // painstate - 200, // painchance - sfx_None, // painsound - S_MINUS_DOWNWARD1,// meleestate - S_MINUS_POPUP, // missilestate - S_XPLD_FLICKY, // deathstate - S_NULL, // xdeathstate - sfx_pop, // deathsound - 12, // speed + 4, // speed 24*FRACUNIT, // radius 32*FRACUNIT, // height 0, // display offset 100, // mass 0, // damage - sfx_mindig, // activesound + sfx_s3k7e, // activesound MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE, // flags - S_MINUS_UPWARD1 // raisestate + S_NULL // raisestate + }, + + { // MT_SNAPPER_LEG + -1, // doomednum + S_SNAPPER_LEG, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 6*FRACUNIT, // radius + 12*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_PAIN|MF_NOCLIPHEIGHT|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags + S_SNAPPER_LEGRAISE // raisestate + }, + + { // MT_SNAPPER_HEAD + -1, // doomednum + S_SNAPPER_HEAD, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 6*FRACUNIT, // radius + 12*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_PAIN|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MINUS + 121, // doomednum + S_MINUS_INIT, // spawnstate + 1, // spawnhealth + S_MINUS_DIGGING1,// seestate + sfx_None, // seesound + 32, // reactiontime + sfx_s3kccs, // attacksound + S_NULL, // painstate + 200, // painchance + sfx_None, // painsound + S_MINUS_BURST0, // meleestate + S_MINUS_POPUP, // missilestate + S_XPLD_FLICKY, // deathstate + S_NULL, // xdeathstate + sfx_pop, // deathsound + 17, // speed + 24*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_s3kd3s, // activesound + MF_ENEMY|MF_NOCLIPTHING, // flags + S_MINUS_BURST1 // raisestate + }, + + { // MT_MINUSDIRT + -1, // doomednum + S_MINUSDIRT1, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8*FRACUNIT, // radius + 8*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIPTHING, // flags + S_NULL // raisestate }, { // MT_SPRINGSHELL @@ -4726,6 +4948,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_CANARIVORE + 134, // doomednum + S_CANARIVORE_LOOK, // spawnstate + 1, // spawnhealth + S_CANARIVORE_AWAKEN1, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_XPLD_FLICKY, // deathstate + S_NULL, // xdeathstate + sfx_pop, // deathsound + 0, // speed + 12*FRACUNIT, // radius + 80*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_SHOOTABLE|MF_ENEMY|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_CANARIVORE_GAS + -1, // doomednum + S_CANARIVOREGAS_1, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_s3k5d, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOCLIP|MF_SPECIAL, // flags + S_NULL // raisestate + }, + { // MT_BOSSEXPLODE -1, // doomednum S_BOSSEXPLODE, // spawnstate @@ -5423,7 +5699,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // display offset 0, // mass 0, // damage - sfx_s3k8d, // activesound + sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE, // flags S_NULL // raisestate }, @@ -11217,8 +11493,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 40*FRACUNIT, // radius - 128*FRACUNIT, // height + 32*FRACUNIT, // radius + 96*FRACUNIT, // height 0, // display offset 100, // mass 0, // damage @@ -11244,8 +11520,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 24*FRACUNIT, // radius - 132*FRACUNIT, // height + 20*FRACUNIT, // radius + 128*FRACUNIT, // height 0, // display offset 100, // mass 0, // damage @@ -11299,7 +11575,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // deathsound 0, // speed 24*FRACUNIT, // radius - 208*FRACUNIT, // height + 256*FRACUNIT, // height 0, // display offset 100, // mass 0, // damage @@ -11326,7 +11602,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // deathsound 0, // speed 48*FRACUNIT, // radius - 208*FRACUNIT, // height + 96*FRACUNIT, // height 0, // display offset 100, // mass 0, // damage @@ -11416,6 +11692,546 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_OILLAMP + 1215, // doomednum + S_OILLAMP, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 22*FRACUNIT, // radius + 64*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_s3k4b, // activesound + MF_SCENERY|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SPAWNCEILING, // flags + S_NULL // raisestate + }, + + { // MT_TNTBARREL + 1216, // doomednum + S_TNTBARREL_STND1, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_bowl, // attacksound + S_TNTBARREL_EXPL1, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_TNTBARREL_FLYING, // missilestate + S_TNTBARREL_EXPL1, // deathstate + S_NULL, // xdeathstate + sfx_s3k4e, // deathsound + 0, // speed + 24*FRACUNIT, // radius + 63*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SHOOTABLE|MF_ENEMY|MF_PUSHABLE, // flags + S_NULL // raisestate + }, + + { // MT_PROXIMITYTNT + 1217, // doomednum + S_PROXIMITY_TNT, // spawnstate + 1, // spawnhealth + S_PROXIMITY_TNT_TRIGGER1, // seestate + sfx_s3k5c, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_s3k4e, // deathsound + 0, // speed + 64*FRACUNIT, // radius + 40*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_s3k89, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_DUSTDEVIL + 1218, // doomednum + S_DUSTDEVIL, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 2, // speed + 80*FRACUNIT, // radius + 416*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_s3k4b, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_DUSTLAYER + -1, // doomednum + S_DUSTLAYER1, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 64*FRACUNIT, // radius + 256*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_ARIDDUST + -1, // doomednum + S_ARIDDUST1, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 24*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOCLIPHEIGHT, // flags + S_NULL // raisestate + }, + + { // MT_MINECART + -1, // doomednum + S_MINECART_IDLE,// spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 24*FRACUNIT, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_statu2, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_MINECART_DTH1,// deathstate + S_NULL, // xdeathstate + sfx_s3k59, // deathsound + 20*FRACUNIT, // speed + 22*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_s3k76, // activesound + MF_PUSHABLE, // flags + MT_MINECARTSIDEMARK // raisestate + }, + + { // MT_MINECARTSEG + -1, // doomednum + S_INVISIBLE, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP, // flags + S_NULL // raisestate + }, + + { // MT_MINECARTSPAWNER + 1219, // doomednum + S_INVISIBLE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 22*FRACUNIT, // radius + 16*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MINECARTEND + 1220, // doomednum + S_MINECARTEND, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 32*FRACUNIT, // radius + 160*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MINECARTENDSOLID + -1, // doomednum + S_INVISIBLE, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 32*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_PAPERCOLLISION|MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MINECARTSIDEMARK + -1, // doomednum + S_MINECARTSIDEMARK2, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 22*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MINECARTSPARK + -1, // doomednum + S_MINECARTSPARK,// spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 2*FRACUNIT, // radius + 2*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_BOUNCE|MF_NOCLIPTHING|MF_GRENADEBOUNCE, // flags + S_NULL // raisestate + }, + + { // MT_SALOONDOOR + -1, // doomednum + S_SALOONDOOR, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 48*FRACUNIT, // radius + 160*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_s3k90, // activesound + MF_SOLID|MF_NOGRAVITY|MF_RUNSPAWNFUNC|MF_PAPERCOLLISION|MF_NOCLIPHEIGHT, // flags + S_NULL // raisestate + }, + + { // MT_SALOONDOORTHINKER + 1221, // doomednum + S_SALOONDOORTHINKER, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 96*FRACUNIT, // radius + 160*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + + { // MT_TRAINCAMEOSPAWNER + 1222, // doomednum + S_TRAINCAMEOSPAWNER_1, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 28*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOCLIP, // flags + S_NULL // raisestate + }, + + { // MT_TRAINSEG + -1, // doomednum + S_INVISIBLE, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + FRACUNIT, // radius + FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags + S_NULL // raisestate + }, + + { // MT_TRAINDUSTSPAWNER + 1223, // doomednum + S_INVISIBLE, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + FRACUNIT, // radius + FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIP, // flags + S_NULL // raisestate + }, + + { // MT_TRAINSTEAMSPAWNER + 1224, // doomednum + S_INVISIBLE, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + FRACUNIT, // radius + FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIP, // flags + S_NULL // raisestate + }, + + { // MT_MINECARTSWITCHPOINT + 1229, // doomednum + S_INVISIBLE, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + FRACUNIT, // radius + 160*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + { // MT_FLAMEJET 1300, // doomednum S_FLAMEJETSTND, // spawnstate @@ -18641,6 +19457,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_WOODDEBRIS + -1, // doomednum + S_WOODDEBRIS, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_RUNSPAWNFUNC|MF_NOCLIPHEIGHT, // flags + S_NULL // raisestate + }, + { // MT_ROCKSPAWNER 1202, // doomednum S_ROCKSPAWN, // spawnstate diff --git a/src/info.h b/src/info.h index 5482af60b..13abfa5f6 100644 --- a/src/info.h +++ b/src/info.h @@ -115,6 +115,9 @@ void A_CrushclawAim(); void A_CrushclawLaunch(); void A_VultureVtol(); void A_VultureCheck(); +void A_VultureHover(); +void A_VultureBlast(); +void A_VultureFly(); void A_SkimChase(); void A_SkullAttack(); void A_LobShot(); @@ -251,6 +254,17 @@ void A_Boss5PinchShot(); void A_Boss5MakeItRain(); void A_LookForBetter(); void A_Boss5BombExplode(); +void A_DustDevilThink(); +void A_TNTExplode(); +void A_DebrisRandom(); +void A_TrainCameo(); +void A_TrainCameo2(); +void A_CanarivoreGas(); +void A_KillSegments(); +void A_SnapperSpawn(); +void A_SnapperThinker(); +void A_SaloonDoorSpawn(); +void A_MinecartSparkThink(); // ratio of states to sprites to mobj types is roughly 6 : 1 : 1 #define NUMMOBJFREESLOTS 512 @@ -291,9 +305,14 @@ typedef enum sprite SPR_SPSH, // Egg Guard SPR_ESHI, // Egg Guard's shield SPR_GSNP, // Green Snapper + SPR_GSNL, // Green Snapper leg + SPR_GSNH, // Green Snapper head SPR_MNUS, // Minus + SPR_MNUD, // Minus dirt SPR_SSHL, // Spring Shell SPR_UNID, // Unidus + SPR_CANA, // Canarivore + SPR_CANG, // Canarivore gas // Generic Boss Items SPR_JETF, // Boss jet fumes @@ -476,6 +495,19 @@ typedef enum sprite SPR_WWSG, // Caution Sign SPR_WWS2, // Cacti Sign SPR_WWS3, // Sharp Turn Sign + SPR_OILL, // Oil lamp + SPR_OILF, // Oil lamp flare + SPR_BARR, // TNT barrel + SPR_REMT, // TNT proximity shell + SPR_TAZD, // Dust devil + SPR_ADST, // Arid dust + SPR_MCRT, // Minecart + SPR_MCSP, // Minecart spark + SPR_NON2, // Saloon door thinker + SPR_SALD, // Saloon door + SPR_TRAE, // Train cameo locomotive + SPR_TRAI, // Train cameo wagon + SPR_STEA, // Train steam // Red Volcano Scenery SPR_FLME, // Flame jet @@ -668,6 +700,7 @@ typedef enum sprite SPR_BOM3, // Boss Explosion 2 SPR_BOM4, // Underwater Explosion SPR_BMNB, // Mine Explosion + SPR_WDDB, // Wood Debris // Crumbly rocks SPR_ROIA, @@ -1126,15 +1159,10 @@ typedef enum state // Vulture S_VULTURE_STND, - S_VULTURE_VTOL1, - S_VULTURE_VTOL2, - S_VULTURE_VTOL3, - S_VULTURE_VTOL4, + S_VULTURE_DRIFT, S_VULTURE_ZOOM1, S_VULTURE_ZOOM2, - S_VULTURE_ZOOM3, - S_VULTURE_ZOOM4, - S_VULTURE_ZOOM5, + S_VULTURE_STUNNED, // Pointy S_POINTY1, @@ -1185,15 +1213,31 @@ typedef enum state S_EGGSHIELDBREAK, // Green Snapper + S_SNAPPER_SPAWN, + S_SNAPPER_SPAWN2, S_GSNAPPER_STND, S_GSNAPPER1, S_GSNAPPER2, S_GSNAPPER3, S_GSNAPPER4, + S_SNAPPER_XPLD, + S_SNAPPER_LEG, + S_SNAPPER_LEGRAISE, + S_SNAPPER_HEAD, // Minus + S_MINUS_INIT, S_MINUS_STND, - S_MINUS_DIGGING, + S_MINUS_DIGGING1, + S_MINUS_DIGGING2, + S_MINUS_DIGGING3, + S_MINUS_DIGGING4, + S_MINUS_BURST0, + S_MINUS_BURST1, + S_MINUS_BURST2, + S_MINUS_BURST3, + S_MINUS_BURST4, + S_MINUS_BURST5, S_MINUS_POPUP, S_MINUS_UPWARD1, S_MINUS_UPWARD2, @@ -1212,6 +1256,15 @@ typedef enum state S_MINUS_DOWNWARD7, S_MINUS_DOWNWARD8, + // Minus dirt + S_MINUSDIRT1, + S_MINUSDIRT2, + S_MINUSDIRT3, + S_MINUSDIRT4, + S_MINUSDIRT5, + S_MINUSDIRT6, + S_MINUSDIRT7, + // Spring Shell S_SSHELL_STND, S_SSHELL_RUN1, @@ -1239,6 +1292,28 @@ typedef enum state S_UNIDUS_RUN, S_UNIDUS_BALL, + // Canarivore + S_CANARIVORE_LOOK, + S_CANARIVORE_AWAKEN1, + S_CANARIVORE_AWAKEN2, + S_CANARIVORE_AWAKEN3, + S_CANARIVORE_GAS1, + S_CANARIVORE_GAS2, + S_CANARIVORE_GAS3, + S_CANARIVORE_GAS4, + S_CANARIVORE_GAS5, + S_CANARIVORE_GASREPEAT, + S_CANARIVORE_CLOSE1, + S_CANARIVORE_CLOSE2, + S_CANARIVOREGAS_1, + S_CANARIVOREGAS_2, + S_CANARIVOREGAS_3, + S_CANARIVOREGAS_4, + S_CANARIVOREGAS_5, + S_CANARIVOREGAS_6, + S_CANARIVOREGAS_7, + S_CANARIVOREGAS_8, + // Boss Explosion S_BOSSEXPLODE, @@ -2426,6 +2501,85 @@ typedef enum state S_ARIDSIGN_CACTI, S_ARIDSIGN_SHARPTURN, + // Oil lamp + S_OILLAMP, + S_OILLAMPFLARE, + + // TNT barrel + S_TNTBARREL_STND1, + S_TNTBARREL_EXPL1, + S_TNTBARREL_EXPL2, + S_TNTBARREL_EXPL3, + S_TNTBARREL_EXPL4, + S_TNTBARREL_EXPL5, + S_TNTBARREL_EXPL6, + S_TNTBARREL_FLYING, + + // TNT proximity shell + S_PROXIMITY_TNT, + S_PROXIMITY_TNT_TRIGGER1, + S_PROXIMITY_TNT_TRIGGER2, + S_PROXIMITY_TNT_TRIGGER3, + S_PROXIMITY_TNT_TRIGGER4, + S_PROXIMITY_TNT_TRIGGER5, + S_PROXIMITY_TNT_TRIGGER6, + S_PROXIMITY_TNT_TRIGGER7, + S_PROXIMITY_TNT_TRIGGER8, + S_PROXIMITY_TNT_TRIGGER9, + S_PROXIMITY_TNT_TRIGGER10, + S_PROXIMITY_TNT_TRIGGER11, + S_PROXIMITY_TNT_TRIGGER12, + S_PROXIMITY_TNT_TRIGGER13, + S_PROXIMITY_TNT_TRIGGER14, + S_PROXIMITY_TNT_TRIGGER15, + S_PROXIMITY_TNT_TRIGGER16, + S_PROXIMITY_TNT_TRIGGER17, + S_PROXIMITY_TNT_TRIGGER18, + S_PROXIMITY_TNT_TRIGGER19, + S_PROXIMITY_TNT_TRIGGER20, + S_PROXIMITY_TNT_TRIGGER21, + S_PROXIMITY_TNT_TRIGGER22, + S_PROXIMITY_TNT_TRIGGER23, + + // Dust devil + S_DUSTDEVIL, + S_DUSTLAYER1, + S_DUSTLAYER2, + S_DUSTLAYER3, + S_DUSTLAYER4, + S_DUSTLAYER5, + S_ARIDDUST1, + S_ARIDDUST2, + S_ARIDDUST3, + + // Minecart + S_MINECART_IDLE, + S_MINECART_DTH1, + S_MINECARTEND, + S_MINECARTSEG_FRONT, + S_MINECARTSEG_BACK, + S_MINECARTSEG_LEFT, + S_MINECARTSEG_RIGHT, + S_MINECARTSIDEMARK1, + S_MINECARTSIDEMARK2, + S_MINECARTSPARK, + + // Saloon door + S_SALOONDOOR, + S_SALOONDOORTHINKER, + + // Train cameo + S_TRAINCAMEOSPAWNER_1, + S_TRAINCAMEOSPAWNER_2, + S_TRAINCAMEOSPAWNER_3, + S_TRAINCAMEOSPAWNER_4, + S_TRAINCAMEOSPAWNER_5, + S_TRAINPUFFMAKER, + + // Train + S_TRAINDUST, + S_TRAINSTEAM, + // Flame jet S_FLAMEJETSTND, S_FLAMEJETSTART, @@ -3748,6 +3902,8 @@ typedef enum state S_DUST3, S_DUST4, + S_WOODDEBRIS, + S_ROCKSPAWN, S_ROCKCRUMBLEA, @@ -3831,11 +3987,16 @@ typedef enum mobj_type MT_EGGGUARD, // Egg Guard MT_EGGSHIELD, // Egg Guard's shield MT_GSNAPPER, // Green Snapper + MT_SNAPPER_LEG, // Green Snapper leg + MT_SNAPPER_HEAD, // Green Snapper head MT_MINUS, // Minus + MT_MINUSDIRT, // Minus dirt MT_SPRINGSHELL, // Spring Shell MT_YELLOWSHELL, // Spring Shell (yellow) MT_UNIDUS, // Unidus MT_UNIBALL, // Unidus Ball + MT_CANARIVORE, // Canarivore + MT_CANARIVORE_GAS, // Canarivore gas // Generic Boss Items MT_BOSSEXPLODE, @@ -4134,6 +4295,26 @@ typedef enum mobj_type MT_ARIDSIGN_CAUTION, // Caution Sign MT_ARIDSIGN_CACTI, // Cacti Sign MT_ARIDSIGN_SHARPTURN, // Sharp Turn Sign + MT_OILLAMP, + MT_TNTBARREL, + MT_PROXIMITYTNT, + MT_DUSTDEVIL, + MT_DUSTLAYER, + MT_ARIDDUST, + MT_MINECART, + MT_MINECARTSEG, + MT_MINECARTSPAWNER, + MT_MINECARTEND, + MT_MINECARTENDSOLID, + MT_MINECARTSIDEMARK, + MT_MINECARTSPARK, + MT_SALOONDOOR, + MT_SALOONDOORTHINKER, + MT_TRAINCAMEOSPAWNER, + MT_TRAINSEG, + MT_TRAINDUSTSPAWNER, + MT_TRAINSTEAMSPAWNER, + MT_MINECARTSWITCHPOINT, // Red Volcano Scenery MT_FLAMEJET, @@ -4456,6 +4637,7 @@ typedef enum mobj_type MT_EXPLODE, // Robot Explosion MT_UWEXPLODE, // Underwater Explosion MT_DUST, + MT_WOODDEBRIS, MT_ROCKSPAWNER, MT_FALLINGROCK, MT_ROCKCRUMBLE1, diff --git a/src/p_enemy.c b/src/p_enemy.c index 664e3b9b0..4123d316c 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -79,6 +79,9 @@ void A_CrushclawAim(mobj_t *actor); void A_CrushclawLaunch(mobj_t *actor); void A_VultureVtol(mobj_t *actor); void A_VultureCheck(mobj_t *actor); +void A_VultureHover(mobj_t *actor); +void A_VultureBlast(mobj_t *actor); +void A_VultureFly(mobj_t *actor); void A_SkimChase(mobj_t *actor); void A_FaceTarget(mobj_t *actor); void A_FaceTracer(mobj_t *actor); @@ -280,6 +283,17 @@ void A_Boss5PinchShot(mobj_t *actor); void A_Boss5MakeItRain(mobj_t *actor); void A_LookForBetter(mobj_t *actor); void A_Boss5BombExplode(mobj_t *actor); +void A_DustDevilThink(mobj_t *actor); +void A_TNTExplode(mobj_t *actor); +void A_DebrisRandom(mobj_t *actor); +void A_TrainCameo(mobj_t *actor); +void A_TrainCameo2(mobj_t *actor); +void A_CanarivoreGas(mobj_t *actor); +void A_KillSegments(mobj_t *actor); +void A_SnapperSpawn(mobj_t *actor); +void A_SnapperThinker(mobj_t *actor); +void A_SaloonDoorSpawn(mobj_t *actor); +void A_MinecartSparkThink(mobj_t *actor); //for p_enemy.c // @@ -2295,6 +2309,222 @@ void A_VultureCheck(mobj_t *actor) } } +static void P_VultureHoverParticle(mobj_t *actor) +{ + fixed_t fdist = actor->z - P_FloorzAtPos(actor->x, actor->y, actor->z, actor->height); + + if (fdist < 128*FRACUNIT) + { + mobj_t *dust; + UINT8 i; + angle_t angle = (leveltime % 2)*ANGLE_45/2; + + for (i = 0; i <= 7; i++) + { + angle_t fa = (angle >> ANGLETOFINESHIFT) & FINEMASK; + fixed_t px = actor->x + FixedMul(fdist + 64*FRACUNIT, FINECOSINE(fa)); + fixed_t py = actor->y + FixedMul(fdist + 64*FRACUNIT, FINESINE(fa)); + fixed_t pz = P_FloorzAtPos(px, py, actor->z, actor->height); + + dust = P_SpawnMobj(px, py, pz, MT_ARIDDUST); + P_SetMobjState(dust, (statenum_t)(dust->state - states + P_RandomRange(0, 2))); + P_Thrust(dust, angle, FixedDiv(12*FRACUNIT, max(FRACUNIT, fdist/2))); + dust->momx += actor->momx; + dust->momy += actor->momy; + angle += ANGLE_45; + } + } +} + +// Function: A_VultureHover +// +// Description: Vulture hovering and checking whether to attack. +// +// var1 = unused +// var2 = unused +// +void A_VultureHover(mobj_t *actor) +{ + fixed_t targetz; + fixed_t distdif; + fixed_t memz = actor->z; + INT8 i; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_VultureHover", actor)) + return; +#endif + + if (!actor->target || P_MobjWasRemoved(actor->target)) + { + P_SetMobjState(actor, actor->info->spawnstate); + return; + } + + actor->flags |= MF_NOGRAVITY; + + actor->momx -= actor->momx/24; + actor->momy -= actor->momy/24; + + P_VultureHoverParticle(actor); + + A_FaceTarget(actor); + targetz = actor->target->z + actor->target->height / 2; + for (i = -1; i <= 1; i++) + { + actor->z = targetz - i * 128 * FRACUNIT; + if (P_CheckSight(actor, actor->target)) + { + targetz -= i * 128 * FRACUNIT; + break; + } + } + actor->z = memz; + + distdif = (actor->z + actor->height/2) - targetz; + + if (abs(actor->momz*16) > abs(distdif)) + actor->momz -= actor->momz/16; + else if (distdif < 0) + actor->momz = min(actor->momz+FRACUNIT/8, actor->info->speed*FRACUNIT); + else + actor->momz = max(actor->momz-FRACUNIT/8, -actor->info->speed*FRACUNIT); + + if (abs(distdif) < 128*FRACUNIT && abs(actor->momz) < FRACUNIT && P_CheckSight(actor, actor->target)) + { + P_SetMobjState(actor, actor->info->missilestate); + actor->momx = 0; + actor->momy = 0; + actor->momz = 0; + actor->extravalue1 = 0; + } +} + +// Function: A_VultureBlast +// +// Description: Vulture spawning a dust cloud. +// +// var1 = unused +// var2 = unused +// +void A_VultureBlast(mobj_t *actor) +{ + mobj_t *dust; + UINT8 i; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_VultureBlast", actor)) + return; +#endif + + S_StartSound(actor, actor->info->attacksound); + + for (i = 0; i <= 7; i++) + { + angle_t fa = ((i*(angle_t)ANGLE_45) >> ANGLETOFINESHIFT) & FINEMASK; + angle_t faa = (actor->angle >> ANGLETOFINESHIFT) & FINEMASK; + dust = P_SpawnMobj(actor->x + 48*FixedMul(FINECOSINE(fa), -FINESINE(faa)), actor->y + 48*FixedMul(FINECOSINE(fa), FINECOSINE(faa)), actor->z + actor->height/2 + 48*FINESINE(fa), MT_PARTICLE); + + P_SetScale(dust, 4*FRACUNIT); + dust->destscale = FRACUNIT; + dust->scalespeed = 4*FRACUNIT/TICRATE; + dust->fuse = TICRATE; + dust->momx = FixedMul(FINECOSINE(fa), -FINESINE(faa))*3; + dust->momy = FixedMul(FINECOSINE(fa), FINECOSINE(faa))*3; + dust->momz = FINESINE(fa)*6; + } +} + +// Function: A_VultureFly +// +// Description: Vulture charging towards target. +// +// var1 = unused +// var2 = unused +// +void A_VultureFly(mobj_t *actor) +{ + fixed_t speedmax = 18*FRACUNIT; + angle_t angledif = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) - actor->angle; + fixed_t dx = actor->target->x - actor->x; + fixed_t dy = actor->target->y - actor->y; + fixed_t dz = actor->target->z - actor->z; + fixed_t dxy = FixedHypot(dx, dy); + fixed_t dm; + mobj_t *dust; + fixed_t momm; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_VultureFly", actor)) + return; +#endif + + if (leveltime % 4 == 0) + S_StartSound(actor, actor->info->activesound); + + if (angledif > ANGLE_180) + angledif = InvAngle(angledif); + + // Tweak the target height according to the position. + if (angledif < ANGLE_45) // Centered? + { + actor->reactiontime = actor->info->reactiontime; + if (dxy > 768*FRACUNIT) + dz = max(P_FloorzAtPos(actor->target->x, actor->target->y, actor->target->z, 0) - actor->z + min(dxy/8, 128*FRACUNIT), dz); + } + else + { + actor->reactiontime--; + + if (angledif < ANGLE_90) + dz = max(P_FloorzAtPos(actor->target->x, actor->target->y, actor->target->z, 0) - actor->z + min(dxy/2, 192*FRACUNIT), dz); + else + dz = max(P_FloorzAtPos(actor->target->x, actor->target->y, actor->target->z, 0) - actor->z + 232*FRACUNIT, dz); + } + + dm = FixedHypot(dz, dxy); + + P_VultureHoverParticle(actor); + + dust = P_SpawnMobj(actor->x + P_RandomFixed() - FRACUNIT/2, actor->y + P_RandomFixed() - FRACUNIT/2, actor->z + actor->height/2 + P_RandomFixed() - FRACUNIT/2, MT_PARTICLE); + P_SetScale(dust, 2*FRACUNIT); + dust->destscale = FRACUNIT/3; + dust->scalespeed = FRACUNIT/40; + dust->fuse = TICRATE*2; + + actor->momx += FixedDiv(dx, dm)*2; + actor->momy += FixedDiv(dy, dm)*2; + actor->momz += FixedDiv(dz, dm)*2; + + momm = FixedHypot(actor->momz, FixedHypot(actor->momx, actor->momy)); + + if (momm > speedmax/2 && actor->reactiontime == 0) + { + P_SetMobjState(actor, actor->info->seestate); + return; + } + + //Hits a wall hard? + if (actor->extravalue1 - momm > 15*FRACUNIT) + { + actor->flags &= ~MF_NOGRAVITY; + P_SetMobjState(actor, actor->info->painstate); + S_StopSound(actor); + S_StartSound(actor, actor->info->painsound); + return; + } + actor->extravalue1 = momm; + + if (momm > speedmax) + { + actor->momx = FixedMul(FixedDiv(actor->momx, momm), speedmax); + actor->momy = FixedMul(FixedDiv(actor->momy, momm), speedmax); + actor->momz = FixedMul(FixedDiv(actor->momz, momm), speedmax); + } + + actor->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy); +} + // Function: A_SkimChase // // Description: Thinker/Chase routine for Skims @@ -4921,56 +5151,111 @@ void A_ShootBullet(mobj_t *actor) S_StartSound(actor, actor->info->attacksound); } +static mobj_t *minus; + +static boolean PIT_MinusCarry(mobj_t *thing) +{ + if (minus->type == thing->type) + return true; + + if (!(thing->flags & MF_SHOOTABLE) || !(thing->flags & MF_ENEMY)) + return true; + + if (P_AproxDistance(minus->x - thing->x, minus->y - thing->y) >= minus->radius * 3) + return true; + + if (abs(thing->z - minus->z) > minus->height) + return true; + + P_SetTarget(&minus->tracer, thing); + minus->tracer->flags &= ~MF_PUSHABLE; + + return true; +} + // Function: A_MinusDigging // // Description: Minus digging in the ground. // -// var1 = unused +// var1 = If 1, play digging sound. // var2 = unused // void A_MinusDigging(mobj_t *actor) { + INT32 locvar1 = var1; + INT32 rad = 32; + angle_t fa = (actor->angle >> ANGLETOFINESHIFT) & FINEMASK; + fixed_t dis = actor->info->speed*4; + fixed_t x = FINECOSINE(fa)*dis + actor->x + FRACUNIT*P_RandomRange(-rad, rad); + fixed_t y = FINESINE(fa)*dis + actor->y + FRACUNIT*P_RandomRange(-rad, rad); + fixed_t mz = (actor->eflags & MFE_VERTICALFLIP) ? actor->ceilingz : actor->floorz; + mobj_t *par; + #ifdef HAVE_BLUA if (LUA_CallAction("A_MinusDigging", actor)) return; #endif - actor->flags &= ~MF_SPECIAL; - actor->flags &= ~MF_SHOOTABLE; if (!actor->target) { - A_Look(actor); + P_SetMobjState(actor, actor->info->spawnstate); return; } - if (actor->reactiontime) + par = P_SpawnMobj(actor->x, actor->y, mz, MT_MINUSDIRT); + if (actor->eflags & MFE_VERTICALFLIP) + par->eflags |= MFE_VERTICALFLIP; + P_TryMove(par, x, y, false); + + // If close enough, prepare to attack + if (P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y) < actor->radius*2) { - actor->reactiontime--; + P_SetMobjState(actor, actor->info->meleestate); + P_TryMove(actor, actor->target->x, actor->target->y, false); + S_StartSound(actor, actor->info->attacksound); + + // Spawn growing dirt pile. + par = P_SpawnMobj(actor->x, actor->y, mz, MT_MINUSDIRT); + P_SetMobjState(par, actor->info->raisestate); + P_SetScale(par, actor->scale*2); + if (actor->eflags & MFE_VERTICALFLIP) + par->eflags |= MFE_VERTICALFLIP; return; } - // Dirt trail - P_SpawnGhostMobj(actor); - - actor->flags |= MF_NOCLIPTHING; - var1 = 3; - A_Chase(actor); - actor->flags &= ~MF_NOCLIPTHING; - // Play digging sound - if (!(leveltime & 15)) - S_StartSound(actor, actor->info->activesound); + if (locvar1 == 1) + A_PlayActiveSound(actor); - // If we're close enough to our target, pop out of the ground - if (P_AproxDistance(actor->target->x-actor->x, actor->target->y-actor->y) < actor->radius - && abs(actor->target->z - actor->z) < 2*actor->height) - P_SetMobjState(actor, actor->info->missilestate); + // Move + var1 = 3; + A_Chase(actor); - // Snap to ground - if (actor->eflags & MFE_VERTICALFLIP) - actor->z = actor->ceilingz - actor->height; + // Carry over shit, maybe + if (!actor->tracer) + { + fixed_t radius = 3*actor->radius; + fixed_t yh = (unsigned)(actor->y + radius - bmaporgy) >> MAPBLOCKSHIFT; + fixed_t yl = (unsigned)(actor->y - radius - bmaporgy) >> MAPBLOCKSHIFT; + fixed_t xh = (unsigned)(actor->x + radius - bmaporgx) >> MAPBLOCKSHIFT; + fixed_t xl = (unsigned)(actor->x - radius - bmaporgx) >> MAPBLOCKSHIFT; + fixed_t bx, by; + + BMBOUNDFIX(xl, xh, yl, yh); + + minus = actor; + + for (bx = xl; bx <= xh; bx++) + for (by = yl; by <= yh; by++) + P_BlockThingsIterator(bx, by, PIT_MinusCarry); + } else - actor->z = actor->floorz; + { + if (P_TryMove(actor->tracer, actor->x, actor->y, false)) + actor->tracer->z = mz; + else + P_SetTarget(&actor->tracer, NULL); + } } // Function: A_MinusPopup @@ -4982,45 +5267,56 @@ void A_MinusDigging(mobj_t *actor) // void A_MinusPopup(mobj_t *actor) { + INT32 num = 6; + angle_t ani = FixedAngle(FRACUNIT*360/num); + INT32 i; + #ifdef HAVE_BLUA if (LUA_CallAction("A_MinusPopup", actor)) return; #endif - P_SetObjectMomZ(actor, 10*FRACUNIT, false); - actor->flags |= MF_SPECIAL; - actor->flags |= MF_SHOOTABLE; + if (actor->eflags & MFE_VERTICALFLIP) + actor->momz = -10*FRACUNIT; + else + actor->momz = 10*FRACUNIT; + + actor->flags |= MF_SPECIAL|MF_SHOOTABLE; + S_StartSound(actor, sfx_s3k82); + for (i = 1; i <= num; i++) + { + mobj_t *rock = P_SpawnMobj(actor->x, actor->y, actor->z + actor->height/4, MT_ROCKCRUMBLE1); + P_Thrust(rock, ani*i, FRACUNIT); + rock->momz = 3*FRACUNIT; + P_SetScale(rock, FRACUNIT/3); + } + P_RadiusAttack(actor, actor, 2*actor->radius, 0); + if (actor->tracer) + P_DamageMobj(actor->tracer, actor, actor, 1, 0); - // Sound for busting out of the ground. - S_StartSound(actor, actor->info->attacksound); } // Function: A_MinusCheck // // Description: If the minus hits the floor, dig back into the ground. // -// var1 = unused +// var1 = State to switch to (if 0, use seestate). // var2 = unused // void A_MinusCheck(mobj_t *actor) { + INT32 locvar1 = var1; + #ifdef HAVE_BLUA if (LUA_CallAction("A_MinusCheck", actor)) return; #endif - if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz) - || ((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz)) - { - actor->flags &= ~MF_SPECIAL; - actor->flags &= ~MF_SHOOTABLE; - actor->reactiontime = TICRATE; - P_SetMobjState(actor, actor->info->seestate); - return; - } - // 'Falling' animation - if (P_MobjFlip(actor)*actor->momz < 0 && actor->state < &states[actor->info->meleestate]) - P_SetMobjState(actor, actor->info->meleestate); + if (((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz) || (!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz)) + { + P_SetMobjState(actor, locvar1 ? (statenum_t)locvar1 : actor->info->seestate); + actor->flags = actor->info->flags; + } } // Function: A_ChickenCheck @@ -6005,6 +6301,10 @@ void A_MixUp(mobj_t *actor) } //get this done first! + if (players[one].powers[pw_carry] == CR_MINECART && players[one].mo->tracer && !(P_MobjWasRemoved(players[one].mo->tracer))) + P_SetTarget(&players[one].mo->tracer->target, players[two].mo); + if (players[two].powers[pw_carry] == CR_MINECART && players[two].mo->tracer && !(P_MobjWasRemoved(players[two].mo->tracer))) + P_SetTarget(&players[two].mo->tracer->target, players[one].mo); tempthing = players[one].mo->tracer; P_SetTarget(&players[one].mo->tracer, players[two].mo->tracer); P_SetTarget(&players[two].mo->tracer, tempthing); @@ -6146,6 +6446,8 @@ void A_MixUp(mobj_t *actor) //...carry after. same reasoning. players[i].powers[pw_carry] = transcarry[teleportfrom]; + if (transcarry[teleportfrom] == CR_MINECART && transtracer[teleportfrom] && !(P_MobjWasRemoved(transtracer[teleportfrom]))) + P_SetTarget(&transtracer[teleportfrom]->target, players[i].mo); teleported[i] = true; counter++; @@ -12452,9 +12754,10 @@ void A_LookForBetter(mobj_t *actor) * \param z Center Z coordinates. * \param radius Radius. * \param speed Additional thrust on particles. - * \param scale Scale. + * \param initscale Initial scale when spawning. + * \param scale "Default" scale. */ -static void P_DustRing(mobjtype_t mobjtype, UINT32 div, fixed_t x, fixed_t y, fixed_t z, fixed_t radius, fixed_t speed, fixed_t scale) +static void P_DustRing(mobjtype_t mobjtype, UINT32 div, fixed_t x, fixed_t y, fixed_t z, fixed_t radius, fixed_t speed, fixed_t initscale, fixed_t scale) { angle_t ang = FixedAngle(FixedDiv(360*FRACUNIT, div*FRACUNIT)); //(ANGLE_180/div)*2; UINT32 i; @@ -12475,7 +12778,7 @@ static void P_DustRing(mobjtype_t mobjtype, UINT32 div, fixed_t x, fixed_t y, fi ); dust->angle = ang*i + ANGLE_90; - P_SetScale(dust, scale); + P_SetScale(dust, FixedMul(initscale, scale)); dust->destscale = FixedMul(4*FRACUNIT + P_RandomFixed(), scale); dust->scalespeed = scale/24; P_Thrust(dust, ang*i, speed + FixedMul(P_RandomFixed(), scale)); @@ -12508,8 +12811,8 @@ void A_Boss5BombExplode(mobj_t *actor) if (actor->target) P_RadiusAttack(actor, actor->target, 7*actor->radius, 0); - P_DustRing(locvar1, 4, actor->x, actor->y, actor->z+actor->height, 2*actor->radius, 0, actor->scale); - P_DustRing(locvar1, 6, actor->x, actor->y, actor->z+actor->height/2, 3*actor->radius, FRACUNIT, actor->scale); + P_DustRing(locvar1, 4, actor->x, actor->y, actor->z+actor->height, 2*actor->radius, 0, FRACUNIT, actor->scale); + P_DustRing(locvar1, 6, actor->x, actor->y, actor->z+actor->height/2, 3*actor->radius, FRACUNIT, FRACUNIT, actor->scale); //P_StartQuake(9*actor->scale, TICRATE/6, {actor->x, actor->y, actor->z}, 20*actor->radius); // the above does not exist, so we set the quake values directly instead quake.intensity = 9*actor->scale; @@ -12521,3 +12824,736 @@ void A_Boss5BombExplode(mobj_t *actor) } quake.radius = 20*actor->radius; } + +static mobj_t *dustdevil; + +static boolean PIT_DustDevilLaunch(mobj_t *thing) +{ + player_t *player = thing->player; + + if (!player) + return true; + + if (abs(thing->x - dustdevil->x) > dustdevil->radius || abs(thing->y - dustdevil->y) > dustdevil->radius) + return true; + + if (thing->z + thing->height >= dustdevil->z && dustdevil->z + dustdevil->height >= thing->z) { + fixed_t pos = thing->z - dustdevil->z; + fixed_t thrust = max(FixedDiv(pos, dustdevil->height) * 20, 8 * FRACUNIT); + angle_t fa = R_PointToAngle2(thing->x, thing->y, dustdevil->x, dustdevil->y) >> ANGLETOFINESHIFT; + fixed_t c = FINECOSINE(fa); + fixed_t s = FINESINE(fa); + fixed_t thresh = dustdevil->scale * 20; + + //Player in the swirl part. + if (dustdevil->height - pos > thresh) + { + fixed_t dist = FixedHypot(thing->x - dustdevil->x, thing->y - dustdevil->y); + fixed_t dragamount = 6 * FRACUNIT; + fixed_t x, y; + + if (player->powers[pw_nocontrol] == 0) + A_PlayActiveSound(dustdevil); + player->powers[pw_nocontrol] = 2; + player->drawangle += ANG20; + P_SetPlayerMobjState(thing, S_PLAY_PAIN); + + if (dist > dragamount) + { + x = thing->x + FixedMul(c, dragamount); + y = thing->y + FixedMul(s, dragamount); + } + else + { + x = dustdevil->x; + y = dustdevil->y; + } + P_TryMove(thing, x - thing->momx, y - thing->momy, true); + } + else + { //Player on the top of the tornado. + thing->z = dustdevil->z + dustdevil->height; + thrust = 20 * FRACUNIT; + player->powers[pw_nocontrol] = 0; + S_StartSound(thing, sfx_wdjump); + P_SetPlayerMobjState(thing, S_PLAY_FALL); + player->pflags &= ~PF_JUMPED; + } + + thing->momz = thrust; + } + + return true; +} + +// Function: A_DustDevilThink +// +// Description: Thinker for the dust devil. +// +// var1 = unused +// var2 = unused +// +void A_DustDevilThink(mobj_t *actor) +{ + fixed_t scale = actor->scale; + mobj_t *layer = actor->tracer; + INT32 bx, by, xl, xh, yl, yh; + fixed_t radius = actor->radius; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_DustDevilThink", actor)) + return; +#endif + + //Chained thinker for the spiralling dust column. + while (layer && !P_MobjWasRemoved(layer)) { + angle_t fa = layer->angle >> ANGLETOFINESHIFT; + P_TeleportMove(layer, layer->x + 5 * FixedMul(scale, FINECOSINE(fa)), layer->y + 5 * FixedMul(scale, FINESINE(fa)), layer->z); + layer->scale = scale; + layer->angle += ANG10 / 2; + layer->momx = actor->momx; + layer->momy = actor->momy; + layer = layer->tracer; + } + + //Spawn random dust around the column on the base. + if (P_IsObjectOnGround(actor)) { + angle_t dustang = ((P_RandomRange(0, 7)*ANGLE_45)>>ANGLETOFINESHIFT) & FINEMASK; + mobj_t *dust = P_SpawnMobj(actor->x + 96 * FixedMul(scale, FINECOSINE(dustang)), actor->y + 96 * FixedMul(scale, FINESINE(dustang)), actor->z, MT_ARIDDUST); + P_SetMobjState(dust, dust->info->spawnstate + P_RandomRange(0, 2)); + dust->destscale = scale * 3; + P_SetScale(dust, dust->destscale); + } + + actor->extravalue1++; + if (actor->extravalue1 == 12) { + size_t i = 0; + actor->extravalue1 = 0; + + //Create a set of items for the rising dust column + for (; i <= 3; i++) { + fixed_t fa = (ANGLE_90*i) >> ANGLETOFINESHIFT; + fixed_t px = actor->x + 70 * FixedMul(scale, FINECOSINE(fa)); + fixed_t py = actor->y + 70 * FixedMul(scale, FINESINE(fa)); + fixed_t pz = actor->z; + + layer = P_SpawnMobj(px, py, pz, MT_DUSTLAYER); + layer->momz = 5 * scale; + layer->angle = ANGLE_90 + ANGLE_90*i; + layer->extravalue1 = TICRATE * 3; + + //Chain them + P_SetTarget(&layer->tracer, actor->tracer); + P_SetTarget(&actor->tracer, layer); + } + } + + //The physics are handled here. + yh = (unsigned)(actor->y + radius - bmaporgy) >> MAPBLOCKSHIFT; + yl = (unsigned)(actor->y - radius - bmaporgy) >> MAPBLOCKSHIFT; + xh = (unsigned)(actor->x + radius - bmaporgx) >> MAPBLOCKSHIFT; + xl = (unsigned)(actor->x - radius - bmaporgx) >> MAPBLOCKSHIFT; + + BMBOUNDFIX(xl, xh, yl, yh); + + dustdevil = actor; + + for (bx = xl; bx <= xh; bx++) + for (by = yl; by <= yh; by++) + P_BlockThingsIterator(bx, by, PIT_DustDevilLaunch); + + //Whirlwind sound effect. + if (leveltime % 70 == 0) + S_StartSound(actor, sfx_s3kcel); +} + +// stuff used by A_TNTExplode +static mobj_t *barrel; +static fixed_t exploderadius; +static fixed_t explodethrust; + +static boolean PIT_TNTExplode(mobj_t *nearby) +{ + fixed_t dx, dy, dz; + fixed_t dm; + + if (nearby == barrel) + return true; + + dx = nearby->x - barrel->x; + dy = nearby->y - barrel->y; + dz = nearby->z - barrel->z + (nearby->height - barrel->height/2)/2; + dm = P_AproxDistance(P_AproxDistance(dx, dy), dz); + + if (dm >= exploderadius || !P_CheckSight(barrel, nearby)) // out of range or not visible + return true; + + if (barrel->type == nearby->type) // nearby is also a barrel + { + if (nearby->state == &states[nearby->info->spawnstate]) + { + if (barrel->info->attacksound) + S_StartSound(nearby, barrel->info->attacksound); + nearby->momx = FixedMul(FixedDiv(dx, dm), explodethrust); + nearby->momy = FixedMul(FixedDiv(dy, dm), explodethrust); + nearby->momz = FixedMul(FixedDiv(dz, dm), explodethrust); + nearby->flags = MF_NOBLOCKMAP|MF_MISSILE; + P_SetMobjState(nearby, nearby->info->missilestate); + } + } + else + { + if (barrel->target == nearby) + { + mobj_t *tar = barrel->target; // temporarily store barrel's target + barrel->target = NULL; + P_DamageMobj(nearby, barrel, NULL, 1, 0); + barrel->target = tar; + } + else + { + P_DamageMobj(nearby, + (barrel->target) ? barrel->target : barrel, + (barrel->target) ? barrel->target : barrel, + 1, 0); + } + } + + return true; +} + +// Function: A_TNTExplode +// +// Description: Creates a TNT explosion. Used by TNT barrels and the like. +// +// var1 = Thing type to spawn as dust. +// var2 = unused +// +void A_TNTExplode(mobj_t *actor) +{ + INT32 locvar1 = var1; + //INT32 locvar2 = var2; + INT32 x, y; + INT32 xl, xh, yl, yh; + static mappoint_t epicenter = {0,0,0}; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_TNTExplode", actor)) + return; +#endif + + actor->flags = MF_NOCLIP|MF_NOGRAVITY|MF_NOBLOCKMAP; + actor->flags2 = MF2_EXPLOSION; + if (actor->info->deathsound) + S_StartSound(actor, actor->info->deathsound); + + explodethrust = 32*FRACUNIT; + exploderadius = 256*FRACUNIT; + + xl = (unsigned)(actor->x - exploderadius - bmaporgx)>>MAPBLOCKSHIFT; + xh = (unsigned)(actor->x + exploderadius - bmaporgx)>>MAPBLOCKSHIFT; + yl = (unsigned)(actor->y - exploderadius - bmaporgy)>>MAPBLOCKSHIFT; + yh = (unsigned)(actor->y + exploderadius - bmaporgy)>>MAPBLOCKSHIFT; + + BMBOUNDFIX(xl, xh, yl, yh); + + barrel = actor; + + for (x = xl; x <= xh; x++) + for (y = yl; y <= yh; y++) + P_BlockThingsIterator(x, y, PIT_TNTExplode); + + // cause a quake -- P_StartQuake does not exist yet + epicenter.x = actor->x; + epicenter.y = actor->y; + epicenter.z = actor->z; + quake.intensity = 9*FRACUNIT; + quake.time = TICRATE/6; + quake.epicenter = &epicenter; + quake.radius = 512*FRACUNIT; + + if (locvar1) + { + P_DustRing(locvar1, 4, actor->x, actor->y, actor->z+actor->height, 64, 0, FRACUNIT, actor->scale); + P_DustRing(locvar1, 6, actor->x, actor->y, actor->z+actor->height/2, 96, FRACUNIT, FRACUNIT, actor->scale); + } + + actor->destscale *= 4; +} + +// Function: A_DebrisRandom +// +// Description: Randomizes debris frame and movement. +// +// var1 = Frame range. +// var2 = unused +// +void A_DebrisRandom(mobj_t *actor) +{ + INT32 locvar1 = var1; + //INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_DebrisRandom", actor)) + return; +#endif + + actor->frame |= P_RandomRange(0, locvar1); + var1 = 0; + var2 = 359; + A_ChangeAngleAbsolute(actor); + P_Thrust(actor, actor->angle, FRACUNIT * 2); +} + +static mobj_t *P_TrainSeg(mobj_t *src, fixed_t x, fixed_t y, fixed_t z, angle_t ang, spritenum_t spr, UINT32 frame) +{ + mobj_t *s = P_SpawnMobj(x, y, z, MT_TRAINSEG); + s->fuse = 16*TICRATE; + s->sprite = spr; + s->frame = frame|FF_PAPERSPRITE; + s->angle = ang; + P_Thrust(s, src->angle, 7*FRACUNIT); + return s; +} + +// Function: A_TrainCameo +// +// Description: Sets up train cameo locomotive. +// +// var1 = Train width. +// var2 = Train length. +// +void A_TrainCameo(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + fixed_t x = actor->x; + fixed_t y = actor->y; + fixed_t z = actor->z; + angle_t ang = actor->angle; + mobj_t *m; + spritenum_t spr = SPR_TRAE; + fixed_t span = locvar1*FRACUNIT; + fixed_t len = locvar2*FRACUNIT; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_TrainCameo", actor)) + return; +#endif + + //Spawn sides. + P_TrainSeg(actor, x, y + span, z, ang, spr, 0); + P_TrainSeg(actor, x, y - span, z, ang, spr, 0); + + //Center. + P_TrainSeg(actor, x, y, z, ang, spr, 1); + + //Front and back. + P_TrainSeg(actor, x + len, y, z, ang + ANGLE_90, spr, 2); + P_TrainSeg(actor, x - len, y, z, ang + ANGLE_90, spr, 2); + + //Smoke spawner. + m = P_TrainSeg(actor, x - (20 * FRACUNIT), y, z + (30 * FRACUNIT), ang + ANGLE_90, spr, 0); + P_SetMobjState(m, S_TRAINPUFFMAKER); +} + +// Function: A_TrainCameo2 +// +// Description: Sets up train cameo wagon. +// +// var1 = Train width. +// var2 = Train length. +// +void A_TrainCameo2(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + fixed_t x = actor->x; + fixed_t y = actor->y; + fixed_t z = actor->z; + angle_t ang = actor->angle; + spritenum_t spr = SPR_TRAI; + fixed_t span = locvar1*FRACUNIT; + fixed_t len = locvar2*FRACUNIT; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_TrainCameo2", actor)) + return; +#endif + + //Spawn sides. + P_TrainSeg(actor, x, y + span, z, ang, spr, 0); + P_TrainSeg(actor, x, y - span, z, ang, spr, 0); + + //Center. + P_TrainSeg(actor, x, y, z, ang, spr, 1); + + //Front and back. + P_TrainSeg(actor, x + len, y, z, ang + ANGLE_90, spr, 2); + P_TrainSeg(actor, x - len, y, z, ang + ANGLE_90, spr, 2); +} + +// Function: A_CanarivoreGas +// +// Description: Releases gas clouds. Used by the Canarivore. +// +// var1 = Mobj type. +// var2 = Unused +// +void A_CanarivoreGas(mobj_t *actor) +{ + INT32 locvar1 = var1; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_CanarivoreGas", actor)) + return; +#endif + + P_DustRing(locvar1, 4, actor->x, actor->y, actor->z + actor->height / 5, 18, 0, FRACUNIT/10, actor->scale); + P_DustRing(locvar1, 6, actor->x, actor->y, actor->z + actor->height / 5, 28, FRACUNIT, FRACUNIT/10, actor->scale); +} + +// +// Function: A_KillSegments +// +// Description: Causes segments attached via tracer chain to be killed. +// +// var1 = Fuse (if 0, default to TICRATE/2). +// var2 = Unused +// +void A_KillSegments(mobj_t *actor) +{ + INT32 locvar1 = var1; + mobj_t *seg = actor->tracer; + INT32 fuse = locvar1 ? locvar1 : TICRATE/2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_KillSegments", actor)) + return; +#endif + + while (seg) + { + mobj_t *kseg = seg; + seg = seg->tracer; + + kseg->flags = MF_NOBLOCKMAP|MF_BOUNCE; + kseg->flags2 = 0; + kseg->fuse = fuse; + P_Thrust(kseg, R_PointToAngle2(actor->x, actor->y, kseg->x, kseg->y), 3*actor->scale); + kseg->momz = 3*actor->scale; + } +} + +static void P_SnapperLegPlace(mobj_t *mo) +{ + mobj_t *seg = mo->tracer; + fixed_t x0 = mo->x; + fixed_t y0 = mo->y; + angle_t a = mo->angle; + angle_t fa = (a >> ANGLETOFINESHIFT) & FINEMASK; + fixed_t c = FINECOSINE(fa); + fixed_t s = FINESINE(fa); + fixed_t x, y; + INT32 o1, o2; + INT32 woffset = mo->extravalue1; + INT32 side = mo->extravalue2; + INT32 alt; + + // Move head first. + fixed_t rad = mo->radius; + INT32 necklen = (32*(mo->info->reactiontime - mo->reactiontime))/mo->info->reactiontime; // Not in FU + + P_TeleportMove(seg, mo->x + FixedMul(c, rad) + necklen*c, mo->y + FixedMul(s, rad) + necklen*s, mo->z + mo->height/3); + seg->angle = a; + + // Move as many legs as available. + seg = seg->tracer; + do + { + o1 = seg->extravalue1; + o2 = seg->extravalue2; + alt = seg->cusval; + + if (alt == 1) + o2 += woffset; + else + o2 -= woffset; + + if (alt != side) + { + x = c*o2 + s*o1; + y = s*o2 - c*o1; + P_TryMove(seg, x0 + x, y0 + y, true); + P_SetMobjState(seg, seg->info->raisestate); + } + else + P_SetMobjState(seg, seg->info->spawnstate); + + seg->angle = R_PointToAngle2(x0, y0, seg->x, seg->y); + + seg = seg->tracer; + } while (seg); +} + +// +// Function: A_SnapperSpawn +// +// Description: Sets up Green Snapper legs and head. +// +// var1 = Leg mobj type. +// var2 = Head mobj type. +// +void A_SnapperSpawn(mobj_t *actor) +{ + mobjtype_t legtype = (mobjtype_t)var1; + mobjtype_t headtype = (mobjtype_t)var2; + mobj_t *ptr = actor; + INT32 i; + mobj_t *seg; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SnapperSpawn", actor)) + return; +#endif + + // It spawns 1 head. + seg = P_SpawnMobj(actor->x, actor->y, actor->z, headtype); + P_SetTarget(&ptr->tracer, seg); + ptr = seg; + + // It spawns 4 legs which will be handled in the thinker function. + for (i = 1; i <= 4; i++) + { + seg = P_SpawnMobj(actor->x, actor->y, actor->z, legtype); + P_SetTarget(&ptr->tracer, seg); + ptr = seg; + + // The legs' base offsets are stored as extravalues, as relative coordinates in xy space. + seg->extravalue1 = 28; + seg->extravalue2 = 28; + if (i % 2) + seg->extravalue1 = -seg->extravalue1; + + if ((i/2) % 2) + seg->extravalue2 = -seg->extravalue2; + + // Alternating motion stuff. + seg->cusval = ((i + 1)/2) % 2; + } + + actor->extravalue1 = 0; + actor->extravalue2 = 0; + P_SnapperLegPlace(actor); +} + +// +// Function: A_SnapperThinker +// +// Description: Thinker for Green Snapper. +// +// var1 = Unused +// var2 = Unused +// +void A_SnapperThinker(mobj_t *actor) +{ + fixed_t x0 = actor->x; + fixed_t y0 = actor->y; + fixed_t xs, ys; + fixed_t x1, y1; + fixed_t dist; + boolean chasing; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SnapperThinker", actor)) + return; +#endif + + // We make a check just in case there's no spawnpoint. + if (actor->spawnpoint) + { + xs = actor->spawnpoint->x*FRACUNIT; + ys = actor->spawnpoint->y*FRACUNIT; + } + else + { + xs = x0; + ys = y0; + } + + // Look for nearby, valid players to chase angrily at. + if ((actor->target || P_LookForPlayers(actor, true, false, 1024*FRACUNIT)) + && P_AproxDistance(actor->target->x - xs, actor->target->y - ys) < 2048*FRACUNIT + && abs(actor->target->z - actor->z) < 80*FRACUNIT + && P_CheckSight(actor, actor->target)) + { + chasing = true; + x1 = actor->target->x; + y1 = actor->target->y; + } + else + { + chasing = false; + x1 = xs; + y1 = ys; + } + + dist = P_AproxDistance(x1 - x0, y1 - y0); + + // The snapper either chases what it considers to be a nearby player, or instead decides to go back to its spawnpoint. + if (chasing || dist > 32*FRACUNIT) + { + INT32 speed = actor->info->speed + actor->info->reactiontime - actor->reactiontime; + + angle_t maxang = FixedAngle(speed*FRACUNIT/2); + angle_t ang = actor->angle; + angle_t realang = R_PointToAngle2(x0, y0, x1, y1); + angle_t dif = realang - ang; + angle_t fa; + fixed_t c, s; + + if (dif < ANGLE_180 && dif > maxang) + actor->angle += maxang; + else if (dif >= ANGLE_180 && dif < InvAngle(maxang)) + actor->angle -= maxang; + else + actor->angle = realang; + + fa = (actor->angle >> ANGLETOFINESHIFT) & FINEMASK; + c = FINECOSINE(fa); + s = FINESINE(fa); + + P_TryMove(actor, actor->x + c*speed, actor->y + s*speed, false); + + // The snapper spawns dust if going fast! + if (actor->reactiontime < 4) + { + mobj_t *dust = P_SpawnMobj(x0, y0, actor->z, MT_SPINDUST); + P_Thrust(dust, ang + ANGLE_180 + FixedAngle(P_RandomRange(-20, 20)*FRACUNIT), speed*FRACUNIT); + } + + if (actor->extravalue2 == 0) + { + if (actor->extravalue1 > 16) + { + A_PlayActiveSound(actor); + actor->extravalue2 = 1; + + // If the snapper is chasing, accelerate; otherwise, decelerate. + if (chasing) + actor->reactiontime = max(0, actor->reactiontime - 1); + else + actor->reactiontime = min(actor->info->reactiontime, actor->reactiontime + 1); + } + else + actor->extravalue1 += speed; + } + else + { + if (actor->extravalue1 < -16) + { + A_PlayActiveSound(actor); + actor->extravalue2 = 0; + + // If the snapper is chasing, accelerate; otherwise, decelerate. + if (chasing) + actor->reactiontime = max(0, actor->reactiontime - 1); + else + actor->reactiontime = min(actor->info->reactiontime, actor->reactiontime + 1); + } + else + actor->extravalue1 -= speed; + } + } + + P_SnapperLegPlace(actor); +} + +// Function: A_SaloonDoorSpawn +// +// Description: Spawns a saloon door. +// +// var1 = unused +// var2 = unused +// +void A_SaloonDoorSpawn(mobj_t *actor) +{ + angle_t ang = actor->angle; + angle_t fa = (ang >> ANGLETOFINESHIFT) & FINEMASK; + fixed_t c = FINECOSINE(fa); + fixed_t s = FINESINE(fa); + INT32 d = 48; + fixed_t x = actor->x; + fixed_t y = actor->y; + fixed_t z = actor->z; + mobj_t *door; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SaloonDoorSpawn", actor)) + return; +#endif + + //Front + door = P_SpawnMobj(x + c*d, y + s*d, z, MT_SALOONDOOR); + door->angle = ang + ANGLE_180; + + // Origin angle + door->extravalue1 = AngleFixed(door->angle); + + // Angular speed + door->extravalue2 = 0; + + // Origin door + door->tracer = actor; + + //Back + door = P_SpawnMobj(x - c*d, y - s*d, z, MT_SALOONDOOR); + door->angle = ang; + + // Origin angle + door->extravalue1 = AngleFixed(door->angle); + + // Angular speed + door->extravalue2 = 0; + + // Origin door + door->tracer = actor; +} + +// Function: A_MinecartSparkThink +// +// Description: Thinker for the minecart spark. +// +// var1 = unused +// var2 = unused +// +void A_MinecartSparkThink(mobj_t *actor) +{ + fixed_t dx = actor->momx; + fixed_t dy = actor->momy; + fixed_t dz, dm; + UINT8 i; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_MinecartSparkThink", actor)) + return; +#endif + + if (actor->momz == 0 && P_IsObjectOnGround(actor)) + actor->momz = P_RandomRange(2, 4)*FRACUNIT; + + dz = actor->momz; + dm = FixedHypot(FixedHypot(dx, dy), dz); + dx = FixedDiv(dx, dm); + dy = FixedDiv(dy, dm); + dz = FixedDiv(dz, dm); + + for (i = 1; i <= 8; i++) + { + mobj_t *trail = P_SpawnMobj(actor->x - dx*i, actor->y - dy*i, actor->z - dz*i, MT_PARTICLE); + trail->tics = 2; + trail->sprite = actor->sprite; + P_SetScale(trail, trail->scale/4); + trail->destscale = trail->scale; + } +} \ No newline at end of file diff --git a/src/p_inter.c b/src/p_inter.c index 68f1782c5..0fab3353c 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1699,6 +1699,73 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } return; + case MT_CANARIVORE_GAS: + // if player and gas touch, attach gas to player (overriding any gas that already attached) and apply slowdown effect + P_UnsetThingPosition(special); + special->x = toucher->x - toucher->momx/2; + special->y = toucher->y - toucher->momy/2; + special->z = toucher->z - toucher->momz/2; + P_SetThingPosition(special); + toucher->momx = FixedMul(toucher->momx, 50*FRACUNIT/51); + toucher->momy = FixedMul(toucher->momy, 50*FRACUNIT/51); + special->momx = toucher->momx; + special->momy = toucher->momy; + special->momz = toucher->momz; + return; + + case MT_MINECARTSPAWNER: + if (!special->fuse || player->powers[pw_carry] != CR_MINECART) + { + mobj_t *mcart = P_SpawnMobj(special->x, special->y, special->z, MT_MINECART); + P_SetTarget(&mcart->target, toucher); + mcart->angle = toucher->angle = player->drawangle = special->angle; + mcart->friction = FRACUNIT; + + P_ResetPlayer(player); + player->pflags |= PF_JUMPDOWN; + player->powers[pw_carry] = CR_MINECART; + toucher->player->pflags &= ~PF_APPLYAUTOBRAKE; + P_SetTarget(&toucher->tracer, mcart); + toucher->momx = toucher->momy = toucher->momz = 0; + + special->fuse = 3*TICRATE; + special->flags2 |= MF2_DONTDRAW; + } + return; + + case MT_MINECARTEND: + if (player->powers[pw_carry] == CR_MINECART && toucher->tracer && !P_MobjWasRemoved(toucher->tracer) && toucher->tracer->health) + { + fixed_t maxz = max(toucher->z, special->z + 35*special->scale); + + toucher->momx = toucher->tracer->momx/2; + toucher->momy = toucher->tracer->momy/2; + toucher->momz = toucher->tracer->momz + P_AproxDistance(toucher->tracer->momx, toucher->tracer->momy)/2; + P_ResetPlayer(player); + player->pflags &= ~PF_APPLYAUTOBRAKE; + P_SetPlayerMobjState(toucher, S_PLAY_FALL); + P_SetTarget(&toucher->tracer->target, NULL); + P_KillMobj(toucher->tracer, toucher, special, 0); + P_SetTarget(&toucher->tracer, NULL); + player->powers[pw_carry] = CR_NONE; + P_UnsetThingPosition(toucher); + toucher->x = special->x; + toucher->y = special->y; + toucher->z = maxz; + P_SetThingPosition(toucher); + } + return; + + case MT_MINECARTSWITCHPOINT: + if (player->powers[pw_carry] == CR_MINECART && toucher->tracer && !P_MobjWasRemoved(toucher->tracer) && toucher->tracer->health) + { + mobjflag2_t destambush = special->flags2 & MF2_AMBUSH; + angle_t angdiff = toucher->tracer->angle - special->angle; + if (angdiff > ANGLE_90 && angdiff < ANGLE_270) + destambush ^= MF2_AMBUSH; + toucher->tracer->flags2 = (toucher->tracer->flags2 & ~MF2_AMBUSH) | destambush; + } + return; default: // SOC or script pickup if (player->bot) return; @@ -2546,6 +2613,13 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget target->fuse = TICRATE*2; break; + case MT_MINECART: + A_Scream(target); + target->momx = target->momy = target->momz = 0; + if (target->target && target->target->health) + P_KillMobj(target->target, target, source, 0); + break; + case MT_PLAYER: { target->fuse = TICRATE*3; // timer before mobj disappears from view (even if not an actual player) @@ -2960,6 +3034,9 @@ static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage) P_ResetPlayer(player); + if (!player->spectator) + player->mo->flags2 &= ~MF2_DONTDRAW; + P_SetPlayerMobjState(player->mo, player->mo->info->deathstate); if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) { @@ -3591,9 +3668,6 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) } if (player->mo->eflags & MFE_VERTICALFLIP) mo->momz *= -1; - - if (P_IsObjectOnGround(player->mo)) - player->powers[pw_carry] = CR_NONE; } player->losstime += 10*TICRATE; diff --git a/src/p_local.h b/src/p_local.h index b686b9f09..2149a95bf 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -229,6 +229,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state); boolean P_SetMobjState(mobj_t *mobj, statenum_t state); void P_RunShields(void); void P_RunOverlays(void); +void P_HandleMinecartSegments(mobj_t *mobj); void P_MobjThinker(mobj_t *mobj); boolean P_RailThinker(mobj_t *mobj); void P_PushableThinker(mobj_t *mobj); diff --git a/src/p_map.c b/src/p_map.c index ffe6cf916..abd4174d6 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -818,6 +818,83 @@ static boolean PIT_CheckThing(mobj_t *thing) } #endif + if (tmthing->type == MT_MINECART) + { + //height check + if (tmthing->z > thing->z + thing->height || thing->z > tmthing->z + tmthing->height || !(thing->health)) + return true; + + if (thing->type == MT_TNTBARREL) + P_KillMobj(thing, tmthing, tmthing->target, 0); + else if ((thing->flags & MF_MONITOR) || (thing->flags & MF_ENEMY)) + { + P_KillMobj(thing, tmthing, tmthing->target, 0); + if (tmthing->momz*P_MobjFlip(tmthing) < 0) + tmthing->momz = abs(tmthing->momz)*P_MobjFlip(tmthing); + } + } + + if (thing->type == MT_SALOONDOOR && tmthing->player) + { + if (tmthing->player->powers[pw_carry] == CR_MINECART && tmthing->tracer && !P_MobjWasRemoved(tmthing->tracer) && tmthing->tracer->health) + { + fixed_t dx = tmthing->tracer->momx; + fixed_t dy = tmthing->tracer->momy; + fixed_t dm = min(FixedHypot(dx, dy), 16*FRACUNIT); + angle_t ang = R_PointToAngle2(0, 0, dx, dy) - thing->angle; + fixed_t s = FINESINE((ang >> ANGLETOFINESHIFT) & FINEMASK); + S_StartSound(tmthing, thing->info->activesound); + thing->extravalue2 += 2*FixedMul(s, dm)/3; + return true; + } + } + + if (thing->type == MT_TNTBARREL && tmthing->player) + { + if (tmthing->momz < 0) + { + if (tmthing->z + tmthing->momz > thing->z + thing->height) + return true; + } + else + { + if (tmthing->z > thing->z + thing->height) + return true; + } + + if (tmthing->momz > 0) + { + if (tmthing->z + tmthing->height + tmthing->momz < thing->z) + return true; + } + else + { + if (tmthing->z + tmthing->height < thing->z) + return true; + } + + if ((tmthing->player->pflags & (PF_SPINNING | PF_GLIDING)) + || ((tmthing->player->pflags & PF_JUMPED) + && (!(tmthing->player->pflags & PF_NOJUMPDAMAGE) + || (tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY))) + || (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2) + || ((tmthing->player->charflags & SF_STOMPDAMAGE || tmthing->player->pflags & PF_BOUNCING) + && (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height / 2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0)) + || (((tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (tmthing->player->pflags & PF_SHIELDABILITY))) + P_DamageMobj(thing, tmthing, tmthing, 1, 0); + } + + if (thing->type == MT_VULTURE && tmthing->type == MT_VULTURE) + { + fixed_t dx = thing->x - tmthing->x; + fixed_t dy = thing->y - tmthing->y; + fixed_t dz = thing->z - tmthing->z; + fixed_t dm = FixedHypot(dz, FixedHypot(dx, dy)); + thing->momx += FixedDiv(dx, dm); + thing->momy += FixedDiv(dy, dm); + thing->momz += FixedDiv(dz, dm); + } + if (tmthing->type == MT_FANG && thing->type == MT_FSGNB) { if (thing->z > tmthing->z + tmthing->height) @@ -1395,7 +1472,7 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->type == MT_FAN || thing->type == MT_STEAM) P_DoFanAndGasJet(thing, tmthing); - else if (thing->flags & MF_SPRING) + else if (thing->flags & MF_SPRING && tmthing->player->powers[pw_carry] != CR_MINECART) { if ( thing->z <= tmthing->z + tmthing->height && tmthing->z <= thing->z + thing->height) @@ -3859,6 +3936,8 @@ static boolean nofit; static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush) { mobj_t *killer = NULL; + //If a thing is both pushable and vulnerable, it doesn't block the crusher because it gets killed. + boolean immunepushable = ((thing->flags & (MF_PUSHABLE | MF_SHOOTABLE)) == MF_PUSHABLE); if (P_ThingHeightClip(thing)) { @@ -3877,7 +3956,7 @@ static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush) // just be blocked by another object - check if it's really a ceiling! if (thing->z + thing->height > thing->ceilingz && thing->z <= thing->ceilingz) { - if (thing->flags & MF_PUSHABLE && thing->z + thing->height > thing->subsector->sector->ceilingheight) + if (immunepushable && thing->z + thing->height > thing->subsector->sector->ceilingheight) { //Thing is a pushable and blocks the moving ceiling nofit = true; @@ -3885,7 +3964,7 @@ static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush) } //Check FOFs in the sector - if (thing->subsector->sector->ffloors && (realcrush || thing->flags & MF_PUSHABLE)) + if (thing->subsector->sector->ffloors && (realcrush || immunepushable)) { ffloor_t *rover; fixed_t topheight, bottomheight; @@ -3912,7 +3991,7 @@ static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush) delta2 = thingtop - (bottomheight + topheight)/2; if (bottomheight <= thing->ceilingz && abs(delta1) >= abs(delta2)) { - if (thing->flags & MF_PUSHABLE) + if (immunepushable) { //FOF is blocked by pushable nofit = true; diff --git a/src/p_mobj.c b/src/p_mobj.c index bc43fbe1e..38bc7ed96 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2580,9 +2580,9 @@ static boolean P_ZMovement(mobj_t *mo) if (!mo->player && P_CheckDeathPitCollide(mo)) { - if (mo->flags & MF_ENEMY || mo->flags & MF_BOSS) + if (mo->flags & MF_ENEMY || mo->flags & MF_BOSS || mo->type == MT_MINECART) { - // Kill enemies and bosses that fall into death pits. + // Kill enemies, bosses and minecarts that fall into death pits. if (mo->health) { P_KillMobj(mo, NULL, NULL, 0); @@ -6728,6 +6728,67 @@ static void P_KoopaThinker(mobj_t *koopa) } } +// Spawns and chains the minecart sides. +static void P_SpawnMinecartSegments(mobj_t *mobj, boolean mode) +{ + fixed_t x = mobj->x; + fixed_t y = mobj->y; + fixed_t z = mobj->z; + mobj_t *prevseg = mobj; + mobj_t *seg; + UINT8 i; + + for (i = 0; i < 4; i++) + { + seg = P_SpawnMobj(x, y, z, MT_MINECARTSEG); + P_SetMobjState(seg, (statenum_t)(S_MINECARTSEG_FRONT + i)); + if (i >= 2) + seg->extravalue1 = (i == 2) ? -18 : 18; + else + { + seg->extravalue2 = (i == 0) ? 24 : -24; + seg->cusval = -90; + } + if (!mode) + seg->frame &= ~FF_ANIMATE; + P_SetTarget(&prevseg->tracer, seg); + prevseg = seg; + } +} + +// Updates the chained segments. +static void P_UpdateMinecartSegments(mobj_t *mobj) +{ + mobj_t *seg = mobj->tracer; + fixed_t x = mobj->x; + fixed_t y = mobj->y; + fixed_t z = mobj->z; + angle_t ang = mobj->angle; + angle_t fa = (ang >> ANGLETOFINESHIFT) & FINEMASK; + fixed_t c = FINECOSINE(fa); + fixed_t s = FINESINE(fa); + INT32 dx, dy; + INT32 sang; + + while (seg) + { + dx = seg->extravalue1; + dy = seg->extravalue2; + sang = seg->cusval; + P_TeleportMove(seg, x + s*dx + c*dy, y - c*dx + s*dy, z); + seg->angle = ang + FixedAngle(FRACUNIT*sang); + seg->flags2 = (seg->flags2 & ~MF2_DONTDRAW) | (mobj->flags2 & MF2_DONTDRAW); + seg = seg->tracer; + } +} + +void P_HandleMinecartSegments(mobj_t *mobj) +{ + if (!mobj->tracer) + P_SpawnMinecartSegments(mobj, (mobj->type == MT_MINECART)); + P_UpdateMinecartSegments(mobj); +} + // // P_MobjThinker // @@ -7502,38 +7563,35 @@ void P_MobjThinker(mobj_t *mobj) break; case MT_PLAYER: /// \todo Have the player's dead body completely finish its animation even if they've already respawned. - if (!(mobj->flags2 & MF2_DONTDRAW)) - { - if (!mobj->fuse) - { // Go away. - /// \todo Actually go ahead and remove mobj completely, and fix any bugs and crashes doing this creates. Chasecam should stop moving, and F12 should never return to it. - mobj->momz = 0; - if (mobj->player) - mobj->flags2 |= MF2_DONTDRAW; - else // safe to remove, nobody's going to complain! - { - P_RemoveMobj(mobj); - return; - } - } - else // Apply gravity to fall downwards. + if (!mobj->fuse) + { // Go away. + /// \todo Actually go ahead and remove mobj completely, and fix any bugs and crashes doing this creates. Chasecam should stop moving, and F12 should never return to it. + mobj->momz = 0; + if (mobj->player) + mobj->flags2 |= MF2_DONTDRAW; + else // safe to remove, nobody's going to complain! { - if (mobj->player && !(mobj->fuse % 8) && (mobj->player->charflags & SF_MACHINE)) - { - fixed_t r = mobj->radius>>FRACBITS; - mobj_t *explosion = P_SpawnMobj( - mobj->x + (P_RandomRange(r, -r)<y + (P_RandomRange(r, -r)<z + (P_RandomKey(mobj->height>>FRACBITS)<movedir == DMG_DROWNED) - P_SetObjectMomZ(mobj, -FRACUNIT/2, true); // slower fall from drowning - else - P_SetObjectMomZ(mobj, -2*FRACUNIT/3, true); + P_RemoveMobj(mobj); + return; } } + else // Apply gravity to fall downwards. + { + if (mobj->player && !(mobj->fuse % 8) && (mobj->player->charflags & SF_MACHINE)) + { + fixed_t r = mobj->radius >> FRACBITS; + mobj_t *explosion = P_SpawnMobj( + mobj->x + (P_RandomRange(r, -r) << FRACBITS), + mobj->y + (P_RandomRange(r, -r) << FRACBITS), + mobj->z + (P_RandomKey(mobj->height >> FRACBITS) << FRACBITS), + MT_BOSSEXPLODE); + S_StartSound(explosion, sfx_cybdth); + } + if (mobj->movedir == DMG_DROWNED) + P_SetObjectMomZ(mobj, -FRACUNIT / 2, true); // slower fall from drowning + else + P_SetObjectMomZ(mobj, -2 * FRACUNIT / 3, true); + } break; default: break; @@ -8412,6 +8470,114 @@ void P_MobjThinker(mobj_t *mobj) mobj->flags2 |= MF2_DONTDRAW; } break; + case MT_TRAINDUSTSPAWNER: + if (leveltime % 5 == 0) { + mobj_t *traindust = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_PARTICLE); + traindust->flags = MF_SCENERY; + P_SetMobjState(traindust, S_TRAINDUST); + traindust->frame = P_RandomRange(0, 8) | FF_TRANS90; + traindust->angle = mobj->angle; + traindust->tics = TICRATE * 4; + traindust->destscale = FRACUNIT * 64; + traindust->scalespeed = FRACUNIT / 24; + P_SetScale(traindust, FRACUNIT * 6); + } + break; + case MT_TRAINSTEAMSPAWNER: + if (leveltime % 5 == 0) { + mobj_t *steam = P_SpawnMobj(mobj->x + FRACUNIT*P_SignedRandom() / 2, mobj->y + FRACUNIT*P_SignedRandom() / 2, mobj->z, MT_PARTICLE); + P_SetMobjState(steam, S_TRAINSTEAM); + steam->frame = P_RandomRange(0, 1) | FF_TRANS90; + steam->tics = TICRATE * 8; + steam->destscale = FRACUNIT * 64; + steam->scalespeed = FRACUNIT / 8; + P_SetScale(steam, FRACUNIT * 16); + steam->momx = P_SignedRandom() * 32; + steam->momy = -64 * FRACUNIT; + steam->momz = 2 * FRACUNIT; + } + break; + case MT_CANARIVORE_GAS: + { + fixed_t momz; + + if (mobj->flags2 & MF2_AMBUSH) + { + mobj->momx = FixedMul(mobj->momx, 50 * FRACUNIT / 51); + mobj->momy = FixedMul(mobj->momy, 50 * FRACUNIT / 51); + break; + } + + if (mobj->eflags & MFE_VERTICALFLIP) + { + if ((mobj->z + mobj->height + mobj->momz) <= mobj->ceilingz) + break; + } + else + { + if ((mobj->z + mobj->momz) >= mobj->floorz) + break; + } + + momz = abs(mobj->momz); + if (R_PointToDist2(0, 0, mobj->momx, mobj->momy) < momz) + P_InstaThrust(mobj, R_PointToAngle2(0, 0, mobj->momx, mobj->momy), momz); + mobj->flags |= MF_NOGRAVITY|MF_NOCLIPHEIGHT; + mobj->flags2 |= MF2_AMBUSH; + break; + } + case MT_SALOONDOOR: + { + fixed_t x = mobj->tracer->x; + fixed_t y = mobj->tracer->y; + fixed_t z = mobj->tracer->z; + angle_t oang = FixedAngle(mobj->extravalue1); + angle_t fa = (oang >> ANGLETOFINESHIFT) & FINEMASK; + fixed_t c0 = -96*FINECOSINE(fa); + fixed_t s0 = -96*FINESINE(fa); + angle_t fma; + fixed_t c, s; + angle_t angdiff; + + // Adjust angular speed + fixed_t da = AngleFixed(mobj->angle - oang); + if (da > 180*FRACUNIT) + da -= 360*FRACUNIT; + mobj->extravalue2 = 8*(mobj->extravalue2 - da/32)/9; + + // Update angle + mobj->angle += FixedAngle(mobj->extravalue2); + + angdiff = mobj->angle - FixedAngle(mobj->extravalue1); + if (angdiff > (ANGLE_90 - ANG2) && angdiff < ANGLE_180) + { + mobj->angle = FixedAngle(mobj->extravalue1) + (ANGLE_90 - ANG2); + mobj->extravalue2 /= 2; + } + else if (angdiff < (ANGLE_270 + ANG2) && angdiff >= ANGLE_180) + { + mobj->angle = FixedAngle(mobj->extravalue1) + (ANGLE_270 + ANG2); + mobj->extravalue2 /= 2; + } + + // Update position + fma = (mobj->angle >> ANGLETOFINESHIFT) & FINEMASK; + c = 48*FINECOSINE(fma); + s = 48*FINESINE(fma); + P_TeleportMove(mobj, x + c0 + c, y + s0 + s, z); + break; + } + case MT_MINECARTSPAWNER: + P_HandleMinecartSegments(mobj); + if (!mobj->fuse || mobj->fuse > TICRATE) + break; + if (mobj->fuse == 2) + { + mobj->fuse = 0; + break; + } + mobj->flags2 ^= MF2_DONTDRAW; + break; case MT_SPINFIRE: if (mobj->flags & MF_NOGRAVITY) { @@ -8488,6 +8654,10 @@ void P_MobjThinker(mobj_t *mobj) // Check fuse if (mobj->fuse) { + + if (mobj->type == MT_SNAPPER_HEAD || mobj->type == MT_SNAPPER_LEG || mobj->type == MT_MINECARTSEG) + mobj->flags2 ^= MF2_DONTDRAW; + mobj->fuse--; if (!mobj->fuse) { @@ -8789,6 +8959,16 @@ void P_PushableThinker(mobj_t *mobj) if (mobj->flags & MF_PUSHABLE && !(mobj->momx || mobj->momy)) P_TryMove(mobj, mobj->x, mobj->y, true); + if (mobj->type == MT_MINECART && mobj->health) + { + // If player is ded, remove this minecart + if (!mobj->target || P_MobjWasRemoved(mobj->target) || !mobj->target->health || !mobj->target->player || mobj->target->player->powers[pw_carry] != CR_MINECART) + { + P_KillMobj(mobj, NULL, NULL, 0); + return; + } + } + if (mobj->fuse == 1) // it would explode in the MobjThinker code { mobj_t *spawnmo; @@ -9152,6 +9332,20 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_FBOMB: mobj->flags2 |= MF2_EXPLOSION; break; + case MT_OILLAMP: + { + mobj_t* overlay = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_OVERLAY); + P_SetTarget(&overlay->target, mobj); + P_SetMobjState(overlay, S_OILLAMPFLARE); + break; + } + case MT_TNTBARREL: + mobj->momx = 1; //stack hack + break; + case MT_MINECARTEND: + mobj->tracer = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_MINECARTENDSOLID); + mobj->tracer->angle = mobj->angle + ANGLE_90; + break; default: break; } diff --git a/src/p_user.c b/src/p_user.c index ca14c64d4..54ca6c78c 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -963,7 +963,7 @@ void P_ResetPlayer(player_t *player) { player->pflags &= ~(PF_SPINNING|PF_STARTDASH|PF_STARTJUMP|PF_JUMPED|PF_NOJUMPDAMAGE|PF_GLIDING|PF_THOKKED|PF_CANCARRY|PF_SHIELDABILITY|PF_BOUNCING); - if (!(player->powers[pw_carry] == CR_NIGHTSMODE || player->powers[pw_carry] == CR_NIGHTSFALL || player->powers[pw_carry] == CR_BRAKGOOP)) + if (!(player->powers[pw_carry] == CR_NIGHTSMODE || player->powers[pw_carry] == CR_NIGHTSFALL || player->powers[pw_carry] == CR_BRAKGOOP || player->powers[pw_carry] == CR_MINECART)) player->powers[pw_carry] = CR_NONE; player->secondjump = 0; @@ -9753,6 +9753,417 @@ void P_DoPityCheck(player_t *player) } } +static sector_t *P_GetMinecartSector(fixed_t x, fixed_t y, fixed_t z, fixed_t *nz) +{ + sector_t *sec = R_PointInSubsector(x, y)->sector; + + if ((sec->ceilingheight - sec->floorheight) < 64*FRACUNIT) + return NULL; + + if (sec->ffloors) + { + ffloor_t *rover; + for (rover = sec->ffloors; rover; rover = rover->next) + { + if (!(rover->flags & FF_EXISTS)) + continue; + + *nz = *rover->t_slope ? P_GetZAt(*rover->t_slope, x, y) : *rover->topheight; + if (abs(z - *nz) <= 56*FRACUNIT) + { + sec = §ors[rover->secnum]; + return sec; + } + } + + } + + *nz = sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : sec->floorheight; + if (abs(z - *nz) > 56*FRACUNIT) + return NULL; + + return sec; +} + +static INT32 P_GetMinecartSpecialLine(sector_t *sec) +{ + INT32 line = -1; + + if (!sec) + return line; + + if (sec->tag != 0) + line = P_FindSpecialLineFromTag(16, sec->tag, -1); + + // Also try for lines facing the sector itself, with tag 0. + { + UINT32 i; + for (i = 0; i < sec->linecount; i++) + { + line_t *li = sec->lines[i]; + if (li->tag == 0 && li->special == 16 && li->frontsector == sec) + line = li - lines; + } + } + + return line; +} + +// Get an axis of a certain ID number +static mobj_t *P_GetAxis(INT32 num) +{ + thinker_t *th; + mobj_t *mobj; + + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mobj = (mobj_t *)th; + + // NiGHTS axes spawn before anything else. If this mobj doesn't have MF2_AXIS, it means we reached the axes' end. + if (!(mobj->flags2 & MF2_AXIS)) + break; + + // Skip if this axis isn't the one we want. + if (mobj->health != num) + continue; + + return mobj; + } + CONS_Alert(CONS_WARNING, "P_GetAxis: Track segment %d is missing!\n", num); + return NULL; +} + +// Auxiliary function. For a given position and axis, it calculates the nearest "valid" snap-on position. +static void P_GetAxisPosition(fixed_t x, fixed_t y, mobj_t *amo, fixed_t *newx, fixed_t *newy, angle_t *targetangle, angle_t *grind) +{ + fixed_t ax = amo->x; + fixed_t ay = amo->y; + angle_t ang; + angle_t gr = 0; + + if (amo->type == MT_AXISTRANSFERLINE) + { + ang = amo->angle; + // Extra security for cardinal directions. + if (ang == ANGLE_90 || ang == ANGLE_270) // Vertical lines + x = ax; + else if (ang == 0 || ang == ANGLE_180) // Horizontal lines + y = ay; + else // Diagonal lines + { + fixed_t distance = R_PointToDist2(ax, ay, x, y); + angle_t fad = ((R_PointToAngle2(ax, ay, x, y) - ang) >> ANGLETOFINESHIFT) & FINEMASK; + fixed_t cosine = FINECOSINE(fad); + angle_t fa = (ang >> ANGLETOFINESHIFT) & FINEMASK; + distance = FixedMul(distance, cosine); + x = ax + FixedMul(distance, FINECOSINE(fa)); + y = ay + FixedMul(distance, FINESINE(fa)); + } + } + else // Keep minecart to circle + { + fixed_t rad = amo->radius; + fixed_t distfactor = FixedDiv(rad, R_PointToDist2(ax, ay, x, y)); + + gr = R_PointToAngle2(ax, ay, x, y); + ang = gr + ANGLE_90; + x = ax + FixedMul(x - ax, distfactor); + y = ay + FixedMul(y - ay, distfactor); + } + + *newx = x; + *newy = y; + *targetangle = ang; + *grind = gr; +} + +static void P_SpawnSparks(mobj_t *mo, angle_t maindir) +{ + angle_t fa = (mo->angle >> ANGLETOFINESHIFT) & FINEMASK; + fixed_t c = FixedMul(FINECOSINE(fa), mo->radius); + fixed_t s = FixedMul(FINESINE(fa), mo->radius); + mobj_t *spark; + SINT8 b1 = (leveltime & 1) ? 1 : -1; + SINT8 b2 = (leveltime & 2) ? 1 : -1; + fixed_t r1 = FRACUNIT*P_RandomRange(-1, 1); + fixed_t r2 = FRACUNIT*P_RandomRange(-1, 1); + fixed_t r3 = FRACUNIT*P_RandomRange(-1, 1); + fixed_t fm = (maindir >> ANGLETOFINESHIFT) & FINEMASK; + + spark = P_SpawnMobj(mo->x - b2*s + b1*c, mo->y + b2*c + b1*s, mo->z, MT_MINECARTSPARK); + spark->momx = mo->momx + r1 + 8*FINECOSINE(fm); + spark->momy = mo->momy + r2 + 8*FINESINE(fm); + spark->momz = mo->momz + r3; + + P_Thrust(spark, R_PointToAngle2(mo->x, mo->y, spark->x, spark->y), 8*FRACUNIT); + P_SetScale(spark, FRACUNIT/4); + spark->destscale = spark->scale; + spark->fuse = TICRATE/3; +} + +// Performs a proximity check on a given direction looking for rails. +static mobj_t *P_LookForRails(mobj_t* mobj, fixed_t c, fixed_t s, angle_t targetangle, fixed_t xcom, fixed_t ycom) +{ + INT16 interval = 16; + INT16 fwooffset = FixedHypot(mobj->momx, mobj->momy) >> FRACBITS; + fixed_t x = mobj->x; + fixed_t y = mobj->y; + fixed_t z = mobj->z; + UINT8 i; + + for (i = 4; i <= 10; i++) + { + fixed_t nz; + INT32 lline; + + x += interval*xcom*i + fwooffset*c*i; + y += interval*ycom*i + fwooffset*s*i; + + lline = P_GetMinecartSpecialLine(P_GetMinecartSector(x, y, z, &nz)); + if (lline != -1) + { + fixed_t nx, ny; + angle_t nang, dummy, angdiff; + mobj_t *mark; + mobj_t *snax = P_GetAxis(sides[lines[lline].sidenum[0]].textureoffset >> FRACBITS); + if (!snax) + return NULL; + P_GetAxisPosition(x, y, snax, &nx, &ny, &nang, &dummy); + angdiff = ((nang - targetangle) + ANG10/2) & ~ANGLE_180; + //Axes must be directly parallel or antiparallel, give or take 5 degrees. + if (angdiff < ANG10) + { + mark = P_SpawnMobj(nx, ny, nz, mobj->info->raisestate); + return mark; + } + } + } + return NULL; +} + +static void P_ParabolicMove(mobj_t *mo, fixed_t x, fixed_t y, fixed_t z, fixed_t g, fixed_t speed) +{ + fixed_t dx = x - mo->x; + fixed_t dy = y - mo->y; + fixed_t dz = z - mo->z; + fixed_t dh = P_AproxDistance(dx, dy); + fixed_t c = FixedDiv(dx, dh); + fixed_t s = FixedDiv(dy, dh); + fixed_t fixConst = FixedDiv(speed, g); + + mo->momx = FixedMul(c, speed); + mo->momy = FixedMul(s, speed); + mo->momz = FixedDiv(dh, 2*fixConst) + FixedDiv(dz, FixedDiv(dh, fixConst/2)); +} + +static void P_MinecartThink(player_t *player) +{ + mobj_t *minecart = player->mo->tracer; + angle_t fa; + + if (!minecart || P_MobjWasRemoved(minecart) || !minecart->health) + { + // Minecart died on you, so kill yourself. + P_KillMobj(player->mo, NULL, NULL, 0); + return; + } + + //Limit player's angle to a cone. +#define MINECARTCONEMAX FixedAngle(20*FRACUNIT) + { + angle_t angdiff = player->mo->angle - minecart->angle; + if (angdiff < ANGLE_180 && angdiff > MINECARTCONEMAX) + player->mo->angle = minecart->angle + MINECARTCONEMAX; + else if (angdiff > ANGLE_180 && angdiff < InvAngle(MINECARTCONEMAX)) + player->mo->angle = minecart->angle - MINECARTCONEMAX; + + if (angdiff + minecart->angle != player->mo->angle && (!demoplayback || P_AnalogMove(player))) + { + if (player == &players[consoleplayer]) + localangle = player->mo->angle; + else if (player == &players[secondarydisplayplayer]) + localangle2 = player->mo->angle; + } + } + + // Player holding jump? + if (!(player->cmd.buttons & BT_JUMP)) + player->pflags &= ~PF_JUMPDOWN; + + // Handle segments. + P_HandleMinecartSegments(minecart); + + // Force 0 friction. + minecart->friction = FRACUNIT; + + fa = (minecart->angle >> ANGLETOFINESHIFT) & FINEMASK; + if (!P_TryMove(minecart, minecart->x + FINECOSINE(fa), minecart->y + FINESINE(fa), true)) + { + P_KillMobj(minecart, NULL, NULL, 0); + return; + } + + if (P_IsObjectOnGround(minecart)) + { + sector_t *sec; + INT32 lnum; + fixed_t dummy; + + // Just hit floor. + if (minecart->eflags & MFE_JUSTHITFLOOR) + { + S_StopSound(minecart); + S_StartSound(minecart, sfx_s3k96); + } + + sec = P_GetMinecartSector(minecart->x, minecart->y, minecart->z, &dummy); + + if (sec) + lnum = P_GetMinecartSpecialLine(sec); + + // Update axis if the cart is standing on a rail. + if (sec && lnum != -1) + { + mobj_t *axis = P_GetAxis(sides[lines[lnum].sidenum[0]].textureoffset >> FRACBITS); + fixed_t newx, newy; + angle_t targetangle, grind; + angle_t prevangle, angdiff; + mobj_t *detleft = NULL; + mobj_t *detright = NULL; + mobj_t *sidelock = NULL; + boolean jumped = false; + fixed_t currentSpeed; + + if (!axis) + { + P_KillMobj(minecart, NULL, NULL, 0); + return; + } + + minecart->movefactor = 0; + P_ResetScore(player); + // Handle angle and position + P_GetAxisPosition(minecart->x, minecart->y, axis, &newx, &newy, &targetangle, &grind); + if (axis->type != MT_AXISTRANSFERLINE) + P_SpawnSparks(minecart, grind); + P_TryMove(minecart, newx, newy, true); + + // Set angle based on target + prevangle = minecart->angle; + angdiff = targetangle - minecart->angle; + if (angdiff < ANGLE_90 + ANG2 || angdiff > ANGLE_270 - ANG2) + minecart->angle = targetangle; + else + minecart->angle = targetangle + ANGLE_180; + angdiff = (minecart->angle - prevangle); + if (angdiff && (!demoplayback || P_AnalogMove(player))) // maintain relative angle on turns + { + player->mo->angle += angdiff; + if (player == &players[consoleplayer]) + localangle += angdiff; + else if (player == &players[secondarydisplayplayer]) + localangle2 += angdiff; + } + + // Sideways detection + if (minecart->flags2 & MF2_AMBUSH) + { + angle_t fa2 = (minecart->angle >> ANGLETOFINESHIFT) & FINEMASK; + fixed_t c = FINECOSINE(fa2); + fixed_t s = FINESINE(fa2); + + detleft = P_LookForRails(minecart, c, s, targetangle, -s, c); + detright = P_LookForRails(minecart, c, s, targetangle, s, -c); + } + + // How fast are we going? + currentSpeed = FixedHypot(minecart->momx, minecart->momy); + angdiff = R_PointToAngle2(0, 0, minecart->momx, minecart->momy) - minecart->angle; + if (angdiff > ANGLE_90 && angdiff < ANGLE_270) + currentSpeed *= -1; + + // Player-specific behavior. + if (detleft && player->cmd.sidemove < 0) + sidelock = detleft; + else if (detright && player->cmd.sidemove > 0) + sidelock = detright; + + //if (player->cmd.buttons & BT_USE && currentSpeed > 4*FRACUNIT) + // currentSpeed -= FRACUNIT/8; + + // Jumping + if (sidelock || ((player->cmd.buttons & BT_JUMP) && !(player->pflags & PF_JUMPDOWN))) + { + player->pflags |= PF_JUMPDOWN; + + if (minecart->eflags & MFE_ONGROUND) + minecart->eflags &= ~MFE_ONGROUND; + minecart->z += P_MobjFlip(minecart); + if (sidelock) + P_ParabolicMove(minecart, sidelock->x, sidelock->y, sidelock->z, gravity, max(currentSpeed, 10 * FRACUNIT)); + else + minecart->momz = 10 * FRACUNIT; + + S_StartSound(minecart, sfx_s3k51); + jumped = true; + } + + if (!jumped) + { + // Natural acceleration and boosters + if (currentSpeed < minecart->info->speed) + currentSpeed += FRACUNIT/4; + + if (minecart->standingslope) + { + fixed_t fa2 = (minecart->angle >> ANGLETOFINESHIFT) & FINEMASK; + fixed_t front = P_GetZAt(minecart->standingslope, minecart->x, minecart->y); + fixed_t back = P_GetZAt(minecart->standingslope, minecart->x - FINECOSINE(fa2), minecart->y - FINESINE(fa2)); + + if (abs(front - back) < 3*FRACUNIT) + currentSpeed += (back - front)/3; + } + + // Go forward at our current speed + P_InstaThrust(minecart, minecart->angle, currentSpeed); + + // On-track ka-klong sound FX. + minecart->movecount += abs(currentSpeed); + if (minecart->movecount > 128*FRACUNIT) + { + minecart->movecount %= 128*FRACUNIT; + S_StartSound(minecart, minecart->info->activesound); + } + } + } + else + { + minecart->movefactor++; + if ((P_IsObjectOnGround(minecart) && minecart->movefactor >= 5) // off rail + || (abs(minecart->momx) < minecart->scale/2 && abs(minecart->momy) < minecart->scale/2)) // hit a wall + { + P_KillMobj(minecart, NULL, NULL, 0); + return; + } + } + } + + P_SetPlayerMobjState(player->mo, S_PLAY_STND); + + // Move player to minecart. + P_TeleportMove(player->mo, minecart->x - minecart->momx, minecart->y - minecart->momy, minecart->z + max(minecart->momz, 0) + 8*FRACUNIT); + if (player->powers[pw_carry] != CR_MINECART) + return; + player->mo->momx = player->mo->momy = player->mo->momz = 0; + P_TryMove(player->mo, player->mo->x + minecart->momx, player->mo->y + minecart->momy, true); + + if (player->powers[pw_flashing] == flashingtics) + player->powers[pw_flashing]--; +} + // // P_PlayerThink // @@ -10052,6 +10463,17 @@ void P_PlayerThink(player_t *player) // for a bit after a teleport. if (player->mo->reactiontime) player->mo->reactiontime--; + else if (player->powers[pw_carry] == CR_MINECART) + { + if (!P_AnalogMove(player)) + player->mo->angle = (cmd->angleturn << 16 /* not FRACBITS */); + + ticruned++; + if ((cmd->angleturn & TICCMD_RECEIVED) == 0) + ticmiss++; + + P_MinecartThink(player); + } else if (player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT && (player->powers[pw_carry] == CR_ROPEHANG || player->powers[pw_carry] == CR_ZOOMTUBE)) { if (player->powers[pw_carry] == CR_ROPEHANG) @@ -10113,7 +10535,15 @@ void P_PlayerThink(player_t *player) switch (player->powers[pw_carry]) { case CR_PLAYER: - player->drawangle = (player->mo->tracer->player ? player->mo->tracer->player->drawangle : player->mo->tracer->angle); + if (player->mo->tracer->player) + { + player->drawangle = player->mo->tracer->player->drawangle; + break; + } + /* FALLTHRU */ + case CR_MINECART: + case CR_GENERIC: + player->drawangle = player->mo->tracer->angle; break; /* -- in case we wanted to have the camera freely movable during zoom tubes case CR_ZOOMTUBE:*/ diff --git a/src/sounds.c b/src/sounds.c index 66d498838..56de4a9c5 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -195,6 +195,8 @@ sfxinfo_t S_sfx[NUMSFX] = {"boingf", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bouncing"}, {"corkp", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Cork fired"}, {"corkh", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Cork hit"}, + {"bowl", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bowling"}, + {"chuchu", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Train horn"}, // Menu, interface {"chchng", false, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Score"}, @@ -311,13 +313,13 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k48", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Pulse"}, {"s3k49", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Impact"}, {"s3k4a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Grab"}, - {"s3k4b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Water splash"}, + {"s3k4b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Splash"}, {"s3k4c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Heavy hit"}, {"s3k4d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Firing bullet"}, {"s3k4e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Big explosion"}, {"s3k4f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flamethrower"}, {"s3k50", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Siren"}, - {"s3k51", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Falling hazard"}, + {"s3k51", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Falling"}, {"s3k52", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spike"}, {"s3k53", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Powering up"}, {"s3k54", false, 64, 64, -1, NULL, 0, -1, -1, LUMPERROR, "Firing"}, // MetalSonic shot fire @@ -362,7 +364,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k7b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Soft bounce"}, {"s3k7c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Magnet"}, {"s3k7d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"s3k7e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Eating dirt"}, + {"s3k7e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Dust"}, {"s3k7f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Freeze"}, {"s3k80", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ice spike burst"}, {"s3k81", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Burst"}, @@ -373,7 +375,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k86", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Alarm"}, {"s3k87", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bounce"}, {"s3k88", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Metallic squeak"}, - {"s3k89", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Advanced technology"}, + {"s3k89", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Advanced tech"}, {"s3k8a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Boing"}, {"s3k8b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Powerful hit"}, {"s3k8c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Humming power"}, @@ -383,10 +385,10 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k90", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Impact"}, {"s3k91", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Closed"}, {"s3k92", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ghost"}, - {"s3k93", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Rebuilding"}, + {"s3k93", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Gas release"}, {"s3k94", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spike"}, {"s3k95", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Lava burst"}, - {"s3k96", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Falling object"}, + {"s3k96", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Landing"}, {"s3k97", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Wind"}, {"s3k98", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Falling spike"}, {"s3k99", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bounce"}, @@ -454,13 +456,13 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3kcas", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Energy"}, {"s3kcal", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Energy"}, // ditto {"s3kcbs", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominous rumbling"}, - {"s3kcbl", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominuous rumbling"}, // ditto + {"s3kcbl", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominous rumbling"}, // ditto {"s3kccs", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Collapsing"}, {"s3kccl", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Collapsing"}, // ditto {"s3kcds", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominous rumbling"}, {"s3kcdl", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominous rumbling"}, // ditto {"s3kces", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Wind tunnel"}, - {"s3kcel", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Wind tunnel"}, // ditto + {"s3kcel", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Dust devil"}, // ditto {"s3kcfs", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"s3kcfl", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // ditto {"s3kd0s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Rising"}, @@ -469,8 +471,8 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3kd1l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // ditto {"s3kd2s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Turning"}, {"s3kd2l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Moving chain"}, // ditto - {"s3kd3s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"s3kd3l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // ditto + {"s3kd3s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Digging"}, + {"s3kd3l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Digging"}, // ditto {"s3kd4s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Engine"}, {"s3kd4l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Engine"}, // ditto {"s3kd5s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Falling lava"}, diff --git a/src/sounds.h b/src/sounds.h index 90c7d9ac6..475309121 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -261,6 +261,8 @@ typedef enum sfx_boingf, sfx_corkp, sfx_corkh, + sfx_bowl, + sfx_chuchu, // Menu, interface sfx_chchng,