mirror of
https://github.com/cxong/cdogs-sdl.git
synced 2025-07-23 07:23:01 +02:00
Show upgrade icons #740
This commit is contained in:
@@ -19,7 +19,7 @@
|
||||
{
|
||||
"Pic": "chainsaw",
|
||||
"Icon": "chainsaw",
|
||||
"Name": "Chainsaw x2",
|
||||
"Name": "2xChainsaw",
|
||||
"Bullet": "chainsaw_x2",
|
||||
"Prerequisite": "Chainsaw",
|
||||
"Cost": 0,
|
||||
@@ -34,9 +34,9 @@
|
||||
{
|
||||
"Pic": "chainsaw",
|
||||
"Icon": "chainsaw",
|
||||
"Name": "Chainsaw x3",
|
||||
"Name": "3xChainsaw",
|
||||
"Bullet": "chainsaw_x3",
|
||||
"Prerequisite": "Chainsaw x2",
|
||||
"Prerequisite": "2xChainsaw",
|
||||
"Cost": 0,
|
||||
"Lock": 0,
|
||||
"Sound": "",
|
||||
@@ -49,9 +49,9 @@
|
||||
{
|
||||
"Pic": "chainsaw",
|
||||
"Icon": "chainsaw",
|
||||
"Name": "Chainsaw x4",
|
||||
"Name": "4xChainsaw",
|
||||
"Bullet": "chainsaw_x4",
|
||||
"Prerequisite": "Chainsaw x3",
|
||||
"Prerequisite": "3xChainsaw",
|
||||
"Cost": 0,
|
||||
"Lock": 0,
|
||||
"Sound": "",
|
||||
@@ -64,9 +64,9 @@
|
||||
{
|
||||
"Pic": "chainsaw",
|
||||
"Icon": "chainsaw",
|
||||
"Name": "Chainsaw x5",
|
||||
"Name": "5xChainsaw",
|
||||
"Bullet": "chainsaw_x5",
|
||||
"Prerequisite": "Chainsaw x4",
|
||||
"Prerequisite": "4xChainsaw",
|
||||
"Cost": 0,
|
||||
"Lock": 0,
|
||||
"Sound": "",
|
||||
|
@@ -17,10 +17,10 @@
|
||||
"EnemyDensity": 13,
|
||||
"Weapons": ["Barehanded",
|
||||
"Chainsaw",
|
||||
"Chainsaw x2",
|
||||
"Chainsaw x3",
|
||||
"Chainsaw x4",
|
||||
"Chainsaw x5",
|
||||
"2xChainsaw",
|
||||
"3xChainsaw",
|
||||
"4xChainsaw",
|
||||
"5xChainsaw",
|
||||
"MiniGun",
|
||||
"Launcher",
|
||||
"Flamer",
|
||||
|
@@ -500,6 +500,10 @@ bool PlayerHasGrenadeButton(const PlayerData *p)
|
||||
|
||||
bool PlayerHasWeapon(const PlayerData *p, const WeaponClass *wc)
|
||||
{
|
||||
if (wc == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < MAX_WEAPONS; i++)
|
||||
{
|
||||
if (p->guns[i] == wc)
|
||||
@@ -510,6 +514,23 @@ bool PlayerHasWeapon(const PlayerData *p, const WeaponClass *wc)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PlayerHasWeaponUpgrade(const PlayerData *p, const WeaponClass *wc)
|
||||
{
|
||||
if (wc == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < MAX_WEAPONS; i++)
|
||||
{
|
||||
const WeaponClass *prereq = WeaponClassGetPrerequisite(p->guns[i]);
|
||||
if (prereq == wc)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void AddWeaponToSlot(
|
||||
PlayerData *p, const WeaponClass *wc, const int slot)
|
||||
{
|
||||
|
@@ -110,6 +110,7 @@ bool PlayerTrySetUnusedInputDevice(
|
||||
int PlayerGetNumWeapons(const PlayerData *p);
|
||||
bool PlayerHasGrenadeButton(const PlayerData *p);
|
||||
bool PlayerHasWeapon(const PlayerData *p, const WeaponClass *wc);
|
||||
bool PlayerHasWeaponUpgrade(const PlayerData *p, const WeaponClass *wc);
|
||||
void PlayerAddWeapon(PlayerData *p, const WeaponClass *wc);
|
||||
void PlayerAddWeaponToSlot(
|
||||
PlayerData *p, const WeaponClass *wc, const int slot);
|
||||
|
102
src/equip_menu.c
102
src/equip_menu.c
@@ -173,10 +173,25 @@ static void DrawEquipSlot(
|
||||
g, pData, pData->guns[slot], mask, svec2i(bgPos.x, bgPos.y + FontH()),
|
||||
svec2i(slotSize.x, slotSize.y - 2 * FontH() - 1));
|
||||
|
||||
if (data->SlotHasNew[slot])
|
||||
const Pic *arrow = PicManagerGetPic(&gPicManager, "hud/arrow");
|
||||
const struct vec2i metaPos = svec2i(pos.x + EQUIP_MENU_WIDTH / 2 - 6, y + 13);
|
||||
const struct vec2i arrowPos = svec2i(metaPos.x - 4, metaPos.y);
|
||||
switch (data->SlotMeta[slot])
|
||||
{
|
||||
DrawCross(
|
||||
g, svec2i(pos.x + EQUIP_MENU_WIDTH / 2 - 6, y + 13), colorGreen);
|
||||
case META_NONE:
|
||||
break;
|
||||
case META_NEW:
|
||||
DrawCross(g, metaPos, colorGreen);
|
||||
break;
|
||||
case META_UPGRADE:
|
||||
PicRender(arrow, g->gameWindow.renderer, arrowPos, colorGreen, 0, svec2_one(), SDL_FLIP_NONE, Rect2iZero());
|
||||
break;
|
||||
case META_DOWNGRADE:
|
||||
PicRender(arrow, g->gameWindow.renderer, arrowPos, colorRed, 0, svec2_one(), SDL_FLIP_VERTICAL, Rect2iZero());
|
||||
break;
|
||||
default:
|
||||
CASSERT(false, "unexpected");
|
||||
break;
|
||||
}
|
||||
|
||||
// Draw price
|
||||
@@ -424,6 +439,53 @@ static int HandleInputEquipMenu(int cmd, void *data)
|
||||
}
|
||||
|
||||
static bool HasWeapon(const CArray *weapons, const WeaponClass *wc);
|
||||
static void ResetSlotMeta(EquipMenu *menu)
|
||||
{
|
||||
const PlayerData *pData = PlayerDataGetByUID(menu->PlayerUID);
|
||||
|
||||
// Update SlotMeta
|
||||
for (int i = 0; i < MAX_WEAPONS; i++)
|
||||
{
|
||||
menu->SlotMeta[i] = META_NONE;
|
||||
const WeaponClass *slotWC = pData->guns[i];
|
||||
CA_FOREACH(const WeaponClass *, wc, menu->weapons)
|
||||
if (!InSlot(*wc, i))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const bool isNew = *(const bool *)CArrayGet(&menu->weaponIsNew, _ca_index);
|
||||
DrawGunMeta meta = isNew ? META_NEW : META_NONE;
|
||||
if (slotWC != NULL)
|
||||
{
|
||||
// Check if this slot has an upgrade/downgrade
|
||||
if (slotWC == WeaponClassGetPrerequisite(*wc))
|
||||
{
|
||||
meta = META_UPGRADE;
|
||||
}
|
||||
else if (WeaponClassGetPrerequisite(slotWC) == *wc)
|
||||
{
|
||||
meta = META_DOWNGRADE;
|
||||
}
|
||||
}
|
||||
menu->SlotMeta[i] = MAX(menu->SlotMeta[i], meta);
|
||||
CA_FOREACH_END()
|
||||
}
|
||||
}
|
||||
static bool HasWeapon(const CArray *weapons, const WeaponClass *wc)
|
||||
{
|
||||
if (weapons == NULL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
CA_FOREACH(const WeaponClass *, wc2, *weapons)
|
||||
if (*wc2 == wc)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
CA_FOREACH_END()
|
||||
return false;
|
||||
}
|
||||
|
||||
void EquipMenuCreate(
|
||||
EquipMenu *menu, const CArray *weapons, const CArray *prevWeapons,
|
||||
const int numPlayers, const int player, const int playerUID,
|
||||
@@ -447,25 +509,8 @@ void EquipMenuCreate(
|
||||
CA_FOREACH(const WeaponClass *, wc, menu->weapons)
|
||||
const bool isNew = !HasWeapon(prevWeapons, *wc);
|
||||
CArrayPushBack(&menu->weaponIsNew, &isNew);
|
||||
if (isNew)
|
||||
{
|
||||
if ((*wc)->Type == GUNTYPE_GRENADE)
|
||||
{
|
||||
menu->SlotHasNew[MAX_GUNS] = true;
|
||||
}
|
||||
else if ((*wc)->Type == GUNTYPE_MELEE)
|
||||
{
|
||||
menu->SlotHasNew[MELEE_SLOT] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < MELEE_SLOT; i++)
|
||||
{
|
||||
menu->SlotHasNew[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
CA_FOREACH_END()
|
||||
ResetSlotMeta(menu);
|
||||
|
||||
switch (numPlayers)
|
||||
{
|
||||
@@ -575,20 +620,6 @@ void EquipMenuCreate(
|
||||
&menu->ammoMenu, playerUID, pos, menu->size, handlers, graphics);
|
||||
}
|
||||
}
|
||||
static bool HasWeapon(const CArray *weapons, const WeaponClass *wc)
|
||||
{
|
||||
if (weapons == NULL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
CA_FOREACH(const WeaponClass *, wc2, *weapons)
|
||||
if (*wc2 == wc)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
CA_FOREACH_END()
|
||||
return false;
|
||||
}
|
||||
|
||||
void EquipMenuTerminate(EquipMenu *menu)
|
||||
{
|
||||
@@ -619,6 +650,7 @@ void EquipMenuUpdate(EquipMenu *menu, const int cmd)
|
||||
WeaponMenuReset(&menu->weaponMenus[i]);
|
||||
}
|
||||
AmmoMenuReset(&menu->ammoMenu);
|
||||
ResetSlotMeta(menu);
|
||||
}
|
||||
}
|
||||
else if (menu->slot == menu->ammoSlot && menu->ammoMenu.Active)
|
||||
|
@@ -34,6 +34,13 @@
|
||||
#include "menu_utils.h"
|
||||
#include "weapon_menu.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
META_NONE,
|
||||
META_DOWNGRADE,
|
||||
META_UPGRADE,
|
||||
META_NEW
|
||||
} DrawGunMeta;
|
||||
typedef struct
|
||||
{
|
||||
MenuDisplayPlayerData display;
|
||||
@@ -45,7 +52,7 @@ typedef struct
|
||||
const NamedSprites *slotBGSprites;
|
||||
CArray weapons; // of const WeaponClass *
|
||||
CArray weaponIsNew; // of bool
|
||||
bool SlotHasNew[MAX_WEAPONS];
|
||||
DrawGunMeta SlotMeta[MAX_WEAPONS];
|
||||
struct vec2i size;
|
||||
int ammoSlot;
|
||||
int endSlot;
|
||||
|
@@ -36,6 +36,8 @@
|
||||
#include <cdogs/draw/nine_slice.h>
|
||||
#include <cdogs/font.h>
|
||||
|
||||
#include "equip_menu.h"
|
||||
|
||||
#define NO_GUN_LABEL "(None)"
|
||||
#define EQUIP_MENU_SLOT_HEIGHT 40
|
||||
#define WEAPON_MENU_MAX_ROWS 4
|
||||
@@ -242,7 +244,7 @@ static menu_t *CreateMenu(WeaponMenu *data)
|
||||
}
|
||||
static void DrawGun(
|
||||
const WeaponMenu *data, GraphicsDevice *g, const int idx,
|
||||
const WeaponClass *wc, const bool isNew, const struct vec2i pos,
|
||||
const WeaponClass *wc, const DrawGunMeta meta, const struct vec2i pos,
|
||||
const struct vec2i bgSize);
|
||||
static void DrawMenu(
|
||||
const menu_t *menu, GraphicsDevice *g, const struct vec2i pos,
|
||||
@@ -264,10 +266,10 @@ static void DrawMenu(
|
||||
const int row = _ca_index / d->cols;
|
||||
if (row >= d->scroll && row < d->scroll + WEAPON_MENU_MAX_ROWS)
|
||||
{
|
||||
const bool *isNew = CArrayGet(d->weaponIsNew, *idx);
|
||||
const DrawGunMeta *meta = CArrayGet(&d->weaponMeta, *idx);
|
||||
const WeaponClass **wc = CArrayGet(d->weapons, *idx);
|
||||
DrawGun(
|
||||
d, g, _ca_index, *wc, *isNew, svec2i(pos.x, pos.y + weaponsY), bgSize);
|
||||
d, g, _ca_index, *wc, *meta, svec2i(pos.x, pos.y + weaponsY), bgSize);
|
||||
}
|
||||
if (_ca_index / d->cols == d->scroll + WEAPON_MENU_MAX_ROWS)
|
||||
{
|
||||
@@ -334,7 +336,7 @@ static void DrawMenu(
|
||||
}
|
||||
static void DrawGun(
|
||||
const WeaponMenu *data, GraphicsDevice *g, const int idx,
|
||||
const WeaponClass *wc, const bool isNew, const struct vec2i pos,
|
||||
const WeaponClass *wc, const DrawGunMeta meta, const struct vec2i pos,
|
||||
const struct vec2i bgSize)
|
||||
{
|
||||
const bool selected = data->idx == idx;
|
||||
@@ -390,10 +392,26 @@ static void DrawGun(
|
||||
sprintf(buf, "$%d", wc->Price);
|
||||
FontStrOpt(buf, bgPos, foptsP);
|
||||
}
|
||||
|
||||
if (isNew)
|
||||
|
||||
const Pic *arrow = PicManagerGetPic(&gPicManager, "hud/arrow");
|
||||
const struct vec2i metaPos = svec2i(bgPos.x + GUN_BG_W - 6, bgPos.y + 5);
|
||||
const struct vec2i arrowPos = svec2i(metaPos.x - 4, metaPos.y);
|
||||
switch (meta)
|
||||
{
|
||||
DrawCross(g, svec2i(bgPos.x + GUN_BG_W - 6, bgPos.y + 5), colorGreen);
|
||||
case META_NONE:
|
||||
break;
|
||||
case META_NEW:
|
||||
DrawCross(g, metaPos, colorGreen);
|
||||
break;
|
||||
case META_UPGRADE:
|
||||
PicRender(arrow, g->gameWindow.renderer, arrowPos, colorGreen, 0, svec2_one(), SDL_FLIP_NONE, Rect2iZero());
|
||||
break;
|
||||
case META_DOWNGRADE:
|
||||
PicRender(arrow, g->gameWindow.renderer, arrowPos, colorRed, 0, svec2_one(), SDL_FLIP_VERTICAL, Rect2iZero());
|
||||
break;
|
||||
default:
|
||||
CASSERT(false, "unexpected");
|
||||
break;
|
||||
}
|
||||
|
||||
const FontOpts fopts = {
|
||||
@@ -472,19 +490,41 @@ void WeaponMenuTerminate(WeaponMenu *menu)
|
||||
{
|
||||
MenuSystemTerminate(&menu->ms);
|
||||
CArrayTerminate(&menu->weaponIndices);
|
||||
CArrayTerminate(&menu->weaponMeta);
|
||||
}
|
||||
|
||||
void WeaponMenuReset(WeaponMenu *menu)
|
||||
{
|
||||
const PlayerData *pData = PlayerDataGetByUID(menu->PlayerUID);
|
||||
menu->idx = 0;
|
||||
const WeaponClass *equipped = pData->guns[menu->slot];
|
||||
|
||||
// Find out which weapons are new/upgrades/downgrades
|
||||
CArrayTerminate(&menu->weaponMeta);
|
||||
CArrayInit(&menu->weaponMeta, sizeof(DrawGunMeta));
|
||||
CA_FOREACH(const WeaponClass *, wc, *menu->weapons)
|
||||
const bool isNew = *(const bool *)CArrayGet(menu->weaponIsNew, _ca_index);
|
||||
DrawGunMeta meta = isNew ? META_NEW : META_NONE;
|
||||
if (equipped != NULL)
|
||||
{
|
||||
// Check if this slot has an upgrade/downgrade
|
||||
if (equipped == WeaponClassGetPrerequisite(*wc))
|
||||
{
|
||||
meta = META_UPGRADE;
|
||||
}
|
||||
else if (WeaponClassGetPrerequisite(equipped) == *wc)
|
||||
{
|
||||
meta = META_DOWNGRADE;
|
||||
}
|
||||
}
|
||||
CArrayPushBack(&menu->weaponMeta, &meta);
|
||||
CA_FOREACH_END()
|
||||
|
||||
// Get the weapon indices available for this slot
|
||||
CArrayTerminate(&menu->weaponIndices);
|
||||
CArrayInit(&menu->weaponIndices, sizeof(int));
|
||||
|
||||
// Add the equipped weapon's upgrades and downgrades first
|
||||
const WeaponClass *equipped = pData->guns[menu->slot];
|
||||
if (equipped != NULL)
|
||||
{
|
||||
CA_FOREACH(const WeaponClass *, wc, *menu->weapons)
|
||||
|
@@ -49,6 +49,7 @@ typedef struct
|
||||
CArray weaponIndices; // of int
|
||||
const CArray *weapons; // of const WeaponClass *
|
||||
const CArray *weaponIsNew; // of bool
|
||||
CArray weaponMeta; // of DrawGunMeta
|
||||
struct vec2i size;
|
||||
int cols;
|
||||
int scroll;
|
||||
|
Reference in New Issue
Block a user