From: terencehill Date: Tue, 3 Feb 2015 18:32:51 +0000 (+0100) Subject: Merge branch 'master' into terencehill/welcome_dialog X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=c3b41654fd21757a1d35e5b9c9fdece57511ba29;p=xonotic%2Fxonotic-data.pk3dir.git Merge branch 'master' into terencehill/welcome_dialog Conflicts: qcsrc/common/constants.qh qcsrc/menu/classes.c qcsrc/menu/command/menu_cmd.qc --- c3b41654fd21757a1d35e5b9c9fdece57511ba29 diff --cc qcsrc/client/main.qc index 000000000,13f9545fa..e5a9004d9 mode 000000,100644..100644 --- a/qcsrc/client/main.qc +++ b/qcsrc/client/main.qc @@@ -1,0 -1,1319 +1,1362 @@@ + #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 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(); + 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; + + 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; + } + } + ++string welcomedialog_args; ++void Net_ReadServerInfo() ++{ ++ if(welcomedialog_args) ++ strunzone(welcomedialog_args); ++ welcomedialog_args = strcat("name \"", ReadString(), "\""); ++ welcomedialog_args = strcat(welcomedialog_args, " ip \"", ReadString(), "\""); ++ welcomedialog_args = strcat(welcomedialog_args, " motd \"", MakeConsoleSafe(strreplace("\n", "\\n", ReadString())), "\""); ++ string pic = ReadString(); ++ if(pic == "" || PreviewExists(pic) ) ++ { ++ if(pic != "") ++ welcomedialog_args = strcat(welcomedialog_args, " pic \"", pic, "\""); ++ localcmd("\nmenu_cmd directmenu Welcome ", welcomedialog_args, "\n"); ++ welcomedialog_args = string_null; ++ return; ++ } else { ++ welcomedialog_args = strzone(welcomedialog_args); ++ print(_("Requesting server banner...\n")); ++ localcmd("\ncmd getserverpic\n"); ++ } ++} ++ ++void Net_ReadServerInfo_Pic() ++{ ++ if(welcomedialog_args) ++ { ++ localcmd("\nmenu_cmd directmenu Welcome ", strcat(welcomedialog_args, " pic \"", ReadPicture(), "\""), "\n"); ++ strunzone(welcomedialog_args); ++ welcomedialog_args = string_null; ++ } ++ else // just get the image, we don't want to display the welcome dialog ++ ReadPicture(); ++} ++ + // 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; ++ case TE_CSQC_SERVERINFO: ++ Net_ReadServerInfo(); ++ bHandled = true; ++ break; ++ case TE_CSQC_SERVERINFO_PIC: ++ Net_ReadServerInfo_Pic(); ++ 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/common/constants.qh index 25ae390ac,45a65abbe..e72164427 --- a/qcsrc/common/constants.qh +++ b/qcsrc/common/constants.qh @@@ -1,126 -1,102 +1,104 @@@ - // 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 TE_CSQC_SERVERINFO = 115; - const float TE_CSQC_SERVERINFO_PIC = 116; - - 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_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; + #ifndef CONSTANTS_H + #define CONSTANTS_H + + 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 TE_CSQC_SERVERINFO = 115; ++const int TE_CSQC_SERVERINFO_PIC = 116; + + 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_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/menu/classes.qc index 000000000,9b4bb4dab..7439a3ed7 mode 000000,100644..100644 --- a/qcsrc/menu/classes.qc +++ b/qcsrc/menu/classes.qc @@@ -1,0 -1,130 +1,132 @@@ + #include "anim/animhost.qc" + #include "anim/animation.qc" + #include "anim/easing.qc" + #include "anim/keyframe.qc" + #include "item.qc" + #include "item/container.qc" + #include "item/inputcontainer.qc" + #include "item/nexposee.qc" + #include "item/modalcontroller.qc" + #include "item/image.qc" + #include "item/label.qc" + #include "item/button.qc" + #include "item/checkbox.qc" + #include "item/radiobutton.qc" + #include "item/borderimage.qc" + #include "item/slider.qc" + #include "item/dialog.qc" + #include "item/tab.qc" + #include "item/textslider.qc" + #include "item/listbox.qc" + #include "item/inputbox.qc" + #include "xonotic/dialog.qc" + #include "xonotic/tab.qc" + #include "xonotic/mainwindow.qc" + #include "xonotic/button.qc" + #include "xonotic/bigbutton.qc" + #include "xonotic/commandbutton.qc" + #include "xonotic/bigcommandbutton.qc" + #include "xonotic/textlabel.qc" + #include "xonotic/dialog_firstrun.qc" ++#include "xonotic/dialog_welcome.qc" + #include "xonotic/dialog_teamselect.qc" + #include "xonotic/dialog_sandboxtools.qc" + #include "xonotic/dialog_monstertools.qc" + #include "xonotic/dialog_settings.qc" + #include "xonotic/dialog_settings_video.qc" + #include "xonotic/dialog_settings_effects.qc" + #include "xonotic/dialog_settings_audio.qc" + #include "xonotic/dialog_settings_game.qc" + #include "xonotic/dialog_settings_user.qc" + #include "xonotic/dialog_settings_user_languagewarning.qc" + #include "xonotic/dialog_settings_misc.qc" + #include "xonotic/dialog_multiplayer.qc" + #include "xonotic/dialog_multiplayer_profile.qc" + #include "xonotic/tabcontroller.qc" + #include "xonotic/slider.qc" + #include "xonotic/slider_resolution.qc" + #include "xonotic/checkbox.qc" + #include "xonotic/checkbox_string.qc" + #include "xonotic/weaponarenacheckbox.qc" + #include "xonotic/radiobutton.qc" + #include "xonotic/nexposee.qc" + #include "xonotic/rootdialog.qc" + #include "xonotic/textslider.qc" + #include "xonotic/colorbutton.qc" + #include "xonotic/dialog_multiplayer_join.qc" + #include "xonotic/dialog_multiplayer_join_serverinfo.qc" + #include "xonotic/playerlist.qc" + #include "xonotic/listbox.qc" ++#include "xonotic/textlistbox.qc" + #include "xonotic/serverlist.qc" + #include "xonotic/inputbox.qc" + #include "xonotic/dialog_quit.qc" + #include "xonotic/dialog_multiplayer_create.qc" + #include "xonotic/dialog_multiplayer_create_mutators.qc" + #include "xonotic/dialog_multiplayer_create_mapinfo.qc" + #include "xonotic/gametypelist.qc" + #include "xonotic/maplist.qc" + #include "xonotic/skinlist.qc" + #include "xonotic/languagelist.qc" + #include "xonotic/image.qc" + #include "xonotic/crosshairbutton.qc" + #include "xonotic/playermodel.qc" + #include "xonotic/checkbox_slider_invalid.qc" + #include "xonotic/charmap.qc" + #include "xonotic/keybinder.qc" + #include "xonotic/dialog_settings_input.qc" + #include "xonotic/dialog_settings_input_userbind.qc" + #include "xonotic/slider_decibels.qc" + #include "xonotic/dialog_singleplayer.qc" + #include "xonotic/campaign.qc" + #include "xonotic/dialog_singleplayer_winner.qc" + #include "xonotic/dialog_credits.qc" + #include "xonotic/credits.qc" + #include "xonotic/dialog_settings_game_crosshair.qc" + #include "xonotic/dialog_settings_game_hud.qc" + #include "xonotic/dialog_settings_game_hudconfirm.qc" + #include "xonotic/dialog_settings_game_model.qc" + #include "xonotic/dialog_settings_game_messages.qc" + #include "xonotic/dialog_settings_game_view.qc" + #include "xonotic/dialog_settings_game_weapons.qc" + #include "xonotic/weaponslist.qc" + #include "xonotic/dialog_multiplayer_media.qc" + #include "xonotic/dialog_multiplayer_media_demo.qc" + #include "xonotic/dialog_multiplayer_media_demo_startconfirm.qc" + #include "xonotic/dialog_multiplayer_media_demo_timeconfirm.qc" + #include "xonotic/demolist.qc" + #include "xonotic/screenshotimage.qc" + #include "xonotic/dialog_multiplayer_media_screenshot.qc" + #include "xonotic/dialog_multiplayer_media_screenshot_viewer.qc" + #include "xonotic/screenshotlist.qc" + #include "xonotic/statslist.qc" + #include "xonotic/dialog_multiplayer_media_musicplayer.qc" + #include "xonotic/soundlist.qc" + #include "xonotic/playlist.qc" + #include "xonotic/colorpicker.qc" + #include "xonotic/colorpicker_string.qc" + #include "xonotic/cvarlist.qc" + #include "xonotic/dialog_settings_misc_cvars.qc" + #include "xonotic/dialog_hudsetup_exit.qc" + #include "xonotic/dialog_hudpanel_notification.qc" + #include "xonotic/dialog_hudpanel_ammo.qc" + #include "xonotic/dialog_hudpanel_healtharmor.qc" + #include "xonotic/dialog_hudpanel_powerups.qc" + #include "xonotic/dialog_hudpanel_racetimer.qc" + #include "xonotic/dialog_hudpanel_pressedkeys.qc" + #include "xonotic/dialog_hudpanel_radar.qc" + #include "xonotic/dialog_hudpanel_score.qc" + #include "xonotic/dialog_hudpanel_timer.qc" + #include "xonotic/dialog_hudpanel_vote.qc" + #include "xonotic/dialog_hudpanel_modicons.qc" + #include "xonotic/dialog_hudpanel_chat.qc" + #include "xonotic/dialog_hudpanel_engineinfo.qc" + #include "xonotic/dialog_hudpanel_infomessages.qc" + #include "xonotic/dialog_hudpanel_weapons.qc" + #include "xonotic/dialog_hudpanel_physics.qc" + #include "xonotic/dialog_hudpanel_centerprint.qc" + #include "xonotic/dialog_hudpanel_buffs.qc" + #include "xonotic/slider_picmip.qc" + #include "xonotic/slider_particles.qc" + #include "xonotic/slider_sbfadetime.qc" + #include "xonotic/dialog_settings_misc_reset.qc" diff --cc qcsrc/menu/command/menu_cmd.qc index 6b8ba6c30,93825cd56..dac57f34a --- a/qcsrc/menu/command/menu_cmd.qc +++ b/qcsrc/menu/command/menu_cmd.qc @@@ -85,27 -89,10 +89,30 @@@ void GameCommand(string theCommand } } else if(argc == 2 && !isdemo()) // don't allow this command in demos + { + m_play_click_sound(MENU_SOUND_OPEN); m_goto(strcat(filter, argv(1))); // switch to a menu item + } + else if(argc > 2 && !isdemo()) + { + float argsbuf = 0; + s = strzone(argv(1)); // dialog name + for(i = 0, e = world; (e = nextent(e)); ) + if(e.classname != "vtbl" && e.name == strcat(filter, s)) + { + argsbuf = buf_create(); + if(argsbuf >= 0) + if(e.readInputArgs) + { + for(i = 2; i < argc; ++i) + bufstr_add(argsbuf, argv(i), 1); + e.readInputArgs(e, argsbuf); + m_goto(strcat(filter, s)); + } + if(argsbuf >= 0) + buf_del(argsbuf); + } + } if(filter) strunzone(filter); return; diff --cc qcsrc/menu/xonotic/dialog_welcome.qc index 000000000,000000000..49c9ab4e8 new file mode 100644 --- /dev/null +++ b/qcsrc/menu/xonotic/dialog_welcome.qc @@@ -1,0 -1,0 +1,113 @@@ ++#ifdef INTERFACE ++CLASS(XonoticWelcomeDialog) EXTENDS(XonoticRootDialog) ++ METHOD(XonoticWelcomeDialog, fill, void(entity)) ++ ATTRIB(XonoticWelcomeDialog, title, string, _("Welcome")) ++ ATTRIB(XonoticWelcomeDialog, color, vector, SKINCOLOR_DIALOG_WELCOME) ++ ATTRIB(XonoticWelcomeDialog, intendedWidth, float, 0.7) ++ ATTRIB(XonoticWelcomeDialog, rows, float, 14) ++ ATTRIB(XonoticWelcomeDialog, columns, float, 4) ++ ATTRIB(XonoticWelcomeDialog, name, string, "Welcome") ++ ++ METHOD(XonoticWelcomeDialog, configureDialog, void(entity)) ++ METHOD(XonoticWelcomeDialog, readInputArgs, void(entity, float)) ++ ATTRIB(XonoticWelcomeDialog, serverinfo_name, string, string_null) ++ ATTRIB(XonoticWelcomeDialog, serverinfo_name_ent, entity, world) ++ ATTRIB(XonoticWelcomeDialog, serverinfo_ip, string, string_null) ++ ATTRIB(XonoticWelcomeDialog, serverinfo_ip_ent, entity, world) ++ ATTRIB(XonoticWelcomeDialog, serverinfo_MOTD, string, string_null) ++ ATTRIB(XonoticWelcomeDialog, serverinfo_MOTD_ent, entity, world) ++ ATTRIB(XonoticWelcomeDialog, serverinfo_pic, string, string_null) ++ ATTRIB(XonoticWelcomeDialog, serverinfo_pic_ent, entity, NULL) ++ENDCLASS(XonoticWelcomeDialog) ++#endif ++ ++#ifdef IMPLEMENTATION ++void welcomeDialog_resetStrings(entity me) ++{ ++ if(me.serverinfo_name) ++ strunzone(me.serverinfo_name); ++ me.serverinfo_name = strzone(_("")); ++ ++ if(me.serverinfo_ip) ++ strunzone(me.serverinfo_ip); ++ me.serverinfo_ip = strzone(_("")); ++ ++ if(me.serverinfo_MOTD) ++ strunzone(me.serverinfo_MOTD); ++ me.serverinfo_MOTD = strzone(_("")); ++ ++ if(me.serverinfo_pic) ++ strunzone(me.serverinfo_pic); ++ me.serverinfo_pic = strzone("nopic"); ++} ++void XonoticWelcomeDialog_configureDialog(entity me) ++{ ++ welcomeDialog_resetStrings(me); ++ SUPER(XonoticWelcomeDialog).configureDialog(me); ++} ++void XonoticWelcomeDialog_readInputArgs(entity me, float argsbuf) ++{ ++ float i = 0; ++ string s; ++ welcomeDialog_resetStrings(me); ++ while((s = bufstr_get(argsbuf, i)) != "") ++ { ++ if(s == "name") ++ { ++ if(me.serverinfo_name) ++ strunzone(me.serverinfo_name); ++ me.serverinfo_name = strzone(bufstr_get(argsbuf, i + 1)); ++ ++i; ++ } ++ else if(s == "ip") ++ { ++ if(me.serverinfo_ip) ++ strunzone(me.serverinfo_ip); ++ me.serverinfo_ip = strzone(bufstr_get(argsbuf, i + 1)); ++ ++i; ++ } ++ else if(s == "motd") ++ { ++ if(me.serverinfo_MOTD) ++ strunzone(me.serverinfo_MOTD); ++ me.serverinfo_MOTD = strzone(bufstr_get(argsbuf, i + 1)); ++ ++i; ++ } ++ else if(s == "pic") ++ { ++ if(me.serverinfo_pic) ++ strunzone(me.serverinfo_pic); ++ me.serverinfo_pic = strzone(strcat("/", bufstr_get(argsbuf, i + 1))); ++ ++i; ++ } ++ ++i; ++ } ++ me.serverinfo_name_ent.setText(me.serverinfo_name_ent, me.serverinfo_name); ++ me.serverinfo_ip_ent.setText(me.serverinfo_ip_ent, me.serverinfo_ip); ++ me.serverinfo_MOTD_ent.setText(me.serverinfo_MOTD_ent, me.serverinfo_MOTD); ++ ++ if(me.serverinfo_pic_ent.src) ++ strunzone(me.serverinfo_pic_ent.src); ++ me.serverinfo_pic_ent.src = strzone(me.serverinfo_pic); ++} ++ ++void XonoticWelcomeDialog_fill(entity me) ++{ ++ entity e; ++ ++ me.TR(me); ++ me.TD(me, 4, 2, me.serverinfo_pic_ent = makeXonoticImage(string_null, 4.0/3.0)); ++ ++ me.gotoRC(me, 1, 2); ++ me.TD(me, 1, 2, me.serverinfo_name_ent = makeXonoticTextLabel(0, "")); ++ me.gotoRC(me, 2, 2); ++ me.TD(me, 1, 2, me.serverinfo_ip_ent = makeXonoticTextLabel(0, "")); ++ ++ me.gotoRC(me, 4, 0); ++ me.TD(me, me.rows - 4 - 1, 4, me.serverinfo_MOTD_ent = makeXonoticTextListBox()); ++ me.serverinfo_MOTD_ent.allowColors = 1; ++ me.gotoRC(me, me.rows - 1, 0); ++ me.TDempty(me, 1); ++ me.TD(me, 1, 2, e = makeXonoticCommandButton(_("Disconnect"), '0 0 0', "disconnect", COMMANDBUTTON_CLOSE)); ++} ++#endif diff --cc qcsrc/menu/xonotic/mainwindow.qc index 000000000,45a0f93dc..d3b74ef3b mode 000000,100644..100644 --- a/qcsrc/menu/xonotic/mainwindow.qc +++ b/qcsrc/menu/xonotic/mainwindow.qc @@@ -1,0 -1,253 +1,257 @@@ + #ifdef INTERFACE + CLASS(MainWindow) EXTENDS(ModalController) + METHOD(MainWindow, configureMainWindow, void(entity)) + METHOD(MainWindow, draw, void(entity)) + ATTRIB(MainWindow, firstRunDialog, entity, NULL) + ATTRIB(MainWindow, advancedDialog, entity, NULL) + ATTRIB(MainWindow, mutatorsDialog, entity, NULL) + ATTRIB(MainWindow, mapInfoDialog, entity, NULL) + ATTRIB(MainWindow, userbindEditDialog, entity, NULL) + ATTRIB(MainWindow, winnerDialog, entity, NULL) + ATTRIB(MainWindow, serverInfoDialog, entity, NULL) + ATTRIB(MainWindow, cvarsDialog, entity, NULL) + ATTRIB(MainWindow, screenshotViewerDialog, entity, NULL) + ATTRIB(MainWindow, viewDialog, entity, NULL) + ATTRIB(MainWindow, hudconfirmDialog, entity, NULL) + ATTRIB(MainWindow, languageWarningDialog, entity, NULL) + ATTRIB(MainWindow, mainNexposee, entity, NULL) + ATTRIB(MainWindow, fadedAlpha, float, SKINALPHA_BEHIND) + ATTRIB(MainWindow, dialogToShow, entity, NULL) + ATTRIB(MainWindow, demostartconfirmDialog, entity, NULL) + ATTRIB(MainWindow, demotimeconfirmDialog, entity, NULL) + ATTRIB(MainWindow, resetDialog, entity, NULL) + ENDCLASS(MainWindow) + #endif + + #ifdef IMPLEMENTATION + void MainWindow_draw(entity me) + { + SUPER(MainWindow).draw(me); + + if(me.dialogToShow) + { + DialogOpenButton_Click_withCoords(world, me.dialogToShow, '0 0 0', eX * conwidth + eY * conheight); + me.dialogToShow = NULL; + } + } + + void DemoButton_Click(entity me, entity other) + { + if(me.text == _("Do not press this button again!")) + DialogOpenButton_Click(me, other); + else + me.setText(me, _("Do not press this button again!")); + } + + void MainWindow_configureMainWindow(entity me) + { + entity n, i; + + // dialog run upon startup + me.firstRunDialog = i = spawnXonoticFirstRunDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + + // hud_configure dialogs + i = spawnXonoticHUDExitDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + i = spawnXonoticHUDNotificationDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + i = spawnXonoticHUDAmmoDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + i = spawnXonoticHUDHealthArmorDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + i = spawnXonoticHUDChatDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + i = spawnXonoticHUDModIconsDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + i = spawnXonoticHUDPowerupsDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + i = spawnXonoticHUDPressedKeysDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + i = spawnXonoticHUDRaceTimerDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + i = spawnXonoticHUDRadarDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + i = spawnXonoticHUDScoreDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + i = spawnXonoticHUDTimerDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + i = spawnXonoticHUDVoteDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + i = spawnXonoticHUDWeaponsDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + i = spawnXonoticHUDEngineInfoDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + i = spawnXonoticHUDInfoMessagesDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + i = spawnXonoticHUDPhysicsDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + me.screenshotViewerDialog = i = spawnXonoticScreenshotViewerDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + i = spawnXonoticHUDCenterprintDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + i = spawnXonoticHUDBuffsDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + + // dialogs used by settings + me.userbindEditDialog = i = spawnXonoticUserbindEditDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + me.cvarsDialog = i = spawnXonoticCvarsDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + me.resetDialog = i = spawnXonoticResetDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + me.languageWarningDialog = i = spawnXonoticLanguageWarningDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + me.hudconfirmDialog = i = spawnXonoticHUDConfirmDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + + // dialog used by singleplayer + me.winnerDialog = i = spawnXonoticWinnerDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + + // dialog used by multiplayer/join + me.serverInfoDialog = i = spawnXonoticServerInfoDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + me.demostartconfirmDialog = i = spawnXonoticDemoStartConfirmDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + me.demotimeconfirmDialog = i = spawnXonoticDemoTimeConfirmDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + + // dialogs used by multiplayer/create + me.mapInfoDialog = i = spawnXonoticMapInfoDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + me.mutatorsDialog = i = spawnXonoticMutatorsDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + // mutator dialogs + i = spawnXonoticSandboxToolsDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z * SKINALPHA_DIALOG_SANDBOXTOOLS); + + + // miscellaneous dialogs + i = spawnXonoticTeamSelectDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + + i = spawnXonoticMonsterToolsDialog(); + i.configureDialog(i); + me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z * SKINALPHA_DIALOG_SANDBOXTOOLS); + ++ i = spawnXonoticWelcomeDialog(); ++ i.configureDialog(i); ++ me.addItemCentered(me, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); ++ + + // main dialogs/windows + me.mainNexposee = n = spawnXonoticNexposee(); + /* + if(checkextension("DP_GECKO_SUPPORT")) + { + i = spawnXonoticNewsDialog(); + i.configureDialog(i); + n.addItemCentered(n, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + n.setNexposee(n, i, '0.1 0.1 0', SKINALPHAS_MAINMENU_x, SKINALPHAS_MAINMENU_y); + } + */ + i = spawnXonoticSingleplayerDialog(); + i.configureDialog(i); + n.addItemCentered(n, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + n.setNexposee(n, i, SKINPOSITION_DIALOG_SINGLEPLAYER, SKINALPHAS_MAINMENU_x, SKINALPHAS_MAINMENU_y); + + i = spawnXonoticMultiplayerDialog(); + i.configureDialog(i); + n.addItemCentered(n, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + n.setNexposee(n, i, SKINPOSITION_DIALOG_MULTIPLAYER, SKINALPHAS_MAINMENU_x, SKINALPHAS_MAINMENU_y); + + i = spawnXonoticSettingsDialog(); + i.configureDialog(i); + n.addItemCentered(n, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + n.setNexposee(n, i, SKINPOSITION_DIALOG_SETTINGS, SKINALPHAS_MAINMENU_x, SKINALPHAS_MAINMENU_y); + + i = spawnXonoticCreditsDialog(); + i.configureDialog(i); + n.addItemCentered(n, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + n.setNexposee(n, i, SKINPOSITION_DIALOG_CREDITS, SKINALPHAS_MAINMENU_x, SKINALPHAS_MAINMENU_y); + n.pullNexposee(n, i, eY * (SKINHEIGHT_TITLE * SKINFONTSIZE_TITLE / conheight)); + + i = spawnXonoticQuitDialog(); + i.configureDialog(i); + n.addItemCentered(n, i, i.intendedWidth * eX + i.intendedHeight * eY, SKINALPHAS_MAINMENU_z); + n.setNexposee(n, i, SKINPOSITION_DIALOG_QUIT, SKINALPHAS_MAINMENU_x, SKINALPHAS_MAINMENU_y); + n.pullNexposee(n, i, eY * (SKINHEIGHT_TITLE * SKINFONTSIZE_TITLE / conheight)); + + me.addItem(me, n, '0 0 0', '1 1 0', SKINALPHAS_MAINMENU_z); + me.moveItemAfter(me, n, NULL); + + me.initializeDialog(me, n); + + if(cvar_string("_cl_name") == cvar_defstring("_cl_name")) + me.dialogToShow = me.firstRunDialog; + } + #endif + + /* Click. The c-word is here so you can grep for it :-) */ diff --cc qcsrc/menu/xonotic/textlistbox.qc index 000000000,000000000..c42754d3b new file mode 100644 --- /dev/null +++ b/qcsrc/menu/xonotic/textlistbox.qc @@@ -1,0 -1,0 +1,91 @@@ ++#ifdef INTERFACE ++CLASS(XonoticTextListBox) EXTENDS(ListBox) ++ METHOD(XonoticTextListBox, configureXonoticTextListBox, void(entity)) ++ ATTRIB(XonoticTextListBox, fontSize, float, SKINFONTSIZE_NORMAL) ++ ATTRIB(XonoticTextListBox, scrollbarWidth, float, SKINWIDTH_SCROLLBAR) ++ ATTRIB(XonoticTextListBox, src, string, SKINGFX_SCROLLBAR) ++ ATTRIB(XonoticTextListBox, tolerance, vector, SKINTOLERANCE_SLIDER) ++ ATTRIB(XonoticTextListBox, rowsPerItem, float, 1) ++ METHOD(XonoticTextListBox, resizeNotify, void(entity, vector, vector, vector, vector)) ++ ATTRIB(XonoticTextListBox, color, vector, SKINCOLOR_SCROLLBAR_N) ++ ATTRIB(XonoticTextListBox, colorF, vector, SKINCOLOR_SCROLLBAR_F) ++ ATTRIB(XonoticTextListBox, color2, vector, SKINCOLOR_SCROLLBAR_S) ++ ATTRIB(XonoticTextListBox, colorC, vector, SKINCOLOR_SCROLLBAR_C) ++ ATTRIB(XonoticTextListBox, colorBG, vector, SKINCOLOR_LISTBOX_BACKGROUND) ++ ATTRIB(XonoticTextListBox, alphaBG, float, SKINALPHA_LISTBOX_BACKGROUND) ++ ++ METHOD(XonoticTextListBox, setSelected, void(entity, float)) ++ METHOD(XonoticTextListBox, destroy, void(entity)) ++ ATTRIB(XonoticTextListBox, textbuf, float, -1) ++ ATTRIB(XonoticTextListBox, allowColors, float, 0) ++ METHOD(XonoticTextListBox, setText, void(entity, string)) ++ METHOD(XonoticTextListBox, drawListBoxItem, void(entity, float, vector, float)) // item number, width/height, selected ++ENDCLASS(XonoticTextListBox) ++entity makeXonoticTextListBox(); ++#endif ++ ++#ifdef IMPLEMENTATION ++entity makeXonoticTextListBox() ++{ ++ entity me; ++ me = spawnXonoticTextListBox(); ++ me.configureXonoticTextListBox(me); ++ return me; ++} ++void XonoticTextListBox_configureXonoticTextListBox(entity me) ++{ ++ me.configureListBox(me, me.scrollbarWidth, 1); // item height gets set up later ++} ++void XonoticTextListBox_setSelected(entity me, float i) ++{ ++ // nothing ++} ++void XonoticTextListBox_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize) ++{ ++ me.itemHeight = me.rowsPerItem * me.fontSize / absSize_y; ++ SUPER(XonoticTextListBox).resizeNotify(me, relOrigin, relSize, absOrigin, absSize); ++ ++ me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight); ++ me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth)); ++ me.realUpperMargin = 0.5 * (1 - me.realFontSize_y); ++} ++void XonoticTextListBox_setText(entity me, string theText) ++{ ++ float i, k; ++ string ts; ++ if(me.textbuf >= 0) ++ buf_del(me.textbuf); ++ me.textbuf = buf_create(); ++ string s = strzone(theText); ++ me.nItems = 0; ++ k = tokenizebyseparator(s, "\\n"); ++ for(i = 0; i < k; ++i) ++ { ++ getWrappedLine_remaining = argv(i); ++ if(!getWrappedLine_remaining) ++ { ++ bufstr_add(me.textbuf, "", 1); ++ ++me.nItems; ++ } ++ else while(getWrappedLine_remaining) ++ { ++ ts = getWrappedLine(1 - me.controlWidth, me.realFontSize, draw_TextWidth_WithColors); ++ if (ts != "") ++ { ++ bufstr_add(me.textbuf, ts, 1); ++ ++me.nItems; ++ } ++ } ++ } ++ strunzone(s); ++} ++void XonoticTextListBox_destroy(entity me) ++{ ++ if(me.textbuf >= 0) ++ buf_del(me.textbuf); ++} ++void XonoticTextListBox_drawListBoxItem(entity me, float i, vector absSize, float isSelected) ++{ ++ draw_CenterText(me.realUpperMargin * eY + 0.5 * eX, bufstr_get(me.textbuf, i), me.realFontSize, '1 1 1', 1, me.allowColors); ++} ++#endif