.int lodmodelindex0;
.int lodmodelindex1;
.int lodmodelindex2;
-void CSQCPlayer_LOD_Apply(entity this)
+void CSQCPlayer_LOD_Apply(entity this, bool isplayer)
{
+ int detailreduction = ((isplayer) ? autocvar_cl_playerdetailreduction : autocvar_cl_modeldetailreduction);
+
// LOD model loading
if(this.lodmodelindex0 != this.modelindex)
{
}
// apply LOD
- if(autocvar_cl_playerdetailreduction <= 0)
+ if(detailreduction <= 0)
{
- if(autocvar_cl_playerdetailreduction <= -2)
+ if(detailreduction <= -2)
this.modelindex = this.lodmodelindex2;
- else if(autocvar_cl_playerdetailreduction <= -1)
+ else if(detailreduction <= -1)
this.modelindex = this.lodmodelindex1;
else
this.modelindex = this.lodmodelindex0;
}
else
{
- float distance = vlen(this.origin - view_origin);
- float f = (distance * current_viewzoom + 100.0) * autocvar_cl_playerdetailreduction;
+ float distance = vlen(((isplayer) ? this.origin : NearestPointOnBox(this, view_origin)) - view_origin); // TODO: perhaps it should just use NearestPointOnBox all the time, player hitbox can potentially be huge
+ float f = (distance * current_viewzoom + 100.0) * detailreduction;
f *= 1.0 / bound(0.01, view_quality, 1);
if(f > autocvar_cl_loddistance2)
this.modelindex = this.lodmodelindex2;
tref = EFFECT_TR_BLOOD.m_id;
if(this.csqcmodel_modelflags & MF_ROTATE)
{
+ // This will be hard to replace with MAKE_VECTORS because it's called as part of the predraw function
+ // as documented in csprogs.h in the engine. The globals can then be read in many places in the engine.
+ // However MF_ROTATE is currently only used in one place - might be possible to get rid of it entirely.
this.renderflags |= RF_USEAXIS;
- MAKEVECTORS(makevectors, this.angles + '0 100 0' * fmod(time, 3.6), v_forward, v_right, v_up);
+ makevectors(this.angles + '0 100 0' * fmod(time, 3.6));
}
if(this.csqcmodel_modelflags & MF_TRACER)
tref = EFFECT_TR_WIZSPIKE.m_id;
if((this.isplayermodel & ISPLAYER_MODEL) && this.drawmask) // this checks if it's a player MODEL!
{
CSQCPlayer_ModelAppearance_Apply(this, (this.isplayermodel & ISPLAYER_LOCAL));
- CSQCPlayer_LOD_Apply(this);
+ CSQCPlayer_LOD_Apply(this, true);
if(!isplayer)
{
}
}
}
+ else
+ CSQCPlayer_LOD_Apply(this, false);
CSQCModel_AutoTagIndex_Apply(this);
CLASS(LastManStanding, Gametype)
INIT(LastManStanding)
{
- this.gametype_init(this, _("Last Man Standing"),"lms","g_lms",false,true,"","timelimit=20 lives=9 leadlimit=0",_("Survive and kill until the enemies have no lives left"));
+ this.gametype_init(this, _("Last Man Standing"),"lms","g_lms",false,true,"","timelimit=20 lives=5 leadlimit=0",_("Survive and kill until the enemies have no lives left"));
}
METHOD(LastManStanding, m_isAlwaysSupported, bool(Gametype this, int spawnpoints, float diameter))
{
CLASS(ClanArena, Gametype)
INIT(ClanArena)
{
- this.gametype_init(this, _("Clan Arena"),"ca","g_ca",true,true,"","timelimit=20 pointlimit=10 teams=2 leadlimit=0",_("Kill all enemy teammates to win the round"));
+ this.gametype_init(this, _("Clan Arena"),"ca","g_ca",true,true,"","timelimit=20 pointlimit=10 teams=2 leadlimit=6",_("Kill all enemy teammates to win the round"));
}
METHOD(ClanArena, m_parse_mapinfo, bool(string k, string v))
{
CLASS(FreezeTag, Gametype)
INIT(FreezeTag)
{
- this.gametype_init(this, _("Freeze Tag"),"ft","g_freezetag",true,true,"","timelimit=20 pointlimit=10 teams=2 leadlimit=0",_("Kill enemies to freeze them, stand next to frozen teammates to revive them; freeze all enemies to win"));
+ this.gametype_init(this, _("Freeze Tag"),"ft","g_freezetag",true,true,"","timelimit=20 pointlimit=10 teams=2 leadlimit=6",_("Kill enemies to freeze them, stand next to frozen teammates to revive them; freeze all enemies to win"));
}
METHOD(FreezeTag, m_parse_mapinfo, bool(string k, string v))
{
CLASS(Invasion, Gametype)
INIT(Invasion)
{
- this.gametype_init(this, _("Invasion"),"inv","g_invasion",false,true,"","pointlimit=50 teams=0 type=0",_("Survive against waves of monsters"));
+ this.gametype_init(this, _("Invasion"),"inv","g_invasion",false,true,"","pointlimit=50 type=0",_("Survive against waves of monsters"));
}
METHOD(Invasion, m_parse_mapinfo, bool(string k, string v))
{
switch (k) {
- case "teams":
- cvar_set("g_invasion_teams", v);
- return true;
case "type":
cvar_set("g_invasion_type", v);
return true;
void MapInfo_Cache_Create(); // enable caching
void MapInfo_Cache_Invalidate(); // delete cache if any, but keep enabled
+ void _MapInfo_Parse_Settemp(string pFilename, string acl, float type, string s, float recurse);
+
void MapInfo_ClearTemps(); // call this when done with mapinfo for this frame
void MapInfo_Shutdown(); // call this in the shutdown handler
if (!IS_PLAYER(actor) || weapon_prepareattack(thiswep, actor, weaponentity, false, 0.2)) {
if (!actor.target_range) actor.target_range = autocvar_g_monsters_target_range;
actor.enemy = Monster_FindTarget(actor);
+ monster_makevectors(actor, actor.enemy);
W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_MageSpike_FIRE, CH_WEAPON_B, 0, DEATH_MONSTER_MAGE.m_id);
if (!IS_PLAYER(actor)) w_shotdir = normalize((actor.enemy.origin + '0 0 10') - actor.origin);
M_Mage_Attack_Spike(actor, w_shotdir);
float autocvar_g_monster_mage_attack_spike_delay;
float autocvar_g_monster_mage_attack_spike_accel;
float autocvar_g_monster_mage_attack_spike_decel;
+float autocvar_g_monster_mage_attack_spike_chance = 0.45;
float autocvar_g_monster_mage_attack_spike_turnrate;
float autocvar_g_monster_mage_attack_spike_speed_max;
float autocvar_g_monster_mage_attack_spike_smart;
float autocvar_g_monster_mage_attack_spike_smart_trace_min;
float autocvar_g_monster_mage_attack_spike_smart_trace_max;
float autocvar_g_monster_mage_attack_spike_smart_mindist;
+float autocvar_g_monster_mage_attack_push_chance = 0.7;
float autocvar_g_monster_mage_attack_push_damage;
float autocvar_g_monster_mage_attack_push_radius;
float autocvar_g_monster_mage_attack_push_delay;
float autocvar_g_monster_mage_attack_push_force;
+float autocvar_g_monster_mage_attack_teleport_chance = 0.2;
+float autocvar_g_monster_mage_attack_teleport_delay = 2;
+float autocvar_g_monster_mage_attack_teleport_random = 0.4;
+float autocvar_g_monster_mage_attack_teleport_random_range = 1200;
float autocvar_g_monster_mage_heal_self;
float autocvar_g_monster_mage_heal_allies;
float autocvar_g_monster_mage_heal_minhealth;
void M_Mage_Defend_Heal(entity this)
{
- float washealed = false;
+ bool washealed = false;
FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_monster_mage_heal_range, M_Mage_Defend_Heal_Check(this, it),
{
}
case 1:
{
- if(GetResource(this, RES_CELLS)) GiveResourceWithLimit(it, RES_CELLS, 1, g_pickup_cells_max);
- if(GetResource(this, RES_PLASMA)) GiveResourceWithLimit(it, RES_PLASMA, 1, g_pickup_plasma_max);
- if(GetResource(this, RES_ROCKETS)) GiveResourceWithLimit(it, RES_ROCKETS, 1, g_pickup_rockets_max);
- if(GetResource(this, RES_SHELLS)) GiveResourceWithLimit(it, RES_SHELLS, 2, g_pickup_shells_max);
- if(GetResource(this, RES_BULLETS)) GiveResourceWithLimit(it, RES_BULLETS, 5, g_pickup_nails_max);
+ if(GetResource(it, RES_CELLS)) GiveResourceWithLimit(it, RES_CELLS, 1, g_pickup_cells_max);
+ if(GetResource(it, RES_PLASMA)) GiveResourceWithLimit(it, RES_PLASMA, 1, g_pickup_plasma_max);
+ if(GetResource(it, RES_ROCKETS)) GiveResourceWithLimit(it, RES_ROCKETS, 1, g_pickup_rockets_max);
+ if(GetResource(it, RES_SHELLS)) GiveResourceWithLimit(it, RES_SHELLS, 2, g_pickup_shells_max);
+ if(GetResource(it, RES_BULLETS)) GiveResourceWithLimit(it, RES_BULLETS, 5, g_pickup_nails_max);
// TODO: fuel?
fx = EFFECT_AMMO_REGEN;
break;
if(washealed)
{
- setanim(this, this.anim_shoot, true, true, true);
+ setanim(this, this.anim_melee, true, true, true);
this.attack_finished_single[0] = time + (autocvar_g_monster_mage_heal_delay);
+ this.state = MONSTER_ATTACK_MELEE;
this.anim_finished = time + 1.5;
}
}
NULL, NULL, (autocvar_g_monster_mage_attack_push_force), DEATH_MONSTER_MAGE.m_id, DMG_NOWEP, this.enemy);
Send_Effect(EFFECT_TE_EXPLOSION, this.origin, '0 0 0', 1);
- setanim(this, this.anim_shoot, true, true, true);
+ setanim(this, this.anim_duckjump, true, true, true);
this.attack_finished_single[0] = time + (autocvar_g_monster_mage_attack_push_delay);
+ this.anim_finished = time + 1;
+ this.state = MONSTER_ATTACK_MELEE; // prevent moving while firing spike
}
void M_Mage_Attack_Teleport(entity this, entity targ)
if(!targ) return;
if(vdist(targ.origin - this.origin, >, 1500)) return;
+ if(autocvar_g_monster_mage_attack_teleport_random && random() <= autocvar_g_monster_mage_attack_teleport_random)
+ {
+ vector oldpos = this.origin;
+ vector extrasize = '1 1 1' * autocvar_g_monster_mage_attack_teleport_random_range;
+ if(MoveToRandomLocationWithinBounds(this, this.absmin - extrasize, this.absmax + extrasize,
+ DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER,
+ Q3SURFACEFLAG_SKY, 10, 64, 256, true))
+ {
+ vector a = vectoangles(targ.origin - this.origin);
+ this.angles = '0 1 0' * a.y;
+ this.fixangle = true;
+ Send_Effect(EFFECT_SPAWN_NEUTRAL, oldpos, '0 0 0', 1);
+ Send_Effect(EFFECT_SPAWN_NEUTRAL, this.origin, '0 0 0', 1);
+ this.attack_finished_single[0] = time + autocvar_g_monster_mage_attack_teleport_delay;
+ return;
+ }
+ }
+
+ if(!IS_ONGROUND(targ)) return;
+
makevectors(targ.angles);
- tracebox(targ.origin + ((v_forward * -1) * 200), this.mins, this.maxs, this.origin, MOVE_NOMONSTERS, this);
+ tracebox(CENTER_OR_VIEWOFS(targ), this.mins, this.maxs, CENTER_OR_VIEWOFS(targ) + ((v_forward * -1) * 200), MOVE_NOMONSTERS, this);
if(trace_fraction < 1)
return;
- vector newpos = targ.origin + ((v_forward * -1) * 200);
+ vector newpos = trace_endpos;
Send_Effect(EFFECT_SPAWN_NEUTRAL, this.origin, '0 0 0', 1);
Send_Effect(EFFECT_SPAWN_NEUTRAL, newpos, '0 0 0', 1);
this.fixangle = true;
this.velocity *= 0.5;
- this.attack_finished_single[0] = time + 0.2;
+ this.attack_finished_single[0] = time + autocvar_g_monster_mage_attack_teleport_delay;
}
void M_Mage_Defend_Shield_Remove(entity this)
SetResourceExplicit(this, RES_ARMOR, autocvar_g_monster_mage_shield_blockpercent);
this.mage_shield_time = time + (autocvar_g_monster_mage_shield_time);
setanim(this, this.anim_shoot, true, true, true);
- this.attack_finished_single[0] = time + 1;
+ this.attack_finished_single[0] = time + 1; // give just a short cooldown on attacking
this.anim_finished = time + 1;
}
{
case MONSTER_ATTACK_MELEE:
{
- if(random() <= 0.7)
+ if(random() <= autocvar_g_monster_mage_attack_push_chance)
{
Weapon wep = WEP_MAGE_SPIKE;
}
case MONSTER_ATTACK_RANGED:
{
- if(!actor.mage_spike)
+ if(random() <= autocvar_g_monster_mage_attack_teleport_chance)
{
- if(random() <= 0.4)
- {
- OffhandWeapon off = OFFHAND_MAGE_TELEPORT;
- off.offhand_think(off, actor, true);
- return true;
- }
- else
- {
- setanim(actor, actor.anim_shoot, true, true, true);
- actor.attack_finished_single[0] = time + (autocvar_g_monster_mage_attack_spike_delay);
- actor.anim_finished = time + 1;
- Weapon wep = WEP_MAGE_SPIKE;
- wep.wr_think(wep, actor, weaponentity, 1);
- return true;
- }
+ OffhandWeapon off = OFFHAND_MAGE_TELEPORT;
+ actor.OffhandMageTeleport_key_pressed = 0;
+ off.offhand_think(off, actor, 1);
+ return true;
}
-
- if(actor.mage_spike)
+ else if(!actor.mage_spike && random() <= autocvar_g_monster_mage_attack_spike_chance)
+ {
+ setanim(actor, actor.anim_shoot, true, true, true);
+ actor.attack_finished_single[0] = time + (autocvar_g_monster_mage_attack_spike_delay);
+ actor.anim_finished = time + 1;
+ actor.state = MONSTER_ATTACK_MELEE; // prevent moving while firing spike
+ Weapon wep = WEP_MAGE_SPIKE;
+ wep.wr_think(wep, actor, weaponentity, 1);
return true;
- else
- return false;
+ }
+
+ return false;
}
}
METHOD(Mage, mr_death, bool(Mage this, entity actor))
{
TC(Mage, this);
- setanim(actor, actor.anim_die1, false, true, true);
+ setanim(actor, ((random() > 0.5) ? actor.anim_die2 : actor.anim_die1), false, true, true);
return true;
}
{
TC(Mage, this);
vector none = '0 0 0';
- actor.anim_die1 = animfixfps(actor, '4 1 0.5', none); // 2 seconds
- actor.anim_walk = animfixfps(actor, '1 1 1', none);
actor.anim_idle = animfixfps(actor, '0 1 1', none);
- actor.anim_pain1 = animfixfps(actor, '3 1 2', none); // 0.5 seconds
+ actor.anim_walk = animfixfps(actor, '1 1 1', none);
+ actor.anim_run = animfixfps(actor, '1 1 1', none);
actor.anim_shoot = animfixfps(actor, '2 1 5', none); // analyze models and set framerate
- actor.anim_run = animfixfps(actor, '5 1 1', none);
+ actor.anim_duckjump = animfixfps(actor, '4 1 5', none); // analyze models and set framerate
+ actor.anim_melee = animfixfps(actor, '5 1 5', none); // analyze models and set framerate
+ //actor.anim_fire1 = animfixfps(actor, '3 1 5', none); // analyze models and set framerate
+ //actor.anim_fire2 = animfixfps(actor, '4 1 5', none); // analyze models and set framerate
+ //actor.anim_fire3 = animfixfps(actor, '5 1 5', none); // analyze models and set framerate
+ actor.anim_pain1 = animfixfps(actor, '6 1 2', none); // 0.5 seconds
+ actor.anim_pain2 = animfixfps(actor, '7 1 2', none); // 0.5 seconds
+ //actor.anim_pain3 = animfixfps(actor, '8 1 2', none); // 0.5 seconds
+ actor.anim_die1 = animfixfps(actor, '9 1 0.5', none); // 2 seconds
+ actor.anim_die2 = animfixfps(actor, '10 1 0.5', none); // 2 seconds
+ //actor.anim_dead1 = animfixfps(actor, '11 1 0.5', none); // 2 seconds
+ //actor.anim_dead2 = animfixfps(actor, '12 1 0.5', none); // 2 seconds
return true;
}
#endif
float autocvar_g_monster_spider_attack_web_speed;
float autocvar_g_monster_spider_attack_web_speed_up;
float autocvar_g_monster_spider_attack_web_delay;
+float autocvar_g_monster_spider_attack_web_range = 800;
float autocvar_g_monster_spider_attack_bite_damage;
float autocvar_g_monster_spider_attack_bite_delay;
TC(SpiderAttack, thiswep);
bool isPlayer = IS_PLAYER(actor);
if (fire & 1)
- if ((!isPlayer && time >= actor.spider_web_delay) || weapon_prepareattack(thiswep, actor, weaponentity, false, autocvar_g_monster_spider_attack_web_delay)) {
+ if ((!isPlayer && time >= actor.spider_web_delay) || (isPlayer && weapon_prepareattack(thiswep, actor, weaponentity, false, autocvar_g_monster_spider_attack_web_delay))) {
if (!isPlayer) {
- actor.spider_web_delay = time + 3;
+ actor.spider_web_delay = time + autocvar_g_monster_spider_attack_web_delay;
setanim(actor, actor.anim_shoot, true, true, true);
- actor.attack_finished_single[0] = time + (autocvar_g_monster_spider_attack_web_delay);
- actor.anim_finished = time + 1;
+ if(actor.animstate_endtime > time)
+ actor.anim_finished = actor.animstate_endtime;
+ else
+ actor.anim_finished = time + 1;
+ actor.attack_finished_single[0] = actor.anim_finished + 0.2;
}
if (isPlayer) actor.enemy = Monster_FindTarget(actor);
W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_SpiderAttack_FIRE, CH_WEAPON_B, 0, DEATH_MONSTER_SPIDER.m_id);
void M_Spider_Attack_Web(entity this)
{
- monster_makevectors(this, this.enemy);
-
sound(this, CH_SHOTS, SND_ELECTRO_FIRE2, VOL_BASE, ATTEN_NORM);
entity proj = new(plasma);
}
case MONSTER_ATTACK_RANGED:
{
- wep.wr_think(wep, actor, weaponentity, 1);
- return true;
+ if(vdist(actor.enemy.origin - actor.origin, <=, autocvar_g_monster_spider_attack_web_range))
+ {
+ wep.wr_think(wep, actor, weaponentity, 1);
+ return true;
+ }
}
}
METHOD(Spider, mr_pain, float(Spider this, entity actor, float damage_take, entity attacker, float deathtype))
{
TC(Spider, this);
+ setanim(actor, ((random() > 0.5) ? actor.anim_pain2 : actor.anim_pain1), true, true, false);
+ actor.pain_finished = actor.animstate_endtime;
return damage_take;
}
METHOD(Spider, mr_death, bool(Spider this, entity actor))
{
TC(Spider, this);
- setanim(actor, actor.anim_melee, false, true, true);
- actor.angles_x = 180;
+ setanim(actor, ((random() > 0.5) ? actor.anim_die2 : actor.anim_die1), false, true, true);
return true;
}
#endif
{
TC(Spider, this);
vector none = '0 0 0';
- actor.anim_walk = animfixfps(actor, '1 1 1', none);
- actor.anim_idle = animfixfps(actor, '0 1 1', none);
- actor.anim_melee = animfixfps(actor, '2 1 5', none); // analyze models and set framerate
- actor.anim_shoot = animfixfps(actor, '3 1 5', none); // analyze models and set framerate
- actor.anim_run = animfixfps(actor, '1 1 1', none);
+ actor.anim_melee = animfixfps(actor, '0 1 5', none); // analyze models and set framerate
+ actor.anim_die1 = animfixfps(actor, '1 1 1', none);
+ actor.anim_die2 = animfixfps(actor, '2 1 1', none);
+ actor.anim_shoot = animfixfps(actor, '3 1 1', none);
+ //actor.anim_fire2 = animfixfps(actor, '4 1 1', none);
+ actor.anim_idle = animfixfps(actor, '5 1 1', none);
+ //actor.anim_sight = animfixfps(actor, '6 1 1', none);
+ actor.anim_pain1 = animfixfps(actor, '7 1 1', none);
+ actor.anim_pain2 = animfixfps(actor, '8 1 1', none);
+ //actor.anim_pain3 = animfixfps(actor, '9 1 1', none);
+ actor.anim_walk = animfixfps(actor, '10 1 1', none);
+ actor.anim_run = animfixfps(actor, '10 1 1', none); // temp?
+ //actor.anim_forwardright = animfixfps(actor, '11 1 1', none);
+ //actor.anim_walkright = animfixfps(actor, '12 1 1', none);
+ //actor.anim_walkbackright = animfixfps(actor, '13 1 1', none);
+ //actor.anim_walkback = animfixfps(actor, '14 1 1', none);
+ //actor.anim_walkbackleft = animfixfps(actor, '15 1 1', none);
+ //actor.anim_walkleft = animfixfps(actor, '16 1 1', none);
+ //actor.anim_forwardleft = animfixfps(actor, '17 1 1', none);
return true;
}
#endif
if (fire & 1)
if (time > actor.attack_finished_single[0] || weapon_prepareattack(thiswep, actor, weaponentity, false, 1.2)) {
if (IS_PLAYER(actor)) W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_WyvernAttack_FIRE, CH_WEAPON_B, 0, DEATH_MONSTER_WYVERN.m_id);
- if (IS_MONSTER(actor)) monster_makevectors(actor, actor.enemy);
+ if (IS_MONSTER(actor)) {
+ actor.attack_finished_single[0] = time + 1.2;
+ actor.anim_finished = time + 1.2;
+ }
entity missile = spawn();
missile.owner = missile.realowner = actor;
entity own = this.realowner;
RadiusDamage(this, own, autocvar_g_monster_wyvern_attack_fireball_damage, autocvar_g_monster_wyvern_attack_fireball_edgedamage, autocvar_g_monster_wyvern_attack_fireball_force,
- NULL, NULL, autocvar_g_monster_wyvern_attack_fireball_radius, this.projectiledeathtype, DMG_NOWEP, NULL);
+ own, NULL, autocvar_g_monster_wyvern_attack_fireball_radius, this.projectiledeathtype, DMG_NOWEP, NULL);
- FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_monster_wyvern_attack_fireball_radius, it.takedamage == DAMAGE_AIM,
+ FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_monster_wyvern_attack_fireball_radius, it.takedamage == DAMAGE_AIM && it != own,
{
Fire_AddDamage(it, own, 5 * MONSTER_SKILLMOD(own), autocvar_g_monster_wyvern_attack_fireball_damagetime, this.projectiledeathtype);
});
M_Wyvern_Attack_Fireball_Explode(this);
}
+void M_Wyvern_Attack_Fireball(entity this)
+{
+ w_shotdir = normalize((this.enemy.origin + '0 0 10') - this.origin);
+ Weapon wep = WEP_WYVERN_ATTACK;
+ // TODO
+ .entity weaponentity = weaponentities[0];
+ wep.wr_think(wep, this, weaponentity, 1);
+}
+
bool M_Wyvern_Attack(int attack_type, entity actor, entity targ, .entity weaponentity)
{
switch(attack_type)
case MONSTER_ATTACK_MELEE:
case MONSTER_ATTACK_RANGED:
{
- w_shotdir = normalize((actor.enemy.origin + '0 0 10') - actor.origin);
- Weapon wep = WEP_WYVERN_ATTACK;
- wep.wr_think(wep, actor, weaponentity, 1);
+ Monster_Delay(actor, 0, 1, M_Wyvern_Attack_Fireball);
+ //actor.anim_finished = time + 1.2;
+ setanim(actor, actor.anim_shoot, false, true, true);
+ if(actor.animstate_endtime > time)
+ actor.anim_finished = actor.animstate_endtime;
+ else
+ actor.anim_finished = time + 1.2;
+ actor.attack_finished_single[0] = actor.anim_finished + 0.2;
return true;
}
}
return true;
}
+METHOD(Wyvern, mr_deadthink, bool(Wyvern this, entity actor))
+{
+ TC(Wyvern, this);
+ if(IS_ONGROUND(actor))
+ setanim(actor, actor.anim_die2, true, false, false);
+ return true;
+}
+
METHOD(Wyvern, mr_pain, float(Wyvern this, entity actor, float damage_take, entity attacker, float deathtype))
{
TC(Wyvern, this);
{
TC(Wyvern, this);
vector none = '0 0 0';
- actor.anim_die1 = animfixfps(actor, '4 1 0.5', none); // 2 seconds
- actor.anim_walk = animfixfps(actor, '1 1 1', none);
actor.anim_idle = animfixfps(actor, '0 1 1', none);
+ actor.anim_walk = animfixfps(actor, '1 1 1', none);
+ actor.anim_run = animfixfps(actor, '2 1 1', none);
actor.anim_pain1 = animfixfps(actor, '3 1 2', none); // 0.5 seconds
- actor.anim_shoot = animfixfps(actor, '2 1 5', none); // analyze models and set framerate
- actor.anim_run = animfixfps(actor, '1 1 1', none);
+ actor.anim_pain2 = animfixfps(actor, '4 1 2', none); // 0.5 seconds
+ actor.anim_melee = animfixfps(actor, '5 1 5', none); // analyze models and set framerate
+ actor.anim_shoot = animfixfps(actor, '6 1 5', none); // analyze models and set framerate
+ actor.anim_die1 = animfixfps(actor, '7 1 0.5', none); // 2 seconds
+ actor.anim_die2 = animfixfps(actor, '8 1 0.5', none); // 2 seconds
return true;
}
#endif
}
}
+bool monster_facing(entity this, entity targ)
+{
+ // relies on target having an origin
+ makevectors(this.angles);
+ vector targ_org = targ.origin, my_org = this.origin;
+ if(autocvar_g_monsters_target_infront_2d)
+ {
+ targ_org = vec2(targ_org);
+ my_org = vec2(my_org);
+ }
+ float dot = normalize(targ_org - my_org) * v_forward;
+
+ return !(dot <= autocvar_g_monsters_target_infront_range);
+}
+
void monster_makevectors(entity this, entity targ)
{
if(IS_MONSTER(this))
// Target handling
// ===============
-bool Monster_ValidTarget(entity this, entity targ)
+bool Monster_ValidTarget(entity this, entity targ, bool skipfacing)
{
// ensure we're not checking nonexistent monster/target
if(!this || !targ) { return false; }
if((targ == this)
- || (autocvar_g_monsters_lineofsight && !checkpvs(this.origin + this.view_ofs, targ)) // enemy cannot be seen
- || (IS_VEHICLE(targ) && !((Monsters_from(this.monsterid)).spawnflags & MON_FLAG_RANGED)) // melee vs vehicle is useless
|| (time < game_starttime) // monsters do nothing before match has started
|| (targ.takedamage == DAMAGE_NO)
|| (game_stopped)
|| (this.monster_follow == targ || targ.monster_follow == this)
|| (!IS_VEHICLE(targ) && (targ.flags & FL_NOTARGET))
|| (!autocvar_g_monsters_typefrag && PHYS_INPUT_BUTTON_CHAT(targ))
+ || (IS_VEHICLE(targ) && !((Monsters_from(this.monsterid)).spawnflags & MON_FLAG_RANGED)) // melee vs vehicle is useless
|| (SAME_TEAM(targ, this))
|| (STAT(FROZEN, targ))
|| (targ.alpha != 0 && targ.alpha < 0.5)
+ || (autocvar_g_monsters_lineofsight && !checkpvs(this.origin + this.view_ofs, targ)) // enemy cannot be seen
|| (MUTATOR_CALLHOOK(MonsterValidTarget, this, targ))
)
{
}
vector targ_origin = ((targ.absmin + targ.absmax) * 0.5);
- traceline(this.origin + this.view_ofs, targ_origin, MOVE_NOMONSTERS, this);
+ traceline(this.origin + this.view_ofs, targ_origin, MOVE_NOMONSTERS, this); // TODO: maybe we can rely a bit on PVS data instead?
if(trace_fraction < 1 && trace_ent != targ)
return false; // solid
- if(autocvar_g_monsters_target_infront || (this.spawnflags & MONSTERFLAG_INFRONT))
+ if(!skipfacing && (autocvar_g_monsters_target_infront || (this.spawnflags & MONSTERFLAG_INFRONT)))
if(this.enemy != targ)
{
- makevectors (this.angles);
- float dot = normalize (targ.origin - this.origin) * v_forward;
-
- if(dot <= autocvar_g_monsters_target_infront_range) { return false; }
+ if(!monster_facing(this, targ))
+ return false;
}
return true; // this target is valid!
vector my_center = CENTER_OR_VIEWOFS(this);
// find the closest acceptable target to pass to
- IL_EACH(g_monster_targets, it.monster_attack && vdist(it.origin - this.origin, <, this.target_range),
+ IL_EACH(g_monster_targets, it.monster_attack,
{
- if(Monster_ValidTarget(this, it))
- {
- // if it's a player, use the view origin as reference (stolen from RadiusDamage functions in g_damage.qc)
- vector targ_center = CENTER_OR_VIEWOFS(it);
+ float trange = this.target_range;
+ if(PHYS_INPUT_BUTTON_CROUCH(it))
+ trange *= 0.75; // TODO cvar this
+ vector theirmid = (it.absmin + it.absmax) * 0.5;
+ if(vdist(theirmid - this.origin, >, trange))
+ continue;
+ if(!Monster_ValidTarget(this, it, false))
+ continue;
- if(closest_target)
- {
- vector closest_target_center = CENTER_OR_VIEWOFS(closest_target);
- if(vlen2(my_center - targ_center) < vlen2(my_center - closest_target_center))
- { closest_target = it; }
- }
- else { closest_target = it; }
+ // if it's a player, use the view origin as reference (stolen from RadiusDamage functions in g_damage.qc)
+ vector targ_center = CENTER_OR_VIEWOFS(it);
+
+ if(closest_target)
+ {
+ vector closest_target_center = CENTER_OR_VIEWOFS(closest_target);
+ if(vlen2(my_center - targ_center) < vlen2(my_center - closest_target_center))
+ { closest_target = it; }
}
+ else { closest_target = it; }
});
return closest_target;
else
{
if(this.monster_skill <= MONSTER_SKILL_EASY)
- this.colormap = 1029;
+ this.colormap = 1126;
else if(this.monster_skill <= MONSTER_SKILL_MEDIUM)
- this.colormap = 1027;
+ this.colormap = 1075;
else if(this.monster_skill <= MONSTER_SKILL_HARD)
- this.colormap = 1038;
+ this.colormap = 1228;
else if(this.monster_skill <= MONSTER_SKILL_INSANE)
- this.colormap = 1028;
+ this.colormap = 1092;
else if(this.monster_skill <= MONSTER_SKILL_NIGHTMARE)
- this.colormap = 1032;
+ this.colormap = 1160;
else
this.colormap = 1024;
}
+
+ if(this.colormap > 0)
+ this.glowmod = colormapPaletteColor(this.colormap & 0x0F, false);
+ else
+ this.glowmod = '1 1 1';
}
void monster_changeteam(entity this, int newteam)
.void(entity) monster_delayedfunc;
void Monster_Delay_Action(entity this)
{
- if(Monster_ValidTarget(this.owner, this.owner.enemy))
+ // TODO: maybe do check for facing here
- if(Monster_ValidTarget(this.owner, this.owner.enemy, false)) { this.monster_delayedfunc(this.owner); }
++ if(Monster_ValidTarget(this.owner, this.owner.enemy, false))
+ {
+ monster_makevectors(this.owner, this.owner.enemy);
+ this.monster_delayedfunc(this.owner);
+ }
if(this.cnt > 1)
{
string sample = this.(samplefield);
if (sample != "") sample = GlobalSound_sample(sample, random());
float myscale = ((this.scale) ? this.scale : 1); // safety net
- // TODO: change volume depending on size too?
sound7(this, chan, sample, VOL_BASE, ATTEN_NORM, 100 / myscale, 0);
this.msound_delay = time + sound_delay;
else
this.attack_finished_single[0] = this.anim_finished = time + animtime;
- monster_makevectors(this, targ);
-
traceline(this.origin + this.view_ofs, this.origin + v_forward * er, 0, this);
if(trace_ent.takedamage)
if((!this || !targ)
|| (!this.monster_attackfunc)
|| (time < this.attack_finished_single[slot])
+ || ((autocvar_g_monsters_target_infront || (this.spawnflags & MONSTERFLAG_INFRONT)) && !monster_facing(this, targ))
) { return; }
if(vdist(targ.origin - this.origin, <=, this.attack_range))
{
+ monster_makevectors(this, targ);
int attack_success = this.monster_attackfunc(MONSTER_ATTACK_MELEE, this, targ, weaponentity);
if(attack_success == 1)
Monster_Sound(this, monstersound_melee, 0, false, CH_VOICE);
if(vdist(targ.origin - this.origin, >, this.attack_range))
{
+ monster_makevectors(this, targ);
int attack_success = this.monster_attackfunc(MONSTER_ATTACK_RANGED, this, targ, weaponentity);
if(attack_success == 1)
Monster_Sound(this, monstersound_melee, 0, false, CH_VOICE);
void Monster_Touch(entity this, entity toucher)
{
- if(toucher == NULL) { return; }
+ if(!toucher) { return; }
- if(toucher.monster_attack)
- if(this.enemy != toucher)
- if(!IS_MONSTER(toucher))
- if(Monster_ValidTarget(this, toucher))
+ if(toucher.monster_attack && this.enemy != toucher && !IS_MONSTER(toucher) && time >= this.spawn_time)
+ if(Monster_ValidTarget(this, toucher, true))
this.enemy = toucher;
}
void Monster_Use(entity this, entity actor, entity trigger)
{
- if(Monster_ValidTarget(this, actor)) { this.enemy = actor; }
+ if(Monster_ValidTarget(this, actor, true)) { this.enemy = actor; }
}
-.float pass_distance;
vector Monster_Move_Target(entity this, entity targ)
{
// enemy is always preferred target
WarpZone_TraceLine(this.origin, targ_origin, MOVE_NOMONSTERS, this);
// cases where the enemy may have changed their state (don't need to check everything here)
- if((!this.enemy)
- || (IS_DEAD(this.enemy) || GetResource(this.enemy, RES_HEALTH) < 1)
+ if( (IS_DEAD(this.enemy) || GetResource(this.enemy, RES_HEALTH) < 1)
|| (STAT(FROZEN, this.enemy))
|| (this.enemy.flags & FL_NOTARGET)
|| (this.enemy.alpha < 0.5 && this.enemy.alpha != 0)
|| (this.enemy.takedamage == DAMAGE_NO)
|| (vdist(this.origin - targ_origin, >, this.target_range))
- || ((trace_fraction < 1) && (trace_ent != this.enemy)))
+ || ((trace_fraction < 1) && (trace_ent != this.enemy))
+ )
{
this.enemy = NULL;
- //this.pass_distance = 0;
}
if(this.enemy)
}
}
-void Monster_CalculateVelocity(entity this, vector to, vector from, float turnrate, float movespeed)
-{
- //float current_distance = vlen((('1 0 0' * to.x) + ('0 1 0' * to.y)) - (('1 0 0' * from.x) + ('0 1 0' * from.y))); // for the sake of this check, exclude Z axis
- //float initial_height = 0; //min(50, (targ_distance * tanh(20)));
- //float current_height = (initial_height * min(1, (this.pass_distance) ? (current_distance / this.pass_distance) : current_distance));
- //print("current_height = ", ftos(current_height), ", initial_height = ", ftos(initial_height), ".\n");
-
- vector targpos = to;
-#if 0
- if(current_height) // make sure we can actually do this arcing path
- {
- targpos = (to + ('0 0 1' * current_height));
- WarpZone_TraceLine(this.origin, targpos, MOVE_NOMONSTERS, this);
- if(trace_fraction < 1)
- {
- //print("normal arc line failed, trying to find new pos...");
- WarpZone_TraceLine(to, targpos, MOVE_NOMONSTERS, this);
- targpos = (trace_endpos + '0 0 -10');
- WarpZone_TraceLine(this.origin, targpos, MOVE_NOMONSTERS, this);
- if(trace_fraction < 1) { targpos = to; /* print(" ^1FAILURE^7, reverting to original direction.\n"); */ }
- /*else { print(" ^3SUCCESS^7, using new arc line.\n"); } */
- }
- }
- else { targpos = to; }
-#endif
-
- //this.angles = normalize(('0 1 0' * to_y) - ('0 1 0' * from_y));
-
- vector desired_direction = normalize(targpos - from);
- if(turnrate) { this.velocity = (normalize(normalize(this.velocity) + (desired_direction * 50)) * movespeed); }
- else { this.velocity = (desired_direction * movespeed); }
-
- //this.steerto = steerlib_attract2(targpos, 0.5, 500, 0.95);
- //this.angles = vectoangles(this.velocity);
-}
-
.entity draggedby;
void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed)
if(!(this.spawnflags & MONSTERFLAG_FLY_VERTICAL) && !(this.flags & FL_SWIM))
this.moveto_z = this.origin_z;
- if(vdist(this.origin - this.moveto, >, 100))
+ fixedmakevectors(this.angles);
+ float vz = this.velocity_z;
+
+ if(!turret_closetotarget(this, this.moveto, 16))
{
bool do_run = (this.enemy || this.monster_moveto);
- if(IS_ONGROUND(this) || ((this.flags & FL_FLY) || (this.flags & FL_SWIM)))
- Monster_CalculateVelocity(this, this.moveto, this.origin, true, ((do_run) ? runspeed : walkspeed));
+ movelib_move_simple(this, v_forward, ((do_run) ? runspeed : walkspeed), 0.4);
- if(time > this.pain_finished && time > this.anim_finished) // TODO: use anim_finished instead!?
+ if(time > this.pain_finished && time > this.anim_finished)
if(!this.state)
{
if(vdist(this.velocity, >, 10))
setanim(this, this.anim_idle, true, false, false);
}
+ if(!((this.flags & FL_FLY) || (this.flags & FL_SWIM)))
+ this.velocity_z = vz;
+
this.steerto = steerlib_attract2(this, ((this.monster_face) ? this.monster_face : this.moveto), 0.5, 500, 0.95);
vector real_angle = vectoangles(this.steerto) - this.angles;
{
this.nextthink = time + this.ticrate;
+ Monster mon = Monsters_from(this.monsterid);
+ mon.mr_deadthink(mon, this);
+
if(this.monster_lifetime != 0)
if(time >= this.monster_lifetime)
{
this.state = 0;
this.attack_finished_single[0] = 0;
this.effects = 0;
+ this.dphitcontentsmask &= ~DPCONTENTS_BODY;
if(!((this.flags & FL_FLY) || (this.flags & FL_SWIM)))
this.velocity = '0 0 0';
void Monster_Enemy_Check(entity this)
{
- if(!this.enemy)
+ if(this.enemy)
+ return;
+
+ this.enemy = Monster_FindTarget(this);
+ if(this.enemy)
{
- this.enemy = Monster_FindTarget(this);
- if(this.enemy)
- {
- WarpZone_RefSys_Copy(this.enemy, this);
- WarpZone_RefSys_AddInverse(this.enemy, this); // wz1^-1 ... wzn^-1 receiver
- // update move target immediately?
- this.moveto = WarpZone_RefSys_TransformOrigin(this.enemy, this, (0.5 * (this.enemy.absmin + this.enemy.absmax)));
- this.monster_moveto = '0 0 0';
- this.monster_face = '0 0 0';
-
- //this.pass_distance = vlen((('1 0 0' * this.enemy.origin_x) + ('0 1 0' * this.enemy.origin_y)) - (('1 0 0' * this.origin_x) + ('0 1 0' * this.origin_y)));
- Monster_Sound(this, monstersound_sight, 0, false, CH_VOICE);
- }
+ WarpZone_RefSys_Copy(this.enemy, this);
+ WarpZone_RefSys_AddInverse(this.enemy, this); // wz1^-1 ... wzn^-1 receiver
+ // update move target immediately?
+ this.moveto = WarpZone_RefSys_TransformOrigin(this.enemy, this, (0.5 * (this.enemy.absmin + this.enemy.absmax)));
+ this.monster_moveto = '0 0 0';
+ this.monster_face = '0 0 0';
+
+ Monster_Sound(this, monstersound_sight, 0, false, CH_VOICE);
}
}
this.max_health = GetResource(this, RES_HEALTH);
this.pain_finished = this.nextthink;
+ this.last_enemycheck = this.spawn_time + random(); // slight delay
if(IS_PLAYER(this.monster_follow))
this.effects |= EF_DIMLIGHT;
else
setmodel(this, mon.m_model);
+ if(!this.monster_name || this.monster_name == "")
+ this.monster_name = mon.monster_name;
+
this.flags = FL_MONSTER;
this.classname = "monster";
this.takedamage = DAMAGE_AIM;
this.reset = Monster_Reset;
this.netname = mon.netname;
this.monster_attackfunc = mon.monster_attackfunc;
- this.monster_name = mon.monster_name;
this.candrop = true;
- this.view_ofs = '0 0 0.7' * (this.maxs_z * 0.5);
this.oldtarget2 = this.target2;
- //this.pass_distance = 0;
this.deadflag = DEAD_NO;
this.spawn_time = time;
this.gravity = 1;
if(autocvar_g_nodepthtestplayers) { this.effects |= EF_NODEPTHTEST; }
if(mon.spawnflags & MONSTER_TYPE_SWIM) { this.flags |= FL_SWIM; }
- if(autocvar_g_playerclip_collisions)
+ if(autocvar_g_monsters_playerclip_collisions)
this.dphitcontentsmask |= DPCONTENTS_PLAYERCLIP;
if(mon.spawnflags & MONSTER_TYPE_FLY)
set_movetype(this, MOVETYPE_FLY);
}
- if(!(this.spawnflags & MONSTERFLAG_RESPAWNED))
- {
- if(mon.spawnflags & MONSTER_SIZE_BROKEN)
- this.scale *= 1.3;
-
- if(mon.spawnflags & MONSTER_SIZE_QUAKE)
- if(autocvar_g_monsters_quake_resize)
- this.scale *= 1.3;
- }
+ if((mon.spawnflags & MONSTER_SIZE_QUAKE) && autocvar_g_monsters_quake_resize && !(this.spawnflags & MONSTERFLAG_RESPAWNED))
+ this.scale *= 1.3;
setsize(this, mon.m_mins * this.scale, mon.m_maxs * this.scale);
+ this.view_ofs = '0 0 0.7' * (this.maxs_z * 0.5);
this.ticrate = bound(sys_frametime, ((!this.ticrate) ? autocvar_g_monsters_think_delay : this.ticrate), 60);
MSG_INFO_NOTIF(DEATH_SELF_GENERIC, N_CONSOLE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_selfkill", _("^BG%s^K1 died%s%s"), "")
MSG_INFO_NOTIF(DEATH_SELF_LAVA, N_CONSOLE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_lava", _("^BG%s^K1 turned into hot slag%s%s"), _("^BG%s^K1 found a hot place%s%s"))
MSG_INFO_NOTIF(DEATH_SELF_MON_MAGE, N_CONSOLE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was exploded by a Mage%s%s"), "")
- MSG_INFO_NOTIF(DEATH_SELF_MON_SHAMBLER_CLAW, N_CONSOLE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1's innards became outwards by a Shambler%s%s"), "")
- MSG_INFO_NOTIF(DEATH_SELF_MON_SHAMBLER_SMASH, N_CONSOLE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was smashed by a Shambler%s%s"), "")
- MSG_INFO_NOTIF(DEATH_SELF_MON_SHAMBLER_ZAP, N_CONSOLE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was zapped to death by a Shambler%s%s"), "")
+ MSG_INFO_NOTIF(DEATH_SELF_MON_GOLEM_CLAW, N_CONSOLE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1's innards became outwards by a Golem%s%s"), "")
+ MSG_INFO_NOTIF(DEATH_SELF_MON_GOLEM_SMASH, N_CONSOLE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was smashed by a Golem%s%s"), "")
+ MSG_INFO_NOTIF(DEATH_SELF_MON_GOLEM_ZAP, N_CONSOLE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was zapped to death by a Golem%s%s"), "")
MSG_INFO_NOTIF(DEATH_SELF_MON_SPIDER, N_CONSOLE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was bitten by a Spider%s%s"), "")
MSG_INFO_NOTIF(DEATH_SELF_MON_WYVERN, N_CONSOLE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was fireballed by a Wyvern%s%s"), "")
MSG_INFO_NOTIF(DEATH_SELF_MON_ZOMBIE_JUMP, N_CONSOLE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 joins the Zombies%s%s"), "")
MULTITEAM_INFO(NEXBALL_RETURN_HELD, N_CONSOLE, 0, 0, "", "", "", _("^BGThe ^TC^TT^BG team held the ball for too long"), "", NAME)
MSG_INFO_NOTIF(ONSLAUGHT_CAPTURE, N_CONSOLE, 2, 0, "s1 s2", "", "", _("^BG%s^BG captured %s^BG control point"), "")
+ MSG_INFO_NOTIF(ONSLAUGHT_CAPTURE_NONAME, N_CONSOLE, 1, 0, "s1", "", "", _("^BG%s^BG captured a control point"), "")
MULTITEAM_INFO(ONSLAUGHT_CPDESTROYED, N_CONSOLE, 2, 0, "s1 s2", "", "", _("^TC^TT^BG team %s^BG control point has been destroyed by %s"), "", NAME)
+ MULTITEAM_INFO(ONSLAUGHT_CPDESTROYED_NONAME, N_CONSOLE, 1, 0, "s1", "", "", _("^TC^TT^BG team control point has been destroyed by %s"), "", NAME)
MULTITEAM_INFO(ONSLAUGHT_GENDESTROYED, N_CONSOLE, 0, 0, "", "", "", _("^TC^TT^BG generator has been destroyed"), "", GENERATOR)
MULTITEAM_INFO(ONSLAUGHT_GENDESTROYED_OVERTIME, N_CONSOLE, 0, 0, "", "", "", _("^TC^TT^BG generator spontaneously combusted due to overtime!"), "", GENERATOR)
MSG_CENTER_NOTIF(DOOR_LOCKED_ALSONEED, N_ENABLE, 1, 0, "s1", CPID_Null, "0 0", _("^BGYou also need %s^BG!"), "")
MSG_CENTER_NOTIF(DOOR_UNLOCKED, N_ENABLE, 0, 0, "", CPID_Null, "0 0", _("^BGDoor unlocked!"), "")
- MSG_CENTER_NOTIF(EXTRALIVES, N_ENABLE, 0, 0, "", CPID_Null, "0 0", _("^F2You picked up some extra lives"), "")
+ MSG_CENTER_NOTIF(EXTRALIVES, N_ENABLE, 0, 1, "f1", CPID_Null, "0 0", _("^F2Extra lives taken: ^K1%s"), "")
MSG_CENTER_NOTIF(FREEZETAG_REVIVE, N_ENABLE, 1, 0, "s1", CPID_Null, "0 0", _("^K3You revived ^BG%s"), "")
MSG_CENTER_NOTIF(FREEZETAG_REVIVE_SELF, N_ENABLE, 0, 0, "", CPID_Null, "0 0", _("^K3You revived yourself"), "")
MSG_CENTER_NOTIF(NIX_NEWWEAPON, N_ENABLE, 0, 1, "item_wepname", CPID_NIX, "0 0", _("^F2Active weapon: ^F1%s"), "")
MSG_CENTER_NOTIF(ONS_CAPTURE, N_ENABLE, 1, 0, "s1", CPID_ONSLAUGHT, "0 0", _("^BGYou captured %s^BG control point"), "")
+ MSG_CENTER_NOTIF(ONS_CAPTURE_NONAME, N_ENABLE, 0, 0, "", CPID_ONSLAUGHT, "0 0", _("^BGYou captured a control point"), "")
MULTITEAM_CENTER(ONS_CAPTURE_TEAM, N_ENABLE, 1, 0, "s1", CPID_ONSLAUGHT, "0 0", _("^TC^TT^BG team captured %s^BG control point"), "", NAME)
+ MULTITEAM_CENTER(ONS_CAPTURE_TEAM_NONAME, N_ENABLE, 0, 0, "", CPID_ONSLAUGHT, "0 0", _("^TC^TT^BG team captured a control point"), "", NAME)
MSG_CENTER_NOTIF(ONS_CONTROLPOINT_SHIELDED, N_ENABLE, 0, 0, "", CPID_ONS_CAPSHIELD, "0 0", _("^BGThis control point currently cannot be captured"), "")
MSG_CENTER_NOTIF(ONS_GENERATOR_SHIELDED, N_ENABLE, 0, 0, "", CPID_ONS_CAPSHIELD, "0 0", _("^BGThe enemy generator cannot be destroyed yet\n^F2Capture some control points to unshield it"), "")
MULTITEAM_CENTER(ONS_NOTSHIELDED, N_ENABLE, 0, 0, "", CPID_ONSLAUGHT, "0 0", _("^BGThe ^TCenemy^BG generator is no longer shielded!"), "", NAME)
MSG_CENTER_NOTIF(RACE_FINISHLAP, N_ENABLE, 0, 0, "", CPID_RACE_FINISHLAP, "0 0", _("^F2The race is over, finish your lap!"), "")
- MSG_CENTER_NOTIF(SECONDARY_NODAMAGE, N_ENABLE, 0, 0, "", CPID_Null, "0 0", _("^BGSecondary fire inflicts no damage!"), "")
-
MSG_CENTER_NOTIF(SEQUENCE_COMPLETED, N_ENABLE, 0, 0, "", CPID_Null, "0 0", _("^BGSequence completed!"), "")
MSG_CENTER_NOTIF(SEQUENCE_COUNTER, N_ENABLE, 0, 0, "", CPID_Null, "0 0", _("^BGThere are more to go..."), "")
MSG_CENTER_NOTIF(SEQUENCE_COUNTER_FEWMORE, N_ENABLE, 0, 1, "f1", CPID_Null, "0 0", _("^BGOnly %s^BG more to go..."), "")
MSG_MULTI_NOTIF(DEATH_SELF_GENERIC, N_ENABLE, NULL, INFO_DEATH_SELF_GENERIC, CENTER_DEATH_SELF_GENERIC)
MSG_MULTI_NOTIF(DEATH_SELF_LAVA, N_ENABLE, NULL, INFO_DEATH_SELF_LAVA, CENTER_DEATH_SELF_LAVA)
MSG_MULTI_NOTIF(DEATH_SELF_MON_MAGE, N_ENABLE, NULL, INFO_DEATH_SELF_MON_MAGE, CENTER_DEATH_SELF_MONSTER)
- MSG_MULTI_NOTIF(DEATH_SELF_MON_SHAMBLER_CLAW, N_ENABLE, NULL, INFO_DEATH_SELF_MON_SHAMBLER_CLAW, CENTER_DEATH_SELF_MONSTER)
- MSG_MULTI_NOTIF(DEATH_SELF_MON_SHAMBLER_SMASH, N_ENABLE, NULL, INFO_DEATH_SELF_MON_SHAMBLER_SMASH, CENTER_DEATH_SELF_MONSTER)
- MSG_MULTI_NOTIF(DEATH_SELF_MON_SHAMBLER_ZAP, N_ENABLE, NULL, INFO_DEATH_SELF_MON_SHAMBLER_ZAP, CENTER_DEATH_SELF_MONSTER)
+ MSG_MULTI_NOTIF(DEATH_SELF_MON_GOLEM_CLAW, N_ENABLE, NULL, INFO_DEATH_SELF_MON_GOLEM_CLAW, CENTER_DEATH_SELF_MONSTER)
+ MSG_MULTI_NOTIF(DEATH_SELF_MON_GOLEM_SMASH, N_ENABLE, NULL, INFO_DEATH_SELF_MON_GOLEM_SMASH, CENTER_DEATH_SELF_MONSTER)
+ MSG_MULTI_NOTIF(DEATH_SELF_MON_GOLEM_ZAP, N_ENABLE, NULL, INFO_DEATH_SELF_MON_GOLEM_ZAP, CENTER_DEATH_SELF_MONSTER)
MSG_MULTI_NOTIF(DEATH_SELF_MON_SPIDER, N_ENABLE, NULL, INFO_DEATH_SELF_MON_SPIDER, CENTER_DEATH_SELF_MONSTER)
MSG_MULTI_NOTIF(DEATH_SELF_MON_WYVERN, N_ENABLE, NULL, INFO_DEATH_SELF_MON_WYVERN, CENTER_DEATH_SELF_MONSTER)
MSG_MULTI_NOTIF(DEATH_SELF_MON_ZOMBIE_JUMP, N_ENABLE, NULL, INFO_DEATH_SELF_MON_ZOMBIE_JUMP, CENTER_DEATH_SELF_MONSTER)
bool autocvar_g_mirrordamage_onlyweapons;
float autocvar_g_movement_highspeed = 1;
+ bool autocvar_g_movement_highspeed_q3_compat = 0;
string autocvar_g_mutatormsg;
//float autocvar_g_nick_flood_penalty;
int autocvar_g_nick_flood_penalty_red;
string autocvar_sv_defaultplayermodel_red;
string autocvar_sv_defaultplayermodel_yellow;
int autocvar_sv_defaultplayerskin;
+ bool autocvar_sv_doors_always_open;
bool autocvar_sv_doublejump;
bool autocvar_sv_eventlog;
bool autocvar_sv_eventlog_console;
bool autocvar_sv_eventlog_files_timestamps;
float autocvar_sv_friction_on_land;
var float autocvar_sv_friction_slick = 0.5;
- float autocvar_sv_gameplayfix_q2airaccelerate;
+ float autocvar_sv_gameplayfix_q2airaccelerate = 1;
int autocvar_sv_gentle;
#define autocvar_sv_gravity cvar("sv_gravity")
string autocvar_sv_intermission_cdtrack;
int autocvar_timelimit_overtimes;
float autocvar_timelimit_suddendeath;
#define autocvar_utf8_enable cvar("utf8_enable")
- float autocvar_sv_gameplayfix_gravityunaffectedbyticrate;
- bool autocvar_sv_gameplayfix_upwardvelocityclearsongroundflag;
+ bool autocvar_sv_gameplayfix_gravityunaffectedbyticrate = true;
+ bool autocvar_sv_gameplayfix_upwardvelocityclearsongroundflag = true;
float autocvar_g_trueaim_minrange;
float autocvar_g_grab_range;
int autocvar_g_max_info_autoscreenshot;
float autocvar_g_monsters_target_range;
bool autocvar_g_monsters_target_infront;
float autocvar_g_monsters_target_infront_range = 0.3;
+bool autocvar_g_monsters_target_infront_2d = true;
float autocvar_g_monsters_attack_range;
int autocvar_g_monsters_score_kill;
int autocvar_g_monsters_score_spawned;
bool autocvar_g_monsters_typefrag;
bool autocvar_g_monsters_owners;
+bool autocvar_g_monsters_playerclip_collisions;
float autocvar_g_monsters_miniboss_chance;
float autocvar_g_monsters_miniboss_healthboost;
float autocvar_g_monsters_drop_time;
BADCVAR("g_duel_not_dm_maps");
BADCVAR("g_freezetag");
BADCVAR("g_freezetag_teams");
- BADCVAR("g_invasion_teams");
BADCVAR("g_invasion_type");
BADCVAR("g_jailbreak");
BADCVAR("g_jailbreak_teams");
BADCVAR("sv_damagetext");
BADCVAR("sv_db_saveasdump");
BADCVAR("sv_intermission_cdtrack");
+ BADCVAR("sv_mapchange_delay");
BADCVAR("sv_minigames");
BADCVAR("sv_namechangetimer");
BADCVAR("sv_precacheplayermodels");
return "Map switch will happen after scoreboard.";
}
- bool autocvar_sv_gameplayfix_multiplethinksperframe;
+ bool autocvar_sv_gameplayfix_multiplethinksperframe = true;
void RunThink(entity this)
{
// don't let things stay in the past.
}
bool autocvar_sv_freezenonclients;
- bool autocvar_sv_gameplayfix_delayprojectiles;
+ bool autocvar_sv_gameplayfix_delayprojectiles = false;
void Physics_Frame()
{
if(autocvar_sv_freezenonclients)
{
g_weapon_stay = 0; // incompatible
start_weapons = g_weaponarena_weapons;
- start_items |= IT_UNLIMITED_AMMO;
+ start_items |= IT_UNLIMITED_AMMO | IT_UNLIMITED_SUPERWEAPONS;
}
else
{
if(!cvar("g_use_ammunition"))
start_items |= IT_UNLIMITED_AMMO;
- if(start_items & IT_UNLIMITED_WEAPON_AMMO)
+ if(start_items & IT_UNLIMITED_AMMO)
{
start_ammo_shells = 999;
start_ammo_nails = 999;
return s;
}
-float MoveToRandomLocationWithinBounds(entity e, vector boundmin, vector boundmax, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
+bool MoveToRandomLocationWithinBounds(entity e, vector boundmin, vector boundmax, float goodcontents, float badcontents, float badsurfaceflags, int attempts, float maxaboveground, float minviewdistance, bool frompos)
{
float m, i;
vector start, org, delta, end, enddown, mstart;
// rule 4: we must "see" some spawnpoint or item
entity sp = NULL;
- IL_EACH(g_spawnpoints, checkpvs(mstart, it),
+ if(frompos)
{
- if((traceline(mstart, it.origin, MOVE_NORMAL, e), trace_fraction) >= 1)
- {
- sp = it;
- break;
- }
- });
+ if((traceline(mstart, e.origin, MOVE_NORMAL, e), trace_fraction) >= 1)
+ sp = e;
+ }
+ if(!sp)
+ {
+ IL_EACH(g_spawnpoints, checkpvs(mstart, it),
+ {
+ if((traceline(mstart, it.origin, MOVE_NORMAL, e), trace_fraction) >= 1)
+ {
+ sp = it;
+ break;
+ }
+ });
+ }
if(!sp)
{
int items_checked = 0;
return false;
}
-float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
+bool MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, int attempts, float maxaboveground, float minviewdistance)
{
- return MoveToRandomLocationWithinBounds(e, world.mins, world.maxs, goodcontents, badcontents, badsurfaceflags, attempts, maxaboveground, minviewdistance);
+ return MoveToRandomLocationWithinBounds(e, world.mins, world.maxs, goodcontents, badcontents, badsurfaceflags, attempts, maxaboveground, minviewdistance, false);
}
void write_recordmarker(entity pl, float tstart, float dt)