void instagib_replace_item_with(entity this, GameItem def)
{
- entity new_item = NULL;
+ entity new_item = spawn();
switch (def)
{
case ITEM_Invisibility:
- new_item = new(item_invisibility);
new_item.invisibility_finished = autocvar_g_instagib_invisibility_time;
break;
case ITEM_Speed:
- new_item = new(item_speed);
new_item.speed_finished = autocvar_g_instagib_speed_time;
break;
- case ITEM_ExtraLife:
- new_item = new(item_extralife);
- break;
- case ITEM_VaporizerCells:
- new_item = new(item_vaporizer_cells);
- break;
- default:
- error("Unhandled replacement item.");
}
Item_CopyFields(this, new_item);
StartItem(new_item, def);
MUTATOR_HOOKFUNCTION(mutator_instagib, FilterItem)
{
entity item = M_ARGV(0, entity);
- entity def = item.itemdef;
- if(def == ITEM_Strength || def == ITEM_Shield || def == ITEM_HealthMega || def == ITEM_ArmorMega)
- {
- if(autocvar_g_powerups)
- instagib_replace_item_with_random_powerup(item);
- return true;
- }
- if(def == ITEM_Cells)
- {
- if(autocvar_g_instagib_ammo_convert_cells)
- instagib_replace_item_with(item, ITEM_VaporizerCells);
- return true;
- }
- else if(def == ITEM_Rockets)
- {
- if(autocvar_g_instagib_ammo_convert_rockets)
- instagib_replace_item_with(item, ITEM_VaporizerCells);
- return true;
- }
- else if(def == ITEM_Shells)
+ switch (item.itemdef)
{
- if(autocvar_g_instagib_ammo_convert_shells)
- instagib_replace_item_with(item, ITEM_VaporizerCells);
- return true;
- }
- else if(def == ITEM_Bullets)
- {
- if(autocvar_g_instagib_ammo_convert_bullets)
- instagib_replace_item_with(item, ITEM_VaporizerCells);
- return true;
+ case ITEM_Strength: case ITEM_Shield: case ITEM_HealthMega: case ITEM_ArmorMega:
+ if(autocvar_g_powerups)
+ instagib_replace_item_with_random_powerup(item);
+ return true;
+ case ITEM_Cells:
+ if(autocvar_g_instagib_ammo_convert_cells)
+ instagib_replace_item_with(item, ITEM_VaporizerCells);
+ return true;
+ case ITEM_Rockets:
+ if(autocvar_g_instagib_ammo_convert_rockets)
+ instagib_replace_item_with(item, ITEM_VaporizerCells);
+ return true;
+ case ITEM_Shells:
+ if(autocvar_g_instagib_ammo_convert_shells)
+ instagib_replace_item_with(item, ITEM_VaporizerCells);
+ return true;
+ case ITEM_Bullets:
+ if(autocvar_g_instagib_ammo_convert_bullets)
+ instagib_replace_item_with(item, ITEM_VaporizerCells);
+ return true;
}
- if(item.weapon == WEP_VAPORIZER.m_id && ITEM_IS_LOOT(item))
+ switch (item.weapon)
{
- SetResource(item, RES_CELLS, autocvar_g_instagib_ammo_drop);
- return false;
- }
-
- if(item.weapon == WEP_DEVASTATOR.m_id || item.weapon == WEP_VORTEX.m_id)
- {
- instagib_replace_item_with(item, ITEM_VaporizerCells);
- return true;
+ case WEP_VAPORIZER.m_id:
+ if (ITEM_IS_LOOT(item))
+ {
+ SetResource(item, RES_CELLS, autocvar_g_instagib_ammo_drop);
+ return false;
+ }
+ break;
+ case WEP_DEVASTATOR.m_id: case WEP_VORTEX.m_id:
+ instagib_replace_item_with(item, ITEM_VaporizerCells);
+ return true;
}
if(item.itemdef.instanceOfPowerup)
#ifdef SVQC
.float invisibility_finished;
-bool autocvar_g_powerups_invisibility = 1;
-float autocvar_g_balance_powerup_invisibility_alpha = 0.15;
-float autocvar_g_balance_powerup_invisibility_time = 30;
-void powerup_invisibility_init(Pickup this, entity item)
+bool autocvar_g_powerups_invisibility;
+float autocvar_g_balance_powerup_invisibility_alpha;
+float autocvar_g_balance_powerup_invisibility_time;
+void powerup_invisibility_init(Pickup def, entity item)
{
- if(autocvar_g_powerups_invisibility)
- this.spawnflags = ITEM_FLAG_NORMAL;
- else
- this.spawnflags = ITEM_FLAG_MUTATORBLOCKED;
+ if(!autocvar_g_powerups || !autocvar_g_powerups_invisibility)
+ def.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
if(!item.invisibility_finished)
item.invisibility_finished = (item.count) ? item.count : autocvar_g_balance_powerup_invisibility_time;
this.m_iteminit = powerup_invisibility_init;
#endif
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL;
this.m_itemid = IT_INVISIBILITY;
this.m_model = MDL_BUFF; // TODO: MDL_Invisibility_ITEM when new model available
this.m_skin = 12;
#endif
#ifdef SVQC
-bool autocvar_g_powerups_shield = 1;
+bool autocvar_g_powerups_shield;
float autocvar_g_balance_powerup_invincible_takedamage;
-float autocvar_g_balance_powerup_invincible_takeforce = 0.33;
+float autocvar_g_balance_powerup_invincible_takeforce;
float autocvar_g_balance_powerup_invincible_time;
-void powerup_shield_init(Pickup this, entity item)
+void powerup_shield_init(Pickup def, entity item)
{
- if(autocvar_g_powerups_shield)
- this.spawnflags = ITEM_FLAG_NORMAL;
- else
- this.spawnflags = ITEM_FLAG_MUTATORBLOCKED;
+ if(!autocvar_g_powerups || !autocvar_g_powerups_shield)
+ def.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
if(!item.invincible_finished)
item.invincible_finished = (item.count) ? item.count : autocvar_g_balance_powerup_invincible_time;
this.m_iteminit = powerup_shield_init;
#endif
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL;
this.m_itemid = IT_INVINCIBLE;
this.m_model = MDL_Shield_ITEM;
this.m_sound = SND_Shield;
#ifdef SVQC
.float speed_finished;
-bool autocvar_g_powerups_speed = 1;
-float autocvar_g_balance_powerup_speed_attackrate = 0.8;
-float autocvar_g_balance_powerup_speed_highspeed = 1.5;
-float autocvar_g_balance_powerup_speed_time = 30;
-void powerup_speed_init(Pickup this, entity item)
+bool autocvar_g_powerups_speed;
+float autocvar_g_balance_powerup_speed_attackrate;
+float autocvar_g_balance_powerup_speed_highspeed;
+float autocvar_g_balance_powerup_speed_time;
+void powerup_speed_init(Pickup def, entity item)
{
- if(autocvar_g_powerups_speed)
- this.spawnflags = ITEM_FLAG_NORMAL;
- else
- this.spawnflags = ITEM_FLAG_MUTATORBLOCKED;
+ if(!autocvar_g_powerups || !autocvar_g_powerups_speed)
+ def.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
if(!item.speed_finished)
item.speed_finished = (item.count) ? item.count : autocvar_g_balance_powerup_speed_time;
this.m_iteminit = powerup_speed_init;
#endif
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL;
this.m_itemid = IT_SPEED;
this.m_model = MDL_BUFF; // TODO: MDL_Speed_ITEM when new model available
this.m_skin = 9;
#endif
#ifdef SVQC
-bool autocvar_g_powerups_strength = 1;
+bool autocvar_g_powerups_strength;
float autocvar_g_balance_powerup_strength_damage;
float autocvar_g_balance_powerup_strength_force;
float autocvar_g_balance_powerup_strength_selfdamage;
float autocvar_g_balance_powerup_strength_selfforce;
float autocvar_g_balance_powerup_strength_time;
-void powerup_strength_init(Pickup this, entity item)
+void powerup_strength_init(Pickup def, entity item)
{
- if(autocvar_g_powerups_strength)
- this.spawnflags = ITEM_FLAG_NORMAL;
- else
- this.spawnflags = ITEM_FLAG_MUTATORBLOCKED;
+ if(!autocvar_g_powerups || !autocvar_g_powerups_strength)
+ def.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
if(!item.strength_finished)
item.strength_finished = (item.count) ? item.count : autocvar_g_balance_powerup_strength_time;
this.m_iteminit = powerup_strength_init;
#endif
#ifdef GAMEQC
+ this.spawnflags = ITEM_FLAG_NORMAL;
this.m_itemid = IT_STRENGTH;
this.m_model = MDL_Strength_ITEM;
this.m_sound = SND_Strength;
if (this.itemdef.spawnflags & ITEM_FLAG_MUTATORBLOCKED)
return false;
- if(this.itemdef.instanceOfPowerup)
- {
- if(autocvar_g_powerups > 0)
- return true;
- if(autocvar_g_powerups == 0)
- return false;
- }
- else
+ if(!this.itemdef.instanceOfPowerup)
{
if(autocvar_g_pickup_items > 0)
return true;
gettouch(this)(this, actor);
}
-// if defaultrespawntime is 0 get respawntime from the item definition
-// if defaultrespawntimejitter is 0 get respawntimejitter from the item definition
-void _StartItem(entity this, entity def, float defaultrespawntime, float defaultrespawntimejitter)
+void StartItem(entity this, entity def)
{
- string itemname = def.m_name;
- float(entity player, entity item) pickupevalfunc = def.m_pickupevalfunc;
- float pickupbasevalue = def.m_botvalue;
-
- startitem_failed = false;
+ if (def.m_spawnfunc_hookreplace)
+ def = def.m_spawnfunc_hookreplace(def, this);
+ this.itemdef = def;
+ if (def.m_canonical_spawnfunc != "") // FIXME why do weapons set itemdef to an entity that doesn't have this?
+ this.classname = def.m_canonical_spawnfunc;
- this.item_model_ent = def.m_model;
- this.item_pickupsound_ent = def.m_sound;
- if (!this.item_pickupsound)
- this.item_pickupsound = Sound_fixpath(this.item_pickupsound_ent);
+ startitem_failed = true; // early return means failure
+ // some mutators check for resources set by m_iteminit in FilterItem
if(def.m_iteminit)
def.m_iteminit(def, this);
+ // also checked by some mutators in FilterItem
+ this.items = def.m_itemid;
+ this.weapon = def.instanceOfWeaponPickup ? def.m_weapon.m_id : 0;
+ if(this.weapon)
+ STAT(WEAPONS, this) = WepSet_FromWeapon(REGISTRY_GET(Weapons, this.weapon));
+ this.flags = FL_ITEM | def.m_itemflags;
+
+ // FilterItem may change any field of a specific instance of an item, but
+ // it must not change any itemdef field (would cause mutators to break other mutators),
+ // and must not convert items into different ones (StartItem could be refactored to support that).
+ if(MUTATOR_CALLHOOK(FilterItem, this))
+ {
+ delete(this);
+ return;
+ }
+
+ if (!this.item_model_ent)
+ this.item_model_ent = def.m_model;
+
+ if (!this.item_pickupsound_ent)
+ this.item_pickupsound_ent = def.m_sound;
+ if (!this.item_pickupsound && this.item_pickupsound_ent)
+ this.item_pickupsound = Sound_fixpath(this.item_pickupsound_ent);
+ if (this.item_pickupsound == "")
+ LOG_WARNF("No pickup sound set for a %s", this.classname);
+
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;
- this.weapon = weaponid;
-
// bones_was_here TODO: implement sv_cullentities_dist and replace g_items_maxdist with it
if(!this.fade_end)
this.fade_end = autocvar_g_items_maxdist;
- if(weaponid)
- STAT(WEAPONS, this) = WepSet_FromWeapon(REGISTRY_GET(Weapons, weaponid));
-
- this.flags = FL_ITEM | def.m_itemflags;
+ // bones_was_here TODO: can we do this after we're sure the entity won't be deleted?
IL_PUSH(g_items, this);
- if(MUTATOR_CALLHOOK(FilterItem, this)) // error means we do not want the item
- {
- startitem_failed = true;
- delete(this);
- return;
- }
-
this.mdl = this.model ? this.model : strzone(this.item_model_ent.model_str());
setmodel(this, MDL_Null); // precision set below
// set item size before we spawn a waypoint or droptofloor or MoveOutOfSolid
traceline(this.origin, this.origin, MOVE_NORMAL, this);
if (trace_dpstartcontents & DPCONTENTS_NODROP)
{
- startitem_failed = true;
delete(this);
return;
}
// must be done after def.m_iteminit() as that may set ITEM_FLAG_MUTATORBLOCKED
if(!have_pickup_item(this))
{
- startitem_failed = true;
delete(this);
return;
}
// must be done before Item_Reset() and after MUTATORBLOCKED check (blocked items may have null func ptrs)
if(!this.respawntime) // both need to be set
{
- this.respawntime = defaultrespawntime ? defaultrespawntime : def.m_respawntime();
- this.respawntimejitter = defaultrespawntimejitter ? defaultrespawntimejitter : def.m_respawntimejitter();
+ if (def.m_respawntime)
+ this.respawntime = def.m_respawntime();
+ else
+ LOG_WARNF("Default respawntime for a %s is unavailable from its itemdef", this.classname);
+
+ if (def.m_respawntimejitter)
+ this.respawntimejitter = def.m_respawntimejitter();
+ else
+ LOG_WARNF("Default respawntimejitter for a %s is unavailable from its itemdef", this.classname);
}
if(this.angles != '0 0 0')
{
// target_give not yet supported; maybe later
print("removed targeted ", this.classname, "\n");
- startitem_failed = true;
delete(this);
return;
}
{
// why not flags & fl_item?
FOREACH_ENTITY_RADIUS(this.origin, 3, it.is_item, {
- LOG_TRACE("XXX Found duplicated item: ", itemname, vtos(this.origin));
+ LOG_TRACE("XXX Found duplicated item: ", def.m_name, vtos(this.origin));
LOG_TRACE(" vs ", it.netname, vtos(it.origin));
error("Mapper sucks.");
});
this.is_item = true;
}
- weaponsInMap |= WepSet_FromWeapon(REGISTRY_GET(Weapons, weaponid));
+ weaponsInMap |= WepSet_FromWeapon(REGISTRY_GET(Weapons, this.weapon));
if ( def.instanceOfPowerup
|| def.instanceOfWeaponPickup
|| (def.instanceOfHealth && def != ITEM_HealthSmall)
|| (def.instanceOfArmor && def != ITEM_ArmorSmall)
- || (itemid & (IT_KEY1 | IT_KEY2))
+ || (def.m_itemid & (IT_KEY1 | IT_KEY2))
)
{
if(!this.target || this.target == "")
}
this.bot_pickup = true;
- this.bot_pickupevalfunc = pickupevalfunc;
- this.bot_pickupbasevalue = pickupbasevalue;
- this.netname = itemname;
+ this.bot_pickupevalfunc = def.m_pickupevalfunc;
+ this.bot_pickupbasevalue = def.m_botvalue;
+ this.netname = def.m_name;
settouch(this, Item_Touch);
//this.effects |= EF_LOWPRECISION;
// call this hook after everything else has been done
if (MUTATOR_CALLHOOK(Item_Spawn, this))
{
- startitem_failed = true;
delete(this);
return;
}
precache_sound(this.item_pickupsound);
setItemGroup(this);
-}
-void StartItem(entity this, GameItem def)
-{
- def = def.m_spawnfunc_hookreplace(def, this);
-
- this.classname = def.m_canonical_spawnfunc;
-
- this.itemdef = def;
- _StartItem(this, this.itemdef, 0, 0);
+ startitem_failed = false;
}
#define IS_SMALL(def) ((def.instanceOfHealth && def == ITEM_HealthSmall) || (def.instanceOfArmor && def == ITEM_ArmorSmall))
bool autocvar_g_nodepthtestitems;
#define autocvar_g_weapon_stay cvar("g_weapon_stay")
-void StartItem(entity this, entity a);
-.int item_group;
-.int item_group_count;
-
float autocvar_sv_simple_items;
+
bool ItemSend(entity this, entity to, int sf);
const float ITEM_RESPAWN_TICKS = 10;
.bool is_item;
.entity itemdef;
-void _StartItem(entity this, entity def, float defaultrespawntime, float defaultrespawntimejitter);
+void StartItem(entity this, entity def);
+.int item_group;
+.int item_group_count;
void setItemGroup(entity this);
void setItemGroupCount();
else
this.glowmod = colormapPaletteColor(this.owner.clientcolors & 0x0F, true);
- GameItem def = wpn.m_pickup;
- this.itemdef = def;
- _StartItem(this, this.itemdef, this.respawntime, this.respawntimejitter);
+ StartItem(this, wpn.m_pickup);
#if 0 // WEAPONTODO
if (this.modelindex) { // don't precache if this was removed