Merge branch 'master' into checksight-fixes

# Conflicts:
#	src/p_sight.c
This commit is contained in:
Monster Iestyn 2019-06-02 18:13:02 +01:00
commit b7f75246e4
8 changed files with 1400 additions and 86 deletions

View file

@ -2381,6 +2381,18 @@ static actionpointer_t actionpointers[] =
{{A_ParentTriesToSleep}, "A_PARENTTRIESTOSLEEP"},
{{A_CryingToMomma}, "A_CRYINGTOMOMMA"},
{{A_CheckFlags2}, "A_CHECKFLAGS2"},
{{A_Boss5FindWaypoint}, "A_BOSS5FINDWAYPOINT"},
{{A_DoNPCSkid}, "A_DONPCSKID"},
{{A_DoNPCPain}, "A_DONPCPAIN"},
{{A_PrepareRepeat}, "A_PREPAREREPEAT"},
{{A_Boss5ExtraRepeat}, "A_BOSS5EXTRAREPEAT"},
{{A_Boss5Calm}, "A_BOSS5CALM"},
{{A_Boss5CheckOnGround}, "A_BOSS5CHECKONGROUND"},
{{A_Boss5CheckFalling}, "A_BOSS5CHECKFALLING"},
{{A_Boss5PinchShot}, "A_BOSS5PINCHSHOT"},
{{A_Boss5MakeItRain}, "A_BOSS5MAKEITRAIN"},
{{A_LookForBetter}, "A_LOOKFORBETTER"},
{{A_Boss5BombExplode}, "A_BOSS5BOMBEXPLODE"},
{{NULL}, "NONE"},
@ -4704,6 +4716,96 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_JETFLAME1",
"S_JETFLAME2",
// Boss 5
"S_FANG_IDLE1",
"S_FANG_IDLE2",
"S_FANG_IDLE3",
"S_FANG_IDLE4",
"S_FANG_IDLE5",
"S_FANG_IDLE6",
"S_FANG_IDLE7",
"S_FANG_IDLE8",
"S_FANG_PAIN1",
"S_FANG_PAIN2",
"S_FANG_PATHINGSTART1",
"S_FANG_PATHINGSTART2",
"S_FANG_PATHING",
"S_FANG_BOUNCE1",
"S_FANG_BOUNCE2",
"S_FANG_BOUNCE3",
"S_FANG_BOUNCE4",
"S_FANG_FALL1",
"S_FANG_FALL2",
"S_FANG_CHECKPATH1",
"S_FANG_CHECKPATH2",
"S_FANG_PATHINGCONT1",
"S_FANG_PATHINGCONT2",
"S_FANG_PATHINGCONT3",
"S_FANG_SKID1",
"S_FANG_SKID2",
"S_FANG_SKID3",
"S_FANG_CHOOSEATTACK",
"S_FANG_FIRESTART1",
"S_FANG_FIRESTART2",
"S_FANG_FIRE1",
"S_FANG_FIRE2",
"S_FANG_FIRE3",
"S_FANG_FIRE4",
"S_FANG_FIREREPEAT",
"S_FANG_LOBSHOT1",
"S_FANG_LOBSHOT2",
"S_FANG_WAIT1",
"S_FANG_WAIT2",
"S_FANG_WALLHIT",
"S_FANG_PINCHPATHINGSTART1",
"S_FANG_PINCHPATHINGSTART2",
"S_FANG_PINCHPATHING",
"S_FANG_PINCHBOUNCE1",
"S_FANG_PINCHBOUNCE2",
"S_FANG_PINCHBOUNCE3",
"S_FANG_PINCHBOUNCE4",
"S_FANG_PINCHFALL1",
"S_FANG_PINCHFALL2",
"S_FANG_PINCHSKID1",
"S_FANG_PINCHSKID2",
"S_FANG_PINCHLOBSHOT1",
"S_FANG_PINCHLOBSHOT2",
"S_FANG_PINCHLOBSHOT3",
"S_FANG_PINCHLOBSHOT4",
"S_FANG_DIE1",
"S_FANG_DIE2",
"S_FANG_DIE3",
"S_FANG_DIE4",
"S_FANG_DIE5",
"S_FANG_DIE6",
"S_FANG_DIE7",
"S_FANG_DIE8",
"S_FANG_FLEEPATHING1",
"S_FANG_FLEEPATHING2",
"S_FANG_FLEEBOUNCE1",
"S_FANG_FLEEBOUNCE2",
"S_FANG_KO",
"S_FBOMB1",
"S_FBOMB2",
"S_FBOMB_EXPL1",
"S_FBOMB_EXPL2",
"S_FBOMB_EXPL3",
"S_FBOMB_EXPL4",
"S_FBOMB_EXPL5",
"S_FBOMB_EXPL6",
"S_TNTDUST_1",
"S_TNTDUST_2",
"S_TNTDUST_3",
"S_TNTDUST_4",
"S_TNTDUST_5",
"S_TNTDUST_6",
"S_TNTDUST_7",
"S_TNTDUST_8",
"S_FSGNA",
"S_FSGNB",
"S_FSGNC",
// Black Eggman (Boss 7)
"S_BLACKEGG_STND",
"S_BLACKEGG_STND2",
@ -7004,6 +7106,14 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_EGGMOBILE4_MACE",
"MT_JETFLAME",
// Boss 5
"MT_FANG",
"MT_FBOMB",
"MT_TNTDUST", // also used by barrel
"MT_FSGNA",
"MT_FSGNB",
"MT_FANGWAYPOINT",
// Black Eggman (Boss 7)
"MT_BLACKEGGMAN",
"MT_BLACKEGGMAN_HELPER",

View file

@ -199,7 +199,11 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[REDBALL_L], // SPR_EFIR
// Boss 5 (Arid Canyon)
&lspr[NOLIGHT], // SPR_EGGQ
&lspr[NOLIGHT], //SPR_FANG // replaces EGGQ
&lspr[NOLIGHT], //SPR_FBOM
&lspr[NOLIGHT], //SPR_FSGN
&lspr[REDBALL_L], //SPR_BARX // bomb explosion (also used by barrel)
&lspr[NOLIGHT], //SPR_BARD // bomb dust (also used by barrel)
// Boss 6 (Red Volcano)
&lspr[NOLIGHT], // SPR_EEGR

View file

@ -87,7 +87,11 @@ char sprnames[NUMSPRITES + 1][5] =
"EFIR", // Boss 4 jet flame
// Boss 5 (Arid Canyon)
"EGGQ",
"FANG", // replaces EGGQ
"FBOM",
"FSGN",
"BARX", // bomb explosion (also used by barrel)
"BARD", // bomb dust (also used by barrel)
// Boss 6 (Red Volcano)
"EGGR",
@ -1318,6 +1322,115 @@ state_t states[NUMSTATES] =
{SPR_EFIR, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_JETFLAME2}, // S_JETFLAME1
{SPR_EFIR, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_JETFLAME1}, // S_JETFLAME2
// Boss 5
{SPR_FANG, 2, 16, {A_Look}, 1, 0, S_FANG_IDLE2}, // S_FANG_IDLE1
{SPR_FANG, 3, 16, {A_Look}, 1, 0, S_FANG_IDLE3}, // S_FANG_IDLE2
{SPR_FANG, 3, 16, {A_Look}, 1, 0, S_FANG_IDLE4}, // S_FANG_IDLE3
{SPR_FANG, 3, 16, {A_Look}, 1, 0, S_FANG_IDLE5}, // S_FANG_IDLE4
{SPR_FANG, 2, 16, {A_Look}, 1, 0, S_FANG_IDLE6}, // S_FANG_IDLE5
{SPR_FANG, 1, 16, {A_Look}, 1, 0, S_FANG_IDLE7}, // S_FANG_IDLE6
{SPR_FANG, 1, 16, {A_Look}, 1, 0, S_FANG_IDLE8}, // S_FANG_IDLE7
{SPR_FANG, 1, 16, {A_Look}, 1, 0, S_FANG_IDLE1}, // S_FANG_IDLE8
{SPR_FANG, 14, 0, {A_DoNPCPain}, FRACUNIT, 0, S_FANG_PAIN2}, // S_FANG_PAIN1
{SPR_FANG, 14, 1, {A_Boss5CheckOnGround}, S_FANG_PATHINGSTART1, S_FANG_PINCHPATHINGSTART1, S_FANG_PAIN2}, // S_FANG_PAIN2
{SPR_FANG, 8, 0, {A_Boss5ExtraRepeat}, 5, 4, S_FANG_PATHINGSTART2}, // S_FANG_PATHINGSTART1
{SPR_FANG, 8, 0, {A_PlayActiveSound}, 0, 0, S_FANG_PATHING}, // S_FANG_PATHINGSTART2
{SPR_FANG, 8, 0, {A_Boss5FindWaypoint}, 0, 0, S_FANG_BOUNCE1}, // S_FANG_PATHING
{SPR_FANG, 8, 2, {A_Thrust}, 0, 1, S_FANG_BOUNCE2}, // S_FANG_BOUNCE1
{SPR_FANG, 9, 2, {NULL}, 0, 0, S_FANG_BOUNCE3}, // S_FANG_BOUNCE2
{SPR_FANG, 10, 1, {A_Boss5Jump}, 0, 0, S_FANG_BOUNCE4}, // S_FANG_BOUNCE3
{SPR_FANG, 10, 1, {A_Boss5CheckFalling}, S_FANG_CHECKPATH1, S_FANG_FALL1, S_FANG_BOUNCE4}, // S_FANG_BOUNCE4
{SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_CHECKPATH1, 0, S_FANG_FALL2}, // S_FANG_FALL1
{SPR_FANG, 13, 1, {A_Boss5CheckOnGround}, S_FANG_CHECKPATH1, 0, S_FANG_FALL1}, // S_FANG_FALL2
{SPR_FANG, 8, 0, {A_Boss5Calm}, 0, 0, S_FANG_CHECKPATH2}, // S_FANG_CHECKPATH1
{SPR_FANG, 8, 0, {A_Repeat}, 0, S_FANG_PATHINGCONT1, S_FANG_SKID1}, // S_FANG_CHECKPATH2
{SPR_FANG, 9, 0, {A_Boss5PinchShot}, MT_FBOMB, -16, S_FANG_PATHINGCONT2}, // S_FANG_PATHINGCONT1
{SPR_FANG, 9, 0, {A_PlayActiveSound}, 0, 0, S_FANG_PATHINGCONT3}, // S_FANG_PATHINGCONT2
{SPR_FANG, 9, 2, {A_Thrust}, 0, 1, S_FANG_PATHING}, // S_FANG_PATHINGCONT3
{SPR_FANG, 4, 0, {A_PlayAttackSound}, 0, 0, S_FANG_SKID2}, // S_FANG_SKID1
{SPR_FANG, 4, 1, {A_DoNPCSkid}, S_FANG_SKID3, 0, S_FANG_SKID2}, // S_FANG_SKID2
{SPR_FANG, 4, 10, {NULL}, 0, 0, S_FANG_CHOOSEATTACK}, // S_FANG_SKID3
{SPR_FANG, 0, 0, {A_RandomState}, S_FANG_LOBSHOT1, S_FANG_FIRESTART1, S_NULL}, // S_FANG_CHOOSEATTACK
{SPR_FANG, 5, 0, {A_PrepareRepeat}, 3, 0, S_FANG_FIRESTART2}, // S_FANG_FIRESTART1 // Reset loop
{SPR_FANG, 5, 18, {A_LookForBetter}, 1, 0, S_FANG_FIRE1}, // S_FANG_FIRESTART2
{SPR_FANG, 5, 5, {A_FireShot}, MT_CORK, -16, S_FANG_FIRE2}, // S_FANG_FIRE1 // Start of loop
{SPR_FANG, 6, 5, {NULL}, 0, 0, S_FANG_FIRE3}, // S_FANG_FIRE2
{SPR_FANG, 7, 5, {NULL}, 0, 0, S_FANG_FIRE4}, // S_FANG_FIRE3
{SPR_FANG, 5, 5, {NULL}, 2, 0, S_FANG_FIREREPEAT}, // S_FANG_FIRE4
{SPR_FANG, 5, 0, {A_Repeat}, 3, S_FANG_FIRE1, S_FANG_WAIT1}, // S_FANG_FIREREPEAT // End of loop
{SPR_FANG, 19, 18, {A_LookForBetter}, 1, 0, S_FANG_LOBSHOT2}, // S_FANG_LOBSHOT1
{SPR_FANG, 20, 18, {A_BrakLobShot}, MT_FBOMB, 32+(1<<16), S_FANG_WAIT1}, // S_FANG_LOBSHOT2
{SPR_FANG, FF_ANIMATE|15, 70, {NULL}, 1, 5, S_FANG_WAIT2}, // S_FANG_WAIT1
{SPR_FANG, 0, 35, {A_Look}, 1, 0, S_FANG_IDLE1}, // S_FANG_WAIT2
{SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_PATHINGSTART2, S_FANG_PINCHPATHINGSTART1, S_FANG_WALLHIT}, // S_FANG_WALLHIT
{SPR_FANG, 8, 0, {A_PrepareRepeat}, 1, 0, S_FANG_PINCHPATHINGSTART2}, // S_FANG_PINCHPATHINGSTART1
{SPR_FANG, 8, 0, {A_PlayActiveSound}, 0, 0, S_FANG_PINCHPATHING}, // S_FANG_PINCHPATHINGSTART2
{SPR_FANG, 8, 0, {A_Boss5FindWaypoint}, 1, 0, S_FANG_PINCHBOUNCE1}, // S_FANG_PINCHPATHING
{SPR_FANG, 8, 2, {A_Thrust}, 0, 1, S_FANG_PINCHBOUNCE2}, // S_FANG_PINCHBOUNCE1
{SPR_FANG, 9, 2, {NULL}, 0, 0, S_FANG_PINCHBOUNCE3}, // S_FANG_PINCHBOUNCE2
{SPR_FANG, 10, 2, {A_Boss5Jump}, 0, 0, S_FANG_PINCHBOUNCE4}, // S_FANG_PINCHBOUNCE3
{SPR_FANG, 10, 1, {A_Boss5CheckFalling}, S_FANG_PINCHSKID1, S_FANG_PINCHFALL1, S_FANG_PINCHBOUNCE4}, // S_FANG_PINCHBOUNCE4
{SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_PINCHSKID1, 0, S_FANG_PINCHFALL2}, // S_FANG_PINCHFALL1
{SPR_FANG, 13, 1, {A_Boss5CheckOnGround}, S_FANG_PINCHSKID1, 0, S_FANG_PINCHFALL1}, // S_FANG_PINCHFALL2
{SPR_FANG, 4, 0, {A_PlayAttackSound}, 0, 0, S_FANG_PINCHSKID2}, // S_FANG_PINCHSKID1
{SPR_FANG, 4, 1, {A_DoNPCSkid}, S_FANG_PINCHLOBSHOT1, 0, S_FANG_PINCHSKID2}, // S_FANG_PINCHSKID2
{SPR_FANG, 19, 18, {A_FaceTarget}, 3, 0, S_FANG_PINCHLOBSHOT2}, // S_FANG_PINCHLOBSHOT1
{SPR_FANG, 20, 30, {A_Boss5MakeItRain}, MT_FBOMB, -16, S_FANG_PINCHLOBSHOT3}, // S_FANG_PINCHLOBSHOT2
{SPR_FANG, 19, 18, {A_LinedefExecute}, LE_BOSS4DROP, 0, S_FANG_PINCHLOBSHOT4}, // S_FANG_PINCHLOBSHOT3
{SPR_FANG, 19, 0, {A_Boss5Calm}, 0, 0, S_FANG_PATHINGSTART1}, // S_FANG_PINCHLOBSHOT4
{SPR_FANG, 14, 0, {A_DoNPCPain}, 0, 0, S_FANG_DIE2}, // S_FANG_DIE1
{SPR_FANG, 14, 1, {A_Boss5CheckOnGround}, S_FANG_DIE3, 0, S_FANG_DIE2}, // S_FANG_DIE2
{SPR_FANG, 17, 0, {A_Scream}, 0, 0, S_FANG_DIE4}, // S_FANG_DIE3
{SPR_FANG, 17, 104, {NULL}, 0, 0, S_FANG_DIE5}, // S_FANG_DIE4
{SPR_FANG, 11, 0, {A_PlaySound}, sfx_jump, 0, S_FANG_DIE6}, // S_FANG_DIE5
{SPR_FANG, 11, 1, {A_ZThrust}, 6, (1<<16)|1, S_FANG_DIE7}, // S_FANG_DIE6
{SPR_FANG, 11, 1, {A_Boss5CheckFalling}, S_FANG_FLEEPATHING1, S_FANG_DIE8, S_FANG_DIE7}, // S_FANG_DIE7
{SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_FLEEPATHING1, 0, S_FANG_DIE8}, // S_FANG_DIE8
{SPR_FANG, 9, 0, {A_PlayActiveSound}, 0, 0, S_FANG_FLEEPATHING2}, // S_FANG_FLEEPATHING1
{SPR_FANG, 8, 2, {A_Boss5FindWaypoint}, 2, 0, S_FANG_FLEEBOUNCE1}, // S_FANG_FLEEPATHING2
{SPR_FANG, 9, 2, {NULL}, 0, 0, S_FANG_FLEEBOUNCE2}, // S_FANG_FLEEBOUNCE1
{SPR_FANG, 10, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_FANG_FLEEBOUNCE2
{SPR_FANG, 18, 7*TICRATE, {NULL}, 0, 0, S_NULL}, // S_FANG_KO
{SPR_FBOM, 0, 1, {A_GhostMe}, 0, 0, S_FBOMB2}, // S_FBOMB1
{SPR_FBOM, 1, 1, {A_GhostMe}, 0, 0, S_FBOMB1}, // S_FBOMB2
{SPR_BARX, 0|FF_FULLBRIGHT, 3, {A_SetObjectFlags}, MF_NOCLIP|MF_NOGRAVITY|MF_NOBLOCKMAP, 0, S_FBOMB_EXPL2}, // S_FBOMB_EXPL1
{SPR_BARX, 1|FF_FULLBRIGHT, 2, {A_Boss5BombExplode}, MT_TNTDUST, 0, S_FBOMB_EXPL3}, // S_FBOMB_EXPL2
{SPR_BARX, 1|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_FBOMB_EXPL4}, // S_FBOMB_EXPL3
{SPR_BARX, 2|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FBOMB_EXPL5}, // S_FBOMB_EXPL4
{SPR_BARX, 3|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FBOMB_EXPL6}, // S_FBOMB_EXPL5
{SPR_NULL, 0, 2*TICRATE, {NULL}, 0, 0, S_NULL}, // S_FBOMB_EXPL6
{SPR_BARD, 0|FF_TRANS90, 2, {NULL}, 0, 0, S_TNTDUST_2}, // S_TNTDUST_1
{SPR_BARD, 0|FF_TRANS30, 2*TICRATE, {A_SetRandomTics}, 2, TICRATE, S_TNTDUST_3}, // S_TNTDUST_2
{SPR_BARD, 0|FF_TRANS40, 10, {NULL}, 0, 0, S_TNTDUST_4}, // S_TNTDUST_3
{SPR_BARD, 0|FF_TRANS50, 10, {NULL}, 0, 0, S_TNTDUST_5}, // S_TNTDUST_4
{SPR_BARD, 0|FF_TRANS60, 10, {NULL}, 0, 0, S_TNTDUST_6}, // S_TNTDUST_5
{SPR_BARD, 0|FF_TRANS70, 10, {NULL}, 0, 0, S_TNTDUST_7}, // S_TNTDUST_6
{SPR_BARD, 0|FF_TRANS80, 10, {NULL}, 0, 0, S_TNTDUST_8}, // S_TNTDUST_7
{SPR_BARD, 0|FF_TRANS90, 10, {NULL}, 0, 0, S_NULL}, // S_TNTDUST_8
{SPR_FSGN, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_FSGNA
{SPR_FSGN, 1|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_FSGNB
{SPR_FSGN, 2|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_FSGNC
// Black Eggman (Boss 7)
{SPR_BRAK, 0, 1, {A_SetReactionTime}, 0, 0, S_BLACKEGG_STND2}, // S_BLACKEGG_STND
{SPR_BRAK, 0, 7, {A_Look}, 1, 0, S_BLACKEGG_STND2}, // S_BLACKEGG_STND2
{SPR_BRAK, 1, 7, {NULL}, 0, 0, S_BLACKEGG_WALK2}, // S_BLACKEGG_WALK1
@ -5261,6 +5374,167 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_FANG
204, // doomednum
S_FANG_IDLE1, // spawnstate
8, // spawnhealth
S_FANG_PATHINGSTART1, // seestate
sfx_None, // seesound
0, // reactiontime
sfx_skid, // attacksound
S_FANG_PAIN1, // painstate
0, // painchance
sfx_s3k5d, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_FANG_DIE1, // deathstate
S_FANG_KO, // xdeathstate
sfx_s3k90, // deathsound
0, // speed
24*FRACUNIT, // radius
60*FRACUNIT, // height
0, // display offset
0, // mass
3, // damage
sfx_boingf, // activesound
MF_SPECIAL|MF_BOSS|MF_SHOOTABLE, // flags
S_NULL // raisestate
},
{ // MT_FBOMB
-1, // doomednum
S_FBOMB1, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_s3k51, // seesound
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_FBOMB_EXPL1, // deathstate
S_NULL, // xdeathstate
sfx_s3k4e, // deathsound
20*FRACUNIT, // speed
24*FRACUNIT, // radius
48*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_s3k8d, // activesound
MF_NOBLOCKMAP|MF_MISSILE, // flags
S_NULL // raisestate
},
{ // MT_TNTDUST
-1, // doomednum
S_TNTDUST_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
20*FRACUNIT, // speed
16*FRACUNIT, // radius
32*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_FSGNA
-1, // doomednum
S_FSGNA, // 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_mspogo, // deathsound
0, // speed
124*FRACUNIT, // radius
124*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
S_NULL // raisestate
},
{ // MT_FSGNB
-1, // doomednum
S_FSGNB, // 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_FSGNC, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
124*FRACUNIT, // radius
640*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY|MF_SOLID, // flags
S_NULL // raisestate
},
{ // MT_FANGWAYPOINT
294, // 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
FRACUNIT, // radius
FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOTHINK, // flags
S_NULL // raisestate
},
{ // MT_BLACKEGGMAN
206, // doomednum
S_BLACKEGG_STND, // spawnstate

View file

@ -239,6 +239,18 @@ void A_WhoCaresIfYourSonIsABee();
void A_ParentTriesToSleep();
void A_CryingToMomma();
void A_CheckFlags2();
void A_Boss5FindWaypoint();
void A_DoNPCSkid();
void A_DoNPCPain();
void A_PrepareRepeat();
void A_Boss5ExtraRepeat();
void A_Boss5Calm();
void A_Boss5CheckOnGround();
void A_Boss5CheckFalling();
void A_Boss5PinchShot();
void A_Boss5MakeItRain();
void A_LookForBetter();
void A_Boss5BombExplode();
// ratio of states to sprites to mobj types is roughly 6 : 1 : 1
#define NUMMOBJFREESLOTS 256
@ -306,7 +318,11 @@ typedef enum sprite
SPR_EFIR, // Boss 4 jet flame
// Boss 5 (Arid Canyon)
SPR_EGGQ,
SPR_FANG, // replaces EGGQ
SPR_FBOM,
SPR_FSGN,
SPR_BARX, // bomb explosion (also used by barrel)
SPR_BARD, // bomb dust (also used by barrel)
// Boss 6 (Red Volcano)
SPR_EGGR,
@ -1445,6 +1461,96 @@ typedef enum state
S_JETFLAME1,
S_JETFLAME2,
// Boss 5
S_FANG_IDLE1,
S_FANG_IDLE2,
S_FANG_IDLE3,
S_FANG_IDLE4,
S_FANG_IDLE5,
S_FANG_IDLE6,
S_FANG_IDLE7,
S_FANG_IDLE8,
S_FANG_PAIN1,
S_FANG_PAIN2,
S_FANG_PATHINGSTART1,
S_FANG_PATHINGSTART2,
S_FANG_PATHING,
S_FANG_BOUNCE1,
S_FANG_BOUNCE2,
S_FANG_BOUNCE3,
S_FANG_BOUNCE4,
S_FANG_FALL1,
S_FANG_FALL2,
S_FANG_CHECKPATH1,
S_FANG_CHECKPATH2,
S_FANG_PATHINGCONT1,
S_FANG_PATHINGCONT2,
S_FANG_PATHINGCONT3,
S_FANG_SKID1,
S_FANG_SKID2,
S_FANG_SKID3,
S_FANG_CHOOSEATTACK,
S_FANG_FIRESTART1,
S_FANG_FIRESTART2,
S_FANG_FIRE1,
S_FANG_FIRE2,
S_FANG_FIRE3,
S_FANG_FIRE4,
S_FANG_FIREREPEAT,
S_FANG_LOBSHOT1,
S_FANG_LOBSHOT2,
S_FANG_WAIT1,
S_FANG_WAIT2,
S_FANG_WALLHIT,
S_FANG_PINCHPATHINGSTART1,
S_FANG_PINCHPATHINGSTART2,
S_FANG_PINCHPATHING,
S_FANG_PINCHBOUNCE1,
S_FANG_PINCHBOUNCE2,
S_FANG_PINCHBOUNCE3,
S_FANG_PINCHBOUNCE4,
S_FANG_PINCHFALL1,
S_FANG_PINCHFALL2,
S_FANG_PINCHSKID1,
S_FANG_PINCHSKID2,
S_FANG_PINCHLOBSHOT1,
S_FANG_PINCHLOBSHOT2,
S_FANG_PINCHLOBSHOT3,
S_FANG_PINCHLOBSHOT4,
S_FANG_DIE1,
S_FANG_DIE2,
S_FANG_DIE3,
S_FANG_DIE4,
S_FANG_DIE5,
S_FANG_DIE6,
S_FANG_DIE7,
S_FANG_DIE8,
S_FANG_FLEEPATHING1,
S_FANG_FLEEPATHING2,
S_FANG_FLEEBOUNCE1,
S_FANG_FLEEBOUNCE2,
S_FANG_KO,
S_FBOMB1,
S_FBOMB2,
S_FBOMB_EXPL1,
S_FBOMB_EXPL2,
S_FBOMB_EXPL3,
S_FBOMB_EXPL4,
S_FBOMB_EXPL5,
S_FBOMB_EXPL6,
S_TNTDUST_1,
S_TNTDUST_2,
S_TNTDUST_3,
S_TNTDUST_4,
S_TNTDUST_5,
S_TNTDUST_6,
S_TNTDUST_7,
S_TNTDUST_8,
S_FSGNA,
S_FSGNB,
S_FSGNC,
// Black Eggman (Boss 7)
S_BLACKEGG_STND,
S_BLACKEGG_STND2,
@ -3765,6 +3871,14 @@ typedef enum mobj_type
MT_EGGMOBILE4_MACE,
MT_JETFLAME,
// Boss 5
MT_FANG,
MT_FBOMB,
MT_TNTDUST, // also used by barrel
MT_FSGNA,
MT_FSGNB,
MT_FANGWAYPOINT,
// Black Eggman (Boss 7)
MT_BLACKEGGMAN,
MT_BLACKEGGMAN_HELPER,

View file

@ -15,6 +15,7 @@
#include "doomdef.h"
#include "g_game.h"
#include "p_local.h"
#include "p_setup.h"
#include "r_main.h"
#include "r_state.h"
#include "s_sound.h"
@ -22,6 +23,7 @@
#include "m_misc.h"
#include "r_things.h"
#include "i_video.h"
#include "z_zone.h"
#include "lua_hook.h"
#ifdef HW3SOUND
@ -266,6 +268,18 @@ void A_WhoCaresIfYourSonIsABee(mobj_t *actor);
void A_ParentTriesToSleep(mobj_t *actor);
void A_CryingToMomma(mobj_t *actor);
void A_CheckFlags2(mobj_t *actor);
void A_Boss5FindWaypoint(mobj_t *actor);
void A_DoNPCSkid(mobj_t *actor);
void A_DoNPCPain(mobj_t *actor);
void A_PrepareRepeat(mobj_t *actor);
void A_Boss5ExtraRepeat(mobj_t *actor);
void A_Boss5Calm(mobj_t *actor);
void A_Boss5CheckOnGround(mobj_t *actor);
void A_Boss5CheckFalling(mobj_t *actor);
void A_Boss5PinchShot(mobj_t *actor);
void A_Boss5MakeItRain(mobj_t *actor);
void A_LookForBetter(mobj_t *actor);
void A_Boss5BombExplode(mobj_t *actor);
//for p_enemy.c
//
@ -3549,59 +3563,103 @@ bossjustdie:
else if (P_MobjWasRemoved(mo))
return;
#endif
if (mo->type == MT_BLACKEGGMAN || mo->type == MT_CYBRAKDEMON)
switch (mo->type)
{
mo->flags |= MF_NOCLIP;
mo->flags &= ~MF_SPECIAL;
case MT_BLACKEGGMAN:
case MT_CYBRAKDEMON:
{
mo->flags |= MF_NOCLIP;
mo->flags &= ~MF_SPECIAL;
S_StartSound(NULL, sfx_befall);
}
else if (mo->type == MT_KOOPA)
{
junk.tag = 650;
EV_DoCeiling(&junk, raiseToHighest);
return;
}
else // eggmobiles
{
// Stop exploding and prepare to run.
P_SetMobjState(mo, mo->info->xdeathstate);
if (P_MobjWasRemoved(mo))
S_StartSound(NULL, sfx_befall);
break;
}
case MT_KOOPA:
{
junk.tag = 650;
EV_DoCeiling(&junk, raiseToHighest);
return;
P_SetTarget(&mo->target, NULL);
// Flee! Flee! Find a point to escape to! If none, just shoot upward!
// scan the thinkers to find the runaway point
for (th = thinkercap.next; th != &thinkercap; th = th->next)
}
case MT_FANG:
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
continue;
mo2 = (mobj_t *)th;
if (mo2->type == MT_BOSSFLYPOINT)
if (mo->tracer)
{
// If this one's closer then the last one, go for it.
if (!mo->target ||
P_AproxDistance(P_AproxDistance(mo->x - mo2->x, mo->y - mo2->y), mo->z - mo2->z) <
P_AproxDistance(P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y), mo->z - mo->target->z))
P_SetTarget(&mo->target, mo2);
// Otherwise... Don't!
var1 = var2 = 0;
A_Boss5Jump(mo);
mo->momx = ((16 - 1)*mo->momx)/16;
mo->momy = ((16 - 1)*mo->momy)/16;
if (!(mo->flags2 & MF2_AMBUSH))
{
const fixed_t time = FixedHypot(mo->tracer->x - mo->x, mo->tracer->y - mo->y)/FixedHypot(mo->momx, mo->momy);
const fixed_t speed = 64*FRACUNIT;
mobj_t *pole = P_SpawnMobj(
mo->tracer->x - P_ReturnThrustX(mo->tracer, mo->tracer->angle, speed*time),
mo->tracer->y - P_ReturnThrustY(mo->tracer, mo->tracer->angle, speed*time),
mo->tracer->floorz + 4*FRACUNIT,
MT_FSGNB);
P_SetTarget(&pole->tracer, P_SpawnMobj(
pole->x + P_ReturnThrustX(pole, mo->tracer->angle, FRACUNIT),
pole->y + P_ReturnThrustY(pole, mo->tracer->angle, FRACUNIT),
pole->z + 256*FRACUNIT,
MT_FSGNA));
pole->angle = mo->tracer->angle;
pole->tracer->angle = pole->angle - ANGLE_90;
pole->momx = P_ReturnThrustX(pole, pole->angle, speed);
pole->momy = P_ReturnThrustY(pole, pole->angle, speed);
pole->tracer->momx = pole->momx;
pole->tracer->momy = pole->momy;
}
}
else
{
P_SetObjectMomZ(mo, 10*FRACUNIT, false);
mo->flags |= MF_NOGRAVITY;
}
mo->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT;
return;
}
mo->flags |= MF_NOGRAVITY|MF_NOCLIP;
mo->flags |= MF_NOCLIPHEIGHT;
if (mo->target)
default: //eggmobiles
{
mo->angle = R_PointToAngle2(mo->x, mo->y, mo->target->x, mo->target->y);
mo->flags2 |= MF2_BOSSFLEE;
mo->momz = FixedMul(FixedDiv(mo->target->z - mo->z, P_AproxDistance(mo->x-mo->target->x,mo->y-mo->target->y)), FixedMul(2*FRACUNIT, mo->scale));
// Stop exploding and prepare to run.
P_SetMobjState(mo, mo->info->xdeathstate);
if (P_MobjWasRemoved(mo))
return;
P_SetTarget(&mo->target, NULL);
// Flee! Flee! Find a point to escape to! If none, just shoot upward!
// scan the thinkers to find the runaway point
for (th = thinkercap.next; th != &thinkercap; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
continue;
mo2 = (mobj_t *)th;
if (mo2->type == MT_BOSSFLYPOINT)
{
// If this one's closer then the last one, go for it.
if (!mo->target ||
P_AproxDistance(P_AproxDistance(mo->x - mo2->x, mo->y - mo2->y), mo->z - mo2->z) <
P_AproxDistance(P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y), mo->z - mo->target->z))
P_SetTarget(&mo->target, mo2);
// Otherwise... Don't!
}
}
mo->flags |= MF_NOGRAVITY|MF_NOCLIP;
mo->flags |= MF_NOCLIPHEIGHT;
if (mo->target)
{
mo->angle = R_PointToAngle2(mo->x, mo->y, mo->target->x, mo->target->y);
mo->flags2 |= MF2_BOSSFLEE;
mo->momz = FixedMul(FixedDiv(mo->target->z - mo->z, P_AproxDistance(mo->x-mo->target->x,mo->y-mo->target->y)), FixedMul(2*FRACUNIT, mo->scale));
}
else
mo->momz = FixedMul(2*FRACUNIT, mo->scale);
break;
}
else
mo->momz = FixedMul(2*FRACUNIT, mo->scale);
}
if (mo->type == MT_EGGMOBILE2)
@ -11852,3 +11910,614 @@ void A_CheckFlags2(mobj_t *actor)
if (actor->flags2 & locvar1)
P_SetMobjState(actor, (statenum_t)locvar2);
}
// Function: A_Boss5FindWaypoint
//
// Description: Finds the next waypoint in sequence and sets it as its tracer.
//
// var1 = if 1, always go to ambush-marked waypoint. if 2, go to MT_BOSSFLYPOINT.
// var2 = unused
//
void A_Boss5FindWaypoint(mobj_t *actor)
{
INT32 locvar1 = var1;
//INT32 locvar2 = var2;
boolean avoidcenter;
UINT32 i;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_Boss5FindWaypoint", actor))
return;
#endif
avoidcenter = !actor->tracer || (actor->health == actor->info->damage+1);
if (locvar1 == 2) // look for the boss waypoint
{
for (i = 0; i < nummapthings; i++)
{
if (!mapthings[i].mobj)
continue;
if (mapthings[i].mobj->type != MT_BOSSFLYPOINT)
continue;
P_SetTarget(&actor->tracer, mapthings[i].mobj);
break;
}
if (i == nummapthings)
return; // no boss flypoints found
}
else if (locvar1 == 1) // always go to ambush-marked waypoint
{
if (avoidcenter)
goto nowaypoints; // if we can't go the center, why on earth are we doing this?
for (i = 0; i < nummapthings; i++)
{
if (!mapthings[i].mobj)
continue;
if (mapthings[i].mobj->type != MT_FANGWAYPOINT)
continue;
if (mapthings[i].options & MTF_AMBUSH)
{
P_SetTarget(&actor->tracer, mapthings[i].mobj);
break;
}
}
if (i == nummapthings)
goto nowaypoints;
}
else // locvar1 == 0
{
fixed_t hackoffset = P_MobjFlip(actor)*56*FRACUNIT;
INT32 numwaypoints = 0;
mobj_t **waypoints;
INT32 key;
actor->z += hackoffset;
// first, count how many waypoints we have
for (i = 0; i < nummapthings; i++)
{
if (!mapthings[i].mobj)
continue;
if (mapthings[i].mobj->type != MT_FANGWAYPOINT)
continue;
if (actor->tracer == mapthings[i].mobj) // this was your tracer last time
continue;
if (mapthings[i].options & MTF_AMBUSH)
{
if (avoidcenter)
continue;
}
else if (mapthings[i].mobj->reactiontime > 0)
continue;
if (!P_CheckSight(actor, mapthings[i].mobj))
continue;
numwaypoints++;
}
// players also count as waypoints apparently
if (actor->extravalue2 > 1)
{
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
if (!players[i].mo)
continue;
if (players[i].spectator)
continue;
if (players[i].mo->health <= 0)
continue;
if (players[i].powers[pw_flashing])
continue;
if (actor->tracer == players[i].mo) // this was your tracer last time
continue;
if (!P_CheckSight(actor, players[i].mo))
continue;
numwaypoints++;
}
}
if (!numwaypoints)
{
// restore z position
actor->z -= hackoffset;
goto nowaypoints; // no waypoints :(
}
// allocate the table and reset count to zero
waypoints = Z_Calloc(sizeof(*waypoints)*numwaypoints, PU_STATIC, NULL);
numwaypoints = 0;
// now find them again and add them to the table!
for (i = 0; i < nummapthings; i++)
{
if (!mapthings[i].mobj)
continue;
if (mapthings[i].mobj->type != MT_FANGWAYPOINT)
continue;
if (actor->tracer == mapthings[i].mobj) // this was your tracer last time
continue;
if (mapthings[i].options & MTF_AMBUSH)
{
if (avoidcenter)
continue;
}
else if (mapthings[i].mobj->reactiontime > 0)
{
mapthings[i].mobj->reactiontime--;
continue;
}
if (!P_CheckSight(actor, mapthings[i].mobj))
continue;
waypoints[numwaypoints++] = mapthings[i].mobj;
}
if (actor->extravalue2 > 1)
{
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
if (!players[i].mo)
continue;
if (players[i].spectator)
continue;
if (players[i].mo->health <= 0)
continue;
if (players[i].powers[pw_flashing])
continue;
if (actor->tracer == players[i].mo) // this was your tracer last time
continue;
if (!P_CheckSight(actor, players[i].mo))
continue;
waypoints[numwaypoints++] = players[i].mo;
}
}
// restore z position
actor->z -= hackoffset;
if (!numwaypoints)
{
Z_Free(waypoints); // free table
goto nowaypoints; // ???
}
key = P_RandomKey(numwaypoints);
P_SetTarget(&actor->tracer, waypoints[key]);
if (actor->tracer->type == MT_FANGWAYPOINT)
actor->tracer->reactiontime = numwaypoints/4; // Monster Iestyn: is this how it should be? I count center waypoints as waypoints unlike the original Lua script
Z_Free(waypoints); // free table
}
// now face the tracer you just set!
A_FaceTracer(actor);
return;
nowaypoints:
// no waypoints at all, guess the mobj has to disappear
if (actor->health)
P_KillMobj(actor, NULL, NULL, 0);
else
P_RemoveMobj(actor);
return;
}
// Function: A_DoNPCSkid
//
// Description: Something that looks like a player is skidding.
//
// var1 = state to change to upon being slow enough
// var2 = minimum speed
//
void A_DoNPCSkid(mobj_t *actor)
{
INT32 locvar1 = var1;
INT32 locvar2 = var2;
fixed_t x, y, z;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_DoNPCSkid", actor))
return;
#endif
x = actor->x;
y = actor->y;
z = actor->z;
if (!locvar2)
locvar2 = FRACUNIT/2;
if ((FixedHypot(actor->momx, actor->momy) < locvar2)
|| !P_TryMove(actor, actor->x + actor->momx, actor->y + actor->momy, false))
{
actor->momx = actor->momy = 0;
P_SetMobjState(actor, locvar1);
return;
}
else
{
actor->momx = (2*actor->momx)/3;
actor->momy = (2*actor->momy)/3;
}
P_TeleportMove(actor, x, y, z);
// Spawn a particle every 3 tics.
if (!(leveltime % 3))
{
mobj_t *particle = P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_SPINDUST);
particle->tics = 10;
P_SetScale(particle, 2*actor->scale/3);
particle->destscale = actor->scale;
P_SetObjectMomZ(particle, FRACUNIT, false);
}
}
// Function: A_DoNPCPain
//
// Description: Something that looks like a player was hit, put them in pain.
//
// var1 = If zero, always fling the same amount.
// Otherwise, slowly reduce the vertical
// and horizontal speed to the base value
// multiplied by this the more damage is done.
// var2 = If zero, use default fling values.
// Otherwise, vertical and horizontal speed
// will be multiplied by this.
//
void A_DoNPCPain(mobj_t *actor)
{
INT32 locvar1 = var1;
INT32 locvar2 = var2;
fixed_t vspeed = 0;
fixed_t hspeed = FixedMul(4*FRACUNIT, actor->scale);
#ifdef HAVE_BLUA
if (LUA_CallAction("A_DoNPCPain", actor))
return;
#endif
actor->flags &= ~(MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT);
var1 = var2 = 0;
A_Pain(actor);
actor->z += P_MobjFlip(actor);
if (actor->eflags & MFE_UNDERWATER)
vspeed = FixedDiv(10511*FRACUNIT,2600*FRACUNIT);
else
vspeed = FixedDiv(69*FRACUNIT,10*FRACUNIT);
if (actor->target)
actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x + actor->target->momx, actor->target->y + actor->target->momy);
if (locvar1)
{
if (!actor->info->spawnhealth)
return; // there's something very wrong here if you're using this action on something with no starting health
locvar1 += ((FRACUNIT - locvar1)/actor->info->spawnhealth)*actor->health;
hspeed = FixedMul(hspeed, locvar1);
vspeed = FixedMul(vspeed, locvar1);
}
if (locvar2)
{
hspeed = FixedMul(hspeed, locvar2);
vspeed = FixedMul(vspeed, locvar2);
}
P_SetObjectMomZ(actor, vspeed, false);
P_InstaThrust(actor, actor->angle, -hspeed);
}
// Function: A_PrepareRepeat
//
// Description: Simple way to prepare A_Repeat.
//
// var1 = value to set extravalue2 to
// var2 = unused
//
void A_PrepareRepeat(mobj_t *actor)
{
INT32 locvar1 = var1;
//INT32 locvar2 = var2;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_PrepareRepeat", actor))
return;
#endif
actor->extravalue2 = locvar1;
}
// Function: A_Boss5ExtraRepeat
//
// Description: Simple way to prepare A_Repeat.
//
// var1 = maximum value to setextravalue2 to (normally)
// var2 = pinch annoyance
//
void A_Boss5ExtraRepeat(mobj_t *actor)
{
INT32 locvar1 = var1;
INT32 locvar2 = var2;
INT32 calc;
INT32 locspawn;
INT32 lochealth;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_Boss5ExtraRepeat", actor))
return;
#endif
if (actor->extravalue2 > 0 && !(actor->flags2 & MF2_FRET))
return;
locspawn = actor->info->spawnhealth - actor->info->damage;
lochealth = actor->health - actor->info->damage;
if (locspawn <= 0 || lochealth <= 0)
calc = locvar1;
else
calc = (locvar1*(locspawn - lochealth))/locspawn;
if (calc > 2)
actor->extravalue2 = 1 + calc/2 + P_RandomKey(calc/2);
else
actor->extravalue2 = 1 + calc;
if (lochealth <= 0)
actor->extravalue2 += locvar2;
}
// Function: A_Boss5Calm
//
// Description: Simple way to disable MF2_FRET (and enable MF_SHOOTABLE the first time it's called)
//
// var1 = unused
// var2 = unused
//
void A_Boss5Calm(mobj_t *actor)
{
#ifdef HAVE_BLUA
if (LUA_CallAction("A_Boss5Calm", actor))
return;
#endif
actor->flags |= MF_SHOOTABLE;
actor->flags2 &= ~MF2_FRET;
}
// Function: A_Boss5CheckOnGround
//
// Description: Ground checker.
//
// var1 = state to change to upon hitting ground.
// var2 = state to change to upon hitting ground if health == pinchhealth, assuming it exists
//
void A_Boss5CheckOnGround(mobj_t *actor)
{
INT32 locvar1 = var1;
INT32 locvar2 = var2;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_Boss5CheckOnGround", actor))
return;
#endif
if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz)
|| (actor->eflags & MFE_VERTICALFLIP && actor->z + actor->height >= actor->ceilingz))
{
if (locvar2 && (!actor->health || (actor->health == actor->info->damage && !(actor->flags2 & MF2_STRONGBOX))))
P_SetMobjState(actor, locvar2);
else
P_SetMobjState(actor, locvar1);
}
if (actor->tracer && P_AproxDistance(actor->tracer->x - actor->x, actor->tracer->y - actor->y) < 2*actor->radius)
{
actor->momx = (4*actor->momx)/5;
actor->momy = (4*actor->momy)/5;
}
}
// Function: A_Boss5CheckFalling
//
// Description: Falling checker.
//
// var1 = state to change to when hitting ground.
// var2 = state to change to when falling.
//
void A_Boss5CheckFalling(mobj_t *actor)
{
INT32 locvar1 = var1;
INT32 locvar2 = var2;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_Boss5CheckFalling", actor))
return;
#endif
if (actor->health && actor->extravalue2 > 1)
{
var1 = locvar1;
var2 = 0;
A_Boss5CheckOnGround(actor);
return;
}
if (P_MobjFlip(actor)*actor->momz <= 0)
P_SetMobjState(actor, locvar2);
}
// Function: A_Boss5PinchShot
//
// Description: Fires a missile directly upwards if in pinch.
//
// var1 = object # to shoot
// var2 = height offset (from default of +48 FU)
//
void A_Boss5PinchShot(mobj_t *actor)
{
INT32 locvar1 = var1;
INT32 locvar2 = var2;
fixed_t zoffset;
mobj_t *missile;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_Boss5PinchShot", actor))
return;
#endif
if (actor->health > actor->info->damage)
return;
if (actor->eflags & MFE_VERTICALFLIP)
zoffset = actor->z + actor->height - FixedMul((48 + locvar2)*FRACUNIT, actor->scale);
else
zoffset = actor->z + FixedMul((48 + locvar2)*FRACUNIT, actor->scale);
missile = P_SpawnPointMissile(actor, actor->x, actor->y, zoffset, locvar1,
actor->x, actor->y, zoffset);
if (!missile)
return;
missile->momx = missile->momy = 0;
missile->momz = P_MobjFlip(actor)*missile->info->speed/2;
}
// Function: A_Boss5MakeItRain
//
// Description: Pinch crisis.
//
// var1 = object # to shoot
// var2 = height offset (from default of +48 FU)
//
void A_Boss5MakeItRain(mobj_t *actor)
{
INT32 locvar1 = var1;
INT32 locvar2 = var2;
INT32 offset = (48 + locvar2)<<16; // upper 16 bits, not fixed_t!
INT32 i;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_Boss5MakeItRain", actor))
return;
#endif
actor->flags2 |= MF2_STRONGBOX;
var1 = locvar1;
var2 = offset + 90;
A_TrapShot(actor);
for (i = 0; i < 8; i++)
{
actor->angle += ANGLE_45;
var1 = locvar1;
var2 = offset + (i & 1) ? 55 : 70;
A_TrapShot(actor);
}
actor->extravalue2 = 0;
}
// Function: A_LookForBetter
//
// Description: A_Look, except it finds a better target in multiplayer, and doesn't lose the target in singleplayer.
//
// var1 lower 16 bits = 0 - looks only in front, 1 - looks all around
// var1 upper 16 bits = distance limit
// var2 = unused
//
void A_LookForBetter(mobj_t *actor)
{
INT32 locvar1 = var1;
//INT32 locvar2 = var2;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_LookForBetter", actor))
return;
#endif
P_LookForPlayers(actor, (locvar1 & 65535), false, FixedMul((locvar1 >> 16)*FRACUNIT, actor->scale));
A_FaceTarget(actor);
}
/* * Spawns a dust ring.
* The dust ring behaves slightly randomly so it doesn't look too uniform.
*
* \param mobjtype Thing type to make a ring of.
* \param div Amount of things to spawn on the ring.
* \param x Center X coordinates.
* \param y Center Y coordinates.
* \param z Center Z coordinates.
* \param radius Radius.
* \param speed Additional thrust on particles.
* \param scale 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)
{
angle_t ang = FixedAngle(FixedDiv(360*FRACUNIT, div*FRACUNIT)); //(ANGLE_180/div)*2;
UINT32 i;
// it turned out the radius was effectively nullified thanks to errors in the original script
// BUT people preferred how it looked before I "fixed" it, so I got rid of the radius calculations altogether
// this was a bit of a mess to sort out, but at least it's probably somewhat fine now?
// -- Monster Iestyn (21/05/19)
(void)radius;
for (i = 0; i < div; i++)
{
mobj_t *dust = P_SpawnMobj(
x, //+ FixedMul(radius, FINECOSINE((ang*i) >> ANGLETOFINESHIFT)),
y, //+ FixedMul(radius, FINESINE((ang*i) >> ANGLETOFINESHIFT)),
z,
mobjtype
);
dust->angle = ang*i + ANGLE_90;
P_SetScale(dust, scale);
dust->destscale = FixedMul(4*FRACUNIT + P_RandomFixed(), scale);
dust->scalespeed = scale/24;
P_Thrust(dust, ang*i, speed + FixedMul(P_RandomFixed(), scale));
dust->momz = P_SignedRandom()*scale/64;
}
}
// Function: A_Boss5BombExplode
//
// Description: Boss 5's bomb exploding.
//
// var1 = Thing type to spawn as dust
// var2 = unused
//
void A_Boss5BombExplode(mobj_t *actor)
{
INT32 locvar1 = var1;
//INT32 locvar2 = var2;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_Boss5BombExplode", actor))
return;
#endif
// The original Lua script did not use |= to add flags but just set these flags exactly apparently?
// (I may modify this later)
// -- Monster Iestyn (21/05/19)
actor->flags = MF_NOCLIP|MF_NOGRAVITY|MF_NOBLOCKMAP;
actor->flags2 = MF2_EXPLOSION;
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_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;
quake.time = TICRATE/6;
// the following quake values have no effect atm? ah well, may as well set them anyway
{
mappoint_t q_epicenter = {actor->x, actor->y, actor->z};
quake.epicenter = &q_epicenter;
}
quake.radius = 20*actor->radius;
}

View file

@ -375,44 +375,82 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
/////ENEMIES & BOSSES!!/////////////////////////////////
////////////////////////////////////////////////////////
if (special->type == MT_BLACKEGGMAN)
switch (special->type)
{
P_DamageMobj(toucher, special, special, 1, 0); // ouch
return;
}
if (special->type == MT_BIGMINE)
{
special->momx = toucher->momx/3;
special->momy = toucher->momy/3;
special->momz = toucher->momz/3;
toucher->momx /= -8;
toucher->momy /= -8;
toucher->momz /= -8;
special->flags &= ~MF_SPECIAL;
if (special->info->activesound)
S_StartSound(special, special->info->activesound);
P_SetTarget(&special->tracer, toucher);
player->homing = 0;
return;
}
if (special->type == MT_GSNAPPER && !elementalpierce
&& toucher->z < special->z + special->height && toucher->z + toucher->height > special->z
&& P_DamageMobj(toucher, special, special, 1, DMG_SPIKE))
return; // Can only hit snapper from above
if (special->type == MT_SPINCUSHION
&& (P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0))
{
if (player->pflags & PF_BOUNCING)
case MT_BLACKEGGMAN:
{
toucher->momz = -toucher->momz;
P_DoAbilityBounce(player, false);
P_DamageMobj(toucher, special, special, 1, 0); // ouch
return;
}
else if (P_DamageMobj(toucher, special, special, 1, DMG_SPIKE))
return; // Cannot hit sharp from above
case MT_BIGMINE:
{
special->momx = toucher->momx/3;
special->momy = toucher->momy/3;
special->momz = toucher->momz/3;
toucher->momx /= -8;
toucher->momy /= -8;
toucher->momz /= -8;
special->flags &= ~MF_SPECIAL;
if (special->info->activesound)
S_StartSound(special, special->info->activesound);
P_SetTarget(&special->tracer, toucher);
player->homing = 0;
return;
}
case MT_GSNAPPER:
if (!elementalpierce
&& toucher->z < special->z + special->height
&& toucher->z + toucher->height > special->z
&& P_DamageMobj(toucher, special, special, 1, DMG_SPIKE))
return; // Can only hit snapper from above
break;
case MT_SPINCUSHION:
if (P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0)
{
if (player->pflags & PF_BOUNCING)
{
toucher->momz = -toucher->momz;
P_DoAbilityBounce(player, false);
return;
}
else if (P_DamageMobj(toucher, special, special, 1, DMG_SPIKE))
return; // Cannot hit sharp from above
}
break;
case MT_FANG:
if (!player->powers[pw_flashing]
&& !(player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)
&& !(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2))
{
if ((special->state == &states[S_FANG_BOUNCE3]
|| special->state == &states[S_FANG_BOUNCE4]
|| special->state == &states[S_FANG_PINCHBOUNCE3]
|| special->state == &states[S_FANG_PINCHBOUNCE4])
&& P_MobjFlip(special)*((special->z + special->height/2) - (toucher->z - toucher->height/2)) > 0)
{
P_DamageMobj(toucher, special, special, 1, 0);
P_SetTarget(&special->tracer, toucher);
if (special->state == &states[S_FANG_PINCHBOUNCE3]
|| special->state == &states[S_FANG_PINCHBOUNCE4])
P_SetMobjState(special, S_FANG_PINCHPATHINGSTART2);
else
{
var1 = var2 = 4;
A_Boss5ExtraRepeat(special);
P_SetMobjState(special, S_FANG_PATHINGCONT2); //S_FANG_PATHINGCONT1 if you want him to drop a bomb on the player
}
if (special->eflags & MFE_VERTICALFLIP)
special->z = toucher->z - special->height;
else
special->z = toucher->z + toucher->height;
return;
}
}
break;
default:
break;
}
if (((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING))
@ -3352,9 +3390,11 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
else if (player->powers[pw_invulnerability] || player->powers[pw_flashing] // ignore bouncing & such in invulnerability
|| player->powers[pw_super])
{
if (force || (inflictor && (inflictor->flags & MF_MISSILE)
&& (inflictor->flags2 & MF2_SUPERFIRE)
&& player->powers[pw_super]))
if (force
|| (player->powers[pw_super]
&& inflictor && inflictor->flags & MF_MISSILE && inflictor->flags2 & MF2_SUPERFIRE) // Super Sonic is stunned!
|| (player->powers[pw_flashing]
&& source && source->type == MT_FANG && inflictor && inflictor->type == MT_CORK)) // Fang's cork bullets knock you back even when flashing
{
#ifdef HAVE_BLUA
if (!LUAh_MobjDamage(target, inflictor, source, damage, damagetype))
@ -3362,8 +3402,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
P_SuperDamage(player, inflictor, source, damage);
return true;
}
else
return false;
return false;
}
#ifdef HAVE_BLUA
else if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype))

View file

@ -551,6 +551,44 @@ static void P_DoTailsCarry(player_t *sonic, player_t *tails)
}
}
// Boss 5 post-defeat comedy
static void P_SlapStick(mobj_t *fang, mobj_t *pole)
{
fixed_t momx1, momx2, momy1, momy2;
#define dist 3
momx1 = pole->momx/dist;
momy1 = pole->momy/dist;
momx2 = fang->momx/dist;
momy2 = fang->momy/dist;
pole->tracer->momx = momx1 + (dist-1)*momx2;
pole->tracer->momy = momy1 + (dist-1)*momy2;
fang->momx = (dist-1)*momx1 + momx2;
fang->momy = (dist-1)*momy1 + momy2;
#undef dist
P_SetMobjState(pole, pole->info->deathstate);
P_SetObjectMomZ(pole->tracer, 6*FRACUNIT, false);
pole->tracer->flags &= ~(MF_NOGRAVITY|MF_NOCLIP);
pole->tracer->movedir = ANGLE_67h;
if ((R_PointToAngle(fang->x - pole->tracer->x, fang->y - pole->tracer->y) - pole->angle) > ANGLE_180)
pole->tracer->movedir = InvAngle(pole->tracer->movedir);
P_SetObjectMomZ(fang, 14*FRACUNIT, false);
fang->flags |= MF_NOGRAVITY|MF_NOCLIP;
P_SetMobjState(fang, fang->info->xdeathstate);
pole->tracer->tics = pole->tics = fang->tics;
var1 = var2 = 0;
A_Scream(pole->tracer);
S_StartSound(fang, sfx_altdi1);
P_SetTarget(&pole->tracer, NULL);
}
//
// PIT_CheckThing
//
@ -780,6 +818,20 @@ static boolean PIT_CheckThing(mobj_t *thing)
}
#endif
if (tmthing->type == MT_FANG && thing->type == MT_FSGNB)
{
if (thing->z > tmthing->z + tmthing->height)
return true; // overhead
if (thing->z + thing->height < tmthing->z)
return true; // underneath
if (!thing->tracer)
return true;
P_SlapStick(tmthing, thing);
// no return value was used in the original prototype script at this point,
// so I'm assuming we fall back on the solid code to determine how it all ends?
// -- Monster Iestyn
}
// Billiards mines!
if (thing->type == MT_BIGMINE)
{

View file

@ -5013,6 +5013,47 @@ static void P_Boss4Thinker(mobj_t *mobj)
A_FaceTarget(mobj);
}
//
// AI for the fifth boss.
//
static void P_Boss5Thinker(mobj_t *mobj)
{
if (!mobj->health)
{
if (mobj->state == &states[mobj->info->xdeathstate])
mobj->momz -= (2*FRACUNIT)/3;
else if (mobj->tracer && P_AproxDistance(mobj->tracer->x - mobj->x, mobj->tracer->y - mobj->y) < 2*mobj->radius)
mobj->flags &= ~MF_NOCLIP;
}
else
{
if (mobj->flags2 & MF2_FRET && (leveltime & 1)
&& mobj->state != &states[S_FANG_PAIN1] && mobj->state != &states[S_FANG_PAIN2])
mobj->flags2 |= MF2_DONTDRAW;
else
mobj->flags2 &= ~MF2_DONTDRAW;
}
if (mobj->state == &states[S_FANG_BOUNCE3]
|| mobj->state == &states[S_FANG_BOUNCE4]
|| mobj->state == &states[S_FANG_PINCHBOUNCE3]
|| mobj->state == &states[S_FANG_PINCHBOUNCE4])
{
if (P_MobjFlip(mobj)*mobj->momz > 0
&& abs(mobj->momx) < FRACUNIT/2 && abs(mobj->momy) < FRACUNIT/2
&& !P_IsObjectOnGround(mobj))
{
mobj_t *prevtarget = mobj->target;
P_SetTarget(&mobj->target, NULL);
var1 = var2 = 0;
A_DoNPCPain(mobj);
P_SetTarget(&mobj->target, prevtarget);
P_SetMobjState(mobj, S_FANG_WALLHIT);
mobj->extravalue2++;
}
}
}
//
// AI for Black Eggman
// Note: You CANNOT have more than ONE Black Eggman
@ -7289,6 +7330,10 @@ void P_MobjThinker(mobj_t *mobj)
mobj->angle += (angle_t)mobj->movecount;
}
break;
case MT_FSGNA:
if (mobj->movedir)
mobj->angle += mobj->movedir;
break;
default:
if (mobj->fuse)
{ // Scenery object fuse! Very basic!
@ -7378,6 +7423,9 @@ void P_MobjThinker(mobj_t *mobj)
case MT_EGGMOBILE4:
P_Boss4Thinker(mobj);
break;
case MT_FANG:
P_Boss5Thinker(mobj);
break;
case MT_BLACKEGGMAN:
P_Boss7Thinker(mobj);
break;
@ -9100,6 +9148,10 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
case MT_NIGHTSSTAR:
if (nummaprings >= 0)
nummaprings++;
break;
case MT_FBOMB:
mobj->flags2 |= MF2_EXPLOSION;
break;
default:
break;
}