gren.damageforcescale = 0;
gren.event_damage = M_Shambler_Attack_Lightning_Damage;
gren.damagedbycontents = true;
+ IL_PUSH(g_damagedbycontents, gren);
gren.missile_flags = MIF_SPLASH | MIF_ARC;
W_SetupProjVelocity_Explicit(gren, v_forward, v_up, (autocvar_g_monster_shambler_attack_lightning_speed), (autocvar_g_monster_shambler_attack_lightning_speed_up), 0, 0, false);
return false;
}
- spawnfunc(monster_shambler) { Monster_Spawn(this, MON_SHAMBLER.monsterid); }
+ spawnfunc(monster_shambler) { Monster_Spawn(this, true, MON_SHAMBLER.monsterid); }
#endif // SVQC
#ifdef SVQC
IL_PUSH(g_projectiles, proj);
IL_PUSH(g_bot_dodge, proj);
proj.damagedbycontents = true;
+ IL_PUSH(g_damagedbycontents, proj);
proj.bouncefactor = 0.3;
proj.bouncestop = 0.05;
return false;
}
- spawnfunc(monster_spider) { Monster_Spawn(this, MON_SPIDER.monsterid); }
+ spawnfunc(monster_spider) { Monster_Spawn(this, true, MON_SPIDER.monsterid); }
#endif // SVQC
#ifdef SVQC
return false;
}
- traceline(this.origin + this.view_ofs, targ.origin, 0, this);
+ traceline(this.origin + this.view_ofs, targ.origin, MOVE_NOMONSTERS, this);
- if((trace_fraction < 1) && (trace_ent != targ))
- return false;
+ if(trace_fraction < 1)
+ return false; // solid
if(autocvar_g_monsters_target_infront || (this.spawnflags & MONSTERFLAG_INFRONT))
if(this.enemy != targ)
return true;
}
- void Monster_Respawn(entity this) { Monster_Spawn(this, this.monsterid); }
+ void Monster_Respawn(entity this) { Monster_Spawn(this, true, this.monsterid); }
.vector pos1, pos2;
void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed)
{
- if(this.target2) { this.goalentity = find(NULL, targetname, this.target2); }
+ // update goal entity if lost
+ if(this.target2 && this.goalentity.targetname != this.target2) { this.goalentity = find(NULL, targetname, this.target2); }
entity targ;
}
else
{
- entity e = find(NULL, targetname, this.target2);
+ entity e = this.goalentity; //find(NULL, targetname, this.target2);
if(e.target2)
this.target2 = e.target2;
- else if(e.target)
+ else if(e.target) // compatibility
this.target2 = e.target;
movelib_brake_simple(this, stpspeed);
void Monster_Appear(entity this, entity actor, entity trigger)
{
this.enemy = actor;
- this.spawnflags &= ~MONSTERFLAG_APPEAR; // otherwise, we get an endless loop
- Monster_Spawn(this, this.monsterid);
+ Monster_Spawn(this, false, this.monsterid);
}
bool Monster_Appear_Check(entity this, int monster_id)
return;
}
- float reverse = false;
- vector a, b;
-
makevectors(this.angles);
- a = this.origin + '0 0 16';
- b = this.origin + '0 0 16' + v_forward * 32;
+ vector a = CENTER_OR_VIEWOFS(this);
+ vector b = CENTER_OR_VIEWOFS(this) + v_forward * 32;
traceline(a, b, MOVE_NORMAL, this);
+ bool reverse = false;
if(trace_fraction != 1.0)
- {
reverse = true;
-
- if(trace_ent)
- if(IS_PLAYER(trace_ent) && !(trace_ent.items & IT_STRENGTH))
- reverse = false;
- }
+ if(trace_ent && IS_PLAYER(trace_ent) && !(trace_ent.items & ITEM_Strength.m_itemid))
+ reverse = false;
+ if(trace_ent && IS_MONSTER(trace_ent))
+ reverse = true;
// TODO: fix this... tracing is broken if the floor is thin
/*
void Monster_Think(entity this)
{
setthink(this, Monster_Think);
- this.nextthink = this.ticrate;
+ this.nextthink = time + this.ticrate;
if(this.monster_lifetime)
if(time >= this.monster_lifetime)
return true;
}
- bool Monster_Spawn(entity this, int mon_id)
+ bool Monster_Spawn(entity this, bool check_appear, int mon_id)
{
// setup the basic required properties for a monster
entity mon = Monsters_from(mon_id);
if(!autocvar_g_monsters) { Monster_Remove(this); return false; }
if(!(this.spawnflags & MONSTERFLAG_RESPAWNED))
+ {
IL_PUSH(g_monsters, this);
+ IL_PUSH(g_damagedbycontents, this);
+ }
- if(Monster_Appear_Check(this, mon_id)) { return true; } // return true so the monster isn't removed
+ if(check_appear && Monster_Appear_Check(this, mon_id)) { return true; } // return true so the monster isn't removed
if(!this.monster_skill)
this.monster_skill = cvar("g_monsters_skill");
this.flags = FL_MONSTER;
this.classname = "monster";
this.takedamage = DAMAGE_AIM;
+ if(!this.bot_attack)
+ IL_PUSH(g_bot_targets, this);
this.bot_attack = true;
- IL_PUSH(g_bot_targets, this);
this.iscreature = true;
this.teleportable = true;
this.damagedbycontents = true;
this.oldtarget2 = this.target2;
this.pass_distance = 0;
this.deadflag = DEAD_NO;
- this.noalign = ((mon.spawnflags & MONSTER_TYPE_FLY) || (mon.spawnflags & MONSTER_TYPE_SWIM));
this.spawn_time = time;
this.gravity = 1;
this.monster_moveto = '0 0 0';
this.monster_face = '0 0 0';
this.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_BOTCLIP | DPCONTENTS_MONSTERCLIP;
+ if(!this.noalign) { this.noalign = ((mon.spawnflags & MONSTER_TYPE_FLY) || (mon.spawnflags & MONSTER_TYPE_SWIM)); }
if(!this.scale) { this.scale = 1; }
if(autocvar_g_monsters_edit) { this.grab = 1; }
if(autocvar_g_fullbrightplayers) { this.effects |= EF_FULLBRIGHT; }
if(d < dist)
{
e.fireball_impactvec = p;
- RandomSelection_Add(e, 0, string_null, 1 / (1 + d), !Fire_IsBurning(e));
+ RandomSelection_AddEnt(e, 1 / (1 + d), !Fire_IsBurning(e));
}
}
if(RandomSelection_chosen_ent)
void nade_monster_boom(entity this)
{
- entity e = spawnmonster(this.pokenade_type, 0, this.realowner, this.realowner, this.origin, false, false, 1);
+ entity e = spawnmonster(spawn(), this.pokenade_type, 0, this.realowner, this.realowner, this.origin, false, false, 1);
if(autocvar_g_nades_pokenade_monster_lifetime > 0)
e.monster_lifetime = time + autocvar_g_nades_pokenade_monster_lifetime;
setsize(_nade, '-16 -16 -16', '16 16 16');
set_movetype(_nade, MOVETYPE_BOUNCE);
- tracebox(_nade.origin, _nade.mins, _nade.maxs, _nade.origin, false, _nade);
+ tracebox(_nade.origin, _nade.mins, _nade.maxs, _nade.origin, MOVE_NOMONSTERS, _nade);
if (trace_startsolid)
setorigin(_nade, e.origin);
_nade.gravity = 1;
_nade.missile_flags = MIF_SPLASH | MIF_ARC;
_nade.damagedbycontents = true;
+ IL_PUSH(g_damagedbycontents, _nade);
_nade.angles = vectoangles(_nade.velocity);
_nade.flags = FL_PROJECTILE;
IL_PUSH(g_projectiles, _nade);
void vehicles_enter(entity pl, entity veh)
{
- // Remove this when bots know how to use vehicles
+ // Remove this when bots know how to use vehicles
if((IS_BOT_CLIENT(pl) && !autocvar_g_vehicles_allow_bots))
return;
this.iscreature = true;
this.teleportable = false; // no teleporting for vehicles, too buggy
this.damagedbycontents = true;
+ IL_PUSH(g_damagedbycontents, this);
this.vehicleid = info.vehicleid;
this.PlayerPhysplug = info.PlayerPhysplug;
this.event_damage = func_null;
else
this.nextthink = time + game_starttime;
- if(MUTATOR_CALLHOOK(VehicleSpawn, this))
+ if(!MUTATOR_CALLHOOK(VehicleInit, this))
return false;
return true;
missile.damageforcescale = WEP_CVAR(arc, bolt_damageforcescale);
missile.event_damage = W_Arc_Bolt_Damage;
missile.damagedbycontents = true;
+ IL_PUSH(g_damagedbycontents, missile);
settouch(missile, W_Arc_Bolt_Touch);
missile.use = W_Arc_Bolt_Explode_use;
||
forbidWeaponUse(this.owner)
||
+ PS(this.owner).m_switchweapon != WEP_ARC
+ ||
(!PHYS_INPUT_BUTTON_ATCK(this.owner) && !burst )
||
this.owner.vehicle
P(class, prefix, remote_edgedamage, float, NONE) \
P(class, prefix, remote_force, float, NONE) \
P(class, prefix, remote_jump_damage, float, NONE) \
+ P(class, prefix, remote_jump_force, float, NONE) \
P(class, prefix, remote_jump_radius, float, NONE) \
P(class, prefix, remote_jump_velocity_z_add, float, NONE) \
P(class, prefix, remote_jump_velocity_z_max, float, NONE) \
this.event_damage = func_null;
this.takedamage = DAMAGE_NO;
- float handled_as_rocketjump = false;
+ bool handled_as_rocketjump = false;
+ entity head = NULL;
- entity head = WarpZone_FindRadius(
- this.origin,
- WEP_CVAR(devastator, remote_jump_radius),
- false
- );
-
- while(head)
+ if(WEP_CVAR(devastator, remote_jump_radius))
{
- if(head.takedamage && (head == this.realowner))
+ head = WarpZone_FindRadius(
+ this.origin,
+ WEP_CVAR(devastator, remote_jump_radius),
+ false
+ );
+
+ while(head)
{
- float distance_to_head = vlen(this.origin - head.WarpZone_findradius_nearest);
- if(distance_to_head <= WEP_CVAR(devastator, remote_jump_radius))
+ if(head.takedamage && (head == this.realowner))
{
- // we handled this as a rocketjump :)
- handled_as_rocketjump = true;
-
- // modify velocity
- head.velocity_x *= 0.9;
- head.velocity_y *= 0.9;
- head.velocity_z = bound(
- WEP_CVAR(devastator, remote_jump_velocity_z_min),
- head.velocity.z + WEP_CVAR(devastator, remote_jump_velocity_z_add),
- WEP_CVAR(devastator, remote_jump_velocity_z_max)
- );
-
- // now do the damage
- RadiusDamage(
- this,
- head,
- WEP_CVAR(devastator, remote_jump_damage),
- WEP_CVAR(devastator, remote_jump_damage),
- WEP_CVAR(devastator, remote_jump_radius),
- NULL,
- head,
- 0,
- this.projectiledeathtype | HITTYPE_BOUNCE,
- NULL
- );
- break;
+ if(vdist(this.origin - head.WarpZone_findradius_nearest, <=, WEP_CVAR(devastator, remote_jump_radius)))
+ {
+ // we handled this as a rocketjump :)
+ handled_as_rocketjump = true;
+
+ // modify velocity
+ if(WEP_CVAR(devastator, remote_jump_velocity_z_add))
+ {
+ head.velocity_x *= 0.9;
+ head.velocity_y *= 0.9;
+ head.velocity_z = bound(
+ WEP_CVAR(devastator, remote_jump_velocity_z_min),
+ head.velocity.z + WEP_CVAR(devastator, remote_jump_velocity_z_add),
+ WEP_CVAR(devastator, remote_jump_velocity_z_max)
+ );
+ }
+
+ // now do the damage
+ RadiusDamage(
+ this,
+ head,
+ WEP_CVAR(devastator, remote_jump_damage),
+ WEP_CVAR(devastator, remote_jump_damage),
+ WEP_CVAR(devastator, remote_jump_radius),
+ NULL,
+ head,
+ (WEP_CVAR(devastator, remote_jump_force) ? WEP_CVAR(devastator, remote_jump_force) : 0),
+ this.projectiledeathtype | HITTYPE_BOUNCE,
+ NULL
+ );
+ break;
+ }
}
+ head = head.chain;
}
- head = head.chain;
}
RadiusDamage(
missile.health = WEP_CVAR(devastator, health);
missile.event_damage = W_Devastator_Damage;
missile.damagedbycontents = true;
+ IL_PUSH(g_damagedbycontents, missile);
set_movetype(missile, MOVETYPE_FLY);
PROJECTILE_MAKETRIGGER(missile);
if(fire & 2)
if(PS(actor).m_switchweapon == WEP_DEVASTATOR)
{
- entity rock;
bool rockfound = false;
- for(rock = NULL; (rock = find(rock, classname, "rocket")); ) if(rock.realowner == actor)
+ IL_EACH(g_projectiles, it.realowner == actor && it.classname == "rocket",
{
- if(!rock.rl_detonate_later)
+ if(!it.rl_detonate_later)
{
- rock.rl_detonate_later = true;
+ it.rl_detonate_later = true;
rockfound = true;
}
- }
+ });
if(rockfound)
sound(actor, CH_WEAPON_B, SND_ROCKET_DET, VOL_BASE, ATTN_NORM);
}
missile.damageforcescale = WEP_CVAR_PRI(hagar, damageforcescale);
missile.event_damage = W_Hagar_Damage;
missile.damagedbycontents = true;
+ IL_PUSH(g_damagedbycontents, missile);
settouch(missile, W_Hagar_Touch);
missile.use = W_Hagar_Explode_use;
missile.damageforcescale = WEP_CVAR_SEC(hagar, damageforcescale);
missile.event_damage = W_Hagar_Damage;
missile.damagedbycontents = true;
+ IL_PUSH(g_damagedbycontents, missile);
settouch(missile, W_Hagar_Touch2);
missile.cnt = 0;
missile.damageforcescale = WEP_CVAR_SEC(hagar, damageforcescale);
missile.event_damage = W_Hagar_Damage;
missile.damagedbycontents = true;
+ IL_PUSH(g_damagedbycontents, missile);
settouch(missile, W_Hagar_Touch); // not bouncy
missile.use = W_Hagar_Explode2_use;
{
// loadable hagar secondary attack, must always run each frame
- if(time < game_starttime)
+ if(time < game_starttime || PS(actor).m_switchweapon != WEP_HAGAR)
return;
bool loaded = actor.hagar_load >= WEP_CVAR_SEC(hagar, load_max);
void W_Hagar_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity, int fire)
{
- if(!(fire & 1) || actor.hagar_load || actor.hagar_loadblock)
+ if(!(fire & 1) || actor.hagar_load || actor.hagar_loadblock || PS(actor).m_switchweapon != WEP_HAGAR)
{
w_ready(thiswep, actor, weaponentity, fire);
return;
gren.damageforcescale = WEP_CVAR_SEC(hook, damageforcescale);
gren.event_damage = W_Hook_Damage;
gren.damagedbycontents = true;
+ IL_PUSH(g_damagedbycontents, gren);
gren.missile_flags = MIF_SPLASH | MIF_ARC;
gren.velocity = '0 0 1' * WEP_CVAR_SEC(hook, speed);
break;
}
- if((this.owner.sv_entnum == player_localentnum - 1) && autocvar_chase_active <= 0)
+ if((this.owner.sv_entnum == player_localentnum - 1))
{
switch(this.HookType)
{
default:
case NET_ENT_CLIENT_HOOK:
- a = view_origin + view_forward * vs.x + view_right * -vs.y + view_up * vs.z;
+ if(autocvar_chase_active > 0)
+ a = csqcplayer.origin;
+ else
+ a = view_origin + view_forward * vs.x + view_right * -vs.y + view_up * vs.z;
b = this.origin;
break;
case NET_ENT_CLIENT_ARC_BEAM:
gren.damageforcescale = WEP_CVAR_PRI(mortar, damageforcescale);
gren.event_damage = W_Mortar_Grenade_Damage;
gren.damagedbycontents = true;
+ IL_PUSH(g_damagedbycontents, gren);
gren.missile_flags = MIF_SPLASH | MIF_ARC;
W_SetupProjVelocity_UP_PRI(gren, mortar);
gren.damageforcescale = WEP_CVAR_SEC(mortar, damageforcescale);
gren.event_damage = W_Mortar_Grenade_Damage;
gren.damagedbycontents = true;
+ IL_PUSH(g_damagedbycontents, gren);
gren.missile_flags = MIF_SPLASH | MIF_ARC;
W_SetupProjVelocity_UP_SEC(gren, mortar);
if(WEP_CVAR_SEC(mortar, remote_detonateprimary))
{
bool nadefound = false;
- entity nade;
- for(nade = NULL; (nade = find(nade, classname, "grenade")); ) if(nade.realowner == actor)
+ IL_EACH(g_projectiles, it.realowner == actor && it.classname == "grenade",
{
- if(!nade.gl_detonate_later)
+ if(!it.gl_detonate_later)
{
- nade.gl_detonate_later = true;
+ it.gl_detonate_later = true;
nadefound = true;
}
- }
+ });
if(nadefound)
sound(actor, CH_WEAPON_B, SND_ROCKET_DET, VOL_BASE, ATTN_NORM);
}
// Do evasive maneuvers for world objects? ( this should be a cpu hog. :P )
if(WEP_CVAR(seeker, missile_smart) && (dist > WEP_CVAR(seeker, missile_smart_mindist)))
{
- // Is it a better idea (shorter distance) to trace to the target itthis?
+ // Is it a better idea (shorter distance) to trace to the target itself?
if( vdist(this.origin + olddir * this.wait, <, dist))
traceline(this.origin, this.origin + olddir * this.wait, false, this);
else
missile.health = WEP_CVAR(seeker, missile_health);
missile.damageforcescale = WEP_CVAR(seeker, missile_damageforcescale);
missile.damagedbycontents = true;
+ IL_PUSH(g_damagedbycontents, missile);
//missile.think = W_Seeker_Missile_Animate; // csqc projectiles.
if(missile.enemy != NULL)
TRANSMUTE(Observer, this);
this.iscreature = false;
this.teleportable = TELEPORT_SIMPLE;
+ if(this.damagedbycontents)
+ IL_REMOVE(g_damagedbycontents, this);
this.damagedbycontents = false;
this.health = FRAGS_SPECTATOR;
SetSpectatee_status(this, etof(this));
this.wasplayer = true;
this.iscreature = true;
this.teleportable = TELEPORT_NORMAL;
+ if(!this.damagedbycontents)
+ IL_PUSH(g_damagedbycontents, this);
this.damagedbycontents = true;
set_movetype(this, MOVETYPE_WALK);
this.solid = SOLID_SLIDEBOX;
FixPlayermodel(this);
this.drawonlytoclient = NULL;
+ this.viewloc = NULL;
+
this.crouch = false;
- this.view_ofs = STAT(PL_VIEW_OFS, NULL);
- setsize(this, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL));
+ this.view_ofs = STAT(PL_VIEW_OFS, this);
+ setsize(this, STAT(PL_MIN, this), STAT(PL_MAX, this));
this.spawnorigin = spot.origin;
setorigin(this, spot.origin + '0 0 1' * (1 - this.mins.z - 24));
// don't reset back to last position, even if new position is stuck in solid
void ClientInit_misc(entity this);
- .float ebouncefactor, ebouncestop; // electro's values
// TODO do we need all these fields, or should we stop autodetecting runtime
// changes and just have a console command to update this?
bool ClientInit_SendEntity(entity this, entity to, int sf)
this.netname_previous = strzone(this.netname);
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((teamplay && IS_PLAYER(this)) ? APP_TEAM_ENT(this, INFO_JOIN_CONNECT_TEAM) : INFO_JOIN_CONNECT), this.netname);
+ if(teamplay && IS_PLAYER(this))
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_JOIN_CONNECT_TEAM), this.netname);
+ else
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_JOIN_CONNECT, this.netname);
stuffcmd(this, clientstuff, "\n");
stuffcmd(this, "cl_particles_reloadeffects\n"); // TODO do we still need this?
if (IS_REAL_CLIENT(this))
sv_notice_join(this);
+ // update physics stats (players can spawn before physics runs)
+ Physics_UpdateStats(this, PHYS_HIGHSPEED(this));
+
IL_EACH(g_initforplayer, it.init_for_player, {
it.init_for_player(it, this);
});
void GetPressedKeys(entity this)
{
MUTATOR_CALLHOOK(GetPressedKeys, this);
- int keys = this.pressedkeys;
+ int keys = STAT(PRESSED_KEYS, this);
keys = BITSET(keys, KEY_FORWARD, this.movement.x > 0);
keys = BITSET(keys, KEY_BACKWARD, this.movement.x < 0);
keys = BITSET(keys, KEY_RIGHT, this.movement.y > 0);
keys = BITSET(keys, KEY_CROUCH, PHYS_INPUT_BUTTON_CROUCH(this));
keys = BITSET(keys, KEY_ATCK, PHYS_INPUT_BUTTON_ATCK(this));
keys = BITSET(keys, KEY_ATCK2, PHYS_INPUT_BUTTON_ATCK2(this));
- this.pressedkeys = keys;
+ this.pressedkeys = keys; // store for other users
+
+ STAT(PRESSED_KEYS, this) = keys;
}
/*
this.hit_time = spectatee.hit_time;
this.strength_finished = spectatee.strength_finished;
this.invincible_finished = spectatee.invincible_finished;
- this.pressedkeys = spectatee.pressedkeys;
+ STAT(PRESSED_KEYS, this) = STAT(PRESSED_KEYS, spectatee);
this.weapons = spectatee.weapons;
this.vortex_charge = spectatee.vortex_charge;
this.vortex_chargepool_ammo = spectatee.vortex_chargepool_ammo;
this.angles = spectatee.v_angle;
STAT(FROZEN, this) = STAT(FROZEN, spectatee);
this.revive_progress = spectatee.revive_progress;
+ this.viewloc = spectatee.viewloc;
if(!PHYS_INPUT_BUTTON_USE(this) && STAT(CAMERA_SPECTATOR, this) != 2)
this.fixangle = true;
setorigin(this, spectatee.origin);
bool SpectateUpdate(entity this)
{
if(!this.enemy)
- return false;
+ return false;
if(!IS_PLAYER(this.enemy) || this == this.enemy)
{
}
}
- .float caplayer;
-
- void LeaveSpectatorMode(entity this)
+ .bool team_selected;
+ bool ShowTeamSelection(entity this)
{
- if(this.caplayer)
- return;
- if(nJoinAllowed(this, this))
- {
- if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || (this.wasplayer && autocvar_g_changeteam_banned) || this.team_forced > 0)
- {
- TRANSMUTE(Player, this);
-
- SetSpectatee(this, NULL);
+ if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || this.team_selected || (this.wasplayer && autocvar_g_changeteam_banned) || this.team_forced > 0)
+ return false;
+ stuffcmd(this, "menu_showteamselect\n");
+ return true;
+ }
+ void Join(entity this)
+ {
+ TRANSMUTE(Player, this);
- if(autocvar_g_campaign || autocvar_g_balance_teams)
- { JoinBestTeam(this, false, true); }
+ if(!this.team_selected)
+ if(autocvar_g_campaign || autocvar_g_balance_teams)
+ JoinBestTeam(this, false, true);
- if(autocvar_g_campaign)
- { campaign_bots_may_start = true; }
+ if(autocvar_g_campaign)
+ campaign_bots_may_start = true;
- Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_PREVENT_JOIN);
+ Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_PREVENT_JOIN);
- PutClientInServer(this);
+ PutClientInServer(this);
- if(IS_PLAYER(this)) { Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((teamplay && this.team != -1) ? APP_TEAM_ENT(this, INFO_JOIN_PLAY_TEAM) : INFO_JOIN_PLAY), this.netname); }
- }
- else
- stuffcmd(this, "menu_showteamselect\n");
- }
+ if(teamplay && this.team != -1)
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_JOIN_PLAY_TEAM), this.netname);
else
- {
- // Player may not join because g_maxplayers is set
- Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_JOIN_PREVENT);
- }
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_JOIN_PLAY, this.netname);
+ this.team_selected = false;
}
/**
* it checks whether the number of currently playing players exceeds g_maxplayers.
* @return int number of free slots for players, 0 if none
*/
- bool nJoinAllowed(entity this, entity ignore)
+ int nJoinAllowed(entity this, entity ignore)
{
if(!ignore)
// this is called that way when checking if anyone may be able to join (to build qcstatus)
// so report 0 free slots if restricted
{
if(autocvar_g_forced_team_otherwise == "spectate")
- return false;
+ return 0;
if(autocvar_g_forced_team_otherwise == "spectator")
- return false;
+ return 0;
}
- if(this.team_forced < 0)
- return false; // forced spectators can never join
+ if(this && this.team_forced < 0)
+ return 0; // forced spectators can never join
// TODO simplify this
int totalClients = 0;
++currentlyPlaying;
));
+ float free_slots = 0;
if (!autocvar_g_maxplayers)
- return maxclients - totalClients;
+ free_slots = maxclients - totalClients;
+ else if(currentlyPlaying < autocvar_g_maxplayers)
+ free_slots = min(maxclients - totalClients, autocvar_g_maxplayers - currentlyPlaying);
- if(currentlyPlaying < autocvar_g_maxplayers)
- return min(maxclients - totalClients, autocvar_g_maxplayers - currentlyPlaying);
+ static float join_prevent_msg_time = 0;
+ if(this && ignore && !free_slots && time > join_prevent_msg_time)
+ {
+ Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_JOIN_PREVENT);
+ join_prevent_msg_time = time + 3;
+ }
- return false;
+ return free_slots;
}
/**
}
}
+ bool joinAllowed(entity this)
+ {
+ if (this.version_mismatch) return false;
+ if (!nJoinAllowed(this, this)) return false;
+ if (teamplay && lockteams) return false;
+ if (ShowTeamSelection(this)) return false;
+ if (MUTATOR_CALLHOOK(ForbidSpawn, this)) return false;
+ return true;
+ }
+
void ObserverThink(entity this)
{
if ( this.impulse )
MinigameImpulse(this, this.impulse);
this.impulse = 0;
}
+
if (this.flags & FL_JUMPRELEASED) {
- if (PHYS_INPUT_BUTTON_JUMP(this) && !this.version_mismatch) {
+ if (PHYS_INPUT_BUTTON_JUMP(this) && joinAllowed(this)) {
this.flags &= ~FL_JUMPRELEASED;
this.flags |= FL_SPAWNING;
} else if(PHYS_INPUT_BUTTON_ATCK(this) && !this.version_mismatch) {
if(this.flags & FL_SPAWNING)
{
this.flags &= ~FL_SPAWNING;
- LeaveSpectatorMode(this);
+ Join(this);
return;
}
}
return;
}
}
+
if (this.flags & FL_JUMPRELEASED) {
- if (PHYS_INPUT_BUTTON_JUMP(this) && !this.version_mismatch) {
+ if (PHYS_INPUT_BUTTON_JUMP(this) && joinAllowed(this)) {
this.flags &= ~FL_JUMPRELEASED;
this.flags |= FL_SPAWNING;
} else if(PHYS_INPUT_BUTTON_ATCK(this) || this.impulse == 10 || this.impulse == 15 || this.impulse == 18 || (this.impulse >= 200 && this.impulse <= 209)) {
if(this.flags & FL_SPAWNING)
{
this.flags &= ~FL_SPAWNING;
- LeaveSpectatorMode(this);
+ Join(this);
return;
}
}
{
if ((this.respawn_flags & RESPAWN_FORCE) && !(this.respawn_time < this.respawn_time_max))
this.deadflag = DEAD_RESPAWNING;
- else if (!button_pressed || (this.respawn_flags & RESPAWN_FORCE))
+ else if (!button_pressed || (time >= this.respawn_time_max && (this.respawn_flags & RESPAWN_FORCE)))
this.deadflag = DEAD_DEAD;
break;
}
.float noalign; // if set to 1, the item or spawnpoint won't be dropped to the floor
.vector death_origin;
- .vector killer_origin;
float default_player_alpha;
float default_weapon_alpha;
string clientstuff;
.float phase;
- .int pressedkeys = _STAT(PRESSED_KEYS);
+ .int pressedkeys;
.string fog;
////
- .entity player_stats;
- //.float playerid;
- .string playernick;
- .float elos;
- .float ranks;
-
.string cvar_cl_physics;
.void(entity this, entity player) init_for_player;
+IntrusiveList g_damagedbycontents;
+STATIC_INIT(g_damagedbycontents) { g_damagedbycontents = IL_NEW(); }
+
IntrusiveList g_monsters;
STATIC_INIT(g_monsters) { g_monsters = IL_NEW(); }
string refername = db_get(ServerProgsDB, strcat(GetMapname(), "/captimerecord/netname"));
// notify about shit
- if(ctf_oneflag) { Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_CTF_CAPTURE_NEUTRAL, player.netname); }
- else if(!ctf_captimerecord) { Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_ENT(flag, CHOICE_CTF_CAPTURE_TIME), player.netname, (cap_time * 100)); }
- else if(cap_time < cap_record) { Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_ENT(flag, CHOICE_CTF_CAPTURE_BROKEN), player.netname, refername, (cap_time * 100), (cap_record * 100)); }
- else { Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_ENT(flag, CHOICE_CTF_CAPTURE_UNBROKEN), player.netname, refername, (cap_time * 100), (cap_record * 100)); }
+ if(ctf_oneflag)
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_CTF_CAPTURE_NEUTRAL, player.netname);
+ else if(!ctf_captimerecord)
+ Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_CAPTURE_TIME), player.netname, (cap_time * 100));
+ else if(cap_time < cap_record)
+ Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_CAPTURE_BROKEN), player.netname, refername, (cap_time * 100), (cap_record * 100));
+ else
+ Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_CAPTURE_UNBROKEN), player.netname, refername, (cap_time * 100), (cap_record * 100));
// write that shit in the database
if(!ctf_oneflag) // but not in 1-flag mode
flag.ctf_status = FLAG_DROPPED;
// messages and sounds
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((flag.team) ? APP_TEAM_ENT(flag, INFO_CTF_LOST) : INFO_CTF_LOST_NEUTRAL), player.netname);
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_LOST), player.netname);
_sound(flag, CH_TRIGGER, flag.snd_flag_dropped, VOL_BASE, ATTEN_NONE);
ctf_EventLog("dropped", player.team, player);
FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), LAMBDA(
if(it == sender)
- Send_Notification(NOTIF_ONE, it, MSG_CENTER, ((flag.team) ? APP_TEAM_ENT(flag, CENTER_CTF_PASS_SENT) : CENTER_CTF_PASS_SENT_NEUTRAL), player.netname);
+ Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_NUM(flag.team, CENTER_CTF_PASS_SENT), player.netname);
else if(it == player)
- Send_Notification(NOTIF_ONE, it, MSG_CENTER, ((flag.team) ? APP_TEAM_ENT(flag, CENTER_CTF_PASS_RECEIVED) : CENTER_CTF_PASS_RECEIVED_NEUTRAL), sender.netname);
+ Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_NUM(flag.team, CENTER_CTF_PASS_RECEIVED), sender.netname);
else if(SAME_TEAM(it, sender))
- Send_Notification(NOTIF_ONE, it, MSG_CENTER, ((flag.team) ? APP_TEAM_ENT(flag, CENTER_CTF_PASS_OTHER) : CENTER_CTF_PASS_OTHER_NEUTRAL), sender.netname, player.netname);
+ Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_NUM(flag.team, CENTER_CTF_PASS_OTHER), sender.netname, player.netname);
));
// create new waypoint
player.throw_count = 0;
// messages and sounds
- Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((enemy_flag.team) ? APP_TEAM_ENT(enemy_flag, CENTER_CTF_CAPTURE) : CENTER_CTF_CAPTURE_NEUTRAL));
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_NUM(enemy_flag.team, CENTER_CTF_CAPTURE));
ctf_CaptureRecord(enemy_flag, player);
_sound(player, CH_TRIGGER, ((ctf_oneflag) ? player_team_flag.snd_flag_capture : ((DIFF_TEAM(player, flag)) ? enemy_flag.snd_flag_capture : flag.snd_flag_capture)), VOL_BASE, ATTEN_NONE);
// messages and sounds
if(IS_MONSTER(player))
{
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_ENT(flag, INFO_CTF_RETURN_MONSTER), player.monster_name);
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(flag.team, INFO_CTF_RETURN_MONSTER), player.monster_name);
}
else if(flag.team)
{
- Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_ENT(flag, CENTER_CTF_RETURN));
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_ENT(flag, INFO_CTF_RETURN), player.netname);
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_NUM(flag.team, CENTER_CTF_RETURN));
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(flag.team, INFO_CTF_RETURN), player.netname);
}
_sound(player, CH_TRIGGER, flag.snd_flag_returned, VOL_BASE, ATTEN_NONE);
ctf_EventLog("return", flag.team, player);
}
// messages and sounds
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((flag.team) ? APP_TEAM_ENT(flag, INFO_CTF_PICKUP) : INFO_CTF_PICKUP_NEUTRAL), player.netname);
- if(ctf_stalemate) { Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_STALEMATE_CARRIER); }
- if(!flag.team) { Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PICKUP_NEUTRAL); }
- else if(CTF_DIFFTEAM(player, flag)) { Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_ENT(flag, CENTER_CTF_PICKUP)); }
- else { Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((SAME_TEAM(player, flag)) ? CENTER_CTF_PICKUP_TEAM : CENTER_CTF_PICKUP_TEAM_ENEMY), Team_ColorCode(flag.team)); }
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_PICKUP), player.netname);
+ if(ctf_stalemate)
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_STALEMATE_CARRIER);
+ if(!flag.team)
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PICKUP_NEUTRAL);
+ else if(CTF_DIFFTEAM(player, flag))
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_NUM(flag.team, CENTER_CTF_PICKUP));
+ else
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((SAME_TEAM(player, flag)) ? CENTER_CTF_PICKUP_TEAM : CENTER_CTF_PICKUP_TEAM_ENEMY), Team_ColorCode(flag.team));
- Send_Notification(NOTIF_TEAM_EXCEPT, player, MSG_CHOICE, ((flag.team) ? APP_TEAM_ENT(flag, CHOICE_CTF_PICKUP_TEAM) : CHOICE_CTF_PICKUP_TEAM_NEUTRAL), Team_ColorCode(player.team), player.netname);
+ Send_Notification(NOTIF_TEAM_EXCEPT, player, MSG_CHOICE, APP_NUM(flag.team, CHOICE_CTF_PICKUP_TEAM), Team_ColorCode(player.team), player.netname);
if(!flag.team)
FOREACH_CLIENT(IS_PLAYER(it) && it != player && DIFF_TEAM(it, player), LAMBDA(Send_Notification(NOTIF_ONE, it, MSG_CHOICE, CHOICE_CTF_PICKUP_ENEMY_NEUTRAL, Team_ColorCode(player.team), player.netname)));
FOREACH_CLIENT(IS_PLAYER(it) && it != player, LAMBDA(
if(CTF_SAMETEAM(flag, it))
if(SAME_TEAM(player, it))
- Send_Notification(NOTIF_ONE, it, MSG_CHOICE, APP_TEAM_ENT(flag, CHOICE_CTF_PICKUP_TEAM), Team_ColorCode(player.team), player.netname);
+ Send_Notification(NOTIF_ONE, it, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_PICKUP_TEAM), Team_ColorCode(player.team), player.netname);
else
Send_Notification(NOTIF_ONE, it, MSG_CHOICE, ((SAME_TEAM(flag, player)) ? CHOICE_CTF_PICKUP_ENEMY_TEAM : CHOICE_CTF_PICKUP_ENEMY), Team_ColorCode(player.team), player.netname);
));
{
switch(returntype)
{
- case RETURN_DROPPED: Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((flag.team) ? APP_TEAM_ENT(flag, INFO_CTF_FLAGRETURN_DROPPED) : INFO_CTF_FLAGRETURN_DROPPED_NEUTRAL)); break;
- case RETURN_DAMAGE: Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((flag.team) ? APP_TEAM_ENT(flag, INFO_CTF_FLAGRETURN_DAMAGED) : INFO_CTF_FLAGRETURN_DAMAGED_NEUTRAL)); break;
- case RETURN_SPEEDRUN: Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((flag.team) ? APP_TEAM_ENT(flag, INFO_CTF_FLAGRETURN_SPEEDRUN) : INFO_CTF_FLAGRETURN_SPEEDRUN_NEUTRAL), ctf_captimerecord); break;
- case RETURN_NEEDKILL: Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((flag.team) ? APP_TEAM_ENT(flag, INFO_CTF_FLAGRETURN_NEEDKILL) : INFO_CTF_FLAGRETURN_NEEDKILL_NEUTRAL)); break;
-
+ case RETURN_DROPPED:
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_DROPPED)); break;
+ case RETURN_DAMAGE:
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_DAMAGED)); break;
+ case RETURN_SPEEDRUN:
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_SPEEDRUN), ctf_captimerecord); break;
+ case RETURN_NEEDKILL:
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_NEEDKILL)); break;
default:
case RETURN_TIMEOUT:
- { Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((flag.team) ? APP_TEAM_ENT(flag, INFO_CTF_FLAGRETURN_TIMEOUT) : INFO_CTF_FLAGRETURN_TIMEOUT_NEUTRAL)); break; }
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_TIMEOUT)); break;
}
_sound(flag, CH_TRIGGER, flag.snd_flag_respawn, VOL_BASE, ATTEN_NONE);
ctf_EventLog("returned", flag.team, NULL);
flag.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP;
flag.damagedbytriggers = autocvar_g_ctf_flag_return_when_unreachable;
flag.damagedbycontents = autocvar_g_ctf_flag_return_when_unreachable;
+ if(flag.damagedbycontents)
+ IL_PUSH(g_damagedbycontents, flag);
flag.velocity = '0 0 0';
flag.mangle = flag.angles;
flag.reset = ctf_Reset;
if(player.flagcarried)
{
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((player.flagcarried.team) ? APP_TEAM_ENT(player.flagcarried, INFO_CTF_FLAGRETURN_ABORTRUN) : INFO_CTF_FLAGRETURN_ABORTRUN_NEUTRAL));
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(player.flagcarried.team, INFO_CTF_FLAGRETURN_ABORTRUN));
ctf_RespawnFlag(player.flagcarried);
return true;
}
return true;
}
- MUTATOR_HOOKFUNCTION(ctf, GetTeamCount)
+ MUTATOR_HOOKFUNCTION(ctf, CheckAllowedTeams)
{
//M_ARGV(0, float) = ctf_teams;
M_ARGV(1, string) = "ctf_team";
clone.iscreature = this.iscreature;
clone.teleportable = this.teleportable;
clone.damagedbycontents = this.damagedbycontents;
+ if(clone.damagedbycontents)
+ IL_PUSH(g_damagedbycontents, clone);
clone.angles = this.angles;
clone.v_angle = this.v_angle;
clone.avelocity = this.avelocity;
this.alpha = -1;
this.solid = SOLID_NOT; // restore later
this.takedamage = DAMAGE_NO; // restore later
+ if(this.damagedbycontents)
+ IL_REMOVE(g_damagedbycontents, this);
this.damagedbycontents = false;
}
}
// increment frag counter for used weapon type
Weapon w = DEATH_WEAPONOF(deathtype);
- if(w != WEP_Null)
- if(accuracy_isgooddamage(attacker, this))
- attacker.accuracy.(accuracy_frags[w.m_id-1]) += 1;
+ if(w != WEP_Null && accuracy_isgooddamage(attacker, this))
+ attacker.accuracy.(accuracy_frags[w.m_id-1]) += 1;
MUTATOR_CALLHOOK(PlayerDies, inflictor, attacker, this, deathtype, damage);
excess = M_ARGV(4, float);
*/
int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodcontrol)
{
- if (!teamsay && !privatesay) if (substring(msgin, 0, 1) == " ")
+ if (!teamsay && !privatesay && substring(msgin, 0, 1) == " ")
msgin = substring(msgin, 1, -1); // work around DP say bug (say_team does not have this!)
msgin = formatmessage(source, msgin);