diff --git a/src/d_player.h b/src/d_player.h index 2c664bfcb..152aeb272 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -308,6 +308,7 @@ typedef enum k_accelboost, // Boost value smoothing for acceleration k_draftpower, // Drafting power (from 0 to FRACUNIT), doubles your top speed & acceleration at max k_draftleeway, // Leniency timer before removing draft power + k_lastdraft, // Last player being drafted k_boostcam, // Camera push forward on boost k_destboostcam, // Ditto k_timeovercam, // Camera timer for leaving behind or not diff --git a/src/dehacked.c b/src/dehacked.c index ef24e6bd7..c62d2cf7e 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8390,6 +8390,7 @@ static const char *const KARTSTUFF_LIST[] = { "ACCELBOOST", "DRAFTPOWER", "DRAFTLEEWAY", + "LASTDRAFT", "BOOSTCAM", "DESTBOOSTCAM", "TIMEOVERCAM", diff --git a/src/g_game.c b/src/g_game.c index f024d8786..ef0896837 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2542,6 +2542,7 @@ void G_PlayerReborn(INT32 player) p->kartstuff[k_comebacktimer] = comebacktime; p->kartstuff[k_wanted] = wanted; p->kartstuff[k_eggmanblame] = -1; + p->kartstuff[k_lastdraft] = -1; p->kartstuff[k_starpostflip] = respawnflip; // Don't do anything immediately diff --git a/src/k_kart.c b/src/k_kart.c index e7be8bbc8..b3782540c 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1541,6 +1541,65 @@ static void K_UpdateOffroad(player_t *player) player->kartstuff[k_offroad] = 0; } +static void K_DrawDraftCombiring(player_t *player, player_t *victim, fixed_t curdist, fixed_t maxdist, boolean transparent) +{ +#define CHAOTIXBANDLEN 15 +#define CHAOTIXBANDCOLORS 9 + static const UINT8 colors[CHAOTIXBANDCOLORS] = { + SKINCOLOR_SAPPHIRE, + SKINCOLOR_PLATINUM, + SKINCOLOR_TEA, + SKINCOLOR_GARDEN, + SKINCOLOR_MUSTARD, + SKINCOLOR_YELLOW, + SKINCOLOR_ORANGE, + SKINCOLOR_SCARLET, + SKINCOLOR_CHERRY + }; + fixed_t minimumdist = FixedMul(RING_DIST>>1, player->mo->scale); + UINT8 c = FixedMul(CHAOTIXBANDCOLORS<> FRACBITS; + UINT8 n = CHAOTIXBANDLEN; + UINT8 offset = ((leveltime / 3) % 3); + fixed_t stepx, stepy, stepz; + fixed_t curx, cury, curz; + + stepx = (victim->mo->x - player->mo->x) / CHAOTIXBANDLEN; + stepy = (victim->mo->y - player->mo->y) / CHAOTIXBANDLEN; + stepz = ((victim->mo->z + (victim->mo->height / 2)) - (player->mo->z + (player->mo->height / 2))) / CHAOTIXBANDLEN; + + curx = player->mo->x + stepx; + cury = player->mo->y + stepy; + curz = player->mo->z + stepz; + + while (n) + { + if (offset == 0) + { + mobj_t *band = P_SpawnMobj(curx + (P_RandomRange(-12,12)*mapobjectscale), + cury + (P_RandomRange(-12,12)*mapobjectscale), + curz + (P_RandomRange(24,48)*mapobjectscale), + MT_SIGNSPARKLE); + P_SetMobjState(band, S_SIGNSPARK1 + (abs(leveltime+offset) % 11)); + P_SetScale(band, (band->destscale = (3*player->mo->scale)/2)); + band->color = colors[c]; + band->colorized = true; + band->fuse = 2; + if (transparent) + band->flags2 |= MF2_SHADOW; + if (!P_IsLocalPlayer(player) && !P_IsLocalPlayer(victim)) + band->flags2 |= MF2_DONTDRAW; + } + + curx += stepx; + cury += stepy; + curz += stepz; + + offset = abs(offset-1) % 3; + n--; + } +#undef CHAOTIXBANDLEN +} + /** \brief Updates the player's drafting values once per frame \param player player object passed from K_KartPlayerThink @@ -1554,12 +1613,12 @@ static void K_UpdateDraft(player_t *player) UINT8 i; // Not enough speed to draft. - if (player->speed < 20*mapobjectscale) + if (player->speed < 20*player->mo->scale) return; // Distance you have to be to draft. If you're still accelerating, then this distance is lessened. - // This distance biases toward low weight! (min weight is 2368 units, max weight is 832 units) - draftdistance = (2048 + (512 * (9 - player->kartweight))) * mapobjectscale; + // This distance biases toward low weight! (min weight gets 2368 units, max weight gets 832 units) + draftdistance = (2048 + (512 * (9 - player->kartweight))) * player->mo->scale; if (player->speed < topspd) draftdistance = FixedMul(draftdistance, FixedDiv(player->speed, topspd)); @@ -1577,7 +1636,7 @@ static void K_UpdateDraft(player_t *player) continue; // Not enough speed to draft off of. - if (players[i].speed < 20*mapobjectscale) + if (players[i].speed < 20*players[i].mo->scale) continue; yourangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); @@ -1602,17 +1661,18 @@ static void K_UpdateDraft(player_t *player) dist = P_AproxDistance(P_AproxDistance(players[i].mo->x - player->mo->x, players[i].mo->y - player->mo->y), players[i].mo->z - player->mo->z); // TOO close to draft. - if (dist < RING_DIST/2) + if (dist < FixedMul(RING_DIST>>1, player->mo->scale)) continue; // Not close enough to draft. if (dist > draftdistance) continue; - player->kartstuff[k_draftleeway] = 10; + player->kartstuff[k_draftleeway] = TICRATE; + player->kartstuff[k_lastdraft] = i; // Draft power is used later in K_GetKartBoostPower, ranging from 0 for normal speed and FRACUNIT for max draft speed. - // How much this increments every tic biases toward acceleration! (min speed is 6.25% per tic, max speed is 0.25% per tic) + // How much this increments every tic biases toward acceleration! (min speed gets 6.25% per tic, max speed gets 0.25% per tic) if (player->kartstuff[k_draftpower] < FRACUNIT) player->kartstuff[k_draftpower] += (FRACUNIT/400) + ((9 - player->kartspeed) * (FRACUNIT/400)); @@ -1620,70 +1680,31 @@ static void K_UpdateDraft(player_t *player) player->kartstuff[k_draftpower] = FRACUNIT; // Spawn in the visual! - //if (leveltime & 1) - { -#define CHAOTIXBANDLEN 15 -#define CHAOTIXBANDCOLORS 9 - static const UINT8 colors[CHAOTIXBANDCOLORS] = { - SKINCOLOR_SAPPHIRE, - SKINCOLOR_PLATINUM, - SKINCOLOR_TEA, - SKINCOLOR_GARDEN, - SKINCOLOR_MUSTARD, - SKINCOLOR_YELLOW, - SKINCOLOR_ORANGE, - SKINCOLOR_SCARLET, - SKINCOLOR_CHERRY - }; - UINT8 c = FixedMul(CHAOTIXBANDCOLORS<> FRACBITS; - UINT8 n = CHAOTIXBANDLEN; - UINT8 offset = ((leveltime / 3) % 3); - fixed_t stepx, stepy, stepz; - fixed_t curx, cury, curz; - - stepx = (players[i].mo->x - player->mo->x) / CHAOTIXBANDLEN; - stepy = (players[i].mo->y - player->mo->y) / CHAOTIXBANDLEN; - stepz = ((players[i].mo->z + (players[i].mo->height / 2)) - (player->mo->z + (player->mo->height / 2))) / CHAOTIXBANDLEN; - - curx = player->mo->x + stepx; - cury = player->mo->y + stepy; - curz = player->mo->z + stepz; - - while (n) - { - if (offset == 0) - { - mobj_t *band = P_SpawnMobj(curx + (P_RandomRange(-12,12)*mapobjectscale), - cury + (P_RandomRange(-12,12)*mapobjectscale), - curz + (P_RandomRange(24,48)*mapobjectscale), - MT_SIGNSPARKLE); - P_SetMobjState(band, S_SIGNSPARK1 + (abs(leveltime+offset) % 11)); - P_SetScale(band, (band->destscale = (3*band->scale)/2)); - band->color = colors[c]; - band->colorized = true; - band->fuse = 2; - if (!P_IsLocalPlayer(player) && !P_IsLocalPlayer(&players[i])) - band->flags2 |= MF2_DONTDRAW; - } - - curx += stepx; - cury += stepy; - curz += stepz; - - offset = abs(offset-1) % 3; - n--; - } -#undef CHAOTIXBANDLEN - } + K_DrawDraftCombiring(player, &players[i], dist, draftdistance, false); return; // Finished doing our draft. } // No one to draft off of? Then you can knock that off. if (player->kartstuff[k_draftleeway]) // Prevent small disruptions from stopping your draft. + { player->kartstuff[k_draftleeway]--; - else if (player->kartstuff[k_draftpower]) // Remove draft speed boost. + if (player->kartstuff[k_lastdraft] >= 0 + && player->kartstuff[k_lastdraft] < MAXPLAYERS + && playeringame[player->kartstuff[k_lastdraft]] + && !players[player->kartstuff[k_lastdraft]].spectator + && players[player->kartstuff[k_lastdraft]].mo) + { + player_t *victim = &players[player->kartstuff[k_lastdraft]]; + fixed_t dist = P_AproxDistance(P_AproxDistance(victim->mo->x - player->mo->x, victim->mo->y - player->mo->y), victim->mo->z - player->mo->z); + K_DrawDraftCombiring(player, victim, dist, draftdistance, true); + } + } + else // Remove draft speed boost. + { player->kartstuff[k_draftpower] = 0; + player->kartstuff[k_lastdraft] = -1; + } } void K_KartPainEnergyFling(player_t *player) @@ -4964,9 +4985,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) } } - /*if (player->kartstuff[k_thunderanim]) - player->kartstuff[k_thunderanim]--;*/ - if (player->kartstuff[k_rings] > 20) player->kartstuff[k_rings] = 20; else if (player->kartstuff[k_rings] < -20) @@ -5619,6 +5637,68 @@ void K_StripOther(player_t *player) } } +// SRB2Kart: blockmap iterate for attraction shield users +static mobj_t *attractmo; +static fixed_t attractdist; +static inline boolean PIT_AttractingRings(mobj_t *thing) +{ + if (!attractmo || P_MobjWasRemoved(attractmo)) + return false; + + if (!attractmo->player) + return false; // not a player + + if (thing->health <= 0 || !thing) + return true; // dead + + if (thing->type != MT_RING && thing->type != MT_FLINGRING) + return true; // not a ring + + if (thing->extravalue1) + return true; // in special ring animation + + if (thing->cusval) + return true; // already attracted + + // see if it went over / under + if (attractmo->z - (attractdist>>2) > thing->z + thing->height) + return true; // overhead + if (attractmo->z + attractmo->height + (attractdist>>2) < thing->z) + return true; // underneath + + if (P_AproxDistance(attractmo->x - thing->x, attractmo->y - thing->y) < attractdist) + return true; // Too far away + + // set target + P_SetTarget(&thing->tracer, attractmo); + // flag to show it's been attracted once before + thing->cusval = 1; + return true; // find other rings +} + +/** Looks for rings near a player in the blockmap. + * + * \param pmo Player object looking for rings to attract + * \sa A_AttractChase + */ +static void K_LookForRings(mobj_t *pmo) +{ + INT32 bx, by, xl, xh, yl, yh; + attractdist = FixedMul(RING_DIST, pmo->scale)>>2; + + // Use blockmap to check for nearby rings + yh = (unsigned)(pmo->y + attractdist - bmaporgy)>>MAPBLOCKSHIFT; + yl = (unsigned)(pmo->y - attractdist - bmaporgy)>>MAPBLOCKSHIFT; + xh = (unsigned)(pmo->x + attractdist - bmaporgx)>>MAPBLOCKSHIFT; + xl = (unsigned)(pmo->x - attractdist - bmaporgx)>>MAPBLOCKSHIFT; + + attractmo = pmo; + + for (by = yl; by <= yh; by++) + for (bx = xl; bx <= xh; bx++) + P_BlockThingsIterator(bx, by, PIT_AttractingRings); +} + // // K_MoveKartPlayer // @@ -6130,7 +6210,12 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->kartstuff[k_itemtype] = KITEM_NONE; } - if (player->kartstuff[k_itemtype] != KITEM_THUNDERSHIELD) + if (player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) + { + if ((player->kartstuff[k_rings]+player->kartstuff[k_pickuprings]) < 20) + K_LookForRings(player->mo); + } + else player->kartstuff[k_curshield] = 0; if (player->kartstuff[k_growshrinktimer] <= 0) diff --git a/src/p_enemy.c b/src/p_enemy.c index 5e3247b96..848264b69 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -710,63 +710,6 @@ boolean P_LookForPlayers(mobj_t *actor, boolean allaround, boolean tracer, fixed //return false; } -/** Looks for a player with a ring shield. - * Used by rings. - * - * \param actor Ring looking for a shield to be attracted to. - * \return True if a player with ring shield is found, otherwise false. - * \sa A_AttractChase - */ -static boolean P_LookForShield(mobj_t *actor) -{ - INT32 c = 0, stop; - player_t *player; - - // BP: first time init, this allow minimum lastlook changes - if (actor->lastlook < 0) - actor->lastlook = P_RandomByte(); - - actor->lastlook %= MAXPLAYERS; - - stop = (actor->lastlook - 1) & PLAYERSMASK; - - for (; ; actor->lastlook = ((actor->lastlook + 1) & PLAYERSMASK)) - { - // done looking - if (actor->lastlook == stop) - return false; - - if (!playeringame[actor->lastlook]) - continue; - - if (c++ == 2) - return false; - - player = &players[actor->lastlook]; - - if (player->health <= 0 || !player->mo) - continue; // dead - - if (!P_CheckSight(actor, player->mo)) - continue; // can't see - - //When in CTF, don't pull rings that you cannot pick up. - if ((actor->type == MT_REDTEAMRING && player->ctfteam != 1) || - (actor->type == MT_BLUETEAMRING && player->ctfteam != 2)) - continue; - - if ((player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) && ((player->kartstuff[k_rings]+player->kartstuff[k_pickuprings]) < 20) - && P_AproxDistance(actor->x-player->mo->x, actor->y-player->mo->y) < FixedMul(RING_DIST/4, player->mo->scale) - && P_AproxDistance(0, actor->z-player->mo->z) < FixedMul(RING_DIST/16, player->mo->scale)) - { - P_SetTarget(&actor->tracer, player->mo); - return true; - } - } - - return false; -} - #ifdef WEIGHTEDRECYCLER // Compares players to see who currently has the "best" items, etc. static int P_RecycleCompare(const void *p1, const void *p2) @@ -3752,9 +3695,6 @@ void A_AttractChase(mobj_t *actor) // Let attracted rings move through walls and such. actor->flags |= MF_NOCLIP; - // flag to show it's been attracted once before - actor->cusval = 1; - // P_Attract is too "smart" for Kart; keep it simple, stupid! dist = P_AproxDistance(P_AproxDistance(actor->x - actor->tracer->x, actor->y - actor->tracer->y), actor->z - actor->tracer->z); hang = R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y); @@ -3778,8 +3718,9 @@ void A_AttractChase(mobj_t *actor) P_RemoveMobj(actor); return; } - else - P_LookForShield(actor); // Go find 'em, boy! + /*else + P_LookForShield(actor);*/ + // SRB2Kart: now it's the PLAYER'S job to use the blockmap to find rings, not the ring's. } } }