2 #include "../dpdefs/csprogsdefs.qh"
3 #include "../common/util.qh"
4 #include "../common/buffs.qh"
5 #include "../common/weapons/weapons.qh"
6 #include "../client/autocvars.qh"
7 #include "../client/movetypes.qh"
8 #include "../client/main.qh"
9 #include "../csqcmodellib/common.qh"
10 #include "../csqcmodellib/cl_model.qh"
14 #include "../dpdefs/progsdefs.qh"
15 #include "../dpdefs/dpextensions.qh"
16 #include "../warpzonelib/util_server.qh"
17 #include "../common/constants.qh"
18 #include "../common/util.qh"
19 #include "../common/monsters/monsters.qh"
20 #include "../common/weapons/weapons.qh"
21 #include "weapons/weaponsystem.qh"
23 #include "autocvars.qh"
24 #include "constants.qh"
26 #include "../common/notifications.qh"
27 #include "../common/deathtypes.qh"
28 #include "mutators/mutators_include.qh"
36 Movetype_Physics_MatchServer(autocvar_cl_projectiles_sloppy);
37 if(self.move_flags & FL_ONGROUND)
38 { // For some reason move_avelocity gets set to '0 0 0' here ...
39 self.oldorigin = self.origin;
42 if(autocvar_cl_animate_items)
43 { // ... so reset it if animations are requested.
44 if(self.ItemStatus & ITS_ANIMATE1)
45 self.move_avelocity = '0 180 0';
47 if(self.ItemStatus & ITS_ANIMATE2)
48 self.move_avelocity = '0 -90 0';
52 else if (autocvar_cl_animate_items)
54 if(self.ItemStatus & ITS_ANIMATE1)
56 self.angles += self.move_avelocity * frametime;
57 setorigin(self, '0 0 10' + self.oldorigin + '0 0 8' * sin(time * 2));
60 if(self.ItemStatus & ITS_ANIMATE2)
62 self.angles += self.move_avelocity * frametime;
63 setorigin(self, '0 0 8' + self.oldorigin + '0 0 4' * sin(time * 3));
72 Movetype_Physics_MatchServer(autocvar_cl_projectiles_sloppy);
74 if(self.move_flags & FL_ONGROUND)
79 void ItemRead(float _IsNew)
85 self.origin_x = ReadCoord();
86 self.origin_y = ReadCoord();
87 self.origin_z = ReadCoord();
88 setorigin(self, self.origin);
89 self.oldorigin = self.origin;
94 self.angles_x = ReadCoord();
95 self.angles_y = ReadCoord();
96 self.angles_z = ReadCoord();
97 self.move_angles = self.angles;
102 self.mins_x = ReadCoord();
103 self.mins_y = ReadCoord();
104 self.mins_z = ReadCoord();
105 self.maxs_x = ReadCoord();
106 self.maxs_y = ReadCoord();
107 self.maxs_z = ReadCoord();
108 setsize(self, self.mins, self.maxs);
111 if(sf & ISF_STATUS) // need to read/write status frist so model can handle simple, fb etc.
113 self.ItemStatus = ReadByte();
115 if(self.ItemStatus & ITS_AVAILABLE)
118 self.colormod = self.glowmod = '1 1 1';
122 if (autocvar_cl_ghost_items_color)
124 self.alpha = autocvar_cl_ghost_items;
125 self.colormod = self.glowmod = autocvar_cl_ghost_items_color;
131 if(autocvar_cl_fullbright_items)
132 if(self.ItemStatus & ITS_ALLOWFB)
133 self.effects |= EF_FULLBRIGHT;
135 if(self.ItemStatus & ITS_STAYWEP)
137 self.colormod = self.glowmod = autocvar_cl_weapon_stay_color;
138 self.alpha = autocvar_cl_weapon_stay_alpha;
142 if(self.ItemStatus & ITS_POWERUP)
144 if(self.ItemStatus & ITS_AVAILABLE)
145 self.effects |= (EF_ADDITIVE | EF_FULLBRIGHT);
147 self.effects &= ~(EF_ADDITIVE | EF_FULLBRIGHT);
153 self.drawmask = MASK_NORMAL;
154 self.movetype = MOVETYPE_TOSS;
155 self.draw = ItemDraw;
161 string _fn = ReadString();
163 if(autocvar_cl_simple_items && (self.ItemStatus & ITS_ALLOWSI))
165 string _fn2 = substring(_fn, 0 , strlen(_fn) -4);
166 self.draw = ItemDrawSimple;
170 if(fexists(sprintf("%s%s.md3", _fn2, autocvar_cl_simpleitems_postfix)))
171 self.mdl = strzone(sprintf("%s%s.md3", _fn2, autocvar_cl_simpleitems_postfix));
172 else if(fexists(sprintf("%s%s.dpm", _fn2, autocvar_cl_simpleitems_postfix)))
173 self.mdl = strzone(sprintf("%s%s.dpm", _fn2, autocvar_cl_simpleitems_postfix));
174 else if(fexists(sprintf("%s%s.iqm", _fn2, autocvar_cl_simpleitems_postfix)))
175 self.mdl = strzone(sprintf("%s%s.iqm", _fn2, autocvar_cl_simpleitems_postfix));
176 else if(fexists(sprintf("%s%s.obj", _fn2, autocvar_cl_simpleitems_postfix)))
177 self.mdl = strzone(sprintf("%s%s.obj", _fn2, autocvar_cl_simpleitems_postfix));
180 self.draw = ItemDraw;
181 dprint("Simple item requested for ", _fn, " but no model exsist for it\n");
185 if(self.draw != ItemDrawSimple)
186 self.mdl = strzone(_fn);
190 dprint("^1WARNING!^7 self.mdl is unset for item ", self.classname, " tell tZork aboute this!\n");
192 precache_model(self.mdl);
193 setmodel(self, self.mdl);
196 if(sf & ISF_COLORMAP)
197 self.colormap = ReadShort();
202 //self.move_angles = '0 0 0';
203 self.move_movetype = MOVETYPE_TOSS;
204 self.move_velocity_x = ReadCoord();
205 self.move_velocity_y = ReadCoord();
206 self.move_velocity_z = ReadCoord();
207 self.velocity = self.move_velocity;
208 self.move_origin = self.oldorigin;
212 self.move_time = time;
213 self.spawntime = time;
216 self.move_time = max(self.move_time, time);
219 if(autocvar_cl_animate_items)
221 if(self.ItemStatus & ITS_ANIMATE1)
222 self.move_avelocity = '0 180 0';
224 if(self.ItemStatus & ITS_ANIMATE2)
225 self.move_avelocity = '0 -90 0';
232 bool ItemSend(entity to, int sf)
239 WriteByte(MSG_ENTITY, ENT_CLIENT_ITEM);
240 WriteByte(MSG_ENTITY, sf);
242 //WriteByte(MSG_ENTITY, self.cnt);
243 if(sf & ISF_LOCATION)
245 WriteCoord(MSG_ENTITY, self.origin.x);
246 WriteCoord(MSG_ENTITY, self.origin.y);
247 WriteCoord(MSG_ENTITY, self.origin.z);
252 WriteCoord(MSG_ENTITY, self.angles.x);
253 WriteCoord(MSG_ENTITY, self.angles.y);
254 WriteCoord(MSG_ENTITY, self.angles.z);
259 WriteCoord(MSG_ENTITY, self.mins.x);
260 WriteCoord(MSG_ENTITY, self.mins.y);
261 WriteCoord(MSG_ENTITY, self.mins.z);
262 WriteCoord(MSG_ENTITY, self.maxs.x);
263 WriteCoord(MSG_ENTITY, self.maxs.y);
264 WriteCoord(MSG_ENTITY, self.maxs.z);
268 WriteByte(MSG_ENTITY, self.ItemStatus);
274 dprint("^1WARNING!^7 self.mdl is unset for item ", self.classname, "exspect a crash just aboute now\n");
276 WriteString(MSG_ENTITY, self.mdl);
280 if(sf & ISF_COLORMAP)
281 WriteShort(MSG_ENTITY, self.colormap);
285 WriteCoord(MSG_ENTITY, self.velocity.x);
286 WriteCoord(MSG_ENTITY, self.velocity.y);
287 WriteCoord(MSG_ENTITY, self.velocity.z);
293 void ItemUpdate(entity item)
295 item.SendFlags |= ISF_LOCATION;
298 float have_pickup_item(void)
300 if(self.flags & FL_POWERUP)
302 if(autocvar_g_powerups > 0)
304 if(autocvar_g_powerups == 0)
309 if(autocvar_g_pickup_items > 0)
311 if(autocvar_g_pickup_items == 0)
314 if(self.weapons || (self.items & IT_AMMO)) // no item or ammo pickups in weaponarena
321 float Item_Customize()
323 if(self.spawnshieldtime)
325 if(self.weapons & ~other.weapons)
327 self.colormod = '0 0 0';
328 self.glowmod = self.colormod;
329 self.alpha = 0.5 + 0.5 * g_ghost_items; // halfway more alpha
336 self.colormod = stov(autocvar_g_ghost_items_color);
337 self.glowmod = self.colormod;
338 self.alpha = g_ghost_items;
347 void Item_Show (entity e, float mode)
349 e.effects &= ~(EF_ADDITIVE | EF_STARDUST | EF_FULLBRIGHT | EF_NODEPTHTEST);
350 e.ItemStatus &= ~ITS_STAYWEP;
353 // make the item look normal, and be touchable
355 e.solid = SOLID_TRIGGER;
356 e.spawnshieldtime = 1;
357 e.ItemStatus |= ITS_AVAILABLE;
361 // hide the item completely
362 e.model = string_null;
364 e.spawnshieldtime = 1;
365 e.ItemStatus &= ~ITS_AVAILABLE;
367 else if((e.flags & FL_WEAPON) && !(e.flags & FL_NO_WEAPON_STAY) && g_weapon_stay)
369 // make the item translucent and not touchable
371 e.solid = SOLID_TRIGGER; // can STILL be picked up!
372 e.effects |= EF_STARDUST;
373 e.spawnshieldtime = 0; // field indicates whether picking it up may give you anything other than the weapon
374 e.ItemStatus |= (ITS_AVAILABLE | ITS_STAYWEP);
378 //setmodel(e, "null");
380 e.colormod = '0 0 0';
381 e.glowmod = e.colormod;
382 e.spawnshieldtime = 1;
383 e.ItemStatus &= ~ITS_AVAILABLE;
386 if (e.items & IT_STRENGTH || e.items & IT_INVINCIBLE)
387 e.ItemStatus |= ITS_POWERUP;
389 if (autocvar_g_nodepthtestitems)
390 e.effects |= EF_NODEPTHTEST;
393 if (autocvar_g_fullbrightitems)
394 e.ItemStatus |= ITS_ALLOWFB;
396 if (autocvar_sv_simple_items)
397 e.ItemStatus |= ITS_ALLOWSI;
399 // relink entity (because solid may have changed)
400 setorigin(e, e.origin);
401 e.SendFlags |= ISF_STATUS;
406 self.nextthink = time;
407 if(self.origin != self.oldorigin)
409 self.oldorigin = self.origin;
414 void Item_Respawn (void)
418 if(self.items == IT_STRENGTH)
419 sound (self, CH_TRIGGER, "misc/strength_respawn.wav", VOL_BASE, ATTEN_NORM); // play respawn sound
420 else if(self.items == IT_INVINCIBLE)
421 sound (self, CH_TRIGGER, "misc/shield_respawn.wav", VOL_BASE, ATTEN_NORM); // play respawn sound
423 sound (self, CH_TRIGGER, "misc/itemrespawn.wav", VOL_BASE, ATTEN_NORM); // play respawn sound
424 setorigin (self, self.origin);
426 self.think = Item_Think;
427 self.nextthink = time;
429 //pointparticles(particleeffectnum("item_respawn"), self.origin + self.mins_z * '0 0 1' + '0 0 48', '0 0 0', 1);
430 pointparticles(particleeffectnum("item_respawn"), self.origin + 0.5 * (self.mins + self.maxs), '0 0 0', 1);
433 void Item_RespawnCountdown (void)
435 if(self.count >= ITEM_RESPAWN_TICKS)
437 if(self.waypointsprite_attached)
438 WaypointSprite_Kill(self.waypointsprite_attached);
443 self.nextthink = time + 1;
448 vector rgb = '1 0 1';
452 case IT_FUEL_REGEN: name = "item-fuelregen"; rgb = '1 0.5 0'; break;
453 case IT_JETPACK: name = "item-jetpack"; rgb = '0.5 0.5 0.5'; break;
454 case IT_STRENGTH: name = "item-strength"; rgb = '0 0 1'; break;
455 case IT_INVINCIBLE: name = "item-shield"; rgb = '1 0 1'; break;
459 MUTATOR_CALLHOOK(Item_RespawnCountdown);
462 if(self.flags & FL_WEAPON)
464 entity wi = get_weaponinfo(self.weapon);
473 WaypointSprite_Spawn(name, 0, 0, self, '0 0 64', world, 0, self, waypointsprite_attached, true, RADARICON_POWERUP, rgb);
474 if(self.waypointsprite_attached)
475 WaypointSprite_UpdateBuildFinished(self.waypointsprite_attached, time + ITEM_RESPAWN_TICKS);
479 print("Unknown powerup-marked item is wanting to respawn\n");
480 localcmd(sprintf("prvm_edict server %d\n", num_for_edict(self)));
483 sound (self, CH_TRIGGER, "misc/itemrespawncountdown.wav", VOL_BASE, ATTEN_NORM); // play respawn sound
484 if(self.waypointsprite_attached)
486 WaypointSprite_Ping(self.waypointsprite_attached);
487 //WaypointSprite_UpdateHealth(self.waypointsprite_attached, self.count);
492 void Item_RespawnThink()
494 self.nextthink = time;
495 if(self.origin != self.oldorigin)
497 self.oldorigin = self.origin;
501 if(time >= self.wait)
505 void Item_ScheduleRespawnIn(entity e, float t)
507 if((e.flags & FL_POWERUP) || (e.weapons & WEPSET_SUPERWEAPONS))
509 e.think = Item_RespawnCountdown;
510 e.nextthink = time + max(0, t - ITEM_RESPAWN_TICKS);
515 e.think = Item_RespawnThink;
521 void Item_ScheduleRespawn(entity e)
523 if(e.respawntime > 0)
526 Item_ScheduleRespawnIn(e, ITEM_RESPAWNTIME(e));
528 else // if respawntime is -1, this item does not respawn
532 void Item_ScheduleInitialRespawn(entity e)
535 Item_ScheduleRespawnIn(e, game_starttime - time + ITEM_RESPAWNTIME_INITIAL(e));
538 float Item_GiveAmmoTo(entity item, entity player, .float ammotype, float ammomax, float mode)
543 if (item.spawnshieldtime)
545 if ((player.ammotype < ammomax) || item.pickup_anyway)
547 player.ammotype = bound(player.ammotype, ammomax, player.ammotype + item.ammotype);
551 else if(g_weapon_stay == 2)
553 float mi = min(item.ammotype, ammomax);
554 if (player.ammotype < mi)
556 player.ammotype = mi;
567 player.pauserotfuel_finished = max(player.pauserotfuel_finished, time + autocvar_g_balance_pause_fuel_rot);
569 case ITEM_MODE_HEALTH:
570 player.pauserothealth_finished = max(player.pauserothealth_finished, time + autocvar_g_balance_pause_health_rot);
572 case ITEM_MODE_ARMOR:
573 player.pauserotarmor_finished = max(player.pauserotarmor_finished, time + autocvar_g_balance_pause_armor_rot);
581 float Item_GiveTo(entity item, entity player)
588 // if nothing happens to player, just return without taking the item
590 _switchweapon = false;
591 // in case the player has autoswitch enabled do the following:
592 // if the player is using their best weapon before items are given, they
593 // probably want to switch to an even better weapon after items are given
594 if (player.autoswitch)
595 if (player.switchweapon == w_getbestweapon(player))
596 _switchweapon = true;
598 if (!(player.weapons & WepSet_FromWeapon(player.switchweapon)))
599 _switchweapon = true;
601 pickedup |= Item_GiveAmmoTo(item, player, ammo_fuel, g_pickup_fuel_max, ITEM_MODE_FUEL);
602 pickedup |= Item_GiveAmmoTo(item, player, ammo_shells, g_pickup_shells_max, ITEM_MODE_NONE);
603 pickedup |= Item_GiveAmmoTo(item, player, ammo_nails, g_pickup_nails_max, ITEM_MODE_NONE);
604 pickedup |= Item_GiveAmmoTo(item, player, ammo_rockets, g_pickup_rockets_max, ITEM_MODE_NONE);
605 pickedup |= Item_GiveAmmoTo(item, player, ammo_cells, g_pickup_cells_max, ITEM_MODE_NONE);
606 pickedup |= Item_GiveAmmoTo(item, player, ammo_plasma, g_pickup_plasma_max, ITEM_MODE_NONE);
607 pickedup |= Item_GiveAmmoTo(item, player, health, item.max_health, ITEM_MODE_HEALTH);
608 pickedup |= Item_GiveAmmoTo(item, player, armorvalue, item.max_armorvalue, ITEM_MODE_ARMOR);
610 if (item.flags & FL_WEAPON)
614 it &= ~player.weapons;
616 if (it || (item.spawnshieldtime && item.pickup_anyway))
619 for(i = WEP_FIRST; i <= WEP_LAST; ++i)
620 if(it & WepSet_FromWeapon(i))
622 W_DropEvent(WR_PICKUP, player, i, item);
623 W_GiveWeapon(player, i);
628 if((it = (item.items - (item.items & player.items)) & IT_PICKUPMASK))
632 Send_Notification(NOTIF_ONE, player, MSG_INFO, INFO_ITEM_WEAPON_GOT, item.netname);
635 if (item.strength_finished)
638 player.strength_finished = max(player.strength_finished, time) + item.strength_finished;
640 if (item.invincible_finished)
643 player.invincible_finished = max(player.invincible_finished, time) + item.invincible_finished;
645 if (item.superweapons_finished)
648 player.superweapons_finished = max(player.superweapons_finished, time) + item.superweapons_finished;
653 // always eat teamed entities
661 if (player.switchweapon != w_getbestweapon(player))
662 W_SwitchWeapon_Force(player, w_getbestweapon(player));
667 void Item_Touch (void)
671 // remove the item if it's currnetly in a NODROP brush or hits a NOIMPACT surface (such as sky)
672 if(self.classname == "droppedweapon")
674 if (ITEM_TOUCH_NEEDKILL())
681 if (!IS_PLAYER(other))
687 if (self.solid != SOLID_TRIGGER)
689 if (self.owner == other)
691 if (time < self.item_spawnshieldtime)
694 switch(MUTATOR_CALLHOOK(ItemTouch))
696 case MUT_ITEMTOUCH_RETURN: { return; }
697 case MUT_ITEMTOUCH_PICKUP: { goto pickup; }
700 if (self.classname == "droppedweapon")
702 self.strength_finished = max(0, self.strength_finished - time);
703 self.invincible_finished = max(0, self.invincible_finished - time);
704 self.superweapons_finished = max(0, self.superweapons_finished - time);
707 if(!Item_GiveTo(self, other))
709 if (self.classname == "droppedweapon")
711 // undo what we did above
712 self.strength_finished += time;
713 self.invincible_finished += time;
714 self.superweapons_finished += time;
721 other.last_pickup = time;
723 pointparticles(particleeffectnum("item_pickup"), self.origin, '0 0 0', 1);
724 sound (other, CH_TRIGGER, self.item_pickupsound, VOL_BASE, ATTEN_NORM);
726 if (self.classname == "droppedweapon")
728 else if (!self.spawnshieldtime)
734 RandomSelection_Init();
735 for(head = world; (head = findfloat(head, team, self.team)); )
737 if(head.flags & FL_ITEM)
740 RandomSelection_Add(head, 0, string_null, head.cnt, 0);
743 e = RandomSelection_chosen_ent;
748 Item_ScheduleRespawn(e);
754 Item_Show(self, !self.state);
755 setorigin (self, self.origin);
757 if(self.classname != "droppedweapon")
759 self.think = Item_Think;
760 self.nextthink = time;
762 if(self.waypointsprite_attached)
763 WaypointSprite_Kill(self.waypointsprite_attached);
765 if((self.flags & FL_POWERUP) || (self.weapons & WEPSET_SUPERWEAPONS)) // do not spawn powerups initially!
766 Item_ScheduleInitialRespawn(self);
774 if(self.effects & EF_NODRAW)
776 // marker for item team search
777 dprint("Initializing item team ", ftos(self.team), "\n");
778 RandomSelection_Init();
779 for(head = world; (head = findfloat(head, team, self.team)); ) if(head.flags & FL_ITEM)
780 RandomSelection_Add(head, 0, string_null, head.cnt, 0);
781 e = RandomSelection_chosen_ent;
785 for(head = world; (head = findfloat(head, team, self.team)); ) if(head.flags & FL_ITEM)
789 // make it a non-spawned item
791 head.state = 1; // state 1 = initially hidden item
793 head.effects &= ~EF_NODRAW;
800 // Savage: used for item garbage-collection
801 // TODO: perhaps nice special effect?
802 void RemoveItem(void)
807 // pickup evaluation functions
808 // these functions decide how desirable an item is to the bots
810 float generic_pickupevalfunc(entity player, entity item) {return item.bot_pickupbasevalue;}
812 float weapon_pickupevalfunc(entity player, entity item)
814 float c, j, position;
816 // See if I have it already
817 if(item.weapons & ~player.weapons)
819 // If I can pick it up
820 if(!item.spawnshieldtime)
822 else if(player.ammo_cells || player.ammo_shells || player.ammo_plasma || player.ammo_nails || player.ammo_rockets)
824 // Skilled bots will grab more
825 c = bound(0, skill / 10, 1) * 0.5;
833 // If custom weapon priorities for bots is enabled rate most wanted weapons higher
834 if( bot_custom_weapon && c )
836 // Find the highest position on any range
838 for(j = 0; j < WEP_LAST ; ++j){
840 bot_weapons_far[j] == item.weapon ||
841 bot_weapons_mid[j] == item.weapon ||
842 bot_weapons_close[j] == item.weapon
853 position = WEP_LAST - position;
854 // item.bot_pickupbasevalue is overwritten here
855 return (BOT_PICKUP_RATING_LOW + ( (BOT_PICKUP_RATING_HIGH - BOT_PICKUP_RATING_LOW) * (position / WEP_LAST ))) * c;
859 return item.bot_pickupbasevalue * c;
862 float commodity_pickupevalfunc(entity player, entity item)
865 float need_shells = false, need_nails = false, need_rockets = false, need_cells = false, need_plasma = false, need_fuel = false;
869 // Detect needed ammo
870 for(i = WEP_FIRST; i <= WEP_LAST ; ++i)
872 wi = get_weaponinfo(i);
874 if (!(player.weapons & WepSet_FromWeapon(i)))
877 if(wi.items & IT_SHELLS)
879 else if(wi.items & IT_NAILS)
881 else if(wi.items & IT_ROCKETS)
883 else if(wi.items & IT_CELLS)
885 else if(wi.items & IT_PLASMA)
887 else if(wi.items & IT_FUEL)
891 // TODO: figure out if the player even has the weapon this ammo is for?
892 // may not affect strategy much though...
893 // find out how much more ammo/armor/health the player can hold
895 if (item.ammo_shells)
896 if (player.ammo_shells < g_pickup_shells_max)
897 c = c + max(0, 1 - player.ammo_shells / g_pickup_shells_max);
900 if (player.ammo_nails < g_pickup_nails_max)
901 c = c + max(0, 1 - player.ammo_nails / g_pickup_nails_max);
903 if (item.ammo_rockets)
904 if (player.ammo_rockets < g_pickup_rockets_max)
905 c = c + max(0, 1 - player.ammo_rockets / g_pickup_rockets_max);
908 if (player.ammo_cells < g_pickup_cells_max)
909 c = c + max(0, 1 - player.ammo_cells / g_pickup_cells_max);
911 if (item.ammo_plasma)
912 if (player.ammo_plasma < g_pickup_plasma_max)
913 c = c + max(0, 1 - player.ammo_plasma / g_pickup_plasma_max);
916 if (player.ammo_fuel < g_pickup_fuel_max)
917 c = c + max(0, 1 - player.ammo_fuel / g_pickup_fuel_max);
919 if (player.armorvalue < item.max_armorvalue)
920 c = c + max(0, 1 - player.armorvalue / item.max_armorvalue);
922 if (player.health < item.max_health)
923 c = c + max(0, 1 - player.health / item.max_health);
925 return item.bot_pickupbasevalue * c;
928 void Item_Damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
930 if(ITEM_DAMAGE_NEEDKILL(deathtype))
934 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)
936 startitem_failed = false;
939 self.model = itemmodel;
943 error(strcat("^1Tried to spawn ", itemname, " with no model!\n"));
947 if(self.item_pickupsound == "")
948 self.item_pickupsound = pickupsound;
950 if(!self.respawntime) // both need to be set
952 self.respawntime = defaultrespawntime;
953 self.respawntimejitter = defaultrespawntimejitter;
957 self.weapon = weaponid;
960 self.weapons = WepSet_FromWeapon(weaponid);
962 self.flags = FL_ITEM | itemflags;
964 if(MUTATOR_CALLHOOK(FilterItem)) // error means we do not want the item
966 startitem_failed = true;
971 // is it a dropped weapon?
972 if (self.classname == "droppedweapon")
974 self.reset = SUB_Remove;
975 // it's a dropped weapon
976 self.movetype = MOVETYPE_TOSS;
978 // Savage: remove thrown items after a certain period of time ("garbage collection")
979 self.think = RemoveItem;
980 self.nextthink = time + 20;
982 self.takedamage = DAMAGE_YES;
983 self.event_damage = Item_Damage;
985 if(self.strength_finished || self.invincible_finished || self.superweapons_finished)
988 if(!(self.weapons & ~WEPSET_SUPERWEAPONS)) // only superweapons
989 if(self.ammo_nails == 0)
990 if(self.ammo_cells == 0)
991 if(self.ammo_rockets == 0)
992 if(self.ammo_shells == 0)
993 if(self.ammo_fuel == 0)
995 if(self.armorvalue == 0)
998 // if item is worthless after a timer, have it expire then
999 self.nextthink = max(self.strength_finished, self.invincible_finished, self.superweapons_finished);
1002 // don't drop if in a NODROP zone (such as lava)
1003 traceline(self.origin, self.origin, MOVE_NORMAL, self);
1004 if (trace_dpstartcontents & DPCONTENTS_NODROP)
1006 startitem_failed = true;
1013 if(!have_pickup_item())
1015 startitem_failed = true;
1020 self.reset = Item_Reset;
1021 // it's a level item
1022 if(self.spawnflags & 1)
1025 self.movetype = MOVETYPE_NONE;
1027 self.movetype = MOVETYPE_TOSS;
1028 // do item filtering according to game mode and other things
1031 // first nudge it off the floor a little bit to avoid math errors
1032 setorigin(self, self.origin + '0 0 1');
1033 // set item size before we spawn a spawnfunc_waypoint
1034 if((itemflags & FL_POWERUP) || self.health || self.armorvalue)
1035 setsize (self, '-16 -16 0', '16 16 48');
1037 setsize (self, '-16 -16 0', '16 16 32');
1039 // note droptofloor returns false if stuck/or would fall too far
1041 waypoint_spawnforitem(self);
1045 * can't do it that way, as it would break maps
1046 * TODO make a target_give like entity another way, that perhaps has
1047 * the weapon name in a key
1050 // target_give not yet supported; maybe later
1051 print("removed targeted ", self.classname, "\n");
1052 startitem_failed = true;
1058 if(autocvar_spawn_debug >= 2)
1061 for(otheritem = findradius(self.origin, 3); otheritem; otheritem = otheritem.chain)
1063 // why not flags & fl_item?
1064 if(otheritem.is_item)
1066 dprint("XXX Found duplicated item: ", itemname, vtos(self.origin));
1067 dprint(" vs ", otheritem.netname, vtos(otheritem.origin), "\n");
1068 error("Mapper sucks.");
1071 self.is_item = true;
1074 weaponsInMap |= WepSet_FromWeapon(weaponid);
1076 precache_model (self.model);
1077 precache_sound (self.item_pickupsound);
1079 precache_sound ("misc/itemrespawncountdown.wav");
1080 if(itemid == IT_STRENGTH)
1081 precache_sound ("misc/strength_respawn.wav");
1082 else if(itemid == IT_INVINCIBLE)
1083 precache_sound ("misc/shield_respawn.wav");
1085 precache_sound ("misc/itemrespawn.wav");
1087 if((itemflags & (FL_POWERUP | FL_WEAPON)) || (itemid & (IT_HEALTH | IT_ARMOR | IT_KEY1 | IT_KEY2)))
1088 self.target = "###item###"; // for finding the nearest item using find()
1091 self.bot_pickup = true;
1092 self.bot_pickupevalfunc = pickupevalfunc;
1093 self.bot_pickupbasevalue = pickupbasevalue;
1094 self.mdl = self.model;
1095 self.netname = itemname;
1096 self.touch = Item_Touch;
1097 setmodel(self, "null"); // precision set below
1098 //self.effects |= EF_LOWPRECISION;
1100 if((itemflags & FL_POWERUP) || self.health || self.armorvalue)
1102 self.pos1 = '-16 -16 0';
1103 self.pos2 = '16 16 48';
1107 self.pos1 = '-16 -16 0';
1108 self.pos2 = '16 16 32';
1110 setsize (self, self.pos1, self.pos2);
1112 if(itemflags & FL_POWERUP)
1113 self.ItemStatus |= ITS_ANIMATE1;
1115 if(self.armorvalue || self.health)
1116 self.ItemStatus |= ITS_ANIMATE2;
1118 if(itemflags & FL_WEAPON)
1120 if (self.classname != "droppedweapon") // if dropped, colormap is already set up nicely
1121 self.colormap = 1024; // color shirt=0 pants=0 grey
1125 self.ItemStatus |= ITS_ANIMATE1;
1126 self.ItemStatus |= ISF_COLORMAP;
1130 if(self.team) // broken, no idea why.
1133 self.cnt = 1; // item probability weight
1135 self.effects |= EF_NODRAW; // marker for item team search
1136 InitializeEntity(self, Item_FindTeam, INITPRIO_FINDTARGET);
1141 Net_LinkEntity(self, false, 0, ItemSend);
1143 self.SendFlags |= ISF_SIZE;
1145 self.SendFlags |= ISF_ANGLES;
1147 // call this hook after everything else has been done
1148 if(MUTATOR_CALLHOOK(Item_Spawn))
1150 startitem_failed = true;
1155 void spawnfunc_item_rockets (void) {
1156 if(!self.ammo_rockets)
1157 self.ammo_rockets = g_pickup_rockets;
1158 if(!self.pickup_anyway)
1159 self.pickup_anyway = g_pickup_ammo_anyway;
1160 StartItem ("models/items/a_rockets.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "rockets", IT_ROCKETS, 0, 0, commodity_pickupevalfunc, 3000);
1163 void spawnfunc_item_shells (void);
1164 void spawnfunc_item_bullets (void) {
1166 if(autocvar_sv_q3acompat_machineshotgunswap)
1167 if(self.classname != "droppedweapon")
1169 weaponswapping = true;
1170 spawnfunc_item_shells();
1171 weaponswapping = false;
1175 if(!self.ammo_nails)
1176 self.ammo_nails = g_pickup_nails;
1177 if(!self.pickup_anyway)
1178 self.pickup_anyway = g_pickup_ammo_anyway;
1179 StartItem ("models/items/a_bullets.mdl", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "bullets", IT_NAILS, 0, 0, commodity_pickupevalfunc, 2000);
1182 void spawnfunc_item_cells (void) {
1183 if(!self.ammo_cells)
1184 self.ammo_cells = g_pickup_cells;
1185 if(!self.pickup_anyway)
1186 self.pickup_anyway = g_pickup_ammo_anyway;
1187 StartItem ("models/items/a_cells.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "cells", IT_CELLS, 0, 0, commodity_pickupevalfunc, 2000);
1190 void spawnfunc_item_plasma()
1192 if(!self.ammo_plasma)
1193 self.ammo_plasma = g_pickup_plasma;
1194 if(!self.pickup_anyway)
1195 self.pickup_anyway = g_pickup_ammo_anyway;
1196 StartItem ("models/items/a_cells.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "plasma", IT_PLASMA, 0, 0, commodity_pickupevalfunc, 2000);
1199 void spawnfunc_item_shells (void) {
1201 if(autocvar_sv_q3acompat_machineshotgunswap)
1202 if(self.classname != "droppedweapon")
1204 weaponswapping = true;
1205 spawnfunc_item_bullets();
1206 weaponswapping = false;
1210 if(!self.ammo_shells)
1211 self.ammo_shells = g_pickup_shells;
1212 if(!self.pickup_anyway)
1213 self.pickup_anyway = g_pickup_ammo_anyway;
1214 StartItem ("models/items/a_shells.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "shells", IT_SHELLS, 0, 0, commodity_pickupevalfunc, 500);
1217 void spawnfunc_item_armor_small (void) {
1218 if(!self.armorvalue)
1219 self.armorvalue = g_pickup_armorsmall;
1220 if(!self.max_armorvalue)
1221 self.max_armorvalue = g_pickup_armorsmall_max;
1222 if(!self.pickup_anyway)
1223 self.pickup_anyway = g_pickup_armorsmall_anyway;
1224 StartItem ("models/items/item_armor_small.md3", "misc/armor1.wav", g_pickup_respawntime_short, g_pickup_respawntimejitter_short, "5 Armor", IT_ARMOR_SHARD, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
1227 void spawnfunc_item_armor_medium (void) {
1228 if(!self.armorvalue)
1229 self.armorvalue = g_pickup_armormedium;
1230 if(!self.max_armorvalue)
1231 self.max_armorvalue = g_pickup_armormedium_max;
1232 if(!self.pickup_anyway)
1233 self.pickup_anyway = g_pickup_armormedium_anyway;
1234 StartItem ("models/items/item_armor_medium.md3", "misc/armor10.wav", g_pickup_respawntime_medium, g_pickup_respawntimejitter_medium, "25 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_MID);
1237 void spawnfunc_item_armor_big (void) {
1238 if(!self.armorvalue)
1239 self.armorvalue = g_pickup_armorbig;
1240 if(!self.max_armorvalue)
1241 self.max_armorvalue = g_pickup_armorbig_max;
1242 if(!self.pickup_anyway)
1243 self.pickup_anyway = g_pickup_armorbig_anyway;
1244 StartItem ("models/items/item_armor_big.md3", "misc/armor17_5.wav", g_pickup_respawntime_long, g_pickup_respawntimejitter_long, "50 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, 20000);
1247 void spawnfunc_item_armor_large (void) {
1248 if(!self.armorvalue)
1249 self.armorvalue = g_pickup_armorlarge;
1250 if(!self.max_armorvalue)
1251 self.max_armorvalue = g_pickup_armorlarge_max;
1252 if(!self.pickup_anyway)
1253 self.pickup_anyway = g_pickup_armorlarge_anyway;
1254 StartItem ("models/items/item_armor_large.md3", "misc/armor25.wav", g_pickup_respawntime_long, g_pickup_respawntimejitter_long, "100 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_HIGH);
1257 void spawnfunc_item_health_small (void) {
1258 if(!self.max_health)
1259 self.max_health = g_pickup_healthsmall_max;
1261 self.health = g_pickup_healthsmall;
1262 if(!self.pickup_anyway)
1263 self.pickup_anyway = g_pickup_healthsmall_anyway;
1264 StartItem ("models/items/g_h1.md3", "misc/minihealth.wav", g_pickup_respawntime_short, g_pickup_respawntimejitter_short, "5 Health", IT_5HP, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
1267 void spawnfunc_item_health_medium (void) {
1268 if(!self.max_health)
1269 self.max_health = g_pickup_healthmedium_max;
1271 self.health = g_pickup_healthmedium;
1272 if(!self.pickup_anyway)
1273 self.pickup_anyway = g_pickup_healthmedium_anyway;
1274 StartItem ("models/items/g_h25.md3", "misc/mediumhealth.wav", g_pickup_respawntime_short, g_pickup_respawntimejitter_short, "25 Health", IT_25HP, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_MID);
1277 void spawnfunc_item_health_large (void) {
1278 if(!self.max_health)
1279 self.max_health = g_pickup_healthlarge_max;
1281 self.health = g_pickup_healthlarge;
1282 if(!self.pickup_anyway)
1283 self.pickup_anyway = g_pickup_healthlarge_anyway;
1284 StartItem ("models/items/g_h50.md3", "misc/mediumhealth.wav", g_pickup_respawntime_medium, g_pickup_respawntimejitter_medium, "50 Health", IT_25HP, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_MID);
1287 void spawnfunc_item_health_mega (void) {
1288 if(!self.max_health)
1289 self.max_health = g_pickup_healthmega_max;
1291 self.health = g_pickup_healthmega;
1292 if(!self.pickup_anyway)
1293 self.pickup_anyway = g_pickup_healthmega_anyway;
1294 StartItem ("models/items/g_h100.md3", "misc/megahealth.wav", g_pickup_respawntime_long, g_pickup_respawntimejitter_long, "100 Health", IT_HEALTH, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_HIGH);
1297 // support old misnamed entities
1298 void spawnfunc_item_armor1() { spawnfunc_item_armor_small(); } // FIXME: in Quake this is green armor, in Xonotic maps it is an armor shard
1299 void spawnfunc_item_armor25() { spawnfunc_item_armor_large(); }
1300 void spawnfunc_item_health1() { spawnfunc_item_health_small(); }
1301 void spawnfunc_item_health25() { spawnfunc_item_health_medium(); }
1302 void spawnfunc_item_health100() { spawnfunc_item_health_mega(); }
1304 void spawnfunc_item_strength (void) {
1305 precache_sound("weapons/strength_fire.wav");
1306 if(!self.strength_finished)
1307 self.strength_finished = autocvar_g_balance_powerup_strength_time;
1308 StartItem ("models/items/g_strength.md3", "misc/powerup.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Strength Powerup", IT_STRENGTH, 0, FL_POWERUP, generic_pickupevalfunc, 100000);
1311 void spawnfunc_item_invincible (void) {
1312 if(!self.invincible_finished)
1313 self.invincible_finished = autocvar_g_balance_powerup_invincible_time;
1314 StartItem ("models/items/g_invincible.md3", "misc/powerup_shield.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Shield", IT_INVINCIBLE, 0, FL_POWERUP, generic_pickupevalfunc, 100000);
1318 void spawnfunc_item_quad (void) {self.classname = "item_strength";spawnfunc_item_strength();}
1320 void target_items_use (void)
1322 if(activator.classname == "droppedweapon")
1329 if (!IS_PLAYER(activator))
1331 if(activator.deadflag != DEAD_NO)
1336 for(e = world; (e = find(e, classname, "droppedweapon")); )
1337 if(e.enemy == activator)
1340 if(GiveItems(activator, 0, tokenize_console(self.netname)))
1341 centerprint(activator, self.message);
1344 void spawnfunc_target_items (void)
1350 self.use = target_items_use;
1351 if(!self.strength_finished)
1352 self.strength_finished = autocvar_g_balance_powerup_strength_time;
1353 if(!self.invincible_finished)
1354 self.invincible_finished = autocvar_g_balance_powerup_invincible_time;
1355 if(!self.superweapons_finished)
1356 self.superweapons_finished = autocvar_g_balance_superweapons_time;
1358 precache_sound("misc/itempickup.wav");
1359 precache_sound("misc/megahealth.wav");
1360 precache_sound("misc/armor25.wav");
1361 precache_sound("misc/powerup.wav");
1362 precache_sound("misc/poweroff.wav");
1363 precache_sound("weapons/weaponpickup.wav");
1365 n = tokenize_console(self.netname);
1366 if(argv(0) == "give")
1368 self.netname = substring(self.netname, argv_start_index(1), argv_end_index(-1) - argv_start_index(1));
1372 for(i = 0; i < n; ++i)
1374 if (argv(i) == "unlimited_ammo") self.items |= IT_UNLIMITED_AMMO;
1375 else if(argv(i) == "unlimited_weapon_ammo") self.items |= IT_UNLIMITED_WEAPON_AMMO;
1376 else if(argv(i) == "unlimited_superweapons") self.items |= IT_UNLIMITED_SUPERWEAPONS;
1377 else if(argv(i) == "strength") self.items |= IT_STRENGTH;
1378 else if(argv(i) == "invincible") self.items |= IT_INVINCIBLE;
1379 else if(argv(i) == "superweapons") self.items |= IT_SUPERWEAPON;
1380 else if(argv(i) == "jetpack") self.items |= IT_JETPACK;
1381 else if(argv(i) == "fuel_regen") self.items |= IT_FUEL_REGEN;
1384 for(j = WEP_FIRST; j <= WEP_LAST; ++j)
1386 e = get_weaponinfo(j);
1387 s = W_UndeprecateName(argv(i));
1390 self.weapons |= WepSet_FromWeapon(j);
1391 if(self.spawnflags == 0 || self.spawnflags == 2)
1392 WEP_ACTION(e.weapon, WR_INIT);
1397 print("target_items: invalid item ", argv(i), "\n");
1401 string itemprefix, valueprefix;
1402 if(self.spawnflags == 0)
1407 else if(self.spawnflags == 1)
1409 itemprefix = "max ";
1410 valueprefix = "max ";
1412 else if(self.spawnflags == 2)
1414 itemprefix = "min ";
1415 valueprefix = "min ";
1417 else if(self.spawnflags == 4)
1419 itemprefix = "minus ";
1420 valueprefix = "max ";
1424 error("invalid spawnflags");
1425 itemprefix = valueprefix = string_null;
1429 self.netname = sprintf("%s %s%d %s", self.netname, itemprefix, !!(self.items & IT_UNLIMITED_WEAPON_AMMO), "unlimited_weapon_ammo");
1430 self.netname = sprintf("%s %s%d %s", self.netname, itemprefix, !!(self.items & IT_UNLIMITED_SUPERWEAPONS), "unlimited_superweapons");
1431 self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, self.strength_finished * !!(self.items & IT_STRENGTH), "strength");
1432 self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, self.invincible_finished * !!(self.items & IT_INVINCIBLE), "invincible");
1433 self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, self.superweapons_finished * !!(self.items & IT_SUPERWEAPON), "superweapons");
1434 self.netname = sprintf("%s %s%d %s", self.netname, itemprefix, !!(self.items & IT_JETPACK), "jetpack");
1435 self.netname = sprintf("%s %s%d %s", self.netname, itemprefix, !!(self.items & IT_FUEL_REGEN), "fuel_regen");
1436 if(self.ammo_shells != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_shells), "shells");
1437 if(self.ammo_nails != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_nails), "nails");
1438 if(self.ammo_rockets != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_rockets), "rockets");
1439 if(self.ammo_cells != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_cells), "cells");
1440 if(self.ammo_plasma != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_plasma), "plasma");
1441 if(self.ammo_fuel != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_fuel), "fuel");
1442 if(self.health != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.health), "health");
1443 if(self.armorvalue != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.health), "armor");
1444 for(j = WEP_FIRST; j <= WEP_LAST; ++j)
1446 e = get_weaponinfo(j);
1448 self.netname = sprintf("%s %s%d %s", self.netname, itemprefix, !!(self.weapons & WepSet_FromWeapon(j)), e.netname);
1451 self.netname = strzone(self.netname);
1452 //print(self.netname, "\n");
1454 n = tokenize_console(self.netname);
1455 for(i = 0; i < n; ++i)
1457 for(j = WEP_FIRST; j <= WEP_LAST; ++j)
1459 e = get_weaponinfo(j);
1460 if(argv(i) == e.netname)
1462 WEP_ACTION(e.weapon, WR_INIT);
1469 void spawnfunc_item_fuel(void)
1472 self.ammo_fuel = g_pickup_fuel;
1473 if(!self.pickup_anyway)
1474 self.pickup_anyway = g_pickup_ammo_anyway;
1475 StartItem ("models/items/g_fuel.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "Fuel", IT_FUEL, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
1478 void spawnfunc_item_fuel_regen(void)
1480 if(start_items & IT_FUEL_REGEN)
1482 spawnfunc_item_fuel();
1485 StartItem ("models/items/g_fuelregen.md3", "misc/itempickup.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Fuel regenerator", IT_FUEL_REGEN, 0, FL_POWERUP, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
1488 void spawnfunc_item_jetpack(void)
1491 self.ammo_fuel = g_pickup_fuel_jetpack;
1492 if(start_items & IT_JETPACK)
1494 spawnfunc_item_fuel();
1497 StartItem ("models/items/g_jetpack.md3", "misc/itempickup.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Jet pack", IT_JETPACK, 0, FL_POWERUP, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
1500 float GiveWeapon(entity e, float wpn, float op, float val)
1503 v0 = (e.weapons & WepSet_FromWeapon(wpn));
1508 e.weapons |= WepSet_FromWeapon(wpn);
1510 e.weapons &= ~WepSet_FromWeapon(wpn);
1515 e.weapons |= WepSet_FromWeapon(wpn);
1519 e.weapons &= ~WepSet_FromWeapon(wpn);
1523 e.weapons &= ~WepSet_FromWeapon(wpn);
1526 v1 = (e.weapons & WepSet_FromWeapon(wpn));
1530 float GiveBit(entity e, .float fld, float bit, float op, float val)
1560 float GiveValue(entity e, .float fld, float op, float val)
1570 e.fld = max(e.fld, val); // min 100 cells = at least 100 cells
1573 e.fld = min(e.fld, val);
1586 void GiveSound(entity e, float v0, float v1, float t, string snd_incr, string snd_decr)
1593 sound (e, CH_TRIGGER, snd_decr, VOL_BASE, ATTEN_NORM);
1595 else if(v0 >= v0 + t)
1598 sound (e, CH_TRIGGER, snd_incr, VOL_BASE, ATTEN_NORM);
1602 void GiveRot(entity e, float v0, float v1, .float rotfield, float rottime, .float regenfield, float regentime)
1605 e.rotfield = max(e.rotfield, time + rottime);
1607 e.regenfield = max(e.regenfield, time + regentime);
1609 float GiveItems(entity e, float beginarg, float endarg)
1611 float got, i, j, val, op;
1612 float _switchweapon;
1621 _switchweapon = false;
1623 if (e.switchweapon == w_getbestweapon(e))
1624 _switchweapon = true;
1626 e.strength_finished = max(0, e.strength_finished - time);
1627 e.invincible_finished = max(0, e.invincible_finished - time);
1628 e.superweapons_finished = max(0, e.superweapons_finished - time);
1632 PREGIVE(e, strength_finished);
1633 PREGIVE(e, invincible_finished);
1634 PREGIVE(e, superweapons_finished);
1635 PREGIVE(e, ammo_nails);
1636 PREGIVE(e, ammo_cells);
1637 PREGIVE(e, ammo_plasma);
1638 PREGIVE(e, ammo_shells);
1639 PREGIVE(e, ammo_rockets);
1640 PREGIVE(e, ammo_fuel);
1641 PREGIVE(e, armorvalue);
1644 for(i = beginarg; i < endarg; ++i)
1648 if(cmd == "0" || stof(cmd))
1672 got += GiveBit(e, items, IT_FUEL_REGEN, op, val);
1673 got += GiveValue(e, strength_finished, op, val);
1674 got += GiveValue(e, invincible_finished, op, val);
1675 got += GiveValue(e, superweapons_finished, op, val);
1676 got += GiveBit(e, items, IT_UNLIMITED_AMMO, op, val);
1678 got += GiveBit(e, items, IT_JETPACK, op, val);
1679 got += GiveValue(e, health, op, val);
1680 got += GiveValue(e, armorvalue, op, val);
1682 for(j = WEP_FIRST; j <= WEP_LAST; ++j)
1684 wi = get_weaponinfo(j);
1686 if (!(wi.spawnflags & WEP_FLAG_MUTATORBLOCKED))
1687 got += GiveWeapon(e, j, op, val);
1690 got += GiveValue(e, ammo_cells, op, val);
1691 got += GiveValue(e, ammo_plasma, op, val);
1692 got += GiveValue(e, ammo_shells, op, val);
1693 got += GiveValue(e, ammo_nails, op, val);
1694 got += GiveValue(e, ammo_rockets, op, val);
1695 got += GiveValue(e, ammo_fuel, op, val);
1697 case "unlimited_ammo":
1698 got += GiveBit(e, items, IT_UNLIMITED_AMMO, op, val);
1700 case "unlimited_weapon_ammo":
1701 got += GiveBit(e, items, IT_UNLIMITED_WEAPON_AMMO, op, val);
1703 case "unlimited_superweapons":
1704 got += GiveBit(e, items, IT_UNLIMITED_SUPERWEAPONS, op, val);
1707 got += GiveBit(e, items, IT_JETPACK, op, val);
1710 got += GiveBit(e, items, IT_FUEL_REGEN, op, val);
1713 got += GiveValue(e, strength_finished, op, val);
1716 got += GiveValue(e, invincible_finished, op, val);
1718 case "superweapons":
1719 got += GiveValue(e, superweapons_finished, op, val);
1722 got += GiveValue(e, ammo_cells, op, val);
1725 got += GiveValue(e, ammo_plasma, op, val);
1728 got += GiveValue(e, ammo_shells, op, val);
1732 got += GiveValue(e, ammo_nails, op, val);
1735 got += GiveValue(e, ammo_rockets, op, val);
1738 got += GiveValue(e, health, op, val);
1741 got += GiveValue(e, armorvalue, op, val);
1744 got += GiveValue(e, ammo_fuel, op, val);
1747 for(j = WEP_FIRST; j <= WEP_LAST; ++j)
1749 wi = get_weaponinfo(j);
1750 if(cmd == wi.netname)
1752 got += GiveWeapon(e, j, op, val);
1757 print("give: invalid item ", cmd, "\n");
1764 POSTGIVE_BIT(e, items, IT_FUEL_REGEN, "misc/itempickup.wav", string_null);
1765 POSTGIVE_BIT(e, items, IT_UNLIMITED_SUPERWEAPONS, "misc/powerup.wav", "misc/poweroff.wav");
1766 POSTGIVE_BIT(e, items, IT_UNLIMITED_WEAPON_AMMO, "misc/powerup.wav", "misc/poweroff.wav");
1767 POSTGIVE_BIT(e, items, IT_JETPACK, "misc/itempickup.wav", string_null);
1768 for(j = WEP_FIRST; j <= WEP_LAST; ++j)
1770 wi = get_weaponinfo(j);
1773 POSTGIVE_WEAPON(e, j, "weapons/weaponpickup.wav", string_null);
1774 if (!(save_weapons & WepSet_FromWeapon(j)))
1775 if(e.weapons & WepSet_FromWeapon(j))
1776 WEP_ACTION(wi.weapon, WR_INIT);
1779 POSTGIVE_VALUE(e, strength_finished, 1, "misc/powerup.wav", "misc/poweroff.wav");
1780 POSTGIVE_VALUE(e, invincible_finished, 1, "misc/powerup_shield.wav", "misc/poweroff.wav");
1781 POSTGIVE_VALUE(e, ammo_nails, 0, "misc/itempickup.wav", string_null);
1782 POSTGIVE_VALUE(e, ammo_cells, 0, "misc/itempickup.wav", string_null);
1783 POSTGIVE_VALUE(e, ammo_plasma, 0, "misc/itempickup.wav", string_null);
1784 POSTGIVE_VALUE(e, ammo_shells, 0, "misc/itempickup.wav", string_null);
1785 POSTGIVE_VALUE(e, ammo_rockets, 0, "misc/itempickup.wav", string_null);
1786 POSTGIVE_VALUE_ROT(e, ammo_fuel, 1, pauserotfuel_finished, autocvar_g_balance_pause_fuel_rot, pauseregen_finished, autocvar_g_balance_pause_fuel_regen, "misc/itempickup.wav", string_null);
1787 POSTGIVE_VALUE_ROT(e, armorvalue, 1, pauserotarmor_finished, autocvar_g_balance_pause_armor_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, "misc/armor25.wav", string_null);
1788 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);
1790 if(e.superweapons_finished <= 0)
1791 if(self.weapons & WEPSET_SUPERWEAPONS)
1792 e.superweapons_finished = autocvar_g_balance_superweapons_time;
1794 if(e.strength_finished <= 0)
1795 e.strength_finished = 0;
1797 e.strength_finished += time;
1798 if(e.invincible_finished <= 0)
1799 e.invincible_finished = 0;
1801 e.invincible_finished += time;
1802 if(e.superweapons_finished <= 0)
1803 e.superweapons_finished = 0;
1805 e.superweapons_finished += time;
1807 if (!(e.weapons & WepSet_FromWeapon(e.switchweapon)))
1808 _switchweapon = true;
1810 W_SwitchWeapon_Force(e, w_getbestweapon(e));