diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index de1b854f6..063158b26 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -804,7 +804,12 @@ static int mapthing_set(lua_State *L) else if(fastcmp(field,"z")) mt->z = (INT16)luaL_checkinteger(L, 3); else if(fastcmp(field,"extrainfo")) - mt->extrainfo = (UINT8)luaL_checkinteger(L, 3); + { + INT32 extrainfo = luaL_checkinteger(L, 3); + if (extrainfo & ~15) + return luaL_error(L, "mapthing_t extrainfo set %d out of range (%d - %d)", extrainfo, 0, 15); + mt->extrainfo = (UINT8)extrainfo; + } else if(fastcmp(field,"mobj")) mt->mobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); else diff --git a/src/p_enemy.c b/src/p_enemy.c index 88405437c..18d6f20c0 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -3878,6 +3878,8 @@ bossjustdie: } default: //eggmobiles { + UINT8 extrainfo = (mo->spawnpoint ? mo->spawnpoint->extrainfo : 0); + // Stop exploding and prepare to run. P_SetMobjState(mo, mo->info->xdeathstate); if (P_MobjWasRemoved(mo)) @@ -3897,6 +3899,9 @@ bossjustdie: if (mo2->type != MT_BOSSFLYPOINT) continue; + if (mo2->spawnpoint && mo2->spawnpoint->extrainfo != extrainfo) + continue; + // If this one's further then the last one, don't go for it. if (mo->target && P_AproxDistance(P_AproxDistance(mo->x - mo2->x, mo->y - mo2->y), mo->z - mo2->z) > @@ -12303,6 +12308,7 @@ void A_Boss5FindWaypoint(mobj_t *actor) //INT32 locvar2 = var2; boolean avoidcenter; UINT32 i; + UINT8 extrainfo = (actor->spawnpoint ? actor->spawnpoint->extrainfo : 0); #ifdef HAVE_BLUA if (LUA_CallAction("A_Boss5FindWaypoint", actor)) return; @@ -12312,16 +12318,34 @@ void A_Boss5FindWaypoint(mobj_t *actor) if (locvar1 == 2) // look for the boss waypoint { - for (i = 0; i < nummapthings; i++) + thinker_t *th; + mobj_t *mo2; + P_SetTarget(&actor->tracer, NULL); + // Flee! Flee! Find a point to escape to! If none, just shoot upward! + // scan the thinkers to find the runaway point + for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) { - if (!mapthings[i].mobj) + if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) continue; - if (mapthings[i].mobj->type != MT_BOSSFLYPOINT) + + mo2 = (mobj_t *)th; + + if (mo2->type != MT_BOSSFLYPOINT) continue; - P_SetTarget(&actor->tracer, mapthings[i].mobj); - break; + + if (mo2->spawnpoint && mo2->spawnpoint->extrainfo != extrainfo) + continue; + + // If this one's further then the last one, don't go for it. + if (actor->tracer && + P_AproxDistance(P_AproxDistance(actor->x - mo2->x, actor->y - mo2->y), actor->z - mo2->z) > + P_AproxDistance(P_AproxDistance(actor->x - actor->tracer->x, actor->y - actor->tracer->y), actor->z - actor->tracer->z)) + continue; + + // Otherwise... Do! + P_SetTarget(&actor->tracer, mo2); } - if (i == nummapthings) + if (!actor->tracer) return; // no boss flypoints found } else if (locvar1 == 1) // always go to ambush-marked waypoint @@ -12335,11 +12359,13 @@ void A_Boss5FindWaypoint(mobj_t *actor) continue; if (mapthings[i].mobj->type != MT_FANGWAYPOINT) continue; - if (mapthings[i].options & MTF_AMBUSH) - { - P_SetTarget(&actor->tracer, mapthings[i].mobj); - break; - } + if (mapthings[i].extrainfo != extrainfo) + continue; + if (!(mapthings[i].options & MTF_AMBUSH)) + continue; + + P_SetTarget(&actor->tracer, mapthings[i].mobj); + break; } if (i == nummapthings) @@ -12363,6 +12389,8 @@ void A_Boss5FindWaypoint(mobj_t *actor) continue; if (actor->tracer == mapthings[i].mobj) // this was your tracer last time continue; + if (mapthings[i].extrainfo != extrainfo) + continue; if (mapthings[i].options & MTF_AMBUSH) { if (avoidcenter) @@ -12418,6 +12446,8 @@ void A_Boss5FindWaypoint(mobj_t *actor) continue; if (actor->tracer == mapthings[i].mobj) // this was your tracer last time continue; + if (mapthings[i].extrainfo != extrainfo) + continue; if (mapthings[i].options & MTF_AMBUSH) { if (avoidcenter) diff --git a/src/p_mobj.c b/src/p_mobj.c index 7ff3c3594..eac90f5f0 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -5236,6 +5236,7 @@ static void P_Boss7Thinker(mobj_t *mobj) INT32 i; boolean foundgoop = false; INT32 closestNum; + UINT8 extrainfo = (mobj->spawnpoint ? mobj->spawnpoint->extrainfo : 0); // Looks for players in goop. If you find one, try to jump on him. for (i = 0; i < MAXPLAYERS; i++) @@ -5261,17 +5262,23 @@ static void P_Boss7Thinker(mobj_t *mobj) continue; mo2 = (mobj_t *)th; - if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint) - { - dist = P_AproxDistance(players[i].mo->x - mo2->x, players[i].mo->y - mo2->y); + if (mo2->type != MT_BOSS3WAYPOINT) + continue; + if (!mo2->spawnpoint) + continue; + if (mo2->spawnpoint->extrainfo != extrainfo) + continue; + if (mobj->health <= mobj->info->damage && !(mo2->spawnpoint->options & 7)) + continue; // don't jump to center - if (closestNum == -1 || dist < closestdist) - { - closestNum = (mo2->spawnpoint->options & 7); - closestdist = dist; - foundgoop = true; - } - } + dist = P_AproxDistance(players[i].mo->x - mo2->x, players[i].mo->y - mo2->y); + + if (!(closestNum == -1 || dist < closestdist)) + continue; + + closestNum = (mo2->spawnpoint->options & 7); + closestdist = dist; + foundgoop = true; } waypointNum = closestNum; break; @@ -5280,17 +5287,14 @@ static void P_Boss7Thinker(mobj_t *mobj) if (!foundgoop) { - if (mobj->z > 1056*FRACUNIT) - waypointNum = 0; - else + // Don't jump to the center when health is low. + // Force the player to beat you with missiles. + if (mobj->z <= 1056*FRACUNIT || mobj->health <= mobj->info->damage) waypointNum = 1 + P_RandomKey(4); + else + waypointNum = 0; } - // Don't jump to the center when health is low. - // Force the player to beat you with missiles. - if (mobj->health <= mobj->info->damage && waypointNum == 0) - waypointNum = 1 + P_RandomKey(4); - if (mobj->tracer && mobj->tracer->type == MT_BOSS3WAYPOINT && mobj->tracer->spawnpoint && (mobj->tracer->spawnpoint->options & 7) == waypointNum) { @@ -5299,15 +5303,12 @@ static void P_Boss7Thinker(mobj_t *mobj) else waypointNum--; - waypointNum %= 5; - - if (waypointNum < 0) - waypointNum = 0; + if (mobj->health <= mobj->info->damage) + waypointNum = ((waypointNum + 3) % 4) + 1; // plus four to avoid modulo being negative, minus one to avoid waypoint #0 + else + waypointNum = ((waypointNum + 5) % 5); } - if (waypointNum == 0 && mobj->health <= mobj->info->damage) - waypointNum = 1 + (P_RandomFixed() & 1); - // scan the thinkers to find // the waypoint to use for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) @@ -5316,11 +5317,17 @@ static void P_Boss7Thinker(mobj_t *mobj) continue; mo2 = (mobj_t *)th; - if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint && (mo2->spawnpoint->options & 7) == waypointNum) - { - hitspot = mo2; - break; - } + if (mo2->type != MT_BOSS3WAYPOINT) + continue; + if (!mo2->spawnpoint) + continue; + if ((mo2->spawnpoint->options & 7) != waypointNum) + continue; + if (mo2->spawnpoint->extrainfo != extrainfo) + continue; + + hitspot = mo2; + break; } if (hitspot == NULL) @@ -7004,6 +7011,9 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->flags & MF_NOTHINK) return; + if ((mobj->flags & MF_BOSS) && mobj->spawnpoint && (bossdisabled & (1<spawnpoint->extrainfo))) + return; + // Remove dead target/tracer. if (mobj->target && P_MobjWasRemoved(mobj->target)) P_SetTarget(&mobj->target, NULL); diff --git a/src/p_mobj.h b/src/p_mobj.h index bfcb09210..77791f928 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -470,4 +470,5 @@ extern INT32 numhuntemeralds; extern boolean runemeraldmanager; extern UINT16 emeraldspawndelay; extern INT32 numstarposts; +extern UINT16 bossdisabled; #endif diff --git a/src/p_saveg.c b/src/p_saveg.c index 09df38eb0..24b68b971 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -3990,6 +3990,7 @@ static void P_NetArchiveMisc(void) WRITEUINT32(save_p, leveltime); WRITEUINT32(save_p, ssspheres); WRITEINT16(save_p, lastmap); + WRITEUINT16(save_p, bossdisabled); WRITEUINT16(save_p, emeralds); WRITEUINT8(save_p, stagefailed); @@ -4067,6 +4068,7 @@ static inline boolean P_NetUnArchiveMisc(void) leveltime = READUINT32(save_p); ssspheres = READUINT32(save_p); lastmap = READINT16(save_p); + bossdisabled = READUINT16(save_p); emeralds = READUINT16(save_p); stagefailed = READUINT8(save_p); diff --git a/src/p_setup.c b/src/p_setup.c index 26e8144cf..15576bbe8 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -102,6 +102,7 @@ line_t *lines; side_t *sides; mapthing_t *mapthings; INT32 numstarposts; +UINT16 bossdisabled; boolean levelloading; UINT8 levelfadecol; diff --git a/src/p_spec.c b/src/p_spec.c index c661cd4e5..e03b661a3 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3554,6 +3554,29 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } break; + case 449: // Enable bosses with parameter + { + INT32 bossid = sides[line->sidenum[0]].textureoffset>>FRACBITS; + if (bossid & ~15) // if any bits other than first 16 are set + { + CONS_Alert(CONS_WARNING, + M_GetText("Boss enable linedef (tag %d) has an invalid texture x offset.\nConsider changing it or removing it entirely.\n"), + line->tag); + break; + } + if (line->flags & ML_NOCLIMB) + { + bossdisabled |= (1<tag, mo, NULL); break; @@ -6416,6 +6439,9 @@ void P_SpawnSpecials(INT32 fromnetsave) // but currently isn't. (void)fromnetsave; + // yep, we do this here - "bossdisabled" is considered an apparatus of specials. + bossdisabled = 0; + // Init special SECTORs. sector = sectors; for (i = 0; i < numsectors; i++, sector++) @@ -7304,6 +7330,24 @@ void P_SpawnSpecials(INT32 fromnetsave) case 431: break; + case 449: // Enable bosses with parameter + { + INT32 bossid = sides[*lines[i].sidenum].textureoffset>>FRACBITS; + if (bossid & ~15) // if any bits other than first 16 are set + { + CONS_Alert(CONS_WARNING, + M_GetText("Boss enable linedef (tag %d) has an invalid texture x offset.\nConsider changing it or removing it entirely.\n"), + lines[i].tag); + break; + } + if (!(lines[i].flags & ML_NOCLIMB)) + { + bossdisabled |= (1<