mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-29 15:12:19 +00:00
First weapon wheel implementation.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@6269 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
8faf8a7e96
commit
06038d496e
5 changed files with 474 additions and 42 deletions
|
@ -289,60 +289,327 @@ static cvar_t cl_weaponforgetorder = CVARD("cl_weaponforgetorder", "0", "The 'we
|
||||||
cvar_t r_viewpreselgun = CVARD("r_viewpreselgun", "0", "HACK: Display the preselected weaponmodel, instead of the current weaponmodel.");
|
cvar_t r_viewpreselgun = CVARD("r_viewpreselgun", "0", "HACK: Display the preselected weaponmodel, instead of the current weaponmodel.");
|
||||||
static int preselectedweapons[MAX_SPLITS];
|
static int preselectedweapons[MAX_SPLITS];
|
||||||
static int preselectedweapon[MAX_SPLITS][32];
|
static int preselectedweapon[MAX_SPLITS][32];
|
||||||
|
static kbutton_t in_wwheel;
|
||||||
|
static float wwheeldir[MAX_SPLITS][2];
|
||||||
|
static size_t wwheelsel[MAX_SPLITS];
|
||||||
|
static double wwheelseltime[MAX_SPLITS];
|
||||||
|
|
||||||
|
static struct weaponinfo_s {
|
||||||
|
char shortname[32]; //must not look like an impulse.
|
||||||
|
int impulse; //primary key...
|
||||||
|
int items_mask;
|
||||||
|
int items_val;
|
||||||
|
// int weapon_val; //unused...
|
||||||
|
int ammostat;
|
||||||
|
int ammomin;
|
||||||
|
|
||||||
|
char *icons[3]; //unselected,selected,ammo
|
||||||
|
char *viewmodel;
|
||||||
|
} *weaponinfo;
|
||||||
|
static size_t weaponinfo_count;
|
||||||
|
|
||||||
|
static int IN_NameToWeaponIdx(const char *name)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
char *end;
|
||||||
|
i = strtoul(name, &end, 10);
|
||||||
|
if (i && !end)
|
||||||
|
{ //select by impulse when they specified something numeric.
|
||||||
|
for (i = 0; i < weaponinfo_count; i++)
|
||||||
|
{
|
||||||
|
if (weaponinfo[i].impulse == i)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0; i < weaponinfo_count; i++)
|
||||||
|
{
|
||||||
|
if (!strcmp(name, weaponinfo[i].shortname))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
static int IN_RegisterWeapon(int impulse, const char *name, int items_mask, int items_val, int weapon_val, int ammostat, int ammomin, const char *viewmodel, const char *icon,const char *selicon, const char *ammoicon)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
char *end;
|
||||||
|
if (impulse <= 0 || impulse > 255)
|
||||||
|
return -1; //no. just no...
|
||||||
|
if (strtol(name, &end, 10) != impulse)
|
||||||
|
{
|
||||||
|
if (!*end)
|
||||||
|
return -1; //parsed as a number, which didn't match its impulse... don't break the impulse command.
|
||||||
|
}
|
||||||
|
//slots are unique/replaced by impulse
|
||||||
|
for (i = 0; i < weaponinfo_count; i++)
|
||||||
|
{
|
||||||
|
if (weaponinfo[i].impulse == impulse)
|
||||||
|
break; //replace...
|
||||||
|
}
|
||||||
|
if (i == weaponinfo_count)
|
||||||
|
Z_ReallocElements((void**)&weaponinfo, &weaponinfo_count, i+1, sizeof(*weaponinfo));
|
||||||
|
weaponinfo[i].impulse = impulse;
|
||||||
|
|
||||||
|
Q_strncpyz(weaponinfo[i].shortname, name, sizeof(weaponinfo[i].shortname));
|
||||||
|
weaponinfo[i].items_mask = items_mask;
|
||||||
|
weaponinfo[i].items_val = items_val;
|
||||||
|
// weaponinfo[i].weapon_val; //unused...
|
||||||
|
weaponinfo[i].ammostat = ammostat;
|
||||||
|
weaponinfo[i].ammomin = ammomin;
|
||||||
|
|
||||||
|
#define Z_StrDupPtr2(v,s) do{Z_Free(*v),*(v) = (s&&*s)?strcpy(Z_Malloc(strlen(s)+1), s):NULL;}while(0)
|
||||||
|
Z_StrDupPtr2(&weaponinfo[i].viewmodel, viewmodel);
|
||||||
|
Z_StrDupPtr2(&weaponinfo[i].icons[0], icon);
|
||||||
|
Z_StrDupPtr2(&weaponinfo[i].icons[1], selicon);
|
||||||
|
Z_StrDupPtr2(&weaponinfo[i].icons[2], ammoicon);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
static void IN_RegisterWeapon_Clear(void)
|
||||||
|
{
|
||||||
|
while(weaponinfo_count)
|
||||||
|
Z_Free(weaponinfo[--weaponinfo_count].viewmodel);
|
||||||
|
Z_Free(weaponinfo);
|
||||||
|
weaponinfo = NULL;
|
||||||
|
}
|
||||||
|
void IN_RegisterWeapon_Reset(void)
|
||||||
|
{
|
||||||
|
vfsfile_t *f;
|
||||||
|
IN_RegisterWeapon_Clear();
|
||||||
|
|
||||||
|
f = FS_OpenVFS("wwheel.txt", "rb", FS_GAME);
|
||||||
|
if (f)
|
||||||
|
{ //from the rerelease:
|
||||||
|
/*
|
||||||
|
slot N
|
||||||
|
{
|
||||||
|
impulse N
|
||||||
|
icon "gfx/weapons/ww_foo_1.lmp"
|
||||||
|
icon_sel "gfx/weapons/ww_foo_2.lmp"
|
||||||
|
ammoicon "FOO"
|
||||||
|
entvaroffs N
|
||||||
|
weaponnum N
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
char line[1024];
|
||||||
|
char *v;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
if (!VFS_GETS(f, line, sizeof(line)))
|
||||||
|
break;
|
||||||
|
v = COM_Parse(line);
|
||||||
|
if (!strcmp(com_token, "slot")) //slot N... just assume they're ordered.
|
||||||
|
{
|
||||||
|
//v = COM_Parse(line);
|
||||||
|
//slot = com_token
|
||||||
|
if (!VFS_GETS(f, line, sizeof(line)))
|
||||||
|
break;
|
||||||
|
v = COM_Parse(line);
|
||||||
|
if (!strcmp(com_token, "{"))
|
||||||
|
{
|
||||||
|
int weaponbit=0;
|
||||||
|
int impulse=0;
|
||||||
|
int ammostat=-1;
|
||||||
|
int ammocount=0;
|
||||||
|
int field;
|
||||||
|
char *icon = NULL;
|
||||||
|
char *selicon = NULL;
|
||||||
|
char *ammoicon = NULL;
|
||||||
|
char *viewmodel = NULL;
|
||||||
|
char *name = NULL;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (!VFS_GETS(f, line, sizeof(line)))
|
||||||
|
break;
|
||||||
|
v = COM_Parse(line);
|
||||||
|
if (!strcmp(com_token, "}"))
|
||||||
|
{ //end of this weapon.
|
||||||
|
IN_RegisterWeapon(impulse, name?name:va("%i", impulse), weaponbit,weaponbit, weaponbit, ammostat,ammocount, viewmodel, icon, selicon, ammoicon);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (!strcmp(com_token, "impulse"))
|
||||||
|
{
|
||||||
|
v = COM_Parse(v);
|
||||||
|
impulse = atoi(com_token);
|
||||||
|
}
|
||||||
|
else if (!strcmp(com_token, "weaponnum"))
|
||||||
|
{
|
||||||
|
v = COM_Parse(v);
|
||||||
|
weaponbit = atoi(com_token);
|
||||||
|
}
|
||||||
|
else if (!strcmp(com_token, "icon"))
|
||||||
|
{
|
||||||
|
v = COM_Parse(v);
|
||||||
|
Z_StrDupPtr(&icon, com_token);
|
||||||
|
}
|
||||||
|
else if (!strcmp(com_token, "icon_sel"))
|
||||||
|
{
|
||||||
|
v = COM_Parse(v);
|
||||||
|
Z_StrDupPtr(&selicon, com_token);
|
||||||
|
}
|
||||||
|
else if (!strcmp(com_token, "ammoicon"))
|
||||||
|
{
|
||||||
|
v = COM_Parse(v);
|
||||||
|
if (strchr(com_token, '.') || strchr(com_token, '/'))
|
||||||
|
Z_StrDupPtr(&ammoicon, com_token);
|
||||||
|
else
|
||||||
|
Z_StrDupPtr(&ammoicon, va("gfx/%s", com_token));
|
||||||
|
}
|
||||||
|
else if (!strcmp(com_token, "entvaroffs"))
|
||||||
|
{ //this seems to be a host-only thing. the server can poke the qc's fields directly but other clients can't.
|
||||||
|
//remap known indexes to stats - this can only work for nq's system fields.
|
||||||
|
//note that rogue does some windowing thing so our client can only know either nails or lavanails, not both. either way those are NOT the normal stats and these weapons will appear to have infinite ammo as a result, sorry.
|
||||||
|
//they really should have used field names here, not numbers, but hey, not my spec... use our 'ammostat' instead for fancy mods.
|
||||||
|
v = COM_Parse(v);
|
||||||
|
field = atoi(com_token);
|
||||||
|
switch(field)
|
||||||
|
{
|
||||||
|
case 216: ammostat = STAT_SHELLS, ammocount = 1; break;
|
||||||
|
case 220: ammostat = STAT_NAILS, ammocount = 1; break;
|
||||||
|
case 224: ammostat = STAT_ROCKETS, ammocount = 1; break;
|
||||||
|
case 228: ammostat = STAT_CELLS, ammocount = 1; break;
|
||||||
|
default: ammostat = -1, ammocount = 0; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!strcmp(com_token, "ammostat"))
|
||||||
|
{ //non-qe
|
||||||
|
v = COM_Parse(v);
|
||||||
|
ammostat = atoi(com_token);
|
||||||
|
if (ammocount <= 0)
|
||||||
|
ammocount = 1;
|
||||||
|
}
|
||||||
|
else if (!strcmp(com_token, "ammomin"))
|
||||||
|
{ //non-qe
|
||||||
|
v = COM_Parse(v);
|
||||||
|
ammocount = atoi(com_token);
|
||||||
|
}
|
||||||
|
else if (!strcmp(com_token, "viewmodel"))
|
||||||
|
{ //non-qe, so preselect can show the correct model before its actually changed.
|
||||||
|
v = COM_Parse(v);
|
||||||
|
Z_StrDupPtr(&viewmodel, com_token);
|
||||||
|
}
|
||||||
|
else if (!strcmp(com_token, "shortname"))
|
||||||
|
{ //non-qe, for `+fire nq`
|
||||||
|
v = COM_Parse(v);
|
||||||
|
Z_StrDupPtr(&name, com_token);
|
||||||
|
}
|
||||||
|
else if (*com_token)
|
||||||
|
Con_Printf("Unexpected line in wwheel.txt: %s\n", line);
|
||||||
|
}
|
||||||
|
Z_Free(icon);
|
||||||
|
Z_Free(selicon);
|
||||||
|
Z_Free(ammoicon);
|
||||||
|
Z_Free(viewmodel);
|
||||||
|
Z_Free(name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Con_Printf("missing block, found: %s\n", line);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (*com_token)
|
||||||
|
Con_Printf("Unexpected line in wwheel.txt: %s\n", line);
|
||||||
|
}
|
||||||
|
VFS_CLOSE(f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IN_RegisterWeapon(2, "sg", IT_SHOTGUN,IT_SHOTGUN, IT_SHOTGUN, STAT_SHELLS,1, "progs/v_shot.mdl", NULL,NULL, "gfx/sb_shells");
|
||||||
|
IN_RegisterWeapon(3, "ssg", IT_SUPER_SHOTGUN,IT_SUPER_SHOTGUN, IT_SUPER_SHOTGUN, STAT_SHELLS,1, "progs/v_shot2.mdl", NULL,NULL, "gfx/sb_shells");
|
||||||
|
IN_RegisterWeapon(4, "ng", IT_NAILGUN,IT_NAILGUN, IT_NAILGUN, STAT_NAILS,1, "progs/v_nail.mdl", NULL,NULL, "gfx/sb_nails");
|
||||||
|
IN_RegisterWeapon(5, "sng", IT_SUPER_NAILGUN,IT_SUPER_NAILGUN, IT_SUPER_NAILGUN, STAT_NAILS,1, "progs/v_nail2.mdl", NULL,NULL, "gfx/sb_nails");
|
||||||
|
IN_RegisterWeapon(6, "gl", IT_GRENADE_LAUNCHER,IT_GRENADE_LAUNCHER, IT_GRENADE_LAUNCHER, STAT_ROCKETS,1, "progs/v_rock.mdl", NULL,NULL, "gfx/sb_rocket");
|
||||||
|
IN_RegisterWeapon(7, "rl", IT_ROCKET_LAUNCHER,IT_ROCKET_LAUNCHER, IT_ROCKET_LAUNCHER, STAT_ROCKETS,1, "progs/v_rock2.mdl", NULL,NULL, "gfx/sb_rocket");
|
||||||
|
IN_RegisterWeapon(8, "lg", IT_LIGHTNING,IT_LIGHTNING, IT_LIGHTNING, STAT_CELLS,1, "progs/v_light.mdl", NULL,NULL, "gfx/sb_cells");
|
||||||
|
IN_RegisterWeapon(1, "axe", IT_AXE,IT_AXE, IT_AXE, -1,0, "progs/v_axe.mdl", NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void IN_RegisterWeapon_f(void)
|
||||||
|
{
|
||||||
|
if (Cmd_Argc() <= 2)
|
||||||
|
{
|
||||||
|
const char *arg = Cmd_Argv(1);
|
||||||
|
if (!strcmp(arg, "clear"))
|
||||||
|
IN_RegisterWeapon_Clear();
|
||||||
|
else if (!strcmp(arg, "reset") || !strcmp(arg, "quake")) //'quake' for compat with dp.
|
||||||
|
IN_RegisterWeapon_Reset();
|
||||||
|
else
|
||||||
|
Con_Printf("Unknown arg %s\n", Cmd_Argv(1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IN_RegisterWeapon( atoi(Cmd_Argv(2)), //impulse
|
||||||
|
Cmd_Argv(1), //name
|
||||||
|
atoi(Cmd_Argv(3)), //itemsmask
|
||||||
|
atoi(Cmd_Argv(3)), //itemsval
|
||||||
|
atoi(Cmd_Argv(4)), //weaponval
|
||||||
|
atoi(Cmd_Argv(5)), //ammostat
|
||||||
|
atoi(Cmd_Argv(6)), //ammomin
|
||||||
|
Cmd_Argv(7), //viewmodel
|
||||||
|
Cmd_Argv(8), //weaponicon
|
||||||
|
Cmd_Argv(9), //weaponicon_sel
|
||||||
|
Cmd_Argv(10)); //ammoicon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//hacks, because we have to guess what the mod is doing. we'll probably get it wrong, which sucks.
|
//hacks, because we have to guess what the mod is doing. we'll probably get it wrong, which sucks.
|
||||||
static qboolean IN_HaveWeapon(int pnum, int imp)
|
static qboolean IN_HaveWeapon_Idx(int pnum, size_t widx)
|
||||||
{
|
{
|
||||||
unsigned int items = cl.playerview[pnum].stats[STAT_ITEMS];
|
if (widx < weaponinfo_count)
|
||||||
switch (imp)
|
if ((cl.playerview[pnum].stats[STAT_ITEMS]&weaponinfo[widx].items_mask) == weaponinfo[widx].items_val) //we have the weapon
|
||||||
{
|
if (weaponinfo[widx].ammostat < 0 || cl.playerview[pnum].stats[weaponinfo[widx].ammostat] >= weaponinfo[widx].ammomin) //and we have enough ammo for it too.
|
||||||
case 1: return (items & IT_AXE)?true:false;
|
return true;
|
||||||
case 2: return (items & IT_SHOTGUN && cl.playerview[pnum].stats[STAT_SHELLS] >= 1)?true:false;
|
|
||||||
case 3: return (items & IT_SUPER_SHOTGUN && cl.playerview[pnum].stats[STAT_SHELLS] >= 2)?true:false;
|
|
||||||
case 4: return (items & IT_NAILGUN && cl.playerview[pnum].stats[STAT_NAILS] >= 1)?true:false;
|
|
||||||
case 5: return (items & IT_SUPER_NAILGUN && cl.playerview[pnum].stats[STAT_NAILS] >= 2)?true:false;
|
|
||||||
case 6: return (items & IT_GRENADE_LAUNCHER && cl.playerview[pnum].stats[STAT_ROCKETS] >= 1)?true:false;
|
|
||||||
case 7: return (items & IT_ROCKET_LAUNCHER && cl.playerview[pnum].stats[STAT_ROCKETS] >= 1)?true:false;
|
|
||||||
case 8: return (items & IT_LIGHTNING && cl.playerview[pnum].stats[STAT_CELLS] >= 1)?true:false;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
static qboolean IN_HaveWeapon(int pnum, int impulse)
|
||||||
|
{
|
||||||
|
size_t widx;
|
||||||
|
for (widx = 0; widx < weaponinfo_count; widx++)
|
||||||
|
{
|
||||||
|
if (weaponinfo[widx].impulse == impulse)
|
||||||
|
return IN_HaveWeapon_Idx(pnum, widx);
|
||||||
|
}
|
||||||
|
return false; //we don't really know about it, but assume we can't because false negatives are better than false positives here.
|
||||||
|
}
|
||||||
|
static qboolean IN_HaveWeapon_Name(int pnum, char *name, int *impulse)
|
||||||
|
{
|
||||||
|
int widx = IN_NameToWeaponIdx(name);
|
||||||
|
if (widx < 0)
|
||||||
|
return false;
|
||||||
|
if (!IN_HaveWeapon_Idx(pnum, widx))
|
||||||
|
return false;
|
||||||
|
*impulse = weaponinfo[widx].impulse;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
static int IN_BestWeapon_Pre(unsigned int pnum);
|
static int IN_BestWeapon_Pre(unsigned int pnum);
|
||||||
//if we're using weapon preselection, then we probably also want to show which weapon will be selected, instead of showing the shotgun the whole time.
|
//if we're using weapon preselection, then we probably also want to show which weapon will be selected, instead of showing the shotgun the whole time.
|
||||||
//this of course requires more hacks.
|
//this of course requires more hacks.
|
||||||
const char *IN_GetPreselectedViewmodelName(unsigned int pnum)
|
const char *IN_GetPreselectedViewmodelName(unsigned int pnum)
|
||||||
{
|
{
|
||||||
static const char *nametable[] =
|
|
||||||
{
|
|
||||||
NULL, //can't cope with a 0
|
|
||||||
"progs/v_axe.mdl",
|
|
||||||
"progs/v_shot.mdl",
|
|
||||||
"progs/v_shot2.mdl",
|
|
||||||
"progs/v_nail.mdl",
|
|
||||||
"progs/v_nail2.mdl",
|
|
||||||
"progs/v_rock.mdl",
|
|
||||||
"progs/v_rock2.mdl",
|
|
||||||
"progs/v_light.mdl",
|
|
||||||
};
|
|
||||||
|
|
||||||
if (r_viewpreselgun.ival && cl_weaponpreselect.ival && pnum < countof(preselectedweapons) && preselectedweapons[pnum])
|
if (r_viewpreselgun.ival && cl_weaponpreselect.ival && pnum < countof(preselectedweapons) && preselectedweapons[pnum])
|
||||||
{
|
{
|
||||||
int best = IN_BestWeapon_Pre(pnum);
|
int best = IN_BestWeapon_Pre(pnum);
|
||||||
if (best < countof(nametable))
|
size_t widx;
|
||||||
return nametable[best];
|
for (widx = 0; widx < weaponinfo_count; widx++)
|
||||||
|
{
|
||||||
|
if (weaponinfo[widx].impulse == best)
|
||||||
|
return weaponinfo[widx].viewmodel;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
//FIXME: make a script to decide if a weapon is held? call into the csqc?
|
|
||||||
static int IN_BestWeapon_Args(unsigned int pnum, int firstarg, int argcount)
|
static int IN_BestWeapon_Args(unsigned int pnum, int firstarg, int argcount)
|
||||||
{
|
{ //returns impulses.
|
||||||
int i, imp;
|
int i, imp;
|
||||||
unsigned int best = 0;
|
unsigned int best = 0;
|
||||||
|
|
||||||
for (i = firstarg + argcount; --i >= firstarg; )
|
for (i = firstarg + argcount; --i >= firstarg; )
|
||||||
{
|
{
|
||||||
imp = Q_atoi(Cmd_Argv(i));
|
if (IN_HaveWeapon_Name(pnum, Cmd_Argv(i), &imp))
|
||||||
if (IN_HaveWeapon(pnum, imp))
|
|
||||||
best = imp;
|
best = imp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,13 +632,21 @@ static int IN_BestWeapon_Pre(unsigned int pnum)
|
||||||
|
|
||||||
static void IN_DoPostSelect(void)
|
static void IN_DoPostSelect(void)
|
||||||
{
|
{
|
||||||
|
int pnum = CL_TargettedSplit(false);
|
||||||
if (cl_weaponpreselect.ival)
|
if (cl_weaponpreselect.ival)
|
||||||
{
|
{
|
||||||
int pnum = CL_TargettedSplit(false);
|
|
||||||
int best = IN_BestWeapon_Pre(pnum);
|
int best = IN_BestWeapon_Pre(pnum);
|
||||||
if (best)
|
if (best)
|
||||||
CL_QueueImpulse(pnum, best);
|
CL_QueueImpulse(pnum, best);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (in_wwheel.state[pnum]&1)
|
||||||
|
{
|
||||||
|
in_wwheel.state[pnum] = 0;
|
||||||
|
pnum = CL_TargettedSplit(false);
|
||||||
|
if (wwheelsel[pnum] < weaponinfo_count)
|
||||||
|
CL_QueueImpulse(pnum, weaponinfo[wwheelsel[pnum]].impulse);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//The weapon command autoselects a prioritised weapon like multi-arg impulse does.
|
//The weapon command autoselects a prioritised weapon like multi-arg impulse does.
|
||||||
//however, it potentially makes the switch only on the next +attack.
|
//however, it potentially makes the switch only on the next +attack.
|
||||||
|
@ -381,9 +656,17 @@ void IN_Weapon (void)
|
||||||
int pnum = CL_TargettedSplit(false);
|
int pnum = CL_TargettedSplit(false);
|
||||||
int mode, best, i;
|
int mode, best, i;
|
||||||
|
|
||||||
|
preselectedweapons[pnum] = 0;
|
||||||
for (i = 1; i < Cmd_Argc() && i <= countof(preselectedweapon[pnum]); i++)
|
for (i = 1; i < Cmd_Argc() && i <= countof(preselectedweapon[pnum]); i++)
|
||||||
preselectedweapon[pnum][i-1] = atoi(Cmd_Argv(i));
|
{
|
||||||
preselectedweapons[pnum] = i-1;
|
best = IN_NameToWeaponIdx(Cmd_Argv(i));
|
||||||
|
if (best >= 0)
|
||||||
|
best = weaponinfo[best].impulse; //a known weapon
|
||||||
|
else
|
||||||
|
best = atoi(Cmd_Argv(i)); //fall back
|
||||||
|
if (best > 0)
|
||||||
|
preselectedweapon[pnum][preselectedweapons[pnum]++] = best;
|
||||||
|
}
|
||||||
|
|
||||||
best = IN_BestWeapon_Pre(pnum);
|
best = IN_BestWeapon_Pre(pnum);
|
||||||
if (best)
|
if (best)
|
||||||
|
@ -447,8 +730,7 @@ static void IN_DoWeaponHide(void)
|
||||||
while(l && *l)
|
while(l && *l)
|
||||||
{
|
{
|
||||||
l = COM_ParseOut(l, tok, sizeof(tok));
|
l = COM_ParseOut(l, tok, sizeof(tok));
|
||||||
impulse = atoi(tok);
|
if (IN_HaveWeapon_Name(pnum, tok, &impulse))
|
||||||
if (IN_HaveWeapon(pnum, impulse))
|
|
||||||
best = impulse;
|
best = impulse;
|
||||||
}
|
}
|
||||||
if (best)
|
if (best)
|
||||||
|
@ -476,6 +758,130 @@ void IN_FireUp(void)
|
||||||
if (KeyUp_Scan(&in_attack, k))
|
if (KeyUp_Scan(&in_attack, k))
|
||||||
IN_DoWeaponHide();
|
IN_DoWeaponHide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qboolean IN_WeaponWheelAccumulate(int pnum, float x, float y) //either mouse or controller
|
||||||
|
{
|
||||||
|
if (!(in_wwheel.state[pnum]&1) || !weaponinfo_count)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
wwheeldir[pnum][0] += x;
|
||||||
|
wwheeldir[pnum][1] += y;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#include "shader.h"
|
||||||
|
qboolean IN_DrawWeaponWheel(int pnum)
|
||||||
|
{
|
||||||
|
int w;
|
||||||
|
float pos[2], centre[2];
|
||||||
|
const float radius = 64;
|
||||||
|
float d, a;
|
||||||
|
shader_t *s;
|
||||||
|
if (!(in_wwheel.state[pnum]&1) || !weaponinfo_count)
|
||||||
|
return false;
|
||||||
|
R2D_ImageColours(1,1,1,1);
|
||||||
|
|
||||||
|
centre[0] = cl.playerview[pnum].gamerect.x + cl.playerview[pnum].gamerect.width/2;
|
||||||
|
centre[1] = cl.playerview[pnum].gamerect.y + cl.playerview[pnum].gamerect.height/2;
|
||||||
|
|
||||||
|
d = DotProduct2(wwheeldir[pnum],wwheeldir[pnum]);
|
||||||
|
a = 32;
|
||||||
|
if (d > a*a && d)
|
||||||
|
{
|
||||||
|
wwheeldir[pnum][0] *= a/sqrt(d);
|
||||||
|
wwheeldir[pnum][1] *= a/sqrt(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
a = atan2(wwheeldir[pnum][1], wwheeldir[pnum][0]);
|
||||||
|
w = (a/(2*M_PI)+1) * weaponinfo_count + 0.5;
|
||||||
|
w = w % weaponinfo_count;
|
||||||
|
|
||||||
|
if (w != wwheelsel[pnum])
|
||||||
|
{
|
||||||
|
wwheelseltime[pnum] = realtime;
|
||||||
|
wwheelsel[pnum] = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = R2D_SafeCachePic("gfx/weaponwheel.lmp");
|
||||||
|
if (R_GetShaderSizes(s, NULL, NULL, false)>0)
|
||||||
|
R2D_Image(centre[0]-radius*2, centre[1]-radius*2, radius*4, radius*4, 0, 0, 1, 1, s);
|
||||||
|
for (w = 0; w < weaponinfo_count; w++)
|
||||||
|
{
|
||||||
|
pos[0] = centre[0] + cos((w*2*M_PI) / weaponinfo_count)*radius;
|
||||||
|
pos[1] = centre[1] + sin((w*2*M_PI) / weaponinfo_count)*radius;
|
||||||
|
|
||||||
|
if (weaponinfo[w].icons[0])
|
||||||
|
{ //draw a shadow
|
||||||
|
R2D_ImageColours(0,0,0,1);
|
||||||
|
R2D_Image(pos[0]-24+2, pos[1]-16+2, 48, 32, 0, 0, 1, 1, R2D_SafeCachePic(weaponinfo[w].icons[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
//and the real icon (dark if unavailable)
|
||||||
|
if (IN_HaveWeapon_Idx(pnum, w))
|
||||||
|
R2D_ImageColours(1,1,1,1);
|
||||||
|
else
|
||||||
|
R2D_ImageColours(0.2,0.2,0.2,1);
|
||||||
|
if (w == wwheelsel[pnum])
|
||||||
|
d = 1+sin((realtime - wwheelseltime[pnum])*10); //make it bounce
|
||||||
|
else
|
||||||
|
d = 0;
|
||||||
|
if (cl.playerview[pnum].stats[STAT_ACTIVEWEAPON] == weaponinfo[w].items_val && weaponinfo[w].icons[1])
|
||||||
|
R2D_Image(pos[0]-24-d, pos[1]-16-d, 48, 32, 0, 0, 1, 1, R2D_SafeCachePic(weaponinfo[w].icons[1]));
|
||||||
|
else if (weaponinfo[w].icons[0])
|
||||||
|
R2D_Image(pos[0]-24-d, pos[1]-16-d, 48, 32, 0, 0, 1, 1, R2D_SafeCachePic(weaponinfo[w].icons[0]));
|
||||||
|
else
|
||||||
|
Draw_FunStringWidth(pos[0]-32-d, pos[1]-4-d, weaponinfo[w].shortname, 64, 2, cl.playerview[pnum].stats[STAT_ACTIVEWEAPON] == weaponinfo[w].items_val);
|
||||||
|
}
|
||||||
|
R2D_ImageColours(1,1,1,1);
|
||||||
|
|
||||||
|
w = wwheelsel[pnum];
|
||||||
|
if (weaponinfo[w].icons[2])
|
||||||
|
R2D_Image(centre[0]-12, centre[1]-12, 24, 24, 0, 0, 1, 1, R2D_SafeCachePic(weaponinfo[w].icons[2]));
|
||||||
|
Draw_FunStringWidth(centre[0]-32, centre[1] - 28, weaponinfo[w].shortname, 64, 2, false);
|
||||||
|
if (weaponinfo[w].ammostat >= 0)
|
||||||
|
Draw_FunStringWidth(centre[0]-32, centre[1] + 20, va("%s%d", (cl.playerview[pnum].stats[weaponinfo[w].ammostat]<20)?S_COLOR_RED:"", cl.playerview[pnum].stats[weaponinfo[w].ammostat]), 64, 2, false);
|
||||||
|
|
||||||
|
pos[0] = centre[0] + cos(a)*radius*0.6;
|
||||||
|
pos[1] = centre[1] + sin(a)*radius*0.6;
|
||||||
|
Draw_FunString(pos[0], pos[1], "X");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
static void IN_WWheelDown (void)
|
||||||
|
{
|
||||||
|
#ifdef CSQC_DAT
|
||||||
|
int pnum = CL_TargettedSplit(false);
|
||||||
|
if (CSQC_ConsoleCommand(pnum, Cmd_Argv(0)))
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
if (!(in_wwheel.state[pnum]&1))
|
||||||
|
{
|
||||||
|
size_t w;
|
||||||
|
for (w = 0; w < weaponinfo_count; w++)
|
||||||
|
{
|
||||||
|
if (cl.playerview[pnum].stats[STAT_ACTIVEWEAPON] == weaponinfo[w].items_val)
|
||||||
|
{ //this is our active weapon. start with it highlighted.
|
||||||
|
wwheelseltime[pnum] = realtime;
|
||||||
|
wwheelsel[pnum] = w;
|
||||||
|
|
||||||
|
wwheeldir[pnum][0] = cos((wwheelsel[pnum]*2*M_PI) / weaponinfo_count)*16;
|
||||||
|
wwheeldir[pnum][1] = sin((wwheelsel[pnum]*2*M_PI) / weaponinfo_count)*16;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KeyDown(&in_wwheel, NULL);
|
||||||
|
}
|
||||||
|
static void IN_WWheelUp (void)
|
||||||
|
{
|
||||||
|
int pnum = CL_TargettedSplit(false);
|
||||||
|
#ifdef CSQC_DAT
|
||||||
|
if (CSQC_ConsoleCommand(pnum, Cmd_Argv(0)))
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
if (!KeyUp(&in_wwheel))
|
||||||
|
return;
|
||||||
|
if (wwheelsel[pnum] < weaponinfo_count)
|
||||||
|
CL_QueueImpulse(pnum, weaponinfo[wwheelsel[pnum]].impulse);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
#define IN_DoPostSelect()
|
#define IN_DoPostSelect()
|
||||||
#define IN_DoWeaponHide()
|
#define IN_DoWeaponHide()
|
||||||
|
@ -2753,6 +3159,10 @@ void CL_InitInput (void)
|
||||||
Cmd_AddCommand ("-mlook", IN_MLookUp);
|
Cmd_AddCommand ("-mlook", IN_MLookUp);
|
||||||
|
|
||||||
#ifdef QUAKESTATS
|
#ifdef QUAKESTATS
|
||||||
|
Cmd_AddCommand ("+weaponwheel", IN_WWheelDown);
|
||||||
|
Cmd_AddCommand ("-weaponwheel", IN_WWheelUp);
|
||||||
|
Cmd_AddCommandD ("register_bestweapon", IN_RegisterWeapon_f, "Normally set via a mod's default.cfg file");
|
||||||
|
Cmd_AddCommandD ("bestweapon", IN_Impulse, "Works like 'impulse', for compat with other engines.");
|
||||||
Cvar_Register (&cl_weaponhide, inputnetworkcvargroup);
|
Cvar_Register (&cl_weaponhide, inputnetworkcvargroup);
|
||||||
Cvar_Register (&cl_weaponhide_preference, inputnetworkcvargroup);
|
Cvar_Register (&cl_weaponhide_preference, inputnetworkcvargroup);
|
||||||
Cvar_Register (&cl_weaponpreselect, inputnetworkcvargroup);
|
Cvar_Register (&cl_weaponpreselect, inputnetworkcvargroup);
|
||||||
|
|
|
@ -6894,6 +6894,10 @@ void CL_ExecInitialConfigs(char *resetcommand)
|
||||||
Cbuf_AddText("\n", RESTRICT_LOCAL);
|
Cbuf_AddText("\n", RESTRICT_LOCAL);
|
||||||
COM_ParsePlusSets(true);
|
COM_ParsePlusSets(true);
|
||||||
|
|
||||||
|
#ifdef QUAKESTATS
|
||||||
|
Cbuf_AddText("register_bestweapon reset\n", RESTRICT_LOCAL);
|
||||||
|
#endif
|
||||||
|
|
||||||
def = COM_FDepthFile("default.cfg", true); //q2/q3/tc
|
def = COM_FDepthFile("default.cfg", true); //q2/q3/tc
|
||||||
#ifdef QUAKETC
|
#ifdef QUAKETC
|
||||||
Cbuf_AddText ("exec default.cfg\n", RESTRICT_LOCAL);
|
Cbuf_AddText ("exec default.cfg\n", RESTRICT_LOCAL);
|
||||||
|
|
|
@ -897,6 +897,13 @@ void SCR_CheckDrawCenterString (void)
|
||||||
p = &scr_centerprint[pnum];
|
p = &scr_centerprint[pnum];
|
||||||
p->cursorchar = NULL;
|
p->cursorchar = NULL;
|
||||||
|
|
||||||
|
#ifdef QUAKESTATS
|
||||||
|
if (IN_DrawWeaponWheel(pnum))
|
||||||
|
{ //we won't draw the cprint, but it also won't fade while the wwheel is shown.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (p->time_off <= 0 && !(p->flags & CPRINT_PERSIST))
|
if (p->time_off <= 0 && !(p->flags & CPRINT_PERSIST))
|
||||||
continue; //'/P' prefix doesn't time out
|
continue; //'/P' prefix doesn't time out
|
||||||
|
|
||||||
|
|
|
@ -1215,6 +1215,8 @@ void CL_UpdateWindowTitle(void);
|
||||||
|
|
||||||
#ifdef QUAKESTATS
|
#ifdef QUAKESTATS
|
||||||
const char *IN_GetPreselectedViewmodelName(unsigned int pnum);
|
const char *IN_GetPreselectedViewmodelName(unsigned int pnum);
|
||||||
|
qboolean IN_WeaponWheelAccumulate(int pnum, float x, float y);
|
||||||
|
qboolean IN_DrawWeaponWheel(int pnum);
|
||||||
#endif
|
#endif
|
||||||
void CL_InitInput (void);
|
void CL_InitInput (void);
|
||||||
void CL_SendCmd (double frametime, qboolean mainloop);
|
void CL_SendCmd (double frametime, qboolean mainloop);
|
||||||
|
|
|
@ -469,12 +469,17 @@ void IN_Commands(void)
|
||||||
{
|
{
|
||||||
if (topmenu && topmenu->joyaxis && topmenu->joyaxis(topmenu, ev->devid, ev->joy.axis, ev->joy.value))
|
if (topmenu && topmenu->joyaxis && topmenu->joyaxis(topmenu, ev->devid, ev->joy.axis, ev->joy.value))
|
||||||
joy[ev->devid].axis[ev->joy.axis] = 0;
|
joy[ev->devid].axis[ev->joy.axis] = 0;
|
||||||
else
|
#ifdef QUAKESTATS
|
||||||
#ifdef CSQC_DAT
|
else if (ev->joy.axis==GPAXIS_LT_RIGHT && IN_WeaponWheelAccumulate(ev->devid, ev->joy.value, 0))
|
||||||
if (CSQC_JoystickAxis(ev->joy.axis, ev->joy.value, ev->devid))
|
joy[ev->devid].axis[ev->joy.axis] = 0;
|
||||||
|
else if (ev->joy.axis==GPAXIS_LT_DOWN && IN_WeaponWheelAccumulate(ev->devid, 0, ev->joy.value))
|
||||||
joy[ev->devid].axis[ev->joy.axis] = 0;
|
joy[ev->devid].axis[ev->joy.axis] = 0;
|
||||||
else
|
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CSQC_DAT
|
||||||
|
else if (CSQC_JoystickAxis(ev->joy.axis, ev->joy.value, ev->devid))
|
||||||
|
joy[ev->devid].axis[ev->joy.axis] = 0;
|
||||||
|
#endif
|
||||||
|
else
|
||||||
joy[ev->devid].axis[ev->joy.axis] = ev->joy.value;
|
joy[ev->devid].axis[ev->joy.axis] = ev->joy.value;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -768,7 +773,11 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum, float frame
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//if game is not focused, kill any mouse look
|
//if game is not focused, kill any mouse look
|
||||||
if (Key_Dest_Has(~kdm_game))
|
if (
|
||||||
|
#ifdef QUAKESTATS
|
||||||
|
IN_WeaponWheelAccumulate(pnum, mx, my) ||
|
||||||
|
#endif
|
||||||
|
Key_Dest_Has(~kdm_game))
|
||||||
{
|
{
|
||||||
mx = 0;
|
mx = 0;
|
||||||
my = 0;
|
my = 0;
|
||||||
|
|
Loading…
Reference in a new issue