X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Ft_items.qc;h=ac029e6577659f3e243a610219b9a3f290d15bc4;hb=a4ccbd75da12da9090f3d25ad4dc9edd0efe3060;hp=4afccd9bee8c7c385177e0038ef677281783ce4b;hpb=32d968aa05160c873ef7a124bdf4b92a67710e1d;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/t_items.qc b/qcsrc/server/t_items.qc index 4afccd9be..ac029e657 100644 --- a/qcsrc/server/t_items.qc +++ b/qcsrc/server/t_items.qc @@ -29,7 +29,7 @@ float have_pickup_item(void) if(g_ca) return FALSE; if(g_weaponarena) - if((self.weapons & WEPBIT_ALL) || (self.items & IT_AMMO)) + if(!WEPSET_EMPTY_E(self) || (self.items & IT_AMMO)) return FALSE; } return TRUE; @@ -83,7 +83,7 @@ float Item_Customize() { if(self.spawnshieldtime) return TRUE; - if(self.weapons != (self.weapons & other.weapons)) + if(!WEPSET_CONTAINS_ALL_EE(other, self)) { self.colormod = '0 0 0'; self.glowmod = self.colormod; @@ -209,7 +209,7 @@ void Item_RespawnCountdown (void) if(self.count == 1) { string name; - vector rgb; + vector rgb = '1 0 1'; name = string_null; if(g_minstagib) { @@ -265,7 +265,7 @@ void Item_RespawnCountdown (void) void Item_ScheduleRespawnIn(entity e, float t) { - if((e.flags & FL_POWERUP) || (e.weapons & WEPBIT_SUPERWEAPONS)) + if((e.flags & FL_POWERUP) || WEPSET_CONTAINS_ANY_EA(e, WEPBIT_SUPERWEAPONS)) { e.think = Item_RespawnCountdown; e.nextthink = time + max(0, t - ITEM_RESPAWN_TICKS); @@ -348,7 +348,6 @@ float Item_GiveTo(entity item, entity player) float pickedup; float it; float i; - entity e; // if nothing happens to player, just return without taking the item pickedup = FALSE; @@ -377,10 +376,8 @@ float Item_GiveTo(entity item, entity player) // else if(item.items == IT_CELLS) // AnnounceTo(player, "ammo"); - if (item.weapons & WEPBIT_MINSTANEX) + if (WEPSET_CONTAINS_EW(item, WEP_MINSTANEX)) W_GiveWeapon (player, WEP_MINSTANEX, item.netname); - if (item.ammo_cells) - player.ammo_cells = bound(player.ammo_cells, 999, player.ammo_cells + autocvar_g_minstagib_ammo_drop); player.health = 100; } @@ -428,7 +425,7 @@ float Item_GiveTo(entity item, entity player) if (player.switchweapon == w_getbestweapon(player)) _switchweapon = TRUE; - if not(player.weapons & W_WeaponBit(player.switchweapon)) + if not(WEPSET_CONTAINS_EW(player, player.switchweapon)) _switchweapon = TRUE; pickedup |= Item_GiveAmmoTo(item, player, ammo_fuel, g_pickup_fuel_max, ITEM_MODE_FUEL); @@ -440,14 +437,17 @@ float Item_GiveTo(entity item, entity player) pickedup |= Item_GiveAmmoTo(item, player, armorvalue, item.max_armorvalue, ITEM_MODE_ARMOR); if (item.flags & FL_WEAPON) - if ((it = item.weapons - (item.weapons & player.weapons)) || (item.spawnshieldtime && self.pickup_anyway)) { - pickedup = TRUE; - for(i = WEP_FIRST; i <= WEP_LAST; ++i) + WEPSET_DECLARE_A(it); + WEPSET_COPY_AE(it, item); + WEPSET_ANDNOT_AE(it, player); + + if (!WEPSET_EMPTY_A(it) || (item.spawnshieldtime && self.pickup_anyway)) { - e = get_weaponinfo(i); - if(it & e.weapons) - W_GiveWeapon (player, e.weapon, item.netname); + pickedup = TRUE; + for(i = WEP_FIRST; i <= WEP_LAST; ++i) + if(WEPSET_CONTAINS_AW(it, i)) + W_GiveWeapon (player, i, item.netname); } } @@ -495,11 +495,15 @@ void Item_Touch (void) entity e, head; // remove the item if it's currnetly in a NODROP brush or hits a NOIMPACT surface (such as sky) - if (((trace_dpstartcontents | trace_dphitcontents) & DPCONTENTS_NODROP) || (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)) + if(self.classname == "droppedweapon") { - remove(self); - return; + if (ITEM_TOUCH_NEEDKILL()) + { + remove(self); + return; + } } + if (other.classname != "player") return; if (other.deadflag) @@ -568,7 +572,10 @@ void Item_Reset() self.think = SUB_Null; self.nextthink = 0; - if((self.flags & FL_POWERUP) | (self.weapons & WEPBIT_SUPERWEAPONS)) // do not spawn powerups initially! + if(self.waypointsprite_attached) + WaypointSprite_Kill(self.waypointsprite_attached); + + if((self.flags & FL_POWERUP) | WEPSET_CONTAINS_ANY_EA(self, WEPBIT_SUPERWEAPONS)) // do not spawn powerups initially! Item_ScheduleInitialRespawn(self); } } @@ -617,10 +624,10 @@ float generic_pickupevalfunc(entity player, entity item) {return item.bot_pickup float weapon_pickupevalfunc(entity player, entity item) { - float c, i, j, position; + float c, j, position; // See if I have it already - if(player.weapons & item.weapons == item.weapons) + if(!WEPSET_CONTAINS_ALL_EE(player, item)) { // If I can pick it up if(!item.spawnshieldtime) @@ -639,34 +646,27 @@ float weapon_pickupevalfunc(entity player, entity item) // If custom weapon priorities for bots is enabled rate most wanted weapons higher if( bot_custom_weapon && c ) { - for(i = WEP_FIRST; i <= WEP_LAST ; ++i) - { - // Find weapon - if( (get_weaponinfo(i)).weapons & item.weapons != item.weapons ) - continue; - - // Find the highest position on any range - position = -1; - for(j = 0; j < WEP_LAST ; ++j){ - if( - bot_weapons_far[j] == i || - bot_weapons_mid[j] == i || - bot_weapons_close[j] == i - ) - { - position = j; - break; - } - } - - // Rate it - if (position >= 0 ) + // Find the highest position on any range + position = -1; + for(j = 0; j < WEP_LAST ; ++j){ + if( + bot_weapons_far[j] == item.weapon || + bot_weapons_mid[j] == item.weapon || + bot_weapons_close[j] == item.weapon + ) { - position = WEP_LAST - position; - // item.bot_pickupbasevalue is overwritten here - return (BOT_PICKUP_RATING_LOW + ( (BOT_PICKUP_RATING_HIGH - BOT_PICKUP_RATING_LOW) * (position / WEP_LAST ))) * c; + position = j; + break; } } + + // Rate it + if (position >= 0 ) + { + position = WEP_LAST - position; + // item.bot_pickupbasevalue is overwritten here + return (BOT_PICKUP_RATING_LOW + ( (BOT_PICKUP_RATING_HIGH - BOT_PICKUP_RATING_LOW) * (position / WEP_LAST ))) * c; + } } return item.bot_pickupbasevalue * c; @@ -674,7 +674,8 @@ float weapon_pickupevalfunc(entity player, entity item) float commodity_pickupevalfunc(entity player, entity item) { - float c, i, need_shells, need_nails, need_rockets, need_cells, need_fuel; + float c, i; + float need_shells = FALSE, need_nails = FALSE, need_rockets = FALSE, need_cells = FALSE, need_fuel = FALSE; entity wi; c = 0; @@ -683,7 +684,7 @@ float commodity_pickupevalfunc(entity player, entity item) { wi = get_weaponinfo(i); - if not(wi.weapons & player.weapons) + if not(WEPSET_CONTAINS_EW(player, i)) continue; if(wi.items & IT_SHELLS) @@ -731,16 +732,41 @@ float commodity_pickupevalfunc(entity player, entity item) return item.bot_pickupbasevalue * c; } +void Item_Damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) +{ + if(ITEM_DAMAGE_NEEDKILL(deathtype)) + RemoveItem(); +} .float is_item; void StartItem (string itemmodel, string pickupsound, float defaultrespawntime, float defaultrespawntimejitter, string itemname, float itemid, float weaponid, float itemflags, float(entity player, entity item) pickupevalfunc, float pickupbasevalue) { startitem_failed = FALSE; + if(self.model == "") + self.model = itemmodel; + if(self.item_pickupsound == "") + self.item_pickupsound = pickupsound; + if(!self.respawntime) // both need to be set + { + self.respawntime = defaultrespawntime; + self.respawntimejitter = defaultrespawntimejitter; + } + self.items = itemid; - self.weapons = weaponid; + self.weapon = weaponid; + + if(weaponid) + WEPSET_COPY_EW(self, weaponid); self.flags = FL_ITEM | itemflags; + if(MUTATOR_CALLHOOK(FilterItem)) // error means we do not want the item + { + startitem_failed = TRUE; + remove(self); + return; + } + // is it a dropped weapon? if (self.classname == "droppedweapon") { @@ -752,10 +778,13 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime, self.think = RemoveItem; self.nextthink = time + 20; + self.takedamage = DAMAGE_YES; + self.event_damage = Item_Damage; + if(self.strength_finished || self.invincible_finished || self.superweapons_finished) /* if(self.items == 0) - if(self.weapons == (self.weapons & WEPBIT_SUPERWEAPONS)) // only superweapons + if(WEPSET_CONTAINS_ALL_AE(WEPBIT_SUPERWEAPONS, self)) // only superweapons if(self.ammo_nails == 0) if(self.ammo_cells == 0) if(self.ammo_rockets == 0) @@ -780,13 +809,6 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime, } else { - if(MUTATOR_CALLHOOK(FilterItem)) // error means we do not want the item - { - startitem_failed = TRUE; - remove(self); - return; - } - if(!have_pickup_item()) { startitem_failed = TRUE; @@ -794,11 +816,6 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime, return; } - if(self.model != "") - itemmodel = self.model; - if(self.item_pickupsound != "") - pickupsound = self.item_pickupsound; - self.reset = Item_Reset; // it's a level item if(self.spawnflags & 1) @@ -851,10 +868,10 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime, self.is_item = TRUE; } - weaponsInMap |= weaponid; + WEPSET_OR_AW(weaponsInMap, weaponid); - precache_model (itemmodel); - precache_sound (pickupsound); + precache_model (self.model); + precache_sound (self.item_pickupsound); precache_sound ("misc/itemrespawncountdown.wav"); if(!g_minstagib && itemid == IT_STRENGTH) @@ -871,18 +888,7 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime, self.bot_pickup = TRUE; self.bot_pickupevalfunc = pickupevalfunc; self.bot_pickupbasevalue = pickupbasevalue; - self.mdl = itemmodel; - self.item_pickupsound = pickupsound; - if(self.weapons) - self.weapon = WEP_FIRST + log2of(lowestbit(self.weapons)); - else - self.weapon = 0; - // let mappers override respawntime - if(!self.respawntime) // both set - { - self.respawntime = defaultrespawntime; - self.respawntimejitter = defaultrespawntimejitter; - } + self.mdl = self.model; self.netname = itemname; self.touch = Item_Touch; setmodel (self, self.mdl); // precision set below @@ -992,8 +998,23 @@ void weapon_defaultspawnfunc(float wpn) if(self.classname != "droppedweapon" && self.classname != "replacedweapon") { e = get_weaponinfo(wpn); - s = cvar_string(strcat("g_weaponreplace_", e.netname)); - if(s == "0") + + if(e.spawnflags & WEP_FLAG_MUTATORBLOCKED) + { + print("Attempted to spawn a mutator-blocked weapon; these guns will in the future require a mutator\n"); + /* + objerror("Attempted to spawn a mutator-blocked weapon rejected"); + startitem_failed = TRUE; + return; + */ + } + + s = W_Apply_Weaponreplace(e.netname); + ret_string = s; + other = e; + MUTATOR_CALLHOOK(SetWeaponreplace); + s = ret_string; + if(s == "") { remove(self); startitem_failed = TRUE; @@ -1026,7 +1047,7 @@ void weapon_defaultspawnfunc(float wpn) } self = oldself; } - if(t >= 1) + if(t >= 1) // always the case! { s = argv(0); wpn = 0; @@ -1056,7 +1077,7 @@ void weapon_defaultspawnfunc(float wpn) if(!self.respawntime) { - if(e.weapons & WEPBIT_SUPERWEAPONS) + if(WEPSET_CONTAINS_ANY_EA(e, WEPBIT_SUPERWEAPONS)) { self.respawntime = g_pickup_respawntime_superweapon; self.respawntimejitter = g_pickup_respawntimejitter_superweapon; @@ -1068,7 +1089,7 @@ void weapon_defaultspawnfunc(float wpn) } } - if(e.weapons & WEPBIT_SUPERWEAPONS) + if(WEPSET_CONTAINS_ANY_EA(e, WEPBIT_SUPERWEAPONS)) if(!self.superweapons_finished) self.superweapons_finished = autocvar_g_balance_superweapons_time; @@ -1092,14 +1113,19 @@ void weapon_defaultspawnfunc(float wpn) f = FL_WEAPON; // no weapon-stay on superweapons - if(e.weapons & WEPBIT_SUPERWEAPONS) + if(WEPSET_CONTAINS_ANY_EA(e, WEPBIT_SUPERWEAPONS)) f |= FL_NO_WEAPON_STAY; // weapon stay isn't supported for teamed weapons if(self.team) f |= FL_NO_WEAPON_STAY; - StartItem(e.model, "weapons/weaponpickup.wav", self.respawntime, self.respawntimejitter, e.message, 0, e.weapons, f, weapon_pickupevalfunc, e.bot_pickupbasevalue); + // stupid minstagib hack, don't ask + if(g_minstagib) + if(self.ammo_cells) + self.ammo_cells = autocvar_g_minstagib_ammo_drop; + + StartItem(e.model, "weapons/weaponpickup.wav", self.respawntime, self.respawntimejitter, e.message, 0, e.weapon, f, weapon_pickupevalfunc, e.bot_pickupbasevalue); if (self.modelindex) // don't precache if self was removed weapon_action(e.weapon, WR_PRECACHE); } @@ -1402,19 +1428,21 @@ void spawnfunc_target_items (void) else if(argv(i) == "jetpack") self.items |= IT_JETPACK; else if(argv(i) == "fuel_regen") self.items |= IT_FUEL_REGEN; else - for(j = WEP_FIRST; j <= WEP_LAST; ++j) { - e = get_weaponinfo(j); - if(argv(i) == e.netname) + for(j = WEP_FIRST; j <= WEP_LAST; ++j) { - self.weapons |= e.weapons; - if(self.spawnflags == 0 || self.spawnflags == 2) - weapon_action(e.weapon, WR_PRECACHE); - break; + e = get_weaponinfo(j); + if(argv(i) == e.netname) + { + WEPSET_OR_EW(self, j); + if(self.spawnflags == 0 || self.spawnflags == 2) + weapon_action(e.weapon, WR_PRECACHE); + break; + } } + if(j > WEP_LAST) + print("target_items: invalid item ", argv(i), "\n"); } - if(j > WEP_LAST) - print("target_items: invalid item ", argv(i), "\n"); } string itemprefix, valueprefix; @@ -1459,8 +1487,8 @@ void spawnfunc_target_items (void) for(j = WEP_FIRST; j <= WEP_LAST; ++j) { e = get_weaponinfo(j); - if(e.weapons) - self.netname = sprintf("%s %s%d %s", self.netname, itemprefix, !!(self.weapons & e.weapons), e.netname); + if(e.weapon) + self.netname = sprintf("%s %s%d %s", self.netname, itemprefix, WEPSET_CONTAINS_EW(self, j), e.netname); } } self.netname = strzone(self.netname); @@ -1521,6 +1549,36 @@ void spawnfunc_item_jetpack(void) #define OP_PLUS 3 #define OP_MINUS 4 +float GiveWeapon(entity e, float wpn, float op, float val) +{ + float v0, v1; + v0 = WEPSET_CONTAINS_EW(e, wpn); + switch(op) + { + case OP_SET: + if(val > 0) + WEPSET_OR_EW(e, wpn); + else + WEPSET_ANDNOT_EW(e, wpn); + break; + case OP_MIN: + case OP_PLUS: + if(val > 0) + WEPSET_OR_EW(e, wpn); + break; + case OP_MAX: + if(val <= 0) + WEPSET_ANDNOT_EW(e, wpn); + break; + case OP_MINUS: + if(val > 0) + WEPSET_ANDNOT_EW(e, wpn); + break; + } + v1 = WEPSET_CONTAINS_EW(e, wpn); + return (v0 != v1); +} + float GiveBit(entity e, .float fld, float bit, float op, float val) { float v0, v1; @@ -1601,7 +1659,9 @@ void GiveRot(entity e, float v0, float v1, .float rotfield, float rottime, .floa e.regenfield = max(e.regenfield, time + regentime); } +#define PREGIVE_WEAPONS(e) WEPSET_DECLARE_A(save_weapons); WEPSET_COPY_AE(save_weapons, e) #define PREGIVE(e,f) float save_##f; save_##f = (e).f +#define POSTGIVE_WEAPON(e,b,snd_incr,snd_decr) GiveSound((e), WEPSET_CONTAINS_AW(save_weapons, b), WEPSET_CONTAINS_EW(e, b), 0, snd_incr, snd_decr) #define POSTGIVE_BIT(e,f,b,snd_incr,snd_decr) GiveSound((e), save_##f & (b), (e).f & (b), 0, snd_incr, snd_decr) #define POSTGIVE_VALUE(e,f,t,snd_incr,snd_decr) GiveSound((e), save_##f, (e).f, t, snd_incr, snd_decr) #define POSTGIVE_VALUE_ROT(e,f,t,rotfield,rottime,regenfield,regentime,snd_incr,snd_decr) GiveRot((e), save_##f, (e).f, rotfield, rottime, regenfield, regentime); GiveSound((e), save_##f, (e).f, t, snd_incr, snd_decr) @@ -1628,7 +1688,7 @@ float GiveItems(entity e, float beginarg, float endarg) e.superweapons_finished = max(0, e.superweapons_finished - time); PREGIVE(e, items); - PREGIVE(e, weapons); + PREGIVE_WEAPONS(e); PREGIVE(e, strength_finished); PREGIVE(e, invincible_finished); PREGIVE(e, superweapons_finished); @@ -1681,8 +1741,9 @@ float GiveItems(entity e, float beginarg, float endarg) for(j = WEP_FIRST; j <= WEP_LAST; ++j) { wi = get_weaponinfo(j); - if(wi.weapons) - got += GiveBit(e, weapons, wi.weapons, op, val); + if(wi.weapon) + if not(wi.spawnflags & WEP_FLAG_MUTATORBLOCKED) + got += GiveWeapon(e, j, op, val); } case "allammo": got += GiveValue(e, ammo_cells, op, val); @@ -1743,7 +1804,7 @@ float GiveItems(entity e, float beginarg, float endarg) wi = get_weaponinfo(j); if(cmd == wi.netname) { - got += GiveBit(e, weapons, wi.weapons, op, val); + got += GiveWeapon(e, j, op, val); break; } } @@ -1762,11 +1823,11 @@ float GiveItems(entity e, float beginarg, float endarg) for(j = WEP_FIRST; j <= WEP_LAST; ++j) { wi = get_weaponinfo(j); - if(wi.weapons) + if(wi.weapon) { - POSTGIVE_BIT(e, weapons, wi.weapons, "weapons/weaponpickup.wav", string_null); - if not(save_weapons & wi.weapons) - if(e.weapons & wi.weapons) + POSTGIVE_WEAPON(e, j, "weapons/weaponpickup.wav", string_null); + if not(WEPSET_CONTAINS_AW(save_weapons, j)) + if(WEPSET_CONTAINS_EW(e, j)) weapon_action(wi.weapon, WR_PRECACHE); } } @@ -1781,7 +1842,7 @@ float GiveItems(entity e, float beginarg, float endarg) POSTGIVE_VALUE_ROT(e, health, 1, pauserothealth_finished, autocvar_g_balance_pause_health_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, "misc/megahealth.wav", string_null); if(e.superweapons_finished <= 0) - if(self.weapons & WEPBIT_SUPERWEAPONS) + if(WEPSET_CONTAINS_ANY_EA(self, WEPBIT_SUPERWEAPONS)) e.superweapons_finished = autocvar_g_balance_superweapons_time; if (g_minstagib) @@ -1803,7 +1864,7 @@ float GiveItems(entity e, float beginarg, float endarg) else e.superweapons_finished += time; - if not(e.weapons & W_WeaponBit(e.switchweapon)) + if not(WEPSET_CONTAINS_EW(e, e.switchweapon)) _switchweapon = TRUE; if(_switchweapon) W_SwitchWeapon_Force(e, w_getbestweapon(e));