From a0bcd52bf11e10b5ce63e4ee0d8940778467a65a Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 28 Nov 2022 01:47:00 -0500 Subject: [PATCH 1/6] Break the Capsules HUD tracking --- src/k_hud.c | 341 +++++++++++++++++++++++++++++++++++++++++++++++++++- src/k_hud.h | 2 + 2 files changed, 339 insertions(+), 4 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index 5325f07eb..64b0bf911 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -172,6 +172,11 @@ static patch_t *kp_bossret[4]; static patch_t *kp_trickcool[2]; +static patch_t *kp_capsuletarget_arrow[2][2]; +static patch_t *kp_capsuletarget_icon[2]; +static patch_t *kp_capsuletarget_far[2]; +static patch_t *kp_capsuletarget_near[8]; + void K_LoadKartHUDGraphics(void) { INT32 i, j, k; @@ -643,6 +648,39 @@ void K_LoadKartHUDGraphics(void) buffer[7] = '0'+((i+1)%10); HU_UpdatePatch(&kp_bossret[i], "%s", buffer); } + + sprintf(buffer, "HCAPARxx"); + for (i = 0; i < 2; i++) + { + buffer[6] = 'A'+i; + + for (j = 0; j < 2; j++) + { + buffer[7] = '0'+j; + HU_UpdatePatch(&kp_capsuletarget_arrow[i][j], "%s", buffer); + } + } + + sprintf(buffer, "HUDCAPCx"); + for (i = 0; i < 2; i++) + { + buffer[7] = '0'+i; + HU_UpdatePatch(&kp_capsuletarget_icon[i], "%s", buffer); + } + + sprintf(buffer, "HUDCAPBx"); + for (i = 0; i < 2; i++) + { + buffer[7] = '0'+i; + HU_UpdatePatch(&kp_capsuletarget_far[i], "%s", buffer); + } + + sprintf(buffer, "HUDCAPAx"); + for (i = 0; i < 8; i++) + { + buffer[7] = '0'+i; + HU_UpdatePatch(&kp_capsuletarget_near[i], "%s", buffer); + } } // For the item toggle menu @@ -888,7 +926,7 @@ void K_ObjectTracking(trackingResult_t *result, vector3_t *point, boolean revers fixed_t fovDiff, fov, fovTangent, fg; fixed_t h; - INT32 da; + INT32 da, dp; UINT8 cameraNum = R_GetViewNumber(); @@ -949,6 +987,7 @@ void K_ObjectTracking(trackingResult_t *result, vector3_t *point, boolean revers // Determine viewpoint factors. h = R_PointToDist2(point->x, point->y, viewx, viewy); da = AngleDeltaSigned(viewpointAngle, R_PointToAngle2(point->x, point->y, viewx, viewy)); + dp = AngleDeltaSigned(viewpointAiming, R_PointToAngle2(0, 0, h, viewz)); if (reverse) { @@ -959,6 +998,10 @@ void K_ObjectTracking(trackingResult_t *result, vector3_t *point, boolean revers result->x = FixedMul(NEWTAN(da), fg); result->y = FixedMul((NEWTAN(viewpointAiming) - FixedDiv((viewz - point->z), 1 + FixedMul(NEWCOS(da), h))), fg); + result->angle = da; + result->pitch = dp; + result->fov = fg; + // Rotate for screen roll... if (viewpointRoll) { @@ -3070,6 +3113,217 @@ static void K_DrawWeakSpot(weakspotdraw_t *ws) V_DrawFixedPatch(ws->x, ws->y, FRACUNIT, 0, kp_bossret[j+1], colormap); } +typedef struct capsuletracking_s +{ + mobj_t *mobj; + vector3_t point; + fixed_t camDist; +} capsuletracking_t; + +static void K_DrawCapsuleTracking(capsuletracking_t *caps) +{ + trackingResult_t result = {0}; + INT32 timer = 0; + + K_ObjectTracking(&result, &caps->point, false); + + if (result.onScreen == false) + { + // Off-screen, draw alongside the borders of the screen. + // Probably the most complicated thing. + + INT32 scrVal = 240; + vector2_t screenSize = {0}; + + INT32 borderSize = 7; + vector2_t borderWin = {0}; + vector2_t borderDir = {0}; + fixed_t borderLen = FRACUNIT; + + vector2_t arrowDir = {0}; + + vector2_t arrowPos = {0}; + patch_t *arrowPatch = NULL; + INT32 arrowFlags = 0; + + vector2_t capsulePos = {0}; + patch_t *capsulePatch = NULL; + + timer = (leveltime / 3); + + screenSize.x = vid.width / vid.dupx; + screenSize.y = vid.height / vid.dupy; + + if (r_splitscreen >= 2) + { + // Half-wide screens + screenSize.x >>= 1; + borderSize >>= 1; + } + + if (r_splitscreen >= 1) + { + // Half-tall screens + screenSize.y >>= 1; + } + + scrVal = max(screenSize.x, screenSize.y) - 80; + + borderWin.x = screenSize.x - borderSize; + borderWin.y = screenSize.y - borderSize; + + arrowDir.x = 0; + arrowDir.y = P_MobjFlip(caps->mobj) * FRACUNIT; + + // Simply pointing towards the result doesn't work, so inaccurate hack... + borderDir.x = FixedMul( + FixedMul( + FINESINE((-result.angle >> ANGLETOFINESHIFT) & FINEMASK), + FINECOSINE((-result.pitch >> ANGLETOFINESHIFT) & FINEMASK) + ), + result.fov + ); + + borderDir.y = FixedMul( + FINESINE((-result.pitch >> ANGLETOFINESHIFT) & FINEMASK), + result.fov + ); + + borderLen = R_PointToDist2(0, 0, borderDir.x, borderDir.y); + + if (borderLen > 0) + { + borderDir.x = FixedDiv(borderDir.x, borderLen); + borderDir.y = FixedDiv(borderDir.y, borderLen); + } + else + { + // Eh just put it at the bottom. + borderDir.x = 0; + borderDir.y = FRACUNIT; + } + + capsulePatch = kp_capsuletarget_icon[timer & 1]; + + if (abs(borderDir.x) > abs(borderDir.y)) + { + // Horizontal arrow + arrowPatch = kp_capsuletarget_arrow[1][timer & 1]; + arrowDir.y = 0; + + if (borderDir.x < 0) + { + // LEFT + arrowDir.x = -FRACUNIT; + } + else + { + // RIGHT + arrowDir.x = FRACUNIT; + } + } + else + { + // Vertical arrow + arrowPatch = kp_capsuletarget_arrow[0][timer & 1]; + arrowDir.x = 0; + + if (borderDir.y < 0) + { + // UP + arrowDir.y = -FRACUNIT; + } + else + { + // DOWN + arrowDir.y = FRACUNIT; + } + } + + arrowPos.x = (screenSize.x >> 1) + FixedMul(scrVal, borderDir.x); + arrowPos.y = (screenSize.y >> 1) + FixedMul(scrVal, borderDir.y); + + arrowPos.x = min(max(arrowPos.x, borderSize), borderWin.x) * FRACUNIT; + arrowPos.y = min(max(arrowPos.y, borderSize), borderWin.y) * FRACUNIT; + + capsulePos.x = arrowPos.x - (arrowDir.x * 12); + capsulePos.y = arrowPos.y - (arrowDir.y * 12); + + arrowPos.x -= (arrowPatch->width << FRACBITS) >> 1; + arrowPos.y -= (arrowPatch->height << FRACBITS) >> 1; + + capsulePos.x -= (capsulePatch->width << FRACBITS) >> 1; + capsulePos.y -= (capsulePatch->height << FRACBITS) >> 1; + + if (arrowDir.x < 0) + { + arrowPos.x += arrowPatch->width << FRACBITS; + arrowFlags |= V_FLIP; + } + + if (arrowDir.y < 0) + { + arrowPos.y += arrowPatch->height << FRACBITS; + arrowFlags |= V_VFLIP; + } + + V_DrawFixedPatch( + capsulePos.x, capsulePos.y, + FRACUNIT, + V_SPLITSCREEN, + capsulePatch, NULL + ); + + V_DrawFixedPatch( + arrowPos.x, arrowPos.y, + FRACUNIT, + V_SPLITSCREEN | arrowFlags, + arrowPatch, NULL + ); + } + else + { + // Draw simple overlay. + const fixed_t farDistance = 1280*mapobjectscale; + boolean useNear = (caps->camDist < farDistance); + + patch_t *capsulePatch = NULL; + vector2_t capsulePos = {0}; + + boolean visible = P_CheckSight(stplyr->mo, caps->mobj); + + if (visible == false && (leveltime & 1)) + { + // Flicker when not visible. + return; + } + + capsulePos.x = result.x; + capsulePos.y = result.y; + + if (useNear == true) + { + timer = (leveltime / 2); + capsulePatch = kp_capsuletarget_near[timer % 8]; + } + else + { + timer = (leveltime / 3); + capsulePatch = kp_capsuletarget_far[timer & 1]; + } + + capsulePos.x -= (capsulePatch->width << FRACBITS) >> 1; + capsulePos.y -= (capsulePatch->height << FRACBITS) >> 1; + + V_DrawFixedPatch( + capsulePos.x, capsulePos.y, + FRACUNIT, + V_SPLITSCREEN, + capsulePatch, NULL + ); + } +} + static void K_drawKartNameTags(void) { const fixed_t maxdistance = 8192*mapobjectscale; @@ -3078,7 +3332,7 @@ static void K_drawKartNameTags(void) UINT8 tobesorted[MAXPLAYERS]; fixed_t sortdist[MAXPLAYERS]; UINT8 sortlen = 0; - UINT8 i, j; + size_t i, j; if (stplyr == NULL || stplyr->mo == NULL || P_MobjWasRemoved(stplyr->mo)) { @@ -3169,6 +3423,85 @@ static void K_drawKartNameTags(void) } } + if (battlecapsules == true) + { +#define MAX_CAPSULE_HUD 32 + capsuletracking_t capsuleList[MAX_CAPSULE_HUD]; + size_t capsuleListLen = 0; + + mobj_t *mobj = NULL; + mobj_t *next = NULL; + + for (mobj = kitemcap; mobj; mobj = next) + { + capsuletracking_t *caps = NULL; + + next = mobj->itnext; + + if (mobj->health <= 0) + { + continue; + } + + if (mobj->type != MT_BATTLECAPSULE) + { + continue; + } + + caps = &capsuleList[capsuleListLen]; + + caps->mobj = mobj; + caps->point.x = R_InterpolateFixed(mobj->old_x, mobj->x); + caps->point.y = R_InterpolateFixed(mobj->old_y, mobj->y); + caps->point.z = R_InterpolateFixed(mobj->old_z, mobj->z); + caps->point.z += (mobj->height >> 1); + caps->camDist = R_PointToDist2(c.x, c.y, caps->point.x, caps->point.y); + + capsuleListLen++; + + if (capsuleListLen >= MAX_CAPSULE_HUD) + { + break; + } + } + + if (capsuleListLen > 0) + { + // Sort by distance from camera. + if (capsuleListLen > 1) + { + for (i = 0; i < capsuleListLen-1; i++) + { + size_t swap = i; + + for (j = i + 1; j < capsuleListLen; j++) + { + capsuletracking_t *cj = &capsuleList[j]; + capsuletracking_t *cSwap = &capsuleList[swap]; + + if (cj->camDist > cSwap->camDist) + { + swap = j; + } + } + + if (swap != i) + { + capsuletracking_t temp = capsuleList[swap]; + capsuleList[swap] = capsuleList[i]; + capsuleList[i] = temp; + } + } + } + + for (i = 0; i < capsuleListLen; i++) + { + K_DrawCapsuleTracking(&capsuleList[i]); + } + } +#undef MAX_CAPSULE_HUD + } + for (i = 0; i < MAXPLAYERS; i++) { player_t *ntplayer = &players[i]; @@ -3283,7 +3616,7 @@ static void K_drawKartNameTags(void) { if (!(demo.playback == true && demo.freecam == true)) { - for (j = 0; j <= r_splitscreen; j++) + for (j = 0; j <= (unsigned)r_splitscreen; j++) { if (ntplayer == &players[displayplayers[j]]) { @@ -3291,7 +3624,7 @@ static void K_drawKartNameTags(void) } } - if (j <= r_splitscreen && j != cnum) + if (j <= (unsigned)r_splitscreen && j != cnum) { localindicator = j; } diff --git a/src/k_hud.h b/src/k_hud.h index 4f84f9dd3..3ea839385 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -28,6 +28,8 @@ typedef struct trackingResult_s fixed_t x, y; fixed_t scale; boolean onScreen; + INT32 angle, pitch; + fixed_t fov; } trackingResult_t; void K_ObjectTracking(trackingResult_t *result, vector3_t *point, boolean reverse); From 81cefa2697b7ea25a455bc541c2cef0da7d7b3f5 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 28 Nov 2022 02:41:42 -0500 Subject: [PATCH 2/6] Gachabom initial pass They simply use Kitchen Sink's item icon and Orbinaut's sprites. The forward toss behavior needs fine-tuning to use more MT_BANANA style behavior. --- src/d_netcmd.c | 2 ++ src/d_netcmd.h | 6 +++-- src/d_player.h | 4 ++- src/deh_tables.c | 3 +++ src/info.c | 27 +++++++++++++++++++ src/info.h | 2 ++ src/k_botitem.c | 5 ++++ src/k_botsearch.c | 1 + src/k_collide.c | 7 ++--- src/k_hud.c | 5 ++++ src/k_kart.c | 59 +++++++++++++++++++++++++++++++++++------- src/objects/orbinaut.c | 4 +-- src/p_inter.c | 3 ++- src/p_map.c | 12 ++++----- src/p_mobj.c | 15 ++++++++++- 15 files changed, 129 insertions(+), 26 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 086c4cbfa..3494ad8c3 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -382,6 +382,7 @@ consvar_t cv_superring = CVAR_INIT ("superring", "On", CV_NETVAR, CV_OnOff, consvar_t cv_kitchensink = CVAR_INIT ("kitchensink", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_droptarget = CVAR_INIT ("droptarget", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_gardentop = CVAR_INIT ("gardentop", "On", CV_NETVAR, CV_OnOff, NULL); +consvar_t cv_gachabom = CVAR_INIT ("gachabom", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_dualsneaker = CVAR_INIT ("dualsneaker", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_triplesneaker = CVAR_INIT ("triplesneaker", "On", CV_NETVAR, CV_OnOff, NULL); @@ -389,6 +390,7 @@ consvar_t cv_triplebanana = CVAR_INIT ("triplebanana", "On", CV_NETVAR, CV_O consvar_t cv_tripleorbinaut = CVAR_INIT ("tripleorbinaut", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_quadorbinaut = CVAR_INIT ("quadorbinaut", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_dualjawz = CVAR_INIT ("dualjawz", "On", CV_NETVAR, CV_OnOff, NULL); +consvar_t cv_triplegachabom = CVAR_INIT ("triplegachabom", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_kartspeed = CVAR_INIT ("gamespeed", "Auto", CV_NETVAR|CV_CALL|CV_NOINIT, kartspeed_cons_t, KartSpeed_OnChange); static CV_PossibleValue_t kartbumpers_cons_t[] = {{1, "MIN"}, {12, "MAX"}, {0, NULL}}; diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 1583ec5d8..a6b11d694 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -94,7 +94,8 @@ extern consvar_t cv_superring, cv_kitchensink, cv_droptarget, - cv_gardentop; + cv_gardentop, + cv_gachabom; extern consvar_t cv_dualsneaker, @@ -102,7 +103,8 @@ extern consvar_t cv_triplebanana, cv_tripleorbinaut, cv_quadorbinaut, - cv_dualjawz; + cv_dualjawz, + cv_triplegachabom; extern consvar_t cv_kartspeed; extern consvar_t cv_kartbumpers; diff --git a/src/d_player.h b/src/d_player.h index e9ebe7668..a2581db8c 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -154,7 +154,8 @@ Run this macro, then #undef FOREACH afterward FOREACH (SUPERRING, 19),\ FOREACH (KITCHENSINK, 20),\ FOREACH (DROPTARGET, 21),\ - FOREACH (GARDENTOP, 22) + FOREACH (GARDENTOP, 22),\ + FOREACH (GACHABOM, 23) typedef enum { @@ -171,6 +172,7 @@ typedef enum KRITEM_TRIPLEORBINAUT, KRITEM_QUADORBINAUT, KRITEM_DUALJAWZ, + KRITEM_TRIPLEGACHABOM, NUMKARTRESULTS } kartitems_t; diff --git a/src/deh_tables.c b/src/deh_tables.c index a36b7af9d..47b282030 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -5374,6 +5374,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_SINK_SHIELD", "MT_SINKTRAIL", + "MT_GACHABOM", + "MT_DUELBOMB", // Duel mode bombs "MT_BATTLEBUMPER", // Battle Mode bumper @@ -6778,6 +6780,7 @@ struct int_const_s const INT_CONST[] = { {"KRITEM_TRIPLEORBINAUT",KRITEM_TRIPLEORBINAUT}, {"KRITEM_QUADORBINAUT",KRITEM_QUADORBINAUT}, {"KRITEM_DUALJAWZ",KRITEM_DUALJAWZ}, + {"KRITEM_TRIPLEGACHABOM",KRITEM_TRIPLEGACHABOM}, {"NUMKARTRESULTS",NUMKARTRESULTS}, // kartshields_t diff --git a/src/info.c b/src/info.c index 3824731d1..b71241509 100644 --- a/src/info.c +++ b/src/info.c @@ -24187,6 +24187,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_GACHABOM + -1, // doomednum + S_ORBINAUT1, // spawnstate + 7, // spawnhealth + S_NULL, // seestate + sfx_tossed, // seesound + 8, // reactiontime + sfx_s3k49, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_ORBINAUT_DEAD,// deathstate + S_NULL, // xdeathstate + sfx_s3k5d, // deathsound + 64*FRACUNIT, // speed + 24*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 1, // damage + sfx_s3k96, // activesound + MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN|MF_SLOPE, // flags + S_NULL // raisestate + }, + { // MT_DUELBOMB 2050, // doomednum S_SPB1, // spawnstate diff --git a/src/info.h b/src/info.h index 7dff6e2de..f2d0f62dd 100644 --- a/src/info.h +++ b/src/info.h @@ -6426,6 +6426,8 @@ typedef enum mobj_type MT_SINK_SHIELD, MT_SINKTRAIL, + MT_GACHABOM, + MT_DUELBOMB, // Duel mode bombs MT_BATTLEBUMPER, // Battle Mode bumpers diff --git a/src/k_botitem.c b/src/k_botitem.c index bb90ef736..e51b04b3a 100644 --- a/src/k_botitem.c +++ b/src/k_botitem.c @@ -1373,6 +1373,11 @@ void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt) case KITEM_FLAMESHIELD: K_BotItemFlame(player, cmd); break; + /* + case KITEM_GACHABOM: + K_BotItemGachabom(player, cmd); + break; + */ } } } diff --git a/src/k_botsearch.c b/src/k_botsearch.c index 2d9c9774d..8af4dcc75 100644 --- a/src/k_botsearch.c +++ b/src/k_botsearch.c @@ -415,6 +415,7 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing) case MT_SPB: case MT_BUBBLESHIELDTRAP: case MT_DUELBOMB: + case MT_GACHABOM: K_AddDodgeObject(thing, side, 20); break; case MT_SHRINK_GUN: diff --git a/src/k_collide.c b/src/k_collide.c index 6a67e5a04..5ff75dc17 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -86,7 +86,7 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2) else if (t2->type == MT_BANANA || t2->type == MT_BANANA_SHIELD || t2->type == MT_ORBINAUT || t2->type == MT_ORBINAUT_SHIELD || t2->type == MT_JAWZ || t2->type == MT_JAWZ_SHIELD - || t2->type == MT_BALLHOG) + || t2->type == MT_BALLHOG || t2->type == MT_GACHABOM) { // Other Item Damage angle_t bounceangle = K_GetCollideAngle(t1, t2); @@ -340,7 +340,8 @@ boolean K_MineCollide(mobj_t *t1, mobj_t *t2) } } else if (t2->type == MT_ORBINAUT || t2->type == MT_JAWZ - || t2->type == MT_ORBINAUT_SHIELD || t2->type == MT_JAWZ_SHIELD) + || t2->type == MT_ORBINAUT_SHIELD || t2->type == MT_JAWZ_SHIELD + || t2->type == MT_GACHABOM) { // Bomb death angle_t bounceangle = K_GetCollideAngle(t1, t2); @@ -401,7 +402,7 @@ boolean K_LandMineCollide(mobj_t *t1, mobj_t *t2) else if (t2->type == MT_BANANA || t2->type == MT_BANANA_SHIELD || t2->type == MT_ORBINAUT || t2->type == MT_ORBINAUT_SHIELD || t2->type == MT_JAWZ || t2->type == MT_JAWZ_SHIELD - || t2->type == MT_BALLHOG) + || t2->type == MT_BALLHOG || t2->type == MT_GACHABOM) { // Other Item Damage angle_t bounceangle = K_GetCollideAngle(t1, t2); diff --git a/src/k_hud.c b/src/k_hud.c index 64b0bf911..c33879360 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -736,6 +736,9 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny) return (tiny ? "K_ISDTRG" : "K_ITDTRG"); case KITEM_GARDENTOP: return (tiny ? "K_ISGTOP" : "K_ITGTOP"); + case KITEM_GACHABOM: // temp + case KRITEM_TRIPLEGACHABOM: // temp + return (tiny ? "K_ISSINK" : "K_ITSINK"); case KRITEM_TRIPLEORBINAUT: return (tiny ? "K_ISORBN" : "K_ITORB3"); case KRITEM_QUADORBINAUT: @@ -772,6 +775,7 @@ static patch_t *K_GetCachedItemPatch(INT32 item, UINT8 offset) kp_kitchensink, kp_droptarget, kp_gardentop, + kp_kitchensink, // temp }; if (item == KITEM_SAD || (item > KITEM_NONE && item < NUMKARTITEMS)) @@ -1208,6 +1212,7 @@ static void K_drawKartItem(void) default: localpatch = K_GetCachedItemPatch(item, offset); + break; } } else diff --git a/src/k_kart.c b/src/k_kart.c index 9973bc5d5..c6c3c30f0 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -423,12 +423,14 @@ consvar_t *KartItemCVars[NUMKARTRESULTS-1] = &cv_kitchensink, &cv_droptarget, &cv_gardentop, + &cv_gachabom, &cv_dualsneaker, &cv_triplesneaker, &cv_triplebanana, &cv_tripleorbinaut, &cv_quadorbinaut, - &cv_dualjawz + &cv_dualjawz, + &cv_triplegachabom }; #define NUMKARTODDS 80 @@ -459,12 +461,14 @@ static UINT8 K_KartItemOddsRace[NUMKARTRESULTS-1][8] = { 0, 0, 0, 0, 0, 0, 0, 0 }, // Kitchen Sink { 3, 0, 0, 0, 0, 0, 0, 0 }, // Drop Target { 0, 0, 0, 3, 5, 0, 0, 0 }, // Garden Top + { 0, 0, 0, 0, 0, 0, 0, 0 }, // Gachabom { 0, 0, 2, 2, 2, 0, 0, 0 }, // Sneaker x2 { 0, 0, 0, 0, 4, 4, 4, 0 }, // Sneaker x3 { 0, 1, 1, 0, 0, 0, 0, 0 }, // Banana x3 { 0, 0, 1, 0, 0, 0, 0, 0 }, // Orbinaut x3 { 0, 0, 0, 2, 0, 0, 0, 0 }, // Orbinaut x4 - { 0, 0, 1, 2, 1, 0, 0, 0 } // Jawz x2 + { 0, 0, 1, 2, 1, 0, 0, 0 }, // Jawz x2 + { 0, 0, 0, 0, 0, 0, 0, 0 } // Gachabom x3 }; static UINT8 K_KartItemOddsBattle[NUMKARTRESULTS][2] = @@ -492,12 +496,14 @@ static UINT8 K_KartItemOddsBattle[NUMKARTRESULTS][2] = { 0, 0 }, // Kitchen Sink { 2, 0 }, // Drop Target { 4, 0 }, // Garden Top + { 0, 0 }, // Gachabom { 0, 0 }, // Sneaker x2 { 0, 1 }, // Sneaker x3 { 0, 0 }, // Banana x3 { 2, 0 }, // Orbinaut x3 { 1, 1 }, // Orbinaut x4 - { 5, 1 } // Jawz x2 + { 5, 1 }, // Jawz x2 + { 0, 0 } // Gachabom x3 }; // TODO: add back when this gets used @@ -527,12 +533,14 @@ static UINT8 K_KartItemOddsSpecial[NUMKARTRESULTS-1][4] = { 0, 0, 0, 0 }, // Kitchen Sink { 0, 0, 0, 0 }, // Drop Target { 0, 0, 0, 0 }, // Garden Top + { 0, 0, 0, 0 }, // Gachabom { 0, 1, 1, 0 }, // Sneaker x2 { 0, 0, 1, 1 }, // Sneaker x3 { 0, 0, 0, 0 }, // Banana x3 { 0, 1, 1, 0 }, // Orbinaut x3 { 0, 0, 1, 1 }, // Orbinaut x4 - { 0, 0, 1, 1 } // Jawz x2 + { 0, 0, 1, 1 }, // Jawz x2 + { 0, 0, 0, 0 } // Gachabom x3 }; #endif @@ -599,6 +607,9 @@ SINT8 K_ItemResultToType(SINT8 getitem) case KRITEM_DUALJAWZ: return KITEM_JAWZ; + case KRITEM_TRIPLEGACHABOM: + return KITEM_GACHABOM; + default: I_Error("Bad item cooldown redirect for result %d\n", getitem); break; @@ -619,6 +630,7 @@ UINT8 K_ItemResultToAmount(SINT8 getitem) case KRITEM_TRIPLESNEAKER: case KRITEM_TRIPLEBANANA: case KRITEM_TRIPLEORBINAUT: + case KRITEM_TRIPLEGACHABOM: return 3; case KRITEM_QUADORBINAUT: @@ -1370,24 +1382,24 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) } else if (gametype == GT_BATTLE) { - if (mashed && (modeattacking || bossinfo.boss || cv_banana.value)) // ANY mashed value? You get a banana. + if (mashed && (modeattacking || bossinfo.boss || cv_gachabom.value)) // ANY mashed value? You get a Gachabom. { - K_KartGetItemResult(player, KITEM_BANANA); + K_KartGetItemResult(player, KITEM_GACHABOM); player->karthud[khud_itemblinkmode] = 1; if (P_IsDisplayPlayer(player)) S_StartSound(NULL, sfx_itrolm); } else if (bossinfo.boss) { - K_KartGetItemResult(player, KITEM_ORBINAUT); + K_KartGetItemResult(player, KITEM_ORBINAUT); // FIXME player->karthud[khud_itemblinkmode] = 0; if (P_IsDisplayPlayer(player)) S_StartSound(NULL, sfx_itrolf); } else { - if (modeattacking || cv_tripleorbinaut.value) // Waited patiently? You get Orbinaut x3! - K_KartGetItemResult(player, KRITEM_TRIPLEORBINAUT); + if (modeattacking || cv_triplegachabom.value) // Waited patiently? You get Gachabom x3! + K_KartGetItemResult(player, KRITEM_TRIPLEGACHABOM); else // Default to sad if nothing's enabled... K_KartGetItemResult(player, KITEM_SAD); player->karthud[khud_itemblinkmode] = 0; @@ -1550,6 +1562,7 @@ fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against) break; case MT_ORBINAUT: case MT_ORBINAUT_SHIELD: + case MT_GACHABOM: case MT_DUELBOMB: if (against->player) weight = K_PlayerWeight(against, NULL); @@ -5271,7 +5284,7 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I finalscale = source->scale; } - if (dir == -1 && (type == MT_ORBINAUT || type == MT_BALLHOG)) + if (dir == -1 && (type == MT_ORBINAUT || type == MT_GACHABOM || type == MT_BALLHOG)) { // Backwards nerfs finalspeed /= 8; @@ -5328,6 +5341,7 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I switch (type) { case MT_ORBINAUT: + case MT_GACHABOM: Obj_OrbinautThrown(th, finalspeed, dir); break; case MT_JAWZ: @@ -6175,6 +6189,12 @@ mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing, dir = defaultDir; } + if (mapthing == MT_GACHABOM && dir > 0) + { + // This item is both a missile and not! + missile = false; + } + if (missile) // Shootables { if (dir < 0 && mapthing != MT_SPB && mapthing != MT_GARDENTOP) @@ -6242,6 +6262,16 @@ mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing, mo->rollangle = FixedAngle(P_RandomRange(PR_DECORATION, -180, 180) << FRACBITS); } + if (mapthing == MT_GACHABOM) + { + // Set dropped flag + mo->flags2 |= MF2_AMBUSH; + mo->movecount = 2; + P_SetMobjState(mo, mo->info->deathstate); + mo->tics = -1; + mo->color = player->skincolor; + } + // this is the small graphic effect that plops in you when you throw an item: throwmo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->height/2, MT_FIREDITEM); P_SetTarget(&throwmo->target, player->mo); @@ -11418,6 +11448,15 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_UpdateHnextList(player, true); } break; + case KITEM_GACHABOM: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + K_ThrowKartItem(player, true, MT_GACHABOM, 0, 0, 0); + K_PlayAttackTaunt(player->mo); + player->itemamount--; + K_UpdateHnextList(player, false); + } + break; case KITEM_SAD: if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO && !player->sadtimer) diff --git a/src/objects/orbinaut.c b/src/objects/orbinaut.c index b4daefb9b..0e8bf7d24 100644 --- a/src/objects/orbinaut.c +++ b/src/objects/orbinaut.c @@ -184,7 +184,7 @@ boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2) if (t2->player) { if ((t2->player->flashing > 0 && t2->hitlag == 0) - && !(t1->type == MT_ORBINAUT || t1->type == MT_JAWZ)) + && !(t1->type == MT_ORBINAUT || t1->type == MT_JAWZ || t1->type == MT_GACHABOM)) return true; if (t2->player->hyudorotimer) @@ -209,7 +209,7 @@ boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2) else if (t2->type == MT_ORBINAUT || t2->type == MT_JAWZ || t2->type == MT_ORBINAUT_SHIELD || t2->type == MT_JAWZ_SHIELD || t2->type == MT_BANANA || t2->type == MT_BANANA_SHIELD - || t2->type == MT_BALLHOG) + || t2->type == MT_BALLHOG || t2->type == MT_GACHABOM) { // Other Item Damage angle_t bounceangle = K_GetCollideAngle(t1, t2); diff --git a/src/p_inter.c b/src/p_inter.c index e77a5d8ff..6498397d8 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -955,7 +955,8 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget || target->type == MT_BANANA || target->type == MT_BANANA_SHIELD || target->type == MT_DROPTARGET || target->type == MT_DROPTARGET_SHIELD || target->type == MT_EGGMANITEM || target->type == MT_EGGMANITEM_SHIELD - || target->type == MT_BALLHOG || target->type == MT_SPB)) // kart dead items + || target->type == MT_BALLHOG || target->type == MT_SPB + || target->type == MT_GACHABOM)) // kart dead items target->flags |= MF_NOGRAVITY; // Don't drop Tails 03-08-2000 else target->flags &= ~MF_NOGRAVITY; // lose it if you for whatever reason have it, I'm looking at you shields diff --git a/src/p_map.c b/src/p_map.c index cb5d030a2..ddc02ca0e 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -849,7 +849,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) // Bubble Shield reflect if (((thing->type == MT_BUBBLESHIELD && thing->target->player && thing->target->player->bubbleblowup) || (thing->player && thing->player->bubbleblowup)) - && (tm.thing->type == MT_ORBINAUT || tm.thing->type == MT_JAWZ + && (tm.thing->type == MT_ORBINAUT || tm.thing->type == MT_JAWZ || tm.thing->type == MT_GACHABOM || tm.thing->type == MT_BANANA || tm.thing->type == MT_EGGMANITEM || tm.thing->type == MT_BALLHOG || tm.thing->type == MT_SSMINE || tm.thing->type == MT_LANDMINE || tm.thing->type == MT_SINK || tm.thing->type == MT_GARDENTOP @@ -865,7 +865,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) } else if (((tm.thing->type == MT_BUBBLESHIELD && tm.thing->target->player && tm.thing->target->player->bubbleblowup) || (tm.thing->player && tm.thing->player->bubbleblowup)) - && (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ + && (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_GACHABOM || thing->type == MT_BANANA || thing->type == MT_EGGMANITEM || thing->type == MT_BALLHOG || thing->type == MT_SSMINE || tm.thing->type == MT_LANDMINE || thing->type == MT_SINK || thing->type == MT_GARDENTOP @@ -886,7 +886,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) // Droptarget reflect if ((thing->type == MT_DROPTARGET || thing->type == MT_DROPTARGET_SHIELD) - && (tm.thing->type == MT_ORBINAUT || tm.thing->type == MT_JAWZ + && (tm.thing->type == MT_ORBINAUT || tm.thing->type == MT_JAWZ || tm.thing->type == MT_GACHABOM || tm.thing->type == MT_BANANA || tm.thing->type == MT_EGGMANITEM || tm.thing->type == MT_BALLHOG || tm.thing->type == MT_SSMINE || tm.thing->type == MT_LANDMINE || tm.thing->type == MT_SINK || tm.thing->type == MT_GARDENTOP @@ -901,7 +901,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) return K_DropTargetCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if ((tm.thing->type == MT_DROPTARGET || tm.thing->type == MT_DROPTARGET_SHIELD) - && (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ + && (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_GACHABOM || thing->type == MT_BANANA || thing->type == MT_EGGMANITEM || thing->type == MT_BALLHOG || thing->type == MT_SSMINE || tm.thing->type == MT_LANDMINE || thing->type == MT_SINK || thing->type == MT_GARDENTOP @@ -921,7 +921,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) || thing->type == MT_DROPTARGET_SHIELD || tm.thing->type == MT_DROPTARGET_SHIELD) return BMIT_CONTINUE; - if (tm.thing->type == MT_ORBINAUT || tm.thing->type == MT_JAWZ + if (tm.thing->type == MT_ORBINAUT || tm.thing->type == MT_JAWZ || tm.thing->type == MT_GACHABOM || tm.thing->type == MT_ORBINAUT_SHIELD || tm.thing->type == MT_JAWZ_SHIELD || tm.thing->type == MT_GARDENTOP) { @@ -933,7 +933,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) return Obj_OrbinautJawzCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } - else if (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ + else if (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_GACHABOM || thing->type == MT_ORBINAUT_SHIELD || thing->type == MT_JAWZ_SHIELD || thing->type == MT_GARDENTOP) { diff --git a/src/p_mobj.c b/src/p_mobj.c index 814aa6b57..d08e5ed3a 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1195,6 +1195,13 @@ fixed_t P_GetMobjGravity(mobj_t *mo) case MT_BATTLEBUMPER: gravityadd /= 2; break; + case MT_GACHABOM: + if (!(mo->flags2 & MF2_AMBUSH)) + { + // Use normal gravity, unless if it was tossed. + break; + } + /*FALLTHRU*/ case MT_BANANA: case MT_EGGMANITEM: case MT_SSMINE: @@ -1742,7 +1749,7 @@ void P_XYMovement(mobj_t *mo) //{ SRB2kart - Orbinaut, Ballhog // Bump sparks - if (mo->type == MT_ORBINAUT || mo->type == MT_BALLHOG) + if (mo->type == MT_ORBINAUT || mo->type == MT_BALLHOG || mo->type == MT_GACHABOM) { mobj_t *fx; fx = P_SpawnMobj(mo->x, mo->y, mo->z, MT_BUMP); @@ -1756,6 +1763,7 @@ void P_XYMovement(mobj_t *mo) switch (mo->type) { case MT_ORBINAUT: // Orbinaut speed decreasing + case MT_GACHABOM: case MT_GARDENTOP: if (mo->health > 1) { @@ -5174,6 +5182,7 @@ boolean P_IsKartFieldItem(INT32 type) case MT_SINK: case MT_DROPTARGET: case MT_DUELBOMB: + case MT_GACHABOM: return true; default: @@ -6540,6 +6549,7 @@ static boolean P_MobjDeadThink(mobj_t *mobj) case MT_LANDMINE: //case MT_DROPTARGET: case MT_SPB: + case MT_GACHABOM: if (P_IsObjectOnGround(mobj)) { P_RemoveMobj(mobj); @@ -6936,6 +6946,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } break; case MT_ORBINAUT: + case MT_GACHABOM: { Obj_OrbinautThink(mobj); P_MobjCheckWater(mobj); @@ -9743,6 +9754,7 @@ void P_MobjThinker(mobj_t *mobj) || mobj->type == MT_CANNONBALLDECOR || mobj->type == MT_FALLINGROCK || mobj->type == MT_ORBINAUT + || mobj->type == MT_GACHABOM || mobj->type == MT_JAWZ || (mobj->type == MT_DROPTARGET && mobj->reactiontime)) { @@ -10020,6 +10032,7 @@ static void P_DefaultMobjShadowScale(mobj_t *thing) case MT_ROCKETSNEAKER: case MT_SPB: case MT_DUELBOMB: + case MT_GACHABOM: thing->shadowscale = 3*FRACUNIT/2; break; case MT_BANANA_SHIELD: From 7181e05cce4b85947c8b13773dfa053122c4a35b Mon Sep 17 00:00:00 2001 From: VelocitOni Date: Fri, 16 Dec 2022 23:12:01 -0500 Subject: [PATCH 3/6] Update k_hud.h " trackingResult_t;" on line 31 turned into just ";" because structs use a new format now. --- src/k_hud.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_hud.h b/src/k_hud.h index 22aec1188..6360ca3de 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -28,7 +28,7 @@ struct trackingResult_t boolean onScreen; INT32 angle, pitch; fixed_t fov; -} trackingResult_t; +}; void K_ObjectTracking(trackingResult_t *result, vector3_t *point, boolean reverse); From 021f82911243d8710a88afed3239ee8609259e70 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 19 Dec 2022 01:12:18 -0500 Subject: [PATCH 4/6] Update k_roulette.c --- src/k_roulette.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/k_roulette.c b/src/k_roulette.c index 40cd68af4..042b1a685 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -98,12 +98,14 @@ static UINT8 K_KartItemOddsRace[NUMKARTRESULTS-1][8] = { 0, 0, 0, 0, 0, 0, 0, 0 }, // Kitchen Sink { 3, 0, 0, 0, 0, 0, 0, 0 }, // Drop Target { 0, 0, 0, 3, 5, 0, 0, 0 }, // Garden Top + { 0, 0, 0, 0, 0, 0, 0, 0 }, // Gachabom { 0, 0, 2, 2, 2, 0, 0, 0 }, // Sneaker x2 { 0, 0, 0, 0, 4, 4, 4, 0 }, // Sneaker x3 { 0, 1, 1, 0, 0, 0, 0, 0 }, // Banana x3 { 0, 0, 1, 0, 0, 0, 0, 0 }, // Orbinaut x3 { 0, 0, 0, 2, 0, 0, 0, 0 }, // Orbinaut x4 - { 0, 0, 1, 2, 1, 0, 0, 0 } // Jawz x2 + { 0, 0, 1, 2, 1, 0, 0, 0 }, // Jawz x2 + { 0, 0, 0, 0, 0, 0, 0, 0 } // Gachabom x3 }; static UINT8 K_KartItemOddsBattle[NUMKARTRESULTS-1][2] = @@ -131,12 +133,14 @@ static UINT8 K_KartItemOddsBattle[NUMKARTRESULTS-1][2] = { 0, 0 }, // Kitchen Sink { 2, 0 }, // Drop Target { 4, 0 }, // Garden Top + { 0, 0 }, // Gachabom { 0, 0 }, // Sneaker x2 { 0, 1 }, // Sneaker x3 { 0, 0 }, // Banana x3 { 2, 0 }, // Orbinaut x3 { 1, 1 }, // Orbinaut x4 - { 5, 1 } // Jawz x2 + { 5, 1 }, // Jawz x2 + { 0, 0 } // Gachabom x3 }; static kartitems_t K_KartItemReelTimeAttack[] = From 321c8bf9761bf5e38c0b34623ed7cffe0bb7faf0 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 19 Dec 2022 01:13:44 -0500 Subject: [PATCH 5/6] Update k_roulette.c --- src/k_roulette.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/k_roulette.c b/src/k_roulette.c index 042b1a685..dff3282e7 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -152,13 +152,14 @@ static kartitems_t K_KartItemReelTimeAttack[] = static kartitems_t K_KartItemReelBreakTheCapsules[] = { - KRITEM_TRIPLEORBINAUT, - KITEM_BANANA, + KITEM_GACHABOM, + KRITEM_TRIPLEGACHABOM, KITEM_NONE }; static kartitems_t K_KartItemReelBoss[] = { + // FIXME: gachabom...? KITEM_ORBINAUT, KITEM_BANANA, KITEM_NONE From fed08a28a1b298d35686a24689bfddd7dbc4b028 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 19 Dec 2022 01:50:14 -0500 Subject: [PATCH 6/6] Make Gachabom stay still when tossing forward --- src/p_mobj.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 43aa79294..900076abc 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7058,8 +7058,40 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } } break; - case MT_ORBINAUT: case MT_GACHABOM: + { + if (mobj->flags2 & MF2_AMBUSH) + { + mobj->friction = ORIG_FRICTION/4; + + if (mobj->momx || mobj->momy) + { + mobj_t *ghost = P_SpawnGhostMobj(mobj); + + if (mobj->target && !P_MobjWasRemoved(mobj->target) && mobj->target->player) + { + ghost->color = mobj->target->player->skincolor; + ghost->colorized = true; + } + } + + if (P_IsObjectOnGround(mobj)) + { + if (mobj->movecount > 1) + { + S_StartSound(mobj, mobj->info->activesound); + mobj->momx = mobj->momy = 0; + mobj->movecount = 1; + } + } + + if (mobj->threshold > 0) + mobj->threshold--; + break; + } + } + /* FALLTHRU */ + case MT_ORBINAUT: { Obj_OrbinautThink(mobj); P_MobjCheckWater(mobj);