#include <common/weapons/_all.qh>
+ #include <common/mutators/mutator/buffs/buffs.qh>
+
#include "../lib/warpzone/util_server.qh"
#elif defined(CSQC)
#include "physics/movetypes/movetypes.qh"
this.alpha = -1;
}
- if(!veh_hud)
- if(this.ItemStatus & ITS_STAYWEP)
+ if((!veh_hud) && (this.ItemStatus & ITS_STAYWEP))
{
this.colormod = this.glowmod = autocvar_cl_weapon_stay_color;
this.alpha = autocvar_cl_weapon_stay_alpha;
}
+
+ this.drawmask = ((this.alpha <= 0) ? 0 : MASK_NORMAL);
}
void ItemDraw(entity this)
if(this.ItemStatus & ITS_ANIMATE2)
this.avelocity = '0 -90 0';
}
+
+ // delay is for blocking item's position for a while;
+ // it's a workaround for dropped weapons that receive the position
+ // another time right after they spawn overriding animation position
+ this.onground_time = time + 0.5;
}
}
else if (autocvar_cl_animate_items)
if(this.ItemStatus & ITS_ANIMATE1)
{
this.angles += this.avelocity * frametime;
- setorigin(this, '0 0 10' + this.oldorigin + '0 0 8' * sin(time * 2));
+ float fade_in = bound(0, time - this.onground_time, 1);
+ setorigin(this, this.oldorigin + fade_in * ('0 0 10' + '0 0 8' * sin((time - this.onground_time) * 2)));
}
if(this.ItemStatus & ITS_ANIMATE2)
{
this.angles += this.avelocity * frametime;
- setorigin(this, '0 0 8' + this.oldorigin + '0 0 4' * sin(time * 3));
+ float fade_in = bound(0, time - this.onground_time, 1);
+ setorigin(this, this.oldorigin + fade_in * ('0 0 8' + '0 0 4' * sin((time - this.onground_time) * 3)));
}
}
{
if(warpzone_warpzones_exist)
{
- // just incase warpzones were initialized last, reset these
- //this.alpha = 1; // alpha is already set by the draw function
- this.drawmask = MASK_NORMAL;
+ setpredraw(this, func_null); // no need to keep running this
return;
}
float alph;
vector org = getpropertyvec(VF_ORIGIN);
- if(!checkpvs(org, this)) // this makes sense as long as we don't support recursive warpzones
- alph = 0;
- else if(this.fade_start)
- alph = bound(0, (this.fade_end - vlen(org - this.origin - 0.5 * (this.mins + this.maxs))) / (this.fade_end - this.fade_start), 1);
+ //if(!checkpvs(org, this)) // this makes sense as long as we don't support recursive warpzones
+ //alph = 0; // this shouldn't be needed, since items behind walls are culled anyway
+ if(this.fade_start)
+ {
+ if(vdist(org - this.origin, >, this.fade_end))
+ alph = 0; // save on some processing
+ else if(vdist(org - this.origin, <, this.fade_start))
+ alph = 1; // more processing saved
+ else
+ alph = bound(0, (this.fade_end - vlen(org - this.origin - 0.5 * (this.mins + this.maxs))) / (this.fade_end - this.fade_start), 1);
+ }
else
alph = 1;
//printf("%v <-> %v\n", view_origin, this.origin + 0.5 * (this.mins + this.maxs));
this.alpha = alph;
if(alph <= 0)
this.drawmask = 0;
- else
- this.drawmask = MASK_NORMAL;
+ //else
+ //this.drawmask = MASK_NORMAL; // reset by the setalpha function
}
void ItemRemove(entity this)
setsize(this, '-16 -16 0', (use_bigsize) ? '16 16 48' : '16 16 32');
}
- if(sf & ISF_STATUS) // need to read/write status frist so model can handle simple, fb etc.
+ if(sf & ISF_STATUS) // need to read/write status first so model can handle simple, fb etc.
{
this.ItemStatus = ReadByte();
if(this.ItemStatus & ITS_ALLOWFB)
this.effects |= EF_FULLBRIGHT;
- if(this.ItemStatus & ITS_POWERUP)
+ if(this.ItemStatus & ITS_GLOW)
{
if(this.ItemStatus & ITS_AVAILABLE)
this.effects |= (EF_ADDITIVE | EF_FULLBRIGHT);
this.fade_end = ReadShort();
this.fade_start = ReadShort();
- if(this.fade_start && !autocvar_cl_items_nofade)
+ if(!warpzone_warpzones_exist && this.fade_start && !autocvar_cl_items_nofade)
setpredraw(this, Item_PreDraw);
if(this.mdl)
string _fn2 = substring(_fn, 0 , strlen(_fn) -4);
this.draw = ItemDrawSimple;
- if(fexists(sprintf("%s%s.md3", _fn2, autocvar_cl_simpleitems_postfix)))
- this.mdl = strzone(sprintf("%s%s.md3", _fn2, autocvar_cl_simpleitems_postfix));
- else if(fexists(sprintf("%s%s.dpm", _fn2, autocvar_cl_simpleitems_postfix)))
- this.mdl = strzone(sprintf("%s%s.dpm", _fn2, autocvar_cl_simpleitems_postfix));
- else if(fexists(sprintf("%s%s.iqm", _fn2, autocvar_cl_simpleitems_postfix)))
- this.mdl = strzone(sprintf("%s%s.iqm", _fn2, autocvar_cl_simpleitems_postfix));
- else if(fexists(sprintf("%s%s.mdl", _fn2, autocvar_cl_simpleitems_postfix)))
- this.mdl = strzone(sprintf("%s%s.mdl", _fn2, autocvar_cl_simpleitems_postfix));
+ if(fexists(strcat(_fn2, autocvar_cl_simpleitems_postfix, ".md3")))
+ this.mdl = strzone(strcat(_fn2, autocvar_cl_simpleitems_postfix, ".md3"));
+ else if(fexists(strcat(_fn2, autocvar_cl_simpleitems_postfix, ".dpm")))
+ this.mdl = strzone(strcat(_fn2, autocvar_cl_simpleitems_postfix, ".dpm"));
+ else if(fexists(strcat(_fn2, autocvar_cl_simpleitems_postfix, ".iqm")))
+ this.mdl = strzone(strcat(_fn2, autocvar_cl_simpleitems_postfix, ".iqm"));
+ else if(fexists(strcat(_fn2, autocvar_cl_simpleitems_postfix, ".mdl")))
+ this.mdl = strzone(strcat(_fn2, autocvar_cl_simpleitems_postfix, ".mdl"));
else
{
this.draw = ItemDraw;
if(autocvar_g_pickup_items == 0)
return false;
if(g_weaponarena)
- if(this.weapons || (this.items & IT_AMMO)) // no item or ammo pickups in weaponarena
+ if(this.weapons || this.itemdef.instanceOfAmmo) // no item or ammo pickups in weaponarena
return false;
}
return true;
{
e.effects &= ~(EF_ADDITIVE | EF_STARDUST | EF_FULLBRIGHT | EF_NODEPTHTEST);
e.ItemStatus &= ~ITS_STAYWEP;
+ entity def = e.itemdef;
if (mode > 0)
{
// make the item look normal, and be touchable
e.spawnshieldtime = 1;
e.ItemStatus &= ~ITS_AVAILABLE;
}
- else {
- entity def = e.itemdef;
- bool nostay = def.instanceOfWeaponPickup ? !!(def.m_weapon.weapons & WEPSET_SUPERWEAPONS) : false // no weapon-stay on superweapons
- || e.team // weapon stay isn't supported for teamed weapons
- ;
- if(def.instanceOfWeaponPickup && !nostay && g_weapon_stay)
- {
- // make the item translucent and not touchable
- e.model = e.mdl;
- e.solid = SOLID_TRIGGER; // can STILL be picked up!
- e.effects |= EF_STARDUST;
- e.spawnshieldtime = 0; // field indicates whether picking it up may give you anything other than the weapon
- e.ItemStatus |= (ITS_AVAILABLE | ITS_STAYWEP);
- }
else
{
- //setmodel(e, "null");
- e.solid = SOLID_NOT;
- e.colormod = '0 0 0';
- //e.glowmod = e.colormod;
- e.spawnshieldtime = 1;
- e.ItemStatus &= ~ITS_AVAILABLE;
- }}
+ bool nostay = def.instanceOfWeaponPickup ? !!(def.m_weapon.weapons & WEPSET_SUPERWEAPONS) : false // no weapon-stay on superweapons
+ || e.team // weapon stay isn't supported for teamed weapons
+ ;
+ if(def.instanceOfWeaponPickup && !nostay && g_weapon_stay)
+ {
+ // make the item translucent and not touchable
+ e.model = e.mdl;
+ e.solid = SOLID_TRIGGER; // can STILL be picked up!
+ e.effects |= EF_STARDUST;
+ e.spawnshieldtime = 0; // field indicates whether picking it up may give you anything other than the weapon
+ e.ItemStatus |= (ITS_AVAILABLE | ITS_STAYWEP);
+ }
+ else
+ {
+ //setmodel(e, "null");
+ e.solid = SOLID_NOT;
+ e.colormod = '0 0 0';
+ //e.glowmod = e.colormod;
+ e.spawnshieldtime = 1;
+ e.ItemStatus &= ~ITS_AVAILABLE;
+ }
+ }
- if (e.items & ITEM_Strength.m_itemid || e.items & ITEM_Shield.m_itemid)
- e.ItemStatus |= ITS_POWERUP;
+ if (def.m_glow)
+ e.ItemStatus |= ITS_GLOW;
if (autocvar_g_nodepthtestitems)
e.effects |= EF_NODEPTHTEST;
void Item_Respawn (entity this)
{
Item_Show(this, 1);
- // this is ugly...
- if(this.items == ITEM_Strength.m_itemid)
- sound (this, CH_TRIGGER, SND_STRENGTH_RESPAWN, VOL_BASE, ATTEN_NORM); // play respawn sound
- else if(this.items == ITEM_Shield.m_itemid)
- sound (this, CH_TRIGGER, SND_SHIELD_RESPAWN, VOL_BASE, ATTEN_NORM); // play respawn sound
- else
- sound (this, CH_TRIGGER, SND_ITEMRESPAWN, VOL_BASE, ATTEN_NORM); // play respawn sound
+ sound(this, CH_TRIGGER, this.itemdef.m_respawnsound, VOL_BASE, ATTEN_NORM); // play respawn sound
setorigin(this, this.origin);
- if (Item_ItemsTime_Allow(this.itemdef) || this.weapons & WEPSET_SUPERWEAPONS)
+ if (Item_ItemsTime_Allow(this.itemdef) || (this.weapons & WEPSET_SUPERWEAPONS))
{
float t = Item_ItemsTime_UpdateTime(this, 0);
Item_ItemsTime_SetTime(this, t);
this.count += 1;
if(this.count == 1)
{
- MUTATOR_CALLHOOK(Item_RespawnCountdown, string_null, '0 0 0');
do {
{
entity wi = Weapons_from(this.weapon);
}
}
} while (0);
+ bool mutator_returnvalue = MUTATOR_CALLHOOK(Item_RespawnCountdown, this);
if(this.waypointsprite_attached)
{
GameItem def = this.itemdef;
- if (Item_ItemsTime_SpectatorOnly(def))
+ if (Item_ItemsTime_SpectatorOnly(def) && !mutator_returnvalue)
WaypointSprite_UpdateRule(this.waypointsprite_attached, 0, SPRITERULE_SPECTATOR);
WaypointSprite_UpdateBuildFinished(this.waypointsprite_attached, time + ITEM_RESPAWN_TICKS);
}
void Item_ScheduleRespawnIn(entity e, float t)
{
// if the respawn time is longer than 10 seconds, show a waypoint, otherwise, just respawn normally
- if ((Item_ItemsTime_Allow(e.itemdef) || e.weapons & WEPSET_SUPERWEAPONS) && (t - ITEM_RESPAWN_TICKS) > 0)
+ if ((Item_ItemsTime_Allow(e.itemdef) || (e.weapons & WEPSET_SUPERWEAPONS) || MUTATOR_CALLHOOK(Item_ScheduleRespawn, e, t)) && (t - ITEM_RESPAWN_TICKS) > 0)
{
setthink(e, Item_RespawnCountdown);
e.nextthink = time + max(0, t - ITEM_RESPAWN_TICKS);
e.scheduledrespawntime = e.nextthink + ITEM_RESPAWN_TICKS;
e.count = 0;
- t = Item_ItemsTime_UpdateTime(e, e.scheduledrespawntime);
- Item_ItemsTime_SetTime(e, t);
- Item_ItemsTime_SetTimesForAllPlayers();
+ if(Item_ItemsTime_Allow(e.itemdef) || (e.weapons & WEPSET_SUPERWEAPONS))
+ {
+ t = Item_ItemsTime_UpdateTime(e, e.scheduledrespawntime);
+ Item_ItemsTime_SetTime(e, t);
+ Item_ItemsTime_SetTimesForAllPlayers();
+ }
}
else
{
e.nextthink = time;
e.scheduledrespawntime = time + t;
e.wait = time + t;
+
+ if(Item_ItemsTime_Allow(e.itemdef) || (e.weapons & WEPSET_SUPERWEAPONS))
+ {
+ t = Item_ItemsTime_UpdateTime(e, e.scheduledrespawntime);
+ Item_ItemsTime_SetTime(e, t);
+ Item_ItemsTime_SetTimesForAllPlayers();
+ }
}
}
void Item_ScheduleInitialRespawn(entity e)
{
Item_Show(e, 0);
- Item_ScheduleRespawnIn(e, game_starttime - time + ((e.respawntimestart) ? e.respawntimestart : ITEM_RESPAWNTIME_INITIAL(e)));
+ Item_ScheduleRespawnIn(e, max(0, game_starttime - time) + ((e.respawntimestart) ? e.respawntimestart : ITEM_RESPAWNTIME_INITIAL(e)));
+}
+
+void GivePlayerHealth(entity player, float amount)
+{
+ if (amount == 0)
+ {
+ return;
+ }
+ player.health = bound(player.health, player.health + amount,
+ g_pickup_healthmega_max);
+ player.pauserothealth_finished = max(player.pauserothealth_finished, time +
+ autocvar_g_balance_pause_health_rot);
+}
+
+void GivePlayerArmor(entity player, float amount)
+{
+ if (amount == 0)
+ {
+ return;
+ }
+ player.armorvalue = bound(player.armorvalue, player.armorvalue + amount,
+ g_pickup_armormega_max);
+ player.pauserotarmor_finished = max(player.pauserotarmor_finished, time +
+ autocvar_g_balance_pause_armor_rot);
+}
+
+void GivePlayerAmmo(entity player, .float ammotype, float amount)
+{
+ float maxvalue = 999;
+ switch (ammotype)
+ {
+ case ammo_shells:
+ {
+ maxvalue = g_pickup_shells_max;
+ break;
+ }
+ case ammo_cells:
+ {
+ maxvalue = g_pickup_cells_max;
+ break;
+ }
+ case ammo_rockets:
+ {
+ maxvalue = g_pickup_rockets_max;
+ break;
+ }
+ case ammo_plasma:
+ {
+ maxvalue = g_pickup_plasma_max;
+ break;
+ }
+ case ammo_nails:
+ {
+ maxvalue = g_pickup_nails_max;
+ break;
+ }
+ case ammo_fuel:
+ {
+ maxvalue = g_pickup_fuel_max;
+ break;
+ }
+ }
+ player.(ammotype) = min(player.(ammotype) + amount, maxvalue);
+}
+
+void GivePlayerRandomWeapons(entity player, int num_weapons,
+ string weapon_names, float shells, float bullets, float rockets,
+ float cells, float plasma)
+{
+ if (num_weapons == 0)
+ {
+ return;
+ }
+ int num_potential_weapons = tokenize_console(weapon_names);
+ for (int i = 0; i < num_weapons; ++i)
+ {
+ RandomSelection_Init();
+ for (int j = 0; j < num_potential_weapons; ++j)
+ {
+ string weapon = argv(j);
+ FOREACH(Weapons, it != WEP_Null,
+ {
+ // Finding a weapon which player doesn't have.
+ if (!(player.weapons & it.m_wepset) && (it.netname == weapon))
+ {
+ RandomSelection_AddEnt(it, 1, 1);
+ break;
+ }
+ });
+ }
+ if (RandomSelection_chosen_ent == NULL)
+ {
+ return;
+ }
+ player.weapons |= RandomSelection_chosen_ent.m_wepset;
+ switch (RandomSelection_chosen_ent.ammo_field)
+ {
+ case (ammo_shells):
+ {
+ if (player.ammo_shells != 0)
+ {
+ break;
+ }
+ GivePlayerAmmo(player, ammo_shells, shells);
+ break;
+ }
+ case (ammo_nails):
+ {
+ if (player.ammo_nails != 0)
+ {
+ break;
+ }
+ GivePlayerAmmo(player, ammo_nails, bullets);
+ break;
+ }
+ case (ammo_rockets):
+ {
+ if (player.ammo_rockets != 0)
+ {
+ break;
+ }
+ GivePlayerAmmo(player, ammo_rockets, rockets);
+ break;
+ }
+ case (ammo_cells):
+ {
+ if (player.ammo_cells != 0)
+ {
+ break;
+ }
+ GivePlayerAmmo(player, ammo_cells, cells);
+ break;
+ }
+ case (ammo_plasma):
+ {
+ if (player.ammo_plasma != 0)
+ {
+ break;
+ }
+ GivePlayerAmmo(player, ammo_plasma, plasma);
+ break;
+ }
+ }
+ }
}
float Item_GiveAmmoTo(entity item, entity player, .float ammotype, float ammomax, float mode)
float Item_GiveTo(entity item, entity player)
{
- float _switchweapon;
float pickedup;
// if nothing happens to player, just return without taking the item
pickedup = false;
- _switchweapon = false;
+ int _switchweapon = 0;
// in case the player has autoswitch enabled do the following:
// if the player is using their best weapon before items are given, they
// probably want to switch to an even better weapon after items are given
- if (player.autoswitch)
- if (PS(player).m_switchweapon == w_getbestweapon(player))
- _switchweapon = true;
- if (!(player.weapons & WepSet_FromWeapon(PS(player).m_switchweapon)))
- _switchweapon = true;
+ if(CS(player).autoswitch)
+ {
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ if(player.(weaponentity).m_weapon != WEP_Null || slot == 0)
+ {
+ if(player.(weaponentity).m_switchweapon == w_getbestweapon(player, weaponentity))
+ _switchweapon |= BIT(slot);
+
+ if(!(player.weapons & WepSet_FromWeapon(player.(weaponentity).m_switchweapon)))
+ _switchweapon |= BIT(slot);
+ }
+ }
+ }
pickedup |= Item_GiveAmmoTo(item, player, ammo_fuel, g_pickup_fuel_max, ITEM_MODE_FUEL);
pickedup |= Item_GiveAmmoTo(item, player, ammo_shells, g_pickup_shells_max, ITEM_MODE_NONE);
FOREACH(Weapons, it != WEP_Null, {
if(w & (it.m_wepset))
{
- W_DropEvent(wr_pickup, player, it.m_id, item);
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ if(player.(weaponentity).m_weapon != WEP_Null || slot == 0)
+ W_DropEvent(wr_pickup, player, it.m_id, item, weaponentity);
+ }
W_GiveWeapon(player, it.m_id);
}
});
// crude hack to enforce switching weapons
if(g_cts && item.itemdef.instanceOfWeaponPickup)
{
- W_SwitchWeapon_Force(player, Weapons_from(item.weapon));
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ if(player.(weaponentity).m_weapon != WEP_Null || slot == 0)
+ W_SwitchWeapon_Force(player, Weapons_from(item.weapon), weaponentity);
+ }
return 1;
}
- if (_switchweapon)
- if (PS(player).m_switchweapon != w_getbestweapon(player))
- W_SwitchWeapon_Force(player, w_getbestweapon(player));
+ if(_switchweapon)
+ {
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ if(_switchweapon & BIT(slot))
+ if(player.(weaponentity).m_switchweapon != w_getbestweapon(player, weaponentity))
+ W_SwitchWeapon_Force(player, w_getbestweapon(player, weaponentity), weaponentity);
+ }
+ }
return 1;
}
_sound (toucher, (this.itemdef.instanceOfPowerup ? CH_TRIGGER_SINGLE : CH_TRIGGER), (this.item_pickupsound ? this.item_pickupsound : Sound_fixpath(this.item_pickupsound_ent)), VOL_BASE, ATTEN_NORM);
if (this.classname == "droppedweapon")
- delete (this);
+ delete(this);
else if (this.spawnshieldtime)
{
entity e;
RandomSelection_Init();
IL_EACH(g_items, it.team == this.team,
{
- if(it.classname != "item_flag_team" && it.classname != "item_kh_key")
+ if(it.itemdef) // is a registered item
{
Item_Show(it, -1);
RandomSelection_AddEnt(it, it.cnt, 0);
}
});
e = RandomSelection_chosen_ent;
-
+ Item_Show(e, 1); // reset its state so it is visible (extra sendflags doesn't matter, this happens anyway)
}
else
e = this;
RandomSelection_Init();
IL_EACH(g_items, it.team == this.team,
{
- if(it.classname != "item_flag_team" && it.classname != "item_kh_key")
+ if(it.itemdef) // is a registered item
RandomSelection_AddEnt(it, it.cnt, 0);
});
IL_EACH(g_items, it.team == this.team,
{
- if(it.classname != "item_flag_team" && it.classname != "item_kh_key")
+ if(it.itemdef) // is a registered item
{
if(it != e)
{
float weapon_pickupevalfunc(entity player, entity item)
{
- float c;
-
// See if I have it already
- if(item.weapons & ~player.weapons)
+ if(player.weapons & item.weapons)
{
// If I can pick it up
if(!item.spawnshieldtime)
- c = 0;
- else if(player.ammo_cells || player.ammo_shells || player.ammo_plasma || player.ammo_nails || player.ammo_rockets)
- {
- // Skilled bots will grab more
- c = bound(0, skill / 10, 1) * 0.5;
- }
- else
- c = 0;
+ return 0;
+ return ammo_pickupevalfunc(player, item);
+ }
+
+ // reduce weapon value if bot already got a good arsenal
+ float c = 1;
+ int weapons_value = 0;
+ FOREACH(Weapons, it != WEP_Null && (player.weapons & it.m_wepset), {
+ weapons_value += it.bot_pickupbasevalue;
+ });
+ c -= bound(0, weapons_value / 20000, 1) * 0.5;
+
+ return item.bot_pickupbasevalue * c;
+}
+
+float ammo_pickupevalfunc(entity player, entity item)
+{
+ bool need_shells = false, need_nails = false, need_rockets = false, need_cells = false, need_plasma = false, need_fuel = false;
+ entity wpn = NULL;
+ float c = 0;
+ float rating = 0;
+
+ // Detect needed ammo
+ if(item.itemdef.instanceOfWeaponPickup)
+ {
+ entity ammo = NULL;
+ if(item.ammo_shells) { need_shells = true; ammo = ITEM_Shells; }
+ else if(item.ammo_nails) { need_nails = true; ammo = ITEM_Bullets; }
+ else if(item.ammo_rockets) { need_rockets = true; ammo = ITEM_Rockets; }
+ else if(item.ammo_cells) { need_cells = true; ammo = ITEM_Cells; }
+ else if(item.ammo_plasma) { need_plasma = true; ammo = ITEM_Plasma; }
+ else if(item.ammo_fuel) { need_fuel = true; ammo = ITEM_JetpackFuel; }
+
+ if(!ammo)
+ return 0;
+ wpn = item;
+ rating = ammo.m_botvalue;
}
else
- c = 1;
-
- // If custom weapon priorities for bots is enabled rate most wanted weapons higher
- if( bot_custom_weapon && c )
- {
- // Find the highest position on any range
- int position = -1;
- for (int 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
- )
+ {
+ FOREACH(Weapons, it != WEP_Null, {
+ if(!(player.weapons & (it.m_wepset)))
+ continue;
+
+ switch(it.ammo_field)
{
- position = j;
- break;
+ case ammo_shells: need_shells = true; break;
+ case ammo_nails: need_nails = true; break;
+ case ammo_rockets: need_rockets = true; break;
+ case ammo_cells: need_cells = true; break;
+ case ammo_plasma: need_plasma = true; break;
+ case ammo_fuel: need_fuel = true; 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;
- }
+ });
+ rating = item.bot_pickupbasevalue;
}
- return item.bot_pickupbasevalue * c;
+ float noammorating = 0.5;
+
+ if ((need_shells) && (item.ammo_shells) && (player.ammo_shells < g_pickup_shells_max))
+ c = item.ammo_shells / max(noammorating, player.ammo_shells);
+
+ if ((need_nails) && (item.ammo_nails) && (player.ammo_nails < g_pickup_nails_max))
+ c = item.ammo_nails / max(noammorating, player.ammo_nails);
+
+ if ((need_rockets) && (item.ammo_rockets) && (player.ammo_rockets < g_pickup_rockets_max))
+ c = item.ammo_rockets / max(noammorating, player.ammo_rockets);
+
+ if ((need_cells) && (item.ammo_cells) && (player.ammo_cells < g_pickup_cells_max))
+ c = item.ammo_cells / max(noammorating, player.ammo_cells);
+
+ if ((need_plasma) && (item.ammo_plasma) && (player.ammo_plasma < g_pickup_plasma_max))
+ c = item.ammo_plasma / max(noammorating, player.ammo_plasma);
+
+ if ((need_fuel) && (item.ammo_fuel) && (player.ammo_fuel < g_pickup_fuel_max))
+ c = item.ammo_fuel / max(noammorating, player.ammo_fuel);
+
+ rating *= min(c, 2);
+ if(wpn)
+ rating += wpn.bot_pickupbasevalue * 0.1;
+ return rating;
}
-float commodity_pickupevalfunc(entity player, entity item)
+.int item_group;
+.int item_group_count;
+float healtharmor_pickupevalfunc(entity player, entity item)
{
- float c;
- float need_shells = false, need_nails = false, need_rockets = false, need_cells = false, need_plasma = false, need_fuel = false;
- c = 0;
+ float c = 0;
+ float rating = item.bot_pickupbasevalue;
- // Detect needed ammo
- FOREACH(Weapons, it != WEP_Null, {
- if(!(player.weapons & (it.m_wepset)))
- continue;
+ float itemarmor = item.armorvalue;
+ float itemhealth = item.health;
- if(it.items & ITEM_Shells.m_itemid)
- need_shells = true;
- else if(it.items & ITEM_Bullets.m_itemid)
- need_nails = true;
- else if(it.items & ITEM_Rockets.m_itemid)
- need_rockets = true;
- else if(it.items & ITEM_Cells.m_itemid)
- need_cells = true;
- else if(it.items & ITEM_Plasma.m_itemid)
- need_plasma = true;
- else if(it.items & ITEM_JetpackFuel.m_itemid)
- need_fuel = true;
- });
+ if(item.item_group)
+ {
+ itemarmor *= min(4, item.item_group_count);
+ itemhealth *= min(4, item.item_group_count);
+ }
- // TODO: figure out if the player even has the weapon this ammo is for?
- // may not affect strategy much though...
- // find out how much more ammo/armor/health the player can hold
- if (need_shells)
- if (item.ammo_shells)
- if (player.ammo_shells < g_pickup_shells_max)
- c = c + max(0, 1 - player.ammo_shells / g_pickup_shells_max);
- if (need_nails)
- if (item.ammo_nails)
- if (player.ammo_nails < g_pickup_nails_max)
- c = c + max(0, 1 - player.ammo_nails / g_pickup_nails_max);
- if (need_rockets)
- if (item.ammo_rockets)
- if (player.ammo_rockets < g_pickup_rockets_max)
- c = c + max(0, 1 - player.ammo_rockets / g_pickup_rockets_max);
- if (need_cells)
- if (item.ammo_cells)
- if (player.ammo_cells < g_pickup_cells_max)
- c = c + max(0, 1 - player.ammo_cells / g_pickup_cells_max);
- if (need_plasma)
- if (item.ammo_plasma)
- if (player.ammo_plasma < g_pickup_plasma_max)
- c = c + max(0, 1 - player.ammo_plasma / g_pickup_plasma_max);
- if (need_fuel)
- if (item.ammo_fuel)
- if (player.ammo_fuel < g_pickup_fuel_max)
- c = c + max(0, 1 - player.ammo_fuel / g_pickup_fuel_max);
- if (item.armorvalue)
- if (player.armorvalue < item.max_armorvalue)
- c = c + max(0, 1 - player.armorvalue / item.max_armorvalue);
- if (item.health)
- if (player.health < item.max_health)
- c = c + max(0, 1 - player.health / item.max_health);
+ if (itemarmor && (player.armorvalue < item.max_armorvalue))
+ c = itemarmor / max(1, player.armorvalue * 2/3 + player.health * 1/3);
- return item.bot_pickupbasevalue * c;
+ if (itemhealth && (player.health < item.max_health))
+ c = itemhealth / max(1, player.health);
+
+ rating *= min(2, c);
+ return rating;
}
void Item_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
RemoveItem(this);
}
+void item_use(entity this, entity actor, entity trigger)
+{
+ // use the touch function to handle collection
+ gettouch(this)(this, actor);
+}
+
void _StartItem(entity this, entity def, float defaultrespawntime, float defaultrespawntimejitter)
{
string itemname = def.m_name;
this.item_model_ent = itemmodel;
this.item_pickupsound_ent = pickupsound;
+ if(def.m_iteminit)
+ def.m_iteminit(this);
+
if(!this.respawntime) // both need to be set
{
this.respawntime = defaultrespawntime;
this.respawntimejitter = defaultrespawntimejitter;
}
+ if(!this.pickup_anyway && def.m_pickupanyway)
+ this.pickup_anyway = def.m_pickupanyway();
+
int itemid = def.m_itemid;
this.items = itemid;
int weaponid = def.instanceOfWeaponPickup ? def.m_weapon.m_id : 0;
if(!have_pickup_item(this))
{
startitem_failed = true;
- delete (this);
+ delete(this);
return;
}
// target_give not yet supported; maybe later
print("removed targeted ", this.classname, "\n");
startitem_failed = true;
- remove (this);
+ delete(this);
return;
}
*/
+ if(this.targetname != "" && (this.spawnflags & 16))
+ this.use = item_use;
+
if(autocvar_spawn_debug >= 2)
{
// why not flags & fl_item?
delete(this);
return;
}
+
+ setItemGroup(this);
}
void StartItem(entity this, GameItem def)
);
}
+#define IS_SMALL(def) ((def.instanceOfHealth && def == ITEM_HealthSmall) || (def.instanceOfArmor && def == ITEM_ArmorSmall))
+int group_count = 1;
+
+void setItemGroup(entity this)
+{
+ if(!IS_SMALL(this.itemdef))
+ return;
+
+ FOREACH_ENTITY_RADIUS(this.origin, 120, (it != this) && IS_SMALL(it.itemdef),
+ {
+ if(!this.item_group)
+ {
+ if(!it.item_group)
+ {
+ it.item_group = group_count;
+ group_count++;
+ }
+ this.item_group = it.item_group;
+ }
+ else // spawning item is already part of a item_group X
+ {
+ if(!it.item_group)
+ it.item_group = this.item_group;
+ else if(it.item_group != this.item_group) // found an item near the spawning item that is part of a different item_group Y
+ {
+ int grY = it.item_group;
+ // move all items of item_group Y to item_group X
+ IL_EACH(g_items, IS_SMALL(it.itemdef),
+ {
+ if(it.item_group == grY)
+ it.item_group = this.item_group;
+ });
+ }
+ }
+ });
+}
+
+void setItemGroupCount()
+{
+ for (int k = 1; k <= group_count; k++)
+ {
+ int count = 0;
+ IL_EACH(g_items, IS_SMALL(it.itemdef) && it.item_group == k, { count++; });
+ if (count)
+ IL_EACH(g_items, IS_SMALL(it.itemdef) && it.item_group == k, { it.item_group_count = count; });
+ }
+}
+
spawnfunc(item_rockets)
{
- if(!this.ammo_rockets)
- this.ammo_rockets = g_pickup_rockets;
- if(!this.pickup_anyway)
- this.pickup_anyway = g_pickup_ammo_anyway;
StartItem(this, ITEM_Rockets);
}
spawnfunc(item_bullets)
{
- if(!weaponswapping)
- if(autocvar_sv_q3acompat_machineshotgunswap)
- if(this.classname != "droppedweapon")
+ if(!weaponswapping && autocvar_sv_q3acompat_machineshotgunswap &&
+ (this.classname != "droppedweapon"))
{
weaponswapping = true;
spawnfunc_item_shells(this);
return;
}
- if(!this.ammo_nails)
- this.ammo_nails = g_pickup_nails;
- if(!this.pickup_anyway)
- this.pickup_anyway = g_pickup_ammo_anyway;
StartItem(this, ITEM_Bullets);
}
spawnfunc(item_cells)
{
- if(!this.ammo_cells)
- this.ammo_cells = g_pickup_cells;
- if(!this.pickup_anyway)
- this.pickup_anyway = g_pickup_ammo_anyway;
StartItem(this, ITEM_Cells);
}
spawnfunc(item_plasma)
{
- if(!this.ammo_plasma)
- this.ammo_plasma = g_pickup_plasma;
- if(!this.pickup_anyway)
- this.pickup_anyway = g_pickup_ammo_anyway;
StartItem(this, ITEM_Plasma);
}
spawnfunc(item_shells)
{
- if(!weaponswapping)
- if(autocvar_sv_q3acompat_machineshotgunswap)
- if(this.classname != "droppedweapon")
+ if(!weaponswapping && autocvar_sv_q3acompat_machineshotgunswap &&
+ (this.classname != "droppedweapon"))
{
weaponswapping = true;
spawnfunc_item_bullets(this);
return;
}
- if(!this.ammo_shells)
- this.ammo_shells = g_pickup_shells;
- if(!this.pickup_anyway)
- this.pickup_anyway = g_pickup_ammo_anyway;
StartItem(this, ITEM_Shells);
}
spawnfunc(item_armor_small)
{
- if(!this.armorvalue)
- this.armorvalue = g_pickup_armorsmall;
- if(!this.max_armorvalue)
- this.max_armorvalue = g_pickup_armorsmall_max;
- if(!this.pickup_anyway)
- this.pickup_anyway = g_pickup_armorsmall_anyway;
StartItem(this, ITEM_ArmorSmall);
}
spawnfunc(item_armor_medium)
{
- if(!this.armorvalue)
- this.armorvalue = g_pickup_armormedium;
- if(!this.max_armorvalue)
- this.max_armorvalue = g_pickup_armormedium_max;
- if(!this.pickup_anyway)
- this.pickup_anyway = g_pickup_armormedium_anyway;
StartItem(this, ITEM_ArmorMedium);
}
spawnfunc(item_armor_big)
{
- if(!this.armorvalue)
- this.armorvalue = g_pickup_armorbig;
- if(!this.max_armorvalue)
- this.max_armorvalue = g_pickup_armorbig_max;
- if(!this.pickup_anyway)
- this.pickup_anyway = g_pickup_armorbig_anyway;
- StartItem(this, ITEM_ArmorLarge);
+ StartItem(this, ITEM_ArmorBig);
}
-spawnfunc(item_armor_large)
+spawnfunc(item_armor_mega)
{
- if(!this.armorvalue)
- this.armorvalue = g_pickup_armorlarge;
- if(!this.max_armorvalue)
- this.max_armorvalue = g_pickup_armorlarge_max;
- if(!this.pickup_anyway)
- this.pickup_anyway = g_pickup_armorlarge_anyway;
StartItem(this, ITEM_ArmorMega);
}
spawnfunc(item_health_small)
{
- if(!this.max_health)
- this.max_health = g_pickup_healthsmall_max;
- if(!this.health)
- this.health = g_pickup_healthsmall;
- if(!this.pickup_anyway)
- this.pickup_anyway = g_pickup_healthsmall_anyway;
StartItem(this, ITEM_HealthSmall);
}
spawnfunc(item_health_medium)
{
- if(!this.max_health)
- this.max_health = g_pickup_healthmedium_max;
- if(!this.health)
- this.health = g_pickup_healthmedium;
- if(!this.pickup_anyway)
- this.pickup_anyway = g_pickup_healthmedium_anyway;
StartItem(this, ITEM_HealthMedium);
}
-spawnfunc(item_health_large)
+spawnfunc(item_health_big)
{
- if(!this.max_health)
- this.max_health = g_pickup_healthlarge_max;
- if(!this.health)
- this.health = g_pickup_healthlarge;
- if(!this.pickup_anyway)
- this.pickup_anyway = g_pickup_healthlarge_anyway;
- StartItem(this, ITEM_HealthLarge);
+ StartItem(this, ITEM_HealthBig);
}
spawnfunc(item_health_mega)
{
- if(!this.max_health)
- this.max_health = g_pickup_healthmega_max;
- if(!this.health)
- this.health = g_pickup_healthmega;
- if(!this.pickup_anyway)
- this.pickup_anyway = g_pickup_healthmega_anyway;
StartItem(this, ITEM_HealthMega);
}
// support old misnamed entities
spawnfunc(item_armor1) { spawnfunc_item_armor_small(this); } // FIXME: in Quake this is green armor, in Xonotic maps it is an armor shard
-spawnfunc(item_armor25) { spawnfunc_item_armor_large(this); }
+spawnfunc(item_armor25) { spawnfunc_item_armor_mega(this); }
+spawnfunc(item_armor_large) { spawnfunc_item_armor_mega(this); }
spawnfunc(item_health1) { spawnfunc_item_health_small(this); }
spawnfunc(item_health25) { spawnfunc_item_health_medium(this); }
+spawnfunc(item_health_large) { spawnfunc_item_health_big(this); }
spawnfunc(item_health100) { spawnfunc_item_health_mega(this); }
spawnfunc(item_strength)
{
- if(!this.strength_finished)
- this.strength_finished = autocvar_g_balance_powerup_strength_time;
- StartItem(this, ITEM_Strength);
+ StartItem(this, ITEM_Strength);
}
spawnfunc(item_invincible)
{
- if(!this.invincible_finished)
- this.invincible_finished = autocvar_g_balance_powerup_invincible_time;
- StartItem(this, ITEM_Shield);
+ StartItem(this, ITEM_Shield);
}
// compatibility:
return;
}
- if (!IS_PLAYER(actor))
- return;
- if(IS_DEAD(actor))
+ if (!IS_PLAYER(actor) || IS_DEAD(actor))
return;
+
if(trigger.solid == SOLID_TRIGGER)
{
EXACTTRIGGER_TOUCH(this, trigger);
spawnfunc(target_items)
{
- int n, j;
+ int n;
string s;
this.use = target_items_use;
}
else
{
- for(j = 0; j < n; ++j)
+ for(int j = 0; j < n; ++j)
{
if (argv(j) == "unlimited_ammo") this.items |= IT_UNLIMITED_AMMO;
else if(argv(j) == "unlimited_weapon_ammo") this.items |= IT_UNLIMITED_WEAPON_AMMO;
else if(argv(j) == "fuel_regen") this.items |= ITEM_JetpackRegen.m_itemid;
else
{
+ FOREACH(Buffs, it != BUFF_Null,
+ {
+ s = Buff_UndeprecateName(argv(j));
+ if(s == it.m_name)
+ {
+ this.buffs |= (it.m_itemid);
+ break;
+ }
+ });
FOREACH(Weapons, it != WEP_Null, {
s = W_UndeprecateName(argv(j));
if(s == it.netname)
if(this.ammo_fuel != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.ammo_fuel), "fuel");
if(this.health != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.health), "health");
if(this.armorvalue != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.armorvalue), "armor");
+ FOREACH(Buffs, it != BUFF_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(this.buffs & (it.m_itemid)), it.m_name));
FOREACH(Weapons, it != WEP_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(this.weapons & (it.m_wepset)), it.netname));
}
this.netname = strzone(this.netname);
//print(this.netname, "\n");
n = tokenize_console(this.netname);
- for(j = 0; j < n; ++j)
+ for(int j = 0; j < n; ++j)
{
FOREACH(Weapons, it != WEP_Null && W_UndeprecateName(argv(j)) == it.netname, {
it.wr_init(it);
spawnfunc(item_fuel)
{
- if(!this.ammo_fuel)
- this.ammo_fuel = g_pickup_fuel;
- if(!this.pickup_anyway)
- this.pickup_anyway = g_pickup_ammo_anyway;
StartItem(this, ITEM_JetpackFuel);
}
spawnfunc(item_jetpack)
{
- if(!this.ammo_fuel)
- this.ammo_fuel = g_pickup_fuel_jetpack;
if(start_items & ITEM_Jetpack.m_itemid)
{
spawnfunc_item_fuel(this);
return (v0 != v1);
}
+bool GiveBuff(entity e, Buff thebuff, int op, int val)
+{
+ bool had_buff = (e.buffs & thebuff.m_itemid);
+ switch(op)
+ {
+ case OP_SET:
+ if(val > 0)
+ e.buffs |= thebuff.m_itemid;
+ else
+ e.buffs &= ~thebuff.m_itemid;
+ break;
+ case OP_MIN:
+ case OP_PLUS:
+ if(val > 0)
+ e.buffs |= thebuff.m_itemid;
+ break;
+ case OP_MAX:
+ if(val <= 0)
+ e.buffs &= ~thebuff.m_itemid;
+ break;
+ case OP_MINUS:
+ if(val > 0)
+ e.buffs &= ~thebuff.m_itemid;
+ break;
+ }
+ bool have_buff = (e.buffs & thebuff.m_itemid);
+ return (had_buff != have_buff);
+}
+
void GiveSound(entity e, float v0, float v1, float t, Sound snd_incr, Sound snd_decr)
{
if(v1 == v0)
float GiveItems(entity e, float beginarg, float endarg)
{
float got, i, val, op;
- float _switchweapon;
string cmd;
val = 999;
got = 0;
- _switchweapon = false;
- if (e.autoswitch)
- if (PS(e).m_switchweapon == w_getbestweapon(e))
- _switchweapon = true;
+ int _switchweapon = 0;
+
+ if(CS(e).autoswitch)
+ {
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ if(e.(weaponentity).m_weapon != WEP_Null || slot == 0)
+ if(e.(weaponentity).m_switchweapon == w_getbestweapon(e, weaponentity))
+ _switchweapon |= BIT(slot);
+ }
+ }
e.strength_finished = max(0, e.strength_finished - time);
e.invincible_finished = max(0, e.invincible_finished - time);
got += GiveValue(e, armorvalue, op, val);
case "allweapons":
FOREACH(Weapons, it != WEP_Null && !(it.spawnflags & WEP_FLAG_MUTATORBLOCKED), got += GiveWeapon(e, it.m_id, op, val));
+ //case "allbuffs": // all buffs makes a player god, do not want!
+ //FOREACH(Buffs, it != BUFF_Null, got += GiveBuff(e, it.m_itemid, op, val));
case "allammo":
got += GiveValue(e, ammo_cells, op, val);
got += GiveValue(e, ammo_plasma, op, val);
got += GiveValue(e, ammo_fuel, op, val);
break;
default:
+ FOREACH(Buffs, it != BUFF_Null && Buff_UndeprecateName(cmd) == it.m_name,
+ {
+ got += GiveBuff(e, it, op, val);
+ break;
+ });
FOREACH(Weapons, it != WEP_Null && W_UndeprecateName(cmd) == it.netname, {
got += GiveWeapon(e, it.m_id, op, val);
break;
});
POSTGIVE_VALUE(e, strength_finished, 1, SND_POWERUP, SND_POWEROFF);
POSTGIVE_VALUE(e, invincible_finished, 1, SND_Shield, SND_POWEROFF);
+ //POSTGIVE_VALUE(e, superweapons_finished, 1, SND_Null, SND_Null);
POSTGIVE_VALUE(e, ammo_nails, 0, SND_ITEMPICKUP, SND_Null);
POSTGIVE_VALUE(e, ammo_cells, 0, SND_ITEMPICKUP, SND_Null);
POSTGIVE_VALUE(e, ammo_plasma, 0, SND_ITEMPICKUP, SND_Null);
else
e.superweapons_finished += time;
- if (!(e.weapons & WepSet_FromWeapon(PS(e).m_switchweapon)))
- _switchweapon = true;
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ if(e.(weaponentity).m_weapon != WEP_Null || slot == 0)
+ if(!(e.weapons & WepSet_FromWeapon(e.(weaponentity).m_switchweapon)))
+ _switchweapon |= BIT(slot);
+ }
+
if(_switchweapon)
- W_SwitchWeapon_Force(e, w_getbestweapon(e));
+ {
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ if(_switchweapon & BIT(slot))
+ {
+ Weapon wep = w_getbestweapon(e, weaponentity);
+ if(wep != e.(weaponentity).m_switchweapon)
+ W_SwitchWeapon_Force(e, wep, weaponentity);
+ }
+ }
+ }
return got;
}