diff --git a/graphics/hud/gun_slot_bg_32x40.png b/graphics/hud/gun_slot_bg_32x40.png index 90d6beb6a..1676f2aa0 100644 Binary files a/graphics/hud/gun_slot_bg_32x40.png and b/graphics/hud/gun_slot_bg_32x40.png differ diff --git a/src/cdogs/actors.c b/src/cdogs/actors.c index 906ab453d..33c9ed9c5 100644 --- a/src/cdogs/actors.c +++ b/src/cdogs/actors.c @@ -180,7 +180,7 @@ void UpdateActorState(TActor *actor, int ticks) { actor->DrawRadians -= (float)MIN(DRAW_RADIAN_SPEED * ticks, dr); } - + const struct vec2i tilePos = Vec2ToTile(actor->Pos); const Tile *t = MapGetTile(&gMap, tilePos); @@ -188,7 +188,9 @@ void UpdateActorState(TActor *actor, int ticks) // Step on 2 and 6 // TODO: custom animation and footstep frames const int frame = AnimationGetFrame(&actor->anim); - const bool isFootstepFrame = actor->anim.Type == ACTORANIMATION_WALKING && (frame == 2 || frame == 6) && actor->anim.newFrame; + const bool isFootstepFrame = actor->anim.Type == ACTORANIMATION_WALKING && + (frame == 2 || frame == 6) && + actor->anim.newFrame; if (isFootstepFrame) { @@ -233,18 +235,19 @@ void UpdateActorState(TActor *actor, int ticks) } // Damage when on special tiles - if (!gCampaign.IsClient && - actor->anim.Type == ACTORANIMATION_WALKING ? isFootstepFrame : (gMission.time % FPS_FRAMELIMIT) == 0) + if (!gCampaign.IsClient && actor->anim.Type == ACTORANIMATION_WALKING + ? isFootstepFrame + : (gMission.time % FPS_FRAMELIMIT) == 0) { - const BulletClass *b = MatGetDamageBullet(t); - if (b != NULL) - { - GameEvent e = GameEventNew(GAME_EVENT_THING_DAMAGE); - e.u.ThingDamage.UID = actor->uid; - e.u.ThingDamage.Kind = KIND_CHARACTER; - BulletToDamageEvent(b, &e); - GameEventsEnqueue(&gGameEvents, e); - } + const BulletClass *b = MatGetDamageBullet(t); + if (b != NULL) + { + GameEvent e = GameEventNew(GAME_EVENT_THING_DAMAGE); + e.u.ThingDamage.UID = actor->uid; + e.u.ThingDamage.Kind = KIND_CHARACTER; + BulletToDamageEvent(b, &e); + GameEventsEnqueue(&gGameEvents, e); + } } // Animation @@ -757,11 +760,7 @@ void ActorReplaceGun(const NActorReplaceGun rg) memcpy(&a->guns[rg.GunIdx], &w, sizeof w); // Switch immediately to picked up gun const PlayerData *p = PlayerDataGetByUID(a->PlayerUID); - if (wc->Type == GUNTYPE_GRENADE && PlayerHasGrenadeButton(p)) - { - a->grenadeIndex = rg.GunIdx - MAX_GUNS; - } - else + if (wc->Type != GUNTYPE_GRENADE || !PlayerHasGrenadeButton(p)) { a->gunIndex = rg.GunIdx; } @@ -1656,10 +1655,6 @@ TActor *ActorAdd(NActorAdd aa) { actor->gunIndex = i; } - if (i >= MAX_GUNS && ACTOR_GET_GRENADE(actor)->Gun == NULL) - { - actor->grenadeIndex = i - MAX_GUNS; - } } p->ActorUID = aa.UID; } @@ -1824,13 +1819,14 @@ bool ActorTrySwitchWeapon(const TActor *a, const bool allGuns) // If the player does not have a grenade key set, allow switching to // grenades (classic style) const int switchCount = allGuns ? MAX_WEAPONS : MAX_GUNS; - const int startIndex = - ActorGetNumGuns(a) > 0 ? a->gunIndex : a->grenadeIndex + MAX_GUNS; + const int startIndex = ActorGetNumGuns(a) > 0 ? a->gunIndex : MAX_GUNS; int weaponIndex = startIndex; do { weaponIndex = (weaponIndex + 1) % switchCount; - } while (a->guns[weaponIndex].Gun == NULL); + } while (a->guns[weaponIndex].Gun == + NULL); // TODO: don't cycle to auto-melee or default melee unless + // it's the only gun if (weaponIndex == startIndex) { // No other weapon to switch to diff --git a/src/cdogs/actors.h b/src/cdogs/actors.h index e0986f28a..0add51d8c 100644 --- a/src/cdogs/actors.h +++ b/src/cdogs/actors.h @@ -22,7 +22,7 @@ This file incorporates work covered by the following copyright and permission notice: - Copyright (c) 2013-2021 Cong Xu + Copyright (c) 2013-2022 Cong Xu All rights reserved. Redistribution and use in source and binary forms, with or without @@ -125,16 +125,14 @@ typedef struct Actor // -1 if human character (get from player data), otherwise index into // CharacterStore OtherChars int charId; - int PlayerUID; // -1 unless a human player - int uid; // unique ID across all actors - int pilotUID; // the actor that controls this - // (same as uid for normal actors) + int PlayerUID; // -1 unless a human player + int uid; // unique ID across all actors + int pilotUID; // the actor that controls this + // (same as uid for normal actors) int vehicleUID; // -1 unless piloting a vehicle Weapon guns[MAX_WEAPONS]; CArray ammo; // of int int gunIndex; - // TODO: multiple grenade slots? - int grenadeIndex; int health; // A counter for player death @@ -217,7 +215,7 @@ void ActorDestroy(TActor *a); TActor *ActorGetByUID(const int uid); const Character *ActorGetCharacter(const TActor *a); #define ACTOR_GET_GUN(a) (&(a)->guns[(a)->gunIndex]) -#define ACTOR_GET_GRENADE(a) (&(a)->guns[(a)->grenadeIndex + MAX_GUNS]) +#define ACTOR_GET_GRENADE(a) (&(a)->guns[MAX_GUNS]) #define ACTOR_GET_WEAPON(a) \ (ACTOR_GET_GUN(a)->Gun != NULL ? ACTOR_GET_GUN(a) : ACTOR_GET_GRENADE(a)) struct vec2 ActorGetAverageWeaponMuzzleOffset(const TActor *a); diff --git a/src/cdogs/pickup.c b/src/cdogs/pickup.c index 245f77638..a1938e401 100644 --- a/src/cdogs/pickup.c +++ b/src/cdogs/pickup.c @@ -133,7 +133,8 @@ void PickupsUpdate(CArray *pickups, const int ticks) static bool TreatAsGunPickup(const PickupEffect *pe, const TActor *a); static bool TryPickupAmmo(TActor *a, const Pickup *p, const PickupEffect *pe); static bool TryPickupGun( - TActor *a, const PickupEffect *pe, const bool pickupAll, const char **sound); + TActor *a, const PickupEffect *pe, const bool pickupAll, + const char **sound); void PickupPickup(TActor *a, Pickup *p, const bool pickupAll) { if (p->PickedUp) @@ -222,7 +223,7 @@ void PickupPickup(TActor *a, Pickup *p, const bool pickupAll) GameEventsEnqueue(&gGameEvents, e); } break; - + case PICKUP_LIVES: { canPickup = true; GameEvent e = GameEventNew(GAME_EVENT_PLAYER_ADD_LIVES); @@ -277,10 +278,8 @@ static bool TreatAsGunPickup(const PickupEffect *pe, const TActor *a) return false; case PICKUP_GUN: { const WeaponClass *wc = IdWeaponClass(pe->u.GunId); - // TODO: support picking up multi guns? - return wc->Type == GUNTYPE_NORMAL || - (wc->Type == GUNTYPE_GRENADE && - !HasGunUsingAmmo(a, wc->u.Normal.AmmoId)); + return wc->Type != GUNTYPE_GRENADE || + !HasGunUsingAmmo(a, wc->u.Normal.AmmoId); } default: CASSERT(false, "unexpected pickup type"); @@ -335,7 +334,8 @@ static bool TryPickupAmmo(TActor *a, const Pickup *p, const PickupEffect *pe) return true; } static bool TryPickupGun( - TActor *a, const PickupEffect *pe, const bool pickupAll, const char **sound) + TActor *a, const PickupEffect *pe, const bool pickupAll, + const char **sound) { // Guns can only be picked up manually if (!pickupAll) @@ -354,8 +354,7 @@ static bool TryPickupGun( const WeaponClass *wc = pe->Type == PICKUP_GUN ? IdWeaponClass(pe->u.GunId) - : StrWeaponClass( - AmmoGetById(&gAmmo, pe->u.Ammo.Id)->DefaultGun); + : StrWeaponClass(AmmoGetById(&gAmmo, pe->u.Ammo.Id)->DefaultGun); const int actorsGunIdx = ActorFindGun(a, wc); if (actorsGunIdx >= 0) @@ -377,15 +376,20 @@ static bool TryPickupGun( // Replace the current gun, unless there's a free slot, in which case // pick up into the free spot const int weaponIndexStart = - wc->Type == GUNTYPE_GRENADE ? MAX_GUNS : 0; + wc->Type == GUNTYPE_GRENADE + ? MAX_GUNS + : (wc->Type == GUNTYPE_MELEE ? MELEE_SLOT : 0); const int weaponIndexEnd = - wc->Type == GUNTYPE_GRENADE ? MAX_WEAPONS : MAX_GUNS; + wc->Type == GUNTYPE_GRENADE + ? MAX_WEAPONS + : (wc->Type == GUNTYPE_MELEE ? MELEE_SLOT + 1 : MELEE_SLOT); GameEvent e = GameEventNew(GAME_EVENT_ACTOR_REPLACE_GUN); e.u.ActorReplaceGun.UID = a->uid; strcpy(e.u.ActorReplaceGun.Gun, wc->name); - e.u.ActorReplaceGun.GunIdx = wc->Type == GUNTYPE_GRENADE - ? a->grenadeIndex + MAX_GUNS - : a->gunIndex; + e.u.ActorReplaceGun.GunIdx = + wc->Type == GUNTYPE_GRENADE + ? MAX_GUNS + : (wc->Type == GUNTYPE_MELEE ? MELEE_SLOT : a->gunIndex); int replaceGunIndex = e.u.ActorReplaceGun.GunIdx; for (int i = weaponIndexStart; i < weaponIndexEnd; i++) { diff --git a/src/cdogs/player.h b/src/cdogs/player.h index 0989cda8a..39b7a3346 100644 --- a/src/cdogs/player.h +++ b/src/cdogs/player.h @@ -1,7 +1,7 @@ /* C-Dogs SDL A port of the legendary (and fun) action/arcade cdogs. - Copyright (c) 2014-2016, 2018-2020 Cong Xu + Copyright (c) 2014-2016, 2018-2020, 2022 Cong Xu All rights reserved. Redistribution and use in source and binary forms, with or without @@ -29,7 +29,8 @@ #include "character.h" -#define MAX_GUNS 2 +#define MAX_GUNS 3 +#define MELEE_SLOT 2 #define MAX_GRENADES 1 #define MAX_WEAPONS (MAX_GUNS + MAX_GRENADES) // TODO: track accuracy diff --git a/src/cdogs/weapon_class.c b/src/cdogs/weapon_class.c index c3b4d2893..311218e2c 100644 --- a/src/cdogs/weapon_class.c +++ b/src/cdogs/weapon_class.c @@ -1,7 +1,7 @@ /* C-Dogs SDL A port of the legendary (and fun) action/arcade cdogs. - Copyright (c) 2013-2021 Cong Xu + Copyright (c) 2013-2022 Cong Xu All rights reserved. Redistribution and use in source and binary forms, with or without @@ -41,6 +41,7 @@ static const char *GunTypeStr(const GunType t) switch (t) { T2S(GUNTYPE_NORMAL, "Normal"); + T2S(GUNTYPE_MELEE, "Melee"); T2S(GUNTYPE_GRENADE, "Grenade"); T2S(GUNTYPE_MULTI, "Multi"); default: @@ -125,12 +126,18 @@ static void LoadWeaponClass(WeaponClass *wc, json_t *node, const int version) } else { + bool canShoot = true; + LoadBool(&canShoot, node, "CanShoot"); bool isGrenade = false; LoadBool(&isGrenade, node, "IsGrenade"); if (isGrenade) { wc->Type = GUNTYPE_GRENADE; } + else if (!canShoot) + { + wc->Type = GUNTYPE_MELEE; + } } char *tmp; @@ -148,7 +155,6 @@ static void LoadWeaponClass(WeaponClass *wc, json_t *node, const int version) wc->u.Normal.MuzzleFlash = StrParticleClass(&gParticleClasses, "muzzle_flash_default"); wc->u.Normal.AmmoId = -1; - wc->u.Normal.CanShoot = true; wc->CanDrop = true; } @@ -183,10 +189,16 @@ static void LoadWeaponClass(WeaponClass *wc, json_t *node, const int version) LoadStr(&wc->DropGun, node, "DropGun"); - switch (wc->Type) + if (wc->Type == GUNTYPE_MULTI) { - case GUNTYPE_NORMAL: - case GUNTYPE_GRENADE: // fallthrough + int i = 0; + for (const json_t *gunNode = gunsNode->child->child; gunNode; + gunNode = gunNode->next, i++) + { + wc->u.Guns[i] = json_unescape(gunNode->text); + } + } + else { tmp = NULL; LoadStr(&tmp, node, "Pic"); @@ -293,8 +305,6 @@ static void LoadWeaponClass(WeaponClass *wc, json_t *node, const int version) CFREE(tmp); } - LoadBool(&wc->u.Normal.CanShoot, node, "CanShoot"); - if (version < 3) { LoadInt(&wc->u.Normal.Shake.Amount, node, "ShakeAmount"); @@ -308,27 +318,13 @@ static void LoadWeaponClass(WeaponClass *wc, json_t *node, const int version) "CameraSubjectOnly"); } } - break; - case GUNTYPE_MULTI: { - int i = 0; - for (const json_t *gunNode = gunsNode->child->child; gunNode; - gunNode = gunNode->next, i++) - { - wc->u.Guns[i] = json_unescape(gunNode->text); - } - } - break; - default: - CASSERT(false, "unknown gun type"); - break; - } wc->IsRealGun = true; if (version < 2) { CASSERT(wc->Type != GUNTYPE_MULTI, "unexpected gun type"); - if (!wc->u.Normal.CanShoot) + if (wc->Type == GUNTYPE_MELEE) { wc->Lock = 0; } @@ -337,10 +333,14 @@ static void LoadWeaponClass(WeaponClass *wc, json_t *node, const int version) LOG(LM_MAP, LL_DEBUG, "loaded %s name(%s) lock(%d)...", GunTypeStr(wc->Type), wc->name, wc->Lock); LOG(LM_MAP, LL_DEBUG, "...canDrop(%s)", wc->CanDrop ? "true" : "false"); - switch (wc->Type) + if (wc->Type == GUNTYPE_MULTI) + { + LOG(LM_MAP, LL_DEBUG, "...guns{%s, %s}", + wc->u.Guns[0] ? wc->u.Guns[0] : "", + wc->u.Guns[1] ? wc->u.Guns[1] : ""); + } + else { - case GUNTYPE_NORMAL: - case GUNTYPE_GRENADE: // fallthrough LOG(LM_MAP, LL_DEBUG, "bullets("); CA_FOREACH(const BulletClass *, bc, wc->u.Normal.Bullets) if (_ca_index > 0) @@ -360,24 +360,14 @@ static void LoadWeaponClass(WeaponClass *wc, json_t *node, const int version) wc->u.Normal.Spread.Width, wc->u.Normal.Spread.Count, wc->u.Normal.AngleOffset, wc->u.Normal.MuzzleHeight); LOG(LM_MAP, LL_DEBUG, - "...elevation(%d-%d) muzzleFlash(%s) brass(%s) canShoot(%s)...", + "...elevation(%d-%d) muzzleFlash(%s) brass(%s)...", wc->u.Normal.ElevationLow, wc->u.Normal.ElevationHigh, wc->u.Normal.MuzzleFlash != NULL ? wc->u.Normal.MuzzleFlash->Name : "", - wc->u.Normal.Brass != NULL ? wc->u.Normal.Brass->Name : "", - wc->u.Normal.CanShoot ? "true" : "false"); + wc->u.Normal.Brass != NULL ? wc->u.Normal.Brass->Name : ""); LOG(LM_MAP, LL_DEBUG, "...shake{amount(%d), cameraSubjectOnly(%s)}", wc->u.Normal.Shake.Amount, wc->u.Normal.Shake.CameraSubjectOnly ? "true" : "false"); - break; - case GUNTYPE_MULTI: - LOG(LM_MAP, LL_DEBUG, "...guns{%s, %s}", - wc->u.Guns[0] ? wc->u.Guns[0] : "", - wc->u.Guns[1] ? wc->u.Guns[1] : ""); - break; - default: - CASSERT(false, "unknown gun type"); - break; } } void WeaponClassesTerminate(WeaponClasses *wcs) @@ -399,22 +389,17 @@ static void WeaponClassTerminate(WeaponClass *wc) CFREE(wc->name); CFREE(wc->Description); CFREE(wc->DropGun); - switch (wc->Type) + if (wc->Type == GUNTYPE_MULTI) { - case GUNTYPE_NORMAL: - case GUNTYPE_GRENADE: // fallthrough - CFREE(wc->u.Normal.Sprites); - CArrayTerminate(&wc->u.Normal.Bullets); - break; - case GUNTYPE_MULTI: for (int i = 0; i < MAX_BARRELS; i++) { CFREE(wc->u.Guns[i]); } - break; - default: - CASSERT(false, "unknown gun type"); - break; + } + else + { + CFREE(wc->u.Normal.Sprites); + CArrayTerminate(&wc->u.Normal.Bullets); } memset(wc, 0, sizeof *wc); } @@ -576,8 +561,7 @@ float WeaponClassGetMuzzleHeight( bool WeaponClassHasMuzzle(const WeaponClass *wc) { - return wc->Type == GUNTYPE_NORMAL && wc->u.Normal.Sprites != NULL && - wc->u.Normal.CanShoot; + return wc->Type == GUNTYPE_NORMAL && wc->u.Normal.Sprites != NULL; } bool WeaponClassIsHighDPS(const WeaponClass *wc) { @@ -634,7 +618,7 @@ bool WeaponClassCanShoot(const WeaponClass *wc) return WeaponClassCanShoot(WeaponClassGetBarrel(wc, 0)) || WeaponClassCanShoot(WeaponClassGetBarrel(wc, 1)); } - return wc->u.Normal.CanShoot; + return wc->Type != GUNTYPE_MELEE; } int WeaponClassNumBarrels(const WeaponClass *wc) { diff --git a/src/cdogs/weapon_class.h b/src/cdogs/weapon_class.h index 34ebcd63e..5d810e847 100644 --- a/src/cdogs/weapon_class.h +++ b/src/cdogs/weapon_class.h @@ -1,7 +1,7 @@ /* C-Dogs SDL A port of the legendary (and fun) action/arcade cdogs. - Copyright (c) 2013-2019, 2021 Cong Xu + Copyright (c) 2013-2019, 2021-2022 Cong Xu All rights reserved. Redistribution and use in source and binary forms, with or without @@ -57,6 +57,7 @@ typedef enum typedef enum { GUNTYPE_NORMAL, + GUNTYPE_MELEE, GUNTYPE_GRENADE, GUNTYPE_MULTI } GunType; @@ -98,7 +99,6 @@ typedef struct int ElevationHigh; const ParticleClass *MuzzleFlash; const ParticleClass *Brass; - bool CanShoot; struct { int Amount; // Amount of screen shake to produce diff --git a/src/prep_equip.c b/src/prep_equip.c index 1b38c5d4d..645872f7f 100644 --- a/src/prep_equip.c +++ b/src/prep_equip.c @@ -128,10 +128,10 @@ static void AddDefaultGuns( PlayerData *p, const int idx, const CArray *guns, const bool isGrenade) { const char *defaultGuns[MAX_LOCAL_PLAYERS][MAX_GUNS] = { - {"Shotgun", "Machine gun"}, - {"Powergun", "Flamer"}, - {"Sniper rifle", "Knife"}, - {"Machine gun", "Flamer"}, + {"Shotgun", "Machine gun", "Knife"}, + {"Powergun", "Flamer", "Knife"}, + {"Sniper rifle", "Pulse rifle", "Knife"}, + {"Machine gun", "Flamer", "Knife"}, }; const char *defaultGrenades[MAX_LOCAL_PLAYERS][MAX_GRENADES] = { {"Shrapnel bombs"}, diff --git a/src/weapon_menu.c b/src/weapon_menu.c index 310d912cd..c50f8a0b8 100644 --- a/src/weapon_menu.c +++ b/src/weapon_menu.c @@ -47,9 +47,17 @@ #define GUN_BG_H 25 #define SCROLL_H 12 -static bool IsEquippingGrenade(const int slot) +static GunType SlotType(const int slot) { - return slot >= MAX_GUNS; + if (slot < MELEE_SLOT) + { + return GUNTYPE_NORMAL; + } + else if (slot == MELEE_SLOT) + { + return GUNTYPE_MELEE; + } + return GUNTYPE_GRENADE; } static const WeaponClass *GetGun( @@ -59,10 +67,9 @@ static const WeaponClass *GetGun( { return NULL; } - const bool isGrenade = IsEquippingGrenade(slot); int idx2 = 0; CA_FOREACH(const WeaponClass *, wc, *weapons) - if (((*wc)->Type == GUNTYPE_GRENADE) != isGrenade) + if ((*wc)->Type != SlotType(slot)) { continue; } @@ -130,9 +137,8 @@ static int CountNumGuns(const WeaponMenuData *data, const int slot) } // Count total guns int numGuns = 0; - const bool isGrenade = IsEquippingGrenade(slot); CA_FOREACH(const WeaponClass *, wc, data->weapons) - if (((*wc)->Type == GUNTYPE_GRENADE) != isGrenade) + if ((*wc)->Type != SlotType(slot)) { continue; } @@ -222,12 +228,12 @@ static void DrawEquipSlot( Rect2iNew( svec2i(bgPos.x + 1, bgPos.y + 1), svec2i(WEAPON_MENU_WIDTH / 2, EQUIP_MENU_SLOT_HEIGHT - 2)), - 11, (slot & 1) ? 16 : 4, 12, (slot & 1) ? 4 : 16, true, mask, + 11, (slot & 1) ? 4 : 13, 12, (slot & 1) ? 13 : 4, true, mask, SDL_FLIP_NONE); const FontOpts fopts = { align, ALIGN_START, svec2i(WEAPON_MENU_WIDTH / 2, FontH()), - svec2i(2, 1), color}; + svec2i(3, 1), color}; FontStrOpt(label, pos, fopts); const Pic *gunIcon = pData->guns[slot] @@ -251,10 +257,13 @@ static void DrawEquipSlot( g, svec2i(pos.x + WEAPON_MENU_WIDTH / 2 - 6, y + 13), colorGreen); } - y += EQUIP_MENU_SLOT_HEIGHT - FontH(); + y += EQUIP_MENU_SLOT_HEIGHT - FontH() - 1; const char *gunName = pData->guns[slot] ? pData->guns[slot]->name : NO_GUN_LABEL; - FontStrMask(gunName, svec2i(pos.x, y), color); + const FontOpts fopts2 = { + align, ALIGN_START, svec2i(WEAPON_MENU_WIDTH / 2, FontH()), + svec2i(3, 0), color}; + FontStrOpt(gunName, svec2i(pos.x, y), fopts2); } static void DrawEquipMenu( const menu_t *menu, GraphicsDevice *g, const struct vec2i pos, @@ -269,8 +278,12 @@ static void DrawEquipMenu( d, g, 1, "II", svec2i(pos.x + WEAPON_MENU_WIDTH / 2, pos.y), ALIGN_END); DrawEquipSlot( - d, g, 2, "G", svec2i(pos.x, pos.y + EQUIP_MENU_SLOT_HEIGHT), - ALIGN_START); + d, g, MELEE_SLOT, "Melee", + svec2i(pos.x, pos.y + EQUIP_MENU_SLOT_HEIGHT), ALIGN_START); + DrawEquipSlot( + d, g, 3, "Bombs", + svec2i(pos.x + WEAPON_MENU_WIDTH / 2, pos.y + EQUIP_MENU_SLOT_HEIGHT), + ALIGN_END); const WeaponClass *gun = NULL; if (d->display.GunIdx >= 0 && d->display.GunIdx < MAX_WEAPONS) @@ -438,27 +451,32 @@ static menu_t *CreateEquipMenu( ms->align = MENU_ALIGN_LEFT; MenuAddExitType(ms, MENU_TYPE_RETURN); - // Count number of guns/grenades, and disable extra menu items + // Count number of each gun type, and disable extra menu items int numGuns = 0; + int numMelee = 0; int numGrenades = 0; CA_FOREACH(const WeaponClass *, wc, data->weapons) if ((*wc)->Type == GUNTYPE_GRENADE) { numGrenades++; } + else if ((*wc)->Type == GUNTYPE_MELEE) + { + numMelee++; + } else { numGuns++; } CA_FOREACH_END() - int i; - for (i = 0; i < MAX_GUNS; i++) + for (int i = 0; i < MELEE_SLOT; i++) { data->EquipEnabled[i] = i < numGuns; } - for (; i < MAX_GUNS + MAX_GRENADES; i++) + data->EquipEnabled[MELEE_SLOT] = numMelee > 0; + for (int i = 0; i < MAX_GRENADES; i++) { - data->EquipEnabled[i] = i - MAX_GUNS < numGrenades; + data->EquipEnabled[i + MAX_GUNS] = i < numGrenades; } // Pre-select the End menu @@ -501,9 +519,13 @@ void WeaponMenuCreate( { data->SlotHasNew[MAX_GUNS] = true; } + else if ((*wc)->Type == GUNTYPE_MELEE) + { + data->SlotHasNew[MELEE_SLOT] = true; + } else { - for (int i = 0; i < MAX_GUNS; i++) + for (int i = 0; i < MELEE_SLOT; i++) { data->SlotHasNew[i] = true; } @@ -606,7 +628,7 @@ static void DrawGunMenu( // Draw guns: red if selected, yellow if equipped int idx = 0; CA_FOREACH(const WeaponClass *, wc, d->weapons) - if (((*wc)->Type == GUNTYPE_GRENADE) != IsEquippingGrenade(d->EquipSlot)) + if ((*wc)->Type != SlotType(d->EquipSlot)) { continue; } @@ -745,9 +767,8 @@ static int HandleInputGunMenu(int cmd, void *data) // Count total guns int numGuns = 0; - const bool isGrenade = IsEquippingGrenade(d->EquipSlot); CA_FOREACH(const WeaponClass *, wc, d->weapons) - if (((*wc)->Type == GUNTYPE_GRENADE) != isGrenade) + if ((*wc)->Type != SlotType(d->EquipSlot)) { continue; }