set g_balance_porto_primary_animtime 0.3
set g_balance_porto_primary_speed 2000
set g_balance_porto_primary_lifetime 30
+set g_balance_porto_secondary 0
+set g_balance_porto_secondary_refire 1.5
+set g_balance_porto_secondary_animtime 0.3
+set g_balance_porto_secondary_speed 2000
+set g_balance_porto_secondary_lifetime 30
set g_balance_portal_health 200 // these get recharged whenever the portal is used
set g_balance_portal_lifetime 15 // these get recharged whenever the portal is used
// }}}
set g_balance_porto_primary_animtime 0.2
set g_balance_porto_primary_speed 2000
set g_balance_porto_primary_lifetime 5
+set g_balance_porto_secondary 0
+set g_balance_porto_secondary_refire 1.5
+set g_balance_porto_secondary_animtime 0.2
+set g_balance_porto_secondary_speed 2000
+set g_balance_porto_secondary_lifetime 5
set g_balance_portal_health 200 // these get recharged whenever the portal is used
set g_balance_portal_lifetime 15 // these get recharged whenever the portal is used
// }}}
set g_balance_porto_primary_animtime 0.3
set g_balance_porto_primary_speed 1000
set g_balance_porto_primary_lifetime 5
+set g_balance_porto_secondary 0
+set g_balance_porto_secondary_refire 1.5
+set g_balance_porto_secondary_animtime 0.3
+set g_balance_porto_secondary_speed 1000
+set g_balance_porto_secondary_lifetime 5
set g_balance_portal_health 200 // these get recharged whenever the portal is used
set g_balance_portal_lifetime 15 // these get recharged whenever the portal is used
// }}}
set g_balance_porto_primary_animtime 0.3
set g_balance_porto_primary_speed 1000
set g_balance_porto_primary_lifetime 5
+set g_balance_porto_secondary 1
+set g_balance_porto_secondary_refire 1.5
+set g_balance_porto_secondary_animtime 0.3
+set g_balance_porto_secondary_speed 1000
+set g_balance_porto_secondary_lifetime 5
set g_balance_portal_health 200 // these get recharged whenever the portal is used
set g_balance_portal_lifetime 15 // these get recharged whenever the portal is used
// }}}
// Aliases for settemp subsystem. Warning: Do not touch.
// Usage: settemp variable value, next map resets it.
// =======================================================
-alias settemp "qc_cmd_svcl settemp $$*"
+alias settemp "qc_cmd_svcl settemp $*"
alias settemp_restore "qc_cmd_svcl settemp_restore"
seta cl_forcemyplayermodel "" "set to the model file name you want to show yourself as (requires server to have sv_use_csqc_players 1; does not affect how enemies look with cl_forceplayermodels)"
seta cl_forcemyplayerskin 0 "set to the skin number you want to show yourself as (requires server to have sv_use_csqc_players 1; does not affect how enemies look with cl_forceplayermodels)"
seta cl_forcemyplayercolors 0 "set to the color value (encoding is same as _cl_color) for your own player model (requires server to have sv_use_csqc_players 1, and is ignored in teamplay; does not affect how enemies look with cl_forceplayermodels)"
-seta cl_predictionerrorcompensation 0 "try to compensate for prediction errors and reduce preceived lag (requires server to have sv_use_csqc_players 1)"
+seta cl_movement_errorcompensation 1 "try to compensate for prediction errors and reduce preceived lag (requires server to have sv_use_csqc_players 1)"
// debug cvars for keyhunt attaching
set _angles "0 0 0"
float uid2name_dialog;
-.float csqcmodel_isdead; // used by shownames and miscfunctions (float getplayerisdead(float) {}) to know when a player is dead
\ No newline at end of file
+.float csqcmodel_isdead; // used by shownames and miscfunctions (float getplayerisdead(float) {}) to know when a player is dead
+
+#define player_currententnum (spectatee_status > 0 ? spectatee_status : player_localnum + 1)
+
+float g_balance_porto_secondary;
hagar_maxrockets = ReadByte();
g_trueaim_minrange = ReadCoord();
+ g_balance_porto_secondary = ReadByte();
if(!postinit)
PostInit();
if(activeweapon != WEP_PORTO || spectatee_status || gametype == MAPINFO_TYPE_NEXBALL)
return;
+ if(g_balance_porto_secondary)
+ return;
if(intermission == 1)
return;
if(intermission == 2)
string sign;
vector distribution_color;
entity tm, pl, me;
+
#ifdef COMPAT_XON050_ENGINE
me = (spectatee_status > 0) ? playerslots[spectatee_status - 1] : playerslots[player_localentnum - 1];
#else
* IN THE SOFTWARE.
*/
-var float autocvar_cl_predictionerrorcompensation = 0;
+var float autocvar_cl_movement_errorcompensation = 0;
// engine stuff
.float pmove_flags;
return csqcplayer_predictionerrorv * (csqcplayer_predictionerrortime - time) * csqcplayer_predictionerrorfactor;
}
-void CSQCPlayer_SetPredictionError(vector o, vector v)
+void CSQCPlayer_SetPredictionError(vector o, vector v, float onground_diff)
{
- if(!autocvar_cl_predictionerrorcompensation)
+ // error too big to compensate, we LIKELY hit a teleport or a
+ // jumppad, or it's a jump time disagreement that'll get fixed
+ // next frame
+
+ // FIXME we sometimes have disagreement in order of jump velocity. Do not act on them!
+ /*
+ // commented out as this one did not help
+ if(onground_diff)
{
- csqcplayer_predictionerrorfactor = 0;
+ print(sprintf("ONGROUND MISMATCH: %d x=%v v=%v\n", onground_diff, o, v));
+ return;
+ }
+ */
+ if(vlen(o) > 32 || vlen(v) > 192)
+ {
+ //print(sprintf("TOO BIG: x=%v v=%v\n", o, v));
return;
}
- // error too big to compensate, we LIKELY hit a teleport or a
- // jumppad, or it's a jump time disagreement that'll get fixed
- // next frame
- if(vlen(o) > 32 || vlen(v) > 128)
+ if(!autocvar_cl_movement_errorcompensation)
+ {
+ csqcplayer_predictionerrorfactor = 0;
return;
+ }
csqcplayer_predictionerroro = CSQCPlayer_GetPredictionErrorO() + o;
csqcplayer_predictionerrorv = CSQCPlayer_GetPredictionErrorV() + v;
- csqcplayer_predictionerrorfactor = autocvar_cl_predictionerrorcompensation / ticrate;
+ csqcplayer_predictionerrorfactor = autocvar_cl_movement_errorcompensation / ticrate;
csqcplayer_predictionerrortime = time + 1.0 / csqcplayer_predictionerrorfactor;
}
v = v0;
csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
CSQCPlayer_PredictTo(servercommandframe + 1, FALSE);
- CSQCPlayer_SetPredictionError(self.origin - o, self.velocity - v);
+ CSQCPlayer_SetPredictionError(self.origin - o, self.velocity - v, pmove_onground - !!(self.pmove_flags & PMF_ONGROUND));
self.origin = o;
self.velocity = v;
me.TR(me);
me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_movement", _("Client-side movement prediction")));
+ me.TR(me);
+ me.TDempty(me, 0.2);
+ me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "cl_movement_errorcompensation", _("Movement error compensation")));
+ setDependent(e, "cl_movement", 1, 1);
me.TR(me);
//me.TD(me, 1, 3, e = makeXonoticCheckBox(1, "cl_nolerp", _("Network update smoothing")));
me.TR(me);
float autocvar_g_balance_porto_primary_lifetime;
float autocvar_g_balance_porto_primary_refire;
float autocvar_g_balance_porto_primary_speed;
+float autocvar_g_balance_porto_secondary;
+float autocvar_g_balance_porto_secondary_animtime;
+float autocvar_g_balance_porto_secondary_lifetime;
+float autocvar_g_balance_porto_secondary_refire;
+float autocvar_g_balance_porto_secondary_speed;
float autocvar_g_balance_powerup_invincible_takedamage;
float autocvar_g_balance_powerup_invincible_time;
float autocvar_g_balance_powerup_strength_damage;
if(f)
{
self.colormod = '0 8 8';
- print("Bot wants to fire, inhibited by weaponentity state\n");
+ print("Bot ", self.netname, " using ", self.weaponname, " wants to fire, inhibited by weaponentity state\n");
}
}
else if(ATTACK_FINISHED(self) > time)
if(f)
{
self.colormod = '8 0 8';
- print("Bot wants to fire, inhibited by ATTACK_FINISHED\n");
+ print("Bot ", self.netname, " using ", self.weaponname, " wants to fire, inhibited by ATTACK_FINISHED (", ftos(ATTACK_FINISHED(self) - time), " seconds left)\n");
}
}
else if(self.tuba_note)
if(f)
{
self.colormod = '8 0 0';
- print("Bot wants to fire, bot still has an active tuba note\n");
+ print("Bot ", self.netname, " using ", self.weaponname, " wants to fire, bot still has an active tuba note\n");
}
}
else
if(!f)
{
self.colormod = '8 8 0';
- print("Bot thinks it has fired, but apparently did not\n");
+ print("Bot ", self.netname, " using ", self.weaponname, " thinks it has fired, but apparently did not; ATTACK_FINISHED says ", ftos(ATTACK_FINISHED(self) - time), " seconds left\n");
}
}
WriteByte(MSG_ENTITY, autocvar_g_balance_minelayer_limit); // minelayer max mines
WriteByte(MSG_ENTITY, autocvar_g_balance_hagar_secondary_load_max); // hagar max loadable rockets
WriteCoord(MSG_ENTITY, autocvar_g_trueaim_minrange);
+ WriteByte(MSG_ENTITY, autocvar_g_balance_porto_secondary);
return TRUE;
}
}
if (self.items & IT_SUPERWEAPON)
{
- self.effects = self.effects | EF_RED;
+ //if(W_WeaponBit(self.weapon) & WEPBIT_SUPERWEAPONS)
+ // self.effects = self.effects | EF_RED;
if (!(self.weapons & WEPBIT_SUPERWEAPONS))
{
self.superweapons_finished = 0;
}
}
}
- else
+ else if(self.weapons & WEPBIT_SUPERWEAPONS)
{
- if (time < self.superweapons_finished)
+ if (time < self.superweapons_finished || (self.items & IT_UNLIMITED_SUPERWEAPONS))
{
self.items = self.items | IT_SUPERWEAPON;
sprint(self, "^3You now have a superweapon\n");
}
else
+ {
+ self.superweapons_finished = 0;
self.weapons &~= WEPBIT_SUPERWEAPONS; // just in case
+ }
+ }
+ else
+ {
+ self.superweapons_finished = 0;
}
}
portal = Portal_Spawn(own, org, ang);
if(!portal)
- {
- // if(!own.portal_out || own.portal_out.portal_id == portal_id_val)
- Portal_ClearAll_PortalsOnly(own);
return 0;
- }
portal.portal_id = portal_id_val;
Portal_SetInPortal(own, portal);
portal = Portal_Spawn(own, org, ang);
if(!portal)
- {
- // if(!own.portal_in || own.portal_in.portal_id == portal_id_val)
- Portal_ClearAll_PortalsOnly(own);
return 0;
- }
portal.portal_id = portal_id_val;
Portal_SetOutPortal(own, portal);
void Portal_ClearWithID(entity own, float id);
vector Portal_ApplyTransformToPlayerAngle(vector transform, vector vangle);
+void Portal_ClearAll_PortalsOnly(entity own);
other.lastteleporttime = time;
if (!other.animstate_override)
+ if (other.deadflag == DEAD_NO)
{
if (other.crouch)
setanim(other, other.anim_duckjump, FALSE, TRUE, TRUE);
spot = vehicles_findgoodexit(spot);
setorigin(self.owner , spot);
self.owner.velocity = (v_up + v_forward * 0.25) * 750;
+ self.owner.oldvelocity = self.owner.velocity;
}
else
{
- self.owner.velocity = '0 0 0';
+ self.owner.velocity = normalize(self.velocity) * autocvar_sv_maxairspeed;
+ self.owner.oldvelocity = self.owner.velocity;
spot = self.origin - v_forward * 200 + '0 0 64';
spot = vehicles_findgoodexit(spot);
setorigin(self.owner , spot);
spot = vehicles_findgoodexit(spot);
setorigin(self.owner , spot);
self.owner.velocity = (v_up + v_forward * 0.25) * 750;
+ self.owner.oldvelocity = self.owner.velocity;
}
else
{
- self.owner.velocity = '0 0 0';
+ self.owner.velocity = normalize(self.velocity) * autocvar_sv_maxairspeed;
+ self.owner.oldvelocity = self.owner.velocity;
spot = self.origin - v_forward * 200 + '0 0 64';
spot = vehicles_findgoodexit(spot);
setorigin(self.owner , spot);
spot = vehicles_findgoodexit(spot);
setorigin(self.owner , spot);
self.owner.velocity = (v_up + v_forward * 0.25) * 750;
+ self.owner.oldvelocity = self.owner.velocity;
}
else
{
- self.owner.velocity = '0 0 0';
+ self.owner.velocity = normalize(self.velocity) * autocvar_sv_maxairspeed;
+ self.owner.oldvelocity = self.owner.velocity;
spot = self.origin - v_forward * 200 + '0 0 64';
spot = vehicles_findgoodexit(spot);
setorigin(self.owner , spot);
#ifdef REGISTER_WEAPON
-REGISTER_WEAPON(PORTO, w_porto, 0, 0, WEP_TYPE_OTHER, 0, "porto" , "porto", _("Port-O-Launch"))
+REGISTER_WEAPON(PORTO, w_porto, 0, 0, WEP_TYPE_OTHER | WEP_FLAG_SUPERWEAPON, 0, "porto" , "porto", _("Port-O-Launch"))
#else
#ifdef SVQC
.entity porto_current;
}
// no portals here!
- Portal_ClearWithID(self.realowner, self.portal_id);
+ if(self.cnt < 0)
+ {
+ Portal_ClearWithID(self.realowner, self.portal_id);
+ }
+
self.realowner.porto_current = world;
- if(!failhard && self.realowner.playerid == self.playerid && self.realowner.deadflag == DEAD_NO && !(self.realowner.weapons & WEPBIT_PORTO))
+ if(self.cnt < 0 && !failhard && self.realowner.playerid == self.playerid && self.realowner.deadflag == DEAD_NO && !(self.realowner.weapons & WEPBIT_PORTO))
{
setsize (self, '-16 -16 0', '16 16 32');
setorigin(self, self.origin + trace_plane_normal);
vector norm;
// do not use PROJECTILE_TOUCH here
+ // FIXME but DO handle warpzones!
if(other.classname == "portal")
return; // handled by the portal
{
sound(self, CH_SHOTS, "porto/unsupported.wav", VOL_BASE, ATTN_NORM);
W_Porto_Fail(0);
+ if(self.cnt < 0)
+ Portal_ClearAll_PortalsOnly(self.realowner);
+ }
+ else if(self.cnt == 0)
+ {
+ // in-portal only
+ if(Portal_SpawnInPortalAtTrace(self.realowner, self.right_vector, self.portal_id))
+ {
+ sound(self, CH_SHOTS, "porto/create.wav", VOL_BASE, ATTN_NORM);
+ trace_plane_normal = norm;
+ centerprint(self.realowner, "^1In^7-portal created.");
+ W_Porto_Success();
+ }
+ else
+ {
+ sound(self, CH_SHOTS, "porto/unsupported.wav", VOL_BASE, ATTN_NORM);
+ trace_plane_normal = norm;
+ W_Porto_Fail(0);
+ }
+ }
+ else if(self.cnt == 1)
+ {
+ // out-portal only
+ if(Portal_SpawnOutPortalAtTrace(self.realowner, self.right_vector, self.portal_id))
+ {
+ sound(self, CH_SHOTS, "porto/create.wav", VOL_BASE, ATTN_NORM);
+ trace_plane_normal = norm;
+ centerprint(self.realowner, "^1Out^7-portal created.");
+ W_Porto_Success();
+ }
+ else
+ {
+ sound(self, CH_SHOTS, "porto/unsupported.wav", VOL_BASE, ATTN_NORM);
+ trace_plane_normal = norm;
+ W_Porto_Fail(0);
+ }
}
else if(self.effects & EF_RED)
{
{
sound(self, CH_SHOTS, "porto/unsupported.wav", VOL_BASE, ATTN_NORM);
trace_plane_normal = norm;
+ Portal_ClearAll_PortalsOnly(self.realowner);
W_Porto_Fail(0);
}
}
else
{
sound(self, CH_SHOTS, "porto/unsupported.wav", VOL_BASE, ATTN_NORM);
+ Portal_ClearAll_PortalsOnly(self.realowner);
W_Porto_Fail(0);
}
}
else
{
sound(self, CH_SHOTS, "porto/unsupported.wav", VOL_BASE, ATTN_NORM);
+ Portal_ClearAll_PortalsOnly(self.realowner);
W_Porto_Fail(0);
}
}
}
-void W_Porto_Attack (void)
+void W_Porto_Attack (float type)
{
entity gren;
- if not(self.items & IT_UNLIMITED_SUPERWEAPONS)
- self.weapons = self.weapons - (self.weapons & WEPBIT_PORTO);
+ if(type == -1)
+ {
+ if not(self.items & IT_UNLIMITED_SUPERWEAPONS)
+ self.weapons = self.weapons - (self.weapons & WEPBIT_PORTO);
+ }
+
W_SetupShot (self, FALSE, 4, "porto/fire.wav", CH_WEAPON_A, 0);
// always shoot from the eye
w_shotdir = v_forward;
//pointparticles(particleeffectnum("grenadelauncher_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
gren = spawn ();
+ gren.cnt = type;
gren.owner = gren.realowner = self;
gren.playerid = self.playerid;
gren.classname = "porto";
setorigin(gren, w_shotorg);
setsize(gren, '0 0 0', '0 0 0');
- gren.nextthink = time + autocvar_g_balance_porto_primary_lifetime;
+ if(type > 0)
+ gren.nextthink = time + autocvar_g_balance_porto_secondary_lifetime;
+ else
+ gren.nextthink = time + autocvar_g_balance_porto_primary_lifetime;
gren.think = W_Porto_Think;
gren.touch = W_Porto_Touch;
- if(self.items & IT_STRENGTH)
- W_SetupProjectileVelocity(gren, autocvar_g_balance_porto_primary_speed * autocvar_g_balance_powerup_strength_force, 0);
+
+ if(type > 0)
+ {
+ if(self.items & IT_STRENGTH)
+ W_SetupProjectileVelocity(gren, autocvar_g_balance_porto_secondary_speed * autocvar_g_balance_powerup_strength_force, 0);
+ else
+ W_SetupProjectileVelocity(gren, autocvar_g_balance_porto_secondary_speed, 0);
+ }
else
- W_SetupProjectileVelocity(gren, autocvar_g_balance_porto_primary_speed, 0);
+ {
+ if(self.items & IT_STRENGTH)
+ W_SetupProjectileVelocity(gren, autocvar_g_balance_porto_primary_speed * autocvar_g_balance_powerup_strength_force, 0);
+ else
+ W_SetupProjectileVelocity(gren, autocvar_g_balance_porto_primary_speed, 0);
+ }
gren.angles = vectoangles (gren.velocity);
gren.flags = FL_PROJECTILE;
gren.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP;
- CSQCProjectile(gren, TRUE, PROJECTILE_PORTO_RED, TRUE);
+ if(type > 0)
+ CSQCProjectile(gren, TRUE, PROJECTILE_PORTO_BLUE, TRUE);
+ else
+ CSQCProjectile(gren, TRUE, PROJECTILE_PORTO_RED, TRUE);
other = gren; MUTATOR_CALLHOOK(EditProjectile);
}
{
self.BUTTON_ATCK = FALSE;
self.BUTTON_ATCK2 = FALSE;
- if(bot_aim(autocvar_g_balance_porto_primary_speed, 0, autocvar_g_balance_grenadelauncher_primary_lifetime, FALSE))
- self.BUTTON_ATCK = TRUE;
+ if(!autocvar_g_balance_porto_secondary)
+ if(bot_aim(autocvar_g_balance_porto_primary_speed, 0, autocvar_g_balance_grenadelauncher_primary_lifetime, FALSE))
+ self.BUTTON_ATCK = TRUE;
}
else if (req == WR_THINK)
{
- if(self.porto_v_angle_held)
+ if(autocvar_g_balance_porto_secondary)
{
- if(!self.BUTTON_ATCK2)
+ if (self.BUTTON_ATCK)
+ if (!self.porto_current)
+ if (!self.porto_forbidden)
+ if (weapon_prepareattack(0, autocvar_g_balance_porto_primary_refire))
{
- self.porto_v_angle_held = 0;
+ W_Porto_Attack(0);
+ weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_porto_primary_animtime, w_ready);
+ }
- ClientData_Touch(self);
+ if (self.BUTTON_ATCK2)
+ if (!self.porto_current)
+ if (!self.porto_forbidden)
+ if (weapon_prepareattack(1, autocvar_g_balance_porto_secondary_refire))
+ {
+ W_Porto_Attack(1);
+ weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_porto_secondary_animtime, w_ready);
}
}
else
{
- if(self.BUTTON_ATCK2)
+ if(self.porto_v_angle_held)
{
- self.porto_v_angle = self.v_angle;
- self.porto_v_angle_held = 1;
+ if(!self.BUTTON_ATCK2)
+ {
+ self.porto_v_angle_held = 0;
- ClientData_Touch(self);
+ ClientData_Touch(self);
+ }
+ }
+ else
+ {
+ if(self.BUTTON_ATCK2)
+ {
+ self.porto_v_angle = self.v_angle;
+ self.porto_v_angle_held = 1;
+
+ ClientData_Touch(self);
+ }
+ }
+ v_angle_save = self.v_angle;
+ if(self.porto_v_angle_held)
+ makevectors(self.porto_v_angle); // override the previously set angles
+
+ if (self.BUTTON_ATCK)
+ if (!self.porto_current)
+ if (!self.porto_forbidden)
+ if (weapon_prepareattack(0, autocvar_g_balance_porto_primary_refire))
+ {
+ W_Porto_Attack(-1);
+ weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_porto_primary_animtime, w_ready);
}
- }
- v_angle_save = self.v_angle;
- if(self.porto_v_angle_held)
- makevectors(self.porto_v_angle); // override the previously set angles
-
- if (self.BUTTON_ATCK)
- if (!self.porto_current)
- if (!self.porto_forbidden)
- if (weapon_prepareattack(0, autocvar_g_balance_porto_primary_refire))
- {
- W_Porto_Attack();
- weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_porto_primary_animtime, w_ready);
}
}
else if (req == WR_PRECACHE)