/*
Copyright (C) 2011 azazello and ezQuake team
This program 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.
This program 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 this program. If not, see .
*/
//
// HUD commands
//
#include "ezquakeisms.h"
//#include "common_draw.h"
//#include "keys.h"
#include "hud.h"
#include "hud_common.h"
#include "hud_editor.h"
//#include "utils.h"
//#include "sbar.h"
#define sbar_last_width 320 // yeah yeah I know, *garbage* -> leave it be :>
char *align_strings_x[] = {
"left",
"center",
"right",
"before",
"after"
};
#define num_align_strings_x (sizeof(align_strings_x) / sizeof(align_strings_x[0]))
char *align_strings_y[] = {
"top",
"center",
"bottom",
"before",
"after",
"console"
};
#define num_align_strings_y (sizeof(align_strings_y) / sizeof(align_strings_y[0]))
char *snap_strings[] = {
"screen",
"top",
"view",
"sbar",
"ibar",
"hbar",
"sfree",
"ifree",
"hfree",
};
#define num_snap_strings (sizeof(snap_strings) / sizeof(snap_strings[0]))
// Hud elements list.
hud_t *hud_huds = NULL;
qbool doreorder;
//
// Hud plus func - show element.
//
void HUD_Plus_f(void)
{
char *t;
hud_t *hud;
if (Cmd_Argc() < 1)
return;
t = Cmd_Argv(0);
if (strncmp(t, "+hud_", 5))
return;
hud = HUD_Find(t + 5);
if (!hud)
{
// This should never happen...
return;
}
if (!hud->show)
{
// This should never happen...
return;
}
Cvar_Set(hud->show, "1");
}
//
// Hud minus func - hide element.
//
void HUD_Minus_f(void)
{
char *t;
hud_t *hud;
if (Cmd_Argc() < 1)
return;
t = Cmd_Argv(0);
if (strncmp(t, "-hud_", 5))
return;
hud = HUD_Find(t + 5);
if (!hud)
{
// this should never happen...
return;
}
if (!hud->show)
{
// this should never happen...
return;
}
Cvar_Set(hud->show, "0");
}
//
// Hud element func - describe it
// this also solves the TAB completion problem
//
void HUD_Func_f(void)
{
int i;
hud_t *hud;
hud = HUD_Find(Cmd_Argv(0));
if (!hud)
{
// This should never happen...
Com_Printf("Hud element not found\n");
return;
}
if (Cmd_Argc() > 1)
{
char buf[512];
snprintf(buf, sizeof(buf), "hud_%s_%s", hud->name, Cmd_Argv(1));
if (Cvar_Find(buf) != NULL)
{
Cbuf_AddText(buf);
if (Cmd_Argc() > 2)
{
Cbuf_AddText(" ");
Cbuf_AddText(Cmd_Argv(2));
}
Cbuf_AddText("\n");
}
else
{
Com_Printf("Trying \"%s\" - no such variable\n", buf);
}
return;
}
// Description.
Com_Printf("%s\n\n", hud->description);
// Status.
if (hud->show != NULL)
{
Com_Printf("Current status: %s\n", hud->show->value ? "shown" : "hidden");
}
if (hud->frame != NULL)
{
Com_Printf("Frame: %s\n\n", hud->frame->string);
}
if (hud->frame_color != NULL)
{
Com_Printf("Frame color: %s\n\n", hud->frame_color->string);
}
// Placement.
Com_Printf("Placement: %s\n", hud->place->string);
// Alignment.
Com_Printf("Alignment (x y): %s %s\n", hud->align_x->string, hud->align_y->string);
// Position.
Com_Printf("Offset (x y): %d %d\n", (int)(hud->pos_x->value), (int)(hud->pos_y->value));
// Ordering.
Com_Printf("Draw Order (z): %d\n", (int)hud->order->value);
// Additional parameters.
if (hud->num_params > 0)
{
int prefix_l = strlen(va("hud_%s_", hud->name));
Com_Printf("\nParameters:\n");
for (i=0; i < hud->num_params; i++)
{
if (strlen(hud->params[i]->name) > prefix_l)
Com_Printf(" %-15s %s\n", hud->params[i]->name + prefix_l,
hud->params[i]->string);
}
}
}
//
// Find the elements with the max and min z-order.
//
void HUD_FindMaxMinOrder(int *max, int *min)
{
hud_t *hud = hud_huds;
while(hud)
{
(*min) = ((int)hud->order->value < (*min)) ? (int)hud->order->value : (*min);
(*max) = ((int)hud->order->value > (*max)) ? (int)hud->order->value : (*max);
hud = hud->next;
}
}
//
// Find hud placement by string
// return 0 if error
//
int HUD_FindPlace(hud_t *hud)
{
int i;
hud_t *par;
qbool out;
char *t;
// First try standard strings.
for (i=0; i < num_snap_strings; i++)
{
if (!strcasecmp(hud->place->string, snap_strings[i]))
{
break;
}
}
if (i < num_snap_strings)
{
// Found.
hud->place_num = i+1;
hud->place_hud = NULL;
return 1;
}
// then try another HUD element
out = true;
t = hud->place->string;
if (hud->place->string[0] == '@')
{
// place inside
out = false;
t++;
}
par = hud_huds;
while (par)
{
if (par != hud && !strcmp(t, par->name))
{
hud->place_outside = out;
hud->place_hud = par;
hud->place_num = HUD_PLACE_SCREEN;
return 1;
}
par = par->next;
}
// No way.
hud->place_num = HUD_PLACE_SCREEN;
hud->place_hud = NULL;
return 0;
}
//
// Find hud alignment by strings
// return 0 if error
//
int HUD_FindAlignX(hud_t *hud)
{
int i;
// First try standard strings.
for (i=0; i < num_align_strings_x; i++)
{
if (!strcasecmp(hud->align_x->string, align_strings_x[i]))
{
break;
}
}
if (i < num_align_strings_x)
{
// Found.
hud->align_x_num = i+1;
return 1;
}
else
{
// Error.
hud->align_x_num = HUD_ALIGN_LEFT; // left
return 0;
}
}
//
// Find the alignment for a hud element.
//
int HUD_FindAlignY(hud_t *hud)
{
int i;
// First try standard strings.
for (i=0; i < num_align_strings_y; i++)
{
if (!strcasecmp(hud->align_y->string, align_strings_y[i]))
{
break;
}
}
if (i < num_align_strings_y)
{
// Found.
hud->align_y_num = i + 1;
return 1;
}
else
{
// Error.
hud->align_y_num = HUD_ALIGN_TOP; // Left.
return 0;
}
}
int Hud_HudCompare (const void *p1, const void *p2)
{
return strcmp((*((hud_t **) p1))->name, (*((hud_t **) p2))->name);
}
//
// List hud elements
//
void HUD_List (void)
{
static hud_t *sorted_huds[256];
int i, count;
hud_t *hud;
#define MAX_SORTED_HUDS (sizeof (sorted_huds) / sizeof (sorted_huds[0]))
for (hud = hud_huds, count = 0; hud && count < MAX_SORTED_HUDS; hud = hud->next, count++)
sorted_huds[count] = hud;
qsort (sorted_huds, count, sizeof (hud_t *), Hud_HudCompare);
if (count == MAX_SORTED_HUDS)
assert(!"count == MAX_SORTED_HUDS");
Com_Printf("name status\n");
Com_Printf("--------------- ------\n");
for (i = 0; i < count; i++) {
hud = sorted_huds[i];
Com_Printf("%-15s %s\n", hud->name, hud->show->value ? "shown" : "hidden");
}
}
//
// Show the specified hud element.
//
void HUD_Show_f (void)
{
hud_t *hud;
if (Cmd_Argc() != 2)
{
Com_Printf("Usage: show [ | all]\n");
Com_Printf("Show given HUD element.\n");
Com_Printf("use \"show all\" to show all elements.\n");
Com_Printf("Current elements status:\n\n");
HUD_List();
return;
}
if (!strcasecmp(Cmd_Argv(1), "all"))
{
hud = hud_huds;
while (hud)
{
Cvar_SetValue(hud->show, 1);
hud = hud->next;
}
}
else
{
hud = HUD_Find(Cmd_Argv(1));
if (!hud)
{
Com_Printf("No such element: %s\n", Cmd_Argv(1));
return;
}
Cvar_SetValue(hud->show, 1);
}
}
//
// Hide the specified hud element.
//
void HUD_Hide_f (void)
{
hud_t *hud;
if (Cmd_Argc() != 2)
{
Com_Printf("Usage: hide [ | all]\n");
Com_Printf("Hide given HUD element\n");
Com_Printf("use \"hide all\" to hide all elements.\n");
Com_Printf("Current elements status:\n\n");
HUD_List();
return;
}
if (!strcasecmp(Cmd_Argv(1), "all"))
{
hud = hud_huds;
while (hud)
{
Cvar_SetValue(hud->show, 0);
hud = hud->next;
}
}
else
{
hud = HUD_Find(Cmd_Argv(1));
if (!hud)
{
Com_Printf("No such element: %s\n", Cmd_Argv(1));
return;
}
Cvar_SetValue(hud->show, 0);
}
}
//
// Toggles specified hud element.
//
void HUD_Toggle_f (void)
{
hud_t *hud;
if (Cmd_Argc() != 2)
{
Com_Printf("Usage: togglehud | \n");
Com_Printf("Show/hide given HUD element, or toggles variable value.\n");
return;
}
hud = HUD_Find(Cmd_Argv(1));
if (!hud)
{
// look for cvar
cvar_t *var = Cvar_Find(Cmd_Argv(1));
if (!var)
{
Com_Printf("No such element or variable: %s\n", Cmd_Argv(1));
return;
}
Cvar_Set (var, var->value ? "0" : "1");
return;
}
Cvar_Set (hud->show, hud->show->value ? "0" : "1");
}
//
// Move the specified hud element relative to placement/alignment.
//
void HUD_Move_f (void)
{
hud_t *hud;
if (Cmd_Argc() != 4 && Cmd_Argc() != 2)
{
Com_Printf("Usage: move []\n");
Com_Printf("Set offset for given HUD element\n");
return;
}
hud = HUD_Find(Cmd_Argv(1));
if (!hud)
{
Com_Printf("No such element: %s\n", Cmd_Argv(1));
return;
}
if (Cmd_Argc() == 2)
{
Com_Printf("Current %s offset is:\n", Cmd_Argv(1));
Com_Printf(" x: %s\n", hud->pos_x->string);
Com_Printf(" y: %s\n", hud->pos_y->string);
return;
}
Cvar_SetValue(hud->pos_x, atof(Cmd_Argv(2)));
Cvar_SetValue(hud->pos_y, atof(Cmd_Argv(3)));
}
//
// Resets a hud item to the center of the screen.
//
void HUD_Reset_f (void)
{
hud_t *hud = NULL;
char *hudname = NULL;
if (Cmd_Argc() != 2)
{
Com_Printf("Usage: reset \n");
Com_Printf("Resets the position of the given HUD element to the center of the screen.\n");
return;
}
hudname = Cmd_Argv(1);
hud = HUD_Find(hudname);
if (!hud)
{
Com_Printf("No such HUD element %s.\n", hudname);
return;
}
Cbuf_AddText(va("place %s screen\n", hudname));
Cbuf_AddText(va("move %s 0 0\n", hudname));
Cbuf_AddText(va("align %s center center\n", hudname));
}
//
// Reorders children so that they are place infront of their parent.
//
void HUD_ReorderChildren(void)
{
hud_t *hud = hud_huds;
// Give all children a higher Z-order.
while(hud)
{
if(hud->place_hud && hud->order->value <= hud->place_hud->order->value)
{
Cvar_SetValue(hud->order, hud->place_hud->order->value + 1);
}
hud = hud->next;
}
}
//
// Place the specified hud element.
//
void HUD_Place_f (void)
{
hud_t *hud;
char temp[512];
if (Cmd_Argc() < 2 || Cmd_Argc() > 3)
{
Com_Printf("Usage: move []\n");
Com_Printf("Place HUD element at given area.\n");
Com_Printf("\nPossible areas are:\n");
Com_Printf(" screen - screen area\n");
Com_Printf(" top - screen minus status bar\n");
Com_Printf(" view - view\n");
Com_Printf(" sbar - status bar\n");
Com_Printf(" ibar - inventory bar\n");
Com_Printf(" hbar - health bar\n");
Com_Printf(" sfree - status bar free area\n");
Com_Printf(" ifree - inventory bar free area\n");
Com_Printf(" hfree - health bar free area\n");
Com_Printf("You can also use any other HUD element as a base alignment. In such case you should specify area as:\n");
Com_Printf(" @elem - if you want to place\n");
Com_Printf(" it inside elem\n");
Com_Printf(" elem - if you want to place\n");
Com_Printf(" it outside elem\n");
Com_Printf("Examples:\n");
Com_Printf(" place fps view\n");
Com_Printf(" place fps @ping\n");
return;
}
hud = HUD_Find(Cmd_Argv(1));
if (!hud)
{
Com_Printf("No such element: %s\n", Cmd_Argv(1));
return;
}
if (Cmd_Argc() == 2)
{
Com_Printf("Current %s placement: %s\n", hud->name, hud->place->string);
return;
}
// Place with helper.
strlcpy(temp, hud->place->string, sizeof(temp));
Cvar_Set(hud->place, Cmd_Argv(2));
if (!HUD_FindPlace(hud))
{
Com_Printf("place: invalid area argument: %s\n", Cmd_Argv(2));
Cvar_Set(hud->place, temp); // Restore old value.
}
else
{
HUD_ReorderChildren();
}
}
//
// Sets the z-order of a HUD element.
//
void HUD_Order_f (void)
{
int max = 0;
int min = 0;
char *option = NULL;
hud_t *hud = NULL;
if (Cmd_Argc() < 2 || Cmd_Argc() > 3)
{
Com_Printf("Usage: order [