From: TimePath Date: Fri, 30 Jan 2015 08:59:22 +0000 (+1100) Subject: Merge branch 'Mario/qc_updates' into TimePath/csqc_prediction X-Git-Tag: xonotic-v0.8.1~38^2~37^2~2 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=244e5081c5c503c307e557c98ac864f6c9731475;p=xonotic%2Fxonotic-data.pk3dir.git Merge branch 'Mario/qc_updates' into TimePath/csqc_prediction Conflicts: qcsrc/client/autocvars.qh qcsrc/client/main.qh qcsrc/client/miscfunctions.qc qcsrc/client/movetypes.qc qcsrc/client/movetypes.qh qcsrc/client/progs.src qcsrc/common/constants.qh qcsrc/common/stats.qh qcsrc/csqcmodellib/cl_player.qc qcsrc/server/cl_client.qc qcsrc/server/cl_physics.qc qcsrc/server/miscfunctions.qc qcsrc/server/mutators/mutator_dodging.qc qcsrc/server/mutators/mutator_dodging.qh qcsrc/server/mutators/mutator_multijump.qc qcsrc/server/progs.src qcsrc/server/t_halflife.qc qcsrc/server/t_jumppads.qc qcsrc/server/t_plats.qc qcsrc/warpzonelib/common.qh qcsrc/warpzonelib/util_server.qc --- 244e5081c5c503c307e557c98ac864f6c9731475 diff --cc qcsrc/client/autocvars.qh index adc587764,e35bf82dd..871ac8cdc --- a/qcsrc/client/autocvars.qh +++ b/qcsrc/client/autocvars.qh @@@ -439,28 -445,28 +445,29 @@@ bool autocvar_cl_damageeffect_distribut float autocvar_cl_damageeffect_lifetime; float autocvar_cl_damageeffect_lifetime_min; float autocvar_cl_damageeffect_lifetime_max; - float autocvar_cl_playerdetailreduction; - float autocvar_cl_modeldetailreduction; + int autocvar_cl_playerdetailreduction; + int autocvar_cl_modeldetailreduction; float autocvar_cl_loddistance1 = 768; float autocvar_cl_loddistance2 = 2048; - float autocvar_cl_forceplayermodels; - float autocvar_cl_forceplayercolors; + bool autocvar_cl_forceplayermodels; + bool autocvar_cl_forceplayercolors; string autocvar_cl_forcemyplayermodel; - float autocvar_cl_forcemyplayerskin; - float autocvar_cl_forcemyplayercolors; - float autocvar__cl_color; - float autocvar__cl_playerskin; + int autocvar_cl_forcemyplayerskin; + int autocvar_cl_forcemyplayercolors; + int autocvar__cl_color; + int autocvar__cl_playerskin; string autocvar__cl_playermodel; float autocvar_cl_deathglow; - float autocvar_developer_csqcentities; + bool autocvar_developer_csqcentities; float autocvar_g_jetpack_attenuation; - var string autocvar_crosshair_hmg = ""; - var vector autocvar_crosshair_hmg_color = '0.2 1.0 0.2'; - var float autocvar_crosshair_hmg_alpha = 1; - var float autocvar_crosshair_hmg_size = 1; - var string autocvar_crosshair_rpc = ""; - var vector autocvar_crosshair_rpc_color = '0.2 1.0 0.2'; - var float autocvar_crosshair_rpc_alpha = 1; - var float autocvar_crosshair_rpc_size = 1; - float autocvar_cl_nade_timer; + string autocvar_crosshair_hmg = ""; + vector autocvar_crosshair_hmg_color = '0.2 1.0 0.2'; + float autocvar_crosshair_hmg_alpha = 1; + float autocvar_crosshair_hmg_size = 1; + string autocvar_crosshair_rpc = ""; + vector autocvar_crosshair_rpc_color = '0.2 1.0 0.2'; + float autocvar_crosshair_rpc_alpha = 1; + float autocvar_crosshair_rpc_size = 1; + int autocvar_cl_nade_timer; +float autocvar_speedmeter; + #endif diff --cc qcsrc/client/main.qc index 000000000,13f9545fa..e5c875b37 mode 000000,100644..100644 --- a/qcsrc/client/main.qc +++ b/qcsrc/client/main.qc @@@ -1,0 -1,1319 +1,1350 @@@ + #include "mapvoting.qh" + #include "modeleffects.qh" + #include "particles.qh" + #include "scoreboard.qh" + #include "shownames.qh" + #include "target_music.qh" + #include "tturrets.qh" + #include "tuba.qh" + #include "wall.qh" + #include "waypointsprites.qh" + + #include "vehicles/vehicles.qh" + + #include "../server/vehicles/bumblebee.qh" + + #include "../common/net_notice.qh" + + #include "../common/monsters/monsters.qh" + + #include "../warpzonelib/client.qh" + + // -------------------------------------------------------------------------- + // BEGIN REQUIRED CSQC FUNCTIONS + //include "main.qh" + + entity clearentity_ent; + void clearentity(entity e) + { + if (!clearentity_ent) + { + clearentity_ent = spawn(); + clearentity_ent.classname = "clearentity"; + } + int n = e.entnum; + copyentity(clearentity_ent, e); + e.entnum = n; + } + + #define DP_CSQC_ENTITY_REMOVE_IS_B0RKED + void menu_show_error() + { + drawstring('0 200 0', _("ERROR - MENU IS VISIBLE BUT NO MENU WAS DEFINED!"), '8 8 0', '1 0 0', 1, 0); + } + + // CSQC_Init : Called every time the CSQC code is initialized (essentially at map load) + // Useful for precaching things + + void menu_sub_null() + { + } + + string forcefog; + void WaypointSprite_Load(); + void ConsoleCommand_macro_init(); + void CSQC_Init(void) + { + prvm_language = cvar_string("prvm_language"); + + #ifdef WATERMARK + dprintf("^4CSQC Build information: ^1%s\n", WATERMARK); + #endif + + int i; + + binddb = db_create(); + tempdb = db_create(); + ClientProgsDB = db_load("client.db"); + compressShortVector_init(); + + draw_endBoldFont(); + menu_visible = false; + menu_show = menu_show_error; + menu_action = func_null; + + for(i = 0; i < 255; ++i) + if(getplayerkeyvalue(i, "viewentity") == "") + break; + maxclients = i; + + //registercommand("hud_configure"); + //registercommand("hud_save"); + //registercommand("menu_action"); + + ConsoleCommand_macro_init(); + + registercvar("hud_usecsqc", "1"); + registercvar("scoreboard_columns", "default"); + + registercvar("cl_nade_type", "3"); + registercvar("cl_pokenade_type", "zombie"); + + gametype = 0; + + // hud_fields uses strunzone on the titles! + for(i = 0; i < MAX_HUD_FIELDS; ++i) + hud_title[i] = strzone("(null)"); + + Cmd_HUD_SetFields(0); + + postinit = false; + + calledhooks = 0; + + teams = Sort_Spawn(); + players = Sort_Spawn(); + + GetTeam(NUM_SPECTATOR, true); // add specs first + + // needs to be done so early because of the constants they create + CALL_ACCUMULATED_FUNCTION(RegisterWeapons); + CALL_ACCUMULATED_FUNCTION(RegisterMonsters); + CALL_ACCUMULATED_FUNCTION(RegisterGametypes); + CALL_ACCUMULATED_FUNCTION(RegisterNotifications); + CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes); + CALL_ACCUMULATED_FUNCTION(RegisterHUD_Panels); + CALL_ACCUMULATED_FUNCTION(RegisterBuffs); + + WaypointSprite_Load(); + + // precaches + precache_model("null"); + precache_sound("misc/hit.wav"); + precache_sound("misc/typehit.wav"); + + Projectile_Precache(); + Hook_Precache(); + GibSplash_Precache(); + Casings_Precache(); + Vehicles_Precache(); + turrets_precache(); + Tuba_Precache(); + CSQCPlayer_Precache(); + + if(autocvar_cl_reticle) + { + precache_pic("gfx/reticle_normal"); + // weapon reticles are precached in weapon files + } + + get_mi_min_max_texcoords(1); // try the CLEVER way first + minimapname = strcat("gfx/", mi_shortname, "_radar.tga"); + shortmapname = mi_shortname; + + if(precache_pic(minimapname) == "") + { + // but maybe we have a non-clever minimap + minimapname = strcat("gfx/", mi_shortname, "_mini.tga"); + if(precache_pic(minimapname) == "") + minimapname = ""; // FAIL + else + get_mi_min_max_texcoords(0); // load new texcoords + } + + mi_center = (mi_min + mi_max) * 0.5; + mi_scale = mi_max - mi_min; + minimapname = strzone(minimapname); + + WarpZone_Init(); + + hud_skin_path = strzone(strcat("gfx/hud/", autocvar_hud_skin)); + hud_configure_prev = -1; + + draw_currentSkin = strzone(strcat("gfx/menu/", cvar_string("menu_skin"))); + } + + // CSQC_Shutdown : Called every time the CSQC code is shutdown (changing maps, quitting, etc) + void Shutdown(void) + { + WarpZone_Shutdown(); + + remove(teams); + remove(players); + db_close(binddb); + db_close(tempdb); + if(autocvar_cl_db_saveasdump) + db_dump(ClientProgsDB, "client.db"); + else + db_save(ClientProgsDB, "client.db"); + db_close(ClientProgsDB); + + if(camera_active) + cvar_set("chase_active",ftos(chase_active_backup)); + + // unset the event chasecam's chase_active + if(autocvar_chase_active < 0) + cvar_set("chase_active", "0"); + + if (!isdemo()) + { + if (!(calledhooks & HOOK_START)) + localcmd("\n_cl_hook_gamestart nop\n"); + if (!(calledhooks & HOOK_END)) + localcmd("\ncl_hook_gameend\n"); + } + } + + .float has_team; + float SetTeam(entity o, int Team) + { + entity tm; + if(teamplay) + { + switch(Team) + { + case -1: + case NUM_TEAM_1: + case NUM_TEAM_2: + case NUM_TEAM_3: + case NUM_TEAM_4: + break; + default: + if(GetTeam(Team, false) == world) + { + dprintf("trying to switch to unsupported team %d\n", Team); + Team = NUM_SPECTATOR; + } + break; + } + } + else + { + switch(Team) + { + case -1: + case 0: + break; + default: + if(GetTeam(Team, false) == world) + { + dprintf("trying to switch to unsupported team %d\n", Team); + Team = NUM_SPECTATOR; + } + break; + } + } + if(Team == -1) // leave + { + if(o.has_team) + { + tm = GetTeam(o.team, false); + tm.team_size -= 1; + o.has_team = 0; + return true; + } + } + else + { + if (!o.has_team) + { + o.team = Team; + tm = GetTeam(Team, true); + tm.team_size += 1; + o.has_team = 1; + return true; + } + else if(Team != o.team) + { + tm = GetTeam(o.team, false); + tm.team_size -= 1; + o.team = Team; + tm = GetTeam(Team, true); + tm.team_size += 1; + return true; + } + } + return false; + } + + void Playerchecker_Think() + { + int i; + entity e; + for(i = 0; i < maxclients; ++i) + { + e = playerslots[i]; + if(GetPlayerName(i) == "") + { + if(e.sort_prev) + { + // player disconnected + SetTeam(e, -1); + RemovePlayer(e); + e.sort_prev = world; + //e.gotscores = 0; + } + } + else + { + if (!e.sort_prev) + { + // player connected + if (!e) + playerslots[i] = e = spawn(); + e.sv_entnum = i; + e.ping = 0; + e.ping_packetloss = 0; + e.ping_movementloss = 0; + //e.gotscores = 0; // we might already have the scores... + SetTeam(e, GetPlayerColor(i)); // will not hurt; later updates come with HUD_UpdatePlayerTeams + RegisterPlayer(e); + HUD_UpdatePlayerPos(e); + } + } + } + self.nextthink = time + 0.2; + } + + void Porto_Init(); + void TrueAim_Init(); + void PostInit(void) + { + entity playerchecker; + playerchecker = spawn(); + playerchecker.think = Playerchecker_Think; + playerchecker.nextthink = time + 0.2; + + Porto_Init(); + TrueAim_Init(); + + postinit = true; + } + + // CSQC_InputEvent : Used to perform actions based on any key pressed, key released and mouse on the client. + // Return value should be 1 if CSQC handled the input, otherwise return 0 to have the input passed to the engine. + // All keys are in ascii. + // bInputType = 0 is key pressed, 1 is key released, 2 and 3 are mouse input. + // In the case of keyboard input, nPrimary is the ascii code, and nSecondary is 0. + // In the case of mouse input, nPrimary is xdelta, nSecondary is ydelta. + // In the case of mouse input after a setcursormode(1) call, nPrimary is xpos, nSecondary is ypos. + float CSQC_InputEvent(float bInputType, float nPrimary, float nSecondary) + { + float bSkipKey; + bSkipKey = false; + + if (HUD_Panel_InputEvent(bInputType, nPrimary, nSecondary)) + return true; + + if (MapVote_InputEvent(bInputType, nPrimary, nSecondary)) + return true; + + if(menu_visible && menu_action) + if(menu_action(bInputType, nPrimary, nSecondary)) + return true; + + return bSkipKey; + } + + // END REQUIRED CSQC FUNCTIONS + // -------------------------------------------------------------------------- + + // -------------------------------------------------------------------------- + // BEGIN OPTIONAL CSQC FUNCTIONS ++void trigger_touch_generic(void() touchfunc) ++{ ++ entity e; ++ for(e = findradius((self.absmin + self.absmax) * 0.5, vlen(self.absmax - self.absmin) * 0.5 + 1); e; e = e.chain) ++ if(e.isplayermodel) ++ { ++ vector emin = e.absmin, emax = e.absmax; ++ if(self.solid == SOLID_BSP) ++ { ++ emin -= '1 1 1'; ++ emax += '1 1 1'; ++ } ++ if(boxesoverlap(emin, emax, self.absmin, self.absmax)) // quick ++ if(WarpZoneLib_BoxTouchesBrush(emin, emax, self, e)) // accurate ++ { ++ other = e; ++ touchfunc(); ++ } ++ } ++} ++ + void Ent_RemoveEntCS() + { + entcs_receiver[self.sv_entnum] = world; + } + void Ent_ReadEntCS() + { + int sf; + InterpolateOrigin_Undo(); + + self.classname = "entcs_receiver"; + sf = ReadByte(); + + if(sf & 1) + self.sv_entnum = ReadByte(); + if(sf & 2) + { + self.origin_x = ReadShort(); + self.origin_y = ReadShort(); + self.origin_z = ReadShort(); + setorigin(self, self.origin); + } + if(sf & 4) + { + self.angles_y = ReadByte() * 360.0 / 256; + self.angles_x = self.angles_z = 0; + } + if(sf & 8) + self.healthvalue = ReadByte() * 10; + if(sf & 16) + self.armorvalue = ReadByte() * 10; + + entcs_receiver[self.sv_entnum] = self; + self.entremove = Ent_RemoveEntCS; + self.iflags |= IFLAG_ORIGIN; + + InterpolateOrigin_Note(); + } + + void Ent_Remove(); + + void Ent_RemovePlayerScore() + { + if(self.owner) { + SetTeam(self.owner, -1); + self.owner.gotscores = 0; + for(int i = 0; i < MAX_SCORE; ++i) { + self.owner.(scores[i]) = 0; // clear all scores + } + } + } + + void Ent_ReadPlayerScore() + { + int i, n; + bool isNew; + entity o; + + // damnit -.- don't want to go change every single .sv_entnum in hud.qc AGAIN + // (no I've never heard of M-x replace-string, sed, or anything like that) + isNew = !self.owner; // workaround for DP bug + n = ReadByte()-1; + + #ifdef DP_CSQC_ENTITY_REMOVE_IS_B0RKED + if(!isNew && n != self.sv_entnum) + { + //print("A CSQC entity changed its owner!\n"); + printf("A CSQC entity changed its owner! (edict: %d, classname: %s)\n", num_for_edict(self), self.classname); + isNew = true; + Ent_Remove(); + self.enttype = ENT_CLIENT_SCORES; + } + #endif + + self.sv_entnum = n; + + if (!(playerslots[self.sv_entnum])) + playerslots[self.sv_entnum] = spawn(); + o = self.owner = playerslots[self.sv_entnum]; + o.sv_entnum = self.sv_entnum; + o.gotscores = 1; + + //if (!o.sort_prev) + // RegisterPlayer(o); + //playerchecker will do this for us later, if it has not already done so + + int sf, lf; + #if MAX_SCORE <= 8 + sf = ReadByte(); + lf = ReadByte(); + #else + sf = ReadShort(); + lf = ReadShort(); + #endif + int p; + for(i = 0, p = 1; i < MAX_SCORE; ++i, p *= 2) + if(sf & p) + { + if(lf & p) + o.(scores[i]) = ReadInt24_t(); + else + o.(scores[i]) = ReadChar(); + } + + if(o.sort_prev) + HUD_UpdatePlayerPos(o); // if not registered, we cannot do this yet! + + self.entremove = Ent_RemovePlayerScore; + } + + void Ent_ReadTeamScore() + { + int i; + entity o; + + self.team = ReadByte(); + o = self.owner = GetTeam(self.team, true); // these team numbers can always be trusted + + int sf, lf; + #if MAX_TEAMSCORE <= 8 + sf = ReadByte(); + lf = ReadByte(); + #else + sf = ReadShort(); + lf = ReadShort(); + #endif + int p; + for(i = 0, p = 1; i < MAX_TEAMSCORE; ++i, p *= 2) + if(sf & p) + { + if(lf & p) + o.(teamscores[i]) = ReadInt24_t(); + else + o.(teamscores[i]) = ReadChar(); + } + + HUD_UpdateTeamPos(o); + } + + void Ent_ClientData() + { + float newspectatee_status; + + int f = ReadByte(); + + scoreboard_showscores_force = (f & 1); + + if(f & 2) + { + newspectatee_status = ReadByte(); + if(newspectatee_status == player_localnum + 1) + newspectatee_status = -1; // observing + } + else + newspectatee_status = 0; + + spectatorbutton_zoom = (f & 4); + + if(f & 8) + { + angles_held_status = 1; + angles_held.x = ReadAngle(); + angles_held.y = ReadAngle(); + angles_held.z = 0; + } + else + angles_held_status = 0; + + if(newspectatee_status != spectatee_status) + { + // clear race stuff + race_laptime = 0; + race_checkpointtime = 0; + } + if (autocvar_hud_panel_healtharmor_progressbar_gfx) + { + if ( (spectatee_status == -1 && newspectatee_status > 0) //before observing, now spectating + || (spectatee_status > 0 && newspectatee_status > 0 && spectatee_status != newspectatee_status) //changed spectated player + ) + prev_p_health = -1; + else if(spectatee_status && !newspectatee_status) //before observing/spectating, now playing + prev_health = -1; + } + spectatee_status = newspectatee_status; + + // we could get rid of spectatee_status, and derive it from player_localentnum and player_localnum + } + + void Ent_Nagger() + { + int i, j, b, f; + + int nags = ReadByte(); // NAGS NAGS NAGS NAGS NAGS NAGS NADZ NAGS NAGS NAGS + + if(!(nags & 4)) + { + if(vote_called_vote) + strunzone(vote_called_vote); + vote_called_vote = string_null; + vote_active = 0; + } + else + { + vote_active = 1; + } + + if(nags & 64) + { + vote_yescount = ReadByte(); + vote_nocount = ReadByte(); + vote_needed = ReadByte(); + vote_highlighted = ReadChar(); + } + + if(nags & 128) + { + if(vote_called_vote) + strunzone(vote_called_vote); + vote_called_vote = strzone(ColorTranslateRGB(ReadString())); + } + + if(nags & 1) + { + for(j = 0; j < maxclients; ++j) + if(playerslots[j]) + playerslots[j].ready = 1; + for(i = 1; i <= maxclients; i += 8) + { + f = ReadByte(); + for(j = i-1, b = 1; b < 256; b *= 2, ++j) + if (!(f & b)) + if(playerslots[j]) + playerslots[j].ready = 0; + } + } + + ready_waiting = (nags & 1); + ready_waiting_for_me = (nags & 2); + vote_waiting = (nags & 4); + vote_waiting_for_me = (nags & 8); + warmup_stage = (nags & 16); + } + + void Ent_EliminatedPlayers() + { + int i, j, b, f; + + int sf = ReadByte(); + if(sf & 1) + { + for(j = 0; j < maxclients; ++j) + if(playerslots[j]) + playerslots[j].eliminated = 1; + for(i = 1; i <= maxclients; i += 8) + { + f = ReadByte(); + for(j = i-1, b = 1; b < 256; b *= 2, ++j) + if (!(f & b)) + if(playerslots[j]) + playerslots[j].eliminated = 0; + } + } + } + + void Ent_RandomSeed() + { + float s; + prandom_debug(); + s = ReadShort(); + psrandom(s); + } + + void Ent_ReadAccuracy(void) + { + int f, w; + int sf = ReadInt24_t(); + if(sf == 0) + { + for(w = 0; w <= WEP_LAST - WEP_FIRST; ++w) + weapon_accuracy[w] = -1; + return; + } + + for(w = 0, f = 1; w <= WEP_LAST - WEP_FIRST; ++w) + { + if(sf & f) + { + int b = ReadByte(); + if(b == 0) + weapon_accuracy[w] = -1; + else if(b == 255) + weapon_accuracy[w] = 1.0; // no better error handling yet, sorry + else + weapon_accuracy[w] = (b - 1.0) / 100.0; + } + if(f == 0x800000) + f = 1; + else + f *= 2; + } + } + + void Spawn_Draw(void) + { + pointparticles(self.cnt, self.origin + '0 0 28', '0 0 2', bound(0, frametime, 0.1)); + } + + void Ent_ReadSpawnPoint(float is_new) // entity for spawnpoint + { + float teamnum = (ReadByte() - 1); + vector spn_origin; + spn_origin.x = ReadShort(); + spn_origin.y = ReadShort(); + spn_origin.z = ReadShort(); + + if(is_new) + { + self.origin = spn_origin; + setsize(self, PL_MIN, PL_MAX); + droptofloor(); + + /*if(autocvar_cl_spawn_point_model) // needs a model first + { + self.mdl = "models/spawnpoint.md3"; + self.colormod = Team_ColorRGB(teamnum); + precache_model(self.mdl); + setmodel(self, self.mdl); + self.drawmask = MASK_NORMAL; + //self.movetype = MOVETYPE_NOCLIP; + //self.draw = Spawn_Draw; + }*/ + if(autocvar_cl_spawn_point_particles) + { + if((serverflags & SERVERFLAG_TEAMPLAY)) + { + switch(teamnum) + { + case NUM_TEAM_1: self.cnt = particleeffectnum("spawn_point_red"); break; + case NUM_TEAM_2: self.cnt = particleeffectnum("spawn_point_blue"); break; + case NUM_TEAM_3: self.cnt = particleeffectnum("spawn_point_yellow"); break; + case NUM_TEAM_4: self.cnt = particleeffectnum("spawn_point_pink"); break; + default: self.cnt = particleeffectnum("spawn_point_neutral"); break; + } + } + else { self.cnt = particleeffectnum("spawn_point_neutral"); } + + self.draw = Spawn_Draw; + } + } + + //printf("Ent_ReadSpawnPoint(is_new = %d); origin = %s, team = %d, effect = %d\n", is_new, vtos(self.origin), teamnum, self.cnt); + } + + void Ent_ReadSpawnEvent(float is_new) + { + // If entnum is 0, ONLY do the local spawn actions + // this way the server can disable the sending of + // spawn origin or such to clients if wanted. + float entnum = ReadByte(); + + if(entnum) + { + self.origin_x = ReadShort(); + self.origin_y = ReadShort(); + self.origin_z = ReadShort(); + + if(is_new) + { + float teamnum = GetPlayerColor(entnum - 1); + + if(autocvar_cl_spawn_event_particles) + { + switch(teamnum) + { + case NUM_TEAM_1: pointparticles(particleeffectnum("spawn_event_red"), self.origin, '0 0 0', 1); break; + case NUM_TEAM_2: pointparticles(particleeffectnum("spawn_event_blue"), self.origin, '0 0 0', 1); break; + case NUM_TEAM_3: pointparticles(particleeffectnum("spawn_event_yellow"), self.origin, '0 0 0', 1); break; + case NUM_TEAM_4: pointparticles(particleeffectnum("spawn_event_pink"), self.origin, '0 0 0', 1); break; + default: pointparticles(particleeffectnum("spawn_event_neutral"), self.origin, '0 0 0', 1); break; + } + } + if(autocvar_cl_spawn_event_sound) + { + sound(self, CH_TRIGGER, "misc/spawn.wav", VOL_BASE, ATTEN_NORM); + } + } + } + + // local spawn actions + if(is_new && (!entnum || (entnum == player_localentnum))) + { + zoomin_effect = 1; + current_viewzoom = (1 / bound(1, autocvar_cl_spawnzoom_factor, 16)); + + if(autocvar_cl_unpress_zoom_on_spawn) + { + localcmd("-zoom\n"); + button_zoom = false; + } + } + + //printf("Ent_ReadSpawnEvent(is_new = %d); origin = %s, entnum = %d, localentnum = %d\n", is_new, vtos(self.origin), entnum, player_localentnum); + } + + // CSQC_Ent_Update : Called every frame that the server has indicated an update to the SSQC / CSQC entity has occured. + // The only parameter reflects if the entity is "new" to the client, meaning it just came into the client's PVS. + void Ent_RadarLink(); + void Ent_Init(); + void Ent_ScoresInfo(); ++#ifdef CSQC ++void ent_func_ladder(); ++void ent_trigger_push(); ++void ent_target_push(); ++void ent_conveyor(); ++#endif + void CSQC_Ent_Update(float bIsNewEntity) + { + float t; + float savetime; + t = ReadByte(); + + if(autocvar_developer_csqcentities) + printf("CSQC_Ent_Update(%d) with self=%i self.entnum=%d self.enttype=%d t=%d\n", bIsNewEntity, self, self.entnum, self.enttype, t); + + // set up the "time" global for received entities to be correct for interpolation purposes + savetime = time; + if(servertime) + { + time = servertime; + } + else + { + serverprevtime = time; + serverdeltatime = getstatf(STAT_MOVEVARS_TICRATE) * getstatf(STAT_MOVEVARS_TIMESCALE); + time = serverprevtime + serverdeltatime; + } + + #ifdef DP_CSQC_ENTITY_REMOVE_IS_B0RKED + if(self.enttype) + { + if(t != self.enttype || bIsNewEntity) + { + //print("A CSQC entity changed its type!\n"); + printf("A CSQC entity changed its type! (edict: %d, server: %d, type: %d -> %d)\n", num_for_edict(self), self.entnum, self.enttype, t); + Ent_Remove(); + clearentity(self); + bIsNewEntity = 1; + } + } + else + { + if(!bIsNewEntity) + { + printf("A CSQC entity appeared out of nowhere! (edict: %d, server: %d, type: %d)\n", num_for_edict(self), self.entnum, t); + bIsNewEntity = 1; + } + } + #endif + self.enttype = t; + switch(t) + { + case ENT_CLIENT_ENTCS: Ent_ReadEntCS(); break; + case ENT_CLIENT_SCORES: Ent_ReadPlayerScore(); break; + case ENT_CLIENT_TEAMSCORES: Ent_ReadTeamScore(); break; + case ENT_CLIENT_POINTPARTICLES: Ent_PointParticles(); break; + case ENT_CLIENT_RAINSNOW: Ent_RainOrSnow(); break; + case ENT_CLIENT_LASER: Ent_Laser(); break; + case ENT_CLIENT_NAGGER: Ent_Nagger(); break; + case ENT_CLIENT_ELIMINATEDPLAYERS: Ent_EliminatedPlayers(); break; + case ENT_CLIENT_WAYPOINT: Ent_WaypointSprite(); break; + case ENT_CLIENT_RADARLINK: Ent_RadarLink(); break; + case ENT_CLIENT_PROJECTILE: Ent_Projectile(); break; + case ENT_CLIENT_GIBSPLASH: Ent_GibSplash(bIsNewEntity); break; + case ENT_CLIENT_DAMAGEINFO: Ent_DamageInfo(bIsNewEntity); break; + case ENT_CLIENT_CASING: Ent_Casing(bIsNewEntity); break; + case ENT_CLIENT_INIT: Ent_Init(); break; + case ENT_CLIENT_SCORES_INFO: Ent_ScoresInfo(); break; + case ENT_CLIENT_MAPVOTE: Ent_MapVote(); break; + case ENT_CLIENT_CLIENTDATA: Ent_ClientData(); break; + case ENT_CLIENT_RANDOMSEED: Ent_RandomSeed(); break; + case ENT_CLIENT_WALL: Ent_Wall(); break; + case ENT_CLIENT_MODELEFFECT: Ent_ModelEffect(bIsNewEntity); break; + case ENT_CLIENT_TUBANOTE: Ent_TubaNote(bIsNewEntity); break; + case ENT_CLIENT_WARPZONE: WarpZone_Read(bIsNewEntity); break; + case ENT_CLIENT_WARPZONE_CAMERA: WarpZone_Camera_Read(bIsNewEntity); break; + case ENT_CLIENT_WARPZONE_TELEPORTED: WarpZone_Teleported_Read(bIsNewEntity); break; + case ENT_CLIENT_TRIGGER_MUSIC: Ent_ReadTriggerMusic(); break; + case ENT_CLIENT_HOOK: Ent_ReadHook(bIsNewEntity, ENT_CLIENT_HOOK); break; + case ENT_CLIENT_ARC_BEAM: Ent_ReadArcBeam(bIsNewEntity); break; + case ENT_CLIENT_ACCURACY: Ent_ReadAccuracy(); break; + case ENT_CLIENT_AUXILIARYXHAIR: Net_AuXair2(bIsNewEntity); break; + case ENT_CLIENT_TURRET: ent_turret(); break; + case ENT_CLIENT_MODEL: CSQCModel_Read(bIsNewEntity); break; + case ENT_CLIENT_ITEM: ItemRead(bIsNewEntity); break; + case ENT_CLIENT_BUMBLE_RAYGUN: bumble_raygun_read(bIsNewEntity); break; + case ENT_CLIENT_SPAWNPOINT: Ent_ReadSpawnPoint(bIsNewEntity); break; + case ENT_CLIENT_SPAWNEVENT: Ent_ReadSpawnEvent(bIsNewEntity); break; + case ENT_CLIENT_NOTIFICATION: Read_Notification(bIsNewEntity); break; + case ENT_CLIENT_HEALING_ORB: ent_healer(); break; ++ case ENT_CLIENT_LADDER: ent_func_ladder(); break; ++ case ENT_CLIENT_TRIGGER_PUSH: ent_trigger_push(); break; ++ case ENT_CLIENT_TARGET_PUSH: ent_target_push(); break; ++ case ENT_CLIENT_CONVEYOR: ent_conveyor(); break; + + default: + //error(strcat(_("unknown entity type in CSQC_Ent_Update: %d\n"), self.enttype)); + error(sprintf("Unknown entity type in CSQC_Ent_Update (enttype: %d, edict: %d, classname: %s)\n", self.enttype, num_for_edict(self), self.classname)); + break; + } + + time = savetime; + } + // Destructor, but does NOT deallocate the entity by calling remove(). Also + // used when an entity changes its type. For an entity that someone interacts + // with others, make sure it can no longer do so. + void Ent_Remove() + { + if(self.entremove) + self.entremove(); + + if(self.skeletonindex) + { + skel_delete(self.skeletonindex); + self.skeletonindex = 0; + } + + if(self.snd_looping > 0) + { + sound(self, self.snd_looping, "misc/null.wav", VOL_BASE, autocvar_g_jetpack_attenuation); + self.snd_looping = 0; + } + + self.enttype = 0; + self.classname = ""; + self.draw = menu_sub_null; + self.entremove = menu_sub_null; + // TODO possibly set more stuff to defaults + } + // CSQC_Ent_Remove : Called when the server requests a SSQC / CSQC entity to be removed. Essentially call remove(self) as well. + void CSQC_Ent_Remove() + { + if(autocvar_developer_csqcentities) + printf("CSQC_Ent_Remove() with self=%i self.entnum=%d self.enttype=%d\n", self, self.entnum, self.enttype); + + if(wasfreed(self)) + { + print("WARNING: CSQC_Ent_Remove called for already removed entity. Packet loss?\n"); + return; + } + if(self.enttype) + Ent_Remove(); + remove(self); + } + + void Gamemode_Init() + { + if (!isdemo()) + { + if(!(calledhooks & HOOK_START)) + localcmd("\n_cl_hook_gamestart ", MapInfo_Type_ToString(gametype), "\n"); + calledhooks |= HOOK_START; + } + } + // CSQC_Parse_StuffCmd : Provides the stuffcmd string in the first parameter that the server provided. To execute standard behavior, simply execute localcmd with the string. + void CSQC_Parse_StuffCmd(string strMessage) + { + if(autocvar_developer_csqcentities) + printf("CSQC_Parse_StuffCmd(\"%s\")\n", strMessage); + + localcmd(strMessage); + } + // CSQC_Parse_Print : Provides the print string in the first parameter that the server provided. To execute standard behavior, simply execute print with the string. + void CSQC_Parse_Print(string strMessage) + { + if(autocvar_developer_csqcentities) + printf("CSQC_Parse_Print(\"%s\")\n", strMessage); + + print(ColorTranslateRGB(strMessage)); + } + + // CSQC_Parse_CenterPrint : Provides the centerprint_hud string in the first parameter that the server provided. + void CSQC_Parse_CenterPrint(string strMessage) + { + if(autocvar_developer_csqcentities) + printf("CSQC_Parse_CenterPrint(\"%s\")\n", strMessage); + + centerprint_hud(strMessage); + } + + string notranslate_fogcmd1 = "\nfog "; + string notranslate_fogcmd2 = "\nr_fog_exp2 0\nr_drawfog 1\n"; + void Fog_Force() + { + // TODO somehow thwart prvm_globalset client ... + + if(autocvar_cl_orthoview && autocvar_cl_orthoview_nofog) + { localcmd("\nr_drawfog 0\n"); } + else if(forcefog != "") + { localcmd(strcat(notranslate_fogcmd1, forcefog, notranslate_fogcmd2)); } + } + + void Gamemode_Init(); + void Ent_ScoresInfo() + { + int i; + self.classname = "ent_client_scores_info"; + gametype = ReadInt24_t(); + HUD_ModIcons_SetFunc(); + for(i = 0; i < MAX_SCORE; ++i) + { + if(scores_label[i]) + strunzone(scores_label[i]); + scores_label[i] = strzone(ReadString()); + scores_flags[i] = ReadByte(); + } + for(i = 0; i < MAX_TEAMSCORE; ++i) + { + if(teamscores_label[i]) + strunzone(teamscores_label[i]); + teamscores_label[i] = strzone(ReadString()); + teamscores_flags[i] = ReadByte(); + } + HUD_InitScores(); + Gamemode_Init(); + } + + void Ent_Init() + { + self.classname = "ent_client_init"; + + nb_pb_period = ReadByte() / 32; //Accuracy of 1/32th + + hook_shotorigin[0] = decompressShotOrigin(ReadInt24_t()); + hook_shotorigin[1] = decompressShotOrigin(ReadInt24_t()); + hook_shotorigin[2] = decompressShotOrigin(ReadInt24_t()); + hook_shotorigin[3] = decompressShotOrigin(ReadInt24_t()); + arc_shotorigin[0] = decompressShotOrigin(ReadInt24_t()); + arc_shotorigin[1] = decompressShotOrigin(ReadInt24_t()); + arc_shotorigin[2] = decompressShotOrigin(ReadInt24_t()); + arc_shotorigin[3] = decompressShotOrigin(ReadInt24_t()); + + if(forcefog) + strunzone(forcefog); + forcefog = strzone(ReadString()); + + armorblockpercent = ReadByte() / 255.0; + + g_balance_mortar_bouncefactor = ReadCoord(); + g_balance_mortar_bouncestop = ReadCoord(); + g_balance_electro_secondary_bouncefactor = ReadCoord(); + g_balance_electro_secondary_bouncestop = ReadCoord(); + + vortex_scope = !ReadByte(); + rifle_scope = !ReadByte(); + + serverflags = ReadByte(); + + minelayer_maxmines = ReadByte(); + + hagar_maxrockets = ReadByte(); + + g_trueaim_minrange = ReadCoord(); + g_balance_porto_secondary = ReadByte(); + + if(!postinit) + PostInit(); + } + + void Net_ReadRace() + { + float b; + + b = ReadByte(); + + switch(b) + { + case RACE_NET_CHECKPOINT_HIT_QUALIFYING: + race_checkpoint = ReadByte(); + race_time = ReadInt24_t(); + race_previousbesttime = ReadInt24_t(); + if(race_previousbestname) + strunzone(race_previousbestname); + race_previousbestname = strzone(ColorTranslateRGB(ReadString())); + + race_checkpointtime = time; + + if(race_checkpoint == 0 || race_checkpoint == 254) + { + race_penaltyaccumulator = 0; + race_laptime = time; // valid + } + + break; + + case RACE_NET_CHECKPOINT_CLEAR: + race_laptime = 0; + race_checkpointtime = 0; + break; + + case RACE_NET_CHECKPOINT_NEXT_SPEC_QUALIFYING: + race_laptime = ReadCoord(); + race_checkpointtime = -99999; + // fall through + case RACE_NET_CHECKPOINT_NEXT_QUALIFYING: + race_nextcheckpoint = ReadByte(); + + race_nextbesttime = ReadInt24_t(); + if(race_nextbestname) + strunzone(race_nextbestname); + race_nextbestname = strzone(ColorTranslateRGB(ReadString())); + break; + + case RACE_NET_CHECKPOINT_HIT_RACE: + race_mycheckpoint = ReadByte(); + race_mycheckpointtime = time; + race_mycheckpointdelta = ReadInt24_t(); + race_mycheckpointlapsdelta = ReadByte(); + if(race_mycheckpointlapsdelta >= 128) + race_mycheckpointlapsdelta -= 256; + if(race_mycheckpointenemy) + strunzone(race_mycheckpointenemy); + race_mycheckpointenemy = strzone(ColorTranslateRGB(ReadString())); + break; + + case RACE_NET_CHECKPOINT_HIT_RACE_BY_OPPONENT: + race_othercheckpoint = ReadByte(); + race_othercheckpointtime = time; + race_othercheckpointdelta = ReadInt24_t(); + race_othercheckpointlapsdelta = ReadByte(); + if(race_othercheckpointlapsdelta >= 128) + race_othercheckpointlapsdelta -= 256; + if(race_othercheckpointenemy) + strunzone(race_othercheckpointenemy); + race_othercheckpointenemy = strzone(ColorTranslateRGB(ReadString())); + break; + + case RACE_NET_PENALTY_RACE: + race_penaltyeventtime = time; + race_penaltytime = ReadShort(); + //race_penaltyaccumulator += race_penaltytime; + if(race_penaltyreason) + strunzone(race_penaltyreason); + race_penaltyreason = strzone(ReadString()); + break; + + case RACE_NET_PENALTY_QUALIFYING: + race_penaltyeventtime = time; + race_penaltytime = ReadShort(); + race_penaltyaccumulator += race_penaltytime; + if(race_penaltyreason) + strunzone(race_penaltyreason); + race_penaltyreason = strzone(ReadString()); + break; + + case RACE_NET_SERVER_RECORD: + race_server_record = ReadInt24_t(); + break; + case RACE_NET_SPEED_AWARD: + race_speedaward = ReadInt24_t(); + if(race_speedaward_holder) + strunzone(race_speedaward_holder); + race_speedaward_holder = strzone(ReadString()); + break; + case RACE_NET_SPEED_AWARD_BEST: + race_speedaward_alltimebest = ReadInt24_t(); + if(race_speedaward_alltimebest_holder) + strunzone(race_speedaward_alltimebest_holder); + race_speedaward_alltimebest_holder = strzone(ReadString()); + break; + case RACE_NET_SERVER_RANKINGS: + float prevpos, del; + int pos = ReadShort(); + prevpos = ReadShort(); + del = ReadShort(); + + // move other rankings out of the way + int i; + if (prevpos) { + for (i=prevpos-1;i>pos-1;--i) { + grecordtime[i] = grecordtime[i-1]; + if(grecordholder[i]) + strunzone(grecordholder[i]); + grecordholder[i] = strzone(grecordholder[i-1]); + } + } else if (del) { // a record has been deleted by the admin + for (i=pos-1; i<= RANKINGS_CNT-1; ++i) { + if (i == RANKINGS_CNT-1) { // clear out last record + grecordtime[i] = 0; + if (grecordholder[i]) + strunzone(grecordholder[i]); + grecordholder[i] = string_null; + } + else { + grecordtime[i] = grecordtime[i+1]; + if (grecordholder[i]) + strunzone(grecordholder[i]); + grecordholder[i] = strzone(grecordholder[i+1]); + } + } + } else { // player has no ranked record yet + for (i=RANKINGS_CNT-1;i>pos-1;--i) { + grecordtime[i] = grecordtime[i-1]; + if(grecordholder[i]) + strunzone(grecordholder[i]); + grecordholder[i] = strzone(grecordholder[i-1]); + } + } + + // store new ranking + if(grecordholder[pos-1] != "") + strunzone(grecordholder[pos-1]); + grecordholder[pos-1] = strzone(ReadString()); + grecordtime[pos-1] = ReadInt24_t(); + if(grecordholder[pos-1] == GetPlayerName(player_localnum)) + race_myrank = pos; + break; + case RACE_NET_SERVER_STATUS: + race_status = ReadShort(); + if(race_status_name) + strunzone(race_status_name); + race_status_name = strzone(ReadString()); + } + } + + void Net_TeamNagger() + { + teamnagger = 1; + } + + void Net_ReadPingPLReport() + { + int e, pi, pl, ml; + e = ReadByte(); + pi = ReadShort(); + pl = ReadByte(); + ml = ReadByte(); + if (!(playerslots[e])) + return; + playerslots[e].ping = pi; + playerslots[e].ping_packetloss = pl / 255.0; + playerslots[e].ping_movementloss = ml / 255.0; + } + + void Net_WeaponComplain() + { + complain_weapon = ReadByte(); + + if(complain_weapon_name) + strunzone(complain_weapon_name); + complain_weapon_name = strzone(WEP_NAME(complain_weapon)); + + complain_weapon_type = ReadByte(); + + complain_weapon_time = time; + weapontime = time; // ping the weapon panel + + switch(complain_weapon_type) + { + case 0: Local_Notification(MSG_MULTI, ITEM_WEAPON_NOAMMO, complain_weapon); break; + case 1: Local_Notification(MSG_MULTI, ITEM_WEAPON_DONTHAVE, complain_weapon); break; + default: Local_Notification(MSG_MULTI, ITEM_WEAPON_UNAVAILABLE, complain_weapon); break; + } + } + + // CSQC_Parse_TempEntity : Handles all temporary entity network data in the CSQC layer. + // You must ALWAYS first acquire the temporary ID, which is sent as a byte. + // Return value should be 1 if CSQC handled the temporary entity, otherwise return 0 to have the engine process the event. + float CSQC_Parse_TempEntity() + { + float bHandled; + bHandled = true; + // Acquire TE ID + float nTEID; + nTEID = ReadByte(); + + if(autocvar_developer_csqcentities) + printf("CSQC_Parse_TempEntity() with nTEID=%d\n", nTEID); + + // NOTE: Could just do return instead of break... + switch(nTEID) + { + case TE_CSQC_TARGET_MUSIC: + Net_TargetMusic(); + bHandled = true; + break; + case TE_CSQC_PICTURE: + Net_MapVote_Picture(); + bHandled = true; + break; + case TE_CSQC_RACE: + Net_ReadRace(); + bHandled = true; + break; + case TE_CSQC_VORTEXBEAMPARTICLE: + Net_ReadVortexBeamParticle(); + bHandled = true; + break; + case TE_CSQC_TEAMNAGGER: + Net_TeamNagger(); + bHandled = true; + break; + case TE_CSQC_ARC: + Net_ReadArc(); + bHandled = true; + break; + case TE_CSQC_PINGPLREPORT: + Net_ReadPingPLReport(); + bHandled = true; + break; + case TE_CSQC_WEAPONCOMPLAIN: + Net_WeaponComplain(); + bHandled = true; + break; + case TE_CSQC_VEHICLESETUP: + Net_VehicleSetup(); + bHandled = true; + break; + case TE_CSQC_SVNOTICE: + cl_notice_read(); + bHandled = true; + break; + case TE_CSQC_SHOCKWAVEPARTICLE: + Net_ReadShockwaveParticle(); + bHandled = true; + break; + default: + // No special logic for this temporary entity; return 0 so the engine can handle it + bHandled = false; + break; + } + + return bHandled; + } + + string getcommandkey(string text, string command) + { + string keys; + float n, j, k, l = 0; + + if (!autocvar_hud_showbinds) + return text; + + keys = db_get(binddb, command); + if (keys == "") + { + n = tokenize(findkeysforcommand(command, 0)); // uses '...' strings + for(j = 0; j < n; ++j) + { + k = stof(argv(j)); + if(k != -1) + { + if ("" == keys) + keys = keynumtostring(k); + else + keys = strcat(keys, ", ", keynumtostring(k)); + + ++l; + if (autocvar_hud_showbinds_limit > 0 && autocvar_hud_showbinds_limit <= l) + break; + } + + } + if (keys == "") + keys = "NO_KEY"; + db_put(binddb, command, keys); + } + + if (keys == "NO_KEY") { + if (autocvar_hud_showbinds > 1) + return sprintf(_("%s (not bound)"), text); + else + return text; + } + else if (autocvar_hud_showbinds > 1) + return sprintf("%s (%s)", text, keys); + else + return keys; + } diff --cc qcsrc/client/movetypes.qc index 838404622,2f62ae6dc..92fb64ab7 --- a/qcsrc/client/movetypes.qc +++ b/qcsrc/client/movetypes.qc @@@ -1,3 -1,17 +1,16 @@@ + #if defined(CSQC) + #include "../dpdefs/csprogsdefs.qh" + #include "defs.qh" + #include "../common/stats.qh" + #include "../common/util.qh" + #include "movetypes.qh" + #include "../csqcmodellib/common.qh" + #include "../server/t_items.qh" + #elif defined(MENUQC) + #elif defined(SVQC) + #endif + + -const int MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE = 4; #define GRAVITY_UNAFFECTED_BY_TICRATE (getstati(STAT_MOVEFLAGS) & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE) .entity move_groundentity; // FIXME add move_groundnetworkentity? diff --cc qcsrc/client/movetypes.qh index 9908698c1,3294ce427..f20977146 --- a/qcsrc/client/movetypes.qh +++ b/qcsrc/client/movetypes.qh @@@ -14,32 -17,28 +17,33 @@@ .float move_nomonsters; // -1 for MOVE_NORMAL, otherwise a MOVE_ constant // should match sv_gameplayfix_fixedcheckwatertransition - var float autocvar_cl_gameplayfix_fixedcheckwatertransition = 1; + float autocvar_cl_gameplayfix_fixedcheckwatertransition = 1; - void Movetype_Physics_MatchTicrate(float tr, float sloppy); - void Movetype_Physics_MatchServer(float sloppy); + void Movetype_Physics_MatchTicrate(float tr, bool sloppy); + void Movetype_Physics_MatchServer(bool sloppy); void Movetype_Physics_NoMatchServer(); - const float MOVETYPE_NONE = 0; - const float MOVETYPE_ANGLENOCLIP = 1; - const float MOVETYPE_ANGLECLIP = 2; - const float MOVETYPE_WALK = 3; - const float MOVETYPE_STEP = 4; - const float MOVETYPE_FLY = 5; - const float MOVETYPE_TOSS = 6; - const float MOVETYPE_PUSH = 7; - const float MOVETYPE_NOCLIP = 8; - const float MOVETYPE_FLYMISSILE = 9; - const float MOVETYPE_BOUNCE = 10; - const float MOVETYPE_BOUNCEMISSILE = 11; // Like bounce but doesn't lose speed on bouncing - const float MOVETYPE_FOLLOW = 12; - const float MOVETYPE_FAKEPUSH = 13; - const float MOVETYPE_FLY_WORLDONLY = 33; + const int MOVETYPE_NONE = 0; + const int MOVETYPE_ANGLENOCLIP = 1; + const int MOVETYPE_ANGLECLIP = 2; + const int MOVETYPE_WALK = 3; + const int MOVETYPE_STEP = 4; + const int MOVETYPE_FLY = 5; + const int MOVETYPE_TOSS = 6; + const int MOVETYPE_PUSH = 7; + const int MOVETYPE_NOCLIP = 8; + const int MOVETYPE_FLYMISSILE = 9; + const int MOVETYPE_BOUNCE = 10; + const int MOVETYPE_BOUNCEMISSILE = 11; // Like bounce but doesn't lose speed on bouncing + const int MOVETYPE_FOLLOW = 12; + const int MOVETYPE_FAKEPUSH = 13; + const int MOVETYPE_FLY_WORLDONLY = 33; - const float FL_ITEM = 256; - const float FL_ONGROUND = 512; + const int FL_ITEM = 256; + const int FL_ONGROUND = 512; + +const float MOVEFLAG_Q2AIRACCELERATE = 1; +const float MOVEFLAG_NOGRAVITYONGROUND = 2; +const float MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE = 4; - #define moveflags (getstati(STAT_MOVEFLAGS)) ++#define moveflags (getstati(STAT_MOVEFLAGS)) + #endif diff --cc qcsrc/client/progs.src index e414576c3,505a5cf9b..640a6d6e9 --- a/qcsrc/client/progs.src +++ b/qcsrc/client/progs.src @@@ -2,140 -2,74 +2,81 @@@ ../common/util-pre.qh sys-pre.qh - ../dpdefs/csprogsdefs.qc + ../dpdefs/csprogsdefs.qh sys-post.qh - Defs.qc - ../dpdefs/keycodes.qc - ../common/constants.qh - ../common/stats.qh - - ../warpzonelib/anglestransform.qh - ../warpzonelib/mathlib.qh - ../warpzonelib/common.qh - ../warpzonelib/client.qh - - ../common/playerstats.qh - ../common/teams.qh - ../common/util.qh - ../common/nades.qh - ../common/buffs.qh - ../common/test.qh - ../common/counting.qh - ../common/weapons/weapons.qh // TODO - ../common/mapinfo.qh - ../common/command/markup.qh - ../common/command/rpn.qh - ../common/command/generic.qh - ../common/command/shared_defs.qh - ../common/urllib.qh - ../common/animdecide.qh - command/cl_cmd.qh - - ../common/monsters/monsters.qh - - autocvars.qh - - ../common/notifications.qh // must be after autocvars - ../common/deathtypes.qh // must be after notifications - - damage.qh - - ../csqcmodellib/interpolate.qh - teamradar.qh - hud.qh - scoreboard.qh - waypointsprites.qh - movetypes.qh - prandom.qh - bgmscript.qh - noise.qh - tturrets.qh - ../server/tturrets/include/turrets_early.qh - ../server/movelib.qc - main.qh - vehicles/vehicles.qh - ../common/csqcmodel_settings.qh - ../csqcmodellib/common.qh - ../csqcmodellib/cl_model.qh - ../csqcmodellib/cl_player.qh - weapons/projectile.qh // TODO - player_skeleton.qh - - sortlist.qc - miscfunctions.qc - ../server/t_items.qh - ../server/t_items.qc - - teamradar.qc - hud_config.qc - hud.qc - scoreboard.qc - mapvoting.qc + announcer.qc + bgmscript.qc + casings.qc csqcmodel_hooks.qc - ../common/net_notice.qc - - rubble.qc - hook.qc - particles.qc - laser.qc - weapons/projectile.qc // TODO - gibs.qc damage.qc - casings.qc - ../csqcmodellib/cl_model.qc - ../csqcmodellib/cl_player.qc effects.qc - wall.qc + gibs.qc + hook.qc + hud_config.qc + hud.qc + laser.qc + main.qc + mapvoting.qc + miscfunctions.qc modeleffects.qc - tuba.qc + movetypes.qc + noise.qc + particles.qc + player_skeleton.qc + prandom.qc + rubble.qc + scoreboard.qc + shownames.qc + sortlist.qc target_music.qc - + teamradar.qc + tturrets.qc + tuba.qc vehicles/vehicles.qc - ../server/vehicles/bumblebee.qc - shownames.qh - shownames.qc - - announcer.qc - Main.qc - View.qc - ../csqcmodellib/interpolate.qc + view.qc + wall.qc waypointsprites.qc - movetypes.qc - prandom.qc - bgmscript.qc - noise.qc + command/cl_cmd.qc + + weapons/projectile.qc // TODO + + ../common/animdecide.qc + ../common/buffs.qc + ../common/mapinfo.qc + ../common/nades.qc + ../common/net_notice.qc + ../common/notifications.qc ++../common/physics.qc + ../common/playerstats.qc ../common/test.qc + ../common/urllib.qc ../common/util.qc - ../common/playerstats.qc - ../common/notifications.qc + + ../common/command/generic.qc ../common/command/markup.qc ../common/command/rpn.qc - ../common/command/generic.qc - ../common/mapinfo.qc - ../common/weapons/weapons.qc // TODO - ../common/urllib.qc - command/cl_cmd.qc ../common/monsters/monsters.qc - ../common/physics.qh - ../server/mutators/mutator_dodging.qc - ../server/mutators/mutator_multijump.qc + ../common/weapons/weapons.qc // TODO + + ../csqcmodellib/cl_model.qc + ../csqcmodellib/cl_player.qc + ../csqcmodellib/interpolate.qc + + ../server/movelib.qc +../server/t_halflife.qc + ../server/t_items.qc +../server/t_jumppads.qc +../server/t_plats.qc + - ../common/nades.qc - ../common/buffs.qc - ../common/physics.qc ++../server/mutators/mutator_multijump.qc ++ + ../server/vehicles/bumblebee.qc ../warpzonelib/anglestransform.qc - ../warpzonelib/mathlib.qc - ../warpzonelib/common.qc ../warpzonelib/client.qc - tturrets.qc - - player_skeleton.qc - ../common/animdecide.qc + ../warpzonelib/common.qc + ../warpzonelib/mathlib.qc diff --cc qcsrc/common/constants.qh index 28cf97f5d,45a65abbe..37f80863a --- a/qcsrc/common/constants.qh +++ b/qcsrc/common/constants.qh @@@ -1,128 -1,102 +1,131 @@@ + #ifndef CONSTANTS_H + #define CONSTANTS_H + +// COMMIT-TODO: Update if necessary before committing +// Revision 1: additional statistics sent (flag caps, returns, deaths) +// Revision 2: Mapvote preview pictures +// Revision 3: optimized map vote protocol +// Revision 4: CSQC config var system +// Revision 5: mapvote time fix +// Revision 6: more robust against packet loss/delays, also show not yet connected clients +// Revision 7: packet loss column +// Revision 8: race +// Revision 9: race delta +// Revision 10: scoreboard force +// Revision 11: scoreboard unforce; spectator support beginning +// Revision 12: smaller scores updates (SERVER: requires new engine) +// Revision 13: pointparticles +// Revision 14: laser +// Revision 15: zoom +// Revision 16: multi-weapons +// Revision 17: multi-weaponimpulses +// Revision 18: warmup +// Revision 19: fog +// Revision 20: naggers +// Revision 21: entcs for players optimized (position data down from 12 to 7 bytes); waypointsprites in csqc for team radar +// Revision 22: hook shot origin +#define CSQC_REVISION 22 + - const float AS_STRING = 1; - const float AS_INT = 2; - const float AS_FLOAT_TRUNCATED = 2; - const float AS_FLOAT = 8; - - const float TE_CSQC_PICTURE = 100; - const float TE_CSQC_RACE = 101; - const float TE_CSQC_VORTEXBEAMPARTICLE = 103; - const float TE_CSQC_ARC = 104; - const float TE_CSQC_TEAMNAGGER = 105; - const float TE_CSQC_PINGPLREPORT = 106; - const float TE_CSQC_TARGET_MUSIC = 107; - const float TE_CSQC_WEAPONCOMPLAIN = 108; - const float TE_CSQC_VORTEX_SCOPE = 109; - const float TE_CSQC_MINELAYER_MAXMINES = 110; - const float TE_CSQC_HAGAR_MAXROCKETS = 111; - const float TE_CSQC_VEHICLESETUP = 112; - const float TE_CSQC_SVNOTICE = 113; - const float TE_CSQC_SHOCKWAVEPARTICLE = 114; - - const float RACE_NET_CHECKPOINT_HIT_QUALIFYING = 0; // byte checkpoint, short time, short recordtime, string recordholder - const float RACE_NET_CHECKPOINT_CLEAR = 1; - const float RACE_NET_CHECKPOINT_NEXT_QUALIFYING = 2; // byte nextcheckpoint, short recordtime, string recordholder - const float RACE_NET_CHECKPOINT_HIT_RACE = 3; // byte checkpoint, short delta, byte lapsdelta, string opponent - const float RACE_NET_CHECKPOINT_HIT_RACE_BY_OPPONENT = 4; // byte checkpoint, short delta, byte lapsdelta, string opponent - const float RACE_NET_CHECKPOINT_NEXT_SPEC_QUALIFYING = 5; // byte nextcheckpoint, float laptime, short recordtime, string recordholder - const float RACE_NET_PENALTY_RACE = 6; // byte penaltytime, string reason - const float RACE_NET_PENALTY_QUALIFYING = 7; // byte penaltytime, string reason - const float RACE_NET_SERVER_RECORD = 8; // server record, sent to client - const float RACE_NET_SPEED_AWARD = 9; // speed award, sent to client - const float RACE_NET_SPEED_AWARD_BEST = 10; // all time best speed award, sent to client - const float RACE_NET_SERVER_RANKINGS = 11; - const float RACE_NET_SERVER_STATUS = 12; - const float RANKINGS_CNT = 15; - - const float ENT_CLIENT = 0; - const float ENT_CLIENT_DEAD = 1; - const float ENT_CLIENT_ENTCS = 2; - const float ENT_CLIENT_SCORES_INFO = 3; - const float ENT_CLIENT_SCORES = 4; - const float ENT_CLIENT_TEAMSCORES = 5; - const float ENT_CLIENT_POINTPARTICLES = 6; - const float ENT_CLIENT_RAINSNOW = 7; - const float ENT_CLIENT_LASER = 8; - const float ENT_CLIENT_NAGGER = 9; // flags [votecalledvote] - const float ENT_CLIENT_WAYPOINT = 10; // flags origin [team displayrule] [spritename] [spritename2] [spritename3] [lifetime maxdistance hideable] - const float ENT_CLIENT_RADARLINK = 11; // flags [startorigin] [endorigin] [startcolor+16*endcolor] - const float ENT_CLIENT_PROJECTILE = 12; - const float ENT_CLIENT_GIBSPLASH = 13; - const float ENT_CLIENT_DAMAGEINFO = 14; - const float ENT_CLIENT_CASING = 15; - const float ENT_CLIENT_INIT = 16; - const float ENT_CLIENT_MAPVOTE = 17; - const float ENT_CLIENT_CLIENTDATA = 18; - const float ENT_CLIENT_RANDOMSEED = 19; - const float ENT_CLIENT_WALL = 20; - const float ENT_CLIENT_SPIDERBOT = 21; - const float ENT_CLIENT_MODELEFFECT = 22; - const float ENT_CLIENT_TUBANOTE = 23; - const float ENT_CLIENT_WARPZONE = 24; - const float ENT_CLIENT_WARPZONE_CAMERA = 25; - const float ENT_CLIENT_TRIGGER_MUSIC = 26; - const float ENT_CLIENT_HOOK = 27; - const float ENT_CLIENT_ARC_BEAM = 29; // WEAPONTODO: fix numbers - const float ENT_CLIENT_ACCURACY = 30; - const float ENT_CLIENT_SHOWNAMES = 31; - const float ENT_CLIENT_WARPZONE_TELEPORTED = 32; - const float ENT_CLIENT_MODEL = 33; - const float ENT_CLIENT_ITEM = 34; - const float ENT_CLIENT_BUMBLE_RAYGUN = 35; - const float ENT_CLIENT_SPAWNPOINT = 36; - const float ENT_CLIENT_SPAWNEVENT = 37; - const float ENT_CLIENT_NOTIFICATION = 38; - const float ENT_CLIENT_ELIMINATEDPLAYERS = 39; - const float ENT_CLIENT_TURRET = 40; - const float ENT_CLIENT_AUXILIARYXHAIR = 50; - const float ENT_CLIENT_VEHICLE = 60; - const float ENT_CLIENT_LADDER = 61; - const float ENT_CLIENT_TRIGGER_PUSH = 62; - const float ENT_CLIENT_TARGET_PUSH = 63; - const float ENT_CLIENT_CONVEYOR = 64; - - const float ENT_CLIENT_HEALING_ORB = 80; - - const float SPRITERULE_DEFAULT = 0; - const float SPRITERULE_TEAMPLAY = 1; - - const float RADARICON_NONE = 0; - const float RADARICON_FLAG = 1; - const float RADARICON_FLAGCARRIER = 1; - const float RADARICON_HERE = 1; // TODO make these 3 and 4, and make images for them - const float RADARICON_DANGER = 1; - const float RADARICON_WAYPOINT = 1; - const float RADARICON_HELPME = 1; - const float RADARICON_CONTROLPOINT = 1; - const float RADARICON_GENERATOR = 1; - const float RADARICON_OBJECTIVE = 1; - const float RADARICON_DOMPOINT = 1; - const float RADARICON_POWERUP = 1; - const float RADARICON_TAGGED = 1; + const int AS_STRING = 1; + const int AS_INT = 2; + const int AS_FLOAT_TRUNCATED = 2; + const int AS_FLOAT = 8; + + const int TE_CSQC_PICTURE = 100; + const int TE_CSQC_RACE = 101; + const int TE_CSQC_VORTEXBEAMPARTICLE = 103; + const int TE_CSQC_ARC = 104; + const int TE_CSQC_TEAMNAGGER = 105; + const int TE_CSQC_PINGPLREPORT = 106; + const int TE_CSQC_TARGET_MUSIC = 107; + const int TE_CSQC_WEAPONCOMPLAIN = 108; + const int TE_CSQC_VORTEX_SCOPE = 109; + const int TE_CSQC_MINELAYER_MAXMINES = 110; + const int TE_CSQC_HAGAR_MAXROCKETS = 111; + const int TE_CSQC_VEHICLESETUP = 112; + const int TE_CSQC_SVNOTICE = 113; + const int TE_CSQC_SHOCKWAVEPARTICLE = 114; + + const int RACE_NET_CHECKPOINT_HIT_QUALIFYING = 0; // byte checkpoint, short time, short recordtime, string recordholder + const int RACE_NET_CHECKPOINT_CLEAR = 1; + const int RACE_NET_CHECKPOINT_NEXT_QUALIFYING = 2; // byte nextcheckpoint, short recordtime, string recordholder + const int RACE_NET_CHECKPOINT_HIT_RACE = 3; // byte checkpoint, short delta, byte lapsdelta, string opponent + const int RACE_NET_CHECKPOINT_HIT_RACE_BY_OPPONENT = 4; // byte checkpoint, short delta, byte lapsdelta, string opponent + const int RACE_NET_CHECKPOINT_NEXT_SPEC_QUALIFYING = 5; // byte nextcheckpoint, float laptime, short recordtime, string recordholder + const int RACE_NET_PENALTY_RACE = 6; // byte penaltytime, string reason + const int RACE_NET_PENALTY_QUALIFYING = 7; // byte penaltytime, string reason + const int RACE_NET_SERVER_RECORD = 8; // server record, sent to client + const int RACE_NET_SPEED_AWARD = 9; // speed award, sent to client + const int RACE_NET_SPEED_AWARD_BEST = 10; // all time best speed award, sent to client + const int RACE_NET_SERVER_RANKINGS = 11; + const int RACE_NET_SERVER_STATUS = 12; + const int RANKINGS_CNT = 15; + + const int ENT_CLIENT = 0; + const int ENT_CLIENT_DEAD = 1; + const int ENT_CLIENT_ENTCS = 2; + const int ENT_CLIENT_SCORES_INFO = 3; + const int ENT_CLIENT_SCORES = 4; + const int ENT_CLIENT_TEAMSCORES = 5; + const int ENT_CLIENT_POINTPARTICLES = 6; + const int ENT_CLIENT_RAINSNOW = 7; + const int ENT_CLIENT_LASER = 8; + const int ENT_CLIENT_NAGGER = 9; // flags [votecalledvote] + const int ENT_CLIENT_WAYPOINT = 10; // flags origin [team displayrule] [spritename] [spritename2] [spritename3] [lifetime maxdistance hideable] + const int ENT_CLIENT_RADARLINK = 11; // flags [startorigin] [endorigin] [startcolor+16*endcolor] + const int ENT_CLIENT_PROJECTILE = 12; + const int ENT_CLIENT_GIBSPLASH = 13; + const int ENT_CLIENT_DAMAGEINFO = 14; + const int ENT_CLIENT_CASING = 15; + const int ENT_CLIENT_INIT = 16; + const int ENT_CLIENT_MAPVOTE = 17; + const int ENT_CLIENT_CLIENTDATA = 18; + const int ENT_CLIENT_RANDOMSEED = 19; + const int ENT_CLIENT_WALL = 20; + const int ENT_CLIENT_SPIDERBOT = 21; + const int ENT_CLIENT_MODELEFFECT = 22; + const int ENT_CLIENT_TUBANOTE = 23; + const int ENT_CLIENT_WARPZONE = 24; + const int ENT_CLIENT_WARPZONE_CAMERA = 25; + const int ENT_CLIENT_TRIGGER_MUSIC = 26; + const int ENT_CLIENT_HOOK = 27; + const int ENT_CLIENT_ARC_BEAM = 29; // WEAPONTODO: fix numbers + const int ENT_CLIENT_ACCURACY = 30; + const int ENT_CLIENT_SHOWNAMES = 31; + const int ENT_CLIENT_WARPZONE_TELEPORTED = 32; + const int ENT_CLIENT_MODEL = 33; + const int ENT_CLIENT_ITEM = 34; + const int ENT_CLIENT_BUMBLE_RAYGUN = 35; + const int ENT_CLIENT_SPAWNPOINT = 36; + const int ENT_CLIENT_SPAWNEVENT = 37; + const int ENT_CLIENT_NOTIFICATION = 38; + const int ENT_CLIENT_ELIMINATEDPLAYERS = 39; + const int ENT_CLIENT_TURRET = 40; + const int ENT_CLIENT_AUXILIARYXHAIR = 50; + const int ENT_CLIENT_VEHICLE = 60; ++const int ENT_CLIENT_LADDER = 61; ++const int ENT_CLIENT_TRIGGER_PUSH = 62; ++const int ENT_CLIENT_TARGET_PUSH = 63; ++const int ENT_CLIENT_CONVEYOR = 64; + + const int ENT_CLIENT_HEALING_ORB = 80; + + const int SPRITERULE_DEFAULT = 0; + const int SPRITERULE_TEAMPLAY = 1; + + const int RADARICON_NONE = 0; + const int RADARICON_FLAG = 1; + const int RADARICON_FLAGCARRIER = 1; + const int RADARICON_HERE = 1; // TODO make these 3 and 4, and make images for them + const int RADARICON_DANGER = 1; + const int RADARICON_WAYPOINT = 1; + const int RADARICON_HELPME = 1; + const int RADARICON_CONTROLPOINT = 1; + const int RADARICON_GENERATOR = 1; + const int RADARICON_OBJECTIVE = 1; + const int RADARICON_DOMPOINT = 1; + const int RADARICON_POWERUP = 1; + const int RADARICON_TAGGED = 1; /////////////////////////// // keys pressed diff --cc qcsrc/common/physics.qc index 1b96fe03a,000000000..8e572645c mode 100644,000000..100644 --- a/qcsrc/common/physics.qc +++ b/qcsrc/common/physics.qc @@@ -1,2019 -1,0 +1,1945 @@@ - .float race_penalty; ++#include "physics.qh" + - .float gravity; - .float swamp_slowdown; - .float lastflags; - .float lastground; - .float wasFlying; - .float spectatorspeed; - - .vector movement_old; - .float buttons_old; - .vector v_angle_old; - .string lastclassname; - - .float() PlayerPhysplug; - float AdjustAirAccelQW(float accelqw, float factor); - - #ifdef CSQC - - .float watertype; - - #elif defined(SVQC) - .float stat_sv_airaccel_qw; - .float stat_sv_airstrafeaccel_qw; - .float stat_sv_airspeedlimit_nonqw; - .float stat_sv_maxspeed; - .float stat_movement_highspeed; - - .float stat_sv_friction_on_land; - .float stat_sv_friction_slick; - - .float stat_doublejump; - - .float stat_jumpspeedcap_min; - .float stat_jumpspeedcap_max; - .float stat_jumpspeedcap_disable_onramps; - - .float stat_jetpack_accel_side; - .float stat_jetpack_accel_up; - .float stat_jetpack_antigravity; - .float stat_jetpack_fuel; - .float stat_jetpack_maxspeed_up; - .float stat_jetpack_maxspeed_side; ++#ifdef SVQC + +void Physics_AddStats() +{ + // g_movementspeed hack + addstat(STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW, AS_FLOAT, stat_sv_airspeedlimit_nonqw); + addstat(STAT_MOVEVARS_MAXSPEED, AS_FLOAT, stat_sv_maxspeed); + addstat(STAT_MOVEVARS_AIRACCEL_QW, AS_FLOAT, stat_sv_airaccel_qw); + addstat(STAT_MOVEVARS_AIRSTRAFEACCEL_QW, AS_FLOAT, stat_sv_airstrafeaccel_qw); + addstat(STAT_MOVEVARS_HIGHSPEED, AS_FLOAT, stat_movement_highspeed); + + // jet pack + addstat(STAT_JETPACK_ACCEL_SIDE, AS_FLOAT, stat_jetpack_accel_side); + addstat(STAT_JETPACK_ACCEL_UP, AS_FLOAT, stat_jetpack_accel_up); + addstat(STAT_JETPACK_ANTIGRAVITY, AS_FLOAT, stat_jetpack_antigravity); + addstat(STAT_JETPACK_FUEL, AS_FLOAT, stat_jetpack_fuel); + addstat(STAT_JETPACK_MAXSPEED_UP, AS_FLOAT, stat_jetpack_maxspeed_up); + addstat(STAT_JETPACK_MAXSPEED_SIDE, AS_FLOAT, stat_jetpack_maxspeed_side); + + // hack to fix track_canjump + addstat(STAT_MOVEVARS_TRACK_CANJUMP, AS_INT, cvar_cl_movement_track_canjump); + + // double jump + addstat(STAT_DOUBLEJUMP, AS_INT, stat_doublejump); + + // jump speed caps + addstat(STAT_MOVEVARS_JUMPSPEEDCAP_MIN, AS_FLOAT, stat_jumpspeedcap_min); + addstat(STAT_MOVEVARS_JUMPSPEEDCAP_MIN, AS_FLOAT, stat_jumpspeedcap_min); + addstat(STAT_MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS, AS_INT, stat_jumpspeedcap_disable_onramps); + + // hacks + addstat(STAT_MOVEVARS_FRICTION_ONLAND, AS_FLOAT, stat_sv_friction_on_land); + addstat(STAT_MOVEVARS_FRICTION_SLICK, AS_FLOAT, stat_sv_friction_slick); +} + +void Physics_UpdateStats(float maxspd_mod) +{ + self.stat_sv_airaccel_qw = AdjustAirAccelQW(autocvar_sv_airaccel_qw, maxspd_mod); + if (autocvar_sv_airstrafeaccel_qw) + self.stat_sv_airstrafeaccel_qw = AdjustAirAccelQW(autocvar_sv_airstrafeaccel_qw, maxspd_mod); + else + self.stat_sv_airstrafeaccel_qw = 0; + self.stat_sv_airspeedlimit_nonqw = autocvar_sv_airspeedlimit_nonqw * maxspd_mod; + self.stat_sv_maxspeed = autocvar_sv_maxspeed * maxspd_mod; // also slow walking + self.stat_movement_highspeed = PHYS_HIGHSPEED; // TODO: remove this! + + self.stat_doublejump = PHYS_DOUBLEJUMP; + + self.stat_jetpack_antigravity = PHYS_JETPACK_ANTIGRAVITY; + self.stat_jetpack_accel_up = PHYS_JETPACK_ACCEL_UP; + self.stat_jetpack_accel_side = PHYS_JETPACK_ACCEL_SIDE; + self.stat_jetpack_maxspeed_side = PHYS_JETPACK_MAXSPEED_SIDE; + self.stat_jetpack_maxspeed_up = PHYS_JETPACK_MAXSPEED_UP; + self.stat_jetpack_fuel = PHYS_JETPACK_FUEL; + + self.stat_jumpspeedcap_min = PHYS_JUMPSPEEDCAP_MIN; + self.stat_jumpspeedcap_max = PHYS_JUMPSPEEDCAP_MAX; + self.stat_jumpspeedcap_disable_onramps = PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS; + + self.stat_sv_friction_on_land = PHYS_FRICTION_ONLAND; + self.stat_sv_friction_slick = PHYS_FRICTION_SLICK; +} +#endif + +float IsMoveInDirection(vector mv, float angle) // key mix factor +{ + if (mv_x == 0 && mv_y == 0) + return 0; // avoid division by zero + angle -= RAD2DEG * atan2(mv_y, mv_x); + angle = remainder(angle, 360) / 45; + return angle > 1 ? 0 : angle < -1 ? 0 : 1 - fabs(angle); +} + +float GeomLerp(float a, float lerp, float b) +{ + return a == 0 ? (lerp < 1 ? 0 : b) + : b == 0 ? (lerp > 0 ? 0 : a) + : a * pow(fabs(b / a), lerp); +} + +noref float pmove_waterjumptime; + +const float unstick_count = 27; +vector unstick_offsets[unstick_count] = +{ +// 1 no nudge (just return the original if this test passes) + '0.000 0.000 0.000', +// 6 simple nudges + ' 0.000 0.000 0.125', '0.000 0.000 -0.125', + '-0.125 0.000 0.000', '0.125 0.000 0.000', + ' 0.000 -0.125 0.000', '0.000 0.125 0.000', +// 4 diagonal flat nudges + '-0.125 -0.125 0.000', '0.125 -0.125 0.000', + '-0.125 0.125 0.000', '0.125 0.125 0.000', +// 8 diagonal upward nudges + '-0.125 0.000 0.125', '0.125 0.000 0.125', + ' 0.000 -0.125 0.125', '0.000 0.125 0.125', + '-0.125 -0.125 0.125', '0.125 -0.125 0.125', + '-0.125 0.125 0.125', '0.125 0.125 0.125', +// 8 diagonal downward nudges + '-0.125 0.000 -0.125', '0.125 0.000 -0.125', + ' 0.000 -0.125 -0.125', '0.000 0.125 -0.125', + '-0.125 -0.125 -0.125', '0.125 -0.125 -0.125', + '-0.125 0.125 -0.125', '0.125 0.125 -0.125', +}; + +void PM_ClientMovement_Unstick() +{ + float i; + for (i = 0; i < unstick_count; i++) + { + vector neworigin = unstick_offsets[i] + self.origin; + tracebox(neworigin, PL_CROUCH_MIN, PL_CROUCH_MAX, neworigin, MOVE_NORMAL, self); + if (!trace_startsolid) + { + self.origin = neworigin; + return;// true; + } + } +} + +void PM_ClientMovement_UpdateStatus() +{ + // make sure player is not stuck + PM_ClientMovement_Unstick(); + + // set crouched + if (PHYS_INPUT_BUTTON_CROUCH(self)) + { + // wants to crouch, this always works.. + if (!IS_DUCKED(self)) + SET_DUCKED(self); + } + else + { + // wants to stand, if currently crouching we need to check for a + // low ceiling first + if (IS_DUCKED(self)) + { + tracebox(self.origin, PL_MIN, PL_MAX, self.origin, MOVE_NORMAL, self); + if (!trace_startsolid) + UNSET_DUCKED(self); + } + } + + // set onground + vector origin1 = self.origin + '0 0 1'; + vector origin2 = self.origin - '0 0 1'; + + tracebox(origin1, self.mins, self.maxs, origin2, MOVE_NORMAL, self); + if (trace_fraction < 1 && trace_plane_normal_z > 0.7) + { + SET_ONGROUND(self); + + // this code actually "predicts" an impact; so let's clip velocity first + float f = self.velocity * trace_plane_normal; + if (f < 0) // only if moving downwards actually + self.velocity -= f * trace_plane_normal; + } + else + UNSET_ONGROUND(self); + + // set watertype/waterlevel + origin1 = self.origin; + origin1_z += self.mins_z + 1; + self.waterlevel = WATERLEVEL_NONE; + + self.watertype = (pointcontents(origin1) == CONTENT_WATER); + + if(self.watertype) + { + self.waterlevel = WATERLEVEL_WETFEET; + origin1_z = self.origin_z + (self.mins_z + self.maxs_z) * 0.5; + if(pointcontents(origin1) == CONTENT_WATER) + { + self.waterlevel = WATERLEVEL_SWIMMING; + origin1_z = self.origin_z + 22; + if(pointcontents(origin1) == CONTENT_WATER) + self.waterlevel = WATERLEVEL_SUBMERGED; + } + } + + if(IS_ONGROUND(self) || self.velocity_z <= 0 || pmove_waterjumptime <= 0) + pmove_waterjumptime = 0; +} + +void PM_ClientMovement_Move() +{ +#ifdef CSQC + float t = PHYS_INPUT_TIMELENGTH; + vector primalvelocity = self.velocity; + PM_ClientMovement_UpdateStatus(); + float bump = 0; + for (bump = 0; bump < 8 && self.velocity * self.velocity > 0; bump++) + { + vector neworigin = self.origin + t * self.velocity; + tracebox(self.origin, self.mins, self.maxs, neworigin, MOVE_NORMAL, self); + float old_trace1_fraction = trace_fraction; + vector old_trace1_endpos = trace_endpos; + vector old_trace1_plane_normal = trace_plane_normal; + if (trace_fraction < 1 && trace_plane_normal_z == 0) + { + // may be a step or wall, try stepping up + // first move forward at a higher level + vector currentorigin2 = self.origin; + currentorigin2_z += PHYS_STEPHEIGHT; + vector neworigin2 = neworigin; + neworigin2_z = self.origin_z + PHYS_STEPHEIGHT; + tracebox(currentorigin2, self.mins, self.maxs, neworigin2, MOVE_NORMAL, self); + if (!trace_startsolid) + { + // then move down from there + currentorigin2 = trace_endpos; + neworigin2 = trace_endpos; + neworigin2_z = self.origin_z; + float old_trace2_fraction = trace_fraction; + vector old_trace2_plane_normal = trace_plane_normal; + tracebox(currentorigin2, self.mins, self.maxs, neworigin2, MOVE_NORMAL, self); + // accept the new trace if it made some progress + if (fabs(trace_endpos_x - old_trace1_endpos_x) >= 0.03125 || fabs(trace_endpos_y - old_trace1_endpos_y) >= 0.03125) + { + trace_fraction = old_trace2_fraction; + trace_endpos = trace_endpos; + trace_plane_normal = old_trace2_plane_normal; + } + else + { + trace_fraction = old_trace1_fraction; + trace_endpos = old_trace1_endpos; + trace_plane_normal = old_trace1_plane_normal; + } + } + } + + // check if it moved at all + if (trace_fraction >= 0.001) + self.origin = trace_endpos; + + // check if it moved all the way + if (trace_fraction == 1) + break; + + // this is only really needed for nogravityonground combined with gravityunaffectedbyticrate + // I'm pretty sure I commented it out solely because it seemed redundant + // this got commented out in a change that supposedly makes the code match QW better + // so if this is broken, maybe put it in an if (cls.protocol != PROTOCOL_QUAKEWORLD) block + if (trace_plane_normal_z > 0.7) + SET_ONGROUND(self); + + t -= t * trace_fraction; + + float f = self.velocity * trace_plane_normal; + self.velocity -= f * trace_plane_normal; + } + if (pmove_waterjumptime > 0) + self.velocity = primalvelocity; +#endif +} + +void CPM_PM_Aircontrol(vector wishdir, float wishspeed) +{ + float k = 32 * (2 * IsMoveInDirection(PHYS_INPUT_MOVEVALUES(self), 0) - 1); + if (k <= 0) + return; + + k *= bound(0, wishspeed / PHYS_MAXAIRSPEED, 1); + + float zspeed = self.velocity_z; + self.velocity_z = 0; + float xyspeed = vlen(self.velocity); + self.velocity = normalize(self.velocity); + + float dot = self.velocity * wishdir; + + if (dot > 0) // we can't change direction while slowing down + { + k *= pow(dot, PHYS_AIRCONTROL_POWER)*PHYS_INPUT_TIMELENGTH; + xyspeed = max(0, xyspeed - PHYS_AIRCONTROL_PENALTY * sqrt(max(0, 1 - dot*dot)) * k/32); + k *= PHYS_AIRCONTROL; + self.velocity = normalize(self.velocity * xyspeed + wishdir * k); + } + + self.velocity = self.velocity * xyspeed; + self.velocity_z = zspeed; +} + +float AdjustAirAccelQW(float accelqw, float factor) +{ + return copysign(bound(0.000001, 1 - (1 - fabs(accelqw)) * factor, 1), accelqw); +} + +// example config for alternate speed clamping: +// sv_airaccel_qw 0.8 +// sv_airaccel_sideways_friction 0 +// prvm_globalset server speedclamp_mode 1 +// (or 2) +void PM_Accelerate(vector wishdir, float wishspeed, float wishspeed0, float accel, float accelqw, float stretchfactor, float sidefric, float speedlimit) +{ + float speedclamp = stretchfactor > 0 ? stretchfactor + : accelqw < 0 ? 1 // full clamping, no stretch + : -1; // no clamping + + accelqw = fabs(accelqw); + + if (GAMEPLAYFIX_Q2AIRACCELERATE) + wishspeed0 = wishspeed; // don't need to emulate this Q1 bug + + float vel_straight = self.velocity * wishdir; + float vel_z = self.velocity_z; + vector vel_xy = vec2(self.velocity); + vector vel_perpend = vel_xy - vel_straight * wishdir; + + float step = accel * PHYS_INPUT_TIMELENGTH * wishspeed0; + + float vel_xy_current = vlen(vel_xy); + if (speedlimit) + accelqw = AdjustAirAccelQW(accelqw, (speedlimit - bound(wishspeed, vel_xy_current, speedlimit)) / max(1, speedlimit - wishspeed)); + float vel_xy_forward = vel_xy_current + bound(0, wishspeed - vel_xy_current, step) * accelqw + step * (1 - accelqw); + float vel_xy_backward = vel_xy_current - bound(0, wishspeed + vel_xy_current, step) * accelqw - step * (1 - accelqw); + vel_xy_backward = max(0, vel_xy_backward); // not that it REALLY occurs that this would cause wrong behaviour afterwards + vel_straight = vel_straight + bound(0, wishspeed - vel_straight, step) * accelqw + step * (1 - accelqw); + + if (sidefric < 0 && (vel_perpend*vel_perpend)) + // negative: only apply so much sideways friction to stay below the speed you could get by "braking" + { + float f = max(0, 1 + PHYS_INPUT_TIMELENGTH * wishspeed * sidefric); + float fmin = (vel_xy_backward * vel_xy_backward - vel_straight * vel_straight) / (vel_perpend * vel_perpend); + // assume: fmin > 1 + // vel_xy_backward*vel_xy_backward - vel_straight*vel_straight > vel_perpend*vel_perpend + // vel_xy_backward*vel_xy_backward > vel_straight*vel_straight + vel_perpend*vel_perpend + // vel_xy_backward*vel_xy_backward > vel_xy * vel_xy + // obviously, this cannot be + if (fmin <= 0) + vel_perpend *= f; + else + { + fmin = sqrt(fmin); + vel_perpend *= max(fmin, f); + } + } + else + vel_perpend *= max(0, 1 - PHYS_INPUT_TIMELENGTH * wishspeed * sidefric); + + vel_xy = vel_straight * wishdir + vel_perpend; + + if (speedclamp >= 0) + { + float vel_xy_preclamp; + vel_xy_preclamp = vlen(vel_xy); + if (vel_xy_preclamp > 0) // prevent division by zero + { + vel_xy_current += (vel_xy_forward - vel_xy_current) * speedclamp; + if (vel_xy_current < vel_xy_preclamp) + vel_xy *= (vel_xy_current / vel_xy_preclamp); + } + } + + self.velocity = vel_xy + vel_z * '0 0 1'; +} + +void PM_AirAccelerate(vector wishdir, float wishspeed) +{ + if (wishspeed == 0) + return; + + vector curvel = self.velocity; + curvel_z = 0; + float curspeed = vlen(curvel); + + if (wishspeed > curspeed * 1.01) + wishspeed = min(wishspeed, curspeed + PHYS_WARSOWBUNNY_AIRFORWARDACCEL * PHYS_MAXSPEED(self) * PHYS_INPUT_TIMELENGTH); + else + { + float f = max(0, (PHYS_WARSOWBUNNY_TOPSPEED - curspeed) / (PHYS_WARSOWBUNNY_TOPSPEED - PHYS_MAXSPEED(self))); + wishspeed = max(curspeed, PHYS_MAXSPEED(self)) + PHYS_WARSOWBUNNY_ACCEL * f * PHYS_MAXSPEED(self) * PHYS_INPUT_TIMELENGTH; + } + vector wishvel = wishdir * wishspeed; + vector acceldir = wishvel - curvel; + float addspeed = vlen(acceldir); + acceldir = normalize(acceldir); + + float accelspeed = min(addspeed, PHYS_WARSOWBUNNY_TURNACCEL * PHYS_MAXSPEED(self) * PHYS_INPUT_TIMELENGTH); + + if (PHYS_WARSOWBUNNY_BACKTOSIDERATIO < 1) + { + vector curdir = normalize(curvel); + float dot = acceldir * curdir; + if (dot < 0) + acceldir -= (1 - PHYS_WARSOWBUNNY_BACKTOSIDERATIO) * dot * curdir; + } + + self.velocity += accelspeed * acceldir; +} + + +/* +============= +PlayerJump + +When you press the jump key - returns TRUE if handled ++returns true if handled +============= +*/ +float PlayerJump (void) +{ + if (PHYS_FROZEN(self)) - return TRUE; // no jumping in freezetag when frozen ++ return true; // no jumping in freezetag when frozen + +#ifdef SVQC + if (self.player_blocked) - return TRUE; // no jumping while blocked ++ return true; // no jumping while blocked +#endif + - float doublejump = FALSE; ++ float doublejump = false; + float mjumpheight = PHYS_JUMPVELOCITY; + + player_multijump = doublejump; + player_jumpheight = mjumpheight; +#ifdef SVQC + if (MUTATOR_CALLHOOK(PlayerJump)) +#elif defined(CSQC) + if(PM_multijump_checkjump()) +#endif - return TRUE; ++ return true; + + doublejump = player_multijump; + mjumpheight = player_jumpheight; + + if (PHYS_DOUBLEJUMP) + { + tracebox(self.origin + '0 0 0.01', self.mins, self.maxs, self.origin - '0 0 0.01', MOVE_NORMAL, self); + if (trace_fraction < 1 && trace_plane_normal_z > 0.7) + { - doublejump = TRUE; ++ doublejump = true; + + // we MUST clip velocity here! + float f; + f = self.velocity * trace_plane_normal; + if (f < 0) + self.velocity -= f * trace_plane_normal; + } + } + + if (self.waterlevel >= WATERLEVEL_SWIMMING) + { + self.velocity_z = PHYS_MAXSPEED(self) * 0.7; - return TRUE; ++ return true; + } + + if (!doublejump) + if (!IS_ONGROUND(self)) + return IS_JUMP_HELD(self); + + if (PHYS_TRACK_CANJUMP(self)) + if (IS_JUMP_HELD(self)) - return TRUE; ++ return true; + + // sv_jumpspeedcap_min/sv_jumpspeedcap_max act as baseline + // velocity bounds. Final velocity is bound between (jumpheight * + // min + jumpheight) and (jumpheight * max + jumpheight); + + if(PHYS_JUMPSPEEDCAP_MIN) + { + float minjumpspeed = mjumpheight * PHYS_JUMPSPEEDCAP_MIN; + + if (self.velocity_z < minjumpspeed) + mjumpheight += minjumpspeed - self.velocity_z; + } + + if(PHYS_JUMPSPEEDCAP_MAX) + { + // don't do jump speedcaps on ramps to preserve old xonotic ramjump style + tracebox(self.origin + '0 0 0.01', self.mins, self.maxs, self.origin - '0 0 0.01', MOVE_NORMAL, self); + + if (!(trace_fraction < 1 && trace_plane_normal_z < 0.98 && PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS)) + { + float maxjumpspeed = mjumpheight * PHYS_JUMPSPEEDCAP_MAX; + + if (self.velocity_z > maxjumpspeed) + mjumpheight -= self.velocity_z - maxjumpspeed; + } + } + + if (!WAS_ONGROUND(self)) + { + if(autocvar_speedmeter) + dprint(strcat("landing velocity: ", vtos(self.velocity), " (abs: ", ftos(vlen(self.velocity)), ")\n")); + if(self.lastground < time - 0.3) + { + self.velocity_x *= (1 - PHYS_FRICTION_ONLAND); + self.velocity_y *= (1 - PHYS_FRICTION_ONLAND); + } + if(self.jumppadcount > 1) + dprint(strcat(ftos(self.jumppadcount), "x jumppad combo\n")); + self.jumppadcount = 0; + } + + self.velocity_z += mjumpheight; + + UNSET_ONGROUND(self); + SET_JUMP_HELD(self); + +#ifdef SVQC + + self.oldvelocity_z = self.velocity_z; + - animdecide_setaction(self, ANIMACTION_JUMP, TRUE); ++ animdecide_setaction(self, ANIMACTION_JUMP, true); + + if (autocvar_g_jump_grunt) + PlayerSound(playersound_jump, CH_PLAYER, VOICETYPE_PLAYERSOUND); +#endif - return TRUE; ++ return true; +} + +void CheckWaterJump() +{ +// check for a jump-out-of-water + makevectors(PHYS_INPUT_ANGLES(self)); + vector start = self.origin; + start_z += 8; + v_forward_z = 0; + normalize(v_forward); + vector end = start + v_forward*24; - traceline (start, end, TRUE, self); ++ traceline (start, end, true, self); + if (trace_fraction < 1) + { // solid at waist + start_z = start_z + self.maxs_z - 8; + end = start + v_forward*24; + self.movedir = trace_plane_normal * -50; - traceline(start, end, TRUE, self); ++ traceline(start, end, true, self); + if (trace_fraction == 1) + { // open at eye level + self.velocity_z = 225; +#ifdef SVQC + self.flags |= FL_WATERJUMP; + SET_JUMP_HELD(self); + self.teleport_time = time + 2; // safety net +#endif + } + } +} + + +#ifdef SVQC + #define JETPACK_JUMP(s) s.cvar_cl_jetpack_jump +#elif defined(CSQC) + float autocvar_cl_jetpack_jump; + #define JETPACK_JUMP(s) autocvar_cl_jetpack_jump +#endif +.float jetpack_stopped; +// Hack: shouldn't need to know about this +.float multijump_count; +void CheckPlayerJump() +{ +#ifdef SVQC + float was_flying = ITEMS(self) & IT_USING_JETPACK; +#endif + if (JETPACK_JUMP(self) < 2) +#ifdef SVQC + ITEMS(self) &= ~IT_USING_JETPACK; +#endif + + if(PHYS_INPUT_BUTTON_JUMP(self) || PHYS_INPUT_BUTTON_JETPACK(self)) + { +#ifdef SVQC + float air_jump = !PlayerJump() || self.multijump_count > 0; // PlayerJump() has important side effects + float activate = JETPACK_JUMP(self) && air_jump && PHYS_INPUT_BUTTON_JUMP(self) || PHYS_INPUT_BUTTON_JETPACK(self); + float has_fuel = !autocvar_g_jetpack_fuel || self.ammo_fuel || ITEMS(self) & IT_UNLIMITED_WEAPON_AMMO; +#else + PlayerJump(); // Client only - float has_fuel = TRUE; // TODO ++ float has_fuel = true; // TODO +#endif + if (!(ITEMS(self) & IT_JETPACK)) { } + else if (self.jetpack_stopped) { } + else if (!has_fuel) + { +#ifdef SVQC + if (was_flying) // TODO: ran out of fuel message + Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_JETPACK_NOFUEL); + else if (activate) + Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_JETPACK_NOFUEL); +#endif - self.jetpack_stopped = TRUE; ++ self.jetpack_stopped = true; +#ifdef SVQC + ITEMS(self) &= ~IT_USING_JETPACK; +#endif + } +#ifdef SVQC + else if (activate && !PHYS_FROZEN(self)) + ITEMS(self) |= IT_USING_JETPACK; +#endif + } + else + { - self.jetpack_stopped = FALSE; ++ self.jetpack_stopped = false; +#ifdef SVQC + ITEMS(self) &= ~IT_USING_JETPACK; +#endif + } + if (!PHYS_INPUT_BUTTON_JUMP(self)) + UNSET_JUMP_HELD(self); + + if (self.waterlevel == WATERLEVEL_SWIMMING) + CheckWaterJump(); +} + +float racecar_angle(float forward, float down) +{ + if (forward < 0) + { + forward = -forward; + down = -down; + } + + float ret = vectoyaw('0 1 0' * down + '1 0 0' * forward); + + float angle_mult = forward / (800 + forward); + + if (ret > 180) + return ret * angle_mult + 360 * (1 - angle_mult); + else + return ret * angle_mult; +} + +void RaceCarPhysics() +{ +#ifdef SVQC + // using this move type for "big rigs" + // the engine does not push the entity! + + vector rigvel; + + vector angles_save = self.angles; + float accel = bound(-1, PHYS_INPUT_MOVEVALUES(self).x / PHYS_MAXSPEED(self), 1); + float steer = bound(-1, PHYS_INPUT_MOVEVALUES(self).y / PHYS_MAXSPEED(self), 1); + + if (g_bugrigs_reverse_speeding) + { + if (accel < 0) + { + // back accel is DIGITAL + // to prevent speedhack + if (accel < -0.5) + accel = -1; + else + accel = 0; + } + } + + self.angles_x = 0; + self.angles_z = 0; + makevectors(self.angles); // new forward direction! + + if (IS_ONGROUND(self) || g_bugrigs_air_steering) + { + float myspeed = self.velocity * v_forward; + float upspeed = self.velocity * v_up; + + // responsiveness factor for steering and acceleration + float f = 1 / (1 + pow(max(-myspeed, myspeed) / g_bugrigs_speed_ref, g_bugrigs_speed_pow)); + //MAXIMA: f(v) := 1 / (1 + (v / g_bugrigs_speed_ref) ^ g_bugrigs_speed_pow); + + float steerfactor; + if (myspeed < 0 && g_bugrigs_reverse_spinning) + steerfactor = -myspeed * g_bugrigs_steer; + else + steerfactor = -myspeed * f * g_bugrigs_steer; + + float accelfactor; + if (myspeed < 0 && g_bugrigs_reverse_speeding) + accelfactor = g_bugrigs_accel; + else + accelfactor = f * g_bugrigs_accel; + //MAXIMA: accel(v) := f(v) * g_bugrigs_accel; + + if (accel < 0) + { + if (myspeed > 0) + { + myspeed = max(0, myspeed - PHYS_INPUT_TIMELENGTH * (g_bugrigs_friction_floor - g_bugrigs_friction_brake * accel)); + } + else + { + if (!g_bugrigs_reverse_speeding) + myspeed = min(0, myspeed + PHYS_INPUT_TIMELENGTH * g_bugrigs_friction_floor); + } + } + else + { + if (myspeed >= 0) + { + myspeed = max(0, myspeed - PHYS_INPUT_TIMELENGTH * g_bugrigs_friction_floor); + } + else + { + if (g_bugrigs_reverse_stopping) + myspeed = 0; + else + myspeed = min(0, myspeed + PHYS_INPUT_TIMELENGTH * (g_bugrigs_friction_floor + g_bugrigs_friction_brake * accel)); + } + } + // terminal velocity = velocity at which 50 == accelfactor, that is, 1549 units/sec + //MAXIMA: friction(v) := g_bugrigs_friction_floor; + + self.angles_y += steer * PHYS_INPUT_TIMELENGTH * steerfactor; // apply steering + makevectors(self.angles); // new forward direction! + + myspeed += accel * accelfactor * PHYS_INPUT_TIMELENGTH; + + rigvel = myspeed * v_forward + '0 0 1' * upspeed; + } + else + { + float myspeed = vlen(self.velocity); + + // responsiveness factor for steering and acceleration + float f = 1 / (1 + pow(max(0, myspeed / g_bugrigs_speed_ref), g_bugrigs_speed_pow)); + float steerfactor = -myspeed * f; + self.angles_y += steer * PHYS_INPUT_TIMELENGTH * steerfactor; // apply steering + + rigvel = self.velocity; + makevectors(self.angles); // new forward direction! + } + + rigvel *= max(0, 1 - vlen(rigvel) * g_bugrigs_friction_air * PHYS_INPUT_TIMELENGTH); + //MAXIMA: airfriction(v) := v * v * g_bugrigs_friction_air; + //MAXIMA: total_acceleration(v) := accel(v) - friction(v) - airfriction(v); + //MAXIMA: solve(total_acceleration(v) = 0, v); + + if (g_bugrigs_planar_movement) + { + vector rigvel_xy, neworigin, up; + float mt; + + rigvel_z -= PHYS_INPUT_TIMELENGTH * PHYS_GRAVITY; // 4x gravity plays better + rigvel_xy = vec2(rigvel); + + if (g_bugrigs_planar_movement_car_jumping) + mt = MOVE_NORMAL; + else + mt = MOVE_NOMONSTERS; + + tracebox(self.origin, self.mins, self.maxs, self.origin + '0 0 1024', mt, self); + up = trace_endpos - self.origin; + + // BUG RIGS: align the move to the surface instead of doing collision testing + // can we move? + tracebox(trace_endpos, self.mins, self.maxs, trace_endpos + rigvel_xy * PHYS_INPUT_TIMELENGTH, mt, self); + + // align to surface + tracebox(trace_endpos, self.mins, self.maxs, trace_endpos - up + '0 0 1' * rigvel_z * PHYS_INPUT_TIMELENGTH, mt, self); + + if (trace_fraction < 0.5) + { + trace_fraction = 1; + neworigin = self.origin; + } + else + neworigin = trace_endpos; + + if (trace_fraction < 1) + { + // now set angles_x so that the car points parallel to the surface + self.angles = vectoangles( + '1 0 0' * v_forward_x * trace_plane_normal_z + + + '0 1 0' * v_forward_y * trace_plane_normal_z + + + '0 0 1' * -(v_forward_x * trace_plane_normal_x + v_forward_y * trace_plane_normal_y) + ); + SET_ONGROUND(self); + } + else + { + // now set angles_x so that the car points forward, but is tilted in velocity direction + UNSET_ONGROUND(self); + } + + self.velocity = (neworigin - self.origin) * (1.0 / PHYS_INPUT_TIMELENGTH); + self.movetype = MOVETYPE_NOCLIP; + } + else + { + rigvel_z -= PHYS_INPUT_TIMELENGTH * PHYS_GRAVITY; // 4x gravity plays better + self.velocity = rigvel; + self.movetype = MOVETYPE_FLY; + } + + trace_fraction = 1; + tracebox(self.origin, self.mins, self.maxs, self.origin - '0 0 4', MOVE_NORMAL, self); + if (trace_fraction != 1) + { + self.angles = vectoangles2( + '1 0 0' * v_forward_x * trace_plane_normal_z + + + '0 1 0' * v_forward_y * trace_plane_normal_z + + + '0 0 1' * -(v_forward_x * trace_plane_normal_x + v_forward_y * trace_plane_normal_y), + trace_plane_normal + ); + } + else + { + vector vel_local; + + vel_local_x = v_forward * self.velocity; + vel_local_y = v_right * self.velocity; + vel_local_z = v_up * self.velocity; + + self.angles_x = racecar_angle(vel_local_x, vel_local_z); + self.angles_z = racecar_angle(-vel_local_y, vel_local_z); + } + + // smooth the angles + vector vf1, vu1, smoothangles; + makevectors(self.angles); + float f = bound(0, PHYS_INPUT_TIMELENGTH * g_bugrigs_angle_smoothing, 1); + if (f == 0) + f = 1; + vf1 = v_forward * f; + vu1 = v_up * f; + makevectors(angles_save); + vf1 = vf1 + v_forward * (1 - f); + vu1 = vu1 + v_up * (1 - f); + smoothangles = vectoangles2(vf1, vu1); + self.angles_x = -smoothangles_x; + self.angles_z = smoothangles_z; +#endif +} + +string specialcommand = "xwxwxsxsxaxdxaxdx1x "; +.float specialcommand_pos; +void SpecialCommand() +{ +#ifdef SVQC +#ifdef TETRIS + TetrisImpulse(); +#else + if (!CheatImpulse(99)) + print("A hollow voice says \"Plugh\".\n"); +#endif +#endif +} + - #ifdef SVQC - float speedaward_speed; - string speedaward_holder; - string speedaward_uid; - #endif - void race_send_speedaward(float msg) - { - #ifdef SVQC - // send the best speed of the round - WriteByte(msg, SVC_TEMPENTITY); - WriteByte(msg, TE_CSQC_RACE); - WriteByte(msg, RACE_NET_SPEED_AWARD); - WriteInt24_t(msg, floor(speedaward_speed+0.5)); - WriteString(msg, speedaward_holder); - #endif - } - - #ifdef SVQC - float speedaward_alltimebest; - string speedaward_alltimebest_holder; - string speedaward_alltimebest_uid; - #endif - void race_send_speedaward_alltimebest(float msg) - { - #ifdef SVQC - // send the best speed - WriteByte(msg, SVC_TEMPENTITY); - WriteByte(msg, TE_CSQC_RACE); - WriteByte(msg, RACE_NET_SPEED_AWARD_BEST); - WriteInt24_t(msg, floor(speedaward_alltimebest+0.5)); - WriteString(msg, speedaward_alltimebest_holder); - #endif - } - +float PM_check_keepaway(void) +{ +#ifdef SVQC + return (self.ballcarried && g_keepaway) ? autocvar_g_keepaway_ballcarrier_highspeed : 1; +#else + return 1; +#endif +} + +void PM_check_race_movetime(void) +{ +#ifdef SVQC + self.race_movetime_frac += PHYS_INPUT_TIMELENGTH; + float f = floor(self.race_movetime_frac); + self.race_movetime_frac -= f; + self.race_movetime_count += f; + self.race_movetime = self.race_movetime_frac + self.race_movetime_count; +#endif +} + +float PM_check_specialcommand(float buttons) +{ +#ifdef SVQC + string c; + if (!buttons) + c = "x"; + else if (buttons == 1) + c = "1"; + else if (buttons == 2) + c = " "; + else if (buttons == 128) + c = "s"; + else if (buttons == 256) + c = "w"; + else if (buttons == 512) + c = "a"; + else if (buttons == 1024) + c = "d"; + else + c = "?"; + + if (c == substring(specialcommand, self.specialcommand_pos, 1)) + { + self.specialcommand_pos += 1; + if (self.specialcommand_pos >= strlen(specialcommand)) + { + self.specialcommand_pos = 0; + SpecialCommand(); - return TRUE; ++ return true; + } + } + else if (self.specialcommand_pos && (c != substring(specialcommand, self.specialcommand_pos - 1, 1))) + self.specialcommand_pos = 0; +#endif - return FALSE; ++ return false; +} + +void PM_check_nickspam(void) +{ +#ifdef SVQC + if (time >= self.nickspamtime) + return; + if (self.nickspamcount >= autocvar_g_nick_flood_penalty_yellow) + { + // slight annoyance for nick change scripts + PHYS_INPUT_MOVEVALUES(self) = -1 * PHYS_INPUT_MOVEVALUES(self); + self.BUTTON_ATCK = self.BUTTON_JUMP = self.BUTTON_ATCK2 = self.BUTTON_ZOOM = self.BUTTON_CROUCH = self.BUTTON_HOOK = self.BUTTON_USE = 0; + + if (self.nickspamcount >= autocvar_g_nick_flood_penalty_red) // if you are persistent and the slight annoyance above does not stop you, I'll show you! + { + PHYS_INPUT_ANGLES(self)_x = random() * 360; + PHYS_INPUT_ANGLES(self)_y = random() * 360; + // at least I'm not forcing retardedview by also assigning to angles_z - self.fixangle = TRUE; ++ self.fixangle = true; + } + } +#endif +} + +void PM_check_punch() +{ +#ifdef SVQC + if (self.punchangle != '0 0 0') + { + float f = vlen(self.punchangle) - 10 * PHYS_INPUT_TIMELENGTH; + if (f > 0) + self.punchangle = normalize(self.punchangle) * f; + else + self.punchangle = '0 0 0'; + } + + if (self.punchvector != '0 0 0') + { + float f = vlen(self.punchvector) - 30 * PHYS_INPUT_TIMELENGTH; + if (f > 0) + self.punchvector = normalize(self.punchvector) * f; + else + self.punchvector = '0 0 0'; + } +#endif +} + +void PM_check_spider(void) +{ +#ifdef SVQC + if (time >= self.spider_slowness) + return; + PHYS_MAXSPEED(self) *= 0.5; // half speed while slow from spider + self.stat_sv_airspeedlimit_nonqw *= 0.5; +#endif +} + +// predict frozen movement, as frozen players CAN move in some cases +void PM_check_frozen(void) +{ + if (!PHYS_FROZEN(self)) + return; + if (PHYS_DODGING_FROZEN +#ifdef SVQC + && IS_REAL_CLIENT(self) +#endif + ) + { + PHYS_INPUT_MOVEVALUES(self)_x = bound(-5, PHYS_INPUT_MOVEVALUES(self).x, 5); + PHYS_INPUT_MOVEVALUES(self)_y = bound(-5, PHYS_INPUT_MOVEVALUES(self).y, 5); + PHYS_INPUT_MOVEVALUES(self)_z = bound(-5, PHYS_INPUT_MOVEVALUES(self).z, 5); + } + else + PHYS_INPUT_MOVEVALUES(self) = '0 0 0'; + + vector midpoint = ((self.absmin + self.absmax) * 0.5); + if (pointcontents(midpoint) == CONTENT_WATER) + { + self.velocity = self.velocity * 0.5; + + if (pointcontents(midpoint + '0 0 16') == CONTENT_WATER) + self.velocity_z = 200; + } +} + +void PM_check_blocked(void) +{ +#ifdef SVQC + if (!self.player_blocked) + return; + PHYS_INPUT_MOVEVALUES(self) = '0 0 0'; + self.disableclientprediction = 1; +#endif +} + +#ifdef SVQC +float speedaward_lastsent; +float speedaward_lastupdate; +string GetMapname(void); +#endif +void PM_check_race(void) +{ +#ifdef SVQC + if not(g_cts || g_race) + return; + if (vlen(self.velocity - self.velocity_z * '0 0 1') > speedaward_speed) + { + speedaward_speed = vlen(self.velocity - self.velocity_z * '0 0 1'); + speedaward_holder = self.netname; + speedaward_uid = self.crypto_idfp; + speedaward_lastupdate = time; + } + if (speedaward_speed > speedaward_lastsent && time - speedaward_lastupdate > 1) + { + string rr = (g_cts) ? CTS_RECORD : RACE_RECORD; + race_send_speedaward(MSG_ALL); + speedaward_lastsent = speedaward_speed; + if (speedaward_speed > speedaward_alltimebest && speedaward_uid != "") + { + speedaward_alltimebest = speedaward_speed; + speedaward_alltimebest_holder = speedaward_holder; + speedaward_alltimebest_uid = speedaward_uid; + db_put(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed"), ftos(speedaward_alltimebest)); + db_put(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp"), speedaward_alltimebest_uid); + race_send_speedaward_alltimebest(MSG_ALL); + } + } +#endif +} + +void PM_check_vortex(void) +{ +#ifdef SVQC + // WEAPONTODO + float xyspeed = vlen(vec2(self.velocity)); + if (self.weapon == WEP_VORTEX && WEP_CVAR(vortex, charge) && WEP_CVAR(vortex, charge_velocity_rate) && xyspeed > WEP_CVAR(vortex, charge_minspeed)) + { + // add a maximum of charge_velocity_rate when going fast (f = 1), gradually increasing from minspeed (f = 0) to maxspeed + xyspeed = min(xyspeed, WEP_CVAR(vortex, charge_maxspeed)); + float f = (xyspeed - WEP_CVAR(vortex, charge_minspeed)) / (WEP_CVAR(vortex, charge_maxspeed) - WEP_CVAR(vortex, charge_minspeed)); + // add the extra charge + self.vortex_charge = min(1, self.vortex_charge + WEP_CVAR(vortex, charge_velocity_rate) * f * PHYS_INPUT_TIMELENGTH); + } +#endif +} + +void PM_fly(float maxspd_mod) +{ + // noclipping or flying + UNSET_ONGROUND(self); + + self.velocity = self.velocity * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION); + makevectors(PHYS_INPUT_ANGLES(self)); + //wishvel = v_forward * PHYS_INPUT_MOVEVALUES(self).x + v_right * PHYS_INPUT_MOVEVALUES(self).y + v_up * PHYS_INPUT_MOVEVALUES(self).z; + vector wishvel = v_forward * PHYS_INPUT_MOVEVALUES(self).x + + v_right * PHYS_INPUT_MOVEVALUES(self).y + + '0 0 1' * PHYS_INPUT_MOVEVALUES(self).z; + // acceleration + vector wishdir = normalize(wishvel); + float wishspeed = min(vlen(wishvel), PHYS_MAXSPEED(self) * maxspd_mod); + if (time >= self.teleport_time) + PM_Accelerate(wishdir, wishspeed, wishspeed, PHYS_ACCELERATE * maxspd_mod, 1, 0, 0, 0); +} + +void PM_swim(float maxspd_mod) +{ + // swimming + UNSET_ONGROUND(self); + + float jump = PHYS_INPUT_BUTTON_JUMP(self); + // water jump only in certain situations + // this mimics quakeworld code + if (jump && self.waterlevel == WATERLEVEL_SWIMMING && self.velocity_z >= -180) + { + vector yawangles = '0 1 0' * PHYS_INPUT_ANGLES(self).y; + makevectors(yawangles); + vector forward = v_forward; + vector spot = self.origin + 24 * forward; + spot_z += 8; + traceline(spot, spot, MOVE_NOMONSTERS, self); + if (trace_startsolid) + { + spot_z += 24; + traceline(spot, spot, MOVE_NOMONSTERS, self); + if (!trace_startsolid) + { + self.velocity = forward * 50; + self.velocity_z = 310; + pmove_waterjumptime = 2; + UNSET_ONGROUND(self); + SET_JUMP_HELD(self); + } + } + } + makevectors(PHYS_INPUT_ANGLES(self)); + //wishvel = v_forward * PHYS_INPUT_MOVEVALUES(self).x + v_right * PHYS_INPUT_MOVEVALUES(self).y + v_up * PHYS_INPUT_MOVEVALUES(self).z; + vector wishvel = v_forward * PHYS_INPUT_MOVEVALUES(self).x + + v_right * PHYS_INPUT_MOVEVALUES(self).y + + '0 0 1' * PHYS_INPUT_MOVEVALUES(self).z; + if (wishvel == '0 0 0') + wishvel = '0 0 -60'; // drift towards bottom + + vector wishdir = normalize(wishvel); + float wishspeed = min(vlen(wishvel), PHYS_MAXSPEED(self) * maxspd_mod) * 0.7; + + if (IS_DUCKED(self)) + wishspeed *= 0.5; + +// if (pmove_waterjumptime <= 0) // TODO: use + { + // water friction + float f = 1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION; + f = min(max(0, f), 1); + self.velocity *= f; + + f = wishspeed - self.velocity * wishdir; + if (f > 0) + { + float accelspeed = min(PHYS_ACCELERATE * PHYS_INPUT_TIMELENGTH * wishspeed, f); + self.velocity += accelspeed * wishdir; + } + + // holding jump button swims upward slowly + if (jump) + { +#if 0 + if (self.watertype & CONTENT_LAVA) + self.velocity_z = 50; + else if (self.watertype & CONTENT_SLIME) + self.velocity_z = 80; + else + { + if (IS_NEXUIZ_DERIVED(gamemode)) +#endif + self.velocity_z = 200; +#if 0 + else + self.velocity_z = 100; + } +#endif + } + } + PM_ClientMovement_Move(); + // water acceleration + PM_Accelerate(wishdir, wishspeed, wishspeed, PHYS_ACCELERATE * maxspd_mod, 1, 0, 0, 0); +} + +void PM_ladder(float maxspd_mod) +{ + // on a spawnfunc_func_ladder or swimming in spawnfunc_func_water + UNSET_ONGROUND(self); + + float g; + g = PHYS_GRAVITY * PHYS_INPUT_TIMELENGTH; + if (PHYS_ENTGRAVITY(self)) + g *= PHYS_ENTGRAVITY(self); + if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE) + { + g *= 0.5; + self.velocity_z += g; + } + + self.velocity = self.velocity * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION); + makevectors(PHYS_INPUT_ANGLES(self)); + //wishvel = v_forward * PHYS_INPUT_MOVEVALUES(self).x + v_right * PHYS_INPUT_MOVEVALUES(self).y + v_up * PHYS_INPUT_MOVEVALUES(self).z; + vector wishvel = v_forward * PHYS_INPUT_MOVEVALUES(self)_x + + v_right * PHYS_INPUT_MOVEVALUES(self)_y + + '0 0 1' * PHYS_INPUT_MOVEVALUES(self)_z; + self.velocity_z += g; + if (self.ladder_entity.classname == "func_water") + { + float f = vlen(wishvel); + if (f > self.ladder_entity.speed) + wishvel *= (self.ladder_entity.speed / f); + + self.watertype = self.ladder_entity.skin; + f = self.ladder_entity.origin_z + self.ladder_entity.maxs_z; + if ((self.origin_z + self.view_ofs_z) < f) + self.waterlevel = WATERLEVEL_SUBMERGED; + else if ((self.origin_z + (self.mins_z + self.maxs_z) * 0.5) < f) + self.waterlevel = WATERLEVEL_SWIMMING; + else if ((self.origin_z + self.mins_z + 1) < f) + self.waterlevel = WATERLEVEL_WETFEET; + else + { + self.waterlevel = WATERLEVEL_NONE; + self.watertype = CONTENT_EMPTY; + } + } + // acceleration + vector wishdir = normalize(wishvel); + float wishspeed = min(vlen(wishvel), PHYS_MAXSPEED(self) * maxspd_mod); + PM_ClientMovement_Move(); +#ifdef SVQC + if (time >= self.teleport_time) +#endif + // water acceleration + PM_Accelerate(wishdir, wishspeed, wishspeed, PHYS_ACCELERATE*maxspd_mod, 1, 0, 0, 0); +} + +void PM_check_jumppad() +{ +#ifdef CSQC + entity oldself = self; + + for(self = world; (self = find(self, classname, "jumppad")); ) + trigger_push_draw(); + + self = oldself; +#endif +} + +void PM_jetpack(float maxspd_mod) +{ + //makevectors(PHYS_INPUT_ANGLES(self).y * '0 1 0'); + makevectors(PHYS_INPUT_ANGLES(self)); + vector wishvel = v_forward * PHYS_INPUT_MOVEVALUES(self)_x + + v_right * PHYS_INPUT_MOVEVALUES(self)_y; + // add remaining speed as Z component + float maxairspd = PHYS_MAXAIRSPEED * max(1, maxspd_mod); + // fix speedhacks :P + wishvel = normalize(wishvel) * min(1, vlen(wishvel) / maxairspd); + // add the unused velocity as up component + wishvel_z = 0; + + // if (self.BUTTON_JUMP) + wishvel_z = sqrt(max(0, 1 - wishvel * wishvel)); + + // it is now normalized, so... + float a_side = PHYS_JETPACK_ACCEL_SIDE; + float a_up = PHYS_JETPACK_ACCEL_UP; + float a_add = PHYS_JETPACK_ANTIGRAVITY * PHYS_GRAVITY; + + wishvel_x *= a_side; + wishvel_y *= a_side; + wishvel_z *= a_up; + wishvel_z += a_add; + + float best = 0; + ////////////////////////////////////////////////////////////////////////////////////// + // finding the maximum over all vectors of above form + // with wishvel having an absolute value of 1 + ////////////////////////////////////////////////////////////////////////////////////// + // we're finding the maximum over + // f(a_side, a_up, a_add, z) := a_side * (1 - z^2) + (a_add + a_up * z)^2; + // for z in the range from -1 to 1 + ////////////////////////////////////////////////////////////////////////////////////// + // maximum is EITHER attained at the single extreme point: + float a_diff = a_side * a_side - a_up * a_up; + float f; + if (a_diff != 0) + { + f = a_add * a_up / a_diff; // this is the zero of diff(f(a_side, a_up, a_add, z), z) + if (f > -1 && f < 1) // can it be attained? + { + best = (a_diff + a_add * a_add) * (a_diff + a_up * a_up) / a_diff; + //print("middle\n"); + } + } + // OR attained at z = 1: + f = (a_up + a_add) * (a_up + a_add); + if (f > best) + { + best = f; + //print("top\n"); + } + // OR attained at z = -1: + f = (a_up - a_add) * (a_up - a_add); + if (f > best) + { + best = f; + //print("bottom\n"); + } + best = sqrt(best); + ////////////////////////////////////////////////////////////////////////////////////// + + //print("best possible acceleration: ", ftos(best), "\n"); + + float fxy, fz; + fxy = bound(0, 1 - (self.velocity * normalize(wishvel_x * '1 0 0' + wishvel_y * '0 1 0')) / PHYS_JETPACK_MAXSPEED_SIDE, 1); + if (wishvel_z - PHYS_GRAVITY > 0) + fz = bound(0, 1 - self.velocity_z / PHYS_JETPACK_MAXSPEED_UP, 1); + else + fz = bound(0, 1 + self.velocity_z / PHYS_JETPACK_MAXSPEED_UP, 1); + + float fvel; + fvel = vlen(wishvel); + wishvel_x *= fxy; + wishvel_y *= fxy; + wishvel_z = (wishvel_z - PHYS_GRAVITY) * fz + PHYS_GRAVITY; + + fvel = min(1, vlen(wishvel) / best); + if (PHYS_JETPACK_FUEL && !(ITEMS(self) & IT_UNLIMITED_WEAPON_AMMO)) + f = min(1, PHYS_AMMO_FUEL(self) / (PHYS_JETPACK_FUEL * PHYS_INPUT_TIMELENGTH * fvel)); + else + f = 1; + + //print("this acceleration: ", ftos(vlen(wishvel) * f), "\n"); + + if (f > 0 && wishvel != '0 0 0') + { + self.velocity = self.velocity + wishvel * f * PHYS_INPUT_TIMELENGTH; + UNSET_ONGROUND(self); + +#ifdef SVQC + if (!(ITEMS(self) & IT_UNLIMITED_WEAPON_AMMO)) + self.ammo_fuel -= PHYS_JETPACK_FUEL * PHYS_INPUT_TIMELENGTH * fvel * f; + + ITEMS(self) |= IT_USING_JETPACK; + + // jetpack also inhibits health regeneration, but only for 1 second + self.pauseregen_finished = max(self.pauseregen_finished, time + autocvar_g_balance_pause_fuel_regen); +#endif + } + +#ifdef CSQC + float g = PHYS_GRAVITY * PHYS_ENTGRAVITY(self) * PHYS_INPUT_TIMELENGTH; + if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE) + self.velocity_z -= g * 0.5; + else + self.velocity_z -= g; + PM_ClientMovement_Move(); + if (!IS_ONGROUND(self) || !(GAMEPLAYFIX_NOGRAVITYONGROUND)) + if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE) + self.velocity_z -= g * 0.5; +#endif +} +#ifdef SVQC +void SV_WalkMove () +{ + // if PHYS_INPUT_TIMELENGTH is 0 (due to client sending the same timestamp twice), + // don't move + if (PHYS_INPUT_TIMELENGTH <= 0) + return; + +// if (autocvar_sv_gameplayfix_unstickplayers) +// SV_CheckStuck (self); + +// applygravity = !SV_CheckWater(self) && self.movetype == MOVETYPE_WALK && !(self.flags & FL_WATERJUMP); + +// hitsupercontentsmask = SV_GenericHitSuperContentsMask(self); + +// SV_CheckVelocity(self); + + // do a regular slide move unless it looks like you ran into a step +// float oldonground = self.flags & FL_ONGROUND; + + vector start_origin = self.origin; + vector start_velocity = self.velocity; + + float clip = 0; +// clip = SV_FlyMove (self, PHYS_INPUT_TIMELENGTH, applygravity, NULL, hitsupercontentsmask, sv_gameplayfix_stepmultipletimes.integer ? sv_stepheight.value : 0); + +// if(sv_gameplayfix_downtracesupportsongroundflag.integer) +// if(!(clip & 1)) + { + // only try this if there was no floor in the way in the trace (no, + // this check seems to be not REALLY necessary, because if clip & 1, + // our trace will hit that thing too) + vector upmove = self.origin; + upmove_z++; + vector downmove = self.origin; + upmove_z--; + float type; + if (self.movetype == MOVETYPE_FLYMISSILE) + type = MOVE_MISSILE; + else if (self.movetype == MOVETYPE_FLY_WORLDONLY) + type = MOVE_WORLDONLY; + else if (self.solid == SOLID_TRIGGER || self.solid == SOLID_NOT) + type = MOVE_NOMONSTERS; // only clip against bmodels + else + type = MOVE_NORMAL; + vector entmins = self.mins; + vector entmaxs = self.maxs; + tracebox(upmove, entmins, entmaxs, downmove, type, self); + if(trace_fraction < 1 && trace_plane_normal_z > 0.7) + clip |= 1; // but we HAVE found a floor + } + + // if the move did not hit the ground at any point, we're not on ground +// if(!(clip & 1)) +// self.flags = self.flags & ~FL_ONGROUND; + +// SV_CheckVelocity(self); +// SV_LinkEdict(self); +// SV_LinkEdict_TouchAreaGrid(self); + + if(clip & 8) // teleport + return; + + if (self.flags & FL_WATERJUMP) + return; + +// if (autocvar_sv_nostep) +// return; + + vector originalmove_origin = self.origin; + vector originalmove_velocity = self.velocity; + float originalmove_flags = self.flags; + entity originalmove_groundentity = self.groundentity; + + // if move didn't block on a step, return + if (clip & 2) + { + // if move was not trying to move into the step, return + if (fabs(start_velocity_x) < 0.03125 && fabs(start_velocity_y) < 0.03125) + return; + + if (self.movetype != MOVETYPE_FLY) + { + // return if gibbed by a trigger + if (self.movetype != MOVETYPE_WALK) + return; + + // return if attempting to jump while airborn (unless sv_jumpstep) +// if (!autocvar_sv_jumpstep) +// if (!oldonground && PRVM_serveredictfloat(self, waterlevel) == 0) +// return; + } + + // try moving up and forward to go up a step + // back to start pos + self.origin = start_origin; + self.velocity = start_velocity; + + // move up + vector upmove = '0 0 0'; + upmove_z = autocvar_sv_stepheight; +// if(!SV_PushEntity(&trace, self, upmove, true)) +// { +// // we got teleported when upstepping... must abort the move +// return; +// } + + // move forward + self.velocity_z = 0; +// clip = SV_FlyMove (self, PHYS_INPUT_TIMELENGTH, applygravity, stepnormal, hitsupercontentsmask, 0); + self.velocity_z += start_velocity_z; +// if(clip & 8) +// { +// // we got teleported when upstepping... must abort the move +// // note that z velocity handling may not be what QC expects here, but we cannot help it +// return; +// } + +// SV_CheckVelocity(self); +// SV_LinkEdict(self); +// SV_LinkEdict_TouchAreaGrid(self); + + // check for stuckness, possibly due to the limited precision of floats + // in the clipping hulls + if (clip + && fabs(originalmove_origin_y - self.origin_y < 0.03125) + && fabs(originalmove_origin_x - self.origin_x < 0.03125)) + { + //Con_Printf("wall\n"); + // stepping up didn't make any progress, revert to original move + self.origin = originalmove_origin; + self.velocity = originalmove_velocity; + self.flags = originalmove_flags; + self.groundentity = originalmove_groundentity; + return; + } + + //Con_Printf("step - "); + + // extra friction based on view angle +// if (clip & 2 && sv_wallfriction.integer) +// SV_WallFriction (self, stepnormal); + } + // don't do the down move if stepdown is disabled, moving upward, not in water, or the move started offground or ended onground +// else if (!autocvar_sv_gameplayfix_stepdown || self.waterlevel >= 3 || start_velocity_z >= (1.0 / 32.0) || !oldonground || (self.flags & FL_ONGROUND)) +// return; + + // move down + vector downmove = '0 0 0'; + downmove_z = -autocvar_sv_stepheight + start_velocity_z*PHYS_INPUT_TIMELENGTH; +// if(!SV_PushEntity (&downtrace, self, downmove, true)) +// { +// // we got teleported when downstepping... must abort the move +// return; +// } + + if (trace_fraction < 1 && trace_plane_normal_z > 0.7) + { + // this has been disabled so that you can't jump when you are stepping + // up while already jumping (also known as the Quake2 double jump bug) + } + else + { + //Con_Printf("slope\n"); + // if the push down didn't end up on good ground, use the move without + // the step up. This happens near wall / slope combinations, and can + // cause the player to hop up higher on a slope too steep to climb + self.origin = originalmove_origin; + self.velocity = originalmove_velocity; + self.flags = originalmove_flags; + self.groundentity = originalmove_groundentity; + } + +// SV_CheckVelocity(self); +// SV_LinkEdict(self); +// SV_LinkEdict_TouchAreaGrid(self); +} +#endif +void PM_walk(float buttons_prev, float maxspd_mod) +{ + if (!WAS_ONGROUND(self)) + { + if (autocvar_speedmeter) + dprint(strcat("landing velocity: ", vtos(self.velocity), " (abs: ", ftos(vlen(self.velocity)), ")\n")); + if (self.lastground < time - 0.3) + self.velocity *= (1 - PHYS_FRICTION_ONLAND); + if (self.jumppadcount > 1) + dprint(strcat(ftos(self.jumppadcount), "x jumppad combo\n")); + self.jumppadcount = 0; + } + // walking + makevectors(PHYS_INPUT_ANGLES(self).y * '0 1 0'); + vector wishvel = v_forward * PHYS_INPUT_MOVEVALUES(self).x + + v_right * PHYS_INPUT_MOVEVALUES(self).y; + // acceleration + vector wishdir = normalize(wishvel); + float wishspeed = vlen(wishvel); + + wishspeed = min(wishspeed, PHYS_MAXSPEED(self) * maxspd_mod); + if (IS_DUCKED(self)) + wishspeed *= 0.5; + + // apply edge friction + float f = vlen(vec2(self.velocity)); + if (f > 0) + { + float realfriction; + trace_dphitq3surfaceflags = 0; + tracebox(self.origin, self.mins, self.maxs, self.origin - '0 0 1', MOVE_NOMONSTERS, self); + // TODO: apply edge friction + // apply ground friction + if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK) + realfriction = PHYS_FRICTION_SLICK; + else + realfriction = PHYS_FRICTION; + + f = 1 - PHYS_INPUT_TIMELENGTH * realfriction * ((f < PHYS_STOPSPEED) ? (PHYS_STOPSPEED / f) : 1); + f = max(0, f); + self.velocity *= f; + /* + Mathematical analysis time! + + Our goal is to invert this mess. + + For the two cases we get: + v = v0 * (1 - PHYS_INPUT_TIMELENGTH * (PHYS_STOPSPEED / v0) * PHYS_FRICTION) + = v0 - PHYS_INPUT_TIMELENGTH * PHYS_STOPSPEED * PHYS_FRICTION + v0 = v + PHYS_INPUT_TIMELENGTH * PHYS_STOPSPEED * PHYS_FRICTION + and + v = v0 * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION) + v0 = v / (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION) + + These cases would be chosen ONLY if: + v0 < PHYS_STOPSPEED + v + PHYS_INPUT_TIMELENGTH * PHYS_STOPSPEED * PHYS_FRICTION < PHYS_STOPSPEED + v < PHYS_STOPSPEED * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION) + and, respectively: + v0 >= PHYS_STOPSPEED + v / (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION) >= PHYS_STOPSPEED + v >= PHYS_STOPSPEED * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION) + */ + } + float addspeed = wishspeed - self.velocity * wishdir; + if (addspeed > 0) + { + float accelspeed = min(PHYS_ACCELERATE * PHYS_INPUT_TIMELENGTH * wishspeed, addspeed); + self.velocity += accelspeed * wishdir; + } + float g = PHYS_GRAVITY * PHYS_ENTGRAVITY(self) * PHYS_INPUT_TIMELENGTH; + if (!(GAMEPLAYFIX_NOGRAVITYONGROUND)) + self.velocity_z -= g * (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE ? 0.5 : 1); + if (self.velocity * self.velocity) + PM_ClientMovement_Move(); + if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE) + if (!IS_ONGROUND(self) || !GAMEPLAYFIX_NOGRAVITYONGROUND) + self.velocity_z -= g * 0.5; +} + +void PM_air(float buttons_prev, float maxspd_mod) +{ + makevectors(PHYS_INPUT_ANGLES(self).y * '0 1 0'); + vector wishvel = v_forward * PHYS_INPUT_MOVEVALUES(self).x + + v_right * PHYS_INPUT_MOVEVALUES(self).y; + // acceleration + vector wishdir = normalize(wishvel); + float wishspeed = vlen(wishvel); + +#ifdef SVQC + if (time >= self.teleport_time) +#else + if (pmove_waterjumptime <= 0) +#endif + { + float maxairspd = PHYS_MAXAIRSPEED * min(maxspd_mod, 1); + + // apply air speed limit + float airaccelqw = PHYS_AIRACCEL_QW(self); + float wishspeed0 = wishspeed; + wishspeed = min(wishspeed, maxairspd); + if (IS_DUCKED(self)) + wishspeed *= 0.5; + float airaccel = PHYS_AIRACCELERATE * min(maxspd_mod, 1); + + float accelerating = (self.velocity * wishdir > 0); + float wishspeed2 = wishspeed; + + // CPM: air control + if (PHYS_AIRSTOPACCELERATE) + { + vector curdir = normalize(vec2(self.velocity)); + airaccel += (PHYS_AIRSTOPACCELERATE*maxspd_mod - airaccel) * max(0, -(curdir * wishdir)); + } + // note that for straight forward jumping: + // step = accel * PHYS_INPUT_TIMELENGTH * wishspeed0; + // accel = bound(0, wishspeed - vel_xy_current, step) * accelqw + step * (1 - accelqw); + // --> + // dv/dt = accel * maxspeed (when slow) + // dv/dt = accel * maxspeed * (1 - accelqw) (when fast) + // log dv/dt = logaccel + logmaxspeed (when slow) + // log dv/dt = logaccel + logmaxspeed + log(1 - accelqw) (when fast) + float strafity = IsMoveInDirection(PHYS_INPUT_MOVEVALUES(self), -90) + IsMoveInDirection(PHYS_INPUT_MOVEVALUES(self), +90); // if one is nonzero, other is always zero + if (PHYS_MAXAIRSTRAFESPEED) + wishspeed = min(wishspeed, GeomLerp(PHYS_MAXAIRSPEED*maxspd_mod, strafity, PHYS_MAXAIRSTRAFESPEED*maxspd_mod)); + if (PHYS_AIRSTRAFEACCELERATE) + airaccel = GeomLerp(airaccel, strafity, PHYS_AIRSTRAFEACCELERATE*maxspd_mod); + if (PHYS_AIRSTRAFEACCEL_QW(self)) + airaccelqw = + (((strafity > 0.5 ? PHYS_AIRSTRAFEACCEL_QW(self) : PHYS_AIRACCEL_QW(self)) >= 0) ? +1 : -1) + * + (1 - GeomLerp(1 - fabs(PHYS_AIRACCEL_QW(self)), strafity, 1 - fabs(PHYS_AIRSTRAFEACCEL_QW(self)))); + // !CPM + + if (PHYS_WARSOWBUNNY_TURNACCEL && accelerating && PHYS_INPUT_MOVEVALUES(self).y == 0 && PHYS_INPUT_MOVEVALUES(self).x != 0) + PM_AirAccelerate(wishdir, wishspeed2); + else + PM_Accelerate(wishdir, wishspeed, wishspeed0, airaccel, airaccelqw, PHYS_AIRACCEL_QW_STRETCHFACTOR(self), PHYS_AIRACCEL_SIDEWAYS_FRICTION / maxairspd, PHYS_AIRSPEEDLIMIT_NONQW(self)); + + if (PHYS_AIRCONTROL) + CPM_PM_Aircontrol(wishdir, wishspeed2); + } + float g = PHYS_GRAVITY * PHYS_ENTGRAVITY(self) * PHYS_INPUT_TIMELENGTH; + if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE) + self.velocity_z -= g * 0.5; + else + self.velocity_z -= g; + PM_ClientMovement_Move(); + if (!IS_ONGROUND(self) || !(GAMEPLAYFIX_NOGRAVITYONGROUND)) + if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE) + self.velocity_z -= g * 0.5; +} + +// used for calculating airshots +float PM_is_flying() +{ + if (IS_ONGROUND(self)) + return 0; + if (self.waterlevel >= WATERLEVEL_SWIMMING) + return 0; + traceline(self.origin, self.origin - '0 0 48', MOVE_NORMAL, self); + return trace_fraction >= 1; +} + +void PM_Main() +{ + float buttons = PHYS_INPUT_BUTTON_MASK(self); +#ifdef CSQC + self.team = myteam + 1; // is this correct? + if (!(PHYS_INPUT_BUTTON_JUMP(self))) // !jump + UNSET_JUMP_HELD(self); // canjump = true + pmove_waterjumptime -= PHYS_INPUT_TIMELENGTH; +#endif + PM_ClientMovement_UpdateStatus(); + +#ifdef SVQC + WarpZone_PlayerPhysics_FixVAngle(); +#endif + float maxspeed_mod = 1; + maxspeed_mod *= PM_check_keepaway(); + maxspeed_mod *= PHYS_HIGHSPEED; + +#ifdef SVQC + Physics_UpdateStats(maxspeed_mod); + + if (self.PlayerPhysplug) + if (self.PlayerPhysplug()) + return; +#endif + + PM_check_race_movetime(); +#ifdef SVQC + anticheat_physics(); +#endif + + if (PM_check_specialcommand(buttons)) + return; +#ifdef SVQC + if (sv_maxidle > 0) + { + if (buttons != self.buttons_old || PHYS_INPUT_MOVEVALUES(self) != self.movement_old || PHYS_INPUT_ANGLES(self) != self.v_angle_old) + self.parm_idlesince = time; + } +#endif + float buttons_prev = self.buttons_old; + self.buttons_old = buttons; + self.movement_old = PHYS_INPUT_MOVEVALUES(self); + self.v_angle_old = PHYS_INPUT_ANGLES(self); + + PM_check_nickspam(); + + PM_check_punch(); +#ifdef SVQC + if (IS_BOT_CLIENT(self)) + { + if (playerdemo_read()) + return; + bot_think(); + } + + if (IS_PLAYER(self)) +#endif + { +#ifdef SVQC + if (self.race_penalty) + if (time > self.race_penalty) + self.race_penalty = 0; +#endif + + float not_allowed_to_move = 0; +#ifdef SVQC + if (self.race_penalty) + not_allowed_to_move = 1; +#endif +#ifdef SVQC + if (!autocvar_sv_ready_restart_after_countdown) + if (time < game_starttime) + not_allowed_to_move = 1; +#endif + + if (not_allowed_to_move) + { + self.velocity = '0 0 0'; + self.movetype = MOVETYPE_NONE; +#ifdef SVQC + self.disableclientprediction = 2; +#endif + } +#ifdef SVQC + else if (self.disableclientprediction == 2) + { + if (self.movetype == MOVETYPE_NONE) + self.movetype = MOVETYPE_WALK; + self.disableclientprediction = 0; + } +#endif + } + +#ifdef SVQC + if (self.movetype == MOVETYPE_NONE) + return; + + // when we get here, disableclientprediction cannot be 2 + self.disableclientprediction = 0; +#endif + + PM_check_spider(); + + PM_check_frozen(); + + PM_check_blocked(); + + maxspeed_mod = 1; + +#ifdef SVQC + if (self.in_swamp) { + maxspeed_mod *= self.swamp_slowdown; //cvar("g_balance_swamp_moverate"); + } +#endif + + // conveyors: first fix velocity + if (self.conveyor.state) + self.velocity -= self.conveyor.movedir; + +#ifdef SVQC + MUTATOR_CALLHOOK(PlayerPhysics); +#endif +#ifdef CSQC + PM_multijump(); +#endif + +// float forcedodge = 1; +// if(forcedodge) { +//#ifdef CSQC +// PM_dodging_checkpressedkeys(); +//#endif +// PM_dodging(); +// PM_ClientMovement_Move(); +// return; +// } + +#ifdef SVQC + if (!IS_PLAYER(self)) + { + maxspeed_mod *= autocvar_sv_spectator_speed_multiplier; + if (!self.spectatorspeed) + self.spectatorspeed = maxspeed_mod; + if (self.impulse && self.impulse <= 19 || (self.impulse >= 200 && self.impulse <= 209) || (self.impulse >= 220 && self.impulse <= 229)) + { + if (self.lastclassname != "player") + { + if (self.impulse == 10 || self.impulse == 15 || self.impulse == 18 || (self.impulse >= 200 && self.impulse <= 209)) + self.spectatorspeed = bound(1, self.spectatorspeed + 0.5, 5); + else if (self.impulse == 11) + self.spectatorspeed = maxspeed_mod; + else if (self.impulse == 12 || self.impulse == 16 || self.impulse == 19 || (self.impulse >= 220 && self.impulse <= 229)) + self.spectatorspeed = bound(1, self.spectatorspeed - 0.5, 5); + else if (self.impulse >= 1 && self.impulse <= 9) + self.spectatorspeed = 1 + 0.5 * (self.impulse - 1); + } // otherwise just clear + self.impulse = 0; + } + maxspeed_mod *= self.spectatorspeed; + } +#endif + +#ifdef SVQC + // if dead, behave differently + // in CSQC, physics don't handle dead player + if (self.deadflag) + goto end; +#endif + +#ifdef SVQC + if (!self.fixangle && !g_bugrigs) + self.angles = '0 1 0' * PHYS_INPUT_ANGLES(self).y; +#endif + +#ifdef SVQC + if (IS_ONGROUND(self)) + if (IS_PLAYER(self)) // no fall sounds for observers thank you very much + if (self.wasFlying) + { + self.wasFlying = 0; + if (self.waterlevel < WATERLEVEL_SWIMMING) + if (time >= self.ladder_time) + if (!self.hook) + { + self.nextstep = time + 0.3 + random() * 0.1; + trace_dphitq3surfaceflags = 0; + tracebox(self.origin, self.mins, self.maxs, self.origin - '0 0 1', MOVE_NOMONSTERS, self); + if (!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOSTEPS)) + { + if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_METALSTEPS) + GlobalSound(globalsound_metalfall, CH_PLAYER, VOICETYPE_PLAYERSOUND); + else + GlobalSound(globalsound_fall, CH_PLAYER, VOICETYPE_PLAYERSOUND); + } + } + } +#endif + + if (PM_is_flying()) + self.wasFlying = 1; + +#ifdef SVQC + if (IS_PLAYER(self)) +#endif + CheckPlayerJump(); + + PM_check_jumppad(); + + if (self.flags & /* FL_WATERJUMP */ 2048) + { + self.velocity_x = self.movedir_x; + self.velocity_y = self.movedir_y; + if (time > self.teleport_time || self.waterlevel == WATERLEVEL_NONE) + { + self.flags &= ~/* FL_WATERJUMP */ 2048; + self.teleport_time = 0; + } + } + +#ifdef SVQC + else if (g_bugrigs && IS_PLAYER(self)) + RaceCarPhysics(); +#endif + + else if (self.movetype == MOVETYPE_NOCLIP || self.movetype == MOVETYPE_FLY || self.movetype == MOVETYPE_FLY_WORLDONLY) + PM_fly(maxspeed_mod); + + else if (self.waterlevel >= WATERLEVEL_SWIMMING) + PM_swim(maxspeed_mod); + + else if (time < self.ladder_time) + PM_ladder(maxspeed_mod); + + else if (ITEMS(self) & IT_USING_JETPACK) + PM_jetpack(maxspeed_mod); + + else + { + if (IS_ONGROUND(self)) + PM_walk(buttons_prev, maxspeed_mod); + else + PM_air(buttons_prev, maxspeed_mod); + } + +#ifdef SVQC + if (!IS_OBSERVER(self)) + PM_check_race(); +#endif + PM_check_vortex(); + +:end + if (IS_ONGROUND(self)) + self.lastground = time; + + // conveyors: then break velocity again + if (self.conveyor.state) + self.velocity += self.conveyor.movedir; + +#ifdef SVQC + self.lastflags = self.flags; +#elif defined(CSQC) + self.lastflags = self.pmove_flags; +#endif - ++ + self.lastclassname = self.classname; +} + +#ifdef SVQC +void SV_PlayerPhysics(void) +#elif defined(CSQC) +void CSQC_ClientMovement_PlayerMove_Frame(void) +#endif +{ + PM_Main(); - } ++} diff --cc qcsrc/common/physics.qh index a169ad4ff,000000000..9612f0cfb mode 100644,000000..100644 --- a/qcsrc/common/physics.qh +++ b/qcsrc/common/physics.qh @@@ -1,201 -1,0 +1,254 @@@ ++#ifndef COMMON_PHYSICS_H ++#define COMMON_PHYSICS_H ++ +// Client/server mappings + +.entity conveyor; + ++.float race_penalty; ++ ++.float gravity; ++.float swamp_slowdown; ++.float lastflags; ++.float lastground; ++.float wasFlying; ++.float spectatorspeed; ++ ++.vector movement_old; ++.float buttons_old; ++.vector v_angle_old; ++.string lastclassname; ++ ++.float() PlayerPhysplug; ++float AdjustAirAccelQW(float accelqw, float factor); ++ +#ifdef CSQC + ++ #include "../server/t_jumppads.qh" ++ ++ float PM_multijump_checkjump(); ++ void PM_multijump(); ++ .float speed; ++ .float watertype; ++ .float jumppadcount; ++ .float ladder_time; ++ .entity ladder_entity; ++ + float player_multijump; + float player_jumpheight; + + #define PHYS_INPUT_ANGLES(s) input_angles +// TODO + #define PHYS_WORLD_ANGLES(s) input_angles + + #define PHYS_INPUT_TIMELENGTH input_timelength + #define PHYS_INPUT_FRAMETIME serverdeltatime + + #define PHYS_INPUT_MOVEVALUES(s) input_movevalues + + #define PHYS_INPUT_BUTTON_MASK(s) (input_buttons | 128 * (input_movevalues_x < 0) | 256 * (input_movevalues_x > 0) | 512 * (input_movevalues_y < 0) | 1024 * (input_movevalues_y > 0)) + #define PHYS_INPUT_BUTTON_ATCK(s) !!(input_buttons & 1) + #define PHYS_INPUT_BUTTON_JUMP(s) !!(input_buttons & 2) + #define PHYS_INPUT_BUTTON_ATCK2(s) !!(input_buttons & 4) + #define PHYS_INPUT_BUTTON_ZOOM(s) !!(input_buttons & 8) + #define PHYS_INPUT_BUTTON_CROUCH(s) !!(input_buttons & 16) + #define PHYS_INPUT_BUTTON_HOOK(s) !!(input_buttons & 32) + #define PHYS_INPUT_BUTTON_USE(s) !!(input_buttons & 64) + #define PHYS_INPUT_BUTTON_BACKWARD(s) !!(input_buttons & 128) + #define PHYS_INPUT_BUTTON_FORWARD(s) !!(input_buttons & 256) + #define PHYS_INPUT_BUTTON_LEFT(s) !!(input_buttons & 512) + #define PHYS_INPUT_BUTTON_RIGHT(s) !!(input_buttons & 1024) + #define PHYS_INPUT_BUTTON_JETPACK(s) !!(input_buttons & 2048) + + #define PHYS_DEAD(s) s.csqcmodel_isdead + + #define GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE !!(moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE) + #define GAMEPLAYFIX_NOGRAVITYONGROUND cvar("sv_gameplayfix_nogravityonground") + #define GAMEPLAYFIX_Q2AIRACCELERATE cvar("sv_gameplayfix_q2airaccelerate") + + #define IS_DUCKED(s) !!(s.pmove_flags & PMF_DUCKED) + #define SET_DUCKED(s) s.pmove_flags |= PMF_DUCKED + #define UNSET_DUCKED(s) s.pmove_flags &= ~PMF_DUCKED + + #define IS_JUMP_HELD(s) !!(s.pmove_flags & PMF_JUMP_HELD) + #define SET_JUMP_HELD(s) s.pmove_flags |= PMF_JUMP_HELD + #define UNSET_JUMP_HELD(s) s.pmove_flags &= ~PMF_JUMP_HELD + + #define IS_ONGROUND(s) !!(s.pmove_flags & PMF_ONGROUND) + #define SET_ONGROUND(s) s.pmove_flags |= PMF_ONGROUND + #define UNSET_ONGROUND(s) s.pmove_flags &= ~PMF_ONGROUND + + #define WAS_ONGROUND(s) !!(s.lastflags & PMF_ONGROUND) + + #define ITEMS(s) getstati(STAT_ITEMS, 0, 24) + + #define PHYS_AMMO_FUEL(s) getstati(STAT_FUEL) + + #define PHYS_FROZEN(s) getstati(STAT_FROZEN) + + #define PHYS_DOUBLEJUMP getstati(STAT_DOUBLEJUMP) + + #define PHYS_JUMPSPEEDCAP_MIN getstatf(STAT_MOVEVARS_JUMPSPEEDCAP_MIN) + #define PHYS_JUMPSPEEDCAP_MAX getstatf(STAT_MOVEVARS_JUMPSPEEDCAP_MAX) + #define PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS getstati(STAT_MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS) + + #define PHYS_TRACK_CANJUMP(s) getstati(STAT_MOVEVARS_TRACK_CANJUMP) + #define PHYS_ACCELERATE getstatf(STAT_MOVEVARS_ACCELERATE) + #define PHYS_AIRACCEL_QW(s) getstatf(STAT_MOVEVARS_AIRACCEL_QW) + #define PHYS_AIRACCEL_QW_STRETCHFACTOR(s) getstatf(STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR) + #define PHYS_AIRACCEL_SIDEWAYS_FRICTION getstatf(STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION) + #define PHYS_AIRACCELERATE getstatf(STAT_MOVEVARS_AIRACCELERATE) + #define PHYS_AIRCONTROL getstatf(STAT_MOVEVARS_AIRCONTROL) + #define PHYS_AIRCONTROL_PENALTY getstatf(STAT_MOVEVARS_AIRCONTROL_PENALTY) + #define PHYS_AIRCONTROL_POWER getstatf(STAT_MOVEVARS_AIRCONTROL_POWER) + #define PHYS_AIRSPEEDLIMIT_NONQW(s) getstatf(STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW) + #define PHYS_AIRSTOPACCELERATE getstatf(STAT_MOVEVARS_AIRSTOPACCELERATE) + #define PHYS_AIRSTRAFEACCEL_QW(s) getstatf(STAT_MOVEVARS_AIRSTRAFEACCEL_QW) + #define PHYS_AIRSTRAFEACCELERATE getstatf(STAT_MOVEVARS_AIRSTRAFEACCELERATE) + #define PHYS_ENTGRAVITY(s) getstatf(STAT_MOVEVARS_ENTGRAVITY) + #define PHYS_FRICTION getstatf(STAT_MOVEVARS_FRICTION) + #define PHYS_FRICTION_SLICK getstatf(STAT_MOVEVARS_FRICTION_SLICK) + #define PHYS_FRICTION_ONLAND getstatf(STAT_MOVEVARS_FRICTION_ONLAND) + #define PHYS_GRAVITY getstatf(STAT_MOVEVARS_GRAVITY) + #define PHYS_HIGHSPEED getstatf(STAT_MOVEVARS_HIGHSPEED) + #define PHYS_JUMPVELOCITY getstatf(STAT_MOVEVARS_JUMPVELOCITY) + #define PHYS_MAXAIRSPEED getstatf(STAT_MOVEVARS_MAXAIRSPEED) + #define PHYS_MAXAIRSTRAFESPEED getstatf(STAT_MOVEVARS_MAXAIRSTRAFESPEED) + #define PHYS_MAXSPEED(s) getstatf(STAT_MOVEVARS_MAXSPEED) + #define PHYS_STEPHEIGHT getstatf(STAT_MOVEVARS_STEPHEIGHT) + #define PHYS_STOPSPEED getstatf(STAT_MOVEVARS_STOPSPEED) + #define PHYS_WARSOWBUNNY_ACCEL getstatf(STAT_MOVEVARS_WARSOWBUNNY_ACCEL) + #define PHYS_WARSOWBUNNY_BACKTOSIDERATIO getstatf(STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO) + #define PHYS_WARSOWBUNNY_AIRFORWARDACCEL getstatf(STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL) + #define PHYS_WARSOWBUNNY_TOPSPEED getstatf(STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED) + #define PHYS_WARSOWBUNNY_TURNACCEL getstatf(STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL) + + #define PHYS_JETPACK_ACCEL_UP getstatf(STAT_JETPACK_ACCEL_UP) + #define PHYS_JETPACK_ACCEL_SIDE getstatf(STAT_JETPACK_ACCEL_SIDE) + #define PHYS_JETPACK_ANTIGRAVITY getstatf(STAT_JETPACK_ANTIGRAVITY) + #define PHYS_JETPACK_FUEL getstatf(STAT_JETPACK_FUEL) + #define PHYS_JETPACK_MAXSPEED_UP getstatf(STAT_JETPACK_MAXSPEED_UP) + #define PHYS_JETPACK_MAXSPEED_SIDE getstatf(STAT_JETPACK_MAXSPEED_SIDE) + + #define PHYS_DODGING_FROZEN getstati(STAT_DODGING_FROZEN) + +#elif defined(SVQC) + ++ .float stat_sv_airaccel_qw; ++ .float stat_sv_airstrafeaccel_qw; ++ .float stat_sv_airspeedlimit_nonqw; ++ .float stat_sv_maxspeed; ++ .float stat_movement_highspeed; ++ ++ .float stat_sv_friction_on_land; ++ .float stat_sv_friction_slick; ++ ++ .float stat_doublejump; ++ ++ .float stat_jumpspeedcap_min; ++ .float stat_jumpspeedcap_max; ++ .float stat_jumpspeedcap_disable_onramps; ++ ++ .float stat_jetpack_accel_side; ++ .float stat_jetpack_accel_up; ++ .float stat_jetpack_antigravity; ++ .float stat_jetpack_fuel; ++ .float stat_jetpack_maxspeed_up; ++ .float stat_jetpack_maxspeed_side; ++ + #define PHYS_INPUT_ANGLES(s) s.v_angle + #define PHYS_WORLD_ANGLES(s) s.angles + + #define PHYS_INPUT_TIMELENGTH frametime + #define PHYS_INPUT_FRAMETIME sys_frametime + + #define PHYS_INPUT_MOVEVALUES(s) s.movement + // TODO: cache + #define PHYS_INPUT_BUTTON_MASK(s) (s.BUTTON_ATCK | 2 * s.BUTTON_JUMP | 4 * s.BUTTON_ATCK2 | 8 * s.BUTTON_ZOOM | 16 * s.BUTTON_CROUCH | 32 * s.BUTTON_HOOK | 64 * s.BUTTON_USE | 128 * (s.movement_x < 0) | 256 * (s.movement_x > 0) | 512 * (s.movement_y < 0) | 1024 * (s.movement_y > 0)) + #define PHYS_INPUT_BUTTON_ATCK(s) s.BUTTON_ATCK + #define PHYS_INPUT_BUTTON_JUMP(s) s.BUTTON_JUMP + #define PHYS_INPUT_BUTTON_ATCK2(s) s.BUTTON_ATCK2 + #define PHYS_INPUT_BUTTON_ZOOM(s) s.BUTTON_ZOOM + #define PHYS_INPUT_BUTTON_CROUCH(s) s.BUTTON_CROUCH + #define PHYS_INPUT_BUTTON_HOOK(s) s.BUTTON_HOOK + #define PHYS_INPUT_BUTTON_USE(s) s.BUTTON_USE + #define PHYS_INPUT_BUTTON_BACKWARD(s) (s.movement_x < 0) + #define PHYS_INPUT_BUTTON_FORWARD(s) (s.movement_x > 0) + #define PHYS_INPUT_BUTTON_LEFT(s) (s.movement_y < 0) + #define PHYS_INPUT_BUTTON_RIGHT(s) (s.movement_y > 0) + #define PHYS_INPUT_BUTTON_JETPACK(s) s.BUTTON_JETPACK + + #define PHYS_DEAD(s) s.deadflag != DEAD_NO + + #define GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE autocvar_sv_gameplayfix_gravityunaffectedbyticrate + #define GAMEPLAYFIX_NOGRAVITYONGROUND cvar("sv_gameplayfix_nogravityonground") + #define GAMEPLAYFIX_Q2AIRACCELERATE autocvar_sv_gameplayfix_q2airaccelerate + + #define IS_DUCKED(s) s.crouch - #define SET_DUCKED(s) s.crouch = TRUE - #define UNSET_DUCKED(s) s.crouch = FALSE ++ #define SET_DUCKED(s) s.crouch = true ++ #define UNSET_DUCKED(s) s.crouch = false + + #define IS_JUMP_HELD(s) !(s.flags & FL_JUMPRELEASED) + #define SET_JUMP_HELD(s) s.flags &= ~FL_JUMPRELEASED + #define UNSET_JUMP_HELD(s) s.flags |= FL_JUMPRELEASED + + #define IS_ONGROUND(s) !!(self.flags & FL_ONGROUND) + #define SET_ONGROUND(s) s.flags |= FL_ONGROUND + #define UNSET_ONGROUND(s) s.flags &= ~FL_ONGROUND + + #define WAS_ONGROUND(s) !!((s).lastflags & FL_ONGROUND) + + #define ITEMS(s) s.items + + #define PHYS_AMMO_FUEL(s) s.ammo_fuel + + #define PHYS_FROZEN(s) s.frozen + + #define PHYS_DOUBLEJUMP autocvar_sv_doublejump + + #define PHYS_JUMPSPEEDCAP_MIN autocvar_sv_jumpspeedcap_min + #define PHYS_JUMPSPEEDCAP_MAX autocvar_sv_jumpspeedcap_max + #define PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS autocvar_sv_jumpspeedcap_max_disable_on_ramps + + #define PHYS_TRACK_CANJUMP(s) s.cvar_cl_movement_track_canjump + #define PHYS_ACCELERATE autocvar_sv_accelerate + #define PHYS_AIRACCEL_QW(s) s.stat_sv_airaccel_qw + #define PHYS_AIRACCEL_QW_STRETCHFACTOR(s) autocvar_sv_airaccel_qw_stretchfactor + #define PHYS_AIRACCEL_SIDEWAYS_FRICTION autocvar_sv_airaccel_sideways_friction + #define PHYS_AIRACCELERATE autocvar_sv_airaccelerate + #define PHYS_AIRCONTROL autocvar_sv_aircontrol + #define PHYS_AIRCONTROL_PENALTY autocvar_sv_aircontrol_penalty + #define PHYS_AIRCONTROL_POWER autocvar_sv_aircontrol_power + #define PHYS_AIRSPEEDLIMIT_NONQW(s) s.stat_sv_airspeedlimit_nonqw + #define PHYS_AIRSTOPACCELERATE autocvar_sv_airstopaccelerate + #define PHYS_AIRSTRAFEACCEL_QW(s) s.stat_sv_airstrafeaccel_qw + #define PHYS_AIRSTRAFEACCELERATE autocvar_sv_airstrafeaccelerate + #define PHYS_ENTGRAVITY(s) s.gravity + #define PHYS_FRICTION autocvar_sv_friction + #define PHYS_FRICTION_SLICK autocvar_sv_friction_slick + #define PHYS_FRICTION_ONLAND autocvar_sv_friction_on_land + #define PHYS_GRAVITY autocvar_sv_gravity + #define PHYS_HIGHSPEED autocvar_g_movement_highspeed + #define PHYS_JUMPVELOCITY autocvar_sv_jumpvelocity + #define PHYS_MAXAIRSPEED autocvar_sv_maxairspeed + #define PHYS_MAXAIRSTRAFESPEED autocvar_sv_maxairstrafespeed + #define PHYS_MAXSPEED(s) s.stat_sv_maxspeed + #define PHYS_STEPHEIGHT autocvar_sv_stepheight + #define PHYS_STOPSPEED autocvar_sv_stopspeed + #define PHYS_WARSOWBUNNY_ACCEL autocvar_sv_warsowbunny_accel + #define PHYS_WARSOWBUNNY_BACKTOSIDERATIO autocvar_sv_warsowbunny_backtosideratio + #define PHYS_WARSOWBUNNY_AIRFORWARDACCEL autocvar_sv_warsowbunny_airforwardaccel + #define PHYS_WARSOWBUNNY_TOPSPEED autocvar_sv_warsowbunny_topspeed + #define PHYS_WARSOWBUNNY_TURNACCEL autocvar_sv_warsowbunny_turnaccel + + #define PHYS_JETPACK_ACCEL_UP autocvar_g_jetpack_acceleration_up + #define PHYS_JETPACK_ACCEL_SIDE autocvar_g_jetpack_acceleration_side + #define PHYS_JETPACK_ANTIGRAVITY autocvar_g_jetpack_antigravity + #define PHYS_JETPACK_FUEL autocvar_g_jetpack_fuel + #define PHYS_JETPACK_MAXSPEED_UP autocvar_g_jetpack_maxspeed_up + #define PHYS_JETPACK_MAXSPEED_SIDE autocvar_g_jetpack_maxspeed_side + + #define PHYS_DODGING_FROZEN autocvar_sv_dodging_frozen + - #endif ++#endif ++#endif diff --cc qcsrc/common/stats.qh index 8898ad2b2,481713cc9..261316be2 --- a/qcsrc/common/stats.qh +++ b/qcsrc/common/stats.qh @@@ -223,68 -226,69 +226,69 @@@ const int STAT_REVIVE_PROGRESS // 188 empty? // 189 empty? // 190 empty? - const float STAT_MOVEVARS_FRICTION_SLICK = 191; - const float STAT_MOVEVARS_FRICTION_ONLAND = 192; - const float STAT_MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS = 193; - const float STAT_MOVEVARS_JUMPSPEEDCAP_MAX = 194; - const float STAT_MOVEVARS_JUMPSPEEDCAP_MIN = 195; - const float STAT_DOUBLEJUMP = 196; - const float STAT_MOVEVARS_TRACK_CANJUMP = 197; - const float STAT_MULTIJUMP_ADD = 198; - const float STAT_MULTIJUMP_SPEED = 199; - const float STAT_MULTIJUMP = 200; - const float STAT_DODGING_TIMEOUT = 201; - const float STAT_DODGING_WALL = 202; - const float STAT_DODGING_UP_SPEED = 203; - const float STAT_DODGING_RAMP_TIME = 204; - const float STAT_DODGING_HEIGHT_THRESHOLD = 205; - const float STAT_DODGING_DISTANCE_THRESHOLD = 206; - const float STAT_DODGING_HORIZ_SPEED = 207; - const float STAT_DODGING_DELAY = 208; - const float STAT_DODGING_FROZEN_NO_DOUBLETAP = 209; - const float STAT_DODGING_HORIZ_SPEED_FROZEN = 210; - const float STAT_DODGING = 211; - const float STAT_DODGING_FROZEN = 212; - const float STAT_JETPACK_MAXSPEED_UP = 213; - const float STAT_JETPACK_MAXSPEED_SIDE = 214; - const float STAT_JETPACK_FUEL = 215; - const float STAT_JETPACK_ANTIGRAVITY = 216; - const float STAT_JETPACK_ACCEL_SIDE = 217; - const float STAT_JETPACK_ACCEL_UP = 218; - const float STAT_MOVEVARS_HIGHSPEED = 219; - const float STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR = 220; - const float STAT_MOVEVARS_AIRCONTROL_PENALTY = 221; - const float STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW = 222; - const float STAT_MOVEVARS_AIRSTRAFEACCEL_QW = 223; - const float STAT_MOVEVARS_AIRCONTROL_POWER = 224; - const float STAT_MOVEFLAGS = 225; - const float STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL = 226; - const float STAT_MOVEVARS_WARSOWBUNNY_ACCEL = 227; - const float STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED = 228; - const float STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL = 229; - const float STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO = 230; - const float STAT_MOVEVARS_AIRSTOPACCELERATE = 231; - const float STAT_MOVEVARS_AIRSTRAFEACCELERATE = 232; - const float STAT_MOVEVARS_MAXAIRSTRAFESPEED = 233; - const float STAT_MOVEVARS_AIRCONTROL = 234; - const float STAT_FRAGLIMIT = 235; - const float STAT_TIMELIMIT = 236; - const float STAT_MOVEVARS_WALLFRICTION = 237; - const float STAT_MOVEVARS_FRICTION = 238; - const float STAT_MOVEVARS_WATERFRICTION = 239; - const float STAT_MOVEVARS_TICRATE = 240; - const float STAT_MOVEVARS_TIMESCALE = 241; - const float STAT_MOVEVARS_GRAVITY = 242; - const float STAT_MOVEVARS_STOPSPEED = 243; - const float STAT_MOVEVARS_MAXSPEED = 244; - const float STAT_MOVEVARS_SPECTATORMAXSPEED = 245; - const float STAT_MOVEVARS_ACCELERATE = 246; - const float STAT_MOVEVARS_AIRACCELERATE = 247; - const float STAT_MOVEVARS_WATERACCELERATE = 248; - const float STAT_MOVEVARS_ENTGRAVITY = 249; - const float STAT_MOVEVARS_JUMPVELOCITY = 250; - const float STAT_MOVEVARS_EDGEFRICTION = 251; - const float STAT_MOVEVARS_MAXAIRSPEED = 252; - const float STAT_MOVEVARS_STEPHEIGHT = 253; - const float STAT_MOVEVARS_AIRACCEL_QW = 254; - const float STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION = 255; -// 191 empty? -// 192 empty? -// 193 empty? -// 194 empty? -// 195 empty? -// 196 empty? -// 197 empty? -// 198 empty? -// 199 empty? -// 200 empty? -// 201 empty? -// 202 empty? -// 203 empty? -// 204 empty? -// 205 empty? -// 206 empty? -// 207 empty? -// 208 empty? -// 209 empty? -// 210 empty? -// 211 empty? -// 212 empty? -// 213 empty? -// 214 empty? -// 215 empty? -// 216 empty? -// 217 empty? -// 218 empty? -// 219 empty? ++const int STAT_MOVEVARS_FRICTION_SLICK = 191; ++const int STAT_MOVEVARS_FRICTION_ONLAND = 192; ++const int STAT_MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS = 193; ++const int STAT_MOVEVARS_JUMPSPEEDCAP_MAX = 194; ++const int STAT_MOVEVARS_JUMPSPEEDCAP_MIN = 195; ++const int STAT_DOUBLEJUMP = 196; ++const int STAT_MOVEVARS_TRACK_CANJUMP = 197; ++const int STAT_MULTIJUMP_ADD = 198; ++const int STAT_MULTIJUMP_SPEED = 199; ++const int STAT_MULTIJUMP = 200; ++const int STAT_DODGING_TIMEOUT = 201; ++const int STAT_DODGING_WALL = 202; ++const int STAT_DODGING_UP_SPEED = 203; ++const int STAT_DODGING_RAMP_TIME = 204; ++const int STAT_DODGING_HEIGHT_THRESHOLD = 205; ++const int STAT_DODGING_DISTANCE_THRESHOLD = 206; ++const int STAT_DODGING_HORIZ_SPEED = 207; ++const int STAT_DODGING_DELAY = 208; ++const int STAT_DODGING_FROZEN_NO_DOUBLETAP = 209; ++const int STAT_DODGING_HORIZ_SPEED_FROZEN = 210; ++const int STAT_DODGING = 211; ++const int STAT_DODGING_FROZEN = 212; ++const int STAT_JETPACK_MAXSPEED_UP = 213; ++const int STAT_JETPACK_MAXSPEED_SIDE = 214; ++const int STAT_JETPACK_FUEL = 215; ++const int STAT_JETPACK_ANTIGRAVITY = 216; ++const int STAT_JETPACK_ACCEL_SIDE = 217; ++const int STAT_JETPACK_ACCEL_UP = 218; ++const int STAT_MOVEVARS_HIGHSPEED = 219; + const int STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR = 220; + const int STAT_MOVEVARS_AIRCONTROL_PENALTY = 221; + const int STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW = 222; + const int STAT_MOVEVARS_AIRSTRAFEACCEL_QW = 223; + const int STAT_MOVEVARS_AIRCONTROL_POWER = 224; + const int STAT_MOVEFLAGS = 225; + const int STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL = 226; + const int STAT_MOVEVARS_WARSOWBUNNY_ACCEL = 227; + const int STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED = 228; + const int STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL = 229; + const int STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO = 230; + const int STAT_MOVEVARS_AIRSTOPACCELERATE = 231; + const int STAT_MOVEVARS_AIRSTRAFEACCELERATE = 232; + const int STAT_MOVEVARS_MAXAIRSTRAFESPEED = 233; + const int STAT_MOVEVARS_AIRCONTROL = 234; + const int STAT_FRAGLIMIT = 235; + const int STAT_TIMELIMIT = 236; + const int STAT_MOVEVARS_WALLFRICTION = 237; + const int STAT_MOVEVARS_FRICTION = 238; + const int STAT_MOVEVARS_WATERFRICTION = 239; + const int STAT_MOVEVARS_TICRATE = 240; + const int STAT_MOVEVARS_TIMESCALE = 241; + const int STAT_MOVEVARS_GRAVITY = 242; + const int STAT_MOVEVARS_STOPSPEED = 243; + const int STAT_MOVEVARS_MAXSPEED = 244; + const int STAT_MOVEVARS_SPECTATORMAXSPEED = 245; + const int STAT_MOVEVARS_ACCELERATE = 246; + const int STAT_MOVEVARS_AIRACCELERATE = 247; + const int STAT_MOVEVARS_WATERACCELERATE = 248; + const int STAT_MOVEVARS_ENTGRAVITY = 249; + const int STAT_MOVEVARS_JUMPVELOCITY = 250; + const int STAT_MOVEVARS_EDGEFRICTION = 251; + const int STAT_MOVEVARS_MAXAIRSPEED = 252; + const int STAT_MOVEVARS_STEPHEIGHT = 253; + const int STAT_MOVEVARS_AIRACCEL_QW = 254; + const int STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION = 255; + #endif diff --cc qcsrc/csqcmodellib/cl_player.qc index d3c56c813,1f3017afd..62b60a4c4 --- a/qcsrc/csqcmodellib/cl_player.qc +++ b/qcsrc/csqcmodellib/cl_player.qc @@@ -19,13 -19,24 +19,25 @@@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ + #if defined(CSQC) + #include "../dpdefs/csprogsdefs.qh" + #include "../client/defs.qh" + #include "../common/constants.qh" + #include "../common/stats.qh" + #include "../common/util.qh" + #include "interpolate.qh" + #include "../client/main.qh" + #include "common.qh" + #include "cl_model.qh" + #include "cl_player.qh" + #elif defined(MENUQC) + #elif defined(SVQC) + #endif - var float autocvar_cl_movement_errorcompensation = 0; - var float autocvar_cl_movement = 2; // testing purposes + float autocvar_cl_movement_errorcompensation = 0; ++float autocvar_cl_movement = 2; // testing purposes // engine stuff - #define REFDEFFLAG_TELEPORTED 1 - #define REFDEFFLAG_JUMPING 2 float pmove_onground; // weird engine flag we shouldn't really use but have to for now vector csqcplayer_origin, csqcplayer_velocity; diff --cc qcsrc/dpdefs/csprogsdefs.qh index 000000000,516a8cc7c..1eddb129b mode 000000,100644..100644 --- a/qcsrc/dpdefs/csprogsdefs.qh +++ b/qcsrc/dpdefs/csprogsdefs.qh @@@ -1,0 -1,1447 +1,1448 @@@ + #ifndef CSPROGSDEFS_H + #define CSPROGSDEFS_H + /* + ============================================================================== + + SOURCE FOR GLOBALVARS_T C STRUCTURE + MUST NOT BE MODIFIED, OR CRC ERRORS WILL APPEAR + + ============================================================================== + */ + + // + // system globals + // + entity self; + entity other; + entity world; + float time; + float frametime; + + int player_localentnum; //the entnum + int player_localnum; //the playernum + float maxclients; //a constant filled in by the engine. gah, portability eh? + + float clientcommandframe; //player movement + float servercommandframe; //clientframe echoed off the server + + string mapname; + + // + // global variables set by built in functions + // + vector v_forward, v_up, v_right; // set by makevectors() + + // set by traceline / tracebox + float trace_allsolid; + float trace_startsolid; + float trace_fraction; + vector trace_endpos; + vector trace_plane_normal; + float trace_plane_dist; + entity trace_ent; + float trace_inopen; + float trace_inwater; + + // + // required prog functions + // + void() CSQC_Init; + void() CSQC_Shutdown; + float(float f, float t, float n) CSQC_InputEvent; + void(float w, float h) CSQC_UpdateView; + bool(string s) CSQC_ConsoleCommand; + + //these fields are read and set by the default player physics + vector pmove_org; + vector pmove_vel; + vector pmove_mins; + vector pmove_maxs; + //retrieved from the current movement commands (read by player physics) + float input_timelength; + vector input_angles; + vector input_movevalues; //forwards, right, up. + int input_buttons; //attack, use, jump (default physics only uses jump) + + float movevar_gravity; + float movevar_stopspeed; + float movevar_maxspeed; + float movevar_spectatormaxspeed; //used by NOCLIP movetypes. + float movevar_accelerate; + float movevar_airaccelerate; + float movevar_wateraccelerate; + float movevar_friction; + float movevar_waterfriction; + float movevar_entgravity; //the local player's gravity field. Is a multiple (1 is the normal value) + + //================================================ + void end_sys_globals; // flag for structure dumping + //================================================ + + /* + ============================================================================== + + SOURCE FOR ENTVARS_T C STRUCTURE + MUST NOT BE MODIFIED, OR CRC ERRORS WILL APPEAR + + ============================================================================== + */ + + // + // system fields (*** = do not set in prog code, maintained by C code) + // + .int modelindex; // *** model index in the precached list + .vector absmin, absmax; // *** origin + mins / maxs + + .int entnum; // *** the ent number as on the server + .float drawmask; + .void() predraw; + + .float movetype; + .float solid; + + .vector origin; // *** + .vector oldorigin; // *** + .vector velocity; + .vector angles; + .vector avelocity; + + .string classname; // spawn function + .string model; + .int frame; + .int skin; + .int effects; + + .vector mins, maxs; // bounding box extents reletive to origin + .vector size; // maxs - mins + + .void() touch; + .void() use; + .void() think; + .void() blocked; // for doors or plats, called when can't push other + + .float nextthink; + + .entity chain; + + .string netname; + + .entity enemy; + + .int flags; + + .int colormap; + + .entity owner; // who launched a missile + + //================================================ + void end_sys_fields; // flag for structure dumping + //================================================ + + /* + ============================================================================== + + OPTIONAL FIELDS AND GLOBALS + + ============================================================================== + */ + + // Additional OPTIONAL Fields and Globals + float intermission; // indicates intermission state (0 = normal, 1 = scores, 2 = finale text) + + vector view_angles; // same as input_angles + vector view_punchangle; // from server + vector view_punchvector; // from server + + /* + ============================================================================== + + CONSTANT DEFINITIONS + + ============================================================================== + */ + + const int MASK_ENGINE = 1; + const int MASK_ENGINEVIEWMODELS = 2; + const int MASK_NORMAL = 4; + + const int RF_VIEWMODEL = 1; + const int RF_EXTERNALMODEL = 2; + const int RF_DEPTHHACK = 4; + const int RF_ADDITIVE = 8; + const int RF_USEAXIS = 16; + + const int VF_MIN = 1; //(vector) + const int VF_MIN_X = 2; //(float) + const int VF_MIN_Y = 3; //(float) + const int VF_SIZE = 4; //(vector) (viewport size) + const int VF_SIZE_Y = 5; //(float) + const int VF_SIZE_X = 6; //(float) + const int VF_VIEWPORT = 7; //(vector, vector) + const int VF_FOV = 8; //(vector) + const int VF_FOVX = 9; //(float) + const int VF_FOVY = 10; //(float) + const int VF_ORIGIN = 11; //(vector) + const int VF_ORIGIN_X = 12; //(float) + const int VF_ORIGIN_Y = 13; //(float) + const int VF_ORIGIN_Z = 14; //(float) + const int VF_ANGLES = 15; //(vector) + const int VF_ANGLES_X = 16; //(float) + const int VF_ANGLES_Y = 17; //(float) + const int VF_ANGLES_Z = 18; //(float) + const int VF_DRAWWORLD = 19; //(float) + const int VF_DRAWENGINESBAR = 20; //(float) + const int VF_DRAWCROSSHAIR = 21; //(float) + + const int VF_CL_VIEWANGLES = 33; //(vector) + const int VF_CL_VIEWANGLES_X = 34; //(float) + const int VF_CL_VIEWANGLES_Y = 35; //(float) + const int VF_CL_VIEWANGLES_Z = 36; //(float) + + const int VF_PERSPECTIVE = 200; + + //const int STAT_HEALTH = 0; + //const int STAT_WEAPONMODEL = 2; + //const int STAT_AMMO = 3; + //const int STAT_ARMOR = 4; + //const int STAT_WEAPONFRAME = 5; + //const int STAT_SHELLS = 6; + //const int STAT_NAILS = 7; + //const int STAT_ROCKETS = 8; + //const int STAT_CELLS = 9; + //const int STAT_ACTIVEWEAPON = 10; + //const int STAT_TOTALSECRETS = 11; + //const int STAT_TOTALMONSTERS = 12; + //const int STAT_SECRETS = 13; + //const int STAT_MONSTERS = 14; + //const int STAT_ITEMS = 15; + //const int STAT_VIEWHEIGHT = 16; + + // Quake Sound Constants + const int CHAN_AUTO = 0; + const int CHAN_WEAPON = 1; + const int CHAN_VOICE = 2; + const int CHAN_ITEM = 3; + const int CHAN_BODY = 4; + + const int ATTN_NONE = 0; + const int ATTN_NORM = 1; + const int ATTN_IDLE = 2; + const int ATTN_STATIC = 3; + + // Frik File Constants + const int FILE_READ = 0; + const int FILE_APPEND = 1; + const int FILE_WRITE = 2; + + // Quake Point Contents + const int CONTENT_EMPTY = -1; + const int CONTENT_SOLID = -2; + const int CONTENT_WATER = -3; + const int CONTENT_SLIME = -4; + const int CONTENT_LAVA = -5; + const int CONTENT_SKY = -6; + + // Quake Solid Constants + const int SOLID_NOT = 0; + const int SOLID_TRIGGER = 1; + const int SOLID_BBOX = 2; + const int SOLID_SLIDEBOX = 3; + const int SOLID_BSP = 4; + const int SOLID_CORPSE = 5; + + // Quake Move Constants + const int MOVE_NORMAL = 0; + const int MOVE_NOMONSTERS = 1; + const int MOVE_MISSILE = 2; + + const float EXTRA_LOW = -99999999; + const float EXTRA_HIGH = 99999999; + + const vector VEC_1 = '1 1 1'; + const vector VEC_0 = '0 0 0'; + const vector VEC_M1 = '-1 -1 -1'; + + //const float M_PI = 3.14159265358979323846; + + vector VEC_HULL_MIN = '-16 -16 -24'; + vector VEC_HULL_MAX = '16 16 32'; + + // Quake Temporary Entity Constants + const int TE_SPIKE = 0; + const int TE_SUPERSPIKE = 1; + const int TE_GUNSHOT = 2; + const int TE_EXPLOSION = 3; + const int TE_TAREXPLOSION = 4; + const int TE_LIGHTNING1 = 5; + const int TE_LIGHTNING2 = 6; + const int TE_WIZSPIKE = 7; + const int TE_KNIGHTSPIKE = 8; + const int TE_LIGHTNING3 = 9; + const int TE_LAVASPLASH = 10; + const int TE_TELEPORT = 11; + const int TE_EXPLOSION2 = 12; + + // Darkplaces Additions + const int TE_EXPLOSIONRGB = 53; + const int TE_GUNSHOTQUAD = 57; + const int TE_EXPLOSIONQUAD = 70; + const int TE_SPIKEQUAD = 58; + const int TE_SUPERSPIKEQUAD = 59; + + // PFlags for Dynamic Lights + const int PFLAGS_NOSHADOW = 1; + const int PFLAGS_CORONA = 2; + const int PFLAGS_FULLDYNAMIC = 128; + + const int EF_ADDITIVE = 32; + const int EF_BLUE = 64; + const int EF_FLAME = 1024; + const int EF_FULLBRIGHT = 512; + const int EF_NODEPTHTEST = 8192; + const int EF_NODRAW = 16; + const int EF_NOSHADOW = 4096; + const int EF_RED = 128; + const int EF_STARDUST = 2048; + const int EF_SELECTABLE = 16384; + + const int PFL_ONGROUND = 1; + const int PFL_CROUCH = 2; + const int PFL_DEAD = 4; + const int PFL_GIBBED = 8; + + // draw flags + const int DRAWFLAG_NORMAL = 0; + const int DRAWFLAG_ADDITIVE = 1; + const int DRAWFLAG_MODULATE = 2; + const int DRAWFLAG_2XMODULATE = 3; + const int DRAWFLAG_SCREEN = 4; + const int DRAWFLAG_MIPMAP = 0x100; // only for R_BeginPolygon + + /* + ============================================================================== + + BUILTIN DEFINITIONS + EXTENSIONS ARE NOT ADDED HERE, BUT BELOW! + + ============================================================================== + */ + + void(vector ang) makevectors = #1; + void(entity e, vector o) setorigin = #2; + void(entity e, string m) setmodel = #3; + void(entity e, vector min, vector max) setsize = #4; + + void() break_to_debugger = #6; + float() random = #7; + void(entity e, float chan, string samp) sound = #8; + vector(vector v) normalize = #9; + void(string e) error = #10; + void(string e) objerror = #11; + float(vector v) vlen = #12; + float(vector v) vectoyaw = #13; + entity() spawn = #14; + void(entity e) remove = #15; + float(vector v1, vector v2, float tryents, entity ignoreentity) traceline = #16; + + entity(entity start, .string fld, string match) find = #18; + void(string s) precache_sound = #19; + void(string s) precache_model = #20; + + entity(vector org, float rad) findradius = #22; + + void(string s, ...) dprint = #25; + string(float f) ftos = #26; + string(vector v) vtos = #27; + void() coredump = #28; + void() traceon = #29; + void() traceoff = #30; + void(entity e) eprint = #31; + // settrace optional + float(float yaw, float dist, float settrace) walkmove = #32; + + float() droptofloor = #34; + void(float style, string value) lightstyle = #35; + int(float v) rint = #36; + int(float v) floor = #37; + int(float v) ceil = #38; + + float(entity e) checkbottom = #40; + float(vector v) pointcontents = #41; + + float(float f) fabs = #43; + + float(string s) cvar = #45; + void(string s, ...) localcmd = #46; + entity(entity e) nextent = #47; + void(vector o, vector d, float color, float count) particle = #48; + void() ChangeYaw = #49; + + vector(vector v) vectoangles = #51; + vector(vector v, vector w) vectoangles2 = #51; + + float(float f) sin = #60; + float(float f) cos = #61; + float(float f) sqrt = #62; + void(entity ent) changepitch = #63; + void(entity e, entity ignore) tracetoss = #64; + string(entity ent) etos = #65; + + string(string s) precache_file = #68; + void(entity e) makestatic = #69; + + void(string name, string value) cvar_set = #72; + + void(vector pos, string samp, float vol, float atten) ambientsound = #74; + string(string s) precache_model2 = #75; + string(string s) precache_sound2 = #76; + string(string s) precache_file2 = #77; + + float(string s) stof = #81; + + + void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox = #90; + vector() randomvec = #91; + vector(vector org) getlight = #92; + vector(vector org, float lpflags) getlight2 = #92; + vector getlight_dir; + vector getlight_ambient; + vector getlight_diffuse; + const float LP_LIGHTMAP = 1; + const float LP_RTWORLD = 2; + const float LP_DYNLIGHT = 4; + const float LP_COMPLETE = 7; + + float(string name, string value) registercvar = #93; + float( float a, ... ) min = #94; + float( float b, ... ) max = #95; + float(float minimum, float val, float maximum) bound = #96; + float(float f, float f) pow = #97; ++entity(entity start, .entity fld, entity match) findentity = #98; + entity(entity start, .float fld, float match) findfloat = #98; + float(string s) checkextension = #99; + // FrikaC and Telejano range #100-#199 + + int(string filename, int mode) fopen = #110; + void(float fhandle) fclose = #111; + string(float fhandle) fgets = #112; + void(float fhandle, string s) fputs = #113; + float(string s) strlen = #114; + string(...) strcat = #115; + string(string s, float start, float length) substring = #116; + vector(string) stov = #117; + string(string s) strzone = #118; + void(string s) strunzone = #119; + + // FTEQW range #200-#299 + + float(float number, float quantity) bitshift = #218; + + //float(string str, string sub[, float startpos]) strstrofs = #221; + int(string str, string sub, float startpos) strstrofs = #221; + int(string str, float ofs) str2chr = #222; + string(int c, ...) chr2str = #223; + string(float ccase, float calpha, float cnum, string s, ...) strconv = #224; + string(float chars, string s, ...) strpad = #225; + string(string info, string key, string value, ...) infoadd = #226; + string(string info, string key) infoget = #227; + int(string s1, string s2) strcmp = #228; + int(string s1, string s2, float len) strncmp = #228; + int(string s1, string s2) strcasecmp = #229; + int(string s1, string s2, float len) strncasecmp = #230; + + // CSQC range #300-#399 + void() clearscene = #300; + void(float mask) addentities = #301; + void(entity ent) addentity = #302; + float(float property, ...) setproperty = #303; + float(float property) getproperty = #309; + vector(float property) getpropertyvec = #309; + void() renderscene = #304; + void(vector org, float radius, vector lightcolours) adddynamiclight = #305; + void(vector org, float radius, vector lightcolours, float style, string cubemapname, float pflags) adddynamiclight2 = #305; + //void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon = #306; + void(string texturename, float flag, ...) R_BeginPolygon = #306; + void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex = #307; + void() R_EndPolygon = #308; + vector (vector v) cs_unproject = #310; + vector (vector v) cs_project = #311; + + void(float width, vector pos1, vector pos2, float flag) drawline = #315; + float(string name) iscachedpic = #316; + string(string name, ...) precache_pic = #317; + string(string name) precache_cubemap = #317; + vector(string picname) draw_getimagesize = #318; + void(string name) freepic = #319; + float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter = #320; + float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring = #321; + float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic = #322; + float(vector position, vector size, vector rgb, float alpha, float flag) drawfill = #323; + void(float x, float y, float width, float height) drawsetcliparea = #324; + void(void) drawresetcliparea = #325; + float(vector position, string text, vector scale, float alpha, float flag) drawcolorcodedstring = #326; + vector(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawcolorcodedstring2 = #326; + + float(int stnum) getstatf = #330; + int(int stnum, ...) getstati = #331; // can optionally take first bit and count + string(float firststnum) getstats = #332; + void(entity e, float mdlindex) setmodelindex = #333; + string(float mdlindex) modelnameforindex = #334; + int(string effectname) particleeffectnum = #335; + void(entity ent, float effectnum, vector start, vector end) trailparticles = #336; + //void(float effectnum, vector origin [, vector dir, float count]) pointparticles = #337; + void(float effectnum, vector origin , vector dir, float count) pointparticles = #337; + void(string s, ...) centerprint = #338; + void(string s, ...) print = #339; + string(float keynum) keynumtostring = #340; + float(string keyname) stringtokeynum = #341; + string(float keynum) getkeybind = #342; + void(float usecursor) setcursormode = #343; + vector() getmousepos = #344; + float(float framenum) getinputstate = #345; + void(float sens) setsensitivityscale = #346; + void(...) runstandardplayerphysics = #347; // this may or may not take a player ent + string(float playernum, string keyname) getplayerkeyvalue = #348; + float() isdemo = #349; + float() isserver = #350; + void(vector origin, vector forward, vector right, vector up) SetListener = #351; + void(string cmdname) registercommand = #352; + float(entity ent) wasfreed = #353; + string(string key) serverkey = #354; + + // Use proper case; refer to the id1 Write* functions! + int() ReadByte = #360; + int() ReadChar = #361; + int() ReadShort = #362; + int() ReadLong = #363; + float() ReadCoord = #364; + float() ReadAngle = #365; + string() ReadString = #366; + float() ReadFloat = #367; + + // LordHavoc's range #400-#499 + void(entity from, entity to) copyentity = #400; + + entity(.string fld, string match) findchain = #402; + entity(.float fld, float match) findchainfloat = #403; + void(vector org, string modelname, float startframe, float endframe, float framerate) effect = #404; + void(vector org, vector velocity, float howmany) te_blood = #405; + void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower = #406; + void(vector org, vector color) te_explosionrgb = #407; + void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube = #408; + void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain = #409; + void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow = #410; + void(vector org, vector vel, float howmany) te_spark = #411; + void(vector org) te_gunshotquad = #412; + void(vector org) te_spikequad = #413; + void(vector org) te_superspikequad = #414; + void(vector org) te_explosionquad = #415; + void(vector org) te_smallflash = #416; + void(vector org, float radius, float lifetime, vector color) te_customflash = #417; + void(vector org) te_gunshot = #418; + void(vector org) te_spike = #419; + void(vector org) te_superspike = #420; + void(vector org) te_explosion = #421; + void(vector org) te_tarexplosion = #422; + void(vector org) te_wizspike = #423; + void(vector org) te_knightspike = #424; + void(vector org) te_lavasplash = #425; + void(vector org) te_teleport = #426; + void(vector org, float colorstart, float colorlength) te_explosion2 = #427; + void(entity own, vector start, vector end) te_lightning1 = #428; + void(entity own, vector start, vector end) te_lightning2 = #429; + void(entity own, vector start, vector end) te_lightning3 = #430; + void(entity own, vector start, vector end) te_beam = #431; + void(vector dir) vectorvectors = #432; + void(vector org) te_plasmaburn = #433; + //float(entity e, float s) getsurfacenumpoints = #434; + //vector(entity e, float s, float n) getsurfacepoint = #435; + //vector(entity e, float s) getsurfacenormal = #436; + //string(entity e, float s) getsurfacetexture = #437; + //float(entity e, vector p) getsurfacenearpoint = #438; + //vector(entity e, float s, vector p) getsurfaceclippedpoint = #439; + + int(string s) tokenize = #441; + string(float n) argv = #442; + void(entity e, entity tagentity, string tagname) setattachment = #443; + float(string pattern, float caseinsensitive, float quiet) search_begin = #444; + void(float handle) search_end = #445; + float(float handle) search_getsize = #446; + string(float handle, float num) search_getfilename = #447; + string(string s) cvar_string = #448; + entity(entity start, .float fld, float match) findflags = #449; + entity(.float fld, float match) findchainflags = #450; + int(entity ent, string tagname) gettagindex = #451; + vector(entity ent, float tagindex) gettaginfo = #452; + + void(vector org, vector vel, float howmany) te_flamejet = #457; + + entity(float num) entitybyindex = #459; + int() buf_create = #460; + void(float bufhandle) buf_del = #461; + float(float bufhandle) buf_getsize = #462; + void(float bufhandle_from, float bufhandle_to) buf_copy = #463; + void(float bufhandle, float sortpower, float backward) buf_sort = #464; + string(float bufhandle, string glue) buf_implode = #465; + string(float bufhandle, float string_index) bufstr_get = #466; + void(float bufhandle, float string_index, string str) bufstr_set = #467; + float(float bufhandle, string str, float order) bufstr_add = #468; + void(float bufhandle, float string_index) bufstr_free = #469; + + //float(float s) asin = #471; + //float(float c) acos = #472; + //float(float t) atan = #473; + //float(float c, float s) atan2 = #474; + //float(float a) tan = #475; + float(string s) strippedstringlen = #476; + float(string s) strlennocol = #476; // This is the correct name for the function, but not removing the decolorizedstring mapping. + string(string s) decolorizedstring = #477; + string(string s) strdecolorize = #477; // This is the correct name for the function, but not removing the decolorizedstring mapping. + string(float uselocaltime, string format, ...) strftime = #478; + string(string s) strtolower = #480; + string(string s) strtoupper = #481; + string(string s) cvar_defstring = #482; + void(vector origin, string sample, float volume, float attenuation) pointsound = #483; + string(string search, string replace, string subject) strreplace = #484; + string(string search, string replace, string subject) strireplace = #485; + //vector(entity e, float s, float n, float a) getsurfacepointattribute = #486; + #ifdef SUPPORT_GECKO + float gecko_create( string name ) = #487; + void gecko_destroy( string name ) = #488; + void gecko_navigate( string name, string URI ) = #489; + float gecko_keyevent( string name, float key, float eventtype ) = #490; + void gecko_mousemove( string name, float x, float y ) = #491; + void gecko_resize( string name, float w, float h ) = #492; + vector gecko_get_texture_extent( string name ) = #493; + #else + + #endif + + /* + ============================================================================== + + EXTENSION DEFINITIONS + + ============================================================================== + */ + + // DP_CSQC_SPAWNPARTICLE + // idea: VorteX + // darkplaces implementation: VorteX + // constant definitions: + // particle base behavior: + float PT_ALPHASTATIC = 1; + float PT_STATIC = 2; + float PT_SPARK = 3; + float PT_BEAM = 4; + float PT_RAIN = 5; + float PT_RAINDECAL = 6; + float PT_SNOW = 7; + float PT_BUBBLE = 8; + float PT_BLOOD = 9; + float PT_SMOKE = 10; + float PT_DECAL = 11; + float PT_ENTITYPARTICLE = 12; + // particle blendtypes: + float PBLEND_ALPHA = 0; + float PBLEND_ADD = 1; + float PBLEND_INVMOD = 2; + // particle orientation: + float PARTICLE_BILLBOARD = 0; + float PARTICLE_SPARK = 1; + float PARTICLE_ORIENTED_DOUBLESIDED = 2; + float PARTICLE_BEAM = 3; + // global definitions: + float particle_type; // one of PT_ + float particle_blendmode; // one of PBLEND_ values + float particle_orientation; // one of PARTICLE_ values + vector particle_color1; + vector particle_color2; + float particle_tex; // number of chunk in particlefont + float particle_size; + float particle_sizeincrease; + float particle_alpha; + float particle_alphafade; + float particle_time; + float particle_gravity; + float particle_bounce; + float particle_airfriction; + float particle_liquidfriction; + float particle_originjitter; + float particle_velocityjitter; + float particle_qualityreduction; // enable culling of this particle when FPS is low + float particle_stretch; + vector particle_staincolor1; + vector particle_staincolor2; + float particle_staintex; + float particle_stainalpha; + float particle_stainsize; + float particle_delayspawn; + float particle_delaycollision; + float particle_angle; + float particle_spin; + // builtin definitions: + float(float max_themes) initparticlespawner = #522; // check fields/globals for integration and enable particle spawner, return 1 is succeded, otherwise returns 0 + void() resetparticle = #523; // reset p_ globals to default theme #0 + void(float theme) particletheme = #524; // restore p_ globals from saved theme + float() particlethemesave = #525; // save p_ globals to new particletheme and return it's index + void(float theme) particlethemeupdate = #525; // save p_ globals to new particletheme and return it's index + void(float theme) particlethemefree = #526; // delete a particle theme + float(vector org, vector vel) spawnparticle = #527; // returns 0 when failed, 1 when spawned + float(vector org, vector vel, float theme) quickparticle = #527; // not reading globals, just theme, returns 0 when failed, 1 when spawned + float(vector org, vector vel, float delay, float collisiondelay) delayedparticle = #528; + float(vector org, vector vel, float delay, float collisiondelay, float theme) quickdelayedparticle = #528; + // description: this builtin provides an easy and flexible way to spawn particles, + // it is not created as replace for DP_SV_POINTPARTICLES but as an addition to it. + // With this extension you can create a specific particles like rain particles, or entity particles + // notes: + // 1) 0 is default particle template, it could be changed + // 2) color vectors could have value 0-255 of each component + // restrictions: max themes could be between 4 and 2048 + // warning: you should call initparticlespawner() at very beginning BEFORE all other particle spawner functions + // function to query particle info + // don't remove this function as it protects all particle_ globals from FTEQCC/FRIKQCC non-referenced removal optimisation + void() printparticle = + { + // vortex: this also protects from 'non-referenced' optimisation on some compilers + print("PARTICLE:\n"); + print(strcat(" type: ", ftos(particle_type), "\n")); + print(strcat(" blendmode: ", ftos(particle_blendmode), "\n")); + print(strcat(" orientation: ", ftos(particle_orientation), "\n")); + print(strcat(" color1: ", vtos(particle_color1), "\n")); + print(strcat(" color2: ", vtos(particle_color2), "\n")); + print(strcat(" tex: ", ftos(particle_tex), "\n")); + print(strcat(" size: ", ftos(particle_size), "\n")); + print(strcat(" sizeincrease: ", ftos(particle_sizeincrease), "\n")); + print(strcat(" alpha: ", ftos(particle_alpha), "\n")); + print(strcat(" alphafade: ", ftos(particle_alphafade), "\n")); + print(strcat(" time: ", ftos(particle_time), "\n")); + print(strcat(" gravity: ", ftos(particle_gravity), "\n")); + print(strcat(" bounce: ", ftos(particle_bounce), "\n")); + print(strcat(" airfriction: ", ftos(particle_airfriction), "\n")); + print(strcat(" liquidfriction: ", ftos(particle_liquidfriction), "\n")); + print(strcat(" originjitter: ", ftos(particle_originjitter), "\n")); + print(strcat(" velocityjitter: ", ftos(particle_velocityjitter), "\n")); + print(strcat(" qualityreduction: ", ftos(particle_qualityreduction), "\n")); + print(strcat(" stretch: ", ftos(particle_stretch), "\n")); + print(strcat(" staincolor1: ", vtos(particle_staincolor1), "\n")); + print(strcat(" staincolor2: ", vtos(particle_staincolor2), "\n")); + print(strcat(" staintex: ", ftos(particle_staintex), "\n")); + print(strcat(" stainalpha: ", ftos(particle_stainalpha), "\n")); + print(strcat(" stainsize: ", ftos(particle_stainsize), "\n")); + print(strcat(" delayspawn: ", ftos(particle_delayspawn), "\n")); + print(strcat(" delaycollision: ", ftos(particle_delaycollision), "\n")); + print(strcat(" angle: ", ftos(particle_angle), "\n")); + print(strcat(" spin: ", ftos(particle_spin), "\n")); + } + + // DP_CSQC_ENTITYTRANSPARENTSORTING_OFFSET + // idea: VorteX + // darkplaces implementation: VorteX + float RF_USETRANSPARENTOFFSET = 64; // enables transparent origin offsetting + // global definitions + float transparent_offset; // should be set before entity is added + // description: offset a model's meshes origin used for transparent sorting. Could be used to tweak sorting bugs on very large transparent entities or hacking transparent sorting order for certain objects + // example: transparent_offset = 1000000; // entity always appear on background of other transparents + // note: offset is done in view forward axis + + // DP_CSQC_ENTITYWORLDOBJECT + // idea: VorteX + // darkplaces implementation: VorteX + const float RF_WORLDOBJECT = 128; + // description: when renderflag is set, engine will not use culling methods for this entity, e.g. it will always be drawn + // useful for large outdoor objects (like asteroids on sky horizon or sky models) + + // DP_CSQC_ENTITYMODELLIGHT + // idea: VorteX + // darkplaces implementation: VorteX + const float RF_MODELLIGHT = 4096; + .vector modellight_ambient; + .vector modellight_diffuse; + .vector modellight_dir; + // description: allows CSQC to override directional model lightning on entity + + // DP_CSQC_SETPAUSE + // idea: VorteX + // darkplaces implementation: VorteX + // builtin definitions: + void(float ispaused) setpause = #531; + // description: provides ability to set pause in local games (similar to one set once console is activated) + // not stopping sound/cd track, useful for inventory screens, ingame menus with input etc. + + // DP_CSQC_QUERYRENDERENTITY + // idea: VorteX + // darkplaces implementation: VorteX + // constant definitions: + // render entity fields: + float E_ACTIVE = 0; // float 0/1 + float E_ORIGIN = 1; // vector + float E_FORWARD = 2; // vector + float E_RIGHT = 3; // vector + float E_UP = 4; // vector + float E_SCALE = 5; // float + float E_ORIGINANDVECTORS = 6; // returns origin, + sets v_* vectors to orientation + float E_ALPHA = 7; // float + float E_COLORMOD = 8; // vector + float E_PANTSCOLOR = 9; // vector + float E_SHIRTCOLOR = 10; // vector + float E_SKIN = 11; // float + float E_MINS = 12; // vector + float E_MAXS = 13; // vector + float E_ABSMIN = 14; // vector + float E_ABSMAX = 15; // vector + float E_LIGHT = 16; // vector - modellight + // builtin definitions: + float(float entitynum, float fldnum) getentity = #504; + vector(float entitynum, float fldnum) getentityvec = #504; + // description: allows to query parms from render entities, especially useful with attaching CSQC ents to + // server entities networked and interpolated by engine (monsters, players), number of entity is it's SVQC number + // you can send it via tempentity/CSQC entity message. Note that this builtin doesnt know about entity removing/reallocating + // so it's meaning to work for short period of time, dont use it on missiles/grenades whatever will be removed next five seconds + + //DP_GFX_FONTS + //idea: Blub\0, divVerent + //darkplaces implementation: Blub\0 + //console commands: + // loadfont fontname fontmaps size1 size2 ... + // A font can simply be gfx/tgafile (freetype fonts doent need extension), + // or alternatively you can specify multiple fonts and faces + // Like this: gfx/vera-sans:2,gfx/fallback:1 + // to load face 2 of the font gfx/vera-sans and use face 1 + // of gfx/fallback as fallback font + // You can also specify a list of font sizes to load, like this: + // loadfont console gfx/conchars,gfx/fallback 8 12 16 24 32 + // In many cases, 8 12 16 24 32 should be a good choice. + // for slots see: + //constant definitions: + float drawfont; // set it before drawstring()/drawchar() calls + float FONT_DEFAULT = 0; // 'default' + float FONT_CONSOLE = 1; // 'console', REALLY should be fixed width (ls!) + float FONT_SBAR = 2; // 'sbar', used on hud, must be fixed width + float FONT_NOTIFY = 3; // 'notify', used on sprint/bprint + float FONT_CHAT = 4; // 'chat' + float FONT_CENTERPRINT = 5;// 'centerprint' + float FONT_INFOBAR = 6; // 'infobar' + float FONT_MENU = 7; // 'menu', should be fixed width + float FONT_USER0 = 8; // 'user0', userdefined fonts + float FONT_USER1 = 9; // 'user1', userdefined fonts + float FONT_USER2 = 10; // 'user2', userdefined fonts + float FONT_USER3 = 11; // 'user3', userdefined fonts + float FONT_USER4 = 12; // 'user4', userdefined fonts + float FONT_USER5 = 13; // 'user5', userdefined fonts + float FONT_USER6 = 14; // 'user6', userdefined fonts + float FONT_USER7 = 15; // 'user7' slot, userdefined fonts + //builtin definitions: + float findfont(string s) = #356; // find font by fontname and return it's index + float loadfont(string fontname, string fontmaps, string sizes, float slot, float fix_scale, float fix_voffset) = #357; + // loads font immediately so stringwidth() function can be used just after builtin call + // returns a font slotnum (which is used to set drawfont to) + // first 3 parms are identical to "loadfont" console command ones + // slot could be one of FONT_ constants or result of findfont() or -1 to not use it + // if slot is given, font will be loaded to this slotnum and fontname become new title for it + // this way you can rename user* fonts to something more usable + // fix_* parms let you fix badly made fonts by applying some transformations to them + // fix_scale : per-character center-oriented scale (doesn't change line height at all) + // fix_voffset : vertical offset for each character, it's a multiplier to character height + float stringwidth(string text, float allowColorCodes, vector size) = #327; // get a width of string with given font and char size + float stringwidth_menu(string text, float allowColorCodes, vector size) = #468; // in menu.dat it has different builtin # + //description: engine support for custom fonts in console, hud, qc etc. + // limits: + // max 128 chars for font name + // max 3 font fallbacks + // max 8 sizes per font + + //DP_GFX_FONTS_FREETYPE + //idea: Blub\0, divVerent + //darkplaces implementation: Blub\0 + //cvar definitions: + // r_font_disable_freetype 0/1 : disable freetype fonts loading (uttetly disables freetype library initialization) + // r_font_antialias 0/1 : antialiasing when loading font + // r_font_hint 0/1/2/3 : hinting when loading font, 0 is no hinting, 1 light autohinting , 2 full autohinting, 3 full hinting + // r_font_postprocess_blur X : font outline blur amount + // r_font_postprocess_outline X : font outline width + // r_font_postprocess_shadow_x X : font outline shadow x shift amount, applied during outlining + // r_font_postprocess_shadow_y X : font outline shadow y shift amount, applied during outlining + // r_font_postprocess_shadow_z X : font outline shadow z shift amount, applied during blurring + //description: engine support for truetype/freetype fonts + //so .AFM+.PFB/.OTF/.TTF files could be stuffed as fontmaps in loadfont() + //(console command version will support them as well) + + //DP_CSQC_BINDMAPS + //idea: daemon, motorsep + //darkplaces implementation: divVerent + //builtin definitions: + string(float key, float bindmap) getkeybind_bindmap = #342; + float(float key, string bind, float bindmap) setkeybind_bindmap = #630; + vector(void) getbindmaps = #631; + float(vector bm) setbindmaps = #632; + string(string command, float bindmap) findkeysforcommand = #610; + // float(string key) stringtokeynum = #341; + // string(float keynum) keynumtostring = #340; + //description: key bind setting/getting including support for switchable + //bindmaps. + + //DP_CRYPTO + //idea: divVerent + //darkplaces implementation: divVerent + //builtin definitions: (CSQC) + float(string url, float id, string content_type, string delim, float buf, float keyid) crypto_uri_postbuf = #513; + //description: + //use -1 as buffer handle to justs end delim as postdata + + //DP_CSQC_MAINVIEW + //idea: divVerent + //darkplaces implementation: divVerent + //constant definitions: + const int VF_MAINVIEW = 400; + //use setproperty(VF_MAINVIEW, 1); before calling R_RenderView for the render + //that shall become the "main" view, which is e.g. used by PRYDON_CLIENTCURSOR + //this flag is set for the first scene, and not cleared by R_ClearScene + //this flag is automatically cleared by R_RenderView + //so when not using this extension, the first view rendered is the main view + + //DP_CSQC_MINFPS_QUALITY + //idea: divVerent + //darkplaces implementation: divVerent + //constant definitions: + const int VF_MINFPS_QUALITY = 401; + //use getproperty(VF_MINFPS_QUALITY); to do CSQC based LOD based on cl_minfps + //1 should lead to an unmodified view + + //DP_CSQC_V_CALCREFDEF_WIP1 + //DP_CSQC_V_CALCREFDEF_WIP2 + //idea: divVerent + //darkplaces implementation: divVerent + //builtin definitions: + void(entity e, float refdefflags) V_CalcRefdef = #640; + //constant definitions: + const int PMF_DUCKED = 4; + const int PMF_ONGROUND = 8; + const int REFDEFFLAG_TELEPORTED = 1; + const int REFDEFFLAG_JUMPING = 2; + const int REFDEFFLAG_DEAD = 4; + const int REFDEFFLAG_INTERMISSION = 8; + //- use this on the player entity after performing prediction + //- pass REFDEFFLAG_TELEPORTED if the player teleported since last frame + //- pass REFDEFFLAG_JUMPING if jump button is pressed + //- pass REFDEFFLAG_DEAD if dead (DP_CSQC_V_CALCREFDEF_WIP2) + //- pass REFDEFFLAG_INTERMISSION if in intermission (DP_CSQC_V_CALCREFDEF_WIP2) + //- the player entity needs to have origin, velocity, pmove_flags set according + // to prediction (the above two PMF_ flags are used in the player's pmove_flags) + //- NOTE: to check for this, ALSO OR a check with DP_CSQC_V_CALCREFDEF to also support + // the finished extension once done + + // assorted builtins + float drawsubpic(vector position, vector size, string pic, vector srcPosition, vector srcSize, vector rgb, float alpha, float flag) = #328; + vector drawgetimagesize(string pic) = #318; + const float SPA_POSITION = 0; + const float SPA_S_AXIS = 1; + const float SPA_T_AXIS = 2; + const float SPA_R_AXIS = 3; + const float SPA_TEXCOORDS0 = 4; + const float SPA_LIGHTMAP0_TEXCOORDS = 5; + const float SPA_LIGHTMAP_COLOR = 6; + float (entity e, float s) getsurfacenumpoints = #434; + vector (entity e, float s, float n) getsurfacepoint = #435; + vector (entity e, float s) getsurfacenormal = #436; + string (entity e, float s) getsurfacetexture = #437; + float (entity e, vector p) getsurfacenearpoint = #438; + vector (entity e, float s, vector p) getsurfaceclippedpoint = #439; + vector(entity e, float s, float n, float a) getsurfacepointattribute = #486; + float(entity e, float s) getsurfacenumtriangles = #628; + vector(entity e, float s, float n) getsurfacetriangle = #629; + + //DP_QC_ASINACOSATANATAN2TAN + //idea: Urre + //darkplaces implementation: LordHavoc + //constant definitions: + float DEG2RAD = 0.0174532925199432957692369076848861271344287188854172545609719144; + float RAD2DEG = 57.2957795130823208767981548141051703324054724665643215491602438612; + float PI = 3.1415926535897932384626433832795028841971693993751058209749445923; + //builtin definitions: + float(float s) asin = #471; // returns angle in radians for a given sin() value, the result is in the range -PI*0.5 to PI*0.5 + float(float c) acos = #472; // returns angle in radians for a given cos() value, the result is in the range 0 to PI + float(float t) atan = #473; // returns angle in radians for a given tan() value, the result is in the range -PI*0.5 to PI*0.5 + float(float c, float s) atan2 = #474; // returns angle in radians for a given cos() and sin() value pair, the result is in the range -PI to PI (this is identical to vectoyaw except it returns radians rather than degrees) + float(float a) tan = #475; // returns tangent value (which is simply sin(a)/cos(a)) for the given angle in radians, the result is in the range -infinity to +infinity + //description: + //useful math functions for analyzing vectors, note that these all use angles in radians (just like the cos/sin functions) not degrees unlike makevectors/vectoyaw/vectoangles, so be sure to do the appropriate conversions (multiply by DEG2RAD or RAD2DEG as needed). + //note: atan2 can take unnormalized vectors (just like vectoyaw), and the function was included only for completeness (more often you want vectoyaw or vectoangles), atan2(v_x,v_y) * RAD2DEG gives the same result as vectoyaw(v) + + //DP_QC_SPRINTF + //idea: divVerent + //darkplaces implementation: divVerent + //builtin definitions: + string(string format, ...) sprintf = #627; + //description: + //you know sprintf :P + //supported stuff: + // % + // optional: $ for the argument to format + // flags: #0- + + // optional: , *, or *$ for the field width + // optional: ., .*, or .*$ for the precision + // length modifiers: h for forcing a float, l for forcing an int/entity (by default, %d etc. cast a float to int) + // conversions: + // d takes a float if no length is specified or h is, and an int/entity if l is specified as length, and cast it to an int + // i takes an int/entity if no length is specified or i is, and a float if h is specified as length, and cast it to an int + // ouxXc take a float if no length is specified or h is, and an int/entity if l is specified as length, and cast it to an unsigned int + // eEfFgG take a float if no length is specified or h is, and an int/entity if l is specified as length, and cast it to a double + // s takes a string + // vV takes a vector, and processes the three components as if it were a gG for all three components, separated by space + // For conversions s and c, the flag # makes precision and width interpreted + // as byte count, by default it is interpreted as character count in UTF-8 + // enabled engines. No other conversions can create wide characters, and # + // has another meaning in these. + + //DP_QC_GETTIME + //idea: tZork + //darkplaces implementation: tZork, divVerent + //constant definitions: + float GETTIME_FRAMESTART = 0; // time of start of frame + float GETTIME_REALTIME = 1; // current time (may be OS specific) + float GETTIME_HIRES = 2; // like REALTIME, but may reset between QC invocations and thus can be higher precision + float GETTIME_UPTIME = 3; // time since start of the engine + //builtin definitions: + float(float tmr) gettime = #519; + //description: + //some timers to query... + + //DP_QC_GETTIME_CDTRACK + //idea: divVerent + //darkplaces implementation: divVerent + //constant definitions: + float GETTIME_CDTRACK = 4; + //description: + //returns the playing time of the current cdtrack when passed to gettime() + //see DP_END_GETSOUNDTIME for similar functionality but for entity sound channels + + //DP_QC_TOKENIZEBYSEPARATOR + //idea: Electro, SavageX, LordHavoc + //darkplaces implementation: LordHavoc + //builtin definitions: + int(string s, string separator1, ...) tokenizebyseparator = #479; + //description: + //this function returns tokens separated by any of the supplied separator strings, example: + //numnumbers = tokenizebyseparator("10.2.3.4", "."); + //returns 4 and the tokens are "10" "2" "3" "4" + //possibly useful for parsing IPv4 addresses (such as "1.2.3.4") and IPv6 addresses (such as "[1234:5678:9abc:def0:1234:5678:9abc:def0]:26000") + + //DP_QC_TOKENIZE_CONSOLE + //idea: divVerent + //darkplaces implementation: divVerent + //builtin definitions: + int(string s) tokenize_console = #514; + int(float i) argv_start_index = #515; + int(float i) argv_end_index = #516; + //description: + //this function returns tokens separated just like the console does + //also, functions are provided to get the index of the first and last character of each token in the original string + //Passing negative values to them, or to argv, will be treated as indexes from the LAST token (like lists work in Perl). So argv(-1) will return the LAST token. + + //DP_SND_SOUND7_WIP1 + //DP_SND_SOUND7_WIP2 + //idea: divVerent + //darkplaces implementation: divVerent + //builtin definitions: + void(entity e, float chan, string samp, float vol, float atten, float speed, float flags) sound7 = #8; + float SOUNDFLAG_RELIABLE = 1; + //description: + //plays a sound, with some more flags + //extensions to sound(): + //- channel may be in the range from -128 to 127; channels -128 to 0 are "auto", + // i.e. support multiple sounds at once, but cannot be stopped/restarted + //- a value 0 in the speed parameter means no change; otherwise, it is a + // percentage of playback speed ("pitch shifting"). 100 is normal pitch, 50 is + // half speed, 200 is double speed, etc. (DP_SND_SOUND7_WIP2) + //- the flag SOUNDFLAG_RELIABLE can be specified, which makes the sound send + // to MSG_ALL (reliable) instead of MSG_BROADCAST (unreliable, default); + // similarily, SOUNDFLAG_RELIABLE_TO_ONE sends to MSG_ONE + //- channel 0 is controlled by snd_channel0volume; channel 1 and -1 by + // snd_channel1volume, etc. (so, a channel shares the cvar with its respective + // auto-channel); however, the mod MUST define snd_channel8volume and upwards + // in default.cfg if they are to be used, as the engine does not create them + // to not litter the cvar list + //- this extension applies to CSQC as well; CSQC_Event_Sound will get speed and + // flags as extra 7th and 8th argument + //- WIP2 ideas: SOUNDFLAG_RELIABLE_TO_ONE, SOUNDFLAG_NOPHS, SOUNDFLAG_FORCELOOP + //- NOTE: to check for this, ALSO OR a check with DP_SND_SOUND7 to also support + // the finished extension once done + + //DP_PRECACHE_PIC_FLAGS + //idea: divVerent + //darkplaces implementation: divVerent + //constant definitions: + float PRECACHE_PIC_FROMWAD = 1; // this one actually is part of EXT_CSQC + float PRECACHE_PIC_NOTPERSISTENT = 2; // picture may get deallocated when unused + float PRECACHE_PIC_MIPMAP = 8; // mipmap the texture for possibly better downscaling at memory expense + //notes: these constants are given as optional second argument to precache_pic() + + //DP_QC_TRACE_MOVETYPE_WORLDONLY + //idea: LordHavoc + //darkplaces implementation: LordHavoc + //constant definitions: + float MOVE_WORLDONLY = 3; + //description: + //allows traces to hit only world (ignoring all entities, unlike MOVE_NOMONSTERS which hits all bmodels), use as the nomonsters parameter to trace functions + + //DP_SND_GETSOUNDTIME + //idea: VorteX + //darkplaces implementation: VorteX + //constant definitions: + float(entity e, float channel) getsoundtime = #533; // get currently sound playing position on entity channel, -1 if not playing or error + float(string sample) soundlength = #534; // returns length of sound sample in seconds, -1 on error (sound not precached, sound system not initialized etc.) + //description: provides opportunity to query length of sound samples and realtime tracking of sound playing on entities (similar to DP_GETTIME_CDTRACK) + //note: beware dedicated server not running sound engine at all, so in dedicated mode this builtins will not work in server progs + //note also: menu progs not supporting getsoundtime() (will give a warning) since it has no sound playing on entities + //examples of use: + // - QC-driven looped sounds + // - QC events when sound playing is finished + // - toggleable ambientsounds + // - subtitles + + //DP_QC_NUM_FOR_EDICT + //idea: Blub\0 + //darkplaces implementation: Blub\0 + //Function to get the number of an entity - a clean way. + float(entity num) num_for_edict = #512; + + //DP_TRACE_HITCONTENTSMASK_SURFACEINFO + //idea: LordHavoc + //darkplaces implementation: LordHavoc + //globals: + .int dphitcontentsmask; // if non-zero on the entity passed to traceline/tracebox/tracetoss this will override the normal collidable contents rules and instead hit these contents values (for example AI can use tracelines that hit DONOTENTER if it wants to, by simply changing this field on the entity passed to traceline), this affects normal movement as well as trace calls + float trace_dpstartcontents; // DPCONTENTS_ value at start position of trace + int trace_dphitcontents; // DPCONTENTS_ value of impacted surface (not contents at impact point, just contents of the surface that was hit) + int trace_dphitq3surfaceflags; // Q3SURFACEFLAG_ value of impacted surface + string trace_dphittexturename; // texture name of impacted surface + //constants: + const int DPCONTENTS_SOLID = 1; // hit a bmodel, not a bounding box + const int DPCONTENTS_WATER = 2; + const int DPCONTENTS_SLIME = 4; + const int DPCONTENTS_LAVA = 8; + const int DPCONTENTS_SKY = 16; + const int DPCONTENTS_BODY = 32; // hit a bounding box, not a bmodel + const int DPCONTENTS_CORPSE = 64; // hit a SOLID_CORPSE entity + const int DPCONTENTS_NODROP = 128; // an area where backpacks should not spawn + const int DPCONTENTS_PLAYERCLIP = 256; // blocks player movement + const int DPCONTENTS_MONSTERCLIP = 512; // blocks monster movement + const int DPCONTENTS_DONOTENTER = 1024; // AI hint brush + const int DPCONTENTS_LIQUIDSMASK = 14; // WATER | SLIME | LAVA + const int DPCONTENTS_BOTCLIP = 2048; // AI hint brush + const int DPCONTENTS_OPAQUE = 4096; // only fully opaque brushes get this (may be useful for line of sight checks) + const int Q3SURFACEFLAG_NODAMAGE = 1; + const int Q3SURFACEFLAG_SLICK = 2; // low friction surface + const int Q3SURFACEFLAG_SKY = 4; // sky surface (also has NOIMPACT and NOMARKS set) + const int Q3SURFACEFLAG_LADDER = 8; // climbable surface + const int Q3SURFACEFLAG_NOIMPACT = 16; // projectiles should remove themselves on impact (this is set on sky) + const int Q3SURFACEFLAG_NOMARKS = 32; // projectiles should not leave marks, such as decals (this is set on sky) + const int Q3SURFACEFLAG_FLESH = 64; // projectiles should do a fleshy effect (blood?) on impact + const int Q3SURFACEFLAG_NODRAW = 128; // compiler hint (not important to qc) + //float Q3SURFACEFLAG_HINT = 256; // compiler hint (not important to qc) + //float Q3SURFACEFLAG_SKIP = 512; // compiler hint (not important to qc) + //float Q3SURFACEFLAG_NOLIGHTMAP = 1024; // compiler hint (not important to qc) + //float Q3SURFACEFLAG_POINTLIGHT = 2048; // compiler hint (not important to qc) + const int Q3SURFACEFLAG_METALSTEPS = 4096; // walking on this surface should make metal step sounds + const int Q3SURFACEFLAG_NOSTEPS = 8192; // walking on this surface should not make footstep sounds + const int Q3SURFACEFLAG_NONSOLID = 16384; // compiler hint (not important to qc) + //float Q3SURFACEFLAG_LIGHTFILTER = 32768; // compiler hint (not important to qc) + //float Q3SURFACEFLAG_ALPHASHADOW = 65536; // compiler hint (not important to qc) + //float Q3SURFACEFLAG_NODLIGHT = 131072; // compiler hint (not important to qc) + //float Q3SURFACEFLAG_DUST = 262144; // translucent 'light beam' effect (not important to qc) + //description: + //adds additional information after a traceline/tracebox/tracetoss call. + //also (very important) sets trace_* globals before calling .touch functions, + //this allows them to inspect the nature of the collision (for example + //determining if a projectile hit sky), clears trace_* variables for the other + //object in a touch event (that is to say, a projectile moving will see the + //trace results in its .touch function, but the player it hit will see very + //little information in the trace_ variables as it was not moving at the time) + + //DP_QC_CVAR_TYPE + //idea: divVerent + //DarkPlaces implementation: divVerent + //builtin definitions: + float(string name) cvar_type = #495; + const int CVAR_TYPEFLAG_EXISTS = 1; + const int CVAR_TYPEFLAG_SAVED = 2; + const int CVAR_TYPEFLAG_PRIVATE = 4; + const int CVAR_TYPEFLAG_ENGINE = 8; + const int CVAR_TYPEFLAG_HASDESCRIPTION = 16; + const int CVAR_TYPEFLAG_READONLY = 32; + + //DP_QC_CRC16 + //idea: divVerent + //darkplaces implementation: divVerent + //Some hash function to build hash tables with. This has to be be the CRC-16-CCITT that is also required for the QuakeWorld download protocol. + //When caseinsensitive is set, the CRC is calculated of the lower cased string. + int(bool caseinsensitive, string s, ...) crc16 = #494; + + //DP_QC_URI_ESCAPE + //idea: divVerent + //darkplaces implementation: divVerent + //URI::Escape's functionality + string(string in) uri_escape = #510; + string(string in) uri_unescape = #511; + + //DP_QC_DIGEST + //idea: motorsep, Spike + //DarkPlaces implementation: divVerent + //builtin definitions: + string(string digest, string data, ...) digest_hex = #639; + //description: + //returns a given hex digest of given data + //the returned digest is always encoded in hexadecimal + //only the "MD4" digest is always supported! + //if the given digest is not supported, string_null is returned + //the digest string is matched case sensitively, use "MD4", not "md4"! + + //DP_QC_DIGEST_SHA256 + //idea: motorsep, Spike + //DarkPlaces implementation: divVerent + //description: + //"SHA256" is also an allowed digest type + + //DP_QC_LOG + //darkplaces implementation: divVerent + //builtin definitions: + float log(float f) = #532; + //description: + //logarithm + + //FTE_CSQC_SKELETONOBJECTS + //idea: Spike, LordHavoc + //darkplaces implementation: LordHavoc + //builtin definitions: + // all skeleton numbers are 1-based (0 being no skeleton) + // all bone numbers are 1-based (0 being invalid) + float(float modlindex) skel_create = #263; // create a skeleton (be sure to assign this value into .skeletonindex for use), returns skeleton index (1 or higher) on success, returns 0 on failure (for example if the modelindex is not skeletal), it is recommended that you create a new skeleton if you change modelindex, as the skeleton uses the hierarchy from the model. + float(float skel, entity ent, float modlindex, float retainfrac, float firstbone, float lastbone) skel_build = #264; // blend in a percentage of standard animation, 0 replaces entirely, 1 does nothing, 0.5 blends half, etc, and this only alters the bones in the specified range for which out of bounds values like 0,100000 are safe (uses .frame, .frame2, .frame3, .frame4, .lerpfrac, .lerpfrac3, .lerpfrac4, .frame1time, .frame2time, .frame3time, .frame4time), returns skel on success, 0 on failure + float(float skel) skel_get_numbones = #265; // returns how many bones exist in the created skeleton, 0 if skeleton does not exist + string(float skel, float bonenum) skel_get_bonename = #266; // returns name of bone (as a tempstring), "" if invalid bonenum (< 1 for example) or skeleton does not exist + int(float skel, float bonenum) skel_get_boneparent = #267; // returns parent num for supplied bonenum, 0 if bonenum has no parent or bone does not exist (returned value is always less than bonenum, you can loop on this) + int(float skel, string tagname) skel_find_bone = #268; // get number of bone with specified name, 0 on failure, bonenum (1-based) on success, same as using gettagindex but takes modelindex instead of entity + vector(float skel, float bonenum) skel_get_bonerel = #269; // get matrix of bone in skeleton relative to its parent - sets v_forward, v_right, v_up, returns origin (relative to parent bone) + vector(float skel, float bonenum) skel_get_boneabs = #270; // get matrix of bone in skeleton in model space - sets v_forward, v_right, v_up, returns origin (relative to entity) + void(float skel, float bonenum, vector org) skel_set_bone = #271; // set matrix of bone relative to its parent, reads v_forward, v_right, v_up, takes origin as parameter (relative to parent bone) + void(float skel, float bonenum, vector org) skel_mul_bone = #272; // transform bone matrix (relative to its parent) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bone) + void(float skel, float startbone, float endbone, vector org) skel_mul_bones = #273; // transform bone matrices (relative to their parents) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bones) + void(float skeldst, float skelsrc, float startbone, float endbone) skel_copybones = #274; // copy bone matrices (relative to their parents) from one skeleton to another, useful for copying a skeleton to a corpse + void(float skel) skel_delete = #275; // deletes skeleton at the beginning of the next frame (you can add the entity, delete the skeleton, renderscene, and it will still work) + float(float modlindex, string framename) frameforname = #276; // finds number of a specified frame in the animation, returns -1 if no match found + float(float modlindex, float framenum) frameduration = #277; // returns the intended play time (in seconds) of the specified framegroup, if it does not exist the result is 0, if it is a single frame it may be a small value around 0.1 or 0. + //fields: + .float skeletonindex; // active skeleton overriding standard animation on model + .int frame; // primary framegroup animation (strength = 1 - lerpfrac - lerpfrac3 - lerpfrac4) + .int frame2; // secondary framegroup animation (strength = lerpfrac) + .int frame3; // tertiary framegroup animation (strength = lerpfrac3) + .int frame4; // quaternary framegroup animation (strength = lerpfrac4) + .float lerpfrac; // strength of framegroup blend + .float lerpfrac3; // strength of framegroup blend + .float lerpfrac4; // strength of framegroup blend + .float frame1time; // start time of framegroup animation + .float frame2time; // start time of framegroup animation + .float frame3time; // start time of framegroup animation + .float frame4time; // start time of framegroup animation + //description: + //this extension provides a way to do complex skeletal animation on an entity. + // + //see also DP_SKELETONOBJECTS (this extension implemented on server as well as client) + // + //notes: + //each model contains its own skeleton, reusing a skeleton with incompatible models will yield garbage (or not render). + //each model contains its own animation data, you can use animations from other model files (for example saving out all character animations as separate model files). + //if an engine supports loading an animation-only file format such as .md5anim in FTEQW, it can be used to animate any model with a compatible skeleton. + //proper use of this extension may require understanding matrix transforms (v_forward, v_right, v_up, origin), and you must keep in mind that v_right is negative for this purpose. + // + //features include: + //multiple animations blended together. + //animating a model with animations from another model with a compatible skeleton. + //restricting animation blends to certain bones of a model - for example independent animation of legs, torso, head. + //custom bone controllers - for example making eyes track a target location. + // + // + // + //example code follows... + // + //this helper function lets you identify (by parentage) what group a bone + //belongs to - for example "torso", "leftarm", would return 1 ("torso") for + //all children of the bone named "torso", unless they are children of + //"leftarm" (which is a child of "torso") which would return 2 instead... + float(float skel, float bonenum, string g1, string g2, string g3, string g4, string g5, string g6) example_skel_findbonegroup = + { + string bonename; + while (bonenum >= 0) + { + bonename = skel_get_bonename(skel, bonenum); + if (bonename == g1) return 1; + if (bonename == g2) return 2; + if (bonename == g3) return 3; + if (bonename == g4) return 4; + if (bonename == g5) return 5; + if (bonename == g6) return 6; + bonenum = skel_get_boneparent(skel, bonenum); + } + return 0; + }; + // create a skeletonindex for our player using current modelindex + void() example_skel_player_setup = + { + self.skeletonindex = skel_create(self.modelindex); + }; + // setup bones of skeleton based on an animation + // note: animmodelindex can be a different model than self.modelindex + void(float animmodelindex, float framegroup, float framegroupstarttime) example_skel_player_update_begin = + { + // start with our standard animation + self.frame = framegroup; + self.frame2 = 0; + self.frame3 = 0; + self.frame4 = 0; + self.frame1time = framegroupstarttime; + self.frame2time = 0; + self.frame3time = 0; + self.frame4time = 0; + self.lerpfrac = 0; + self.lerpfrac3 = 0; + self.lerpfrac4 = 0; + skel_build(self.skeletonindex, self, animmodelindex, 0, 0, 100000); + }; + // apply a different framegroup animation to bones with a specified parent + void(float animmodelindex, float framegroup, float framegroupstarttime, float blendalpha, string groupbonename, string excludegroupname1, string excludegroupname2) example_skel_player_update_applyoverride = + { + self.frame = framegroup; + self.frame2 = 0; + self.frame3 = 0; + self.frame4 = 0; + self.frame1time = framegroupstarttime; + self.frame2time = 0; + self.frame3time = 0; + self.frame4time = 0; + self.lerpfrac = 0; + self.lerpfrac3 = 0; + self.lerpfrac4 = 0; + float bonenum = 0; + float numbones = skel_get_numbones(self.skeletonindex); + while (bonenum < numbones) + { + if (example_skel_findbonegroup(self.skeletonindex, bonenum, groupbonename, excludegroupname1, excludegroupname2, "", "", "") == 1) + skel_build(self.skeletonindex, self, animmodelindex, 1 - blendalpha, bonenum, bonenum + 1); + bonenum = bonenum + 1; + } + }; + // make eyes point at a target location, be sure v_forward, v_right, v_up are set correctly before calling + void(vector eyetarget, string bonename) example_skel_player_update_eyetarget = + { + float bonenum = skel_find_bone(self.skeletonindex, bonename) - 1; + if (bonenum < 0) + return; + vector oldforward = v_forward; + vector oldright = v_right; + vector oldup = v_up; + vector v = eyetarget - self.origin; + vector modeleyetarget; + modeleyetarget.x = v * v_forward; + modeleyetarget.y = 0-v * v_right; + modeleyetarget.z = v * v_up; + // this is an eyeball, make it point at the target location + // first get all the data we can... + vector relorg = skel_get_bonerel(self.skeletonindex, bonenum); + vector relforward = v_forward; + vector relright = v_right; + vector relup = v_up; + vector boneorg = skel_get_boneabs(self.skeletonindex, bonenum); + vector boneforward = v_forward; + vector boneright = v_right; + vector boneup = v_up; + vector parentorg = skel_get_boneabs(self.skeletonindex, skel_get_boneparent(self.skeletonindex, bonenum)); + vector parentforward = v_forward; + vector parentright = v_right; + vector parentup = v_up; + // get the vector from the eyeball to the target + vector u = modeleyetarget - boneorg; + // now transform it inversely by the parent matrix to produce new rel vectors + v.x = u * parentforward; + v.y = u * parentright; + v.z = u * parentup; + vector ang = vectoangles2(v, relup); + ang.x = 0 - ang.x; + makevectors(ang); + // set the relative bone matrix + skel_set_bone(self.skeletonindex, bonenum, relorg); + // restore caller's v_ vectors + v_forward = oldforward; + v_right = oldright; + v_up = oldup; + }; + // delete skeleton when we're done with it + // note: skeleton remains valid until next frame when it is really deleted + void() example_skel_player_delete = + { + skel_delete(self.skeletonindex); + self.skeletonindex = 0; + }; + // + // END OF EXAMPLES FOR FTE_CSQC_SKELETONOBJECTS + // + + //DP_QC_ENTITYDATA + //idea: KrimZon + //darkplaces implementation: KrimZon + //builtin definitions: + float() numentityfields = #496; + string(float fieldnum) entityfieldname = #497; + float(float fieldnum) entityfieldtype = #498; + string(float fieldnum, entity ent) getentityfieldstring = #499; + float(float fieldnum, entity ent, string s) putentityfieldstring = #500; + //constants: + //Returned by entityfieldtype + float FIELD_STRING = 1; + float FIELD_FLOAT = 2; + float FIELD_VECTOR = 3; + float FIELD_ENTITY = 4; + float FIELD_FUNCTION = 6; + //description: + //Versatile functions intended for storing data from specific entities between level changes, but can be customized for some kind of partial savegame. + //WARNING: .entity fields cannot be saved and restored between map loads as they will leave dangling pointers. + //numentityfields returns the number of entity fields. NOT offsets. Vectors comprise 4 fields: v, v_x, v_y and v_z. + //entityfieldname returns the name as a string, eg. "origin" or "classname" or whatever. + //entityfieldtype returns a value that the constants represent, but the field may be of another type in more exotic progs.dat formats or compilers. + //getentityfieldstring returns data as would be written to a savegame, eg... "0.05" (float), "0 0 1" (vector), or "Hello World!" (string). Function names can also be returned. + //putentityfieldstring puts the data returned by getentityfieldstring back into the entity. + + //DP_QC_ENTITYSTRING + void(string s) loadfromdata = #529; + void(string s) loadfromfile = #530; + void(string s) callfunction = #605; + void(float fh, entity e) writetofile = #606; + float(string s) isfunction = #607; + void(entity e, string s) parseentitydata = #608; + + // assorted builtins + //const int STAT_MOVEVARS_TICRATE = 240; + //const int STAT_MOVEVARS_TIMESCALE = 241; + //const int STAT_FRAGLIMIT = 235; + //const int STAT_TIMELIMIT = 236; + //const int STAT_MOVEVARS_GRAVITY = 242; + string(void) ReadPicture = #501; + const int PARTICLES_USEALPHA = 1; + float particles_alphamin, particles_alphamax; + const int PARTICLES_USECOLOR = 2; + vector particles_colormin, particles_colormax; + const int PARTICLES_USEFADE = 4; // fades the COUNT (fade alpha using alphamin/alphamax) + float particles_fade; + const int PARTICLES_DRAWASTRAIL = 128; + void(float effectindex, entity own, vector org_from, vector org_to, vector dir_from, vector dir_to, float countmultiplier, float flags) boxparticles = #502; + float trace_networkentity; + const int RF_FULLBRIGHT = 256; + const int RF_NOSHADOW = 512; + const int RF_DYNAMICMODELLIGHT = 8192; + + float gettaginfo_parent; + string gettaginfo_name; + vector gettaginfo_offset; + vector gettaginfo_forward; + vector gettaginfo_right; + vector gettaginfo_up; + float checkpvs(vector viewpos, entity viewee) = #240; + #endif diff --cc qcsrc/server/cl_client.qc index 37a630af8,b73d74754..5f4b771ce --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@@ -1,3 -1,30 +1,31 @@@ + #include "waypointsprites.qh" + + #include "cl_impulse.qh" + #include "cl_player.qh" + #include "ent_cs.qh" + #include "g_subs.qh" + #include "ipban.qh" + #include "miscfunctions.qh" + #include "portals.qh" + #include "teamplay.qh" + #include "playerdemo.qh" + #include "secret.qh" + + #include "bot/bot.qh" + #include "bot/navigation.qh" + + #include "weapons/hitplot.qh" + #include "weapons/weaponsystem.qh" + + #include "../common/net_notice.qh" ++#include "../common/physics.qh" + + #include "../common/monsters/sv_monsters.qh" + + #include "../warpzonelib/server.qh" + + float c1, c2, c3, c4; + void send_CSQC_teamnagger() { WriteByte(MSG_BROADCAST, SVC_TEMPENTITY); WriteByte(MSG_BROADCAST, TE_CSQC_TEAMNAGGER); diff --cc qcsrc/server/cl_player.qc index d899b3db3,49d1c1b46..b2e680e83 --- a/qcsrc/server/cl_player.qc +++ b/qcsrc/server/cl_player.qc @@@ -1,9 -1,10 +1,12 @@@ - .entity pusher; - .float pushltime; - .float istypefrag; + #include "cl_player.qh" + #include "g_triggers.qh" + #include "g_violence.qh" + #include "miscfunctions.qh" + + #include "weapons/weaponstats.qh" + ++#include "../common/animdecide.qh" + - .float CopyBody_nextthink; - .void(void) CopyBody_think; void CopyBody_Think(void) { if(self.CopyBody_nextthink && time > self.CopyBody_nextthink) diff --cc qcsrc/server/defs.qh index 870c61c75,175179b50..fc85ed9d5 --- a/qcsrc/server/defs.qh +++ b/qcsrc/server/defs.qh @@@ -442,9 -447,14 +447,9 @@@ float round_starttime; //point in time .float stat_game_starttime; .float stat_round_starttime; -.float stat_sv_airaccel_qw; -.float stat_sv_airstrafeaccel_qw; -.float stat_sv_airspeedlimit_nonqw; -.float stat_sv_maxspeed; - void W_Porto_Remove (entity p); - .float projectiledeathtype; + .int projectiledeathtype; .string message2; diff --cc qcsrc/server/miscfunctions.qh index 000000000,d20cb168f..0c8c105d5 mode 000000,100644..100644 --- a/qcsrc/server/miscfunctions.qh +++ b/qcsrc/server/miscfunctions.qh @@@ -1,0 -1,686 +1,684 @@@ + #ifndef MISCFUNCTIONS_H + #define MISCFUNCTIONS_H + + #include "t_items.qh" + + #include "mutators/base.qh" + #include "mutators/gamemode_race.qh" + + #include "../common/constants.qh" + #include "../common/mapinfo.qh" + + #ifdef RELEASE + #define cvar_string_normal builtin_cvar_string + #define cvar_normal builtin_cvar + #else + string cvar_string_normal(string n) + { + if (!(cvar_type(n) & 1)) + backtrace(strcat("Attempt to access undefined cvar: ", n)); + return builtin_cvar_string(n); + } + + float cvar_normal(string n) + { + return stof(cvar_string_normal(n)); + } + #endif + #define cvar_set_normal builtin_cvar_set + + .vector dropped_origin; + .void(void) uncustomizeentityforclient; + .float uncustomizeentityforclient_set; + .float nottargeted; + + + float DistributeEvenly_amount; + float DistributeEvenly_totalweight; + var void remove(entity e); + void objerror(string s); + void droptofloor(); + void() spawnfunc_info_player_deathmatch; // needed for the other spawnpoints + void() spawnpoint_use; + void() SUB_Remove; + + void attach_sameorigin(entity e, entity to, string tag); + + void crosshair_trace(entity pl); + + void crosshair_trace_plusvisibletriggers(entity pl); + + void detach_sameorigin(entity e); + + void follow_sameorigin(entity e, entity to); + + string formatmessage(string msg); + + void GameLogEcho(string s); + + void GameLogInit(); + + void GameLogClose(); + + void GetCvars(float f); + + string GetMapname(); + + float isPushable(entity e); + + float LostMovetypeFollow(entity ent); + + float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance); + + string NearestLocation(vector p); + + void play2(entity e, string filename); + + string playername(entity p); + + void precache(); + + void remove_safely(entity e); + + void remove_unsafely(entity e); + + void SetMovetypeFollow(entity ent, entity e); + + vector shotorg_adjust_values(vector vecs, float y_is_right, float visual, float algn); + + void soundto(float dest, entity e, float chan, string samp, float vol, float atten); + + void stopsound(entity e, float chan); + + float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma); + + void traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag); + + void WarpZone_crosshair_trace(entity pl); + + void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag); + + + #define IFTARGETED if(!self.nottargeted && self.targetname != "") + + #define ITEM_TOUCH_NEEDKILL() (((trace_dpstartcontents | trace_dphitcontents) & DPCONTENTS_NODROP) || (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)) + #define ITEM_DAMAGE_NEEDKILL(dt) (((dt) == DEATH_HURTTRIGGER) || ((dt) == DEATH_SLIME) || ((dt) == DEATH_LAVA) || ((dt) == DEATH_SWAMP)) + + #define PROJECTILE_TOUCH if(WarpZone_Projectile_Touch()) return + -#define move_out_of_solid(e) WarpZoneLib_MoveOutOfSolid(e) - + const string STR_PLAYER = "player"; + const string STR_SPECTATOR = "spectator"; + const string STR_OBSERVER = "observer"; + + #define IS_PLAYER(v) (v.classname == STR_PLAYER) + #define IS_SPEC(v) (v.classname == STR_SPECTATOR) + #define IS_OBSERVER(v) (v.classname == STR_OBSERVER) + #define IS_CLIENT(v) (v.flags & FL_CLIENT) + #define IS_BOT_CLIENT(v) (clienttype(v) == CLIENTTYPE_BOT) + #define IS_REAL_CLIENT(v) (clienttype(v) == CLIENTTYPE_REAL) + #define IS_NOT_A_CLIENT(v) (clienttype(v) == CLIENTTYPE_NOTACLIENT) + + #define FOR_EACH_CLIENTSLOT(v) for(v = world; (v = nextent(v)) && (num_for_edict(v) <= maxclients); ) + #define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if(IS_CLIENT(v)) + #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(IS_REAL_CLIENT(v)) + + #define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(IS_PLAYER(v)) + #define FOR_EACH_SPEC(v) FOR_EACH_CLIENT(v) if (!IS_PLAYER(v)) // Samual: shouldn't this be IS_SPEC(v)? and rather create a separate macro to include observers too + #define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(IS_PLAYER(v)) + + #define FOR_EACH_MONSTER(v) for(v = world; (v = findflags(v, flags, FL_MONSTER)) != world; ) + + #define CENTER_OR_VIEWOFS(ent) (ent.origin + (IS_PLAYER(ent) ? ent.view_ofs : ((ent.mins + ent.maxs) * 0.5))) + + // copies a string to a tempstring (so one can strunzone it) + string strcat1(string s) = #115; // FRIK_FILE + + float logfile_open; + float logfile; + + #define strstr strstrofs + /* + // NOTE: DO NOT USE THIS FUNCTION TOO OFTEN. + // IT WILL MOST PROBABLY DESTROY _ALL_ OTHER TEMP + // STRINGS AND TAKE QUITE LONG. haystack and needle MUST + // BE CONSTANT OR strzoneD! + float strstr(string haystack, string needle, float offset) + { + float len, endpos; + string found; + len = strlen(needle); + endpos = strlen(haystack) - len; + while(offset <= endpos) + { + found = substring(haystack, offset, len); + if(found == needle) + return offset; + offset = offset + 1; + } + return -1; + } + */ + + const float NUM_NEAREST_ENTITIES = 4; + entity nearest_entity[NUM_NEAREST_ENTITIES]; + float nearest_length[NUM_NEAREST_ENTITIES]; + + + //#NO AUTOCVARS START + + float g_pickup_shells; + float g_pickup_shells_max; + float g_pickup_nails; + float g_pickup_nails_max; + float g_pickup_rockets; + float g_pickup_rockets_max; + float g_pickup_cells; + float g_pickup_cells_max; + float g_pickup_plasma; + float g_pickup_plasma_max; + float g_pickup_fuel; + float g_pickup_fuel_jetpack; + float g_pickup_fuel_max; + float g_pickup_armorsmall; + float g_pickup_armorsmall_max; + float g_pickup_armorsmall_anyway; + float g_pickup_armormedium; + float g_pickup_armormedium_max; + float g_pickup_armormedium_anyway; + float g_pickup_armorbig; + float g_pickup_armorbig_max; + float g_pickup_armorbig_anyway; + float g_pickup_armorlarge; + float g_pickup_armorlarge_max; + float g_pickup_armorlarge_anyway; + float g_pickup_healthsmall; + float g_pickup_healthsmall_max; + float g_pickup_healthsmall_anyway; + float g_pickup_healthmedium; + float g_pickup_healthmedium_max; + float g_pickup_healthmedium_anyway; + float g_pickup_healthlarge; + float g_pickup_healthlarge_max; + float g_pickup_healthlarge_anyway; + float g_pickup_healthmega; + float g_pickup_healthmega_max; + float g_pickup_healthmega_anyway; + float g_pickup_ammo_anyway; + float g_pickup_weapons_anyway; + float g_weaponarena; + WepSet g_weaponarena_weapons; + float g_weaponarena_random; + float g_weaponarena_random_with_blaster; + string g_weaponarena_list; + float g_weaponspeedfactor; + float g_weaponratefactor; + float g_weapondamagefactor; + float g_weaponforcefactor; + float g_weaponspreadfactor; + + WepSet start_weapons; + WepSet start_weapons_default; + WepSet start_weapons_defaultmask; + int start_items; + float start_ammo_shells; + float start_ammo_nails; + float start_ammo_rockets; + float start_ammo_cells; + float start_ammo_plasma; + float start_ammo_fuel; + float start_health; + float start_armorvalue; + WepSet warmup_start_weapons; + WepSet warmup_start_weapons_default; + WepSet warmup_start_weapons_defaultmask; + #define WARMUP_START_WEAPONS ((g_warmup_allguns == 1) ? (warmup_start_weapons & (weaponsInMap | start_weapons)) : warmup_start_weapons) + float warmup_start_ammo_shells; + float warmup_start_ammo_nails; + float warmup_start_ammo_rockets; + float warmup_start_ammo_cells; + float warmup_start_ammo_plasma; + float warmup_start_ammo_fuel; + float warmup_start_health; + float warmup_start_armorvalue; + float g_weapon_stay; + + float want_weapon(entity weaponinfo, float allguns) // WEAPONTODO: what still needs done? + { + int i = weaponinfo.weapon; + int d = 0; + + if (!i) + return 0; + + if (g_lms || g_ca || allguns) + { + if(weaponinfo.spawnflags & WEP_FLAG_NORMAL) + d = true; + else + d = false; + } + else if (g_cts) + d = (i == WEP_SHOTGUN); + else if (g_nexball) + d = 0; // weapon is set a few lines later + else + d = !(!weaponinfo.weaponstart); + + if(g_grappling_hook) // if possible, redirect off-hand hook to on-hand hook + d |= (i == WEP_HOOK); + if(!g_cts && (weaponinfo.spawnflags & WEP_FLAG_MUTATORBLOCKED)) // never default mutator blocked guns + d = 0; + + float t = weaponinfo.weaponstartoverride; + + //print(strcat("want_weapon: ", weaponinfo.netname, " - d: ", ftos(d), ", t: ", ftos(t), ". \n")); + + // bit order in t: + // 1: want or not + // 2: is default? + // 4: is set by default? + if(t < 0) + t = 4 | (3 * d); + else + t |= (2 * d); + + return t; + } + + void readplayerstartcvars() + { + entity e; + float i, j, t; + string s; + + // initialize starting values for players + start_weapons = '0 0 0'; + start_weapons_default = '0 0 0'; + start_weapons_defaultmask = '0 0 0'; + start_items = 0; + start_ammo_shells = 0; + start_ammo_nails = 0; + start_ammo_rockets = 0; + start_ammo_cells = 0; + start_ammo_plasma = 0; + start_health = cvar("g_balance_health_start"); + start_armorvalue = cvar("g_balance_armor_start"); + + g_weaponarena = 0; + g_weaponarena_weapons = '0 0 0'; + + s = cvar_string("g_weaponarena"); + if (s == "0" || s == "") + { + if(g_ca) + s = "most"; + } + + if (s == "0" || s == "") + { + // no arena + } + else if (s == "off") + { + // forcibly turn off weaponarena + } + else if (s == "all" || s == "1") + { + g_weaponarena = 1; + g_weaponarena_list = "All Weapons"; + for (j = WEP_FIRST; j <= WEP_LAST; ++j) + { + e = get_weaponinfo(j); + if (!(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)) + g_weaponarena_weapons |= WepSet_FromWeapon(j); + } + } + else if (s == "most") + { + g_weaponarena = 1; + g_weaponarena_list = "Most Weapons"; + for (j = WEP_FIRST; j <= WEP_LAST; ++j) + { + e = get_weaponinfo(j); + if (!(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)) + if (e.spawnflags & WEP_FLAG_NORMAL) + g_weaponarena_weapons |= WepSet_FromWeapon(j); + } + } + else if (s == "none") + { + g_weaponarena = 1; + g_weaponarena_list = "No Weapons"; + } + else + { + g_weaponarena = 1; + t = tokenize_console(s); + g_weaponarena_list = ""; + for (i = 0; i < t; ++i) + { + s = argv(i); + for (j = WEP_FIRST; j <= WEP_LAST; ++j) + { + e = get_weaponinfo(j); + if (e.netname == s) + { + g_weaponarena_weapons |= WepSet_FromWeapon(j); + g_weaponarena_list = strcat(g_weaponarena_list, e.message, " & "); + break; + } + } + if (j > WEP_LAST) + { + print("The weapon mutator list contains an unknown weapon ", s, ". Skipped.\n"); + } + } + g_weaponarena_list = strzone(substring(g_weaponarena_list, 0, strlen(g_weaponarena_list) - 3)); + } + + if(g_weaponarena) + g_weaponarena_random = cvar("g_weaponarena_random"); + else + g_weaponarena_random = 0; + g_weaponarena_random_with_blaster = cvar("g_weaponarena_random_with_blaster"); + + if (g_weaponarena) + { + g_weapon_stay = 0; // incompatible + start_weapons = g_weaponarena_weapons; + start_items |= IT_UNLIMITED_AMMO; + } + else + { + for (i = WEP_FIRST; i <= WEP_LAST; ++i) + { + e = get_weaponinfo(i); + int w = want_weapon(e, false); + if(w & 1) + start_weapons |= WepSet_FromWeapon(i); + if(w & 2) + start_weapons_default |= WepSet_FromWeapon(i); + if(w & 4) + start_weapons_defaultmask |= WepSet_FromWeapon(i); + } + } + + if(!cvar("g_use_ammunition")) + start_items |= IT_UNLIMITED_AMMO; + + if(start_items & IT_UNLIMITED_WEAPON_AMMO) + { + start_ammo_shells = 999; + start_ammo_nails = 999; + start_ammo_rockets = 999; + start_ammo_cells = 999; + start_ammo_plasma = 999; + start_ammo_fuel = 999; + } + else + { + start_ammo_shells = cvar("g_start_ammo_shells"); + start_ammo_nails = cvar("g_start_ammo_nails"); + start_ammo_rockets = cvar("g_start_ammo_rockets"); + start_ammo_cells = cvar("g_start_ammo_cells"); + start_ammo_plasma = cvar("g_start_ammo_plasma"); + start_ammo_fuel = cvar("g_start_ammo_fuel"); + } + + if (warmup_stage) + { + warmup_start_ammo_shells = start_ammo_shells; + warmup_start_ammo_nails = start_ammo_nails; + warmup_start_ammo_rockets = start_ammo_rockets; + warmup_start_ammo_cells = start_ammo_cells; + warmup_start_ammo_plasma = start_ammo_plasma; + warmup_start_ammo_fuel = start_ammo_fuel; + warmup_start_health = start_health; + warmup_start_armorvalue = start_armorvalue; + warmup_start_weapons = start_weapons; + warmup_start_weapons_default = start_weapons_default; + warmup_start_weapons_defaultmask = start_weapons_defaultmask; + + if (!g_weaponarena && !g_ca) + { + warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells"); + warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails"); + warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets"); + warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells"); + warmup_start_ammo_plasma = cvar("g_warmup_start_ammo_plasma"); + warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel"); + warmup_start_health = cvar("g_warmup_start_health"); + warmup_start_armorvalue = cvar("g_warmup_start_armor"); + warmup_start_weapons = '0 0 0'; + warmup_start_weapons_default = '0 0 0'; + warmup_start_weapons_defaultmask = '0 0 0'; + for (i = WEP_FIRST; i <= WEP_LAST; ++i) + { + e = get_weaponinfo(i); + int w = want_weapon(e, g_warmup_allguns); + if(w & 1) + warmup_start_weapons |= WepSet_FromWeapon(i); + if(w & 2) + warmup_start_weapons_default |= WepSet_FromWeapon(i); + if(w & 4) + warmup_start_weapons_defaultmask |= WepSet_FromWeapon(i); + } + } + } + + if (g_jetpack) + start_items |= IT_JETPACK; + + MUTATOR_CALLHOOK(SetStartItems); + + if ((start_items & IT_JETPACK) || (g_grappling_hook && (start_weapons & WEPSET_HOOK))) + { + start_items |= IT_FUEL_REGEN; + start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable")); + warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable")); + } + + WepSet precache_weapons = start_weapons; + if (g_warmup_allguns != 1) + precache_weapons |= warmup_start_weapons; + for (i = WEP_FIRST; i <= WEP_LAST; ++i) + { + e = get_weaponinfo(i); + if(precache_weapons & WepSet_FromWeapon(i)) + WEP_ACTION(i, WR_INIT); + } + + start_ammo_shells = max(0, start_ammo_shells); + start_ammo_nails = max(0, start_ammo_nails); + start_ammo_rockets = max(0, start_ammo_rockets); + start_ammo_cells = max(0, start_ammo_cells); + start_ammo_plasma = max(0, start_ammo_plasma); + start_ammo_fuel = max(0, start_ammo_fuel); + + warmup_start_ammo_shells = max(0, warmup_start_ammo_shells); + warmup_start_ammo_nails = max(0, warmup_start_ammo_nails); + warmup_start_ammo_rockets = max(0, warmup_start_ammo_rockets); + warmup_start_ammo_cells = max(0, warmup_start_ammo_cells); + warmup_start_ammo_plasma = max(0, warmup_start_ammo_plasma); + warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel); + } + + float g_bugrigs; + float g_bugrigs_planar_movement; + float g_bugrigs_planar_movement_car_jumping; + float g_bugrigs_reverse_spinning; + float g_bugrigs_reverse_speeding; + float g_bugrigs_reverse_stopping; + float g_bugrigs_air_steering; + float g_bugrigs_angle_smoothing; + float g_bugrigs_friction_floor; + float g_bugrigs_friction_brake; + float g_bugrigs_friction_air; + float g_bugrigs_accel; + float g_bugrigs_speed_ref; + float g_bugrigs_speed_pow; + float g_bugrigs_steer; + + float sv_autotaunt; + float sv_taunt; + + string GetGametype(); // g_world.qc + void mutators_add(); // mutators.qc + void readlevelcvars(void) + { + // load mutators + mutators_add(); + + if(cvar("sv_allow_fullbright")) + serverflags |= SERVERFLAG_ALLOW_FULLBRIGHT; + + g_bugrigs = cvar("g_bugrigs"); + g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement"); + g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping"); + g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning"); + g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding"); + g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping"); + g_bugrigs_air_steering = cvar("g_bugrigs_air_steering"); + g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing"); + g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor"); + g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake"); + g_bugrigs_friction_air = cvar("g_bugrigs_friction_air"); + g_bugrigs_accel = cvar("g_bugrigs_accel"); + g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref"); + g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow"); + g_bugrigs_steer = cvar("g_bugrigs_steer"); + + g_instagib = cvar("g_instagib"); + + sv_clones = cvar("sv_clones"); + sv_foginterval = cvar("sv_foginterval"); + g_cloaked = cvar("g_cloaked"); + g_footsteps = cvar("g_footsteps"); + g_grappling_hook = cvar("g_grappling_hook"); + g_jetpack = cvar("g_jetpack"); + sv_maxidle = cvar("sv_maxidle"); + sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle"); + sv_autotaunt = cvar("sv_autotaunt"); + sv_taunt = cvar("sv_taunt"); + + warmup_stage = cvar("g_warmup"); + g_warmup_limit = cvar("g_warmup_limit"); + g_warmup_allguns = cvar("g_warmup_allguns"); + g_warmup_allow_timeout = cvar("g_warmup_allow_timeout"); + + if ((g_race && g_race_qualifying == 2) || g_assault || cvar("g_campaign")) + warmup_stage = 0; // these modes cannot work together, sorry + + g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon"); + g_pickup_respawntime_superweapon = cvar("g_pickup_respawntime_superweapon"); + g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo"); + g_pickup_respawntime_short = cvar("g_pickup_respawntime_short"); + g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium"); + g_pickup_respawntime_long = cvar("g_pickup_respawntime_long"); + g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup"); + g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon"); + g_pickup_respawntimejitter_superweapon = cvar("g_pickup_respawntimejitter_superweapon"); + g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo"); + g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short"); + g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium"); + g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long"); + g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup"); + + g_weaponspeedfactor = cvar("g_weaponspeedfactor"); + g_weaponratefactor = cvar("g_weaponratefactor"); + g_weapondamagefactor = cvar("g_weapondamagefactor"); + g_weaponforcefactor = cvar("g_weaponforcefactor"); + g_weaponspreadfactor = cvar("g_weaponspreadfactor"); + + g_pickup_shells = cvar("g_pickup_shells"); + g_pickup_shells_max = cvar("g_pickup_shells_max"); + g_pickup_nails = cvar("g_pickup_nails"); + g_pickup_nails_max = cvar("g_pickup_nails_max"); + g_pickup_rockets = cvar("g_pickup_rockets"); + g_pickup_rockets_max = cvar("g_pickup_rockets_max"); + g_pickup_cells = cvar("g_pickup_cells"); + g_pickup_cells_max = cvar("g_pickup_cells_max"); + g_pickup_plasma = cvar("g_pickup_plasma"); + g_pickup_plasma_max = cvar("g_pickup_plasma_max"); + g_pickup_fuel = cvar("g_pickup_fuel"); + g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack"); + g_pickup_fuel_max = cvar("g_pickup_fuel_max"); + g_pickup_armorsmall = cvar("g_pickup_armorsmall"); + g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max"); + g_pickup_armorsmall_anyway = cvar("g_pickup_armorsmall_anyway"); + g_pickup_armormedium = cvar("g_pickup_armormedium"); + g_pickup_armormedium_max = cvar("g_pickup_armormedium_max"); + g_pickup_armormedium_anyway = cvar("g_pickup_armormedium_anyway"); + g_pickup_armorbig = cvar("g_pickup_armorbig"); + g_pickup_armorbig_max = cvar("g_pickup_armorbig_max"); + g_pickup_armorbig_anyway = cvar("g_pickup_armorbig_anyway"); + g_pickup_armorlarge = cvar("g_pickup_armorlarge"); + g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max"); + g_pickup_armorlarge_anyway = cvar("g_pickup_armorlarge_anyway"); + g_pickup_healthsmall = cvar("g_pickup_healthsmall"); + g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max"); + g_pickup_healthsmall_anyway = cvar("g_pickup_healthsmall_anyway"); + g_pickup_healthmedium = cvar("g_pickup_healthmedium"); + g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max"); + g_pickup_healthmedium_anyway = cvar("g_pickup_healthmedium_anyway"); + g_pickup_healthlarge = cvar("g_pickup_healthlarge"); + g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max"); + g_pickup_healthlarge_anyway = cvar("g_pickup_healthlarge_anyway"); + g_pickup_healthmega = cvar("g_pickup_healthmega"); + g_pickup_healthmega_max = cvar("g_pickup_healthmega_max"); + g_pickup_healthmega_anyway = cvar("g_pickup_healthmega_anyway"); + + g_pickup_ammo_anyway = cvar("g_pickup_ammo_anyway"); + g_pickup_weapons_anyway = cvar("g_pickup_weapons_anyway"); + + g_weapon_stay = cvar(strcat("g_", GetGametype(), "_weapon_stay")); + if(!g_weapon_stay) + g_weapon_stay = cvar("g_weapon_stay"); + + if (!warmup_stage) + game_starttime = time + cvar("g_start_delay"); + + readplayerstartcvars(); + } + + //#NO AUTOCVARS END + + + // Sound functions + //string precache_sound (string s) = #19; + // hack + float precache_sound_index (string s) = #19; + + const float SND_VOLUME = 1; + const float SND_ATTENUATION = 2; + const float SND_LARGEENTITY = 8; + const float SND_LARGESOUND = 16; + + // WARNING: this kills the trace globals + #define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return + #define EXACTTRIGGER_INIT WarpZoneLib_ExactTrigger_Init() + + const float INITPRIO_FIRST = 0; + const float INITPRIO_GAMETYPE = 0; + const float INITPRIO_GAMETYPE_FALLBACK = 1; + const float INITPRIO_FINDTARGET = 10; + const float INITPRIO_DROPTOFLOOR = 20; + const float INITPRIO_SETLOCATION = 90; + const float INITPRIO_LINKDOORS = 91; + const float INITPRIO_LAST = 99; + + .void(void) initialize_entity; + .float initialize_entity_order; + .entity initialize_entity_next; + entity initialize_entity_first; + + + + + + float sound_allowed(float dest, entity e); + void InitializeEntity(entity e, void(void) func, float order); + void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer); + void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc); + + #endif diff --cc qcsrc/server/mutators/mutator_dodging.qc index 72efaeba4,ad52d3e29..39ecc2fde --- a/qcsrc/server/mutators/mutator_dodging.qc +++ b/qcsrc/server/mutators/mutator_dodging.qc @@@ -72,138 -20,31 +71,138 @@@ // until it's 0. .float dodging_velocity_gain; -MUTATOR_HOOKFUNCTION(dodging_GetCvars) { - GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_dodging_timeout, "cl_dodging_timeout"); - return 0; +#ifdef CSQC +.float pressedkeys; + +#elif defined(SVQC) + +void dodging_UpdateStats() +{ + self.stat_dodging = PHYS_DODGING; + self.stat_dodging_delay = PHYS_DODGING_DELAY; + self.stat_dodging_horiz_speed_frozen = PHYS_DODGING_HORIZ_SPEED_FROZEN; + self.stat_dodging_frozen = PHYS_DODGING_FROZEN; + self.stat_dodging_frozen_nodoubletap = PHYS_DODGING_FROZEN_NODOUBLETAP; + self.stat_dodging_height_threshold = PHYS_DODGING_HEIGHT_THRESHOLD; + self.stat_dodging_distance_threshold = PHYS_DODGING_DISTANCE_THRESHOLD; + self.stat_dodging_ramp_time = PHYS_DODGING_RAMP_TIME; + self.stat_dodging_up_speed = PHYS_DODGING_UP_SPEED; + self.stat_dodging_wall = PHYS_DODGING_WALL; } -MUTATOR_HOOKFUNCTION(dodging_PlayerPhysics) { - // print("dodging_PlayerPhysics\n"); +void dodging_Initialize() +{ + addstat(STAT_DODGING, AS_INT, stat_dodging); + addstat(STAT_DODGING_DELAY, AS_FLOAT, stat_dodging_delay); + addstat(STAT_DODGING_TIMEOUT, AS_FLOAT, cvar_cl_dodging_timeout); // we stat this, so it is updated on the client when updated on server (otherwise, chaos) + addstat(STAT_DODGING_FROZEN_NO_DOUBLETAP, AS_INT, stat_dodging_frozen_nodoubletap); + addstat(STAT_DODGING_HORIZ_SPEED_FROZEN, AS_FLOAT, stat_dodging_horiz_speed_frozen); + addstat(STAT_DODGING_FROZEN, AS_INT, stat_dodging_frozen); + addstat(STAT_DODGING_HORIZ_SPEED, AS_FLOAT, stat_dodging_horiz_speed); + addstat(STAT_DODGING_HEIGHT_THRESHOLD, AS_FLOAT, stat_dodging_height_threshold); + addstat(STAT_DODGING_DISTANCE_THRESHOLD, AS_FLOAT, stat_dodging_distance_threshold); + addstat(STAT_DODGING_RAMP_TIME, AS_FLOAT, stat_dodging_ramp_time); + addstat(STAT_DODGING_UP_SPEED, AS_FLOAT, stat_dodging_up_speed); + addstat(STAT_DODGING_WALL, AS_FLOAT, stat_dodging_wall); +} + +#endif + +// returns 1 if the player is close to a wall +float check_close_to_wall(float threshold) +{ - if (PHYS_DODGING_WALL == 0) { return FALSE; } ++ if (PHYS_DODGING_WALL == 0) { return false; } + + #define X(OFFSET) \ - tracebox(self.origin, self.mins, self.maxs, self.origin + OFFSET, TRUE, self); \ ++ tracebox(self.origin, self.mins, self.maxs, self.origin + OFFSET, true, self); \ + if (trace_fraction < 1 && vlen (self.origin - trace_endpos) < threshold) \ - return TRUE; ++ return true; + X(1000*v_right); + X(-1000*v_right); + X(1000*v_forward); + X(-1000*v_forward); + #undef X + - return FALSE; ++ return false; +} + +float check_close_to_ground(float threshold) +{ - return IS_ONGROUND(self) ? TRUE : FALSE; ++ return IS_ONGROUND(self) ? true : false; +} + +float PM_dodging_checkpressedkeys() +{ + if(!PHYS_DODGING) - return FALSE; ++ return false; - float common_factor; - float new_velocity_gain; - float velocity_difference; - float clean_up_and_do_nothing; - float horiz_speed = autocvar_sv_dodging_horiz_speed; + float frozen_dodging = (PHYS_FROZEN(self) && PHYS_DODGING_FROZEN); + float frozen_no_doubletap = (frozen_dodging && !PHYS_DODGING_FROZEN_NODOUBLETAP); - if(self.frozen) - horiz_speed = autocvar_sv_dodging_horiz_speed_frozen; + // first check if the last dodge is far enough back in time so we can dodge again + if ((time - self.last_dodging_time) < PHYS_DODGING_DELAY) - return FALSE; ++ return false; + + makevectors(PHYS_WORLD_ANGLES(self)); + + if (check_close_to_ground(PHYS_DODGING_HEIGHT_THRESHOLD) != 1 + && check_close_to_wall(PHYS_DODGING_DISTANCE_THRESHOLD) != 1) - return TRUE; ++ return true; + + float tap_direction_x = 0; + float tap_direction_y = 0; + float dodge_detected = 0; + + #define X(COND,BTN,RESULT) \ + if (PHYS_INPUT_MOVEVALUES(self)_##COND) \ + /* is this a state change? */ \ + if(!(PHYS_DODGING_PRESSED_KEYS(self) & KEY_##BTN) || frozen_no_doubletap) { \ + tap_direction_##RESULT; \ + if ((time - self.last_##BTN##_KEY_time) < PHYS_DODGING_TIMEOUT(self)) \ + dodge_detected = 1; \ + self.last_##BTN##_KEY_time = time; \ + } + X(x < 0, BACKWARD, x--); + X(x > 0, FORWARD, x++); + X(y < 0, LEFT, y--); + X(y > 0, RIGHT, y++); + #undef X + + if (dodge_detected == 1) + { + self.last_dodging_time = time; + + self.dodging_action = 1; + self.dodging_single_action = 1; - if (self.deadflag != DEAD_NO) - return 0; + self.dodging_velocity_gain = PHYS_DODGING_HORIZ_SPEED; - new_velocity_gain = 0; - clean_up_and_do_nothing = 0; + self.dodging_direction_x = tap_direction_x; + self.dodging_direction_y = tap_direction_y; - if (g_dodging == 0) - clean_up_and_do_nothing = 1; + // normalize the dodging_direction vector.. (unlike UT99) XD + float length = self.dodging_direction_x * self.dodging_direction_x + + self.dodging_direction_y * self.dodging_direction_y; + length = sqrt(length); + + self.dodging_direction_x = self.dodging_direction_x * 1.0 / length; + self.dodging_direction_y = self.dodging_direction_y * 1.0 / length; - return TRUE; ++ return true; + } - return FALSE; ++ return false; +} + +void PM_dodging() +{ + if (!PHYS_DODGING) + return; + +#ifdef SVQC + dodging_UpdateStats(); +#endif + + if (PHYS_DEAD(self)) + return; // when swimming, no dodging allowed.. if (self.waterlevel >= WATERLEVEL_SWIMMING) @@@ -254,8 -99,7 +253,8 @@@ if (autocvar_sv_dodging_sound == 1) PlayerSound(playersound_jump, CH_PLAYER, VOICETYPE_PLAYERSOUND); - animdecide_setaction(self, ANIMACTION_JUMP, TRUE); + animdecide_setaction(self, ANIMACTION_JUMP, true); +#endif self.dodging_single_action = 0; } @@@ -268,29 -112,141 +267,29 @@@ self.dodging_direction_x = 0; self.dodging_direction_y = 0; } - - return 0; -} - - -// returns 1 if the player is close to a wall -float check_close_to_wall(float threshold) { - if (autocvar_sv_dodging_wall_dodging == 0) - return 0; - - vector trace_start; - vector trace_end; - - trace_start = self.origin; - - trace_end = self.origin + (1000*v_right); - tracebox(trace_start, self.mins, self.maxs, trace_end, true, self); - if (trace_fraction < 1 && vlen (self.origin - trace_endpos) < threshold) - return 1; - - trace_end = self.origin - (1000*v_right); - tracebox(trace_start, self.mins, self.maxs, trace_end, true, self); - if (trace_fraction < 1 && vlen (self.origin - trace_endpos) < threshold) - return 1; - - trace_end = self.origin + (1000*v_forward); - tracebox(trace_start, self.mins, self.maxs, trace_end, true, self); - if (trace_fraction < 1 && vlen (self.origin - trace_endpos) < threshold) - return 1; - - trace_end = self.origin - (1000*v_forward); - tracebox(trace_start, self.mins, self.maxs, trace_end, true, self); - if (trace_fraction < 1 && vlen (self.origin - trace_endpos) < threshold) - return 1; - - return 0; } -float check_close_to_ground(float threshold) { - if (self.flags & FL_ONGROUND) - return 1; +#ifdef SVQC - return 0; +MUTATOR_HOOKFUNCTION(dodging_GetCvars) +{ + GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_dodging_timeout, "cl_dodging_timeout"); - return FALSE; ++ return false; } - -MUTATOR_HOOKFUNCTION(dodging_GetPressedKeys) { +MUTATOR_HOOKFUNCTION(dodging_PlayerPhysics) +{ // print("dodging_PlayerPhysics\n"); + PM_dodging(); - return FALSE; - float length; - vector tap_direction = '0 0 0'; - - float frozen_dodging, frozen_no_doubletap; - frozen_dodging = (self.frozen && autocvar_sv_dodging_frozen); - frozen_no_doubletap = (frozen_dodging && !autocvar_sv_dodging_frozen_doubletap); - - float dodge_detected; - if (g_dodging == 0) - return 0; - - dodge_detected = 0; - - // first check if the last dodge is far enough back in time so we can dodge again - if ((time - self.last_dodging_time) < autocvar_sv_dodging_delay) - return 0; - - if (check_close_to_ground(autocvar_sv_dodging_height_threshold) != 1 - && check_close_to_wall(autocvar_sv_dodging_wall_distance_threshold) != 1) - return 0; - - if (self.movement.x > 0) { - // is this a state change? - if (!(self.pressedkeys & KEY_FORWARD) || frozen_no_doubletap) { - if ((time - self.last_FORWARD_KEY_time) < self.cvar_cl_dodging_timeout) { - tap_direction.x = 1.0; - dodge_detected = 1; - } - self.last_FORWARD_KEY_time = time; - } - } - - if (self.movement.x < 0) { - // is this a state change? - if (!(self.pressedkeys & KEY_BACKWARD) || frozen_no_doubletap) { - tap_direction.x = -1.0; - if ((time - self.last_BACKWARD_KEY_time) < self.cvar_cl_dodging_timeout) { - dodge_detected = 1; - } - self.last_BACKWARD_KEY_time = time; - } - } - - if (self.movement.y > 0) { - // is this a state change? - if (!(self.pressedkeys & KEY_RIGHT) || frozen_no_doubletap) { - tap_direction.y = 1.0; - if ((time - self.last_RIGHT_KEY_time) < self.cvar_cl_dodging_timeout) { - dodge_detected = 1; - } - self.last_RIGHT_KEY_time = time; - } - } - - if (self.movement.y < 0) { - // is this a state change? - if (!(self.pressedkeys & KEY_LEFT) || frozen_no_doubletap) { - tap_direction.y = -1.0; - if ((time - self.last_LEFT_KEY_time) < self.cvar_cl_dodging_timeout) { - dodge_detected = 1; - } - self.last_LEFT_KEY_time = time; - } - } - - if (dodge_detected == 1) { - self.last_dodging_time = time; - - self.dodging_action = 1; - self.dodging_single_action = 1; - - self.dodging_velocity_gain = autocvar_sv_dodging_horiz_speed; - - self.dodging_direction_x = tap_direction.x; - self.dodging_direction_y = tap_direction.y; - - // normalize the dodging_direction vector.. (unlike UT99) XD - length = self.dodging_direction.x * self.dodging_direction.x; - length = length + self.dodging_direction.y * self.dodging_direction.y; - length = sqrt(length); ++ return false; +} - self.dodging_direction_x = self.dodging_direction.x * 1.0/length; - self.dodging_direction_y = self.dodging_direction.y * 1.0/length; - } +MUTATOR_HOOKFUNCTION(dodging_GetPressedKeys) +{ + PM_dodging_checkpressedkeys(); - return FALSE; - return 0; ++ return false; } MUTATOR_DEFINITION(mutator_dodging) @@@ -318,6 -273,9 +317,6 @@@ g_dodging = 0; } - return FALSE; - MUTATOR_ONREMOVE - { - } - - return 0; ++ return false; } +#endif diff --cc qcsrc/server/mutators/mutator_multijump.qc index bb60cc9bd,d36f3ecbe..f78e6e044 --- a/qcsrc/server/mutators/mutator_multijump.qc +++ b/qcsrc/server/mutators/mutator_multijump.qc @@@ -1,67 -1,30 +1,67 @@@ .float multijump_count; .float multijump_ready; -MUTATOR_HOOKFUNCTION(multijump_PlayerPhysics) +#ifdef CSQC + +#define PHYS_MULTIJUMP getstati(STAT_MULTIJUMP) +#define PHYS_MULTIJUMP_SPEED getstatf(STAT_MULTIJUMP_SPEED) +#define PHYS_MULTIJUMP_ADD getstati(STAT_MULTIJUMP_ADD) + +#elif defined(SVQC) + +#define PHYS_MULTIJUMP autocvar_g_multijump +#define PHYS_MULTIJUMP_SPEED autocvar_g_multijump_speed +#define PHYS_MULTIJUMP_ADD autocvar_g_multijump_add + + +.float stat_multijump; +.float stat_multijump_speed; +.float stat_multijump_add; + +void multijump_UpdateStats() { - if(self.flags & FL_ONGROUND) - self.multijump_count = 0; + self.stat_multijump = PHYS_MULTIJUMP; + self.stat_multijump_speed = PHYS_MULTIJUMP_SPEED; + self.stat_multijump_add = PHYS_MULTIJUMP_ADD; +} - return false; +void multijump_AddStats() +{ + addstat(STAT_MULTIJUMP, AS_INT, stat_multijump); + addstat(STAT_MULTIJUMP_SPEED, AS_FLOAT, stat_multijump_speed); + addstat(STAT_MULTIJUMP_ADD, AS_INT, stat_multijump_add); } -MUTATOR_HOOKFUNCTION(multijump_PlayerJump) +#endif + +void PM_multijump() { - if (self.flags & FL_JUMPRELEASED && !(self.flags & FL_ONGROUND)) // jump button pressed this frame and we are in midair + if(!PHYS_MULTIJUMP) { return; } + + if(IS_ONGROUND(self)) + { + self.multijump_count = 0; + } +} + +float PM_multijump_checkjump() +{ - if(!PHYS_MULTIJUMP) { return FALSE; } ++ if(!PHYS_MULTIJUMP) { return false; } + + if (!IS_JUMP_HELD(self) && !IS_ONGROUND(self)) // jump button pressed this frame and we are in midair - self.multijump_ready = TRUE; // this is necessary to check that we released the jump button and pressed it again + self.multijump_ready = true; // this is necessary to check that we released the jump button and pressed it again else - self.multijump_ready = FALSE; + self.multijump_ready = false; - if(!player_multijump && self.multijump_ready && (autocvar_g_multijump == -1 || self.multijump_count < autocvar_g_multijump) && self.velocity.z > autocvar_g_multijump_speed) + if(!player_multijump && self.multijump_ready && (self.multijump_count < PHYS_MULTIJUMP || PHYS_MULTIJUMP == -1) && self.velocity_z > PHYS_MULTIJUMP_SPEED) { - if (autocvar_g_multijump) + if (PHYS_MULTIJUMP) { - if (autocvar_g_multijump_add == 0) // in this case we make the z velocity == jumpvelocity + if (!PHYS_MULTIJUMP_ADD) // in this case we make the z velocity == jumpvelocity { - if (self.velocity.z < autocvar_sv_jumpvelocity) + if (self.velocity_z < PHYS_JUMPVELOCITY) { - player_multijump = TRUE; + player_multijump = true; self.velocity_z = 0; } } @@@ -95,26 -53,12 +95,26 @@@ self.multijump_count += 1; } } - self.multijump_ready = FALSE; // require releasing and pressing the jump button again for the next jump + self.multijump_ready = false; // require releasing and pressing the jump button again for the next jump } - return FALSE; + return false; } +#ifdef SVQC +MUTATOR_HOOKFUNCTION(multijump_PlayerPhysics) +{ + multijump_UpdateStats(); + PM_multijump(); + - return FALSE; ++ return false; +} + +MUTATOR_HOOKFUNCTION(multijump_PlayerJump) +{ + return PM_multijump_checkjump(); +} + MUTATOR_HOOKFUNCTION(multijump_BuildMutatorsString) { ret_string = strcat(ret_string, ":multijump"); @@@ -134,11 -78,5 +134,11 @@@ MUTATOR_DEFINITION(mutator_multijump MUTATOR_HOOK(BuildMutatorsString, multijump_BuildMutatorsString, CBC_ORDER_ANY); MUTATOR_HOOK(BuildMutatorsPrettyString, multijump_BuildMutatorsPrettyString, CBC_ORDER_ANY); + MUTATOR_ONADD + { + multijump_AddStats(); + } + - return FALSE; + return false; } +#endif diff --cc qcsrc/server/progs.src index 723bf3156,85e75cda9..6d4c76b1b --- a/qcsrc/server/progs.src +++ b/qcsrc/server/progs.src @@@ -2,153 -2,76 +2,75 @@@ ../common/util-pre.qh sys-pre.qh - ../dpdefs/progsdefs.qc - ../dpdefs/dpextensions.qc + ../dpdefs/progsdefs.qh + ../dpdefs/dpextensions.qh sys-post.qh - ../warpzonelib/anglestransform.qh - ../warpzonelib/mathlib.qh - ../warpzonelib/common.qh - ../warpzonelib/util_server.qh - ../warpzonelib/server.qh - ../common/constants.qh - ../common/stats.qh - ../common/teams.qh - ../common/util.qh - ../common/nades.qh - ../common/buffs.qh - ../common/test.qh - ../common/counting.qh - ../common/urllib.qh - ../common/command/markup.qh - ../common/command/rpn.qh - ../common/command/generic.qh - ../common/command/shared_defs.qh - ../common/net_notice.qh - ../common/animdecide.qh - ../common/monsters/monsters.qh - ../common/monsters/sv_monsters.qh - ../common/monsters/spawn.qh - - ../common/weapons/config.qh - ../common/weapons/weapons.qh // TODO - weapons/accuracy.qh - weapons/common.qh - weapons/csqcprojectile.qh // TODO - weapons/hitplot.qh - weapons/selection.qh - weapons/spawning.qh - weapons/throwing.qh - weapons/tracing.qh - weapons/weaponstats.qh - weapons/weaponsystem.qh - - t_items.qh - - autocvars.qh - constants.qh - defs.qh // Should rename this, it has fields and globals - - ../common/notifications.qh // must be after autocvars - ../common/deathtypes.qh // must be after notifications - - mutators/mutators_include.qh - - //// tZork Turrets //// - tturrets/include/turrets_early.qh - vehicles/vehicles_def.qh - - campaign.qh - ../common/campaign_common.qh - ../common/mapinfo.qh - - command/common.qh - command/banning.qh - command/radarmap.qh - command/vote.qh - command/getreplies.qh - command/cmd.qh - command/sv_cmd.qh - - - ../common/csqcmodel_settings.qh - ../csqcmodellib/common.qh - ../csqcmodellib/sv_model.qh + anticheat.qc + antilag.qc + // assault.qc + campaign.qc + cheats.qc + cl_client.qc + cl_impulse.qc -cl_physics.qc + cl_player.qc csqceffects.qc - - anticheat.qh - cheats.qh - ../common/playerstats.qh - - portals.qh - - g_hook.qh // TODO - - scores.qh - - spawnpoints.qh - - mapvoting.qh - - ipban.qh - - race.qh - - antilag.qh - - playerdemo.qh - - round_handler.qh - - // singleplayer stuff - item_key.qh - secret.qh - - scores_rules.qc - - miscfunctions.qc - - mutators/mutators.qc - - waypointsprites.qc - - bot/bot.qc - + // ctf.qc + // domination.qc + ent_cs.qc + func_breakable.qc + g_casings.qc + g_damage.qc + g_hook.qc + g_models.qc g_subs.qc - g_tetris.qc - - //runematch.qc - + g_triggers.qc g_violence.qc - g_damage.qc - - teamplay.qc - - ../common/physics.qh - ../common/physics.qc - - // tZork's libs - movelib.qc - steerlib.qc - pathlib/pathlib.qh - g_world.qc - g_casings.qc - + ipban.qc + item_key.qc mapvoting.qc - + miscfunctions.qc + // mode_onslaught.qc + movelib.qc + // nexball.qc + playerdemo.qc + portals.qc + race.qc + round_handler.qc + // runematch.qc + scores.qc + scores_rules.qc + secret.qc + spawnpoints.qc + steerlib.qc + sv_main.qc + target_music.qc + target_spawn.qc + teamplay.qc + t_halflife.qc + t_items.qc t_jumppads.qc + t_plats.qc + t_quake3.qc + t_quake.qc + t_swamp.qc t_teleporters.qc + waypointsprites.qc - sv_main.qc + bot/bot.qc - g_triggers.qc - g_models.qc + command/banning.qc + command/cmd.qc + command/common.qc + command/getreplies.qc + command/radarmap.qc + command/sv_cmd.qc + command/vote.qc - // singleplayer stuff - item_key.qc - secret.qc + mutators/mutators_include.qc + mutators/mutators.qc weapons/accuracy.qc weapons/common.qc @@@ -160,99 -83,32 +82,33 @@@ weapons/throwing.q weapons/tracing.qc weapons/weaponstats.qc weapons/weaponsystem.qc - ../common/weapons/config.qc - ../common/weapons/weapons.qc // TODO - - t_items.qc - cl_impulse.qc - - ent_cs.qc - - cl_player.qc - cl_client.qc - t_plats.qc - antilag.qc - - //ctf.qc - //domination.qc - //mode_onslaught.qc - //nexball.qc - g_hook.qc - t_swamp.qc - - campaign.qc + ../common/animdecide.qc + ../common/buffs.qc ../common/campaign_file.qc ../common/campaign_setup.qc - ../common/urllib.qc - + ../common/command/generic.qc ../common/command/markup.qc ../common/command/rpn.qc - ../common/command/generic.qc - ../common/net_notice.qc - - command/common.qc - command/banning.qc - command/radarmap.qc - command/vote.qc - command/getreplies.qc - command/cmd.qc - command/sv_cmd.qc - - //assault.qc - - ipban.qc - ../common/mapinfo.qc - - t_quake3.qc - t_halflife.qc - t_quake.qc - - race.qc - - - //// tZork Turrets //// - tturrets/include/turrets.qh - vehicles/vehicles.qh - - scores.qc - - spawnpoints.qc - - portals.qc - - target_spawn.qc - func_breakable.qc - target_music.qc - - ../common/nades.qc - ../common/buffs.qc - - ../csqcmodellib/sv_model.qc - - playerdemo.qc - - anticheat.qc - cheats.qc - ../common/playerstats.qc - - round_handler.qc - - ../common/monsters/sv_monsters.qc ../common/monsters/monsters.qc - ../common/monsters/spawn.qc + ../common/monsters/sv_monsters.qc + ../common/nades.qc + ../common/net_notice.qc + ../common/notifications.qc ++../common/physics.qc + ../common/playerstats.qc + ../common/test.qc + ../common/urllib.qc + ../common/util.qc + ../common/weapons/config.qc + ../common/weapons/weapons.qc // TODO - mutators/mutators_include.qc + ../csqcmodellib/sv_model.qc ../warpzonelib/anglestransform.qc - ../warpzonelib/mathlib.qc ../warpzonelib/common.qc - ../warpzonelib/util_server.qc + ../warpzonelib/mathlib.qc ../warpzonelib/server.qc - - ../common/animdecide.qc - ../common/test.qc - ../common/util.qc - ../common/notifications.qc + ../warpzonelib/util_server.qc diff --cc qcsrc/server/race.qh index 09b4b36ce,bfdc9be43..b51c1a9c7 --- a/qcsrc/server/race.qh +++ b/qcsrc/server/race.qh @@@ -26,3 -29,4 +29,40 @@@ float race_GetFractionalLapCount(entit float race_readTime(string map, float pos); string race_readUID(string map, float pos); string race_readName(string map, float pos); ++ ++ ++#ifdef SVQC ++float speedaward_speed; ++string speedaward_holder; ++string speedaward_uid; ++#endif ++void race_send_speedaward(float msg) ++{ ++#ifdef SVQC ++ // send the best speed of the round ++ WriteByte(msg, SVC_TEMPENTITY); ++ WriteByte(msg, TE_CSQC_RACE); ++ WriteByte(msg, RACE_NET_SPEED_AWARD); ++ WriteInt24_t(msg, floor(speedaward_speed+0.5)); ++ WriteString(msg, speedaward_holder); ++#endif ++} ++ ++#ifdef SVQC ++float speedaward_alltimebest; ++string speedaward_alltimebest_holder; ++string speedaward_alltimebest_uid; ++#endif ++void race_send_speedaward_alltimebest(float msg) ++{ ++#ifdef SVQC ++ // send the best speed ++ WriteByte(msg, SVC_TEMPENTITY); ++ WriteByte(msg, TE_CSQC_RACE); ++ WriteByte(msg, RACE_NET_SPEED_AWARD_BEST); ++ WriteInt24_t(msg, floor(speedaward_alltimebest+0.5)); ++ WriteString(msg, speedaward_alltimebest_holder); ++#endif ++} ++ + #endif diff --cc qcsrc/server/t_halflife.qc index 1f45f9c82,681c5dc7d..4f6c1ca0e --- a/qcsrc/server/t_halflife.qc +++ b/qcsrc/server/t_halflife.qc @@@ -1,7 -1,12 +1,21 @@@ + #if defined(CSQC) + #elif defined(MENUQC) + #elif defined(SVQC) + #include "../dpdefs/progsdefs.qh" - #include "../warpzonelib/util_server.qh" + #include "defs.qh" + #include "vehicles/vehicles_def.qh" + #endif ++#include "../warpzonelib/util_server.qh" + ++#include "miscfunctions.qh" ++#ifdef CSQC ++#define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return ++#endif ++ +.float ladder_time; +.entity ladder_entity; + +#ifdef SVQC .float roomtype; .float radius; .float pitch; @@@ -57,43 -56,6 +71,43 @@@ void func_ladder_touch( other.ladder_entity = self; } +#ifdef SVQC +float func_ladder_send(entity to, float sf) +{ + WriteByte(MSG_ENTITY, ENT_CLIENT_LADDER); + + WriteString(MSG_ENTITY, self.classname); + WriteByte(MSG_ENTITY, self.warpzone_isboxy); + WriteByte(MSG_ENTITY, self.skin); + WriteByte(MSG_ENTITY, self.speed); + WriteByte(MSG_ENTITY, self.scale); + WriteCoord(MSG_ENTITY, self.origin_x); + WriteCoord(MSG_ENTITY, self.origin_y); + WriteCoord(MSG_ENTITY, self.origin_z); + + WriteCoord(MSG_ENTITY, self.mins_x); + WriteCoord(MSG_ENTITY, self.mins_y); + WriteCoord(MSG_ENTITY, self.mins_z); + WriteCoord(MSG_ENTITY, self.maxs_x); + WriteCoord(MSG_ENTITY, self.maxs_y); + WriteCoord(MSG_ENTITY, self.maxs_z); + + WriteCoord(MSG_ENTITY, self.movedir_x); + WriteCoord(MSG_ENTITY, self.movedir_y); + WriteCoord(MSG_ENTITY, self.movedir_z); + + WriteCoord(MSG_ENTITY, self.angles_x); + WriteCoord(MSG_ENTITY, self.angles_y); + WriteCoord(MSG_ENTITY, self.angles_z); + - return TRUE; ++ return true; +} + +void func_ladder_link() +{ - Net_LinkEntity(self, FALSE, 0, func_ladder_send); ++ Net_LinkEntity(self, false, 0, func_ladder_send); +} + void spawnfunc_func_ladder() { EXACTTRIGGER_INIT; diff --cc qcsrc/server/t_jumppads.qc index fa2f4fe50,92af1cdd0..480f5c37f --- a/qcsrc/server/t_jumppads.qc +++ b/qcsrc/server/t_jumppads.qc @@@ -1,38 -1,11 +1,17 @@@ - .float height; - - #ifdef CSQC - .float active; - .string target; - .string targetname; - #define ACTIVE_NOT 0 - #define ACTIVE_ACTIVE 1 - #define ACTIVE_IDLE 2 - #define ACTIVE_BUSY 2 - #define ACTIVE_TOGGLE 3 - #endif + #include "t_jumppads.qh" +#ifdef SVQC + - const float PUSH_ONCE = 1; - const float PUSH_SILENT = 2; - - .float pushltime; - .float istypefrag; - - void() SUB_UseTargets; - void trigger_push_use() { if(teamplay) + { self.team = activator.team; + self.SendFlags |= 2; + } } +#endif - float trigger_push_calculatevelocity_flighttime; - /* trigger_push_calculatevelocity @@@ -54,11 -27,11 +33,11 @@@ vector trigger_push_calculatevelocity(v torg = tgt.origin + (tgt.mins + tgt.maxs) * 0.5; - grav = autocvar_sv_gravity; - if(other.gravity) - grav *= other.gravity; + grav = PHYS_GRAVITY; + if(PHYS_ENTGRAVITY(other)) + grav *= PHYS_ENTGRAVITY(other); - zdist = torg_z - org_z; + zdist = torg.z - org.z; sdist = vlen(torg - org - zdist * '0 0 1'); sdir = normalize(torg - org - zdist * '0 0 1'); @@@ -331,67 -288,8 +307,67 @@@ void trigger_push_findtarget( waypoint_spawnforteleporter(self, trace_endpos, vlen(trace_endpos - org) / vlen(e.velocity)); remove(e); } + + trigger_push_link(); + defer(0.1, trigger_push_updatelink); +#endif } +#ifdef SVQC +float trigger_push_send(entity to, float sf) +{ + WriteByte(MSG_ENTITY, ENT_CLIENT_TRIGGER_PUSH); + WriteByte(MSG_ENTITY, sf); + + if(sf & 1) + { + WriteString(MSG_ENTITY, self.target); + WriteByte(MSG_ENTITY, self.team); + WriteInt24_t(MSG_ENTITY, self.spawnflags); + WriteByte(MSG_ENTITY, self.active); + WriteByte(MSG_ENTITY, self.warpzone_isboxy); + WriteByte(MSG_ENTITY, self.height); + WriteByte(MSG_ENTITY, self.scale); + WriteCoord(MSG_ENTITY, self.origin_x); + WriteCoord(MSG_ENTITY, self.origin_y); + WriteCoord(MSG_ENTITY, self.origin_z); + + WriteCoord(MSG_ENTITY, self.mins_x); + WriteCoord(MSG_ENTITY, self.mins_y); + WriteCoord(MSG_ENTITY, self.mins_z); + WriteCoord(MSG_ENTITY, self.maxs_x); + WriteCoord(MSG_ENTITY, self.maxs_y); + WriteCoord(MSG_ENTITY, self.maxs_z); + + WriteCoord(MSG_ENTITY, self.movedir_x); + WriteCoord(MSG_ENTITY, self.movedir_y); + WriteCoord(MSG_ENTITY, self.movedir_z); + + WriteCoord(MSG_ENTITY, self.angles_x); + WriteCoord(MSG_ENTITY, self.angles_y); + WriteCoord(MSG_ENTITY, self.angles_z); + } + + if(sf & 2) + { + WriteByte(MSG_ENTITY, self.team); + WriteByte(MSG_ENTITY, self.active); + } + - return TRUE; ++ return true; +} + +void trigger_push_updatelink() +{ + self.SendFlags |= 1; +} + +void trigger_push_link() +{ - Net_LinkEntity(self, FALSE, 0, trigger_push_send); ++ Net_LinkEntity(self, false, 0, trigger_push_send); +} +#endif +#ifdef SVQC /* * ENTITY PARAMETERS: * @@@ -427,99 -325,6 +403,99 @@@ void spawnfunc_trigger_push( InitializeEntity(self, trigger_push_findtarget, INITPRIO_FINDTARGET); } -void spawnfunc_target_push() {} -void spawnfunc_info_notnull() {} -void spawnfunc_target_position() {} + +float target_push_send(entity to, float sf) +{ + WriteByte(MSG_ENTITY, ENT_CLIENT_TARGET_PUSH); + + WriteByte(MSG_ENTITY, self.cnt); + WriteString(MSG_ENTITY, self.targetname); + WriteCoord(MSG_ENTITY, self.origin_x); + WriteCoord(MSG_ENTITY, self.origin_y); + WriteCoord(MSG_ENTITY, self.origin_z); + - return TRUE; ++ return true; +} + +void target_push_link() +{ - Net_LinkEntity(self, FALSE, 0, target_push_send); ++ Net_LinkEntity(self, false, 0, target_push_send); + self.SendFlags |= 1; // update +} + +void spawnfunc_target_push() { target_push_link(); } +void spawnfunc_info_notnull() { target_push_link(); } +void spawnfunc_target_position() { target_push_link(); } + +#endif + +#ifdef CSQC +void trigger_push_draw() +{ + float dt = time - self.move_time; + self.move_time = time; + if(dt <= 0) { return; } + + trigger_touch_generic(trigger_push_touch); +} + +void ent_trigger_push() +{ + float sf = ReadByte(); + + if(sf & 1) + { + self.classname = "jumppad"; + self.target = strzone(ReadString()); + float mytm = ReadByte(); if(mytm) { self.team = mytm - 1; } + self.spawnflags = ReadInt24_t(); + self.active = ReadByte(); + self.warpzone_isboxy = ReadByte(); + self.height = ReadByte(); + self.scale = ReadByte(); + self.origin_x = ReadCoord(); + self.origin_y = ReadCoord(); + self.origin_z = ReadCoord(); + setorigin(self, self.origin); + self.mins_x = ReadCoord(); + self.mins_y = ReadCoord(); + self.mins_z = ReadCoord(); + self.maxs_x = ReadCoord(); + self.maxs_y = ReadCoord(); + self.maxs_z = ReadCoord(); + setsize(self, self.mins, self.maxs); + self.movedir_x = ReadCoord(); + self.movedir_y = ReadCoord(); + self.movedir_z = ReadCoord(); + self.angles_x = ReadCoord(); + self.angles_y = ReadCoord(); + self.angles_z = ReadCoord(); + + self.solid = SOLID_TRIGGER; + //self.draw = trigger_push_draw; + self.drawmask = MASK_ENGINE; + self.move_time = time; + //self.touch = trigger_push_touch; + trigger_push_findtarget(); + } + + if(sf & 2) + { + self.team = ReadByte(); + self.active = ReadByte(); + } +} + +void ent_target_push() +{ + self.classname = "push_target"; + self.cnt = ReadByte(); + self.targetname = strzone(ReadString()); + self.origin_x = ReadCoord(); + self.origin_y = ReadCoord(); + self.origin_z = ReadCoord(); + setorigin(self, self.origin); + + self.drawmask = MASK_ENGINE; +} +#endif diff --cc qcsrc/server/t_jumppads.qh index 000000000,9d66e9890..36f203b9e mode 000000,100644..100644 --- a/qcsrc/server/t_jumppads.qh +++ b/qcsrc/server/t_jumppads.qh @@@ -1,0 -1,55 +1,72 @@@ + #ifndef T_JUMPPADS_H + #define T_JUMPPADS_H + + const float PUSH_ONCE = 1; + const float PUSH_SILENT = 2; + + .float pushltime; + .float istypefrag; + .float height; + -void() SUB_UseTargets; + + float trigger_push_calculatevelocity_flighttime; + ++#ifdef SVQC ++void() SUB_UseTargets; + void trigger_push_use(); ++#endif ++ ++#ifdef CSQC ++.float active; ++.string target; ++.string targetname; ++ ++const int ACTIVE_NOT = 0; ++const int ACTIVE_ACTIVE = 1; ++const int ACTIVE_IDLE = 2; ++const int ACTIVE_BUSY = 2; ++const int ACTIVE_TOGGLE = 3; ++void trigger_push_draw(); ++#endif + + /* + trigger_push_calculatevelocity + + Arguments: + org - origin of the object which is to be pushed + tgt - target entity (can be either a point or a model entity; if it is + the latter, its midpoint is used) + ht - jump height, measured from the higher one of org and tgt's midpoint + + Returns: velocity for the jump + the global trigger_push_calculatevelocity_flighttime is set to the total + jump time + */ + + vector trigger_push_calculatevelocity(vector org, entity tgt, float ht); + + void trigger_push_touch(); + + .vector dest; + void trigger_push_findtarget(); + + /* + * ENTITY PARAMETERS: + * + * target: target of jump + * height: the absolute value is the height of the highest point of the jump + * trajectory above the higher one of the player and the target. + * the sign indicates whether the highest point is INSIDE (positive) + * or OUTSIDE (negative) of the jump trajectory. General rule: use + * positive values for targets mounted on the floor, and use negative + * values to target a point on the ceiling. + * movedir: if target is not set, this * speed * 10 is the velocity to be reached. + */ ++#ifdef SVQC + void spawnfunc_trigger_push(); + + void spawnfunc_target_push(); + void spawnfunc_info_notnull(); + void spawnfunc_target_position(); + #endif ++#endif diff --cc qcsrc/server/t_plats.qc index 7bf3c70a8,22b4cf669..c22f87a45 --- a/qcsrc/server/t_plats.qc +++ b/qcsrc/server/t_plats.qc @@@ -1,5 -1,22 +1,24 @@@ + #if defined(CSQC) + #elif defined(MENUQC) + #elif defined(SVQC) + #include "../dpdefs/progsdefs.qh" + #include "../dpdefs/dpextensions.qh" + #include "../warpzonelib/mathlib.qh" + #include "../warpzonelib/common.qh" + #include "../warpzonelib/util_server.qh" + #include "../common/constants.qh" + #include "../common/util.qh" + #include "../common/weapons/weapons.qh" + #include "constants.qh" + #include "defs.qh" + #include "../common/notifications.qh" + #include "../common/deathtypes.qh" + #include "command/common.qh" + #include "../csqcmodellib/sv_model.qh" + #endif + +#ifdef SVQC + .float dmgtime2; void generic_plat_blocked() { @@@ -2249,44 -2236,6 +2262,44 @@@ void conveyor_use( void conveyor_reset() { self.state = (self.spawnflags & 1); + + self.SendFlags |= 2; +} + +float conveyor_send(entity to, float sf) +{ + WriteByte(MSG_ENTITY, ENT_CLIENT_CONVEYOR); + WriteByte(MSG_ENTITY, sf); + + if(sf & 1) + { + WriteByte(MSG_ENTITY, self.warpzone_isboxy); + WriteCoord(MSG_ENTITY, self.origin_x); + WriteCoord(MSG_ENTITY, self.origin_y); + WriteCoord(MSG_ENTITY, self.origin_z); + + WriteCoord(MSG_ENTITY, self.mins_x); + WriteCoord(MSG_ENTITY, self.mins_y); + WriteCoord(MSG_ENTITY, self.mins_z); + WriteCoord(MSG_ENTITY, self.maxs_x); + WriteCoord(MSG_ENTITY, self.maxs_y); + WriteCoord(MSG_ENTITY, self.maxs_z); + + WriteCoord(MSG_ENTITY, self.movedir_x); + WriteCoord(MSG_ENTITY, self.movedir_y); + WriteCoord(MSG_ENTITY, self.movedir_z); + + WriteByte(MSG_ENTITY, self.speed); + WriteByte(MSG_ENTITY, self.state); + + WriteString(MSG_ENTITY, self.targetname); + WriteString(MSG_ENTITY, self.target); + } + + if(sf & 2) + WriteByte(MSG_ENTITY, self.state); + - return TRUE; ++ return true; } void conveyor_init() @@@ -2304,10 -2253,6 +2317,10 @@@ } else self.state = 1; + - Net_LinkEntity(self, 0, FALSE, conveyor_send); ++ Net_LinkEntity(self, 0, false, conveyor_send); + + self.SendFlags |= 1; } void spawnfunc_trigger_conveyor() diff --cc qcsrc/warpzonelib/common.qc index 521cf343b,aa0de9119..6481242dc --- a/qcsrc/warpzonelib/common.qc +++ b/qcsrc/warpzonelib/common.qc @@@ -763,64 -772,3 +772,64 @@@ entity WarpZone_RefSys_SpawnSameRefSys( WarpZone_RefSys_Copy(e, me); return e; } + +float WarpZoneLib_ExactTrigger_Touch() +{ + return !WarpZoneLib_BoxTouchesBrush(other.absmin, other.absmax, self, other); +} + + +void WarpZoneLib_MoveOutOfSolid_Expand(entity e, vector by) +{ + float eps = 0.0625; + tracebox(e.origin, e.mins - '1 1 1' * eps, e.maxs + '1 1 1' * eps, e.origin + by, MOVE_WORLDONLY, e); + if (trace_startsolid) + return; + if (trace_fraction < 1) + { + // hit something + // adjust origin in the other direction... + setorigin(e,e.origin - by * (1 - trace_fraction)); + } +} + +float WarpZoneLib_MoveOutOfSolid(entity e) +{ + vector o, m0, m1; + + o = e.origin; + traceline(o, o, MOVE_WORLDONLY, e); + if (trace_startsolid) - return FALSE; ++ return false; + + tracebox(o, e.mins, e.maxs, o, MOVE_WORLDONLY, e); + if (!trace_startsolid) - return TRUE; ++ return true; + + m0 = e.mins; + m1 = e.maxs; + e.mins = '0 0 0'; + e.maxs = '0 0 0'; + WarpZoneLib_MoveOutOfSolid_Expand(e, '1 0 0' * m0_x); + e.mins_x = m0_x; + WarpZoneLib_MoveOutOfSolid_Expand(e, '1 0 0' * m1_x); + e.maxs_x = m1_x; + WarpZoneLib_MoveOutOfSolid_Expand(e, '0 1 0' * m0_y); + e.mins_y = m0_y; + WarpZoneLib_MoveOutOfSolid_Expand(e, '0 1 0' * m1_y); + e.maxs_y = m1_y; + WarpZoneLib_MoveOutOfSolid_Expand(e, '0 0 1' * m0_z); + e.mins_z = m0_z; + WarpZoneLib_MoveOutOfSolid_Expand(e, '0 0 1' * m1_z); + e.maxs_z = m1_z; + setorigin(e, e.origin); + + tracebox(e.origin, e.mins, e.maxs, e.origin, MOVE_WORLDONLY, e); + if (trace_startsolid) + { + setorigin(e, o); - return FALSE; ++ return false; + } + - return TRUE; ++ return true; +} diff --cc qcsrc/warpzonelib/common.qh index 8a8cfb227,7742db8b9..76a77ab02 --- a/qcsrc/warpzonelib/common.qh +++ b/qcsrc/warpzonelib/common.qh @@@ -100,6 -104,4 +104,6 @@@ entity WarpZone_RefSys_SpawnSameRefSys( #ifndef BITXOR_ASSIGN # define BITXOR_ASSIGN(a,b) ((a) = ((a) | (b)) - ((a) & (b))) #endif - +float WarpZoneLib_MoveOutOfSolid(entity e); +#define move_out_of_solid(e) WarpZoneLib_MoveOutOfSolid(e) + #endif diff --cc qcsrc/warpzonelib/util_server.qc index 87f737a46,79cff0174..4cb061794 --- a/qcsrc/warpzonelib/util_server.qc +++ b/qcsrc/warpzonelib/util_server.qc @@@ -1,3 -1,73 +1,13 @@@ + #if defined(CSQC) + #elif defined(MENUQC) + #elif defined(SVQC) + #include "../dpdefs/progsdefs.qh" + #include "../dpdefs/dpextensions.qh" - #include "common.qh" + #include "util_server.qh" + #include "../csqcmodellib/sv_model.qh" + #endif - -void WarpZoneLib_MoveOutOfSolid_Expand(entity e, vector by) -{ - float eps = 0.0625; - tracebox(e.origin, e.mins - '1 1 1' * eps, e.maxs + '1 1 1' * eps, e.origin + by, MOVE_WORLDONLY, e); - if (trace_startsolid) - return; - if (trace_fraction < 1) - { - // hit something - // adjust origin in the other direction... - setorigin(e,e.origin - by * (1 - trace_fraction)); - } -} - -float WarpZoneLib_MoveOutOfSolid(entity e) -{ - vector o, m0, m1; - - o = e.origin; - traceline(o, o, MOVE_WORLDONLY, e); - if (trace_startsolid) - return false; - - tracebox(o, e.mins, e.maxs, o, MOVE_WORLDONLY, e); - if (!trace_startsolid) - return true; - - m0 = e.mins; - m1 = e.maxs; - e.mins = '0 0 0'; - e.maxs = '0 0 0'; - WarpZoneLib_MoveOutOfSolid_Expand(e, '1 0 0' * m0_x); - e.mins_x = m0_x; - WarpZoneLib_MoveOutOfSolid_Expand(e, '1 0 0' * m1_x); - e.maxs_x = m1_x; - WarpZoneLib_MoveOutOfSolid_Expand(e, '0 1 0' * m0_y); - e.mins_y = m0_y; - WarpZoneLib_MoveOutOfSolid_Expand(e, '0 1 0' * m1_y); - e.maxs_y = m1_y; - WarpZoneLib_MoveOutOfSolid_Expand(e, '0 0 1' * m0_z); - e.mins_z = m0_z; - WarpZoneLib_MoveOutOfSolid_Expand(e, '0 0 1' * m1_z); - e.maxs_z = m1_z; - setorigin(e, e.origin); - - tracebox(e.origin, e.mins, e.maxs, e.origin, MOVE_WORLDONLY, e); - if (trace_startsolid) - { - setorigin(e, o); - return false; - } - - return true; -} - -float WarpZoneLib_ExactTrigger_Touch() -{ - return !WarpZoneLib_BoxTouchesBrush(other.absmin, other.absmax, self, other); -} ++#include "common.qh" + void WarpZoneLib_ExactTrigger_Init() { vector mi, ma; diff --cc qcsrc/warpzonelib/util_server.qh index cd5af7fb4,38df7fe0c..0a42d7d12 --- a/qcsrc/warpzonelib/util_server.qh +++ b/qcsrc/warpzonelib/util_server.qh @@@ -1,3 -1,7 +1,9 @@@ + #ifndef UTIL_SERVER_H + #define UTIL_SERVER_H + float WarpZoneLib_MoveOutOfSolid(entity e); float WarpZoneLib_ExactTrigger_Touch(); ++#ifdef SVQC void WarpZoneLib_ExactTrigger_Init(); + #endif ++#endif