diff --git a/src/d_player.h b/src/d_player.h index 1d3d363cb..fd5c02072 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -502,9 +502,10 @@ struct player_t UINT32 roundscore; // battle score this round UINT8 emeralds; UINT8 bumper; - INT32 wanted; + INT16 wanted; INT16 karmadelay; - tic_t overtimekarma; // time to live in overtime comeback + INT16 karmamode; + INT16 karmapoints; INT16 spheres; tic_t spheredigestion; diff --git a/src/g_game.c b/src/g_game.c index 0f9f23590..9a169022f 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2234,6 +2234,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) INT32 roulettetype; INT32 growshrinktimer; INT32 bumper; + INT32 karmapoints; + INT32 wanted; boolean songcredit = false; tic_t spectatorreentry; tic_t grieftime; @@ -2290,6 +2292,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) itemamount = 0; growshrinktimer = 0; bumper = ((gametyperules & GTR_BUMPERS) ? K_StartingBumperCount() : 0); + karmapoints = 0; + wanted = 0; rings = ((gametyperules & GTR_SPHERES) ? 0 : 10); spheres = 0; kickstartaccel = 0; @@ -2335,6 +2339,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) growshrinktimer = 0; bumper = players[player].bumper; + karmapoints = players[player].karmapoints; + wanted = players[player].wanted; rings = players[player].rings; spheres = players[player].spheres; kickstartaccel = players[player].kickstartaccel; @@ -2444,7 +2450,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) p->growshrinktimer = growshrinktimer; p->bumper = bumper; p->karmadelay = comebacktime; - p->overtimekarma = 0; + p->karmapoints = karmapoints; + p->wanted = wanted; p->eggmanblame = -1; p->nocontrol = nocontrol; p->kickstartaccel = kickstartaccel; diff --git a/src/k_collide.c b/src/k_collide.c index 21b12f095..b156ee30f 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -233,7 +233,9 @@ boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2) if ((gametyperules & GTR_BUMPERS) && t2->player->bumper <= 0) { - return true; + if (t2->player->karmamode || t2->player->karmadelay) + return true; + t2->player->karmamode = 2; } else { diff --git a/src/k_hud.c b/src/k_hud.c index bc2156445..086d3bf8e 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -2584,28 +2584,36 @@ static void K_drawKartBumpersOrKarma(void) } else { - INT32 maxbumper = K_StartingBumperCount(); - V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|splitflags, kp_rankbumper, colormap); - - if (stplyr->bumper > 9 || maxbumper > 9) + if (stplyr->bumper <= 0) { - UINT8 ln[2]; - ln[0] = (stplyr->bumper / 10 % 10); - ln[1] = (stplyr->bumper % 10); - - V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, fontv[PINGNUM_FONT].font[ln[0]]); - V_DrawScaledPatch(fx+17, fy, V_HUDTRANS|splitflags, fontv[PINGNUM_FONT].font[ln[1]]); - - ln[0] = ((abs(maxbumper) / 10) % 10); - ln[1] = (abs(maxbumper) % 10); - - V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, fontv[PINGNUM_FONT].font[ln[0]]); - V_DrawScaledPatch(fx+31, fy, V_HUDTRANS|splitflags, fontv[PINGNUM_FONT].font[ln[1]]); + V_DrawMappedPatch(fx, fy-1, V_HUDTRANS|splitflags, kp_splitkarmabomb, colormap); + V_DrawString(fx+13, fy+1, V_HUDTRANS|splitflags, va("%d/2", stplyr->karmapoints)); } else { - V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, kp_facenum[(stplyr->bumper) % 10]); - V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, kp_facenum[(maxbumper) % 10]); + INT32 maxbumper = K_StartingBumperCount(); + V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|splitflags, kp_rankbumper, colormap); + + if (stplyr->bumper > 9 || maxbumper > 9) + { + UINT8 ln[2]; + ln[0] = (stplyr->bumper / 10 % 10); + ln[1] = (stplyr->bumper % 10); + + V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, fontv[PINGNUM_FONT].font[ln[0]]); + V_DrawScaledPatch(fx+17, fy, V_HUDTRANS|splitflags, fontv[PINGNUM_FONT].font[ln[1]]); + + ln[0] = ((abs(maxbumper) / 10) % 10); + ln[1] = (abs(maxbumper) % 10); + + V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, fontv[PINGNUM_FONT].font[ln[0]]); + V_DrawScaledPatch(fx+31, fy, V_HUDTRANS|splitflags, fontv[PINGNUM_FONT].font[ln[1]]); + } + else + { + V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, kp_facenum[(stplyr->bumper) % 10]); + V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, kp_facenum[(maxbumper) % 10]); + } } } } @@ -2622,17 +2630,22 @@ static void K_drawKartBumpersOrKarma(void) } else { - INT32 maxbumper = K_StartingBumperCount(); - - if (stplyr->bumper > 9 && maxbumper > 9) - V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_bumperstickerwide, colormap); + if (stplyr->bumper <= 0) + { + V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_karmasticker, NULL); + V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|splitflags, va("%d/2", stplyr->karmapoints)); + } else - V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_bumpersticker, colormap); + { + INT32 maxbumper = K_StartingBumperCount(); + + if (stplyr->bumper > 9 && maxbumper > 9) + V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_bumperstickerwide, colormap); + else + V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_bumpersticker, colormap); - if (bossinfo.boss) V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|splitflags, va("%d/%d", stplyr->bumper, maxbumper)); - else // TODO BETTER HUD - V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|splitflags, va("%d/%d %d", stplyr->bumper, maxbumper, stplyr->overtimekarma / TICRATE)); + } } } } diff --git a/src/k_kart.c b/src/k_kart.c index 158664683..bbedbdb40 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -2950,12 +2950,6 @@ UINT16 K_GetKartFlashing(player_t *player) { UINT16 tics = flashingtics; - if (gametype == GT_BATTLE) - { - // TODO: gametyperules - return 1; - } - if (player == NULL) { return tics; @@ -3484,6 +3478,7 @@ void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount) } player->bumper++; + player->karmapoints = 0; victim->bumper--; tookBumpers++; } @@ -8275,8 +8270,37 @@ void K_MoveKartPlayer(player_t *player, boolean onground) { // First, the really specific, finicky items that function without the item being directly in your item slot. { + // Karma item dropping + if (ATTACK_IS_DOWN && player->karmamode && !player->karmadelay) + { + mobj_t *newitem; + + if (player->karmamode == 1) + { + newitem = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_RANDOMITEM); + newitem->threshold = 69; // selected "randomly". + } + else + { + newitem = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_EGGMANITEM); + if (player->eggmanblame >= 0 + && player->eggmanblame < MAXPLAYERS + && playeringame[player->eggmanblame] + && !players[player->eggmanblame].spectator + && players[player->eggmanblame].mo) + P_SetTarget(&newitem->target, players[player->eggmanblame].mo); + player->eggmanblame = -1; + } + + newitem->flags2 = (player->mo->flags2 & MF2_OBJECTFLIP); + newitem->fuse = 15*TICRATE; // selected randomly. + + player->karmamode = 0; + player->karmadelay = comebacktime; + S_StartSound(player->mo, sfx_s254); + } // Ring boosting - if (player->pflags & PF_USERINGS) + else if (player->pflags & PF_USERINGS) { if ((cmd->buttons & BT_ATTACK) && !player->ringdelay && player->rings > 0) { diff --git a/src/p_inter.c b/src/p_inter.c index fc701652f..3ca8183fd 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -280,6 +280,13 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (!P_CanPickupItem(player, 1)) return; + if ((gametyperules & GTR_BUMPERS) && player->bumper <= 0) + { + if (player->karmamode || player->karmadelay) + return; + player->karmamode = 1; + } + special->momx = special->momy = special->momz = 0; P_SetTarget(&special->target, toucher); P_KillMobj(special, toucher, toucher, DMG_NORMAL); @@ -326,6 +333,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (special->target->player->karmadelay > 0) return; + if (!special->target->player->karmamode) { mobj_t *boom; @@ -350,6 +358,84 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) special->target->player->karthud[khud_yougotem] = 2*TICRATE; special->target->player->karmadelay = comebacktime; } + else if (special->target->player->karmamode == 1 && P_CanPickupItem(player, 1)) + { + mobj_t *poof = P_SpawnMobj(special->x, special->y, special->z, MT_EXPLODE); + S_StartSound(poof, special->info->seesound); + + // Karma fireworks + for (i = 0; i < 5; i++) + { + mobj_t *firework = P_SpawnMobj(special->x, special->y, special->z, MT_KARMAFIREWORK); + firework->momx = (special->target->momx + toucher->momx) / 2; + firework->momy = (special->target->momy + toucher->momy) / 2; + firework->momz = (special->target->momz + toucher->momz) / 2; + P_Thrust(firework, FixedAngle((72*i)<scale); + P_SetObjectMomZ(firework, P_RandomRange(1,8)*special->scale, false); + firework->color = special->target->color; + } + + special->target->player->karmamode = 0; + special->target->player->karmapoints++; + + if (special->target->player->karmapoints >= 2) + K_TakeBumpersFromPlayer(special->target->player, player, 1); + + special->target->player->karmadelay = comebacktime; + + player->itemroulette = 1; + player->roulettetype = 1; + } + else if (special->target->player->karmamode == 2 && P_CanPickupItem(player, 2)) + { + mobj_t *poof = P_SpawnMobj(special->x, special->y, special->z, MT_EXPLODE); + UINT8 ptadd = 1; // No WANTED bonus for tricking + + S_StartSound(poof, special->info->seesound); + + if (player->bumper == 1) // If you have only one bumper left, and see if it's a 1v1 + { + INT32 numingame = 0; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator || players[i].bumper <= 0) + continue; + numingame++; + } + + if (numingame <= 2) // If so, then an extra karma point so they are 100% certain to switch places; it's annoying to end matches with a fake kill + ptadd++; + } + + special->target->player->karmamode = 0; + special->target->player->karmapoints += ptadd; + + if (ptadd > 1) + special->target->player->karthud[khud_yougotem] = 2*TICRATE; + + if (special->target->player->karmapoints >= 2) + K_TakeBumpersFromPlayer(special->target->player, player, 1); + + special->target->player->karmadelay = comebacktime; + + K_DropItems(player); //K_StripItems(player); + //K_StripOther(player); + + player->itemroulette = 1; + player->roulettetype = 2; + + if (special->target->player->eggmanblame >= 0 + && special->target->player->eggmanblame < MAXPLAYERS + && playeringame[special->target->player->eggmanblame] + && !players[special->target->player->eggmanblame].spectator) + player->eggmanblame = special->target->player->eggmanblame; + else + player->eggmanblame = -1; + + special->target->player->eggmanblame = -1; + } + return; case MT_SPB: if ((special->target == toucher || special->target == toucher->target) && (special->threshold > 0)) @@ -1882,7 +1968,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da { if (gametyperules & GTR_BUMPERS) { - if (player->bumper <= 0 && player->karmadelay) + if ((player->bumper <= 0 && player->karmadelay) || (player->karmamode == 1)) { // No bumpers & in WAIT, can't be hurt K_DoInstashield(player); @@ -1923,51 +2009,32 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da // We successfully damaged them! Give 'em some bumpers! if (type != DMG_STING) { - UINT8 takeBumpers = 1; - - if (damagetype & DMG_STEAL) - { - takeBumpers = 2; - - if (type == DMG_KARMA) - { - takeBumpers = player->bumper; - } - } - else - { - if (type == DMG_KARMA) - { - // Take half of their bumpers for karma comeback damage - takeBumpers = max(1, player->bumper / 2); - } - } if (source && source != player->mo && source->player) { K_TryHurtSoundExchange(target, source); - - K_BattleAwardHit(source->player, player, inflictor, takeBumpers); - K_TakeBumpersFromPlayer(source->player, player, takeBumpers); - - if (type == DMG_KARMA) - { - // Destroy any remainder bumpers from the player for karma comeback damage - K_DestroyBumpers(player, player->bumper); - } - else - { - source->player->overtimekarma += 5*TICRATE; - } + K_BattleAwardHit(source->player, player, inflictor, 1); if (damagetype & DMG_STEAL) { - K_CheckBumpers(); + K_TakeBumpersFromPlayer(source->player, player, 1); + } + else if (damage & DMG_KARMA) + { + source->player->karmapoints++; + if (source->player->karmapoints >= 2) + { + K_TakeBumpersFromPlayer(source->player, player, 1); + } + else + { + K_DestroyBumpers(player, 1); + } + } + else + { + K_DestroyBumpers(player, 1); } - } - else - { - K_DestroyBumpers(player, takeBumpers); } } diff --git a/src/p_mobj.c b/src/p_mobj.c index 47ad8317b..064a312a4 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7558,12 +7558,12 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } } break; - case MT_KARMAHITBOX: + case MT_KARMAHITBOX: { statenum_t state = (mobj->state-states); if (!mobj->target || !mobj->target->health || !mobj->target->player || mobj->target->player->spectator - || (gametype == GT_RACE || mobj->target->player->bumper)) + || (gametyperules & GTR_CIRCUIT || mobj->target->player->bumper)) { P_RemoveMobj(mobj); return false; @@ -7577,13 +7577,17 @@ static boolean P_MobjRegularThink(mobj_t *mobj) mobj->color = mobj->target->color; mobj->colorized = true; - mobj->radius = 24*mobj->target->scale; + // Give items an item-sized hitbox + if (mobj->target->player->karmamode == 1) + mobj->radius = 48*mobj->target->scale; + else + mobj->radius = 24*mobj->target->scale; mobj->height = 2*mobj->radius; if (mobj->target->player->karmadelay > 0) { - if (state < S_PLAYERBOMB1 || state > S_PLAYERBOMB20) - P_SetMobjState(mobj, S_PLAYERBOMB1); + if (state < mobj->info->spawnstate || state > mobj->info->spawnstate+19) + P_SetMobjState(mobj, mobj->info->spawnstate); if (mobj->target->player->karmadelay < TICRATE && (leveltime & 1)) mobj->renderflags &= ~RF_DONTDRAW; else @@ -7591,8 +7595,15 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } else { - if (state < S_PLAYERBOMB1 || state > S_PLAYERBOMB20) - P_SetMobjState(mobj, S_PLAYERBOMB1); + if (!mobj->target->player->karmamode + && (state < mobj->info->spawnstate || state > mobj->info->spawnstate+19)) + P_SetMobjState(mobj, mobj->info->spawnstate); + else if (mobj->target->player->karmamode == 1 + && state != mobj->info->seestate) + P_SetMobjState(mobj, mobj->info->seestate); + else if (mobj->target->player->karmamode == 2 + && state != mobj->info->painstate) + P_SetMobjState(mobj, mobj->info->painstate); if (mobj->target->player->flashing && (leveltime & 1)) mobj->renderflags |= RF_DONTDRAW; diff --git a/src/p_saveg.c b/src/p_saveg.c index b71f081d3..3b3176dc8 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -333,7 +333,9 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT8(save->p, players[i].emeralds); WRITEUINT8(save->p, players[i].bumper); WRITEINT16(save->p, players[i].karmadelay); - WRITEUINT32(save->p, players[i].overtimekarma); + WRITEINT16(save->p, players[i].karmamode); + WRITEINT16(save->p, players[i].karmapoints); + WRITEINT16(save->p, players[i].wanted); WRITEINT16(save->p, players[i].spheres); WRITEUINT32(save->p, players[i].spheredigestion); @@ -623,7 +625,9 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].emeralds = READUINT8(save->p); players[i].bumper = READUINT8(save->p); players[i].karmadelay = READINT16(save->p); - players[i].overtimekarma = READUINT32(save->p); + players[i].karmamode = READINT16(save->p); + players[i].karmapoints = READINT16(save->p); + players[i].wanted = READINT16(save->p); players[i].spheres = READINT16(save->p); players[i].spheredigestion = READUINT32(save->p); diff --git a/src/p_user.c b/src/p_user.c index f4620e093..f10fbc574 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4487,7 +4487,7 @@ void P_PlayerThink(player_t *player) || (player->pflags & PF_NOCONTEST) // NO CONTEST explosion || ((gametyperules & GTR_BUMPERS) && player->bumper <= 0 && player->karmadelay))) { - if (player->flashing > 1 && player->flashing < K_GetKartFlashing(player) + if (player->flashing > 0 && player->flashing < K_GetKartFlashing(player) && (leveltime & 1)) player->mo->renderflags |= RF_DONTDRAW; else