X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fserver%2Fclient.qc;h=d4a3e9febfa359aef00e37995c6b56961d0a8a25;hp=686829e3331b27eafcd16d059e3821045e0e59ea;hb=c5fcf672c473edef7139d4250398184b8ae17224;hpb=9c46a925f1d4c0287b19a9be100efce8287276b0 diff --git a/qcsrc/server/client.qc b/qcsrc/server/client.qc index 686829e333..d4a3e9febf 100644 --- a/qcsrc/server/client.qc +++ b/qcsrc/server/client.qc @@ -27,6 +27,7 @@ #include +#include "../common/triggers/func/conveyor.qh" #include "../common/triggers/teleporters.qh" #include "../common/vehicles/all.qh" @@ -35,6 +36,7 @@ #include "weapons/weaponsystem.qh" #include "../common/net_notice.qh" +#include "../common/net_linked.qh" #include "../common/physics/player.qh" #include "../common/items/_mod.qh" @@ -159,7 +161,8 @@ void ClientData_Touch(entity e) .string netname_previous; -void SetSpectatee(entity player, entity spectatee); +void SetSpectatee(entity this, entity spectatee); +void SetSpectatee_status(entity this, int spectatee_num); /* @@ -233,7 +236,7 @@ void PutObserverInServer(entity this) this.angles_z = 0; this.fixangle = true; // offset it so that the spectator spawns higher off the ground, looks better this way - setorigin(this, spot.origin + STAT(PL_VIEW_OFS, NULL)); + setorigin(this, spot.origin + STAT(PL_VIEW_OFS, this)); this.prevorigin = this.origin; if (IS_REAL_CLIENT(this)) { @@ -250,7 +253,7 @@ void PutObserverInServer(entity this) FixPlayermodel(this); } setmodel(this, MDL_Null); - setsize(this, STAT(PL_CROUCH_MIN, NULL), STAT(PL_CROUCH_MAX, NULL)); + setsize(this, STAT(PL_CROUCH_MIN, this), STAT(PL_CROUCH_MAX, this)); this.view_ofs = '0 0 0'; } @@ -281,8 +284,8 @@ void PutObserverInServer(entity this) if (this.killcount != FRAGS_SPECTATOR) { Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_SPECTATE, this.netname); - if(!intermission_running) - if(autocvar_g_chat_nospectators == 1 || (!(warmup_stage || gameover) && autocvar_g_chat_nospectators == 2)) + if(!gameover) + if(autocvar_g_chat_nospectators == 1 || (!warmup_stage && autocvar_g_chat_nospectators == 2)) Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_CHAT_NOSPECTATORS); if(this.just_joined == false) { @@ -294,13 +297,18 @@ void PutObserverInServer(entity this) accuracy_resend(this); this.spectatortime = time; + if(this.bot_attack) + IL_REMOVE(g_bot_targets, this); this.bot_attack = false; this.hud = HUD_NORMAL; TRANSMUTE(Observer, this); this.iscreature = false; this.teleportable = TELEPORT_SIMPLE; + if(this.damagedbycontents) + IL_REMOVE(g_damagedbycontents, this); this.damagedbycontents = false; this.health = FRAGS_SPECTATOR; + SetSpectatee_status(this, etof(this)); this.takedamage = DAMAGE_NO; this.solid = SOLID_NOT; set_movetype(this, MOVETYPE_FLY_WORLDONLY); // user preference is controlled by playerprethink @@ -331,6 +339,7 @@ void PutObserverInServer(entity this) this.hook_time = 0; this.deadflag = DEAD_NO; this.crouch = false; + this.revive_progress = 0; this.revival_time = 0; this.items = 0; @@ -515,9 +524,12 @@ void PutClientInServer(entity this) } TRANSMUTE(Player, this); + this.wasplayer = true; this.iscreature = true; this.teleportable = TELEPORT_NORMAL; + if(!this.damagedbycontents) + IL_PUSH(g_damagedbycontents, this); this.damagedbycontents = true; set_movetype(this, MOVETYPE_WALK); this.solid = SOLID_SLIDEBOX; @@ -556,6 +568,7 @@ void PutClientInServer(entity this) this.armorvalue = start_armorvalue; this.weapons = start_weapons; } + SetSpectatee_status(this, 0); this.superweapons_finished = (this.weapons & WEPSET_SUPERWEAPONS) ? time + autocvar_g_balance_superweapons_time : 0; @@ -604,6 +617,7 @@ void PutClientInServer(entity this) this.strength_finished = 0; this.invincible_finished = 0; this.fire_endtime = -1; + this.revive_progress = 0; this.revival_time = 0; this.air_finished = time + 12; @@ -618,20 +632,26 @@ void PutClientInServer(entity this) FixPlayermodel(this); this.drawonlytoclient = NULL; + this.viewloc = NULL; + this.crouch = false; - this.view_ofs = STAT(PL_VIEW_OFS, NULL); - setsize(this, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL)); + this.view_ofs = STAT(PL_VIEW_OFS, this); + setsize(this, STAT(PL_MIN, this), STAT(PL_MAX, this)); this.spawnorigin = spot.origin; setorigin(this, spot.origin + '0 0 1' * (1 - this.mins.z - 24)); // don't reset back to last position, even if new position is stuck in solid this.oldorigin = this.origin; this.prevorigin = this.origin; this.lastteleporttime = time; // prevent insane speeds due to changing origin + if(this.conveyor) + IL_REMOVE(g_conveyed, this); this.conveyor = NULL; // prevent conveyors at the previous location from moving a freshly spawned player this.hud = HUD_NORMAL; this.event_damage = PlayerDamage; + if(!this.bot_attack) + IL_PUSH(g_bot_targets, this); this.bot_attack = true; this.monster_attack = true; @@ -695,7 +715,6 @@ void PutClientInServer(entity this) void ClientInit_misc(entity this); -.float ebouncefactor, ebouncestop; // electro's values // TODO do we need all these fields, or should we stop autodetecting runtime // changes and just have a console command to update this? bool ClientInit_SendEntity(entity this, entity to, int sf) @@ -729,7 +748,7 @@ void ClientInit_misc(entity this) else WriteString(channel, ""); WriteByte(channel, this.count * 255.0); // g_balance_armor_blockpercent - WriteByte(channel, serverflags); // client has to know if it should zoom or not + WriteByte(channel, serverflags); WriteCoord(channel, autocvar_g_trueaim_minrange); } @@ -1033,8 +1052,8 @@ ClientPreConnect Called once (not at each match start) when a client begins a connection to the server ============= */ -void ClientPreConnect () -{ENGINE_EVENT(); +void ClientPreConnect(entity this) +{ if(autocvar_sv_eventlog) { GameLogEcho(sprintf(":connect:%d:%d:%s", @@ -1131,7 +1150,10 @@ void ClientConnect(entity this) this.netname_previous = strzone(this.netname); - Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((teamplay && IS_PLAYER(this)) ? APP_TEAM_ENT(this, INFO_JOIN_CONNECT_TEAM) : INFO_JOIN_CONNECT), this.netname); + if(teamplay && IS_PLAYER(this)) + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_JOIN_CONNECT_TEAM), this.netname); + else + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_JOIN_CONNECT, this.netname); stuffcmd(this, clientstuff, "\n"); stuffcmd(this, "cl_particles_reloadeffects\n"); // TODO do we still need this? @@ -1170,12 +1192,6 @@ void ClientConnect(entity this) if (IS_REAL_CLIENT(this)) { - if (!autocvar_g_campaign) - { - this.motd_actived_time = -1; - Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_MOTD, getwelcomemessage(this)); - } - if (g_weaponarena_weapons == WEPSET(TUBA)) stuffcmd(this, "cl_cmd settemp chase_active 1\n"); } @@ -1194,11 +1210,23 @@ void ClientConnect(entity this) if (IS_REAL_CLIENT(this)) sv_notice_join(this); + // update physics stats (players can spawn before physics runs) + Physics_UpdateStats(this, PHYS_HIGHSPEED(this)); + IL_EACH(g_initforplayer, it.init_for_player, { it.init_for_player(it, this); }); MUTATOR_CALLHOOK(ClientConnect, this); + + if (IS_REAL_CLIENT(this)) + { + if (!autocvar_g_campaign && !IS_PLAYER(this)) + { + this.motd_actived_time = -1; + Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_MOTD, getwelcomemessage(this)); + } + } } /* ============= @@ -1254,6 +1282,8 @@ void ClientDisconnect(entity this) this.playerid = 0; ReadyCount(); if (vote_called && IS_REAL_CLIENT(this)) VoteCount(false); + + ONREMOVE(this); } void ChatBubbleThink(entity this) @@ -1580,11 +1610,11 @@ void player_regen(entity this) } bool zoomstate_set; -void SetZoomState(entity this, float z) +void SetZoomState(entity this, float newzoom) { - if(z != this.zoomstate) + if(newzoom != this.zoomstate) { - this.zoomstate = z; + this.zoomstate = newzoom; ClientData_Touch(this); } zoomstate_set = true; @@ -1593,7 +1623,7 @@ void SetZoomState(entity this, float z) void GetPressedKeys(entity this) { MUTATOR_CALLHOOK(GetPressedKeys, this); - int keys = this.pressedkeys; + int keys = STAT(PRESSED_KEYS, this); keys = BITSET(keys, KEY_FORWARD, this.movement.x > 0); keys = BITSET(keys, KEY_BACKWARD, this.movement.x < 0); keys = BITSET(keys, KEY_RIGHT, this.movement.y > 0); @@ -1603,7 +1633,9 @@ void GetPressedKeys(entity this) keys = BITSET(keys, KEY_CROUCH, PHYS_INPUT_BUTTON_CROUCH(this)); keys = BITSET(keys, KEY_ATCK, PHYS_INPUT_BUTTON_ATCK(this)); keys = BITSET(keys, KEY_ATCK2, PHYS_INPUT_BUTTON_ATCK2(this)); - this.pressedkeys = keys; + this.pressedkeys = keys; // store for other users + + STAT(PRESSED_KEYS, this) = keys; } /* @@ -1636,7 +1668,7 @@ void SpectateCopy(entity this, entity spectatee) this.hit_time = spectatee.hit_time; this.strength_finished = spectatee.strength_finished; this.invincible_finished = spectatee.invincible_finished; - this.pressedkeys = spectatee.pressedkeys; + STAT(PRESSED_KEYS, this) = STAT(PRESSED_KEYS, spectatee); this.weapons = spectatee.weapons; this.vortex_charge = spectatee.vortex_charge; this.vortex_chargepool_ammo = spectatee.vortex_chargepool_ammo; @@ -1653,6 +1685,7 @@ void SpectateCopy(entity this, entity spectatee) this.angles = spectatee.v_angle; STAT(FROZEN, this) = STAT(FROZEN, spectatee); this.revive_progress = spectatee.revive_progress; + this.viewloc = spectatee.viewloc; if(!PHYS_INPUT_BUTTON_USE(this) && STAT(CAMERA_SPECTATOR, this) != 2) this.fixangle = true; setorigin(this, spectatee.origin); @@ -1692,7 +1725,7 @@ void SpectateCopy(entity this, entity spectatee) bool SpectateUpdate(entity this) { if(!this.enemy) - return false; + return false; if(!IS_PLAYER(this.enemy) || this == this.enemy) { @@ -1724,6 +1757,18 @@ bool SpectateSet(entity this) return true; } +void SetSpectatee_status(entity this, int spectatee_num) +{ + int oldspectatee_status = this.spectatee_status; + this.spectatee_status = spectatee_num; + + if (this.spectatee_status != oldspectatee_status) + { + ClientData_Touch(this); + if (g_race || g_cts) race_InitSpectator(); + } +} + void SetSpectatee(entity this, entity spectatee) { entity old_spectatee = this.enemy; @@ -1751,6 +1796,9 @@ void SetSpectatee(entity this, entity spectatee) } } + if (this.enemy) + SetSpectatee_status(this, etof(this.enemy)); + // needed to update spectator list if(old_spectatee) { ClientData_Touch(old_spectatee); } } @@ -1840,40 +1888,34 @@ void ShowRespawnCountdown(entity this) } } -.float caplayer; - -void LeaveSpectatorMode(entity this) +.bool team_selected; +bool ShowTeamSelection(entity this) { - if(this.caplayer) - return; - if(nJoinAllowed(this, this)) - { - if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || (this.wasplayer && autocvar_g_changeteam_banned) || this.team_forced > 0) - { - TRANSMUTE(Player, this); - - SetSpectatee(this, NULL); + if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || this.team_selected || (this.wasplayer && autocvar_g_changeteam_banned) || this.team_forced > 0) + return false; + stuffcmd(this, "menu_showteamselect\n"); + return true; +} +void Join(entity this) +{ + TRANSMUTE(Player, this); - if(autocvar_g_campaign || autocvar_g_balance_teams) - { JoinBestTeam(this, false, true); } + if(!this.team_selected) + if(autocvar_g_campaign || autocvar_g_balance_teams) + JoinBestTeam(this, false, true); - if(autocvar_g_campaign) - { campaign_bots_may_start = true; } + if(autocvar_g_campaign) + campaign_bots_may_start = true; - Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_PREVENT_JOIN); + Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_PREVENT_JOIN); - PutClientInServer(this); + PutClientInServer(this); - if(IS_PLAYER(this)) { Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((teamplay && this.team != -1) ? APP_TEAM_ENT(this, INFO_JOIN_PLAY_TEAM) : INFO_JOIN_PLAY), this.netname); } - } - else - stuffcmd(this, "menu_showteamselect\n"); - } + if(teamplay && this.team != -1) + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_JOIN_PLAY_TEAM), this.netname); else - { - // Player may not join because g_maxplayers is set - Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_JOIN_PREVENT); - } + Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_JOIN_PLAY, this.netname); + this.team_selected = false; } /** @@ -1882,20 +1924,20 @@ void LeaveSpectatorMode(entity this) * it checks whether the number of currently playing players exceeds g_maxplayers. * @return int number of free slots for players, 0 if none */ -bool nJoinAllowed(entity this, entity ignore) +int nJoinAllowed(entity this, entity ignore) { if(!ignore) // this is called that way when checking if anyone may be able to join (to build qcstatus) // so report 0 free slots if restricted { if(autocvar_g_forced_team_otherwise == "spectate") - return false; + return 0; if(autocvar_g_forced_team_otherwise == "spectator") - return false; + return 0; } - if(this.team_forced < 0) - return false; // forced spectators can never join + if(this && this.team_forced < 0) + return 0; // forced spectators can never join // TODO simplify this int totalClients = 0; @@ -1908,13 +1950,20 @@ bool nJoinAllowed(entity this, entity ignore) ++currentlyPlaying; )); + float free_slots = 0; if (!autocvar_g_maxplayers) - return maxclients - totalClients; + free_slots = maxclients - totalClients; + else if(currentlyPlaying < autocvar_g_maxplayers) + free_slots = min(maxclients - totalClients, autocvar_g_maxplayers - currentlyPlaying); - if(currentlyPlaying < autocvar_g_maxplayers) - return min(maxclients - totalClients, autocvar_g_maxplayers - currentlyPlaying); + static float join_prevent_msg_time = 0; + if(this && ignore && !free_slots && time > join_prevent_msg_time) + { + Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_JOIN_PREVENT); + join_prevent_msg_time = time + 3; + } - return false; + return free_slots; } /** @@ -1981,6 +2030,16 @@ void PrintWelcomeMessage(entity this) } } +bool joinAllowed(entity this) +{ + if (this.version_mismatch) return false; + if (!nJoinAllowed(this, this)) return false; + if (teamplay && lockteams) return false; + if (ShowTeamSelection(this)) return false; + if (MUTATOR_CALLHOOK(ForbidSpawn, this)) return false; + return true; +} + void ObserverThink(entity this) { if ( this.impulse ) @@ -1988,8 +2047,9 @@ void ObserverThink(entity this) MinigameImpulse(this, this.impulse); this.impulse = 0; } + if (this.flags & FL_JUMPRELEASED) { - if (PHYS_INPUT_BUTTON_JUMP(this) && !this.version_mismatch) { + if (PHYS_INPUT_BUTTON_JUMP(this) && joinAllowed(this)) { this.flags &= ~FL_JUMPRELEASED; this.flags |= FL_SPAWNING; } else if(PHYS_INPUT_BUTTON_ATCK(this) && !this.version_mismatch) { @@ -2007,7 +2067,7 @@ void ObserverThink(entity this) if(this.flags & FL_SPAWNING) { this.flags &= ~FL_SPAWNING; - LeaveSpectatorMode(this); + Join(this); return; } } @@ -2028,8 +2088,9 @@ void SpectatorThink(entity this) return; } } + if (this.flags & FL_JUMPRELEASED) { - if (PHYS_INPUT_BUTTON_JUMP(this) && !this.version_mismatch) { + if (PHYS_INPUT_BUTTON_JUMP(this) && joinAllowed(this)) { this.flags &= ~FL_JUMPRELEASED; this.flags |= FL_SPAWNING; } else if(PHYS_INPUT_BUTTON_ATCK(this) || this.impulse == 10 || this.impulse == 15 || this.impulse == 18 || (this.impulse >= 200 && this.impulse <= 209)) { @@ -2064,7 +2125,7 @@ void SpectatorThink(entity this) if(this.flags & FL_SPAWNING) { this.flags &= ~FL_SPAWNING; - LeaveSpectatorMode(this); + Join(this); return; } } @@ -2259,8 +2320,9 @@ void PlayerPreThink (entity this) if (IS_PLAYER(this)) { CheckRules_Player(this); - if (intermission_running) { - IntermissionThink(this); + if (gameover || intermission_running) { + if(intermission_running) + IntermissionThink(this); return; } @@ -2291,7 +2353,7 @@ void PlayerPreThink (entity this) { if ((this.respawn_flags & RESPAWN_FORCE) && !(this.respawn_time < this.respawn_time_max)) this.deadflag = DEAD_RESPAWNING; - else if (!button_pressed || (this.respawn_flags & RESPAWN_FORCE)) + else if (!button_pressed || (time >= this.respawn_time_max && (this.respawn_flags & RESPAWN_FORCE))) this.deadflag = DEAD_DEAD; break; } @@ -2411,8 +2473,9 @@ void PlayerPreThink (entity this) this.dmg_team = max(0, this.dmg_team - autocvar_g_teamdamage_resetspeed * frametime); } - else if (gameover) { - if (intermission_running) IntermissionThink(this); + else if (gameover || intermission_running) { + if(intermission_running) + IntermissionThink(this); return; } else if (IS_OBSERVER(this)) { @@ -2431,19 +2494,6 @@ void PlayerPreThink (entity this) ); } - int oldspectatee_status = this.spectatee_status; - if (IS_SPEC(this)) { - this.spectatee_status = etof(this.enemy); - } else if (IS_OBSERVER(this)) { - this.spectatee_status = etof(this); - } else { - this.spectatee_status = 0; - } - if (this.spectatee_status != oldspectatee_status) { - ClientData_Touch(this); - if (g_race || g_cts) race_InitSpectator(); - } - if (this.teamkill_soundtime && time > this.teamkill_soundtime) { this.teamkill_soundtime = 0; @@ -2494,20 +2544,11 @@ void DrownPlayer(entity this) void Player_Physics(entity this) { - set_movetype(this, ((this.move_qcphysics) ? MOVETYPE_NONE : this.move_movetype)); + set_movetype(this, this.move_movetype); if(!this.move_qcphysics) return; - int mt = this.move_movetype; - - if(mt == MOVETYPE_PUSH || mt == MOVETYPE_FAKEPUSH || mt == MOVETYPE_PHYSICS) - { - this.move_qcphysics = false; - set_movetype(this, mt); - return; - } - if(!frametime && !this.pm_frametime) return; @@ -2576,13 +2617,23 @@ void PlayerPostThink (entity this) CheatFrame(this); //CheckPlayerJump(); + if (gameover) + { + this.solid = SOLID_NOT; + this.takedamage = DAMAGE_NO; + set_movetype(this, MOVETYPE_NONE); + } if (IS_PLAYER(this)) { DrownPlayer(this); CheckRules_Player(this); UpdateChatBubble(this); if (this.impulse) ImpulseCommands(this); - if (intermission_running) return; // intermission or finale + if (gameover) + { + CSQCMODEL_AUTOUPDATE(this); + return; + } GetPressedKeys(this); }