mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 13:47:58 +03:00
1057 lines
27 KiB
C++
1057 lines
27 KiB
C++
/*
|
|
===========================================================================
|
|
Copyright (C) 2023 the OpenMoHAA team
|
|
|
|
This file is part of OpenMoHAA source code.
|
|
|
|
OpenMoHAA source code is free software; you can redistribute it
|
|
and/or modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the License,
|
|
or (at your option) any later version.
|
|
|
|
OpenMoHAA source code is distributed in the hope that it will be
|
|
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with OpenMoHAA source code; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
===========================================================================
|
|
*/
|
|
|
|
#include "cl_ui.h"
|
|
#include "../qcommon/tiki.h"
|
|
|
|
static inventory_t s_processed_inv;
|
|
static SafePtr<FakkInventory> s_main_inv;
|
|
|
|
Event FakkInventory_Timeout("_timeout", EV_DEFAULT, NULL, NULL, "Timeout of the menu from inactivity");
|
|
|
|
CLASS_DECLARATION(UIWidget, FakkInventory, NULL) {
|
|
{&W_MouseMoved, &FakkInventory::OnMouseMove },
|
|
{&W_MouseEntered, &FakkInventory::OnMouseEnter},
|
|
{&W_MouseExited, &FakkInventory::OnMouseLeave},
|
|
{&W_LeftMouseDown, &FakkInventory::OnMouseDown },
|
|
{&W_RightMouseDown, &FakkInventory::OnMouseDown },
|
|
{&FakkInventory_Timeout, &FakkInventory::Timeout },
|
|
{NULL, NULL }
|
|
};
|
|
|
|
CLASS_DECLARATION(UIWidget, FakkItemList, NULL) {
|
|
{&W_LeftMouseDown, &FakkItemList::OnLeftMouseDown },
|
|
{&W_RightMouseDown, &FakkItemList::OnRightMouseDown},
|
|
{&W_LeftMouseUp, &FakkItemList::OnLeftMouseUp },
|
|
{&W_RightMouseUp, &FakkItemList::OnRightMouseUp },
|
|
{&W_MouseMoved, &FakkItemList::OnMouseMove },
|
|
{&W_MouseEntered, &FakkItemList::OnMouseEnter },
|
|
{&W_MouseExited, &FakkItemList::OnMouseLeave },
|
|
{&W_Destroyed, &FakkItemList::OnMenuKilled },
|
|
{NULL, NULL }
|
|
};
|
|
|
|
void CL_Draw3DModel(
|
|
float x,
|
|
float y,
|
|
float w,
|
|
float h,
|
|
qhandle_t model,
|
|
vec3_t origin,
|
|
vec3_t rotateoffset,
|
|
vec3_t offset,
|
|
vec3_t angle,
|
|
vec3_t color,
|
|
str anim
|
|
)
|
|
{
|
|
refdef_t inv_refdef {};
|
|
refEntity_t ent {};
|
|
vec3_t unprojoffset;
|
|
vec3_t entaxis[3];
|
|
|
|
inv_refdef.fov_x = 30;
|
|
inv_refdef.fov_y = 30;
|
|
inv_refdef.x = x;
|
|
inv_refdef.y = y;
|
|
inv_refdef.width = w;
|
|
inv_refdef.rdflags = RDF_HUD | RDF_NOWORLDMODEL;
|
|
inv_refdef.height = h;
|
|
inv_refdef.time = cl.serverTime;
|
|
re.ClearScene();
|
|
|
|
AnglesToAxis(angle, entaxis);
|
|
|
|
MatrixTransformVector(rotateoffset, entaxis, unprojoffset);
|
|
|
|
ent.scale = 1.0;
|
|
ent.hModel = model;
|
|
ent.entityNumber = 1023;
|
|
VectorAdd(origin, offset, ent.origin);
|
|
VectorAdd(ent.origin, unprojoffset, ent.origin);
|
|
|
|
ent.tiki = re.R_Model_GetHandle(model);
|
|
if (!ent.tiki) {
|
|
return;
|
|
}
|
|
|
|
if (anim.length()) {
|
|
static qboolean bInited = false;
|
|
static int hModel[8];
|
|
static int iUpdateTime[8];
|
|
static int iIndex[8];
|
|
static float fAnimTime[8];
|
|
static char szAnimName[8][256];
|
|
int i;
|
|
int iCurrNum;
|
|
|
|
if (!bInited) {
|
|
for (i = 0; i < ARRAY_LEN(hModel); i++) {
|
|
iUpdateTime[i] = 0;
|
|
iIndex[i] = -1;
|
|
hModel[i] = -1;
|
|
}
|
|
bInited = true;
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_LEN(hModel); i++) {
|
|
if (hModel[i] == model) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == ARRAY_LEN(hModel)) {
|
|
iCurrNum = 0;
|
|
|
|
// Find a free slot
|
|
for (i = 0; i < ARRAY_LEN(hModel); i++) {
|
|
if (hModel[i] == -1) {
|
|
iCurrNum = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == ARRAY_LEN(hModel)) {
|
|
int iOldestNum, iOldestTime;
|
|
|
|
iOldestTime = iUpdateTime[0];
|
|
iOldestNum = 0;
|
|
|
|
for (i = 1; i < ARRAY_LEN(hModel); i++) {
|
|
if (iUpdateTime[i] < iOldestTime) {
|
|
iOldestNum = i;
|
|
iOldestTime = iUpdateTime[i];
|
|
}
|
|
}
|
|
|
|
iCurrNum = iOldestNum;
|
|
}
|
|
|
|
hModel[iCurrNum] = model;
|
|
iIndex[iCurrNum] = -1;
|
|
Q_strncpyz(szAnimName[iCurrNum], anim, sizeof(szAnimName[iCurrNum]));
|
|
} else {
|
|
iCurrNum = i;
|
|
|
|
if (!Q_stricmp(szAnimName[iCurrNum], anim)) {
|
|
fAnimTime[iCurrNum] += (cls.realtime - iUpdateTime[i]) * 0.001f;
|
|
iUpdateTime[iCurrNum] = cls.realtime;
|
|
|
|
if (TIKI_Anim_Time(ent.tiki, iIndex[iCurrNum]) < fAnimTime[iCurrNum]) {
|
|
// Added in 2.0
|
|
// Clear tunak easter egg
|
|
Cvar_Set("tunak", "0");
|
|
iIndex[iCurrNum] = -1;
|
|
}
|
|
} else {
|
|
iIndex[iCurrNum] = -1;
|
|
Q_strncpyz(szAnimName[iCurrNum], anim, sizeof(szAnimName[iCurrNum]));
|
|
}
|
|
}
|
|
|
|
if (iIndex[iCurrNum] == -1) {
|
|
iIndex[iCurrNum] = TIKI_Anim_NumForName(ent.tiki, szAnimName[iCurrNum]);
|
|
fAnimTime[iCurrNum] = 0;
|
|
iUpdateTime[iCurrNum] = cls.realtime;
|
|
}
|
|
|
|
ent.frameInfo[0].index = iIndex[iCurrNum];
|
|
ent.frameInfo[0].time = fAnimTime[iCurrNum];
|
|
ent.frameInfo[0].weight = 1.f;
|
|
ent.actionWeight = 1.f;
|
|
}
|
|
|
|
ent.shaderRGBA[0] = color[0] * 255;
|
|
ent.shaderRGBA[1] = color[1] * 255;
|
|
ent.shaderRGBA[2] = color[2] * 255;
|
|
ent.shaderRGBA[3] = color[3] * 255;
|
|
|
|
if (cge) {
|
|
vec3_t vViewAngles;
|
|
|
|
cge->CG_EyePosition(&inv_refdef.vieworg);
|
|
cge->CG_EyeAngles(&vViewAngles);
|
|
AnglesToAxis(vViewAngles, inv_refdef.viewaxis);
|
|
|
|
VectorCopy(ent.origin, unprojoffset);
|
|
MatrixTransformVector(unprojoffset, inv_refdef.viewaxis, ent.origin);
|
|
MatrixMultiply(entaxis, inv_refdef.viewaxis, ent.axis);
|
|
VectorAdd(ent.origin, inv_refdef.vieworg, ent.origin);
|
|
} else {
|
|
AnglesToAxis(angle, ent.axis);
|
|
AxisClear(inv_refdef.viewaxis);
|
|
}
|
|
|
|
re.AddRefEntityToScene(&ent, ENTITYNUM_NONE);
|
|
re.RenderScene(&inv_refdef);
|
|
}
|
|
|
|
bool CL_DoIHaveThisItem(const char *name)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
static void ProcessType(inventory_type_t *type)
|
|
{
|
|
for (int i = 1; i < type->items.NumObjects(); i++) {
|
|
const inventory_item_t *item = type->items.ObjectAt(i);
|
|
|
|
if (!CL_DoIHaveThisItem(item->name)) {
|
|
type->items.RemoveObjectAt(i--);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ProcessInventory()
|
|
{
|
|
for (int i = 1; i <= s_processed_inv.types.NumObjects(); i++) {
|
|
inventory_type_t *type = s_processed_inv.types.ObjectAt(i);
|
|
|
|
ProcessType(type);
|
|
if (!type->items.NumObjects()) {
|
|
delete type;
|
|
s_processed_inv.types.RemoveObjectAt(i--);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UI_NextInventory()
|
|
{
|
|
UI_DoInventory(false);
|
|
|
|
if (s_main_inv) {
|
|
s_main_inv->WarpTo(1);
|
|
s_main_inv->NextItem();
|
|
}
|
|
}
|
|
|
|
void UI_PrevInventory()
|
|
{
|
|
UI_DoInventory(false);
|
|
|
|
if (s_main_inv) {
|
|
s_main_inv->WarpTo(1);
|
|
s_main_inv->PrevItem();
|
|
}
|
|
}
|
|
|
|
void UI_WarpInventory()
|
|
{
|
|
UI_DoInventory(0);
|
|
|
|
if (Cmd_Argc() != 2) {
|
|
Com_Printf("Usage: warpinv <slot_name>");
|
|
}
|
|
|
|
if (s_main_inv) {
|
|
s_main_inv->WarpTo(Cmd_Argv(1));
|
|
}
|
|
}
|
|
|
|
void UI_DoInventory_f()
|
|
{
|
|
UI_DoInventory(1);
|
|
|
|
if (s_main_inv) {
|
|
s_main_inv->WarpTo(1);
|
|
}
|
|
}
|
|
|
|
void UI_DoInventory(qboolean activate_mouse)
|
|
{
|
|
if ((cl.snap.ps.stats[STAT_CINEMATIC] & 1) || s_main_inv) {
|
|
return;
|
|
}
|
|
|
|
ProcessInventory();
|
|
|
|
if (!s_processed_inv.types.NumObjects()) {
|
|
UI_UpdateCenterPrint("- No inventory -", 1);
|
|
return;
|
|
}
|
|
|
|
s_main_inv = new FakkInventory();
|
|
s_main_inv->setInventory(&s_processed_inv);
|
|
|
|
if (client_inv.align == INV_ALIGN_RIGHT) {
|
|
s_main_inv->InitFrame(
|
|
NULL,
|
|
client_inv.horizoffset + uid.vidWidth - client_inv.typewidth,
|
|
client_inv.vertoffset,
|
|
client_inv.typewidth,
|
|
client_inv.typeheight * client_inv.types.NumObjects(),
|
|
0
|
|
);
|
|
} else if (client_inv.align == INV_ALIGN_LEFT) {
|
|
s_main_inv->InitFrame(
|
|
NULL,
|
|
client_inv.horizoffset,
|
|
client_inv.vertoffset,
|
|
client_inv.typewidth,
|
|
client_inv.typeheight * client_inv.types.NumObjects(),
|
|
0
|
|
);
|
|
}
|
|
|
|
uWinMan.ActivateControl(s_main_inv);
|
|
|
|
if (activate_mouse) {
|
|
IN_MouseOn();
|
|
}
|
|
|
|
s_main_inv->m_mouse_active = true;
|
|
}
|
|
|
|
qboolean UI_CloseInventory()
|
|
{
|
|
menuManager.PassEventToAllWidgets(EV_ClearInvItemReference);
|
|
|
|
if (!s_main_inv || s_main_inv->isDying()) {
|
|
return false;
|
|
}
|
|
|
|
delete s_main_inv;
|
|
|
|
UI_FocusMenuIfExists();
|
|
return true;
|
|
}
|
|
|
|
FakkInventory::FakkInventory()
|
|
{
|
|
m_currenttype = NULL;
|
|
AllowActivate(false);
|
|
UIWidget::setBackgroundColor(UColor(), true);
|
|
}
|
|
|
|
FakkInventory::~FakkInventory()
|
|
{
|
|
if (!uWinMan.IsDead()) {
|
|
VerifyTypeUp(NULL, false);
|
|
}
|
|
}
|
|
|
|
int FakkInventory::FindFirstItem(int itemindex, int sign)
|
|
{
|
|
int i;
|
|
|
|
for (i = itemindex; i > 0 && i <= m_currenttype->items.NumObjects(); i += sign) {
|
|
const inventory_item_t *item = m_currenttype->items.ObjectAt(i);
|
|
|
|
if (CL_HasInventoryItem(item->name)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
void FakkInventory::ChangeItem(int sign)
|
|
{
|
|
int itemindex;
|
|
int groupindex;
|
|
inventory_item_t *selitem;
|
|
|
|
if (!m_currenttype && !m_currentlist) {
|
|
WarpTo(1);
|
|
}
|
|
|
|
itemindex = m_currenttype->IndexOfItemPtr(m_currentlist->getHoverItem());
|
|
if (itemindex) {
|
|
itemindex = FindFirstItem(itemindex + sign, sign);
|
|
if (itemindex <= 0 || itemindex > m_currenttype->items.NumObjects()) {
|
|
groupindex = m_inv->types.IndexOfObject(m_currenttype);
|
|
if (groupindex) {
|
|
groupindex += sign;
|
|
if (groupindex > m_inv->types.NumObjects()) {
|
|
groupindex = 1;
|
|
} else if (groupindex < 1) {
|
|
groupindex = m_inv->types.NumObjects();
|
|
}
|
|
|
|
VerifyTypeUp(m_inv->types.ObjectAt(groupindex), false);
|
|
|
|
if (sign > 0) {
|
|
itemindex = FindFirstItem(1, sign);
|
|
} else {
|
|
itemindex = FindFirstItem(m_inv->types.ObjectAt(groupindex)->items.NumObjects(), sign);
|
|
}
|
|
|
|
if (itemindex > m_inv->types.ObjectAt(groupindex)->items.NumObjects()) {
|
|
itemindex = 1;
|
|
}
|
|
} else {
|
|
VerifyTypeUp(m_inv->types.ObjectAt(1), false);
|
|
itemindex = FindFirstItem(1, sign);
|
|
}
|
|
}
|
|
} else {
|
|
itemindex = 1;
|
|
}
|
|
|
|
selitem = m_currenttype->items.ObjectAt(itemindex);
|
|
return m_currentlist->VerifyItemUp(selitem, false);
|
|
}
|
|
|
|
void FakkInventory::NextItem(void)
|
|
{
|
|
ChangeItem(1);
|
|
}
|
|
|
|
void FakkInventory::PrevItem(void)
|
|
{
|
|
ChangeItem(-1);
|
|
}
|
|
|
|
void FakkInventory::Timeout(Event *ev)
|
|
{
|
|
UI_CloseInventory();
|
|
}
|
|
|
|
void FakkInventory::PlaySound(invsound_t type)
|
|
{
|
|
switch (type) {
|
|
case invsound_t::selectsound:
|
|
S_StartLocalSound(m_inv->selectsound, qfalse);
|
|
break;
|
|
case invsound_t::rejectsound:
|
|
S_StartLocalSound(m_inv->rejectsound, qfalse);
|
|
break;
|
|
case invsound_t::changesound:
|
|
S_StartLocalSound(m_inv->changesound, qfalse);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void FakkInventory::Draw(void)
|
|
{
|
|
int i;
|
|
bool mouse_in;
|
|
UIPoint2D clientPoint;
|
|
|
|
if (!m_inv) {
|
|
return;
|
|
}
|
|
|
|
clientPoint = UIPoint2D(uid.mouseX, uid.mouseY);
|
|
mouse_in = uWinMan.FindResponder(clientPoint) == this;
|
|
clientPoint = getLocalPoint(clientPoint);
|
|
|
|
for (i = 1; i <= m_inv->types.NumObjects(); i++) {
|
|
inventory_type_t *type;
|
|
float top;
|
|
UIReggedMaterial *torender;
|
|
|
|
type = m_inv->types.ObjectAt(i);
|
|
top = m_inv->typeheight * (i - 1);
|
|
if (type == m_currenttype) {
|
|
if (mouse_in) {
|
|
torender = type->hoverTexture;
|
|
} else {
|
|
torender = type->selTexture;
|
|
}
|
|
} else {
|
|
torender = type->texture;
|
|
}
|
|
|
|
if (torender) {
|
|
uii.Rend_DrawPicStretched(
|
|
0, top, m_inv->typewidth, m_inv->typeheight, 0, 0, 1.f, 1.f, torender->GetMaterial()
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FakkInventory::OnMouseDown(Event *ev)
|
|
{
|
|
inventory_type_t *oldtype;
|
|
UIPoint2D p;
|
|
int i;
|
|
|
|
p = MouseEventToClientPoint(ev);
|
|
i = (int)(p.y / m_inv->typeheight);
|
|
|
|
if (i + 1 > m_inv->types.NumObjects()) {
|
|
return;
|
|
}
|
|
|
|
oldtype = m_currenttype;
|
|
VerifyTypeUp(m_inv->types.ObjectAt(i + 1), true);
|
|
|
|
if (m_currentlist && m_currenttype == oldtype) {
|
|
m_currentlist->VerifyItemUp(m_currenttype->items.ObjectAt(1), true);
|
|
}
|
|
}
|
|
|
|
void FakkInventory::OnMouseMove(Event *ev) {}
|
|
|
|
void FakkInventory::OnMouseLeave(Event *ev) {}
|
|
|
|
void FakkInventory::OnMouseEnter(Event *ev)
|
|
{
|
|
SetHovermaterialActive(true);
|
|
}
|
|
|
|
void FakkInventory::VerifyTypeUp(inventory_type_t *t, qboolean warpmouse)
|
|
{
|
|
CancelEventsOfType(FakkInventory_Timeout);
|
|
PostEvent(new Event(FakkInventory_Timeout), 5);
|
|
|
|
if (m_currenttype != t) {
|
|
if (m_currenttype) {
|
|
delete m_currenttype;
|
|
}
|
|
|
|
m_currenttype = t;
|
|
if (t) {
|
|
m_currentlist = new FakkItemList();
|
|
m_currentlist->setType(m_currenttype);
|
|
|
|
switch (m_inv->cascade) {
|
|
case INV_CASCADE_LEFT:
|
|
m_currentlist->Create(m_screenframe.pos.x, m_screenframe.pos.y, this);
|
|
break;
|
|
case INV_CASCADE_RIGHT:
|
|
m_currentlist->Create(m_screenframe.pos.x + m_screenframe.size.width, m_screenframe.pos.y, this);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (m_currenttype) {
|
|
PlaySound(invsound_t::changesound);
|
|
}
|
|
}
|
|
|
|
if (warpmouse && m_currentlist) {
|
|
int i;
|
|
int height = 0;
|
|
|
|
for (i = 1; i <= m_inv->types.NumObjects() && m_inv->types.ObjectAt(i) != t; i++) {
|
|
height += m_inv->typeheight;
|
|
}
|
|
|
|
CL_SetMousePos(
|
|
(int)((m_inv->typewidth / 2) + m_screenframe.pos.x),
|
|
(int)((m_inv->typeheight / 2 + height) + m_screenframe.pos.y)
|
|
);
|
|
}
|
|
}
|
|
|
|
void FakkInventory::WarpTo(int slotnum)
|
|
{
|
|
int i;
|
|
|
|
for (i = slotnum; i > 0 && i <= m_inv->types.NumObjects(); i++) {
|
|
inventory_type_t *t = m_inv->types.ObjectAt(i);
|
|
if (t) {
|
|
VerifyTypeUp(t, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FakkInventory::WarpTo(const char *name)
|
|
{
|
|
int i;
|
|
int count;
|
|
|
|
count = m_inv->types.NumObjects();
|
|
for (i = 1; i <= count; i++) {
|
|
inventory_type_t *t = m_inv->types.ObjectAt(i);
|
|
|
|
if (name && str::icmp(t->name, name)) {
|
|
continue;
|
|
}
|
|
|
|
VerifyTypeUp(t, true);
|
|
if (name && m_currentlist && m_currenttype) {
|
|
m_currentlist->VerifyItemUp(m_currenttype->items.ObjectAt(1), true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FakkInventory::setInventory(inventory_t *i)
|
|
{
|
|
m_inv = i;
|
|
}
|
|
|
|
qboolean FakkInventory::KeyEvent(int key, unsigned int time)
|
|
{
|
|
char bind[1024];
|
|
const char *cmd;
|
|
const char *name;
|
|
int index;
|
|
bool actionitemlist;
|
|
str command;
|
|
|
|
if (cl.snap.ps.stats[STAT_CINEMATIC] & 1) {
|
|
UI_CloseInventory();
|
|
return false;
|
|
}
|
|
|
|
if (!m_inv->types.NumObjects()) {
|
|
return true;
|
|
}
|
|
|
|
actionitemlist = m_currenttype && m_currentlist && m_currentlist->getHoverItem() != NULL;
|
|
|
|
cmd = Key_GetBinding(key);
|
|
if (cmd) {
|
|
Q_strncpyz(bind, cmd, sizeof(bind));
|
|
} else {
|
|
bind[0] = 0;
|
|
}
|
|
|
|
if (bind[0]) {
|
|
name = strtok(bind, " ");
|
|
if (!str::icmp(name, "+attackleft")) {
|
|
command = "attackleft";
|
|
} else if (!str::icmp(name, "+attackright")) {
|
|
command = "attackright";
|
|
} else if (!str::icmp(name, "warpinv")) {
|
|
name = strtok(NULL, " ");
|
|
} else {
|
|
if (!str::icmp(name, "inventory")) {
|
|
UI_CloseInventory();
|
|
return qtrue;
|
|
} else if (!str::icmp(name, "nextinv")) {
|
|
NextItem();
|
|
return true;
|
|
} else if (!str::icmp(name, "previnv")) {
|
|
PrevItem();
|
|
return true;
|
|
}
|
|
name = NULL;
|
|
}
|
|
}
|
|
|
|
if (actionitemlist) {
|
|
if (m_mouse_active && (key == K_UPARROW || key == K_DOWNARROW) || (key == K_MWHEELUP || key == K_MWHEELDOWN)
|
|
|| (name && !str::icmp(name, m_currenttype->name))) {
|
|
inventory_item_t *hoverItem = m_currentlist->getHoverItem();
|
|
|
|
if (m_currenttype->items.NumObjects()) {
|
|
index = m_currenttype->IndexOfItemPtr(hoverItem);
|
|
|
|
if (!index) {
|
|
index = 1;
|
|
} else if (key == K_UPARROW || key == K_MWHEELUP) {
|
|
index--;
|
|
if (index < 1) {
|
|
index = m_currenttype->items.NumObjects();
|
|
}
|
|
} else {
|
|
index++;
|
|
if (index > m_currenttype->items.NumObjects()) {
|
|
index = 1;
|
|
}
|
|
}
|
|
|
|
m_currentlist->VerifyItemUp(m_currenttype->items.ObjectAt(index), true);
|
|
return true;
|
|
}
|
|
} else {
|
|
if (command.length()) {
|
|
if (!str::icmp(command, "attackleft")) {
|
|
if (m_currentlist) {
|
|
m_currentlist->OnLeftMouseDown(NULL);
|
|
}
|
|
} else if (!str::icmp(command, "attackright")) {
|
|
if (m_currentlist) {
|
|
m_currentlist->OnRightMouseDown(NULL);
|
|
}
|
|
}
|
|
|
|
PostponeEvent(FakkInventory_Timeout, 5.f);
|
|
return true;
|
|
}
|
|
|
|
if (name) {
|
|
WarpTo(name);
|
|
PostponeEvent(FakkInventory_Timeout, 5.f);
|
|
return true;
|
|
}
|
|
|
|
CL_Key_ForceCommand(key, time);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (m_mouse_active && (key == K_UPARROW || key == K_DOWNARROW) || (key == K_MWHEELUP || key == K_MWHEELDOWN)) {
|
|
index = m_inv->types.IndexOfObject(m_currenttype);
|
|
if (!index) {
|
|
index = 1;
|
|
} else if (key == K_UPARROW || key == K_MWHEELUP) {
|
|
index--;
|
|
if (index < 1) {
|
|
index = m_inv->types.NumObjects();
|
|
}
|
|
} else {
|
|
index++;
|
|
if (index > m_inv->types.NumObjects()) {
|
|
index = 1;
|
|
}
|
|
}
|
|
|
|
VerifyTypeUp(m_inv->types.ObjectAt(index), true);
|
|
return qtrue;
|
|
}
|
|
|
|
if (m_mouse_active && (key == K_RIGHTARROW || key == K_LEFTARROW)) {
|
|
if (!m_currenttype || !m_currentlist) {
|
|
return qtrue;
|
|
}
|
|
|
|
if ((m_inv->cascade == INV_CASCADE_LEFT && key == K_LEFTARROW)
|
|
|| (m_inv->cascade == INV_CASCADE_RIGHT && key == K_RIGHTARROW)) {
|
|
m_currentlist->VerifyItemUp(m_currenttype->items.ObjectAt(1), true);
|
|
return qtrue;
|
|
}
|
|
|
|
PostponeEvent(FakkInventory_Timeout, 5.f);
|
|
return true;
|
|
}
|
|
|
|
if (!name) {
|
|
PostponeEvent(FakkInventory_Timeout, 5.f);
|
|
return true;
|
|
}
|
|
|
|
WarpTo(name);
|
|
PostponeEvent(FakkInventory_Timeout, 5.f);
|
|
return true;
|
|
}
|
|
|
|
qboolean FakkInventory::isDying(void)
|
|
{
|
|
return m_dying;
|
|
}
|
|
|
|
FakkItemList::FakkItemList()
|
|
{
|
|
m_hoveritem = NULL;
|
|
m_lastmenuitem = NULL;
|
|
m_parent = NULL;
|
|
UIWidget::setBackgroundColor(UColor(), true);
|
|
}
|
|
|
|
FakkItemList::~FakkItemList() {}
|
|
|
|
void FakkItemList::Create(float x, float y, FakkInventory *parent)
|
|
{
|
|
UIRect2D rect;
|
|
int i;
|
|
float maxWidth = 0;
|
|
|
|
for (i = 1; i <= type->items.NumObjects(); i++) {
|
|
inventory_item_t *item = type->items.ObjectAt(i);
|
|
if (maxWidth <= item->width) {
|
|
maxWidth = item->width;
|
|
}
|
|
|
|
rect.size.height += item->height;
|
|
}
|
|
|
|
if (client_inv.cascade == INV_CASCADE_RIGHT) {
|
|
rect.pos.x = x;
|
|
rect.pos.y = y;
|
|
rect.size.width = maxWidth;
|
|
|
|
InitFrame(NULL, rect, 0);
|
|
} else if (client_inv.cascade == INV_CASCADE_LEFT) {
|
|
rect.pos.x = x - maxWidth;
|
|
rect.pos.y = y;
|
|
rect.size.width = maxWidth;
|
|
|
|
InitFrame(NULL, rect, 0);
|
|
}
|
|
|
|
Com_DPrintf("FakkItemList::Create : Invalid cascade for inventory list\n");
|
|
if (parent) {
|
|
m_parent = parent;
|
|
}
|
|
}
|
|
|
|
bool FakkItemList::HasAnyItems(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 1; i <= type->items.NumObjects(); i++) {
|
|
inventory_item_t *item = type->items.ObjectAt(i);
|
|
|
|
if (CL_HasInventoryItem(item->name)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void FakkItemList::Draw(void) {}
|
|
|
|
void FakkItemList::OnMouseEnter(Event *ev)
|
|
{
|
|
SetHovermaterialActive(true);
|
|
}
|
|
|
|
void FakkItemList::OnLeftMouseDown(Event *ev)
|
|
{
|
|
char bind[1024];
|
|
const char *cmd;
|
|
const char *name;
|
|
|
|
if ((cl.snap.ps.stats[STAT_CINEMATIC] & 1)) {
|
|
return;
|
|
}
|
|
|
|
if (m_parent) {
|
|
m_parent->CancelEventsOfType(FakkInventory_Timeout);
|
|
m_parent->PostEvent(new Event(FakkInventory_Timeout), 5);
|
|
}
|
|
|
|
if (ev) {
|
|
cmd = Key_GetBinding(K_MOUSE1);
|
|
if (cmd) {
|
|
Q_strncpyz(bind, cmd, sizeof(bind));
|
|
} else {
|
|
bind[0] = 0;
|
|
}
|
|
|
|
if (bind[0]) {
|
|
name = strtok(bind, " ");
|
|
if (str::icmp(name, "+attackleft")) {
|
|
if (!str::icmp(name, "+attackright")) {
|
|
OnRightMouseDown(NULL);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!CL_HasInventoryItem(m_lastmenuitem->name) || (m_lastmenuitem->equip & 16)) {
|
|
if (m_parent) {
|
|
m_parent->PlaySound(invsound_t::rejectsound);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (m_lastmenuitem->checkammo) {
|
|
int count;
|
|
int max;
|
|
|
|
CL_AmmoCount(m_lastmenuitem->ammoname, &count, &max);
|
|
|
|
if (!count) {
|
|
if (m_parent) {
|
|
m_parent->PlaySound(invsound_t::rejectsound);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (m_lastmenuitem->command.length()) {
|
|
uii.Cmd_Stuff(va("%s\n", m_lastmenuitem->command.c_str()));
|
|
} else if (m_lastmenuitem->equip & 4) {
|
|
uii.Cmd_Stuff(va("use \"%s\" dualhand\n", m_lastmenuitem->name.c_str()));
|
|
} else if (m_lastmenuitem->equip & 1) {
|
|
uii.Cmd_Stuff(va("use \"%s\" lefthand\n", m_lastmenuitem->name.c_str()));
|
|
} else if (m_lastmenuitem->equip & 8) {
|
|
uii.Cmd_Stuff(va("use \"%s\"\n", m_lastmenuitem->name.c_str()));
|
|
} else {
|
|
if (m_parent) {
|
|
m_parent->PlaySound(invsound_t::rejectsound);
|
|
}
|
|
}
|
|
|
|
if (m_parent) {
|
|
m_parent->PlaySound(invsound_t::selectsound);
|
|
}
|
|
|
|
if (m_parent && !m_parent->m_mouse_active) {
|
|
UI_CloseInventory();
|
|
}
|
|
}
|
|
|
|
void FakkItemList::OnRightMouseDown(Event *ev)
|
|
{
|
|
char bind[1024];
|
|
const char *cmd;
|
|
const char *name;
|
|
|
|
if ((cl.snap.ps.stats[STAT_CINEMATIC] & 1)) {
|
|
return;
|
|
}
|
|
|
|
if (m_parent) {
|
|
m_parent->CancelEventsOfType(FakkInventory_Timeout);
|
|
m_parent->PostEvent(new Event(FakkInventory_Timeout), 5);
|
|
}
|
|
|
|
if (ev) {
|
|
cmd = Key_GetBinding(K_MOUSE2);
|
|
if (cmd) {
|
|
Q_strncpyz(bind, cmd, sizeof(bind));
|
|
} else {
|
|
bind[0] = 0;
|
|
}
|
|
|
|
if (bind[0]) {
|
|
name = strtok(bind, " ");
|
|
if (str::icmp(name, "+attackright")) {
|
|
if (!str::icmp(name, "+attackleft")) {
|
|
OnLeftMouseDown(NULL);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!CL_HasInventoryItem(m_lastmenuitem->name) || (m_lastmenuitem->equip & 16)) {
|
|
if (m_parent) {
|
|
m_parent->PlaySound(invsound_t::rejectsound);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (m_lastmenuitem->checkammo) {
|
|
int count;
|
|
int max;
|
|
|
|
CL_AmmoCount(m_lastmenuitem->ammoname, &count, &max);
|
|
|
|
if (!count) {
|
|
if (m_parent) {
|
|
m_parent->PlaySound(invsound_t::rejectsound);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (m_lastmenuitem->command.length()) {
|
|
uii.Cmd_Stuff(va("%s\n", m_lastmenuitem->command.c_str()));
|
|
} else if (m_lastmenuitem->equip & 4) {
|
|
uii.Cmd_Stuff(va("use \"%s\" dualhand\n", m_lastmenuitem->name.c_str()));
|
|
} else if (m_lastmenuitem->equip & 1) {
|
|
uii.Cmd_Stuff(va("use \"%s\" righthand\n", m_lastmenuitem->name.c_str()));
|
|
} else if (m_lastmenuitem->equip & 8) {
|
|
uii.Cmd_Stuff(va("use \"%s\"\n", m_lastmenuitem->name.c_str()));
|
|
} else {
|
|
if (m_parent) {
|
|
m_parent->PlaySound(invsound_t::rejectsound);
|
|
}
|
|
}
|
|
|
|
if (m_parent) {
|
|
m_parent->PlaySound(invsound_t::selectsound);
|
|
}
|
|
|
|
if (m_parent && !m_parent->m_mouse_active) {
|
|
UI_CloseInventory();
|
|
}
|
|
}
|
|
|
|
void FakkItemList::OnLeftMouseUp(Event *ev) {}
|
|
|
|
void FakkItemList::OnRightMouseUp(Event *ev) {}
|
|
|
|
void FakkItemList::OnMouseLeave(Event *ev) {}
|
|
|
|
void FakkItemList::VerifyItemUp(inventory_item_t *item, qboolean warpmouse)
|
|
{
|
|
int i;
|
|
int height = 0;
|
|
inventory_item_t *ii = NULL;
|
|
|
|
if (m_parent) {
|
|
m_parent->CancelEventsOfType(FakkInventory_Timeout);
|
|
m_parent->PostEvent(new Event(FakkInventory_Timeout), 5);
|
|
}
|
|
|
|
m_hoveritem = item;
|
|
m_lastmenuitem = item;
|
|
|
|
if (m_parent) {
|
|
m_parent->PlaySound(changesound);
|
|
}
|
|
|
|
if (warpmouse) {
|
|
for (i = 1; i <= type->items.NumObjects(); i++) {
|
|
ii = type->items.ObjectAt(i);
|
|
if (ii == item) {
|
|
break;
|
|
}
|
|
|
|
height += ii->height;
|
|
}
|
|
|
|
if (ii) {
|
|
CL_SetMousePos(
|
|
(int)((ii->width / 2) + m_screenframe.pos.x), (int)((ii->height / 2 + height) + m_screenframe.pos.y)
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FakkItemList::OnMouseMove(Event *ev)
|
|
{
|
|
int i;
|
|
float top;
|
|
inventory_item_t *newitem;
|
|
UIPoint2D p;
|
|
|
|
top = 0;
|
|
newitem = NULL;
|
|
p = MouseEventToClientPoint(ev);
|
|
|
|
for (i = 1; i <= type->items.NumObjects(); i++) {
|
|
inventory_item_t *item = type->items.ObjectAt(i);
|
|
if (p.x >= 0 && item->width > p.x && p.y >= top && item->height + top > p.y) {
|
|
newitem = item;
|
|
break;
|
|
}
|
|
|
|
top += item->height;
|
|
}
|
|
|
|
if (newitem != m_hoveritem) {
|
|
VerifyItemUp(newitem, false);
|
|
}
|
|
}
|
|
|
|
void FakkItemList::OnMenuKilled(Event *ev)
|
|
{
|
|
VerifyItemUp(NULL, false);
|
|
}
|
|
|
|
void FakkItemList::setType(inventory_type_t *t)
|
|
{
|
|
type = t;
|
|
}
|
|
|
|
void FakkItemList::EquipItem(Event *ev) {}
|
|
|
|
inventory_item_t *FakkItemList::getHoverItem() const
|
|
{
|
|
return m_hoveritem;
|
|
}
|