From: Mario Date: Fri, 21 Sep 2018 01:57:08 +0000 (+1000) Subject: Merge branch 'master' into Mario/duel X-Git-Tag: xonotic-v0.8.5~1809^2~5 X-Git-Url: https://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=commitdiff_plain;h=8e5d376c49510049572c7c182ba8778c8a8f80dd;hp=1da9577d75cb298a80a5944040148431a8c89894 Merge branch 'master' into Mario/duel --- diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9423d5d5d..f960751ca 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -29,7 +29,7 @@ test_sv_game: - wget -O data/maps/stormkeep.waypoints https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints - wget -O data/maps/stormkeep.waypoints.cache https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints.cache - make - - EXPECT=dc1bc3ac45188576a9651c6b7a1535a8 + - EXPECT=e62d1a2375f0976ab12e2d980add29bd - HASH=$(${ENGINE} -noconfig -nohome +exec serverbench.cfg | tee /dev/stderr | grep '^:' diff --git a/notifications.cfg b/notifications.cfg index dc50883e0..07423e3aa 100644 --- a/notifications.cfg +++ b/notifications.cfg @@ -693,11 +693,11 @@ seta notification_WEAPON_VAPORIZER_MURDER "1" "Enable this multiple notification seta notification_WEAPON_VORTEX_MURDER "1" "Enable this multiple notification" // MSG_CHOICE notifications (count = 28): -seta notification_CHOICE_CTF_CAPTURE_BROKEN "1" "Choice for this notification 0 = off, 1 = default message, 2 = verbose message" +seta notification_CHOICE_CTF_CAPTURE_BROKEN "2" "Choice for this notification 0 = off, 1 = default message, 2 = verbose message" seta notification_CHOICE_CTF_CAPTURE_BROKEN_ALLOWED "2" "Allow choice for this notification 0 = off, 1 = only in warmup mode, 2 = always" -seta notification_CHOICE_CTF_CAPTURE_TIME "1" "Choice for this notification 0 = off, 1 = default message, 2 = verbose message" +seta notification_CHOICE_CTF_CAPTURE_TIME "2" "Choice for this notification 0 = off, 1 = default message, 2 = verbose message" seta notification_CHOICE_CTF_CAPTURE_TIME_ALLOWED "2" "Allow choice for this notification 0 = off, 1 = only in warmup mode, 2 = always" -seta notification_CHOICE_CTF_CAPTURE_UNBROKEN "1" "Choice for this notification 0 = off, 1 = default message, 2 = verbose message" +seta notification_CHOICE_CTF_CAPTURE_UNBROKEN "2" "Choice for this notification 0 = off, 1 = default message, 2 = verbose message" seta notification_CHOICE_CTF_CAPTURE_UNBROKEN_ALLOWED "2" "Allow choice for this notification 0 = off, 1 = only in warmup mode, 2 = always" seta notification_CHOICE_CTF_PICKUP_ENEMY "1" "Choice for this notification 0 = off, 1 = default message, 2 = verbose message" seta notification_CHOICE_CTF_PICKUP_ENEMY_ALLOWED "2" "Allow choice for this notification 0 = off, 1 = only in warmup mode, 2 = always" diff --git a/qcsrc/client/view.qc b/qcsrc/client/view.qc index e873f6453..ff9b47cbc 100644 --- a/qcsrc/client/view.qc +++ b/qcsrc/client/view.qc @@ -48,6 +48,7 @@ #define EFMASK_CHEAP (EF_ADDITIVE | EF_DOUBLESIDED | EF_FULLBRIGHT | EF_NODEPTHTEST | EF_NODRAW | EF_NOSHADOW | EF_SELECTABLE | EF_TELEPORT_BIT) float autocvar_cl_viewmodel_scale; +float autocvar_cl_viewmodel_alpha; bool autocvar_cl_bobmodel; float autocvar_cl_bobmodel_speed; @@ -297,12 +298,9 @@ void viewmodel_draw(entity this) if(!this.activeweapon || !autocvar_r_drawviewmodel) return; int mask = (intermission || (STAT(HEALTH) <= 0) || autocvar_chase_active) ? 0 : MASK_NORMAL; - float a = this.alpha; - static bool wasinvehicle; + float a = ((autocvar_cl_viewmodel_alpha) ? bound(-1, autocvar_cl_viewmodel_alpha, this.m_alpha) : this.m_alpha); bool invehicle = player_localentnum > maxclients; if (invehicle) a = -1; - else if (wasinvehicle) a = 1; - wasinvehicle = invehicle; Weapon wep = this.activeweapon; int c = entcs_GetClientColors(current_player); vector g = weaponentity_glowmod(wep, NULL, c, this); diff --git a/qcsrc/client/weapons/projectile.qc b/qcsrc/client/weapons/projectile.qc index f4871e7fc..067c0badb 100644 --- a/qcsrc/client/weapons/projectile.qc +++ b/qcsrc/client/weapons/projectile.qc @@ -265,19 +265,19 @@ NET_HANDLE(ENT_CLIENT_PROJECTILE, bool isnew) this.fade_rate = 0; } - int myteam = ReadByte(); - this.team = myteam - 1; + int proj_team = ReadByte(); + this.team = proj_team - 1; if(teamplay) { - if(myteam) + if(proj_team) this.colormap = (this.team) * 0x11; // note: team - 1 on server (client uses different numbers) else this.colormap = 0x00; this.colormap |= BIT(10); // RENDER_COLORMAPPED } else - this.colormap = myteam; + this.colormap = proj_team; // TODO: projectiles use glowmaps for their color, not teams #if 0 if(this.colormap > 0) diff --git a/qcsrc/common/animdecide.qc b/qcsrc/common/animdecide.qc index b53a9ba0e..69fe45826 100644 --- a/qcsrc/common/animdecide.qc +++ b/qcsrc/common/animdecide.qc @@ -210,9 +210,8 @@ vector animdecide_getloweranim(entity e) return vec3(e.anim_duckwalkbackright.x, t, ANIMPRIO_CROUCH); case ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_LEFT: return vec3(e.anim_duckwalkbackleft.x, t, ANIMPRIO_CROUCH); - default: - return vec3(e.anim_duckidle.x, t, ANIMPRIO_CROUCH); } + return vec3(e.anim_duckidle.x, t, ANIMPRIO_CROUCH); } else { @@ -236,12 +235,11 @@ vector animdecide_getloweranim(entity e) return vec3(e.anim_backright.x, t, ANIMPRIO_ACTIVE); case ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_LEFT: return vec3(e.anim_backleft.x, t, ANIMPRIO_ACTIVE); - default: - return vec3(e.anim_idle.x, t, ANIMPRIO_IDLE); } + return vec3(e.anim_idle.x, t, ANIMPRIO_IDLE); } // can't get here - return vec3(e.anim_idle.x, t, ANIMPRIO_IDLE); + //return vec3(e.anim_idle.x, t, ANIMPRIO_IDLE); } void animdecide_setimplicitstate(entity e, float onground) diff --git a/qcsrc/common/gamemodes/gamemode/ctf/sv_ctf.qc b/qcsrc/common/gamemodes/gamemode/ctf/sv_ctf.qc index efbbf94e7..2696a4e87 100644 --- a/qcsrc/common/gamemodes/gamemode/ctf/sv_ctf.qc +++ b/qcsrc/common/gamemodes/gamemode/ctf/sv_ctf.qc @@ -1519,7 +1519,7 @@ void havocbot_goalrating_ctf_enemyflag(entity this, float ratingscale) { // adjust rating of our flag carrier depending on his health head = head.tag_entity; - float f = bound(0, (head.health + head.armorvalue) / 100, 2) - 1; + float f = bound(0, (GetResourceAmount(head, RESOURCE_HEALTH) + GetResourceAmount(head, RESOURCE_ARMOR)) / 100, 2) - 1; ratingscale += ratingscale * f * 0.1; } navigation_routerating(this, head, ratingscale, 10000); diff --git a/qcsrc/common/gamemodes/gamemode/lms/sv_lms.qc b/qcsrc/common/gamemodes/gamemode/lms/sv_lms.qc index ffbecf1b3..493320cce 100644 --- a/qcsrc/common/gamemodes/gamemode/lms/sv_lms.qc +++ b/qcsrc/common/gamemodes/gamemode/lms/sv_lms.qc @@ -36,16 +36,16 @@ void ClearWinners(); int WinningCondition_LMS() { entity first_player = NULL; - int total_players = 0; + int totalplayers = 0; FOREACH_CLIENT(IS_PLAYER(it), { - if (!total_players) + if (!totalplayers) first_player = it; - ++total_players; + ++totalplayers; }); - if (total_players) + if (totalplayers) { - if (total_players > 1) + if (totalplayers > 1) { // two or more active players - continue with the game diff --git a/qcsrc/common/gamemodes/sv_rules.qh b/qcsrc/common/gamemodes/sv_rules.qh index ca1b6f8e7..f8950684b 100644 --- a/qcsrc/common/gamemodes/sv_rules.qh +++ b/qcsrc/common/gamemodes/sv_rules.qh @@ -1,7 +1,7 @@ #pragma once // TODO: find a better location for these? -float total_players; +int total_players; // todo: accept the number of teams as a parameter void GameRules_teams(bool value); diff --git a/qcsrc/common/items/inventory.qh b/qcsrc/common/items/inventory.qh index 9075c0912..ba824f40b 100644 --- a/qcsrc/common/items/inventory.qh +++ b/qcsrc/common/items/inventory.qh @@ -107,7 +107,7 @@ bool Inventory_Send(Inventory this, Client to, int sf) TC(Inventory, this); WriteHeader(MSG_ENTITY, ENT_CLIENT_INVENTORY); entity e = this.owner; - if (IS_SPEC(e)) e = e.enemy; + if (IS_SPEC(e)) e = PS(e.enemy); // TODO: how can this *ever* be the case? TC(Player, e); Inventory data = e.inventory; Inventory_Write(data); @@ -118,7 +118,7 @@ void Inventory_new(entity e) { Inventory inv = NEW(Inventory), bak = NEW(Inventory); inv.inventory = bak; - inv.drawonlytoclient = e; + inv.drawonlytoclient = IS_CLIENT(e) ? e : e.m_client; Net_LinkEntity((inv.owner = e).inventory = inv, false, 0, Inventory_Send); } void Inventory_delete(entity e) { delete(e.inventory.inventory); delete(e.inventory); } diff --git a/qcsrc/common/items/item/pickup.qc b/qcsrc/common/items/item/pickup.qc index b5944fc0a..a3c2d779e 100644 --- a/qcsrc/common/items/item/pickup.qc +++ b/qcsrc/common/items/item/pickup.qc @@ -11,9 +11,10 @@ METHOD(Pickup, giveTo, bool(Pickup this, entity item, entity player)) TC(Pickup, this); bool b = Item_GiveTo(item, player); if (b) { - LOG_DEBUGF("entity %i picked up %s", player, this.m_name); - player.inventory.inv_items[this.m_id]++; - Inventory_update(player); + //LOG_DEBUGF("entity %i picked up %s", player, this.m_name); + entity store = IS_PLAYER(player) ? PS(player) : player; + store.inventory.inv_items[this.m_id]++; + Inventory_update(store); } return b; } diff --git a/qcsrc/common/mapinfo.qc b/qcsrc/common/mapinfo.qc index f5a0f666b..8d8884f21 100644 --- a/qcsrc/common/mapinfo.qc +++ b/qcsrc/common/mapinfo.qc @@ -854,6 +854,9 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, Gamet if(fexists(strcat("scripts/", pFilename, ".arena"))) fputs(fh, "settemp_for_type all sv_q3acompat_machineshotgunswap 1\n"); + if(fexists(strcat("scripts/", pFilename, ".defi"))) + fputs(fh, "settemp_for_type all sv_vq3compat 1\n"); + fputs(fh, "// optional: fog density red green blue alpha mindist maxdist\n"); fputs(fh, "// optional: settemp_for_type (all|gametypename) cvarname value\n"); fputs(fh, "// optional: clientsettemp_for_type (all|gametypename) cvarname value\n"); diff --git a/qcsrc/common/mapobjects/func/door.qc b/qcsrc/common/mapobjects/func/door.qc index 8d40a377b..b7418298c 100644 --- a/qcsrc/common/mapobjects/func/door.qc +++ b/qcsrc/common/mapobjects/func/door.qc @@ -277,7 +277,7 @@ void door_damage(entity this, entity inflictor, entity attacker, float damage, i { SetResourceAmountExplicit(this.owner, RESOURCE_HEALTH, this.owner.max_health); this.owner.takedamage = DAMAGE_NO; // will be reset upon return - door_use(this.owner, NULL, NULL); + door_use(this.owner, attacker, NULL); } } diff --git a/qcsrc/common/mapobjects/misc/_mod.inc b/qcsrc/common/mapobjects/misc/_mod.inc index 498f6c521..c7f1619ad 100644 --- a/qcsrc/common/mapobjects/misc/_mod.inc +++ b/qcsrc/common/mapobjects/misc/_mod.inc @@ -2,5 +2,6 @@ #include #include #include +#include #include #include diff --git a/qcsrc/common/mapobjects/misc/_mod.qh b/qcsrc/common/mapobjects/misc/_mod.qh index 3415919f8..617db807b 100644 --- a/qcsrc/common/mapobjects/misc/_mod.qh +++ b/qcsrc/common/mapobjects/misc/_mod.qh @@ -2,5 +2,6 @@ #include #include #include +#include #include #include diff --git a/qcsrc/common/mapobjects/misc/keys.qc b/qcsrc/common/mapobjects/misc/keys.qc new file mode 100644 index 000000000..2c8574249 --- /dev/null +++ b/qcsrc/common/mapobjects/misc/keys.qc @@ -0,0 +1,292 @@ +#include "keys.qh" + +#ifdef CSQC +bool item_keys_usekey(entity l, entity p) +{ + int valid = (l.itemkeys & p.itemkeys); // TODO: itemkeys isn't networked or anything! + l.itemkeys &= ~valid; // only some of the needed keys were given + return valid != 0; +} +#endif + +#ifdef SVQC +/* +TODO: +- add an unlock sound (here to trigger_keylock and to func_door) +- display available keys on the HUD +- make more tests +- think about adding NOT_EASY/NOT_NORMAL/NOT_HARD for Q1 compatibility +- should keys have a trigger? +*/ + +bool item_keys_usekey(entity l, entity p) +{ + int valid = l.itemkeys & p.itemkeys; + + if (!valid) { + // player has none of the needed keys + return false; + } else if (l.itemkeys == valid) { + // ALL needed keys were given + l.itemkeys = 0; + return true; + } else { + // only some of the needed keys were given + l.itemkeys &= ~valid; + return true; + } +} + +string item_keys_keylist(float keylist) { + // no keys + if (!keylist) + return ""; + + // one key + if ((keylist & (keylist-1)) == 0) + return strcat("the ", item_keys_names[lowestbit(keylist)]); + + string n = ""; + int base = 0; + while (keylist) { + int l = lowestbit(keylist); + if (n) + n = strcat(n, ", the ", item_keys_names[base + l]); + else + n = strcat("the ", item_keys_names[base + l]); + + keylist = bitshift(keylist, -(l + 1)); + base+= l + 1; + } + + return n; +} + + +/* +================================ +item_key +================================ +*/ + +/** + * Key touch handler. + */ +void item_key_touch(entity this, entity toucher) +{ + if (!IS_PLAYER(toucher)) + return; + + // player already picked up this key + if (PS(toucher).itemkeys & this.itemkeys) + return; + + PS(toucher).itemkeys |= this.itemkeys; + play2(toucher, this.noise); + + centerprint(toucher, this.message); + + string oldmsg = this.message; + this.message = ""; + SUB_UseTargets(this, toucher, toucher); // TODO: should we be using toucher for the trigger here? + this.message = oldmsg; +} + +/** + * Spawn a key with given model, key code and color. + */ +void spawn_item_key(entity this) +{ + precache_model(this.model); + + if (this.spawnflags & 1) // FLOATING + this.noalign = 1; + + if (this.noalign) + set_movetype(this, MOVETYPE_NONE); + else + set_movetype(this, MOVETYPE_TOSS); + + precache_sound(this.noise); + + this.mdl = this.model; + this.effects = EF_LOWPRECISION; + _setmodel(this, this.model); + //setsize(this, '-16 -16 -24', '16 16 32'); + setorigin(this, this.origin + '0 0 32'); + setsize(this, '-16 -16 -56', '16 16 0'); + this.modelflags |= MF_ROTATE; + this.solid = SOLID_TRIGGER; + + if (!this.noalign) + { + // first nudge it off the floor a little bit to avoid math errors + setorigin(this, this.origin + '0 0 1'); + // note droptofloor returns false if stuck/or would fall too far + droptofloor(this); + } + + settouch(this, item_key_touch); +} + + +/*QUAKED item_key (0 .5 .8) (-16 -16 -24) (16 16 32) FLOATING +A key entity. +The itemkeys should contain one of the following key IDs: +1 - GOLD key - +2 - SILVER key +4 - BRONZE key +8 - RED keycard +16 - BLUE keycard +32 - GREEN keycard +Custom keys: +... - last key is 1<<23 +Keys with bigger Id than 32 don't have a default netname and model, if you use one of them, you MUST provide those. +-----------KEYS------------ +colormod: color of the key (default: '.9 .9 .9'). +itemkeys: a key Id. +message: message to print when player picks up this key. +model: custom key model to use. +netname: the display name of the key. +noise: custom sound to play when player picks up the key. +-------- SPAWNFLAGS -------- +FLOATING: the item will float in air, instead of aligning to the floor by falling +---------NOTES---------- +This is the only correct way to put keys on the map! + +itemkeys MUST always have exactly one bit set. +*/ +spawnfunc(item_key) +{ + string _netname; + vector _colormod; + + // reject this entity if more than one key was set! + if (this.itemkeys>0 && (this.itemkeys & (this.itemkeys-1)) != 0) { + objerror(this, "item_key.itemkeys must contain only 1 bit set specifying the key it represents!"); + delete(this); + return; + } + + // find default netname and colormod + switch(this.itemkeys) { + case BIT(0): + _netname = "GOLD key"; + _colormod = '1 .9 0'; + break; + + case BIT(1): + _netname = "SILVER key"; + _colormod = '.9 .9 .9'; + break; + + case BIT(2): + _netname = "BRONZE key"; + _colormod = '.6 .25 0'; + break; + + case BIT(3): + _netname = "RED keycard"; + _colormod = '.9 0 0'; + break; + + case BIT(4): + _netname = "BLUE keycard"; + _colormod = '0 0 .9'; + break; + + case BIT(5): + _netname = "GREEN keycard"; + _colormod = '0 .9 0'; + break; + + default: + _netname = "FLUFFY PINK keycard"; + _colormod = '1 1 1'; + + if (this.netname == "") { + objerror(this, "item_key doesn't have a default name for this key and a custom one was not specified!"); + delete(this); + return; + } + break; + + } + + // find default model + string _model = string_null; + if (this.itemkeys <= ITEM_KEY_BIT(2)) { + _model = "models/keys/key.md3"; + } else if (this.itemkeys >= ITEM_KEY_BIT(3) && this.itemkeys <= ITEM_KEY_BIT(5)) { + _model = "models/keys/key.md3"; // FIXME: replace it by a keycard model! + } else if (this.model == "") { + objerror(this, "item_key doesn't have a default model for this key and a custom one was not specified!"); + delete(this); + return; + } + + // set defailt netname + if (this.netname == "") + this.netname = _netname; + + // set default colormod + if (!this.colormod) + this.colormod = _colormod; + + // set default model + if (this.model == "") + this.model = _model; + + // set default pickup message + if (this.message == "") + this.message = strzone(strcat("You've picked up the ", this.netname, "!")); + + if (this.noise == "") + this.noise = strzone(SND(ITEMPICKUP)); + + // save the name for later + item_keys_names[lowestbit(this.itemkeys)] = this.netname; + + // put the key on the map + spawn_item_key(this); +} + +/*QUAKED item_key1 (0 .5 .8) (-16 -16 -24) (16 16 32) FLOATING +SILVER key. +-----------KEYS------------ +colormod: color of the key (default: '.9 .9 .9'). +message: message to print when player picks up this key. +model: custom model to use. +noise: custom sound to play when player picks up the key. +-------- SPAWNFLAGS -------- +FLOATING: the item will float in air, instead of aligning to the floor by falling +---------NOTES---------- +Don't use this entity on new maps! Use item_key instead. +*/ +spawnfunc(item_key1) +{ + this.classname = "item_key"; + this.itemkeys = ITEM_KEY_BIT(1); + spawnfunc_item_key(this); +} + +/*QUAKED item_key2 (0 .5 .8) (-16 -16 -24) (16 16 32) FLOATING +GOLD key. +-----------KEYS------------ +colormod: color of the key (default: '1 .9 0'). +message: message to print when player picks up this key. +model: custom model to use. +noise: custom sound to play when player picks up the key. +-------- SPAWNFLAGS -------- +FLOATING: the item will float in air, instead of aligning to the floor by falling +---------NOTES---------- +Don't use this entity on new maps! Use item_key instead. +*/ +spawnfunc(item_key2) +{ + this.classname = "item_key"; + this.itemkeys = ITEM_KEY_BIT(0); + spawnfunc_item_key(this); +} + +#endif diff --git a/qcsrc/common/mapobjects/misc/keys.qh b/qcsrc/common/mapobjects/misc/keys.qh new file mode 100644 index 000000000..50be5f8db --- /dev/null +++ b/qcsrc/common/mapobjects/misc/keys.qh @@ -0,0 +1,26 @@ +#pragma once + +/** + * Returns the bit ID of a key + */ +#define ITEM_KEY_BIT(n) ( bitshift(1, n) ) + +#define ITEM_KEY_MAX 24 + +/** + * list of key names. + */ +#ifdef SVQC +string item_keys_names[ITEM_KEY_MAX]; + +/** + * Use keys from p on l. + * Returns true if any new keys were given, false otherwise. + */ +float item_keys_usekey(entity l, entity p); + +/** + * Returns a string with a comma separated list of key names, as specified in keylist. + */ +string item_keys_keylist(float keylist); +#endif diff --git a/qcsrc/common/mapobjects/models.qc b/qcsrc/common/mapobjects/models.qc index 92ff464b7..4f07409b1 100644 --- a/qcsrc/common/mapobjects/models.qc +++ b/qcsrc/common/mapobjects/models.qc @@ -199,42 +199,42 @@ spawnfunc(func_clientwall) { G_CLIENTMODEL_INIT(this, SOLID_BSP) } // bru void Ent_Wall_PreDraw(entity this) { + float alph = this.alpha; if (this.inactive) { - this.alpha = 0; + alph = 0; } else { vector org = getpropertyvec(VF_ORIGIN); if(!checkpvs(org, this)) - this.alpha = 0; + alph = 0; else if(this.fade_start || this.fade_end) { vector offset = '0 0 0'; offset_z = this.fade_vertical_offset; - float player_dist = vlen(org - this.origin - 0.5 * (this.mins + this.maxs) + offset); + vector player_dist_math = org - this.origin - 0.5 * (this.mins + this.maxs) + offset; if (this.fade_end == this.fade_start) { - if (player_dist >= this.fade_start) - this.alpha = 0; + if (vdist(player_dist_math, >=, this.fade_start)) + alph = 0; else - this.alpha = 1; + alph = 1; } else { - this.alpha = (this.alpha_min + this.alpha_max * bound(0, + float player_dist = vlen(player_dist_math); + alph = (this.alpha_min + this.alpha_max * bound(0, (this.fade_end - player_dist) / (this.fade_end - this.fade_start), 1)) / 100.0; } } else { - this.alpha = 1; + alph = 1; } } - if(this.alpha <= 0) - this.drawmask = 0; - else - this.drawmask = MASK_NORMAL; + this.alpha = alph; + this.drawmask = (alph <= 0) ? 0 : MASK_NORMAL; } void Ent_Wall_Draw(entity this) diff --git a/qcsrc/common/mapobjects/trigger/counter.qc b/qcsrc/common/mapobjects/trigger/counter.qc index 4c89c4c27..9156439f9 100644 --- a/qcsrc/common/mapobjects/trigger/counter.qc +++ b/qcsrc/common/mapobjects/trigger/counter.qc @@ -4,13 +4,21 @@ void counter_reset(entity this); void counter_use(entity this, entity actor, entity trigger) { - this.count -= 1; - if (this.count < 0) + entity store = this; + if(this.spawnflags & COUNTER_PER_PLAYER) + { + if(!IS_PLAYER(actor)) + return; + store = actor; + } + + store.counter_cnt += 1; + if (store.counter_cnt > this.count) return; bool doactivate = (this.spawnflags & COUNTER_FIRE_AT_COUNT); - if (this.count == 0) + if (store.counter_cnt == this.count) { if(IS_PLAYER(actor) && !(this.spawnflags & SPAWNFLAG_NOMESSAGE)) Send_Notification(NOTIF_ONE, actor, MSG_CENTER, CENTER_SEQUENCE_COMPLETED); @@ -27,10 +35,10 @@ void counter_use(entity this, entity actor, entity trigger) { if(IS_PLAYER(actor) && !(this.spawnflags & SPAWNFLAG_NOMESSAGE)) { - if(this.count >= 4) + if((this.count - store.counter_cnt) >= 4) Send_Notification(NOTIF_ONE, actor, MSG_CENTER, CENTER_SEQUENCE_COUNTER); else - Send_Notification(NOTIF_ONE, actor, MSG_CENTER, CENTER_SEQUENCE_COUNTER_FEWMORE, this.count); + Send_Notification(NOTIF_ONE, actor, MSG_CENTER, CENTER_SEQUENCE_COUNTER_FEWMORE, this.count - store.counter_cnt); } } @@ -42,7 +50,7 @@ void counter_reset(entity this) { setthink(this, func_null); this.nextthink = 0; - this.count = this.cnt; + this.counter_cnt = 0; } /*QUAKED spawnfunc_trigger_counter (.5 .5 .5) ? nomessage COUNTER_FIRE_AT_COUNT @@ -59,8 +67,8 @@ spawnfunc(trigger_counter) { if (!this.count) this.count = 2; - this.cnt = this.count; + this.counter_cnt = 0; this.use = counter_use; this.reset = counter_reset; } diff --git a/qcsrc/common/mapobjects/trigger/counter.qh b/qcsrc/common/mapobjects/trigger/counter.qh index 394d15472..d36bd0293 100644 --- a/qcsrc/common/mapobjects/trigger/counter.qh +++ b/qcsrc/common/mapobjects/trigger/counter.qh @@ -1,4 +1,10 @@ #pragma once +#ifdef SVQC +spawnfunc(trigger_counter); + +.float counter_cnt; +#endif const int COUNTER_FIRE_AT_COUNT = BIT(2); +const int COUNTER_PER_PLAYER = BIT(3); diff --git a/qcsrc/common/mapobjects/trigger/hurt.qc b/qcsrc/common/mapobjects/trigger/hurt.qc index 966e0cfb0..ccdf2c7d0 100644 --- a/qcsrc/common/mapobjects/trigger/hurt.qc +++ b/qcsrc/common/mapobjects/trigger/hurt.qc @@ -25,7 +25,7 @@ void trigger_hurt_touch(entity this, entity toucher) if (toucher.triggerhurttime < time) { EXACTTRIGGER_TOUCH(this, toucher); - toucher.triggerhurttime = time + 1; + toucher.triggerhurttime = time + ((autocvar_sv_vq3compat && !(this.spawnflags & HURT_SLOW)) ? 0.1 : 1); entity own; own = this.enemy; @@ -53,7 +53,7 @@ void trigger_hurt_touch(entity this, entity toucher) /*QUAKED spawnfunc_trigger_hurt (.5 .5 .5) ? Any object touching this will be hurt set dmg to damage amount -default dmg = 1000 +default dmg = 10000 */ .entity trigger_hurt_next; entity trigger_hurt_last; @@ -66,7 +66,7 @@ spawnfunc(trigger_hurt) this.use = trigger_hurt_use; this.enemy = world; // I hate you all if (!this.dmg) - this.dmg = 1000; + this.dmg = ((autocvar_sv_vq3compat) ? 5 : 10000); if (this.message == "") this.message = "was in the wrong place"; if (this.message2 == "") diff --git a/qcsrc/common/mapobjects/trigger/hurt.qh b/qcsrc/common/mapobjects/trigger/hurt.qh index 6f70f09be..e992154aa 100644 --- a/qcsrc/common/mapobjects/trigger/hurt.qh +++ b/qcsrc/common/mapobjects/trigger/hurt.qh @@ -1 +1,3 @@ #pragma once + +const int HURT_SLOW = BIT(4); diff --git a/qcsrc/common/mapobjects/trigger/jumppads.qc b/qcsrc/common/mapobjects/trigger/jumppads.qc index 5ffdf2d10..ca1faeaf9 100644 --- a/qcsrc/common/mapobjects/trigger/jumppads.qc +++ b/qcsrc/common/mapobjects/trigger/jumppads.qc @@ -133,9 +133,20 @@ bool jumppad_push(entity this, entity targ) if (!isPushable(targ)) return false; + vector org = targ.origin; +#ifdef SVQC + if(autocvar_sv_vq3compat) +#elif defined(CSQC) + if(STAT(VQ3COMPAT)) +#endif + { + org.z += targ.mins_z; + org.z += 1; // off by 1! + } + if(this.enemy) { - targ.velocity = trigger_push_calculatevelocity(targ.origin, this.enemy, this.height, targ); + targ.velocity = trigger_push_calculatevelocity(org, this.enemy, this.height, targ); } else if(this.target && this.target != "") { @@ -148,7 +159,7 @@ bool jumppad_push(entity this, entity targ) else RandomSelection_AddEnt(e, 1, 1); } - targ.velocity = trigger_push_calculatevelocity(targ.origin, RandomSelection_chosen_ent, this.height, targ); + targ.velocity = trigger_push_calculatevelocity(org, RandomSelection_chosen_ent, this.height, targ); } else { diff --git a/qcsrc/common/mapobjects/trigger/keylock.qc b/qcsrc/common/mapobjects/trigger/keylock.qc index 67db14421..f7ecd7c1f 100644 --- a/qcsrc/common/mapobjects/trigger/keylock.qc +++ b/qcsrc/common/mapobjects/trigger/keylock.qc @@ -30,7 +30,14 @@ void trigger_keylock_touch(entity this, entity toucher) // check silver key if(this.itemkeys) - key_used = item_keys_usekey(this, toucher); + { +#ifdef SVQC + entity store = PS(toucher); +#elif defined(CSQC) + entity store = toucher; +#endif + key_used = item_keys_usekey(this, store); + } if(this.itemkeys) { diff --git a/qcsrc/common/mapobjects/trigger/keylock.qh b/qcsrc/common/mapobjects/trigger/keylock.qh index 904c3fa3d..6f70f09be 100644 --- a/qcsrc/common/mapobjects/trigger/keylock.qh +++ b/qcsrc/common/mapobjects/trigger/keylock.qh @@ -1,10 +1 @@ #pragma once - -#ifdef CSQC -bool item_keys_usekey(entity l, entity p) -{ - int valid = (l.itemkeys & p.itemkeys); // TODO: itemkeys isn't networked or anything! - l.itemkeys &= ~valid; // only some of the needed keys were given - return valid != 0; -} -#endif diff --git a/qcsrc/common/mapobjects/triggers.qc b/qcsrc/common/mapobjects/triggers.qc index c7ed6643d..6a2095999 100644 --- a/qcsrc/common/mapobjects/triggers.qc +++ b/qcsrc/common/mapobjects/triggers.qc @@ -1,7 +1,4 @@ #include "triggers.qh" -#ifdef SVQC - #include -#endif void SUB_DontUseTargets(entity this, entity actor, entity trigger) { } diff --git a/qcsrc/common/monsters/monster/spider.qc b/qcsrc/common/monsters/monster/spider.qc index 5e2cc0513..d847cf4e6 100644 --- a/qcsrc/common/monsters/monster/spider.qc +++ b/qcsrc/common/monsters/monster/spider.qc @@ -168,9 +168,9 @@ void M_Spider_Attack_Web(entity this) bool M_Spider_Attack(int attack_type, entity actor, entity targ, .entity weaponentity) { + Weapon wep = WEP_SPIDER_ATTACK; switch(attack_type) { - Weapon wep = WEP_SPIDER_ATTACK; case MONSTER_ATTACK_MELEE: { wep.wr_think(wep, actor, weaponentity, 2); diff --git a/qcsrc/common/monsters/sv_monsters.qc b/qcsrc/common/monsters/sv_monsters.qc index 84355c7f3..f30c5974a 100644 --- a/qcsrc/common/monsters/sv_monsters.qc +++ b/qcsrc/common/monsters/sv_monsters.qc @@ -695,7 +695,6 @@ void Monster_CalculateVelocity(entity this, vector to, vector from, float turnra } .entity draggedby; -.entity target2; void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed) { diff --git a/qcsrc/common/mutators/mutator/damagetext/sv_damagetext.qc b/qcsrc/common/mutators/mutator/damagetext/sv_damagetext.qc index d9eacaae0..0e0aa13fd 100644 --- a/qcsrc/common/mutators/mutator/damagetext/sv_damagetext.qc +++ b/qcsrc/common/mutators/mutator/damagetext/sv_damagetext.qc @@ -10,12 +10,12 @@ REGISTER_MUTATOR(damagetext, true); #define SV_DAMAGETEXT_ALL() (autocvar_sv_damagetext >= 3) MUTATOR_HOOKFUNCTION(damagetext, PlayerDamaged) { if (SV_DAMAGETEXT_DISABLED()) return; - const entity attacker = M_ARGV(0, entity); - const entity hit = M_ARGV(1, entity); if (hit == attacker) return; - const float health = M_ARGV(2, float); - const float armor = M_ARGV(3, float); - const int deathtype = M_ARGV(5, int); - const float potential_damage = M_ARGV(6, float); + entity attacker = M_ARGV(0, entity); + entity hit = M_ARGV(1, entity); if (hit == attacker) return; + float health = M_ARGV(2, float); + float armor = M_ARGV(3, float); + int deathtype = M_ARGV(5, int); + float potential_damage = M_ARGV(6, float); if(DEATH_WEAPONOF(deathtype) == WEP_VAPORIZER) return; FOREACH_CLIENT(IS_REAL_CLIENT(it), { if ( diff --git a/qcsrc/common/mutators/mutator/dynamic_handicap/sv_dynamic_handicap.qc b/qcsrc/common/mutators/mutator/dynamic_handicap/sv_dynamic_handicap.qc index d5d3ba40f..4cfc0dd23 100644 --- a/qcsrc/common/mutators/mutator/dynamic_handicap/sv_dynamic_handicap.qc +++ b/qcsrc/common/mutators/mutator/dynamic_handicap/sv_dynamic_handicap.qc @@ -32,13 +32,13 @@ float DynamicHandicap_ClampHandicap(float handicap); void DynamicHandicap_UpdateHandicap() { float total_score = 0; - float total_players = 0; + float totalplayers = 0; FOREACH_CLIENT(IS_PLAYER(it), { total_score += PlayerScore_Get(it, SP_SCORE); - ++total_players; + ++totalplayers; }); - float mean_score = total_score / total_players; + float mean_score = total_score / totalplayers; FOREACH_CLIENT(true, { float score = PlayerScore_Get(it, SP_SCORE); diff --git a/qcsrc/common/mutators/mutator/overkill/okshotgun.qc b/qcsrc/common/mutators/mutator/overkill/okshotgun.qc index 2f1651776..d8c79e3f2 100644 --- a/qcsrc/common/mutators/mutator/overkill/okshotgun.qc +++ b/qcsrc/common/mutators/mutator/overkill/okshotgun.qc @@ -45,7 +45,7 @@ METHOD(OverkillShotgun, wr_think, void(entity thiswep, entity actor, .entity wea } if (fire & 1) // Primary attack { - if (!weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(okshotgun, animtime))) + if (!weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(okshotgun, refire))) { return; } diff --git a/qcsrc/common/notifications/all.inc b/qcsrc/common/notifications/all.inc index 7cb218412..1b93cbf35 100644 --- a/qcsrc/common/notifications/all.inc +++ b/qcsrc/common/notifications/all.inc @@ -1005,9 +1005,9 @@ #define A_ALWAYS 2 // MSG_CHOICE_NOTIFICATIONS - MULTITEAM_CHOICE(CTF_CAPTURE_BROKEN, 4, N__NORMAL, A_ALWAYS, MSG_INFO, INFO_CTF_CAPTURE, INFO_CTF_CAPTURE_BROKEN) - MULTITEAM_CHOICE(CTF_CAPTURE_TIME, 4, N__NORMAL, A_ALWAYS, MSG_INFO, INFO_CTF_CAPTURE, INFO_CTF_CAPTURE_TIME) - MULTITEAM_CHOICE(CTF_CAPTURE_UNBROKEN, 4, N__NORMAL, A_ALWAYS, MSG_INFO, INFO_CTF_CAPTURE, INFO_CTF_CAPTURE_UNBROKEN) + MULTITEAM_CHOICE(CTF_CAPTURE_BROKEN, 4, N_VERBOSE, A_ALWAYS, MSG_INFO, INFO_CTF_CAPTURE, INFO_CTF_CAPTURE_BROKEN) + MULTITEAM_CHOICE(CTF_CAPTURE_TIME, 4, N_VERBOSE, A_ALWAYS, MSG_INFO, INFO_CTF_CAPTURE, INFO_CTF_CAPTURE_TIME) + MULTITEAM_CHOICE(CTF_CAPTURE_UNBROKEN, 4, N_VERBOSE, A_ALWAYS, MSG_INFO, INFO_CTF_CAPTURE, INFO_CTF_CAPTURE_UNBROKEN) MULTITEAM_CHOICE(CTF_PICKUP_TEAM, 4, N__NORMAL, A_ALWAYS, MSG_CENTER, CENTER_CTF_PICKUP_TEAM, CENTER_CTF_PICKUP_TEAM_VERBOSE) MSG_CHOICE_NOTIF(CTF_PICKUP_TEAM_NEUTRAL, N__NORMAL, A_ALWAYS, MSG_CENTER, CENTER_CTF_PICKUP_TEAM_NEUTRAL, CENTER_CTF_PICKUP_TEAM_VERBOSE_NEUTRAL) MSG_CHOICE_NOTIF(CTF_PICKUP_ENEMY, N__NORMAL, A_ALWAYS, MSG_CENTER, CENTER_CTF_PICKUP_ENEMY, CENTER_CTF_PICKUP_ENEMY_VERBOSE) diff --git a/qcsrc/common/physics/movetypes/movetypes.qc b/qcsrc/common/physics/movetypes/movetypes.qc index 9ac3e4299..e518fe210 100644 --- a/qcsrc/common/physics/movetypes/movetypes.qc +++ b/qcsrc/common/physics/movetypes/movetypes.qc @@ -232,6 +232,9 @@ int _Movetype_FlyMove(entity this, float dt, bool applygravity, vector stepnorma if(GAMEPLAYFIX_EASIERWATERJUMP(this) && (this.flags & FL_WATERJUMP) && !(blocked & 8)) this.velocity = primal_velocity; + if(PHYS_WALLCLIP(this) && this.pm_time && !(this.flags & FL_WATERJUMP) && !(blocked & 8)) + this.velocity = primal_velocity; + if(applygravity) { if(!GAMEPLAYFIX_NOGRAVITYONGROUND || !IS_ONGROUND(this)) diff --git a/qcsrc/common/physics/movetypes/movetypes.qh b/qcsrc/common/physics/movetypes/movetypes.qh index 85912ee1c..20f9adba1 100644 --- a/qcsrc/common/physics/movetypes/movetypes.qh +++ b/qcsrc/common/physics/movetypes/movetypes.qh @@ -26,6 +26,8 @@ const int WATERLEVEL_SUBMERGED = 3; #define PHYS_JUMPSTEP(s) STAT(MOVEVARS_JUMPSTEP) #define PHYS_WALLFRICTION(s) STAT(MOVEVARS_WALLFRICTION) +#define PHYS_WALLCLIP(s) STAT(MOVEVARS_WALLCLIP) + #ifdef CSQC .float bouncestop; .float bouncefactor; @@ -55,6 +57,8 @@ const int WATERLEVEL_SUBMERGED = 3; void set_movetype(entity this, int mt); +.float pm_time; + .float move_movetype; .float move_time; //.vector move_origin; diff --git a/qcsrc/common/physics/movetypes/walk.qc b/qcsrc/common/physics/movetypes/walk.qc index c20e82e83..6e4c548d6 100644 --- a/qcsrc/common/physics/movetypes/walk.qc +++ b/qcsrc/common/physics/movetypes/walk.qc @@ -20,6 +20,14 @@ void _Movetype_Physics_Walk(entity this, float dt) // SV_WalkMove vector start_origin = this.origin; vector start_velocity = this.velocity; + if(PHYS_WALLCLIP(this) && this.pm_time) + { + if(dt >= this.pm_time || (this.flags & FL_WATERJUMP)) + this.pm_time = 0; + else + this.pm_time -= dt; + } + int clip = _Movetype_FlyMove(this, dt, applygravity, stepnormal, GAMEPLAYFIX_STEPMULTIPLETIMES(this) ? PHYS_STEPHEIGHT(this) : 0); if (GAMEPLAYFIX_DOWNTRACEONGROUND(this) && !(clip & 1)) @@ -45,6 +53,8 @@ void _Movetype_Physics_Walk(entity this, float dt) // SV_WalkMove // if the move did not hit the ground at any point, we're not on ground if (!(clip & 1)) UNSET_ONGROUND(this); + else if(PHYS_WALLCLIP(this) && !this.groundentity && (PHYS_WALLCLIP(this) == 2 || start_velocity.z < -200)) // don't do landing time if we were just going down a slope + this.pm_time = 0.25; _Movetype_CheckVelocity(this); _Movetype_LinkEdict(this, true); @@ -144,7 +154,8 @@ void _Movetype_Physics_Walk(entity this, float dt) // SV_WalkMove } // move down - vector downmove = '0 0 1' * (-PHYS_STEPHEIGHT(this) + start_velocity.z * dt); + vector downmove = '0 0 0'; + downmove.z = -PHYS_STEPHEIGHT(this) + start_velocity.z * dt; _Movetype_PushEntity(this, downmove, true); if(wasfreed(this)) return; diff --git a/qcsrc/common/state.qc b/qcsrc/common/state.qc index 772dbccbd..2e3a262a5 100644 --- a/qcsrc/common/state.qc +++ b/qcsrc/common/state.qc @@ -7,7 +7,7 @@ void PlayerState_attach(entity this) { this._ps = NEW(PlayerState, this); - Inventory_new(this); + Inventory_new(PS(this)); } void PlayerState_detach(entity this) @@ -18,11 +18,10 @@ void PlayerState_detach(entity this) if (ps.m_client != this) return; // don't own state, spectator ps.ps_push(ps, this); + Inventory_delete(ps); FOREACH_CLIENT(PS(it) == ps, { PS(it) = NULL; }); delete(ps); - - Inventory_delete(this); } void GetCvars(entity this, entity store, int); diff --git a/qcsrc/common/stats.qh b/qcsrc/common/stats.qh index 9b8f04041..cf51ea66b 100644 --- a/qcsrc/common/stats.qh +++ b/qcsrc/common/stats.qh @@ -301,6 +301,11 @@ bool autocvar_sv_slick_applygravity; #endif REGISTER_STAT(SLICK_APPLYGRAVITY, bool, autocvar_sv_slick_applygravity) +#ifdef SVQC +bool autocvar_sv_vq3compat; +#endif +REGISTER_STAT(VQ3COMPAT, bool, autocvar_sv_vq3compat) + #ifdef SVQC #include "physics/movetypes/movetypes.qh" float warmup_limit; @@ -360,6 +365,10 @@ REGISTER_STAT(MOVEVARS_STEPHEIGHT, float, autocvar_sv_stepheight) REGISTER_STAT(MOVEVARS_AIRACCEL_QW, float) REGISTER_STAT(MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION, float) REGISTER_STAT(MOVEVARS_SPECIALCOMMAND, bool) +#ifdef SVQC +int autocvar_sv_wallclip; +#endif +REGISTER_STAT(MOVEVARS_WALLCLIP, int, autocvar_sv_wallclip) #ifdef CSQC diff --git a/qcsrc/common/turrets/sv_turrets.qc b/qcsrc/common/turrets/sv_turrets.qc index d3994fd83..4962ddbe6 100644 --- a/qcsrc/common/turrets/sv_turrets.qc +++ b/qcsrc/common/turrets/sv_turrets.qc @@ -731,18 +731,17 @@ float turret_validate_target(entity e_turret, entity e_target, float validate_fl return -5; // Cant touch this + if (GetResourceAmount(e_target, RESOURCE_HEALTH) <= 0) + return -6; + else if(STAT(FROZEN, e_target) > 0) + return -6; + + // vehicle if(IS_VEHICLE(e_target)) { - if (e_target.vehicle_health <= 0) - return -6; - if ((validate_flags & TFL_TARGETSELECT_VEHICLES) && !e_target.owner) return -7; } - else if (GetResourceAmount(e_target, RESOURCE_HEALTH) <= 0) - return -6; - else if(STAT(FROZEN, e_target) > 0) - return -6; // player if (IS_CLIENT(e_target)) diff --git a/qcsrc/common/vehicles/sv_vehicles.qc b/qcsrc/common/vehicles/sv_vehicles.qc index 716dfe8d0..2f5e8e46b 100644 --- a/qcsrc/common/vehicles/sv_vehicles.qc +++ b/qcsrc/common/vehicles/sv_vehicles.qc @@ -385,7 +385,7 @@ bool vehicle_addplayerslot( entity _owner, vector vehicle_aimturret(entity _vehic, vector _target, entity _turrret, string _tagname, float _pichlimit_min, float _pichlimit_max, - float _rotlimit_min, float _rotlimit_max, float _aimspeed) + float _rotlimit_min, float _rotlimit_max, float _aimspeed, float dt) { vector vtmp, vtag; float ftmp; @@ -393,7 +393,7 @@ vector vehicle_aimturret(entity _vehic, vector _target, entity _turrret, string vtmp = vectoangles(normalize(_target - vtag)); vtmp = AnglesTransform_ToAngles(AnglesTransform_LeftDivide(AnglesTransform_FromAngles(_vehic.angles), AnglesTransform_FromAngles(vtmp))) - _turrret.angles; vtmp = AnglesTransform_Normalize(vtmp, true); - ftmp = _aimspeed * frametime; + ftmp = _aimspeed * dt; vtmp_y = bound(-ftmp, vtmp_y, ftmp); vtmp_x = bound(-ftmp, vtmp_x, ftmp); _turrret.angles_y = bound(_rotlimit_min, _turrret.angles_y + vtmp_y, _rotlimit_max); @@ -587,7 +587,7 @@ void vehicles_regen(entity this, float timer, .float regen_field, float field_ma if(timer + rpause < time) { if(_healthscale) - regen = regen * (this.vehicle_health / this.max_health); + regen = regen * (GetResourceAmount(this, RESOURCE_HEALTH) / this.max_health); this.(regen_field) = min(this.(regen_field) + regen * delta_time, field_max); @@ -596,6 +596,23 @@ void vehicles_regen(entity this, float timer, .float regen_field, float field_ma } } +void vehicles_regen_resource(entity this, float timer, .float regen_field, float field_max, float rpause, float regen, float delta_time, float _healthscale, int resource) +{ + float resource_amount = GetResourceAmount(this, resource); + + if(resource_amount < field_max) + if(timer + rpause < time) + { + if(_healthscale) + regen = regen * (resource_amount / this.max_health); + + SetResourceAmount(this, resource, min(resource_amount + regen * delta_time, field_max)); + + if(this.owner) + this.owner.(regen_field) = (GetResourceAmount(this, resource) / field_max) * 100; + } +} + void shieldhit_think(entity this) { this.alpha -= 0.1; @@ -613,7 +630,7 @@ void shieldhit_think(entity this) void vehicles_painframe(entity this) { - int myhealth = ((this.owner) ? this.owner.vehicle_health : ((this.vehicle_health / this.max_health) * 100)); + int myhealth = ((this.owner) ? this.owner.vehicle_health : ((GetResourceAmount(this, RESOURCE_HEALTH) / this.max_health) * 100)); if(myhealth <= 50) if(this.pain_frame < time) @@ -684,7 +701,7 @@ void vehicles_damage(entity this, entity inflictor, entity attacker, float damag if(this.vehicle_shield < 0) { - this.vehicle_health -= fabs(this.vehicle_shield); + TakeResource(this, RESOURCE_HEALTH, fabs(this.vehicle_shield)); this.vehicle_shieldent.colormod = '2 0 0'; this.vehicle_shield = 0; this.vehicle_shieldent.alpha = 0.75; @@ -699,7 +716,7 @@ void vehicles_damage(entity this, entity inflictor, entity attacker, float damag } else { - this.vehicle_health -= damage; + TakeResource(this, RESOURCE_HEALTH, damage); if(sound_allowed(MSG_BROADCAST, attacker)) spamsound (this, CH_PAIN, SND_ONS_HIT2, VOL_BASE, ATTEN_NORM); // FIXME: PLACEHOLDER @@ -710,7 +727,7 @@ void vehicles_damage(entity this, entity inflictor, entity attacker, float damag else this.velocity += force; - if(this.vehicle_health <= 0) + if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0) { if(this.owner) if(this.vehicle_flags & VHF_DEATHEJECT) @@ -730,14 +747,12 @@ void vehicles_damage(entity this, entity inflictor, entity attacker, float damag bool vehicles_heal(entity targ, entity inflictor, float amount, float limit) { float true_limit = ((limit != RESOURCE_LIMIT_NONE) ? limit : targ.max_health); - //if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0 || GetResourceAmount(targ, RESOURCE_HEALTH) >= true_limit) - if(targ.vehicle_health <= 0 || targ.vehicle_health >= true_limit) + if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0 || GetResourceAmount(targ, RESOURCE_HEALTH) >= true_limit) return false; - targ.vehicle_health = min(targ.vehicle_health + amount, true_limit); - //GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit); - //if(targ.owner) - //targ.owner.vehicle_health = (targ.vehicle_health / targ.max_health) * 100; + GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit); + if(targ.owner) + targ.owner.vehicle_health = (GetResourceAmount(targ, RESOURCE_HEALTH) / targ.max_health) * 100; return true; } diff --git a/qcsrc/common/vehicles/sv_vehicles.qh b/qcsrc/common/vehicles/sv_vehicles.qh index 0cc9da56e..a1f23c1df 100644 --- a/qcsrc/common/vehicles/sv_vehicles.qh +++ b/qcsrc/common/vehicles/sv_vehicles.qh @@ -45,7 +45,7 @@ float autocvar_g_vehicles_weapon_damagerate = 2; .entity gunner1; .entity gunner2; -.float vehicle_health = _STAT(VEHICLESTAT_HEALTH); /// If ent is player this is 0..100 indicating precentage of health left on vehicle. If ent is vehicle, this is the real health value. +.float vehicle_health = _STAT(VEHICLESTAT_HEALTH); /// If ent is player this is 0..100 indicating precentage of health left on vehicle. Vehicle's value is the health resource .float vehicle_energy = _STAT(VEHICLESTAT_ENERGY); /// If ent is player this is 0..100 indicating precentage of energy left on vehicle. If ent is vehicle, this is the real energy value. .float vehicle_shield = _STAT(VEHICLESTAT_SHIELD); /// If ent is player this is 0..100 indicating precentage of shield left on vehicle. If ent is vehicle, this is the real shield value. @@ -99,6 +99,9 @@ float vehicles_exit_running; #define VEHICLE_UPDATE_PLAYER(ply,vehi,fld,vhname) \ ply.vehicle_##fld = (vehi.vehicle_##fld / autocvar_g_vehicle_##vhname##_##fld) * 100 +#define VEHICLE_UPDATE_PLAYER_RESOURCE(ply,vehi,fld,vhname,res) \ + ply.vehicle_##fld = (GetResourceAmount(vehi, res) / autocvar_g_vehicle_##vhname##_##fld) * 100 + .float vehicle_enter_delay; // prevent players jumping to and from vehicles instantly void vehicles_exit(entity vehic, int eject); diff --git a/qcsrc/common/vehicles/vehicle/bumblebee.qc b/qcsrc/common/vehicles/vehicle/bumblebee.qc index c340d9470..84f5e144b 100644 --- a/qcsrc/common/vehicles/vehicle/bumblebee.qc +++ b/qcsrc/common/vehicles/vehicle/bumblebee.qc @@ -33,9 +33,9 @@ float autocvar_g_vehicle_bumblebee_cannon_ammo = 100; float autocvar_g_vehicle_bumblebee_cannon_ammo_regen = 100; float autocvar_g_vehicle_bumblebee_cannon_ammo_regen_pause = 1; -float autocvar_g_vehicle_bumblebee_cannon_lock = 0; +float autocvar_g_vehicle_bumblebee_cannon_lock = 1; -float autocvar_g_vehicle_bumblebee_cannon_turnspeed = 160; +float autocvar_g_vehicle_bumblebee_cannon_turnspeed = 260; float autocvar_g_vehicle_bumblebee_cannon_pitchlimit_down = 60; float autocvar_g_vehicle_bumblebee_cannon_pitchlimit_up = 60; float autocvar_g_vehicle_bumblebee_cannon_turnlimit_in = 20; @@ -105,20 +105,28 @@ bool bumblebee_gunner_frame(entity this, float dt) if(autocvar_g_vehicle_bumblebee_cannon_lock) { - if(gun.lock_time < time) + if(gun.lock_time < time || IS_DEAD(gun.enemy) || STAT(FROZEN, gun.enemy)) gun.enemy = NULL; if(trace_ent) - if(trace_ent.move_movetype) - if(trace_ent.takedamage) - if(!IS_DEAD(trace_ent) && !STAT(FROZEN, trace_ent)) - { - if(DIFF_TEAM(trace_ent, this)) - { - gun.enemy = trace_ent; - gun.lock_time = time + 5; - } - } + if(trace_ent.move_movetype) + if(trace_ent.takedamage) + if(!IS_DEAD(trace_ent) && !STAT(FROZEN, trace_ent)) + { + if(teamplay) + { + if(DIFF_TEAM(trace_ent, this)) + { + gun.enemy = trace_ent; + gun.lock_time = time + 2.5; + } + } + else + { + gun.enemy = trace_ent; + gun.lock_time = time + 0.5; + } + } } if(gun.enemy) @@ -141,13 +149,13 @@ bool bumblebee_gunner_frame(entity this, float dt) UpdateAuxiliaryXhair(this, ad, '1 0 1', 1); vehicle_aimturret(vehic, trace_endpos, gun, "fire", autocvar_g_vehicle_bumblebee_cannon_pitchlimit_down * -1, autocvar_g_vehicle_bumblebee_cannon_pitchlimit_up, - _out * -1, _in, autocvar_g_vehicle_bumblebee_cannon_turnspeed); + _out * -1, _in, autocvar_g_vehicle_bumblebee_cannon_turnspeed, dt); } else vehicle_aimturret(vehic, _ct, gun, "fire", autocvar_g_vehicle_bumblebee_cannon_pitchlimit_down * -1, autocvar_g_vehicle_bumblebee_cannon_pitchlimit_up, - _out * -1, _in, autocvar_g_vehicle_bumblebee_cannon_turnspeed); + _out * -1, _in, autocvar_g_vehicle_bumblebee_cannon_turnspeed, dt); if(!forbidWeaponUse(this)) if(PHYS_INPUT_BUTTON_ATCK(this)) @@ -160,7 +168,7 @@ bool bumblebee_gunner_frame(entity this, float dt) gun.attack_finished_single[0] = time + autocvar_g_vehicle_bumblebee_cannon_refire; } - VEHICLE_UPDATE_PLAYER(this, vehic, health, bumblebee); + VEHICLE_UPDATE_PLAYER_RESOURCE(this, vehic, health, bumblebee, RESOURCE_HEALTH); if(vehic.vehicle_flags & VHF_HASSHIELD) VEHICLE_UPDATE_PLAYER(this, vehic, shield, bumblebee); @@ -389,7 +397,7 @@ void bumblebee_regen(entity this, float dt) vehicles_regen(this, this.dmg_time, vehicle_shield, autocvar_g_vehicle_bumblebee_shield, autocvar_g_vehicle_bumblebee_shield_regen_pause, autocvar_g_vehicle_bumblebee_shield_regen, dt, true); if(this.vehicle_flags & VHF_HEALTHREGEN) - vehicles_regen(this, this.dmg_time, vehicle_health, autocvar_g_vehicle_bumblebee_health, autocvar_g_vehicle_bumblebee_health_regen_pause, autocvar_g_vehicle_bumblebee_health_regen, dt, false); + vehicles_regen_resource(this, this.dmg_time, vehicle_health, autocvar_g_vehicle_bumblebee_health, autocvar_g_vehicle_bumblebee_health_regen_pause, autocvar_g_vehicle_bumblebee_health_regen, dt, false, RESOURCE_HEALTH); if(this.vehicle_flags & VHF_ENERGYREGEN) vehicles_regen(this, this.wait, vehicle_energy, autocvar_g_vehicle_bumblebee_energy, autocvar_g_vehicle_bumblebee_energy_regen_pause, autocvar_g_vehicle_bumblebee_energy_regen, dt, false); @@ -521,7 +529,7 @@ bool bumblebee_pilot_frame(entity this, float dt) vang = vehicle_aimturret(vehic, trace_endpos, vehic.gun3, "fire", autocvar_g_vehicle_bumblebee_raygun_pitchlimit_down * -1, autocvar_g_vehicle_bumblebee_raygun_pitchlimit_up, - autocvar_g_vehicle_bumblebee_raygun_turnlimit_sides * -1, autocvar_g_vehicle_bumblebee_raygun_turnlimit_sides, autocvar_g_vehicle_bumblebee_raygun_turnspeed); + autocvar_g_vehicle_bumblebee_raygun_turnlimit_sides * -1, autocvar_g_vehicle_bumblebee_raygun_turnlimit_sides, autocvar_g_vehicle_bumblebee_raygun_turnspeed, dt); if(!forbidWeaponUse(this)) if((PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_ATCK2(this)) && (vehic.vehicle_energy > autocvar_g_vehicle_bumblebee_raygun_dps * PHYS_INPUT_FRAMETIME || autocvar_g_vehicle_bumblebee_raygun == 0)) @@ -555,7 +563,7 @@ bool bumblebee_pilot_frame(entity this, float dt) if(IS_VEHICLE(trace_ent)) { - if(autocvar_g_vehicle_bumblebee_healgun_sps && trace_ent.vehicle_health <= trace_ent.max_health) + if(autocvar_g_vehicle_bumblebee_healgun_sps && GetResourceAmount(trace_ent, RESOURCE_HEALTH) <= trace_ent.max_health) trace_ent.vehicle_shield = min(trace_ent.vehicle_shield + autocvar_g_vehicle_bumblebee_healgun_sps * dt, trace_ent.tur_head.max_health); } else if(IS_CLIENT(trace_ent)) @@ -584,7 +592,7 @@ bool bumblebee_pilot_frame(entity this, float dt) } */ - VEHICLE_UPDATE_PLAYER(this, vehic, health, bumblebee); + VEHICLE_UPDATE_PLAYER_RESOURCE(this, vehic, health, bumblebee, RESOURCE_HEALTH); VEHICLE_UPDATE_PLAYER(this, vehic, energy, bumblebee); this.vehicle_ammo1 = (vehic.gun1.vehicle_energy / autocvar_g_vehicle_bumblebee_cannon_ammo) * 100; @@ -879,7 +887,7 @@ METHOD(Bumblebee, vr_spawn, void(Bumblebee thisveh, entity instance)) if(!autocvar_g_vehicle_bumblebee_swim) instance.dphitcontentsmask |= DPCONTENTS_LIQUIDSMASK; - instance.vehicle_health = autocvar_g_vehicle_bumblebee_health; + SetResourceAmountExplicit(instance, RESOURCE_HEALTH, autocvar_g_vehicle_bumblebee_health); instance.vehicle_shield = autocvar_g_vehicle_bumblebee_shield; instance.solid = SOLID_BBOX; set_movetype(instance, MOVETYPE_TOSS); @@ -906,8 +914,8 @@ METHOD(Bumblebee, vr_setup, void(Bumblebee thisveh, entity instance)) instance.vehicle_exit = bumblebee_exit; instance.respawntime = autocvar_g_vehicle_bumblebee_respawntime; - instance.vehicle_health = autocvar_g_vehicle_bumblebee_health; - instance.max_health = instance.vehicle_health; + SetResourceAmountExplicit(instance, RESOURCE_HEALTH, autocvar_g_vehicle_bumblebee_health); + instance.max_health = GetResourceAmount(instance, RESOURCE_HEALTH); instance.vehicle_shield = autocvar_g_vehicle_bumblebee_shield; } @@ -930,7 +938,7 @@ METHOD(Bumblebee, vr_hud, void(Bumblebee thisveh)) float hudAlpha = autocvar_hud_panel_fg_alpha; float blinkValue = 0.55 + sin(time * 7) * 0.45; vector tmpPos = '0 0 0'; - vector tmpSize = '1 1 1' * hud_fontsize; + vector tmpSize = hud_fontsize; tmpPos.x = vehicleHud_Pos.x + vehicleHud_Size.x * (520/768); if(!AuxiliaryXhair[1].draw2d) diff --git a/qcsrc/common/vehicles/vehicle/bumblebee_weapons.qh b/qcsrc/common/vehicles/vehicle/bumblebee_weapons.qh index e9c5bf41d..f6909fb42 100644 --- a/qcsrc/common/vehicles/vehicle/bumblebee_weapons.qh +++ b/qcsrc/common/vehicles/vehicle/bumblebee_weapons.qh @@ -8,7 +8,7 @@ float autocvar_g_vehicle_bumblebee_cannon_damage = 60; float autocvar_g_vehicle_bumblebee_cannon_radius = 225; float autocvar_g_vehicle_bumblebee_cannon_refire = 0.2; float autocvar_g_vehicle_bumblebee_cannon_speed = 20000; -float autocvar_g_vehicle_bumblebee_cannon_spread = 0.02; +float autocvar_g_vehicle_bumblebee_cannon_spread = 0; float autocvar_g_vehicle_bumblebee_cannon_force = -35; #endif diff --git a/qcsrc/common/vehicles/vehicle/racer.qc b/qcsrc/common/vehicles/vehicle/racer.qc index 18e13bcbb..c7f7af8ac 100644 --- a/qcsrc/common/vehicles/vehicle/racer.qc +++ b/qcsrc/common/vehicles/vehicle/racer.qc @@ -359,12 +359,12 @@ bool racer_frame(entity this, float dt) vehicles_regen(vehic, vehic.dmg_time, vehicle_shield, autocvar_g_vehicle_racer_shield, autocvar_g_vehicle_racer_shield_regen_pause, autocvar_g_vehicle_racer_shield_regen, dt, true); if(vehic.vehicle_flags & VHF_HEALTHREGEN) - vehicles_regen(vehic, vehic.dmg_time, vehicle_health, autocvar_g_vehicle_racer_health, autocvar_g_vehicle_racer_health_regen_pause, autocvar_g_vehicle_racer_health_regen, dt, false); + vehicles_regen_resource(vehic, vehic.dmg_time, vehicle_health, autocvar_g_vehicle_racer_health, autocvar_g_vehicle_racer_health_regen_pause, autocvar_g_vehicle_racer_health_regen, dt, false, RESOURCE_HEALTH); if(vehic.vehicle_flags & VHF_ENERGYREGEN) vehicles_regen(vehic, vehic.wait, vehicle_energy, autocvar_g_vehicle_racer_energy, autocvar_g_vehicle_racer_energy_regen_pause, autocvar_g_vehicle_racer_energy_regen, dt, false); - VEHICLE_UPDATE_PLAYER(player, vehic, health, racer); + VEHICLE_UPDATE_PLAYER_RESOURCE(player, vehic, health, racer, RESOURCE_HEALTH); VEHICLE_UPDATE_PLAYER(player, vehic, energy, racer); if(vehic.vehicle_flags & VHF_HASSHIELD) @@ -514,7 +514,7 @@ METHOD(Racer, vr_enter, void(Racer thisveh, entity instance)) { #ifdef SVQC set_movetype(instance, MOVETYPE_BOUNCE); - instance.owner.vehicle_health = (instance.vehicle_health / autocvar_g_vehicle_racer_health) * 100; + instance.owner.vehicle_health = (GetResourceAmount(instance, RESOURCE_HEALTH) / autocvar_g_vehicle_racer_health) * 100; instance.owner.vehicle_shield = (instance.vehicle_shield / autocvar_g_vehicle_racer_shield) * 100; if(instance.owner.flagcarried) @@ -544,7 +544,7 @@ METHOD(Racer, vr_spawn, void(Racer thisveh, entity instance)) setthink(instance, racer_think); instance.nextthink = time; - instance.vehicle_health = autocvar_g_vehicle_racer_health; + SetResourceAmountExplicit(instance, RESOURCE_HEALTH, autocvar_g_vehicle_racer_health); instance.vehicle_shield = autocvar_g_vehicle_racer_shield; set_movetype(instance, MOVETYPE_TOSS); @@ -557,7 +557,7 @@ METHOD(Racer, vr_spawn, void(Racer thisveh, entity instance)) instance.bouncefactor = autocvar_g_vehicle_racer_bouncefactor; instance.bouncestop = autocvar_g_vehicle_racer_bouncestop; instance.damageforcescale = 0.5; - instance.vehicle_health = autocvar_g_vehicle_racer_health; + SetResourceAmountExplicit(instance, RESOURCE_HEALTH, autocvar_g_vehicle_racer_health); instance.vehicle_shield = autocvar_g_vehicle_racer_shield; #endif } @@ -625,9 +625,9 @@ METHOD(Racer, vr_setup, void(Racer thisveh, entity instance)) instance.vehicle_flags |= VHF_HEALTHREGEN; instance.respawntime = autocvar_g_vehicle_racer_respawntime; - instance.vehicle_health = autocvar_g_vehicle_racer_health; + SetResourceAmountExplicit(instance, RESOURCE_HEALTH, autocvar_g_vehicle_racer_health); instance.vehicle_shield = autocvar_g_vehicle_racer_shield; - instance.max_health = instance.vehicle_health; + instance.max_health = GetResourceAmount(instance, RESOURCE_HEALTH); #endif #ifdef CSQC diff --git a/qcsrc/common/vehicles/vehicle/raptor.qc b/qcsrc/common/vehicles/vehicle/raptor.qc index f44dcc578..0150ee98f 100644 --- a/qcsrc/common/vehicles/vehicle/raptor.qc +++ b/qcsrc/common/vehicles/vehicle/raptor.qc @@ -343,11 +343,11 @@ bool raptor_frame(entity this, float dt) vehicle_aimturret(vehic, trace_endpos, vehic.gun1, "fire1", autocvar_g_vehicle_raptor_cannon_pitchlimit_down * -1, autocvar_g_vehicle_raptor_cannon_pitchlimit_up, - autocvar_g_vehicle_raptor_cannon_turnlimit * -1, autocvar_g_vehicle_raptor_cannon_turnlimit, autocvar_g_vehicle_raptor_cannon_turnspeed); + autocvar_g_vehicle_raptor_cannon_turnlimit * -1, autocvar_g_vehicle_raptor_cannon_turnlimit, autocvar_g_vehicle_raptor_cannon_turnspeed, dt); vehicle_aimturret(vehic, trace_endpos, vehic.gun2, "fire1", autocvar_g_vehicle_raptor_cannon_pitchlimit_down * -1, autocvar_g_vehicle_raptor_cannon_pitchlimit_up, - autocvar_g_vehicle_raptor_cannon_turnlimit * -1, autocvar_g_vehicle_raptor_cannon_turnlimit, autocvar_g_vehicle_raptor_cannon_turnspeed); + autocvar_g_vehicle_raptor_cannon_turnlimit * -1, autocvar_g_vehicle_raptor_cannon_turnlimit, autocvar_g_vehicle_raptor_cannon_turnspeed, dt); /* ad = ad * 0.5; @@ -369,7 +369,7 @@ bool raptor_frame(entity this, float dt) vehicles_regen(vehic, vehic.dmg_time, vehicle_shield, autocvar_g_vehicle_raptor_shield, autocvar_g_vehicle_raptor_shield_regen_pause, autocvar_g_vehicle_raptor_shield_regen, dt, true); if(vehic.vehicle_flags & VHF_HEALTHREGEN) - vehicles_regen(vehic, vehic.dmg_time, vehicle_health, autocvar_g_vehicle_raptor_health, autocvar_g_vehicle_raptor_health_regen_pause, autocvar_g_vehicle_raptor_health_regen, dt, false); + vehicles_regen_resource(vehic, vehic.dmg_time, vehicle_health, autocvar_g_vehicle_raptor_health, autocvar_g_vehicle_raptor_health_regen_pause, autocvar_g_vehicle_raptor_health_regen, dt, false, RESOURCE_HEALTH); if(vehic.vehicle_flags & VHF_ENERGYREGEN) vehicles_regen(vehic, vehic.cnt, vehicle_energy, autocvar_g_vehicle_raptor_energy, autocvar_g_vehicle_raptor_energy_regen_pause, autocvar_g_vehicle_raptor_energy_regen, dt, false); @@ -427,7 +427,7 @@ bool raptor_frame(entity this, float dt) } - VEHICLE_UPDATE_PLAYER(this, vehic, health, raptor); + VEHICLE_UPDATE_PLAYER_RESOURCE(this, vehic, health, raptor, RESOURCE_HEALTH); VEHICLE_UPDATE_PLAYER(this, vehic, energy, raptor); if(vehic.vehicle_flags & VHF_HASSHIELD) VEHICLE_UPDATE_PLAYER(this, vehic, shield, raptor); @@ -471,7 +471,7 @@ bool raptor_takeoff(entity this, float dt) vehicles_regen(vehic, vehic.dmg_time, vehicle_shield, autocvar_g_vehicle_raptor_shield, autocvar_g_vehicle_raptor_shield_regen_pause, autocvar_g_vehicle_raptor_shield_regen, dt, true); if(vehic.vehicle_flags & VHF_HEALTHREGEN) - vehicles_regen(vehic, vehic.dmg_time, vehicle_health, autocvar_g_vehicle_raptor_health, autocvar_g_vehicle_raptor_health_regen_pause, autocvar_g_vehicle_raptor_health_regen, dt, false); + vehicles_regen_resource(vehic, vehic.dmg_time, vehicle_health, autocvar_g_vehicle_raptor_health, autocvar_g_vehicle_raptor_health_regen_pause, autocvar_g_vehicle_raptor_health_regen, dt, false, RESOURCE_HEALTH); if(vehic.vehicle_flags & VHF_ENERGYREGEN) vehicles_regen(vehic, vehic.cnt, vehicle_energy, autocvar_g_vehicle_raptor_energy, autocvar_g_vehicle_raptor_energy_regen_pause, autocvar_g_vehicle_raptor_energy_regen, dt, false); @@ -481,7 +481,7 @@ bool raptor_takeoff(entity this, float dt) this.vehicle_reload2 = bound(0, vehic.bomb1.alpha * 100, 100); this.vehicle_ammo2 = (this.vehicle_reload2 == 100) ? 100 : 0; - VEHICLE_UPDATE_PLAYER(this, vehic, health, raptor); + VEHICLE_UPDATE_PLAYER_RESOURCE(this, vehic, health, raptor, RESOURCE_HEALTH); VEHICLE_UPDATE_PLAYER(this, vehic, energy, raptor); if(vehic.vehicle_flags & VHF_HASSHIELD) VEHICLE_UPDATE_PLAYER(this, vehic, shield, raptor); @@ -594,7 +594,7 @@ METHOD(Raptor, vr_enter, void(Raptor thisveh, entity instance)) instance.owner.PlayerPhysplug = raptor_takeoff; set_movetype(instance, MOVETYPE_BOUNCEMISSILE); instance.solid = SOLID_SLIDEBOX; - instance.owner.vehicle_health = (instance.vehicle_health / autocvar_g_vehicle_raptor_health) * 100; + instance.owner.vehicle_health = (GetResourceAmount(instance, RESOURCE_HEALTH) / autocvar_g_vehicle_raptor_health) * 100; instance.owner.vehicle_shield = (instance.vehicle_shield / autocvar_g_vehicle_raptor_shield) * 100; instance.velocity = '0 0 1'; // nudge upwards so takeoff sequence can work instance.tur_head.exteriormodeltoclient = instance.owner; @@ -701,7 +701,7 @@ METHOD(Raptor, vr_spawn, void(Raptor thisveh, entity instance)) } instance.frame = 0; - instance.vehicle_health = autocvar_g_vehicle_raptor_health; + SetResourceAmountExplicit(instance, RESOURCE_HEALTH, autocvar_g_vehicle_raptor_health); instance.vehicle_shield = autocvar_g_vehicle_raptor_shield; set_movetype(instance, MOVETYPE_TOSS); instance.solid = SOLID_SLIDEBOX; @@ -720,7 +720,7 @@ METHOD(Raptor, vr_spawn, void(Raptor thisveh, entity instance)) instance.bouncefactor = autocvar_g_vehicle_raptor_bouncefactor; instance.bouncestop = autocvar_g_vehicle_raptor_bouncestop; instance.damageforcescale = 0.25; - instance.vehicle_health = autocvar_g_vehicle_raptor_health; + SetResourceAmountExplicit(instance, RESOURCE_HEALTH, autocvar_g_vehicle_raptor_health); instance.vehicle_shield = autocvar_g_vehicle_raptor_shield; } METHOD(Raptor, vr_setup, void(Raptor thisveh, entity instance)) @@ -739,9 +739,9 @@ METHOD(Raptor, vr_setup, void(Raptor thisveh, entity instance)) instance.vehicle_exit = raptor_exit; instance.respawntime = autocvar_g_vehicle_raptor_respawntime; - instance.vehicle_health = autocvar_g_vehicle_raptor_health; + SetResourceAmountExplicit(instance, RESOURCE_HEALTH, autocvar_g_vehicle_raptor_health); instance.vehicle_shield = autocvar_g_vehicle_raptor_shield; - instance.max_health = instance.vehicle_health; + instance.max_health = GetResourceAmount(instance, RESOURCE_HEALTH); if(!autocvar_g_vehicle_raptor_swim) instance.dphitcontentsmask |= DPCONTENTS_LIQUIDSMASK; diff --git a/qcsrc/common/vehicles/vehicle/spiderbot.qc b/qcsrc/common/vehicles/vehicle/spiderbot.qc index 09d0eb2af..7352e1dbb 100644 --- a/qcsrc/common/vehicles/vehicle/spiderbot.qc +++ b/qcsrc/common/vehicles/vehicle/spiderbot.qc @@ -294,7 +294,7 @@ bool spiderbot_frame(entity this, float dt) vehicles_regen(vehic, vehic.dmg_time, vehicle_shield, autocvar_g_vehicle_spiderbot_shield, autocvar_g_vehicle_spiderbot_shield_regen_pause, autocvar_g_vehicle_spiderbot_shield_regen, dt, true); if(vehic.vehicle_flags & VHF_HEALTHREGEN) - vehicles_regen(vehic, vehic.dmg_time, vehicle_health, autocvar_g_vehicle_spiderbot_health, autocvar_g_vehicle_spiderbot_health_regen_pause, autocvar_g_vehicle_spiderbot_health_regen, dt, false); + vehicles_regen_resource(vehic, vehic.dmg_time, vehicle_health, autocvar_g_vehicle_spiderbot_health, autocvar_g_vehicle_spiderbot_health_regen_pause, autocvar_g_vehicle_spiderbot_health_regen, dt, false, RESOURCE_HEALTH); PHYS_INPUT_BUTTON_ATCK(this) = PHYS_INPUT_BUTTON_ATCK2(this) = false; //this.vehicle_ammo2 = vehic.tur_head.frame; @@ -309,7 +309,7 @@ bool spiderbot_frame(entity this, float dt) this.oldorigin = this.origin; // negate fall damage this.velocity = vehic.velocity; - VEHICLE_UPDATE_PLAYER(this, vehic, health, spiderbot); + VEHICLE_UPDATE_PLAYER_RESOURCE(this, vehic, health, spiderbot, RESOURCE_HEALTH); if(vehic.vehicle_flags & VHF_HASSHIELD) VEHICLE_UPDATE_PLAYER(this, vehic, shield, spiderbot); @@ -524,7 +524,7 @@ METHOD(Spiderbot, vr_enter, void(Spiderbot thisveh, entity instance)) STAT(VEHICLESTAT_W2MODE, instance) = SBRM_GUIDE; set_movetype(instance, MOVETYPE_WALK); CSQCVehicleSetup(instance.owner, 0); - instance.owner.vehicle_health = (instance.vehicle_health / autocvar_g_vehicle_spiderbot_health) * 100; + instance.owner.vehicle_health = (GetResourceAmount(instance, RESOURCE_HEALTH) / autocvar_g_vehicle_spiderbot_health) * 100; instance.owner.vehicle_shield = (instance.vehicle_shield / autocvar_g_vehicle_spiderbot_shield) * 100; if(instance.owner.flagcarried) @@ -582,7 +582,7 @@ METHOD(Spiderbot, vr_spawn, void(Spiderbot thisveh, entity instance)) setorigin(instance, instance.pos1 + '0 0 128'); instance.angles = instance.pos2; instance.damageforcescale = 0.03; - instance.vehicle_health = autocvar_g_vehicle_spiderbot_health; + SetResourceAmountExplicit(instance, RESOURCE_HEALTH, autocvar_g_vehicle_spiderbot_health); instance.vehicle_shield = autocvar_g_vehicle_spiderbot_shield; instance.PlayerPhysplug = spiderbot_frame; @@ -599,9 +599,9 @@ METHOD(Spiderbot, vr_setup, void(Spiderbot thisveh, entity instance)) instance.vehicle_flags |= VHF_HEALTHREGEN; instance.respawntime = autocvar_g_vehicle_spiderbot_respawntime; - instance.vehicle_health = autocvar_g_vehicle_spiderbot_health; + SetResourceAmountExplicit(instance, RESOURCE_HEALTH, autocvar_g_vehicle_spiderbot_health); instance.vehicle_shield = autocvar_g_vehicle_spiderbot_shield; - instance.max_health = instance.vehicle_health; + instance.max_health = GetResourceAmount(instance, RESOURCE_HEALTH); instance.pushable = true; // spiderbot can use jumppads } diff --git a/qcsrc/common/weapons/weapon.qh b/qcsrc/common/weapons/weapon.qh index a3f2336a9..cdf5748e6 100644 --- a/qcsrc/common/weapons/weapon.qh +++ b/qcsrc/common/weapons/weapon.qh @@ -162,9 +162,9 @@ CLASS(WeaponPickup, Pickup) METHOD(WeaponPickup, giveTo, bool(entity this, entity item, entity player)) { bool b = Item_GiveTo(item, player); - if (b) { - LOG_TRACEF("entity %i picked up %s", player, this.m_name); - } + //if (b) { + //LOG_TRACEF("entity %i picked up %s", player, this.m_name); + //} return b; } #endif diff --git a/qcsrc/common/wepent.qc b/qcsrc/common/wepent.qc index 9488c4c2c..6b1797c66 100644 --- a/qcsrc/common/wepent.qc +++ b/qcsrc/common/wepent.qc @@ -20,7 +20,7 @@ MACRO_END \ PROP(false, m_alpha, WEPENT_SET_NORMAL, \ { WriteByte(chan, rint(bound(-1, 254 * this.m_alpha, 254) - -1)); }, \ - { (viewmodels[this.m_wepent_slot]).alpha = (ReadByte() + -1) / 254; }) \ + { (viewmodels[this.m_wepent_slot]).m_alpha = (ReadByte() + -1) / 254; }) \ \ PROP(false, vortex_charge, WEPENT_SET_NORMAL, \ { WriteByte(chan, this.vortex_charge * 255); }, \ diff --git a/qcsrc/common/wepent.qh b/qcsrc/common/wepent.qh index d6db7745b..556f58194 100644 --- a/qcsrc/common/wepent.qh +++ b/qcsrc/common/wepent.qh @@ -35,6 +35,8 @@ REGISTER_NET_TEMP(CLIENT_WEPENT) .Weapon switchingweapon; .Weapon switchweapon; + .float m_alpha; + // only for Porto .bool angles_held_status; .vector angles_held; diff --git a/qcsrc/lib/csqcmodel/cl_player.qc b/qcsrc/lib/csqcmodel/cl_player.qc index f87f00033..268b59126 100644 --- a/qcsrc/lib/csqcmodel/cl_player.qc +++ b/qcsrc/lib/csqcmodel/cl_player.qc @@ -210,11 +210,11 @@ bool CSQCPlayer_IsLocalPlayer(entity this) /** Called once per CSQC_UpdateView() */ void CSQCPlayer_SetCamera() { - const vector v0 = ((intermission && !autocvar_cl_movement_intermissionrunning) ? '0 0 0' : pmove_vel); // TRICK: pmove_vel is set by the engine when we get here. No need to network velocity - const float vh = PHYS_VIEWHEIGHT(NULL); - const vector pl_viewofs = PHYS_PL_VIEWOFS(NULL); - const vector pl_viewofs_crouch = PHYS_PL_CROUCH_VIEWOFS(NULL); - const entity e = csqcplayer; + vector v0 = ((intermission && !autocvar_cl_movement_intermissionrunning) ? '0 0 0' : pmove_vel); // TRICK: pmove_vel is set by the engine when we get here. No need to network velocity + float vh = PHYS_VIEWHEIGHT(NULL); + vector pl_viewofs = PHYS_PL_VIEWOFS(NULL); + vector pl_viewofs_crouch = PHYS_PL_CROUCH_VIEWOFS(NULL); + entity e = csqcplayer; if (e) { if (servercommandframe == 0 || clientcommandframe == 0) @@ -239,13 +239,13 @@ void CSQCPlayer_SetCamera() } else { - const int flg = e.iflags; e.iflags &= ~(IFLAG_ORIGIN | IFLAG_ANGLES); + int flg = e.iflags; e.iflags &= ~(IFLAG_ORIGIN | IFLAG_ANGLES); InterpolateOrigin_Do(e); e.iflags = flg; if (csqcplayer_status == CSQCPLAYERSTATUS_FROMSERVER) { - const vector o = e.origin; + vector o = e.origin; csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED; CSQCPlayer_PredictTo(e, servercommandframe + 1, false); CSQCPlayer_SetPredictionError(e.origin - o, e.velocity - v0, pmove_onground - IS_ONGROUND(e)); diff --git a/qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc b/qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc index 21e7ecadc..8b6dd4b73 100644 --- a/qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc +++ b/qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc @@ -37,10 +37,11 @@ string WeaponArenaString() s = ""; for(int j = 0; j < n; ++j) { - FOREACH(Weapons, it != WEP_Null, { - if(argv(j) == it.netname) - s = cons_mid(s, " & ", it.m_name); - }); + Weapon wep = Weapons_fromstr(argv(j)); + if(wep != WEP_Null) + { + s = cons_mid(s, " & ", wep.m_name); + } } s = sprintf(_("%s Arena"), s); diff --git a/qcsrc/menu/xonotic/dialog_settings_misc.qc b/qcsrc/menu/xonotic/dialog_settings_misc.qc index 594b581fe..1c7da7291 100644 --- a/qcsrc/menu/xonotic/dialog_settings_misc.qc +++ b/qcsrc/menu/xonotic/dialog_settings_misc.qc @@ -42,7 +42,7 @@ void XonoticMiscSettingsTab_fill(entity me) e.configureXonoticTextSliderValues(e); me.TR(me); me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Input packets/s:"))); - me.TD(me, 1, 2, e = makeXonoticSlider_T(20, 100, 5, "cl_netfps", + me.TD(me, 1, 2, e = makeXonoticSlider_T(30, 180, 5, "cl_netfps", _("How many input packets to send to the server each second"))); me.TR(me); me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Server queries/s:"))); diff --git a/qcsrc/server/_mod.inc b/qcsrc/server/_mod.inc index 429117ad0..2ec838695 100644 --- a/qcsrc/server/_mod.inc +++ b/qcsrc/server/_mod.inc @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/qcsrc/server/_mod.qh b/qcsrc/server/_mod.qh index 2bbfb7204..cc27baf12 100644 --- a/qcsrc/server/_mod.qh +++ b/qcsrc/server/_mod.qh @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/qcsrc/server/autocvars.qh b/qcsrc/server/autocvars.qh index 8a19f06c6..4e180f731 100644 --- a/qcsrc/server/autocvars.qh +++ b/qcsrc/server/autocvars.qh @@ -99,6 +99,7 @@ float autocvar_g_ban_sync_timeout; string autocvar_g_ban_sync_trusted_servers; bool autocvar_g_ban_sync_trusted_servers_verify; string autocvar_g_ban_sync_uri; +bool autocvar_g_ban_telluser = true; string autocvar_g_banned_list; bool autocvar_g_banned_list_idmode; bool autocvar_g_botclip_collisions; diff --git a/qcsrc/server/bot/default/bot.qc b/qcsrc/server/bot/default/bot.qc index 10ececff6..ec84e5516 100644 --- a/qcsrc/server/bot/default/bot.qc +++ b/qcsrc/server/bot/default/bot.qc @@ -595,8 +595,6 @@ float bot_fixcount() //int player_limit = GetPlayerLimit(); // TODO: use this instead of maxclients! int bots; - // add/remove bots if needed to make sure there are at least - // minplayers+bot_number, or remove all bots if no one is playing // But don't remove bots immediately on level change, as the real players // usually haven't rejoined yet bots_would_leave = false; @@ -604,15 +602,14 @@ float bot_fixcount() bots = min(ceil(fabs(autocvar_bot_vs_human) * activerealplayers), maxclients - realplayers); else if ((realplayers || autocvar_bot_join_empty || (currentbots > 0 && time < 5))) { - float realminplayers, minplayers; - realminplayers = autocvar_minplayers; - minplayers = max(0, floor(realminplayers)); + int minplayers = max(0, floor(autocvar_minplayers)); + int minbots = max(0, floor(autocvar_bot_number)); - float realminbots, minbots; - realminbots = autocvar_bot_number; - minbots = max(0, floor(realminbots)); + // add bots to reach minplayers if needed + bots = max(minbots, minplayers - activerealplayers); + // cap bots to the max players allowed by the server + bots = min(bots, maxclients - realplayers); - bots = min(max(minbots, minplayers - activerealplayers), maxclients - realplayers); if(bots > minbots) bots_would_leave = true; } diff --git a/qcsrc/server/client.qc b/qcsrc/server/client.qc index 88f423e7a..e8ca9649f 100644 --- a/qcsrc/server/client.qc +++ b/qcsrc/server/client.qc @@ -32,11 +32,14 @@ #include "../common/wepent.qh" #include +#include "compat/quake3.qh" + #include #include "../common/mapobjects/func/conveyor.qh" #include "../common/mapobjects/teleporters.qh" #include "../common/mapobjects/target/spawnpoint.qh" +#include #include "../common/vehicles/all.qh" @@ -705,6 +708,9 @@ void PutPlayerInServer(entity this) this.speedrunning = false; + this.counter_cnt = 0; + this.fragsfilter_cnt = 0; + target_voicescript_clear(this); // reset fields the weapons may use @@ -721,10 +727,10 @@ void PutPlayerInServer(entity this) }); { - string s = spot.target; - spot.target = string_null; + //string s = spot.target; + //spot.target = string_null; SUB_UseTargets(spot, this, NULL); - spot.target = s; + //spot.target = s; } Unfreeze(this); diff --git a/qcsrc/server/client.qh b/qcsrc/server/client.qh index c6e4b7879..8b9256806 100644 --- a/qcsrc/server/client.qh +++ b/qcsrc/server/client.qh @@ -17,7 +17,7 @@ CLASS(Client, Object) /** Client IP */ ATTRIB(Client, netaddress, string, this.netaddress); ATTRIB(Client, playermodel, string, this.playermodel); - ATTRIB(Client, playerskin, int, this.playerskin); + ATTRIB(Client, playerskin, string, this.playerskin); /** fingerprint of CA key the player used to authenticate */ ATTRIB(Client, crypto_keyfp, string, this.crypto_keyfp); diff --git a/qcsrc/server/compat/quake3.qc b/qcsrc/server/compat/quake3.qc index 232795fa6..65f231374 100644 --- a/qcsrc/server/compat/quake3.qc +++ b/qcsrc/server/compat/quake3.qc @@ -6,6 +6,7 @@ #include #include #include +#include #include //*********************** @@ -183,6 +184,37 @@ spawnfunc(target_give) InitializeEntity(this, target_give_init, INITPRIO_FINDTARGET); } +void score_use(entity this, entity actor, entity trigger) +{ + if(!IS_PLAYER(actor)) + return; + actor.fragsfilter_cnt += this.count; +} +spawnfunc(target_score) +{ + if(!g_cts) { delete(this); return; } + + if(!this.count) + this.count = 1; + this.use = score_use; +} + +void fragsfilter_use(entity this, entity actor, entity trigger) +{ + if(!IS_PLAYER(actor)) + return; + if(actor.fragsfilter_cnt >= this.frags) + SUB_UseTargets(this, actor, trigger); +} +spawnfunc(target_fragsFilter) +{ + if(!g_cts) { delete(this); return; } + + if(!this.frags) + this.frags = 1; + this.use = fragsfilter_use; +} + //spawnfunc(item_flight) /* handled by buffs mutator */ //spawnfunc(item_haste) /* handled by buffs mutator */ //spawnfunc(item_health) /* handled in t_quake.qc */ diff --git a/qcsrc/server/compat/quake3.qh b/qcsrc/server/compat/quake3.qh index 342a829a1..20e4879d9 100644 --- a/qcsrc/server/compat/quake3.qh +++ b/qcsrc/server/compat/quake3.qh @@ -1,3 +1,5 @@ #pragma once bool DoesQ3ARemoveThisEntity(entity this); + +.int fragsfilter_cnt; diff --git a/qcsrc/server/g_damage.qc b/qcsrc/server/g_damage.qc index 4964bf91e..eb05e2c85 100644 --- a/qcsrc/server/g_damage.qc +++ b/qcsrc/server/g_damage.qc @@ -1236,11 +1236,11 @@ void Fire_ApplyDamage(entity e) } e.fire_hitsound = true; - if(!IS_INDEPENDENT_PLAYER(e)) - if(!STAT(FROZEN, e)) - FOREACH_CLIENT(IS_PLAYER(it) && it != e, { - if(!IS_DEAD(it)) - if(!IS_INDEPENDENT_PLAYER(it)) + if(!IS_INDEPENDENT_PLAYER(e) && !STAT(FROZEN, e)) + { + IL_EACH(g_damagedbycontents, it.damagedbycontents && it != e, + { + if(!IS_DEAD(it) && it.takedamage && !IS_INDEPENDENT_PLAYER(it)) if(boxesoverlap(e.absmin, e.absmax, it.absmin, it.absmax)) { t = autocvar_g_balance_firetransfer_time * (e.fire_endtime - time); @@ -1248,6 +1248,8 @@ void Fire_ApplyDamage(entity e) Fire_AddDamage(it, o, d, t, DEATH_FIRE.m_id); } }); + } + } void Fire_ApplyEffect(entity e) diff --git a/qcsrc/server/g_world.qc b/qcsrc/server/g_world.qc index 05bff1421..522f4f041 100644 --- a/qcsrc/server/g_world.qc +++ b/qcsrc/server/g_world.qc @@ -1612,7 +1612,9 @@ float InitiateSuddenDeath() // - for this timelimit_overtime needs to be >0 of course // - also check the winning condition calculated in the previous frame and only add normal overtime // again, if at the point at which timelimit would be extended again, still no winner was found - if (!autocvar_g_campaign && (checkrules_overtimesadded >= 0) && (checkrules_overtimesadded < autocvar_timelimit_overtimes || autocvar_timelimit_overtimes < 0) && autocvar_timelimit_overtime && !(g_race && !g_race_qualifying)) + if (!autocvar_g_campaign && checkrules_overtimesadded >= 0 + && (checkrules_overtimesadded < autocvar_timelimit_overtimes || autocvar_timelimit_overtimes < 0) + && autocvar_timelimit_overtime && !(g_race && !g_race_qualifying)) { return 1; // need to call InitiateOvertime later } @@ -1635,11 +1637,7 @@ void InitiateOvertime() // ONLY call this if InitiateSuddenDeath returned true { ++checkrules_overtimesadded; //add one more overtime by simply extending the timelimit - float tl; - tl = autocvar_timelimit; - tl += autocvar_timelimit_overtime; - cvar_set("timelimit", ftos(tl)); - + cvar_set("timelimit", ftos(autocvar_timelimit + autocvar_timelimit_overtime)); Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_OVERTIME_TIME, autocvar_timelimit_overtime * 60); } @@ -1778,7 +1776,7 @@ float WinningCondition_RanOutOfSpawns() { Team_SetTeamScore(Team_GetTeamFromIndex(i), 0); } - + FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it), { if (Team_IsValidTeam(it.team)) diff --git a/qcsrc/server/ipban.qc b/qcsrc/server/ipban.qc index 7b1f69384..7c6fcbafe 100644 --- a/qcsrc/server/ipban.qc +++ b/qcsrc/server/ipban.qc @@ -446,6 +446,8 @@ bool Ban_MaybeEnforceBan(entity client) if (Ban_IsClientBanned(client, -1)) { string s = sprintf("^1NOTE:^7 banned client %s just tried to enter\n", client.netaddress); + if(autocvar_g_ban_telluser) + sprint(client, "You are banned from this server.\n"); dropclient(client); bprint(s); return true; diff --git a/qcsrc/server/item_key.qc b/qcsrc/server/item_key.qc deleted file mode 100644 index 2bfdc49b7..000000000 --- a/qcsrc/server/item_key.qc +++ /dev/null @@ -1,287 +0,0 @@ -#include "item_key.qh" - -#include "../common/mapobjects/subs.qh" -#include -#include "../common/monsters/_mod.qh" -#include "../common/notifications/all.qh" -#include "../common/util.qh" -#include "../lib/warpzone/util_server.qh" - -/* -TODO: -- add an unlock sound (here to trigger_keylock and to func_door) -- display available keys on the HUD -- make more tests -- think about adding NOT_EASY/NOT_NORMAL/NOT_HARD for Q1 compatibility -- should keys have a trigger? -*/ - -bool item_keys_usekey(entity l, entity p) -{ - int valid = l.itemkeys & PS(p).itemkeys; - - if (!valid) { - // player has none of the needed keys - return false; - } else if (l.itemkeys == valid) { - // ALL needed keys were given - l.itemkeys = 0; - return true; - } else { - // only some of the needed keys were given - l.itemkeys &= ~valid; - return true; - } -} - -string item_keys_keylist(float keylist) { - // no keys - if (!keylist) - return ""; - - // one key - if ((keylist & (keylist-1)) == 0) - return strcat("the ", item_keys_names[lowestbit(keylist)]); - - string n = ""; - int base = 0; - while (keylist) { - int l = lowestbit(keylist); - if (n) - n = strcat(n, ", the ", item_keys_names[base + l]); - else - n = strcat("the ", item_keys_names[base + l]); - - keylist = bitshift(keylist, -(l + 1)); - base+= l + 1; - } - - return n; -} - - -/* -================================ -item_key -================================ -*/ - -/** - * Key touch handler. - */ -void item_key_touch(entity this, entity toucher) -{ - if (!IS_PLAYER(toucher)) - return; - - // player already picked up this key - if (PS(toucher).itemkeys & this.itemkeys) - return; - - PS(toucher).itemkeys |= this.itemkeys; - play2(toucher, this.noise); - - centerprint(toucher, this.message); - - string oldmsg = this.message; - this.message = ""; - SUB_UseTargets(this, toucher, toucher); // TODO: should we be using toucher for the trigger here? - this.message = oldmsg; -} - -/** - * Spawn a key with given model, key code and color. - */ -void spawn_item_key(entity this) -{ - precache_model(this.model); - - if (this.spawnflags & 1) // FLOATING - this.noalign = 1; - - if (this.noalign) - set_movetype(this, MOVETYPE_NONE); - else - set_movetype(this, MOVETYPE_TOSS); - - precache_sound(this.noise); - - this.mdl = this.model; - this.effects = EF_LOWPRECISION; - _setmodel(this, this.model); - //setsize(this, '-16 -16 -24', '16 16 32'); - setorigin(this, this.origin + '0 0 32'); - setsize(this, '-16 -16 -56', '16 16 0'); - this.modelflags |= MF_ROTATE; - this.solid = SOLID_TRIGGER; - - if (!this.noalign) - { - // first nudge it off the floor a little bit to avoid math errors - setorigin(this, this.origin + '0 0 1'); - // note droptofloor returns false if stuck/or would fall too far - droptofloor(this); - } - - settouch(this, item_key_touch); -} - - -/*QUAKED item_key (0 .5 .8) (-16 -16 -24) (16 16 32) FLOATING -A key entity. -The itemkeys should contain one of the following key IDs: -1 - GOLD key - -2 - SILVER key -4 - BRONZE key -8 - RED keycard -16 - BLUE keycard -32 - GREEN keycard -Custom keys: -... - last key is 1<<23 -Keys with bigger Id than 32 don't have a default netname and model, if you use one of them, you MUST provide those. ------------KEYS------------ -colormod: color of the key (default: '.9 .9 .9'). -itemkeys: a key Id. -message: message to print when player picks up this key. -model: custom key model to use. -netname: the display name of the key. -noise: custom sound to play when player picks up the key. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling ----------NOTES---------- -This is the only correct way to put keys on the map! - -itemkeys MUST always have exactly one bit set. -*/ -spawnfunc(item_key) -{ - string _netname; - vector _colormod; - - // reject this entity if more than one key was set! - if (this.itemkeys>0 && (this.itemkeys & (this.itemkeys-1)) != 0) { - objerror(this, "item_key.itemkeys must contain only 1 bit set specifying the key it represents!"); - delete(this); - return; - } - - // find default netname and colormod - switch(this.itemkeys) { - case BIT(0): - _netname = "GOLD key"; - _colormod = '1 .9 0'; - break; - - case BIT(1): - _netname = "SILVER key"; - _colormod = '.9 .9 .9'; - break; - - case BIT(2): - _netname = "BRONZE key"; - _colormod = '.6 .25 0'; - break; - - case BIT(3): - _netname = "RED keycard"; - _colormod = '.9 0 0'; - break; - - case BIT(4): - _netname = "BLUE keycard"; - _colormod = '0 0 .9'; - break; - - case BIT(5): - _netname = "GREEN keycard"; - _colormod = '0 .9 0'; - break; - - default: - _netname = "FLUFFY PINK keycard"; - _colormod = '1 1 1'; - - if (this.netname == "") { - objerror(this, "item_key doesn't have a default name for this key and a custom one was not specified!"); - delete(this); - return; - } - break; - - } - - // find default model - string _model = string_null; - if (this.itemkeys <= ITEM_KEY_BIT(2)) { - _model = "models/keys/key.md3"; - } else if (this.itemkeys >= ITEM_KEY_BIT(3) && this.itemkeys <= ITEM_KEY_BIT(5)) { - _model = "models/keys/key.md3"; // FIXME: replace it by a keycard model! - } else if (this.model == "") { - objerror(this, "item_key doesn't have a default model for this key and a custom one was not specified!"); - delete(this); - return; - } - - // set defailt netname - if (this.netname == "") - this.netname = _netname; - - // set default colormod - if (!this.colormod) - this.colormod = _colormod; - - // set default model - if (this.model == "") - this.model = _model; - - // set default pickup message - if (this.message == "") - this.message = strzone(strcat("You've picked up the ", this.netname, "!")); - - if (this.noise == "") - this.noise = strzone(SND(ITEMPICKUP)); - - // save the name for later - item_keys_names[lowestbit(this.itemkeys)] = this.netname; - - // put the key on the map - spawn_item_key(this); -} - -/*QUAKED item_key1 (0 .5 .8) (-16 -16 -24) (16 16 32) FLOATING -SILVER key. ------------KEYS------------ -colormod: color of the key (default: '.9 .9 .9'). -message: message to print when player picks up this key. -model: custom model to use. -noise: custom sound to play when player picks up the key. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling ----------NOTES---------- -Don't use this entity on new maps! Use item_key instead. -*/ -spawnfunc(item_key1) -{ - this.classname = "item_key"; - this.itemkeys = ITEM_KEY_BIT(1); - spawnfunc_item_key(this); -} - -/*QUAKED item_key2 (0 .5 .8) (-16 -16 -24) (16 16 32) FLOATING -GOLD key. ------------KEYS------------ -colormod: color of the key (default: '1 .9 0'). -message: message to print when player picks up this key. -model: custom model to use. -noise: custom sound to play when player picks up the key. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling ----------NOTES---------- -Don't use this entity on new maps! Use item_key instead. -*/ -spawnfunc(item_key2) -{ - this.classname = "item_key"; - this.itemkeys = ITEM_KEY_BIT(0); - spawnfunc_item_key(this); -} diff --git a/qcsrc/server/item_key.qh b/qcsrc/server/item_key.qh deleted file mode 100644 index 50be5f8db..000000000 --- a/qcsrc/server/item_key.qh +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -/** - * Returns the bit ID of a key - */ -#define ITEM_KEY_BIT(n) ( bitshift(1, n) ) - -#define ITEM_KEY_MAX 24 - -/** - * list of key names. - */ -#ifdef SVQC -string item_keys_names[ITEM_KEY_MAX]; - -/** - * Use keys from p on l. - * Returns true if any new keys were given, false otherwise. - */ -float item_keys_usekey(entity l, entity p); - -/** - * Returns a string with a comma separated list of key names, as specified in keylist. - */ -string item_keys_keylist(float keylist); -#endif diff --git a/qcsrc/server/miscfunctions.qc b/qcsrc/server/miscfunctions.qc index f8a2cd79e..cf7266b48 100644 --- a/qcsrc/server/miscfunctions.qc +++ b/qcsrc/server/miscfunctions.qc @@ -600,14 +600,12 @@ void readplayerstartcvars() for (i = 0; i < t; ++i) { s = argv(i); - FOREACH(Weapons, it != WEP_Null, { - if(it.netname == s) - { - g_weaponarena_weapons |= (it.m_wepset); - g_weaponarena_list = strcat(g_weaponarena_list, it.m_name, " & "); - break; - } - }); + Weapon wep = Weapons_fromstr(s); + if(wep != WEP_Null) + { + g_weaponarena_weapons |= (wep.m_wepset); + g_weaponarena_list = strcat(g_weaponarena_list, wep.m_name, " & "); + } } g_weaponarena_list = strzone(substring(g_weaponarena_list, 0, strlen(g_weaponarena_list) - 3)); } diff --git a/qcsrc/server/spawnpoints.qc b/qcsrc/server/spawnpoints.qc index e0e33e480..03b40c5e1 100644 --- a/qcsrc/server/spawnpoints.qc +++ b/qcsrc/server/spawnpoints.qc @@ -248,7 +248,7 @@ vector Spawn_Score(entity this, entity spot, float mindist, float teamcheck) vector spawn_score = prio * '1 0 0' + shortest * '0 1 0'; // filter out spots for assault - if(spot.target != "") + if(spot.target && spot.target != "") { int found = 0; for(entity targ = findchain(targetname, spot.target); targ; targ = targ.chain) diff --git a/qcsrc/server/teamplay.qc b/qcsrc/server/teamplay.qc index abc5df1d7..239fb69f0 100644 --- a/qcsrc/server/teamplay.qc +++ b/qcsrc/server/teamplay.qc @@ -585,8 +585,8 @@ entity TeamBalance_CheckAllowedTeams(entity for_whom) TeamBalance_IsTeamAllowedInternal(balance, i)) { TeamBalance_BanTeamsExcept(balance, i); + break; } - break; } balance.m_team_balance_state = TEAM_BALANCE_TEAMS_CHECKED; return balance; @@ -881,16 +881,16 @@ void TeamBalance_AutoBalanceBots() { continue; } - int player_count = TeamBalanceTeam_GetNumberOfPlayers(team_); + int playercount = TeamBalanceTeam_GetNumberOfPlayers(team_); if (smallest_team_index == 0) { smallest_team_index = i; - smallest_team_player_count = player_count; + smallest_team_player_count = playercount; } - else if (player_count < smallest_team_player_count) + else if (playercount < smallest_team_player_count) { smallest_team_index = i; - smallest_team_player_count = player_count; + smallest_team_player_count = playercount; } } //PrintToChatAll(sprintf("Smallest team: %f", smallest_team_index)); @@ -949,16 +949,16 @@ int TeamBalance_GetLargestTeamIndex(entity balance, int teams) { continue; } - int player_count = TeamBalanceTeam_GetNumberOfPlayers(team_); + int playercount = TeamBalanceTeam_GetNumberOfPlayers(team_); if (largest_team_index == 0) { largest_team_index = i; - largest_team_player_count = player_count; + largest_team_player_count = playercount; } - else if (player_count > largest_team_player_count) + else if (playercount > largest_team_player_count) { largest_team_index = i; - largest_team_player_count = player_count; + largest_team_player_count = playercount; } } return largest_team_index; diff --git a/qcsrc/server/weapons/spawning.qc b/qcsrc/server/weapons/spawning.qc index 204b5a763..4ab5a4371 100644 --- a/qcsrc/server/weapons/spawning.qc +++ b/qcsrc/server/weapons/spawning.qc @@ -56,29 +56,20 @@ void weapon_defaultspawnfunc(entity this, Weapon e) for (int i = 1; i < t; ++i) { s = argv(i); - FOREACH(Weapons, it != WEP_Null, { - if(it.netname == s) - { - entity replacement = spawn(); - copyentity(this, replacement); - replacement.m_isreplaced = true; - weapon_defaultspawnfunc(replacement, it); - break; - } - }); + Weapon wep = Weapons_fromstr(s); + if(wep != WEP_Null) + { + entity replacement = spawn(); + copyentity(this, replacement); + replacement.m_isreplaced = true; + weapon_defaultspawnfunc(replacement, wep); + } } } if (t >= 1) // always the case! { s = argv(0); - wpn = WEP_Null; - FOREACH(Weapons, it != WEP_Null, { - if(it.netname == s) - { - wpn = it; - break; - } - }); + wpn = Weapons_fromstr(s); } if (wpn == WEP_Null) { diff --git a/scripts/weapons.shader b/scripts/weapons.shader index 491fd052e..85f27d5c0 100644 --- a/scripts/weapons.shader +++ b/scripts/weapons.shader @@ -1,11 +1,3 @@ -electro -{ - dpreflectcube cubemaps/default/sky - { - map textures/electro.tga - rgbgen lightingDiffuse - } -} nexgun { dpreflectcube cubemaps/default/sky diff --git a/xonotic-client.cfg b/xonotic-client.cfg index 32f08fc94..af69bbb21 100644 --- a/xonotic-client.cfg +++ b/xonotic-client.cfg @@ -722,6 +722,8 @@ seta cl_forcemyplayercolors 0 "set to the color value (encoding is same as _cl_c seta cl_movement_errorcompensation 1 "try to compensate for prediction errors and reduce perceived lag" seta cl_movement_intermissionrunning 0 "keep velocity after the match ends, players may appear to continue running while stationary" +seta cl_viewmodel_alpha 0 "Maximum transparency of the view model, set to 0 to disable" + set debugdraw 0 set debugdraw_filter "" set debugdraw_filterout "" diff --git a/xonotic-server.cfg b/xonotic-server.cfg index 7ad3ced27..ca9b72eee 100644 --- a/xonotic-server.cfg +++ b/xonotic-server.cfg @@ -10,7 +10,7 @@ set sv_autotaunt 1 "allow autotaunts on the server" // server settings hostname "Xonotic $g_xonoticversion Server" set sv_mapchange_delay 5 -set minplayers 0 "number of players playing at the same time (if not enough real players are there the remaining slots are filled with bots)" +set minplayers 0 "fill server with bots to reach this number of players (if bot_number is not enough)" // restart server if all players hit "ready"-button set sv_ready_restart 0 "allow a map to be restarted once all players pressed the \"ready\" button" @@ -372,6 +372,7 @@ set sv_itemstime 1 "enable networking of time left until respawn for items such set g_ban_default_bantime 5400 "90 minutes" set g_ban_default_masksize 3 "masksize 0 means banning by UID only, 1 means banning by /8 (IPv6: /32) network, 2 means banning by /16 (IPv6: /48) network, 3 means banning by /24 (IPv6: /56) network, 4 means banning by single IP (IPv6: /64 network)" +set g_ban_telluser 1 "notify the banned player about it when they try to join" set g_banned_list "" "format: IP remainingtime IP remainingtime ..." set g_banned_list_idmode "1" "when set, the IP banning system always uses the ID over the IP address (so a user in a banned IP range can connect if they have a valid signed ID)" @@ -482,6 +483,7 @@ sv_gameplayfix_gravityunaffectedbyticrate 1 sv_gameplayfix_nogravityonground 1 set sv_q3acompat_machineshotgunswap 0 "shorthand for swapping machinegun and shotgun (for Q3A map compatibility in mapinfo files)" +set sv_vq3compat 0 "toggle for some compatibility hacks (for VQ3 and CPM map compatibility in mapinfo files)" set g_movement_highspeed 1 "movement speed modification factor (only changes movement when above maxspeed)"