Show upgrade icons #740

This commit is contained in:
Cong
2023-03-05 00:01:23 +11:00
parent 973a0bfe08
commit 9db3dfb075
8 changed files with 157 additions and 55 deletions

View File

@@ -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": "",

View File

@@ -17,10 +17,10 @@
"EnemyDensity": 13,
"Weapons": ["Barehanded",
"Chainsaw",
"Chainsaw x2",
"Chainsaw x3",
"Chainsaw x4",
"Chainsaw x5",
"2xChainsaw",
"3xChainsaw",
"4xChainsaw",
"5xChainsaw",
"MiniGun",
"Launcher",
"Flamer",

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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)

View File

@@ -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;

View File

@@ -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)

View File

@@ -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;