diff --git a/README.md b/README.md index 922a2da..75d73df 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,18 @@ # Introduction -Mod zPAM3.31 is a new version of PAM mode for COD2.
+Mod zPAM3.32 is a new version of PAM mode for COD2.
The code from the previous zPAM 2.07 version was completely rewritten and ported to a new code base, which helped in the implementation of new features and bug fixes. Work on this pam was initiated by me in 2015 and was never fully finished. On corona days, I decided to finish it. - +❗ Note ❗
+*This page describe only actual version zPAM 3.32 PREVIEW.
+To see description of previous versions, click on the links in [Version list](#version-list).* ## Download - #### Preview version: - - 2022/10/13 - zPAM 3.31 PREVIEW - zpam331.zip + - 2023/02/24 - zPAM 3.32 PREVIEW - zpam332.zip - ❗ *Preview version demonstrates changes and new features and is not officially accepted by FPS Challange* ❗ - #### Stable version: - 2021/07/15 - zPAM 3.22 - zpam322.zip @@ -19,10 +21,11 @@ Work on this pam was initiated by me in 2015 and was never fully finished. On co -## Previous versions - +## Version list +- 2023/02/24 - zPAM 3.32 PREVIEW - actual preview version +- 2022/10/13 - zPAM 3.31 PREVIEW - 2022/10/07 - zPAM 3.30 PREVIEW -- 2021/07/15 - zPAM 3.22 +- 2021/07/15 - zPAM 3.22 - stable version - 2021/07/15 - zPAM 3.22 - 2021/05/16 - zPAM 3.21 - 2021/05/05 - zPAM 3.20 @@ -34,12 +37,45 @@ Work on this pam was initiated by me in 2015 and was never fully finished. On co - 2020/04/23 - zPAM 3.1 BETA -❗ Note ❗
-*This page describe only actual version zPAM 3.31 PREVIEW.
-To see description of previous version, click on the links above.* - ## Changelog + +
zPAM 3.32 changes (click to open) +

+ +- [3.3.70] Silent weapon switch when climbing - restoring the original behavior + disabling the weapon switch sound that is played only in 1st point of view +- New hand hitbox fix - addressing the hit problems +- Fixed pistol being dropped in rifle mode when player is killed +- Fixed auto-recording in deathmatch +- Fixed RCON menu - rifle and 2v2 mode had wrong order, (correct comp_rifle_2v2 instead of bad comp_2v2_rifle) +- Auto-spectator improvements: + - new XRAY icons besides player names showing enemies behind walls - all toggle able by holding F + - fixed black screen for dead players if killcam is played + - damage info moved down next to "You killed XXX" text + - when there is more killcams to be played at the end of the round and end time elapsed, its extended so killcams are fully played (players will have disabled weapons in this period) +- Improved round report + - showing damage for kills + fixed showing 0hp damage + - red star is added indicating that "Hand hitbox fix" or "Torso hitbox fix" was applied +- Improved scoreboard + - adding a button to take a screenshot of scoreboard with ENTER key (since binds are not working in new scoreboard) + - it will always show disconnected players (with [-] prefix) for 5 mins (so you see stats for all players in final scorebard) + - only Kills and Deaths will be showed for enemy team (to avoid recognize enemy position by watching the scoreboard) + - added statistic of kills with grenade + - hits counting changed: Scope/rifle +1, Semi/Automatic/Shotgun +0.5 (its counted once after the hited player is fully healed) + - hits colored yellow if its value is >=5.0 and red if its value is >=10.0 +- Adding 10min settings for time based gametypes (DM, TDM, HQ, CTF, HTF) +- Added damage info into readyup (testing) +- Fixed scr_motd not being able to change +- Disabled killing with grenade in readyup +- Showing type of server and number of players slots in server info menu +- Some other minor changes + + +

+
+ + +
zPAM 3.31 changes (click to open)

@@ -61,6 +97,9 @@ To see description of previous version, click on the links above.*

+ + +
zPAM 3.30 changes (click to open)

@@ -237,8 +276,8 @@ r_polygonOffsetScale and r_polygonOffsetBias warning appears even if they were c ## Installation -- Download zPAM 3.31 PREVIEW and extract files into following locations: - - ./Call of Duty 2/main/zpam331.iwd +- Download zPAM 3.32 PREVIEW and extract files into following locations: + - ./Call of Duty 2/main/zpam332.iwd - ./Call of Duty 2/main/zpam_maps_v2.iwd (*required only for 1.3 game version) - ./Call of Duty 2/main/server.cfg @@ -255,12 +294,13 @@ r_polygonOffsetScale and r_polygonOffsetBias warning appears even if they were c ❗ Error "PAM is not installed correctly" may show. ❗
To fix this error, follow instructions in [Troubleshooting](#troubleshooting) section +Make sure the server is runned without a mod (```/fs_game```). +PAM uses default main folder because mods does not exec player's configs correctly and settings changed in game would not be persisted to next game session. + +If you are running server manually, this is example of command line parameters:
+```+set dedicated 2 +set sv_punkbuster 0 +pb_sv_disable +exec server.cfg``` -

- Gameservers.com settings example (click to open) - -

@@ -292,7 +332,7 @@ Big thanks for HQ, HTF and RE gametypes integration and overal PAM testing Big thanks for PAM promoting **Other supporters:**
-cokY, Sk1lzZ, YctN, kebit, foxbuster, <==Mustang==>Clan from Hungary, hubertgruber / dutch, excel, shady +cokY, Sk1lzZ, YctN, kebit, foxbuster, <==Mustang==>Clan from Hungary, hubertgruber / dutch, excel, shady, jza

@@ -411,15 +451,21 @@ You can debug this in game via command **/rcon debug_torsohitbox 1**
There are some weird situations when you shot player to the body, but the game process it as a hit only. These types of bugs are probably caused by badly implemented hit boxes within the game engine. In these situations the game process the hit location as hand / arm instead of body (when the arm is right behind the body) -Hand hitbox fix tries to address this issue by these rules: - - if you fire from rifle or scope to left or right arm, and - - enemy is in ads (zoomed), and - - distance is more than 200, and - - left or right hind is in front of body (correct angles check) - - - - In this case, hit location is changed to body, causing deadly damage - - You can debug hitbox fix in game via command **/rcon debug_handhitbox 1** - - **Hand hitbox fix is enabled by default** +Hand hitbox fix tries to address this issue by the following check: + + - if you fire from rifle or scope, and + - distance between you and enemy is more than 200, and + - hit location is inside a box created around head, and + - head is visible to player (is not behind wall), and + - damage is less then 100 (meaning it was hit only to hand) + - In that case, damage is changed to 100 (meaning enemy will be killed) + +The box is created in a way that its always aligned with your point of view and with deph wider towars you. The box is created in this way to cover hands of enemy inside the box when player is in ADS (zoomed). In that case, if you hit the hand from your point of view, it should be a kill, because body is behind the hand. + +To apply this fix, the hit location must be inside the box. If the hitbox is outside the box, original damage values are applied. + +You can debug hitbox fix in game via command **/rcon debug_handhitbox 1**
+**Hand hitbox fix is enabled by default**
@@ -436,23 +482,24 @@ At the start of the round and at the end of the round, info about weapons of pla ### How does the "Climbing fix" works / what is it -If you climb ladder or wall, the "weapon switch" sound was made only for 1st person player, it was silent for other players. Now the sound matches equally, so you hear exactly what other players hear (meaning if you climb ladder or wall, "weapon switch" sound is made for everybody). -If you want to silently climb ladder or wall, you need to hold weapon down by scrolling down 2x and hold left mouse +If you climb ladder or wall, the "weapon switch" sound was made only for 1st person player, it was silent for other players. The sound is now removed completly - meaning if you climb ladder or wall, "weapon switch" sound is not played at all - same for everybody ###### Original: -| Player | Climb ladder
(weapon normal) | Climb wall
(weapon normal) | Climb ladder
(weapon holded down) | Climb wall
(weapon holded down) | -|---------------|---------------|---------------|-----------------|-------------| -| You | sound | sound | - | - | -| Others | - | - | - | - | +| Player | Climb ladder | Climb wall | +|---------------|---------------|---------------| +| You | sound | sound | +| Others | - | - | -###### zPAM3.31: +###### since zPAM3.32: -| Player | Climb ladder
(weapon normal) | Climb wall
(weapon normal) | Climb ladder
(weapon holded down) | Climb wall
(weapon holded down) | -|---------------|---------------|---------------|-----------------|-------------| -| You | sound | sound | - | - | -| Others | sound | sound | - | - | +| Player | Climb ladder | Climb wall | +|---------------|---------------|---------------| +| You | - | - | +| Others | - | - | + +This sound is played only if you regularly and intentionally switch the weapon
@@ -506,7 +553,7 @@ If you change a color, its applied to team, so your teammates can also see the c
### How does the "Round report" works -At the end of the round, hit + kill informations are printed. It include damage value, hit location and first hit location. For shotgun it prints number of pellets that hit the target
+At the end of the round, report of hits and kills is printed. It include damage value, hit location and first hit location. For shotgun it prints number of pellets that hit the target and range. Read star indicates that "Hand hitbox fix" or "Torso hitbox fix" was applied.

@@ -573,16 +620,26 @@ So diagonal is not affected by PAM.
-### Scoreboard menu - how the Score, Kills, Deaths, Assists, Hits, Plant and Defuses are counted + +### Scoreboard menu +

+ +Features: +- shows statistics of players - Score, Kills, Deaths, Assists, Hits, Grenade kills, Plants and Defuses +- It will always show disconnected players (with [-] prefix) for 5 mins (so you see stats for all players in final scorebard) +- Only Kills and Deaths will are showed for enemy team (to avoid recognize enemy position by watching the scoreboard) + +##### How the Score, Kills, Deaths, Assists, Hits, Plant and Defuses are counted | Column | Description | |---------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Score | Sum of following items:
Kill +1
Teamkill -1
Assist +0.5
Plant +0.5
Defuse +0.5 | +| Score | Sum of following items:
- Kill: +1
- Teamkill: -1
- Assist: +0.5
- Plant: +0.5
- Defuse: +0.5 | | Kills | Number of killed enemy players.
Teamkills are not counted (neither substracted) | | Deaths | Number of times you were killed | | Assists | Number of players you damaged and were killed by your teammate within 5 second | -| Hits | Damage you inflicted to opponent that does not lead to kill.
For example, if you damage a player for 75hp, after the player's health is regenerated, you will recieve +0.75 hit points. | +| Hits | Points given when you hit an enemy and the enemy is then fully healed
- Scopes + rifles (single shot weapons): +1
- Semi/Automatic/Shotgun (other weapons): +0.5
- Pistols: 0

The value is counted only once after the hited enemy is fully healed
Value is colored yellow if its value is >=5.0 and red if its value is >=10.0 | +| Grenades | Number of kills with grenade | | Plants | Number of bomb plants | | Defuses | Number of bomd defuses | @@ -612,7 +669,7 @@ Example: "autorecording_1|matchinfo_1|score_0|playersleft_1" ## Troubleshooting ### Error "zPAM is not installed correctly" -#### Iwd file zpam331.iwd must be installed in main folder. (fs_game) +#### Iwd file zpam332.iwd must be installed in main folder. (fs_game) - From version 3.20, all iwd files have to be installed in main folder. This is because of bug that cvars / settings changed in game are not saved into the config when running a game with fs_game set. Make sure cvar /fs_game is empty and iwd files are placed in main folder. @@ -720,7 +777,7 @@ Attackers should take both objectives to the goal (blue box) to win. (or elimina |--------|---| | mr3, mr10, mr12, mr15 | Max rounds mrxx+1 (SD, RE only) | | 20rounds | first to 21 wins (SD, RE only) | -| 15min, 30min, 60min, unlim | total time limit (TDM, DM, HQ, CTF, HTF only) | +| 10min, 15min, 30min, 60min, unlim | total time limit (TDM, DM, HQ, CTF, HTF only) | ##### Options @@ -929,7 +986,7 @@ Added posibility to call bash mode from menu.

[3.3.44] Cvar system rewrited; any change to server settings is retained even when map changes; new cvar /pam_mode_custom is defined - it tells that changes made to server settings stays between map
[3.3.45] Warnings about wrong server settings (no password, cheats enabled, punkbuster disabled, cvars changes) is changed; its showed in left top corner under the score; if some of the server settings is changed, detailed list of changed cvars is showed; punkbuster warning is removed
-[3.3.46] Hand hit box fix - if hands are in front of body and game somehow badly interprets it as hit to the hand, PAM change it to hit to the body; its an extension to already existing fix in 3.22 for left hand - now its applies also for right hand
+[3.3.46] Hand hit box fix - if hands are in front of body and game somehow badly interprets it as hit to the hand, PAM change it to hit to the body; its an extension to already existing fix in 3.22 for left hand - now its applies also for right hand replaced with [3.3.??]
[3.3.47] Torso hitbox fix; lower torso hitbox (pelvis area) is slightly enlarged as workaround for bad hitbox registration between torso_lower and right/left_leg_upper; this change effectively applies only for rifles, because other weapons has the same damage for torso_lower and right/left_leg_upper
[3.3.48] Consistent shotgun - this is the new name for new shotgun; this shotgun fixes close range hits; it replaces rebalanced shotgun
[3.3.49] Ladder weapon bug fix - silent use of ladder is no more possible; its a situation when you double scroll your weapon, hold fire button and use a ladder replaced via 3.3.68
@@ -961,12 +1018,19 @@ Added posibility to call bash mode from menu.
- between halfs: 2min (previously 5min)
- between halfs at overtime: 1min (previously 5min)
- for LAN mode, there will be no time limits between halfs and maps
-[3.3.68] Climbing sound fix
+[3.3.68] Climbing sound fix
- If you climb ladder or wall, the "weapon switch" sound was made only for 1st person player, it was silent for other players
- Now the sound matches equally, so you hear exactly what other players hear (meaning if you climb ladder or wall, "weapon switch" sound is made for everybody)
- If you want to silently climb ladder or wall, you need to hold weapon down by scrolling down 2x and hold left mouse
- - This fix replaces previous [3.3.49] "Ladder weapon fix" in 3.30
+ - This fix replaces previous [3.3.49] "Ladder weapon fix" in 3.30
replaced with 3.3.70
[3.3.69] SD voiceover sound "Move in!" is now played only if player is not moving (replaces [3.3.62])
+[3.3.70] Climbing sound fix (replaces [3.3.68])
+ - restored original behavior that was affected by [3.3.68] and [3.3.49]
+ - disabling the weapon switch sound that is played only in 1st point of view
+ - meaning that everybody hear the same + + + #### 3.4 Other diff --git a/images/gameservers.png b/images/gameservers.png deleted file mode 100644 index a2b4876..0000000 Binary files a/images/gameservers.png and /dev/null differ diff --git a/images/hand_hitbox_fix.png b/images/hand_hitbox_fix.png new file mode 100644 index 0000000..462e410 Binary files /dev/null and b/images/hand_hitbox_fix.png differ diff --git a/images/hitbox_hand2.png b/images/hitbox_hand2.png deleted file mode 100644 index 7da2a0e..0000000 Binary files a/images/hitbox_hand2.png and /dev/null differ diff --git a/images/round_report.png b/images/round_report.png index 48eed7a..1fb4073 100644 Binary files a/images/round_report.png and b/images/round_report.png differ diff --git a/images/scoreboard_columns.png b/images/scoreboard_columns.png index 4bf9de8..43e6e5c 100644 Binary files a/images/scoreboard_columns.png and b/images/scoreboard_columns.png differ diff --git a/images/spectator_esp.png b/images/spectator_esp.png index b27057a..e98cfbe 100644 Binary files a/images/spectator_esp.png and b/images/spectator_esp.png differ diff --git a/source/default_mp.cfg b/source/default_mp.cfg index cea4aee..ab451ca 100644 --- a/source/default_mp.cfg +++ b/source/default_mp.cfg @@ -7,7 +7,7 @@ sets _match_team2 "-" sets _match_score "-" sets _match_round "-" -sets _zpam "3.31" // ZPAM_RENAME +sets _zpam "3.32" // ZPAM_RENAME diff --git a/source/images/stance_crouch_back.iwi b/source/images/stance_crouch_back.iwi new file mode 100644 index 0000000..bb74e61 Binary files /dev/null and b/source/images/stance_crouch_back.iwi differ diff --git a/source/images/stance_crouch_front.iwi b/source/images/stance_crouch_front.iwi new file mode 100644 index 0000000..b820a97 Binary files /dev/null and b/source/images/stance_crouch_front.iwi differ diff --git a/source/images/stance_crouch_left.iwi b/source/images/stance_crouch_left.iwi new file mode 100644 index 0000000..278153f Binary files /dev/null and b/source/images/stance_crouch_left.iwi differ diff --git a/source/images/stance_crouch_right.iwi b/source/images/stance_crouch_right.iwi new file mode 100644 index 0000000..92dafcc Binary files /dev/null and b/source/images/stance_crouch_right.iwi differ diff --git a/source/images/stance_prone_back.iwi b/source/images/stance_prone_back.iwi new file mode 100644 index 0000000..43fe3b3 Binary files /dev/null and b/source/images/stance_prone_back.iwi differ diff --git a/source/images/stance_prone_front.iwi b/source/images/stance_prone_front.iwi new file mode 100644 index 0000000..43fe3b3 Binary files /dev/null and b/source/images/stance_prone_front.iwi differ diff --git a/source/images/stance_prone_left.iwi b/source/images/stance_prone_left.iwi new file mode 100644 index 0000000..9f548c2 Binary files /dev/null and b/source/images/stance_prone_left.iwi differ diff --git a/source/images/stance_prone_right.iwi b/source/images/stance_prone_right.iwi new file mode 100644 index 0000000..5babb08 Binary files /dev/null and b/source/images/stance_prone_right.iwi differ diff --git a/source/images/stance_stand_back.iwi b/source/images/stance_stand_back.iwi new file mode 100644 index 0000000..3361ee1 Binary files /dev/null and b/source/images/stance_stand_back.iwi differ diff --git a/source/images/stance_stand_front.iwi b/source/images/stance_stand_front.iwi new file mode 100644 index 0000000..47349bc Binary files /dev/null and b/source/images/stance_stand_front.iwi differ diff --git a/source/images/stance_stand_left.iwi b/source/images/stance_stand_left.iwi new file mode 100644 index 0000000..d502a7d Binary files /dev/null and b/source/images/stance_stand_left.iwi differ diff --git a/source/images/stance_stand_right.iwi b/source/images/stance_stand_right.iwi new file mode 100644 index 0000000..a917c03 Binary files /dev/null and b/source/images/stance_stand_right.iwi differ diff --git a/source/maps/mp/gametypes/_callbacksetup.gsc b/source/maps/mp/gametypes/_callbacksetup.gsc index 3b45ef0..6ef64a3 100644 --- a/source/maps/mp/gametypes/_callbacksetup.gsc +++ b/source/maps/mp/gametypes/_callbacksetup.gsc @@ -155,7 +155,7 @@ CodeCallback_PlayerConnect() self.pers["antilagTimeOffset"] = 0; self thread maps\mp\gametypes\global\events::notifyConnecting(); - + // Wait here until player is fully connected self waittill("begin"); @@ -268,48 +268,172 @@ CodeCallback_PlayerDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath damageFeedback = 1; - /* - // Debug angle - if (isDefined(sWeapon) && isDefined(sHitLoc) && isDefined(eAttacker) && isPlayer(eAttacker)) + + // Save info about hits + self_num = self getEntityNumber(); + if (isDefined(eAttacker) && isPlayer(eAttacker)) { - angleDiff = angleDiff(self, eAttacker); - iprintln("Hit angle:"+anglediff+""); + // Create variable to hold hit data + if (!isDefined(eAttacker.hitData)) + eAttacker.hitData = []; + // Because we can hit multiple players in same time (multikill), we need to save it according to players + if (!isDefined(eAttacker.hitData[self_num])) + { + eAttacker.hitData[self_num] = spawnstruct(); + eAttacker.hitData[self_num].id = 0; // inited to 0, but will be incremented. 1 then means first bullet + eAttacker.hitData[self_num].adjustedBy = ""; // string telling if hit was adjusted by FIXes + eAttacker.hitData[self_num].damage = 0; + eAttacker.hitData[self_num].damage_comulated = 0; + } + eAttacker.hitData[self_num].id++; + + self thread hitDataAutoRestart(eAttacker, self_num); } - */ + + + debug = 0; // 1 = print to console + // Hitbox left and right hand fix if (level.scr_hitbox_hand_fix && - isDefined(sWeapon) && isDefined(sHitLoc) && isDefined(eAttacker) && isPlayer(eAttacker)) + isDefined(sWeapon) && isDefined(sHitLoc) && isDefined(eAttacker) && isPlayer(eAttacker) && eAttacker != self) { - // Player is in ads and is shoted to left arm with rifle or scope - if (self playerAds() > 0.5 && - (sWeapon == "kar98k_mp" || sWeapon == "enfield_mp" || sWeapon == "mosin_nagant_mp" || - sWeapon == "springfield_mp" || sWeapon == "enfield_scope_mp" || sWeapon == "kar98k_sniper_mp" || sWeapon == "mosin_nagant_sniper_mp")) + correctWeapon = (sMeansOfDeath == "MOD_RIFLE_BULLET" && ( // This will ignore bash + sWeapon == "kar98k_mp" || sWeapon == "enfield_mp" || sWeapon == "mosin_nagant_mp" || + sWeapon == "springfield_mp" || sWeapon == "enfield_scope_mp" || sWeapon == "kar98k_sniper_mp" || sWeapon == "mosin_nagant_sniper_mp")); + damageOk = (iDamage < 100); + bodyOrHeadVisible = false; + distanceOK = false; + applyFix = false; + + if (correctWeapon && damageOk) { - // If players are looking to each other, make shot to arm a kill distance = distance(self.origin, eAttacker.origin); - angleDiff = angleDiff(self, eAttacker); + distanceOK = (distance > 200); + + if (distanceOK) + { + // Head or pelvis is visible to player + bodyOrHeadVisible = eAttacker maps\mp\gametypes\global\player::isPlayerInSight(self); + + if (bodyOrHeadVisible) + { + applyFix = true; + } + } + } + + + // Hit with rifle or scope + if (level.debug_handhitbox || applyFix) + { + // Define box around head tag tag will be used to determine, if hit location is inside this box and it should be a kill + boxBack = 8; // _________ // _________ + boxFront = 30; // | -[]- | Back // | _[]_ | Top + boxLeft = 9; // | | | Left [Head] Right // | || || | Left [Head] Right + boxRight = 9; // | | Front // |__| |___| Down + boxUp = 8; // |________| ^ // || + boxDown = 14; // Top view Enemy // Front view + if (self.isMoving) // if player is moving, make the box bigger so it will compensate poor hitboxes + { + boxLeft = 11; + boxRight = 11; + } + stance = self maps\mp\gametypes\global\player::getStance(); // prone crouch stand + if (stance == "prone") + { + boxDown = 8; + } + attacker_eye = eAttacker maps\mp\gametypes\global\player::getEyeOrigin(); + + // Debug the box + if (level.debug_handhitbox) + { + if (!isDefined(self.hit)) self.hit = []; + for (i = 0; i < 9; i++) + { + if (!isDefined(self.hit[i])) + { + self.hit[i] = spawn("script_origin",(0,0,0)); + self.hit[i].waypoint_color = (1, 0, 0); + self.hit[i] thread maps\mp\gametypes\global\developer::showWaypoint(); + } + } + //angles = eAttacker getPlayerAngles(); + angles = vectortoangles(self.headTag getOrigin() - attacker_eye); + + right = anglestoright(angles); + up = anglestoup(angles); + forward = anglestoforward(angles); + + pointFront = (forward[0]*(boxFront*-1), forward[1]*(boxFront*-1), forward[2]*(boxFront*-1)); + pointBack = (forward[0]*boxBack, forward[1]*boxBack, forward[2]*boxBack); + pointRight = (right[0]*boxRight, right[1]*boxRight, right[2]*boxRight); + pointLeft = (right[0]*(boxLeft*-1), right[1]*(boxLeft*-1), right[2]*(boxLeft*-1)); + pointUp = (up[0]*boxUp, up[1]*boxUp, up[2]*boxUp); + pointDown = (up[0]*(boxDown*-1), up[1]*(boxDown*-1), up[2]*(boxDown*-1)); + + self.hit[0].origin = (self.headTag getOrigin()) + pointFront + pointRight + pointUp; + self.hit[1].origin = (self.headTag getOrigin()) + pointFront + pointRight + pointDown; + self.hit[2].origin = (self.headTag getOrigin()) + pointFront + pointLeft + pointUp; + self.hit[3].origin = (self.headTag getOrigin()) + pointFront + pointLeft + pointDown; + + self.hit[4].origin = (self.headTag getOrigin()) + pointBack + pointRight + pointUp; + self.hit[5].origin = (self.headTag getOrigin()) + pointBack + pointRight + pointDown; + self.hit[6].origin = (self.headTag getOrigin()) + pointBack + pointLeft + pointUp; + self.hit[7].origin = (self.headTag getOrigin()) + pointBack + pointLeft + pointDown; + + self.hit[8].origin = vPoint; + } - // Left arm - if (distance > 200 && ( - (anglediff > 0 && anglediff < 30 && sHitLoc == "left_hand") || - (anglediff > -20 && anglediff < 25 && sHitLoc == "left_arm_lower") - ) && self.angles[0] > -65 && self.angles[0] < 45) + //angles = eAttacker getPlayerAngles(); + angles = vectortoangles(self.headTag getOrigin() - attacker_eye); + rotationMatrix[0] = anglestoforward(angles); // normalized FORWARD vector of the box + rotationMatrix[1] = anglestoright(angles); // normalized RIGHT vector of the box + rotationMatrix[2] = anglestoup(angles); // normalized UP vector of the box + + vectorToPoint = VectorNormalize(vPoint - self.headTag getOrigin()); // vector pointing from the center of the box to the hit location point + rotatedVectorToPoint[0] = VectorDot(rotationMatrix[0], vectorToPoint); + rotatedVectorToPoint[1] = VectorDot(rotationMatrix[1], vectorToPoint) * -1; // idk why, but Y needs to be fliped (propably because we have right vector, but Y is pointing left) + rotatedVectorToPoint[2] = VectorDot(rotationMatrix[2], vectorToPoint); + + // Get back the hit location but now its aligned to coordinate grid, so we can do simple box checks if point is inside + dist = distance(vPoint, self.headTag getOrigin()); + x = rotatedVectorToPoint[0] * dist; + y = rotatedVectorToPoint[1] * dist; + z = rotatedVectorToPoint[2] * dist; + + // Hit location is inside box + if ((x < boxBack && x > boxFront * -1) && (y < boxLeft && y > boxRight * -1) && (z < boxUp && z > boxDown * -1)) { - if (level.debug_handhitbox) iprintln("^1Hand hitbox fix - making damage to "+sHitLoc+" as kill (angle:"+anglediff+")"); - //println("### Hand hitbox fix - making damage to "+sHitLoc+" as kill (angle:"+anglediff+")"); // EYZA_DEBUG - iDamage = 135; + if (level.debug_handhitbox) + { + if (!correctWeapon) eAttacker iprintln("^3Hand hitbox fix - inside, but this weapon is ignored"); + else if (!damageOk) eAttacker iprintln("^3Hand hitbox fix - inside, but this is already determined as KILL"); + else if (!distanceOK) eAttacker iprintln("^3Hand hitbox fix - inside, but your too close to enemy"); + else if (!bodyOrHeadVisible) eAttacker iprintln("^3Hand hitbox fix - inside, but body and head is not visible"); + else eAttacker iprintln("^1Hand hitbox fix - hit is inside the box, changing to KILL!"); + } + if (applyFix) + { + if (debug) println("^1Hand hitbox fix - making damage to "+sHitLoc+" as kill for " + eAttacker.name); // EYZA_DEBUG + eAttacker.hitData[self_num].adjustedBy = "hand_hitbox_fix"; + iDamage = 100; + } } - // Right arm - if (distance > 200 && ( - (anglediff > 0 && anglediff < 75 && sHitLoc == "right_hand") || - (anglediff > 45 && anglediff < 100 && sHitLoc == "right_arm_lower") - ) && self.angles[0] > -65 && self.angles[0] < 45) + else { - if (level.debug_handhitbox) iprintln("^1Hand hitbox fix - making damage to "+sHitLoc+" as kill (angle:"+anglediff+")"); - //println("### Hand hitbox fix - making damage to "+sHitLoc+" as kill (angle:"+anglediff+")"); // EYZA_DEBUG - iDamage = 135; + if (level.debug_handhitbox) eAttacker iprintln("^9Hand hitbox fix - hit is outside the box"); } + + /* + self.hit[7].origin = (self.headTag getOrigin()) + (0, 150, 0) + (0, 0, 0); + self.hit[8].origin = (self.headTag getOrigin()) + (0, 150, 0) + (boxBack, 0, 0); + self.hit[9].origin = (self.headTag getOrigin()) + (0, 150, 0) + (0, boxLeft, 0); + self.hit[10].origin = (self.headTag getOrigin()) + (0, 150, 0) + (0, boxRight * -1, 0); + self.hit[11].origin = (self.headTag getOrigin()) + (0, 150, 0) + (boxFront * -1, 0, 0); + self.hit[12].origin = (self.headTag getOrigin()) + (0, 150, 0) + Transform; + */ } } @@ -319,23 +443,43 @@ CodeCallback_PlayerDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath { // Bigger torso hitbox // This change efectively applies only for rifles, because other weapons has the same damage for torso_lower and right/left_leg_upper - if (sWeapon == "kar98k_mp" || sWeapon == "enfield_mp" || sWeapon == "mosin_nagant_mp") + correctWeapon = (sMeansOfDeath == "MOD_RIFLE_BULLET" && ( // This will ignore bash + sWeapon == "kar98k_mp" || sWeapon == "enfield_mp" || sWeapon == "mosin_nagant_mp")); + + correctHitLoc = (sHitLoc == "left_leg_upper" || sHitLoc == "right_leg_upper"); + dist = 0; + distOk = false; + applyFix = false; + + if (correctWeapon && correctHitLoc) { - if (sHitLoc == "left_leg_upper" || sHitLoc == "right_leg_upper") - { - dist = distance(self.pelvisTag getOrigin(), vPoint); + dist = distance(self.pelvisTag getOrigin(), vPoint); + distOk = (dist <= 16.5); // Distance between pelvis and knee is around 21 - // Distance between pelvis and knee is around 21 - if (dist < 15.0) - { - if (level.debug_torsohitbox) iprintln("^1Torso hitbox fix - adjusted damage from " + iDamage + " to 135"); - //println("### Torso hitbox fix - adjusted damage from " + iDamage + " to 135 for " + eAttacker.name); // EYZA_DEBUG - iDamage = 135; - } + if (distOk) + applyFix = true; + } + + if (applyFix) + { + if (level.debug_torsohitbox) + { + eAttacker iprintln("^1Torso hitbox fix - adjusted damage from " + iDamage + " to 100"); } + if (debug) println("### Torso hitbox fix - adjusted damage from " + iDamage + " to 100 for " + eAttacker.name); // EYZA_DEBUG + eAttacker.hitData[self_num].adjustedBy = "torso_hitbox_fix"; + iDamage = 100; + } + else if (level.debug_torsohitbox) + { + if (!correctWeapon) eAttacker iprintln("^9Torso hitbox fix - no fix, because this weapon is ignored"); + else if (!correctHitLoc) eAttacker iprintln("^9Torso hitbox fix - no fix, because hit location is not LEG_UPPER"); + else if (!distOk) eAttacker iprintln("^9Torso hitbox fix - no fix, because hit distance " + int(dist*10)/10 + " > 16.5"); } } + + // Consistent shotgun if (level.scr_shotgun_consistent && isDefined(eAttacker) && isPlayer(eAttacker) && isDefined(sHitLoc) && isDefined(sMeansOfDeath) && isDefined(sHitLoc) && isDefined(sWeapon) && sWeapon == "shotgun_mp" && sMeansOfDeath == "MOD_PISTOL_BULLET") @@ -345,30 +489,13 @@ CodeCallback_PlayerDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath // In the same frame, all pellets that hit the target are called one by one // If one pellet kills the enemy, all other pellets are not called, because the player is already killed and is not part of world anymore - // Create variable to hold info about shotgun hits - if (!isDefined(eAttacker.shotgunHit)) - { - eAttacker.shotgunHit = []; - eAttacker thread shotgunCounterAutoRestart(); // will delete eAttacker.shotgunHit after this frame ends - } - - // Because we can hit multiple players in same time (multikill), we need to save it according to players - self_num = self getEntityNumber(); - if (!isDefined(eAttacker.shotgunHit[self_num])) - { - eAttacker.shotgunHit[self_num] = spawnstruct(); - eAttacker.shotgunHit[self_num].id = 0; // inited to 0, but will be incremented. 1 then means first pellet - } - eAttacker.shotgunHit[self_num].id++; - - // count distance dist = distance(self getOrigin(), eAttacker getOrigin()); // Make sure pellets do only once a feedback damage // This is the first pellet - if (eAttacker.shotgunHit[self_num].id == 1) + if (eAttacker.hitData[self_num].id == 1) damageFeedback = 1; else damageFeedback = 0; @@ -383,19 +510,14 @@ CodeCallback_PlayerDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath if (sHitLoc == "left_hand" || sHitLoc == "left_arm_lower" || sHitLoc == "right_hand" || sHitLoc == "right_arm_lower" || sHitLoc == "left_foot" || sHitLoc == "left_leg_lower" || sHitLoc == "right_foot" || sHitLoc == "right_leg_lower") { - eye = eAttacker maps\mp\gametypes\global\player::getEyeOrigin(); - - trace = Bullettrace(eye, self.headTag getOrigin(), true, eAttacker); - headVisible = isDefined(trace["entity"]) && trace["entity"] == self; - - trace = Bullettrace(eye, self.pelvisTag getOrigin(), true, eAttacker); - pelvisVisible = isDefined(trace["entity"]) && trace["entity"] == self; - - //println("### Consistent shotgun: upcoming hit is to leg or hand | headVisible:" + headVisible + " | pelvisVisible:" + pelvisVisible); // EYZA_DEBUG + // Head or pelvis is visible to player + bodyOrHeadVisible = eAttacker maps\mp\gametypes\global\player::isPlayerInSight(self); // Head and pelvis is not at sight (only hand or lags are visible to player) - this should be a hit only - if (!headVisible && !pelvisVisible) + if (!bodyOrHeadVisible) isKill = false; + + if (debug) println("### Consistent shotgun: upcoming hit is to leg or hand | bodyOrHeadVisible:" + bodyOrHeadVisible); // EYZA_DEBUG } @@ -404,14 +526,16 @@ CodeCallback_PlayerDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath iDamage = 100; damageFeedback = 2; // Do big damage feedback, because this bullet kills the player and the others are canceled due to this if (level.debug_shotgun) eAttacker iprintln("^1Distance " + int(dist) + " | close range 0-250 | KILL"); - //println("### Consistent shotgun: attacker:"+eAttacker.name+" | victim:"+self.name+" | distance:" + int(dist) + " | hitLoc:" + sHitLoc + " | close range 0-250 | KILL"); // EYZA_DEBUG + if (debug) println("### Consistent shotgun: attacker:"+eAttacker.name+" | victim:"+self.name+" | distance:" + int(dist) + " | hitLoc:" + sHitLoc + " | close range 0-250 | KILL"); // EYZA_DEBUG + eAttacker.hitData[self_num].adjustedBy = "consistent_shotgun_1_kill"; // Range 1, kill } else { // Scale the damage based on distance iDamage = damageScale(dist, 0, 250, 100, 50); //distance, distStart, distEnd, hpStart, hpEnd if (level.debug_shotgun) eAttacker iprintln("^1Distance " + int(dist) + " | close range 0-250 | ^3hit to hand or leg"); - //println("### Consistent shotgun: attacker:"+eAttacker.name+" | victim:"+self.name+" | distance:" + int(dist) + " | hitLoc:" + sHitLoc + " | close range 0-250 | hit to hand or leg"); // EYZA_DEBUG + if (debug) println("### Consistent shotgun: attacker:"+eAttacker.name+" | victim:"+self.name+" | distance:" + int(dist) + " | hitLoc:" + sHitLoc + " | close range 0-250 | hit to hand or leg"); // EYZA_DEBUG + eAttacker.hitData[self_num].adjustedBy = "consistent_shotgun_1_hit"; // Range 1, hit only, because head and body is not visible } } @@ -421,9 +545,9 @@ CodeCallback_PlayerDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath // Scale the damage based on distance iDamage = damageScale(dist, 250, 384, 100, 50); //distance, distStart, distEnd, hpStart, hpEnd - if (level.debug_shotgun) eAttacker iprintln("^3Distance " + int(dist) + " | mid range 250-384 | " + iDamage + "hp damage (pellet id: " + eAttacker.shotgunHit[self_num].id + ")"); - - //println("### Consistent shotgun: attacker:"+eAttacker.name+" | victim:"+self.name+" | distance:" + int(dist) + " | hitLoc:" + sHitLoc + " | mid range 250-384 | damage:" + iDamage + " | pelletId:" + eAttacker.shotgunHit[self_num].id); // EYZA_DEBUG + if (level.debug_shotgun) eAttacker iprintln("^3Distance " + int(dist) + " | mid range 250-384 | " + iDamage + "hp damage (pellet id: " + eAttacker.hitData[self_num].id + ")"); + if (debug) println("### Consistent shotgun: attacker:"+eAttacker.name+" | victim:"+self.name+" | distance:" + int(dist) + " | hitLoc:" + sHitLoc + " | mid range 250-384 | damage:" + iDamage + " | pelletId:" + eAttacker.hitData[self_num].id); // EYZA_DEBUG + eAttacker.hitData[self_num].adjustedBy = "consistent_shotgun_2"; // Range 2 } // Range 384-500 (3 pellets needed for kill) @@ -432,23 +556,23 @@ CodeCallback_PlayerDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath // Scale the damage based on distance iDamage = damageScale(dist, 384, 500, 50, 34); //distance, distStart, distEnd, hpStart, hpEnd - if (level.debug_shotgun) eAttacker iprintln("^4Distance " + int(dist) + " | mid range 384-500 | " + iDamage + "hp damage (pellet id: " + eAttacker.shotgunHit[self_num].id + ")"); - - //println("### Consistent shotgun: attacker:"+eAttacker.name+" | victim:"+self.name+" | distance:" + int(dist) + " | hitLoc:" + sHitLoc + " | mid range 384-500 | damage:" + iDamage + " | pelletId:" + eAttacker.shotgunHit[self_num].id); // EYZA_DEBUG + if (level.debug_shotgun) eAttacker iprintln("^4Distance " + int(dist) + " | mid range 384-500 | " + iDamage + "hp damage (pellet id: " + eAttacker.hitData[self_num].id + ")"); + if (debug) println("### Consistent shotgun: attacker:"+eAttacker.name+" | victim:"+self.name+" | distance:" + int(dist) + " | hitLoc:" + sHitLoc + " | mid range 384-500 | damage:" + iDamage + " | pelletId:" + eAttacker.hitData[self_num].id); // EYZA_DEBUG + eAttacker.hitData[self_num].adjustedBy = "consistent_shotgun_3"; // Range 3 } // Range 500 - 800 (only 1 pellet is counted, so atleast 3 shots are needed for kill) else { // This is the first pellet - if (eAttacker.shotgunHit[self_num].id == 1) + if (eAttacker.hitData[self_num].id == 1) { // Scale the damage based on distance iDamage = damageScale(dist, 500, 800, 34, 0); //distance, distStart, distEnd, hpStart, hpEnd if (level.debug_shotgun) eAttacker iprintln("^9Distance " + int(dist) + " | far range 500-800 | linear " + iDamage + "hp damage"); - - //println("### Consistent shotgun: attacker:"+eAttacker.name+" | victim:"+self.name+" | distance:" + int(dist) + " | hitLoc:" + sHitLoc + " | far range 500-800 | linear damage:" + iDamage); // EYZA_DEBUG + if (debug) println("### Consistent shotgun: attacker:"+eAttacker.name+" | victim:"+self.name+" | distance:" + int(dist) + " | hitLoc:" + sHitLoc + " | far range 500-800 | linear damage:" + iDamage); // EYZA_DEBUG + eAttacker.hitData[self_num].adjustedBy = "consistent_shotgun_4"; // Range 4 } else { @@ -466,10 +590,16 @@ CodeCallback_PlayerDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath } // Prevents a pistol from killing in one shot if active if (level.prevent_single_shot_pistol && isDefined(sWeapon) && maps\mp\gametypes\_weapons::isPistol(sWeapon) && isdefined(sHitLoc) && sHitLoc == "head") - iDamage = int(iDamage * .85); + iDamage = int(iDamage * .85); // Prevents a ppsh from killing in one shot if active if (level.prevent_single_shot_ppsh && isDefined(sWeapon) && sWeapon == "ppsh_mp" && isdefined(sHitLoc) && sHitLoc == "head") - iDamage = int(iDamage * .9); + iDamage = int(iDamage * .9); + + + + // Save affected damage value + if (isDefined(eAttacker) && isPlayer(eAttacker)) + eAttacker.hitData[self_num].damage = iDamage; //println("##################### " + "notifyDamaging"); @@ -477,6 +607,12 @@ CodeCallback_PlayerDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath ret = maps\mp\gametypes\global\events::notifyDamaging(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset); if (ret) return; + + // Save affected damage value + if (isDefined(eAttacker) && isPlayer(eAttacker)) + eAttacker.hitData[self_num].damage_comulated += iDamage; + + //println("##################### " + "notifyDamage"); // Call onPlayerDamaged event maps\mp\gametypes\global\events::notifyDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset); @@ -493,27 +629,34 @@ CodeCallback_PlayerDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath } } -shotgunCounterAutoRestart() +hitDataAutoRestart(eAttacker, id) { - waittillframeend; - self.shotgunHit = undefined; -} + //self endon("disconnect"); + eAttacker endon("disconnect"); -angleDiff(player, eAttacker) -{ - myAngle = player.angles[1]; // -180 <-> +180 - myAngle += 180; // flip direction, now in range 0 <-> 360 - if (myAngle > 180) myAngle -= 360; // back to range -180 <-> +180 + self notify("hitDataAutoRestart_end"); + self endon("hitDataAutoRestart_end"); - enemyAngle = eAttacker.angles[1]; + // Reset data related to a single frame only + waittillframeend; + waittillframeend; + waittillframeend; + waittillframeend; + eAttacker.hitData[id].id = 0; + eAttacker.hitData[id].damage = 0; + eAttacker.hitData[id].adjustedBy = ""; - anglediff = myAngle - enemyAngle; - if (anglediff > 180) anglediff -= 360; - else if (anglediff < -180) anglediff += 360; + // Wait 5 sec if player is still alive + for(i = 0; i < 5; i++) + { + if (!isDefined(self) || !isAlive(self)) + break; - //iprintln(anglediff); + wait level.fps_multiplier * 1; + } - return anglediff; + // Remove the rest of the data + eAttacker.hitData[id] = undefined; } damageScale(dist, distStart, distEnd, hpStart, hpEnd) diff --git a/source/maps/mp/gametypes/_climbing_sound_fix.gsc b/source/maps/mp/gametypes/_climbing_sound_fix.gsc index cd7d30f..d639e64 100644 --- a/source/maps/mp/gametypes/_climbing_sound_fix.gsc +++ b/source/maps/mp/gametypes/_climbing_sound_fix.gsc @@ -1,23 +1,23 @@ #include maps\mp\gametypes\global\_global; /* -If you climb ladder or wall, the "weapon switch" sound is made only for 1st person player, its silent for other players -If you hide weapon and you climb ladder or obstacle, no "weapon switch" sound is played, its silent for everybody +If you climb ladder or wall, the "weapon switch" sound was made only for 1st person player, it was silent for other players. +The sound is now removed completly - meaning if you climb ladder or wall, "weapon switch" sound is not played at all - same for everybody PAM disabled playing weapon sound change in soundaliases and this script is plaing the sound manually -| ----------------------------------------------------------------------------------------------- -| PAM | | Weapon normal state | Weapon holded down | -| PAM | Action | Ladder | Climb wall | Ladder entering | Climb wall | -| --------------|---------------|---------------|---------------|-----------------|-------------| -| Original | Client | sound | sound | - | - | -| Original | Others | - | - | - | - | -| --------------|---------------|---------------|---------------|-----------------|-------------- -| zPAM3.31 | Client | sound | sound | - | - | -| zPAM3.31 | Others | sound | sound | - | - | -| ----------------------------------------------------------------------------------------------- - -If players want to silently climb ladder or wall, they need to bug weapon by scrolling down 2x and hold left mouse (weapon holded down) +| --------------------------------------------------------------| +| PAM | Action | Ladder | Climb wall | +| --------------|---------------|---------------|---------------| +| Original | Client | sound | sound | +| Original | Others | - | - | +| --------------|---------------|---------------|---------------| +| zPAM3.32 | Client | - | - | +| zPAM3.32 | Others | - | - | +| --------------------------------------------------------------| + +This sound is played only if you regularly and intentionally switch the weapon + */ @@ -50,7 +50,7 @@ bug_fix() current = self getcurrentweapon(); alive = self.sessionstate == "playing"; - if (alive && aliveLast && current != currentLast && currentLast != "none" && weapon1 == weapon1Last && weapon2 == weapon2Last) + if (alive && aliveLast && current != currentLast && currentLast != "none" && current != "none" && weapon1 == weapon1Last && weapon2 == weapon2Last) { //self iprintln("^2Climb sound fix"); diff --git a/source/maps/mp/gametypes/_killcam.gsc b/source/maps/mp/gametypes/_killcam.gsc index df8ac41..b52649e 100644 --- a/source/maps/mp/gametypes/_killcam.gsc +++ b/source/maps/mp/gametypes/_killcam.gsc @@ -77,7 +77,7 @@ killcam(attackerNum, pastTime, length, offsetTime, respawn, isReplay) self.archivetime = 0; self.psoffsettime = 0; - self.killcam = false; + self.killcam = undefined; return; } diff --git a/source/maps/mp/gametypes/_language.gsc b/source/maps/mp/gametypes/_language.gsc new file mode 100644 index 0000000..f5c22e7 --- /dev/null +++ b/source/maps/mp/gametypes/_language.gsc @@ -0,0 +1,82 @@ +#include maps\mp\gametypes\global\_global; + +init() +{ + addEventListener("onConnected", ::onConnected); +} + +onConnected() +{ + if (!isDefined(self.pers["language_orig"])) + self.pers["language_orig"] = -1; + if (!isDefined(self.pers["language_setting"])) + self.pers["language_setting"] = -1; + // English by default + if (!isDefined(self.pers["language"])) + self.pers["language"] = 0; +} + +/* + // Localization + execOnDvarStringValue ui_language 0 "openscriptmenu -1 key_0"; // English + execOnDvarStringValue ui_language 1 "openscriptmenu -1 key_1"; // French + execOnDvarStringValue ui_language 2 "openscriptmenu -1 key_2"; // German + execOnDvarStringValue ui_language 6 "openscriptmenu -1 key_6"; // Russian + execOnDvarStringValue ui_language 7 "openscriptmenu -1 key_7"; // Polish + execOnDvarStringValue ui_language 14 "openscriptmenu -1 key_14"; // Czech + execOnDvarStringValue ui_language 15 "openscriptmenu -1 key_15"; // Czech +*/ + +// Called from OnConnect menu - value of original loc_language cvar +// If known languages are not recognized, -1 is as default +saveOriginalLanguage(lang) +{ + if (lang == "0") self.pers["language_orig"] = 0; + else if (lang == "1") self.pers["language_orig"] = 1; + else if (lang == "2") self.pers["language_orig"] = 2; + else if (lang == "6") self.pers["language_orig"] = 6; + else if (lang == "7") self.pers["language_orig"] = 7; + else if (lang == "14") self.pers["language_orig"] = 14; + else if (lang == "15") self.pers["language_orig"] = 15; + else self.pers["language_orig"] = -1; + + // Parse language + self iprintln("Original language: " + self.pers["language_orig"]); +} + +// Called from quick settings menu +toggle() +{ + if (self.pers["language_setting"] == -1) select(0); + else if (self.pers["language_setting"] == 0) select(1); + else if (self.pers["language_setting"] == 1) select(2); + else if (self.pers["language_setting"] == 2) select(6); + else if (self.pers["language_setting"] == 6) select(7); + else if (self.pers["language_setting"] == 7) select(14); + else if (self.pers["language_setting"] == 14) select(15); + else if (self.pers["language_setting"] == 15) select(-1); + else select(-1); +} + +// Called from quick settings menu when saved players settings are loaded +select(lang) +{ + // If language is "Automatic", use original language from game + if (lang == -1) + lang = self.pers["language_orig"]; + + // If original language is unknown, use English + if (lang == -1) + lang = 0; + + self.pers["language_setting"] = lang; + self.pers["language"] = lang; + + self iprintln("Language switched to " + lang); +} + +// Called from quick settings menu when current settings is saved +getValue() +{ + return self.pers["language_setting"]; +} diff --git a/source/maps/mp/gametypes/_menu_debug.gsc b/source/maps/mp/gametypes/_menu_debug.gsc index c751b52..4947b2b 100644 --- a/source/maps/mp/gametypes/_menu_debug.gsc +++ b/source/maps/mp/gametypes/_menu_debug.gsc @@ -75,6 +75,26 @@ onMenuResponse(menu, response) game["allies_score"] = game["axis_score"]; game["is_halftime"] = true; } + if (response == "intermission") + { + level notify("round_ended"); + level.roundended = true; + + game["state"] = "intermission"; + level notify("intermission"); + + // Spawn each player into intermission + players = getentarray("player", "classname"); + for(i = 0; i < players.size; i++) + { + player = players[i]; + + player closeMenu(); + player closeInGameMenu(); + + player [[level.spawnIntermission]](); + } + } } } diff --git a/source/maps/mp/gametypes/_menu_rcon_map.gsc b/source/maps/mp/gametypes/_menu_rcon_map.gsc index a0c14c5..7a6f943 100644 --- a/source/maps/mp/gametypes/_menu_rcon_map.gsc +++ b/source/maps/mp/gametypes/_menu_rcon_map.gsc @@ -324,11 +324,11 @@ saveSubPamMode(str) self.pers["rcon_map_pam_league"] = str; else if ((gametype == "sd" && (str == "mr3" || str == "mr10" || str == "mr12" || str == "mr15" || str == "20rounds")) || - (gametype == "dm" && (str == "15min" || str == "30min" || str == "60min" || str == "unlim")) || - (gametype == "tdm" && (str == "15min" || str == "30min" || str == "60min" || str == "unlim")) || - (gametype == "hq" && (str == "15min" || str == "30min" || str == "60min" || str == "unlim")) || - (gametype == "ctf" && (str == "15min" || str == "30min" || str == "60min" || str == "unlim")) || - (gametype == "htf" && (str == "15min" || str == "30min" || str == "60min" || str == "unlim")) || + (gametype == "dm" && (str == "10min" || str == "15min" || str == "30min" || str == "60min" || str == "unlim")) || + (gametype == "tdm" && (str == "10min" || str == "15min" || str == "30min" || str == "60min" || str == "unlim")) || + (gametype == "hq" && (str == "10min" || str == "15min" || str == "30min" || str == "60min" || str == "unlim")) || + (gametype == "ctf" && (str == "10min" || str == "15min" || str == "30min" || str == "60min" || str == "unlim")) || + (gametype == "htf" && (str == "10min" || str == "15min" || str == "30min" || str == "60min" || str == "unlim")) || (gametype == "re" && (str == "mr3" || str == "mr10" || str == "mr12" || str == "mr15" || str == "20rounds"))) { if (self.pers["rcon_map_pam_gamesettings"] == str) @@ -372,11 +372,11 @@ joinSubPamModes() { str = self.pers["rcon_map_pam_league"]; if (self.pers["rcon_map_pam_gamesettings"] != "") str += "_" + self.pers["rcon_map_pam_gamesettings"]; + if (self.pers["rcon_map_pam_rifle"]) str += "_rifle"; if (self.pers["rcon_map_pam_2v2"]) str += "_2v2"; if (self.pers["rcon_map_pam_russian"]) str += "_russian"; if (self.pers["rcon_map_pam_lan"]) str += "_lan"; if (self.pers["rcon_map_pam_pcw"]) str += "_pcw"; - if (self.pers["rcon_map_pam_rifle"]) str += "_rifle"; return str; } diff --git a/source/maps/mp/gametypes/_menu_scoreboard.gsc b/source/maps/mp/gametypes/_menu_scoreboard.gsc index b52d1bf..1d7636b 100644 --- a/source/maps/mp/gametypes/_menu_scoreboard.gsc +++ b/source/maps/mp/gametypes/_menu_scoreboard.gsc @@ -3,7 +3,7 @@ /* This script will generate scoreboard with players stats -To make this possible, we will generate 24 lines and text will be colums where lines are separated by new line +To make this possible, we will generate 26 lines and text will be colums where lines are separated by new line */ init() @@ -23,7 +23,13 @@ onConnected() else self setClientCvar2("ui_scoreboard_show", ""); - self.pers["scoreboard_lines_players"] = []; + self.pers["scoreboard_lines_statIds"] = []; + if (!isDefined(self.pers["scoreboard_keepRefreshing"])) + self.pers["scoreboard_keepRefreshing"] = false; + + // This will make sure menu is still responsible even if map is restarted (next round) + if (self.pers["scoreboard_keepRefreshing"]) + self thread generatePlayerList(); } /* @@ -53,10 +59,11 @@ onMenuResponse(menu, response) //self iprintln(line); - if (!isDefined(self.pers["scoreboard_lines_players"][line])) + if (!isDefined(self.pers["scoreboard_lines_statIds"][line])) return true; - clickedPlayer = self.pers["scoreboard_lines_players"][line]; + statsId = self.pers["scoreboard_lines_statIds"][line]; + clickedPlayer = game["playerstats"][statsId]["player"]; if (!isPlayer(clickedPlayer)) return true; @@ -64,7 +71,7 @@ onMenuResponse(menu, response) //self iprintln(clickedPlayer.name); if (!self canBeColorChanged(clickedPlayer)) - return false; + return true; if (!isDefined(clickedPlayer.pers["scoreboard_color"])) clickedPlayer.pers["scoreboard_color"] = 1; @@ -105,46 +112,30 @@ updatePlayerLists() } } -sort(players) +sortByScore(stats) { // Sort score from lowest to highest // Players with undefined stats will be lowest - for(j = 1; j < players.size; j++) + for(j = 1; j < stats.size; j++) { for ( jj = j; jj >= 1 && ( - !isDefined(players[jj].stats) || (isDefined(players[jj-1].stats) && isDefined(players[jj].stats) && ( - (players[jj-1].stats["score"] > players[jj].stats["score"]) || - (players[jj-1].stats["score"] == players[jj].stats["score"] && players[jj-1].stats["kills"] > players[jj].stats["kills"]) || - (players[jj-1].stats["score"] == players[jj].stats["score"] && players[jj-1].stats["kills"] == players[jj].stats["kills"] && players[jj-1].stats["deaths"] < players[jj].stats["deaths"]) - )) + (stats[jj-1]["score"] > stats[jj]["score"]) || + (stats[jj-1]["score"] == stats[jj]["score"] && stats[jj-1]["kills"] > stats[jj]["kills"]) || + (stats[jj-1]["score"] == stats[jj]["score"] && stats[jj-1]["kills"] == stats[jj]["kills"] && stats[jj-1]["deaths"] < stats[jj]["deaths"]) ); jj--) { - temp = players[jj]; - players[jj] = players[jj-1]; - players[jj-1] = temp; + temp = stats[jj]; + stats[jj] = stats[jj-1]; + stats[jj-1] = temp; } } - return players; + return stats; } - -sortPlayers(players) -{ - // Find stats - for(p = 0; p < players.size; p++) - { - player = players[p]; - player.stats = player maps\mp\gametypes\_player_stat::getStats(); - } - - return sort(players); -} - - -sortTeamsByScore() +getTeamPlayersArraySorted() { teamplayers = []; teamplayers["allies"] = []; @@ -152,21 +143,25 @@ sortTeamsByScore() teamplayers["spectator"] = []; teamplayers["none"] = []; - players = getentarray("player", "classname"); - for(p = 0; p < players.size; p++) + // Loop statistics of players and save them into array according to team + for(i = 0; i < game["playerstats"].size; i++) { - player = players[p]; - switch(player.sessionteam) + stat = game["playerstats"][i]; + if (stat["deleted"] == false) { - case "allies": case "axis": case "spectator": case "none": - teamplayers[player.sessionteam][teamplayers[player.sessionteam].size] = player; + switch(stat["team"]) + { + case "allies": case "axis": case "spectator": case "none": + teamplayers[stat["team"]][teamplayers[stat["team"]].size] = stat; + } } } + // find stats for players and sort them by score - teamplayers["allies"] = sortPlayers(teamplayers["allies"]); - teamplayers["axis"] = sortPlayers(teamplayers["axis"]); - teamplayers["spectator"] = sortPlayers(teamplayers["spectator"]); - teamplayers["none"] = sortPlayers(teamplayers["none"]); + teamplayers["allies"] = sortByScore(teamplayers["allies"]); + teamplayers["axis"] = sortByScore(teamplayers["axis"]); + teamplayers["spectator"] = sortByScore(teamplayers["spectator"]); + teamplayers["none"] = sortByScore(teamplayers["none"]); return teamplayers; } @@ -175,44 +170,35 @@ canBeColorChanged(player) { // Enable color change only if we are not in first readyup, only for opponent team return !game["is_public_mode"] && !game["readyup_first_run"] && game["state"] != "intermission" && + isDefined(player) && self.pers["team"] != player.pers["team"] && (self.pers["team"] == "allies" || self.pers["team"] == "axis") && (player.pers["team"] == "allies" || player.pers["team"] == "axis"); } -addLine(player, name, score, kills, deaths, assists, damages, plants, defuses) +addLine(stats, name, score, kills, deaths, assists, damages, grenades, plants, defuses) { - if (isDefined(player)) - self.pers["scoreboard_lines_players"][self.scoreboard.i] = player; - else - self.pers["scoreboard_lines_players"][self.scoreboard.i] = undefined; - - if (isDefined(player) && isDefined(player.pers["scoreboard_color"]) && self canBeColorChanged(player)) + // If empty line (parameters of function are not set) + if (!isDefined(stats)) { - if (player.pers["scoreboard_color"] == 1) - self.scoreboard.names += "^1"; // red - else if (player.pers["scoreboard_color"] == 2) - self.scoreboard.names += "^4"; // blue + self.pers["scoreboard_lines_statIds"][self.scoreboard.i] = undefined; } - - - - if (isDefined(name)) + else { - // In final scoreboard show name colors, otherwise dont - if (game["state"] != "intermission") - name = removeColorsFromString(name); + // Save id of current stat into array so when the player is clicked in menu we get the stat + self.pers["scoreboard_lines_statIds"][self.scoreboard.i] = stats["id"]; + self.scoreboard.names += name; + self.scoreboard.scores += score; + self.scoreboard.kills += kills; + self.scoreboard.deaths += deaths; + self.scoreboard.assists += assists; + self.scoreboard.damages += damages; + self.scoreboard.grenades += grenades; + self.scoreboard.plants += plants; + self.scoreboard.defuses += defuses; } - if (isDefined(score)) self.scoreboard.scores += score; - if (isDefined(kills)) self.scoreboard.kills += kills; - if (isDefined(deaths)) self.scoreboard.deaths += deaths; - if (isDefined(assists)) self.scoreboard.assists += assists; - if (isDefined(damages)) self.scoreboard.damages += damages; - if (isDefined(plants)) self.scoreboard.plants += plants; - if (isDefined(defuses)) self.scoreboard.defuses += defuses; - if (isDefined(defuses)) self.scoreboard.pers["antilagTimeOffset"] += player.pers["antilagTimeOffset"] + "ms"; self.scoreboard.names += "\n^7"; self.scoreboard.scores += "\n^7"; @@ -220,9 +206,9 @@ addLine(player, name, score, kills, deaths, assists, damages, plants, defuses) self.scoreboard.deaths += "\n^7"; self.scoreboard.assists += "\n^7"; self.scoreboard.damages += "\n^7"; + self.scoreboard.grenades += "\n^7"; self.scoreboard.plants += "\n^7"; self.scoreboard.defuses += "\n^7"; - self.scoreboard.pers["antilagTimeOffset"] += "\n^7"; self.scoreboard.i++; } @@ -244,11 +230,11 @@ addTeamLine(teamname) addEmptyLine(); } -addPlayerLine(team, player) +addPlayerLine(team, stats) { // 0=hide; 1=show line odd; 2=show line even; 3=show line hightlighted; "string"=show team name value = ""; - if (self == player) + if (isPlayer(stats["player"]) && self == stats["player"]) value = "3"; // highlight else if ((self.scoreboard.i % 2) == 0) value = "2"; @@ -256,7 +242,7 @@ addPlayerLine(team, player) value = "1"; //added _ means that line can be clicked - if (self canBeColorChanged(player)) + if (self canBeColorChanged(stats["player"])) { value = value + "_"; } @@ -264,37 +250,68 @@ addPlayerLine(team, player) self setClientCvarIfChanged("ui_scoreboard_line_"+self.scoreboard.i, value); + name = stats["name"]; + // Final intermission scoreboard + if (game["state"] == "intermission") + { + if (stats["isConnected"]) + name = stats["player"].name; // get actual player name with colors + } + // Ingame menu scoreboard + else { + name = removeColorsFromString(name); // remove colors + + if (isPlayer(stats["player"]) && isDefined(stats["player"].pers["scoreboard_color"]) && self canBeColorChanged(stats["player"])) + { + if (stats["player"].pers["scoreboard_color"] == 1) + name = "^1" + name; // red + else if (stats["player"].pers["scoreboard_color"] == 2) + name = "^4" + name; // blue + } + } + // PLayer is disconnected + color = ""; + if (stats["isConnected"] == false) + { + name = "[-] " + removeColorsFromString(name); + color = "^9"; + } + if (team == "allies" || team == "axis") { // Add line with player stats - stats = player maps\mp\gametypes\_player_stat::getStats(); - if (isDefined(stats)) + score = " -"; + assists = "-"; + damage = " -"; + plants = "-"; + defuses = "-"; + grenades = "-"; + if (self.sessionteam == team || self.sessionteam == "spectator" || game["state"] == "intermission") // dont show enemy's info (it might say location of enemy) { - damage = int(stats["damage"] / 10) / 10; - plants = "-"; - defuses = "-"; - if (self.sessionteam == team || self.sessionteam == "spectator" || game["state"] == "intermission") // dont show enemy's plants - { - plants = stats["plants"]; - defuses = stats["defuses"]; - } + score = format_fractional(stats["score"], 1, 1); + assists = stats["assists"]; - score = int(stats["score"] * 10) / 10; + damage = ""; + if (stats["damage"] >= 500) damage = "^3"; // yellow + if (stats["damage"] >= 1000) damage = "^1"; // red + damage += format_fractional(stats["damage"] / 100, 1, 1); - addLine(player, player.name, score, stats["kills"], stats["deaths"], stats["assists"], damage, plants, defuses); - - // Debug - //addLine(player.name, 48, 32, 18, 4, 3.7, 2, 0); - } - else - { - addLine(player, player.name, player.score, "^1?", player.deaths, "^1?", "^1?", "^1?", "^1?"); + plants = stats["plants"]; + defuses = stats["defuses"]; + grenades = stats["grenades"]; } + + + + addLine(stats, color + name, color + score, color + stats["kills"], color + stats["deaths"], color + assists, color + damage, color + grenades, color + plants, color + defuses); + + // Debug + //addLine(player.name, 48, 32, 18, 4, 3.7, 2, 0); } else { - addLine(player, player.name, "", "", "", "", "", "", ""); + addLine(stats, name, "", "", "", "", "", "", "", ""); } } @@ -302,213 +319,256 @@ addPlayerLine(team, player) generatePlayerList() { - self endon("disconnect"); + self endon("disconnect"); + + // Make sure onlny 1 thread is running + self notify("matchinfo_lock"); + self endon("matchinfo_lock"); - // Make sure onlny 1 thread is running - self notify("matchinfo_lock"); - self endon("matchinfo_lock"); + waittillframeend; + self setClientCvarIfChanged("ui_scoreboard_map", maps\mp\gametypes\_matchinfo::GetMapName(level.mapname)); + + for (;;) + { + teamplayers = getTeamPlayersArraySorted(); + + /* + type + 0 = nothink + 1 = player line + 2 = player line highlighted + 3 = team heading + */ + + // Temp variables + self.scoreboard = spawnstruct(); + self.scoreboard.i = 1; + self.scoreboard.names = ""; + self.scoreboard.scores = ""; + self.scoreboard.kills = ""; + self.scoreboard.deaths = ""; + self.scoreboard.assists = ""; + self.scoreboard.damages = ""; + self.scoreboard.grenades = ""; + self.scoreboard.plants = ""; + self.scoreboard.defuses = ""; + + self.pers["scoreboard_lines_statIds"] = []; + + + teamname_allies = ""; + teamname_axis = ""; + if (game["scr_matchinfo"] == 1 || game["scr_matchinfo"] == 2) + { + teamname_allies = game["match_team1_name"]; + teamname_axis = game["match_team2_name"]; + if (game["match_team1_side"] == "axis") + { + teamname_allies = game["match_team2_name"]; + teamname_axis = game["match_team1_name"]; + } + } - self setClientCvarIfChanged("ui_scoreboard_map", maps\mp\gametypes\_matchinfo::GetMapName(level.mapname)); + // Generate team names + if (!isDefined(game["allies_score"])) + teamname["allies"] = "^8Allies"; + else if (teamname_allies != "") + teamname["allies"] = "^8" + teamname_allies+" ("+game["allies_score"]+")"; + else + teamname["allies"] = "^8Allies ("+game["allies_score"]+")"; + if (!isDefined(game["axis_score"])) + teamname["axis"] = "^9Axis"; + else if (teamname_axis != "") + teamname["axis"] = "^9" + teamname_axis+" ("+game["axis_score"]+")"; + else + teamname["axis"] = "^9Axis ("+game["axis_score"]+")"; - for (;;) + // Swap teams according to score + team1 = "allies"; + team2 = "axis"; + if (game["axis_score"] > game["allies_score"]) { - teamplayers = sortTeamsByScore(); - - /* - type - 0 = nothink - 1 = player line - 2 = player line highlighted - 3 = team heading - */ - - // Temp variables - self.scoreboard = spawnstruct(); - self.scoreboard.i = 1; - self.scoreboard.names = ""; - self.scoreboard.scores = ""; - self.scoreboard.kills = ""; - self.scoreboard.deaths = ""; - self.scoreboard.assists = ""; - self.scoreboard.damages = ""; - self.scoreboard.plants = ""; - self.scoreboard.defuses = ""; - self.scoreboard.pers["antilagTimeOffset"] = ""; - - self.pers["scoreboard_lines_players"] = []; - - - teamname_allies = ""; - teamname_axis = ""; - if (game["scr_matchinfo"] == 1 || game["scr_matchinfo"] == 2) - { - teamname_allies = game["match_team1_name"]; - teamname_axis = game["match_team2_name"]; - if (game["match_team1_side"] == "axis") - { - teamname_allies = game["match_team2_name"]; - teamname_axis = game["match_team1_name"]; - } - } + team1 = "axis"; + team2 = "allies"; + } - // Generate team names - if (!isDefined(game["allies_score"])) - teamname["allies"] = "^8Allies"; - else if (teamname_allies != "") - teamname["allies"] = "^8" + teamname_allies+" ("+game["allies_score"]+")"; - else - teamname["allies"] = "^8Allies ("+game["allies_score"]+")"; + // Fill allies and axis team + addTeamLine(teamname[team1]); + for(p = teamplayers[team1].size-1; p >= 0; p--) + { + self addPlayerLine(team1, teamplayers[team1][p]); + } + addTeamLine(teamname[team2]); + for(p = teamplayers[team2].size-1; p >= 0; p--) + { + self addPlayerLine(team2, teamplayers[team2][p]); + } - if (!isDefined(game["axis_score"])) - teamname["axis"] = "^9Axis"; - else if (teamname_axis != "") - teamname["axis"] = "^9" + teamname_axis+" ("+game["axis_score"]+")"; - else - teamname["axis"] = "^9Axis ("+game["axis_score"]+")"; + // Spectator + if (teamplayers["spectator"].size > 0) + { + addTeamLine("Spectators"); + for(p = teamplayers["spectator"].size-1; p >= 0; p--) + { + self addPlayerLine("spectator", teamplayers["spectator"][p]); + } + } - // Swap teams according to score - team1 = "allies"; - team2 = "axis"; - if (game["axis_score"] > game["allies_score"]) - { - team1 = "axis"; - team2 = "allies"; - } + // None + if (teamplayers["none"].size > 0) + { + addTeamLine("None team"); + for(p = teamplayers["none"].size-1; p >= 0; p--) + { + self addPlayerLine("none", teamplayers["none"][p]); + } + } - // Fill allies and axis team - addTeamLine(teamname[team1]); - for(p = teamplayers[team1].size-1; p >= 0; p--) + // Text separed by new lines + self setClientCvarIfChanged("ui_scoreboard_names", self.scoreboard.names); + self setClientCvarIfChanged("ui_scoreboard_scores", self.scoreboard.scores); + self setClientCvarIfChanged("ui_scoreboard_kills", self.scoreboard.kills); + self setClientCvarIfChanged("ui_scoreboard_assists", self.scoreboard.assists); + self setClientCvarIfChanged("ui_scoreboard_damages", self.scoreboard.damages); + self setClientCvarIfChanged("ui_scoreboard_deaths", self.scoreboard.deaths); + self setClientCvarIfChanged("ui_scoreboard_grenades", self.scoreboard.grenades); + self setClientCvarIfChanged("ui_scoreboard_plants", self.scoreboard.plants); + self setClientCvarIfChanged("ui_scoreboard_defuses", self.scoreboard.defuses); + self setClientCvarIfChanged("ui_scoreboard_ping", ""); + + + + + // Find top player + topplayer = ""; + topplanter = ""; + topgrenader = ""; + if (game["state"] == "intermission") + { + if (teamplayers[team1].size > 0 && teamplayers[team2].size > 0) + { + // Get top player + team1player = teamplayers[team1][ teamplayers[team1].size-1 ]; + team2player = teamplayers[team2][ teamplayers[team2].size-1 ]; + + if (team1player["score"] >= team2player["score"]) { - self addPlayerLine(team1, teamplayers[team1][p]); + topplayer = team1player["name"]; + if (isPlayer(team1player["player"])) + topplayer = team1player["player"].name; // get actual player name with colors } - addTeamLine(teamname[team2]); - for(p = teamplayers[team2].size-1; p >= 0; p--) + else { - self addPlayerLine(team2, teamplayers[team2][p]); + topplayer = team2player["name"]; + if (isPlayer(team2player["player"])) + topplayer = team2player["player"].name; // get actual player name with colors } - // Spectator - if (teamplayers["spectator"].size > 0) + // Find top planter and grenader in team 1 + team1PlantScore = 0; + team1PlantPlayer = ""; + team1GrenadeScore = 0; + team1GrenadePlayer = ""; + for(p = teamplayers[team1].size-1; p >= 0; p--) { - addTeamLine("Spectators"); - for(p = teamplayers["spectator"].size-1; p >= 0; p--) + stats = teamplayers[team1][p]; + name = stats["name"]; + if (isPlayer(stats["player"])) name = stats["player"].name; // get actual player name with colors + + plantScore = stats["plants"] + stats["defuses"]; + if (plantScore > team1PlantScore) { - self addPlayerLine("spectator", teamplayers["spectator"][p]); + team1PlantScore = plantScore; + team1PlantPlayer = name; + } + if (stats["grenades"] > team1GrenadeScore) + { + team1GrenadeScore = stats["grenades"]; + team1GrenadePlayer = name; } } - // None - if (teamplayers["none"].size > 0) + // Find top planter and grenader in team 2 + team2PlantScore = 0; + team2PlantPlayer = ""; + team2GrenadeScore = 0; + team2GrenadePlayer = ""; + for(p = teamplayers[team2].size-1; p >= 0; p--) { - addTeamLine("None team"); - for(p = teamplayers["none"].size-1; p >= 0; p--) + stats = teamplayers[team2][p]; + name = stats["name"]; + if (isPlayer(stats["player"])) name = stats["player"].name; // get actual player name with colors + + plantScore = stats["plants"] + stats["defuses"]; + if (plantScore > team2PlantScore) { - self addPlayerLine("none", teamplayers["none"][p]); + team2PlantScore = plantScore; + team2PlantPlayer = name; + } + if (stats["grenades"] > team2GrenadeScore) + { + team2GrenadeScore = stats["grenades"]; + team2GrenadePlayer = name; } } - // Text separed by new lines - self setClientCvarIfChanged("ui_scoreboard_names", self.scoreboard.names); - self setClientCvarIfChanged("ui_scoreboard_scores", self.scoreboard.scores); - self setClientCvarIfChanged("ui_scoreboard_kills", self.scoreboard.kills); - self setClientCvarIfChanged("ui_scoreboard_assists", self.scoreboard.assists); - self setClientCvarIfChanged("ui_scoreboard_damages", self.scoreboard.damages); - self setClientCvarIfChanged("ui_scoreboard_deaths", self.scoreboard.deaths); - self setClientCvarIfChanged("ui_scoreboard_plants", self.scoreboard.plants); - self setClientCvarIfChanged("ui_scoreboard_defuses", self.scoreboard.defuses); - self setClientCvarIfChanged("ui_scoreboard_ping", ""/*self.scoreboard.pers["antilagTimeOffset"]*/); - - - + if (team1PlantScore >= 4 || team2PlantScore >= 4) + { + if (team2PlantScore > team1PlantScore) topplanter = team2PlantPlayer; + else topplanter = team1PlantPlayer; + } - // Find top player - topplayer = ""; - topplanter = ""; - if (!game["readyup_first_run"]) + if (team1GrenadeScore >= 4 || team2GrenadeScore >= 4) { - if (teamplayers[team1].size > 0 && teamplayers[team2].size > 0) - { - team1player = teamplayers[team1][ teamplayers[team1].size-1 ]; - team2player = teamplayers[team2][ teamplayers[team2].size-1 ]; - - if (team1player.stats["score"] >= team2player.stats["score"]) - topplayer = team1player.name; - else - topplayer = team2player.name; - - // Find top planter team 1 - team1PlantScore = 0; - team1PlantPlayer = ""; - for(p = teamplayers[team1].size-1; p >= 0; p--) - { - player = teamplayers[team1][p]; - - if (isDefined(player.stats)) - { - plantScore = player.stats["plants"] + player.stats["defuses"]; - - if (plantScore > team1PlantScore) - { - team1PlantScore = plantScore; - team1PlantPlayer = player.name; - } - } - } - - // Find top planter team 2 - team2PlantScore = 0; - team2PlantPlayer = ""; - for(p = teamplayers[team2].size-1; p >= 0; p--) - { - player = teamplayers[team2][p]; - - if (isDefined(player.stats)) - { - plantScore = player.stats["plants"] + player.stats["defuses"]; - - if (plantScore > team2PlantScore) - { - team2PlantScore = plantScore; - team2PlantPlayer = player.name; - } - } - } - - if (team2PlantScore > team1PlantScore) - topplanter = team2PlantPlayer; - else - topplanter = team1PlantPlayer; - } + if (team2GrenadeScore > team1GrenadeScore) topgrenader = team2GrenadePlayer; + else topgrenader = team1GrenadePlayer; } + } + } - toptext = ""; - if (topplayer != "") - toptext = "^9Top player: ^7" + topplayer + "\n^7"; - if (topplanter != "") - toptext += "^9Bomb expert: ^7" + topplanter; + toptext = ""; + if (topplayer != "") + toptext = "^9Top player: ^7" + topplayer + "\n^7"; + if (topplanter != "") + toptext += "^9Bomb expert: ^7" + topplanter + "\n^7"; + if (topgrenader != "") + toptext += "^9Grenade expert: ^7" + topgrenader; + addEmptyLine(); + addEmptyLine(); + addTeamLine(toptext); - addEmptyLine(); - addEmptyLine(); - addTeamLine(toptext); + // Fill empty lines + for(; self.scoreboard.i <= 26; self.scoreboard.i++) + { + self setClientCvarIfChanged("ui_scoreboard_line_"+self.scoreboard.i, "0"); + } - // Fill empty lines - for(; self.scoreboard.i <= 24; self.scoreboard.i++) - { - self setClientCvarIfChanged("ui_scoreboard_line_"+self.scoreboard.i, "0"); - } + i = 0; + while(1) + { + wait level.frame; + i++; - // Keep updating untill we start moving in readyup - if (self.isMoving || !level.in_readyup) - break; + // 1 sec elapsed + if (i > level.sv_fps * 1 || self attackbuttonpressed()) + { + if ((self.sessionstate == "playing" && self.isMoving) || self attackbuttonpressed()) + { + self.pers["scoreboard_keepRefreshing"] = false; // to refresh in next round + return; + } else - wait level.fps_multiplier * 1; - - //self iprintln("updating scoreboard..."); + self.pers["scoreboard_keepRefreshing"] = true; + break; + } } + + //self iprintln("updating scoreboard..."); + } } diff --git a/source/maps/mp/gametypes/_menu_serverinfo.gsc b/source/maps/mp/gametypes/_menu_serverinfo.gsc index e8d5ba7..461d9f1 100644 --- a/source/maps/mp/gametypes/_menu_serverinfo.gsc +++ b/source/maps/mp/gametypes/_menu_serverinfo.gsc @@ -5,9 +5,10 @@ init() addEventListener("onStartGameType", ::onStartGameType); addEventListener("onCvarChanged", ::onCvarChanged); - registerCvar("scr_motd", "STRING", "Welcome. This server is running zPAM3.31"); // ZPAM_RENAME + registerCvarEx("I", "scr_motd", "STRING", "Welcome. This server is running zPAM3.32"); // ZPAM_RENAME level.motd = ""; + level.serverversion = ""; level.serverinfo_left1 = ""; level.serverinfo_left2 = ""; level.serverinfo_right1 = ""; @@ -45,6 +46,7 @@ onCvarChanged(cvar, value, isRegisterTime) updateServerInfo() { self setClientCvarIfChanged("ui_motd", level.motd); + self setClientCvarIfChanged("ui_serverversion", level.serverversion); // These are set from gametype self setClientCvarIfChanged("ui_serverinfo_left1", level.serverinfo_left1); @@ -84,6 +86,25 @@ generateGlobalServerInfo() + level.serverversion = getCvar("version") + " "; // "CoD2 MP 1.3 build pc_1.3_1_1 Mon May 01 2006 05:05:43PM win-x86" + + sys_cpuGHz = getCvarFloat("sys_cpuGHz"); // "2.59199" + if (sys_cpuGHz != 0) + level.serverversion += " (CPU " + format_fractional(sys_cpuGHz, 1, 2) + " GHz)"; + + sys_gpu = getcvar("sys_gpu"); // "Intel(R) UHD Graphics" + if (sys_gpu != "") + level.serverversion += " (GPU " + sys_gpu + ")"; + + level.serverversion += " (" + getcvarint("sv_maxclients") + " slots)"; // (14 slots) + + if (contains(level.serverversion, "win")) + level.serverversion += " (Windows server)"; + else if (contains(level.serverversion, "linux")) + level.serverversion += " (Linux server)"; + + + title = "PAM mode:\n"; value = level.pam_mode + "\n"; diff --git a/source/maps/mp/gametypes/_menus.gsc b/source/maps/mp/gametypes/_menus.gsc index 9dbf375..7db8600 100644 --- a/source/maps/mp/gametypes/_menus.gsc +++ b/source/maps/mp/gametypes/_menus.gsc @@ -16,6 +16,7 @@ onStartGameType() if (!isDefined(game["menuPrecached"])) { game["menu_moddownload"] = "moddownload"; + game["menu_language"] = "language"; game["menu_ingame"] = "ingame"; game["menu_team"] = "team_" + game["allies"] + game["axis"]; // team_britishgerman game["menu_weapon_allies"] = "weapon_" + game["allies"]; @@ -34,6 +35,7 @@ onStartGameType() game["menu_strat_records"] = "strat_records"; precacheMenu(game["menu_moddownload"]); + precacheMenu(game["menu_language"]); precacheMenu(game["menu_ingame"]); precacheMenu(game["menu_team"]); precacheMenu(game["menu_weapon_allies"]); @@ -92,24 +94,34 @@ onConnected() // dont open any menu } - // If player is just connected - else if (self.pers["team"] == "none") + // Server info wasnt skiped yet - player didnt click "continue" + else if(!isDefined(self.pers["skipserverinfo"])) + { + scriptMainMenu = game["menu_serverinfo"]; + self openMenu(game["menu_serverinfo"]); + self maps\mp\gametypes\_menu_serverinfo::updateServerInfo(); + } + + // Menu with language was not opened yet + else if (!isDefined(self.pers["languageLoaded"])) + { + scriptMainMenu = game["menu_language"]; + self openMenu(game["menu_language"]); + } + + else if (game["state"] == "intermission") { self setClientCvar2("ui_allow_weaponchange", 0); + self setClientCvar2("ui_allow_changeteam", 0); + scriptMainMenu = game["menu_ingame"]; // default + } - // Server info wasnt skiped yet - player didnt click "continue" - if(!isDefined(self.pers["skipserverinfo"])) - { - scriptMainMenu = game["menu_serverinfo"]; - self openMenu(game["menu_serverinfo"]); - self maps\mp\gametypes\_menu_serverinfo::updateServerInfo(); - } - // Server info is skipped - else - { - scriptMainMenu = game["menu_team"]; // when esc is pressed, show menu with teams - self openMenu(game["menu_team"]); // else open team menu - } + // Player did not choose team yet after connect + else if (!isDefined(self.pers["firstTeamSelected"])) + { + self setClientCvar2("ui_allow_changeteam", 1); + scriptMainMenu = game["menu_team"]; // when esc is pressed, show menu with teams + self openMenu(game["menu_team"]); // else open team menu } // If team is selected @@ -149,6 +161,9 @@ onConnected() onJoinedTeam(team) { + self.pers["firstTeamSelected"] = true; + + if (team == "allies" || team == "axis") { self setClientCvar2("ui_allow_weaponchange", "1"); @@ -195,18 +210,59 @@ onMenuResponse(menu, response) { maps\mp\gametypes\_force_download::modIsDownloaded(); - self setClientCvar2("g_scriptMainMenu", game["menu_serverinfo"]); + /* + TODO LANG + // Open language menu + self closeMenu(); + self closeInGameMenu(); + self openMenu(game["menu_language"]); + self setClientCvar2("g_scriptMainMenu", game["menu_language"]); + + return true; + } + + else if (menu == game["menu_language"]) + { + maps\mp\gametypes\_language::saveOriginalLanguage(response); + TODO LANG + */ + + self.pers["languageLoaded"] = true; // Open server info self closeMenu(); self closeInGameMenu(); self openMenu(game["menu_serverinfo"]); + self setClientCvar2("g_scriptMainMenu", game["menu_serverinfo"]); self maps\mp\gametypes\_menu_serverinfo::updateServerInfo(); + } + + else if(menu == game["menu_serverinfo"] && response == "close") + { + self closeMenu(); + self closeInGameMenu(); + + if (game["state"] != "intermission") + self setClientCvar2("ui_allow_changeteam", 1); + + if (!isDefined(self.pers["skipserverinfo"])) // first time + { + // After serverinfo is skipped, show menu with teams + self setClientCvar2("g_scriptMainMenu", game["menu_team"]); + self openMenu(game["menu_team"]); + } + else if (!isDefined(self.pers["firstTeamSelected"])) + self openMenu(game["menu_team"]); + else + self openMenu(game["menu_ingame"]); // serverinfo may be opened and closed aditionally via menu + + self.pers["skipserverinfo"] = true; return true; } + if(response == "back") { self closeMenu(); @@ -223,7 +279,7 @@ onMenuResponse(menu, response) if(menu == game["menu_ingame"]) { - if (response == "changeweapon") + if (response == "changeweapon" && game["state"] != "intermission") { self closeMenu(); self closeInGameMenu(); @@ -233,7 +289,7 @@ onMenuResponse(menu, response) self openMenu(game["menu_weapon_axis"]); return true; } - if (response == "changeteam") + if (response == "changeteam" && game["state"] != "intermission") { self closeMenu(); self closeInGameMenu(); @@ -257,7 +313,7 @@ onMenuResponse(menu, response) } } - else if(menu == game["menu_team"]) + else if(menu == game["menu_team"] && game["state"] != "intermission") { teamBefore = self.pers["team"]; switch(response) @@ -328,26 +384,6 @@ onMenuResponse(menu, response) maps\mp\gametypes\_quickmessages::quickresponses(response); return true; } - else if(menu == game["menu_serverinfo"] && response == "close") - { - self closeMenu(); - self closeInGameMenu(); - - if (!isDefined(self.pers["skipserverinfo"])) // first time - { - // After serverinfo is skipped, show menu with teams - self setClientCvar2("g_scriptMainMenu", game["menu_team"]); - self openMenu(game["menu_team"]); - } - else if (self.pers["team"] == "none") - self openMenu(game["menu_team"]); - else - self openMenu(game["menu_ingame"]); - - self.pers["skipserverinfo"] = true; - - return true; - } } diff --git a/source/maps/mp/gametypes/_pam.gsc b/source/maps/mp/gametypes/_pam.gsc index 7586a3b..1026728 100644 --- a/source/maps/mp/gametypes/_pam.gsc +++ b/source/maps/mp/gametypes/_pam.gsc @@ -4,8 +4,8 @@ init() { if(game["firstInit"]) { - precacheString2("STRING_VERSION_INFO", &"zPAM 3.31 ^3PREVIEW"); // ZPAM_RENAME - //precacheString2("STRING_VERSION_INFO", &"^1zPAM 3.31 TEST 1"); // ZPAM_RENAME + precacheString2("STRING_VERSION_INFO", &"zPAM 3.32 ^3PREVIEW"); // ZPAM_RENAME + //precacheString2("STRING_VERSION_INFO", &"^1zPAM 3.32 TEST 2"); // ZPAM_RENAME } } diff --git a/source/maps/mp/gametypes/_player_stat.gsc b/source/maps/mp/gametypes/_player_stat.gsc index 4141fe1..635872f 100644 --- a/source/maps/mp/gametypes/_player_stat.gsc +++ b/source/maps/mp/gametypes/_player_stat.gsc @@ -13,6 +13,7 @@ init() addEventListener("onConnected", ::onConnected); addEventListener("onDisconnect", ::onDisconnect); addEventListener("onConnectedAll", ::onConnectedAll); + addEventListener("onJoinedTeam", ::onJoinedTeam); //thread printThread(); } @@ -147,6 +148,7 @@ print() println("game[playerstats]["+i+"][assists] = " + data["assists"]); println("game[playerstats]["+i+"][deaths] = " + data["deaths"]); println("game[playerstats]["+i+"][kills] = " + data["score"]); + println("game[playerstats]["+i+"][grenades] = " + data["grenades"]); println("game[playerstats]["+i+"][plants] = " + data["plants"]); println("game[playerstats]["+i+"][defuses] = " + data["defuses"]); } @@ -178,55 +180,70 @@ printThread() onConnected() { - handleRename(); - - id = self getEntityNumber(); - - dataId = findData(self.name, id); - if (dataId >= 0 && game["playerstats"][dataId]["isConnected"] == false) - { - game["playerstats"][dataId]["isConnected"] = true; - game["playerstats"][dataId]["lastTime"] = getTime(); - - self thread restoreScore(game["playerstats"][dataId]["kills"], game["playerstats"][dataId]["deaths"]); - } - else - { - // Player was not found via name and id, give other players connecting in same time time to identified them via name and id before this player will be found only by name.. (to avoid stat steal by duplicating name) - waittillframeend; - - dataId = findData(self.name); - if (dataId >= 0 && game["playerstats"][dataId]["isConnected"] == false) - { - game["playerstats"][dataId]["entityId"] = id; - game["playerstats"][dataId]["isConnected"] = true; - game["playerstats"][dataId]["lastTime"] = getTime(); - - self thread restoreScore(game["playerstats"][dataId]["kills"], game["playerstats"][dataId]["deaths"]); - //setCvar("sv_playerstats_" + dataId + "_entityId", id); - } - else - { - // Create new entry - newIndex = game["playerstats"].size; - game["playerstats"][newIndex]["deleted"] = false; - game["playerstats"][newIndex]["entityId"] = id; - game["playerstats"][newIndex]["name"] = self.name; - game["playerstats"][newIndex]["isConnected"] = true; - game["playerstats"][newIndex]["lastTime"] = getTime(); - game["playerstats"][newIndex]["kills"] = 0; - game["playerstats"][newIndex]["assists"] = 0; - game["playerstats"][newIndex]["damage"] = 0; - game["playerstats"][newIndex]["deaths"] = 0; - game["playerstats"][newIndex]["score"] = 0.0; - game["playerstats"][newIndex]["plants"] = 0; - game["playerstats"][newIndex]["defuses"] = 0; - } - } + handleRename(); + + id = self getEntityNumber(); + + dataId = findData(self.name, id); + if (dataId >= 0 && game["playerstats"][dataId]["isConnected"] == false) // note: isConnected is reseted every map_restart + { + game["playerstats"][dataId]["player"] = self; + game["playerstats"][dataId]["isConnected"] = true; + game["playerstats"][dataId]["team"] = self.sessionteam; + game["playerstats"][dataId]["lastTime"] = getTime(); + + self thread restoreScore(game["playerstats"][dataId]["kills"], game["playerstats"][dataId]["deaths"]); + } + else + { + // Player was not found via name and id, give other players connecting in same time time to identified them via name and id before this player will be found only by name.. (to avoid stat steal by duplicating name) + waittillframeend; + + dataId = findData(self.name); + if (dataId >= 0 && game["playerstats"][dataId]["isConnected"] == false) + { + game["playerstats"][dataId]["player"] = self; + game["playerstats"][dataId]["entityId"] = id; + game["playerstats"][dataId]["isConnected"] = true; + game["playerstats"][dataId]["team"] = self.sessionteam; + game["playerstats"][dataId]["lastTime"] = getTime(); + + self thread restoreScore(game["playerstats"][dataId]["kills"], game["playerstats"][dataId]["deaths"]); + //setCvar("sv_playerstats_" + dataId + "_entityId", id); + } + else + { + // Create new entry + newIndex = game["playerstats"].size; + game["playerstats"][newIndex]["id"] = newIndex; + game["playerstats"][newIndex]["player"] = self; + game["playerstats"][newIndex]["deleted"] = false; + game["playerstats"][newIndex]["entityId"] = id; + game["playerstats"][newIndex]["name"] = self.name; + game["playerstats"][newIndex]["team"] = self.sessionteam; + game["playerstats"][newIndex]["isConnected"] = true; + game["playerstats"][newIndex]["lastTime"] = getTime(); + game["playerstats"][newIndex]["kills"] = 0; + game["playerstats"][newIndex]["assists"] = 0; + game["playerstats"][newIndex]["damage"] = 0; + game["playerstats"][newIndex]["deaths"] = 0; + game["playerstats"][newIndex]["score"] = 0.0; + game["playerstats"][newIndex]["grenades"] = 0; + game["playerstats"][newIndex]["plants"] = 0; + game["playerstats"][newIndex]["defuses"] = 0; + } + } } - +onJoinedTeam(team) +{ + dataId = findData(self.name, self getEntityNumber()); + if (dataId >= 0) + { + game["playerstats"][dataId]["team"] = team; + } +} onDisconnect() @@ -235,10 +252,10 @@ onDisconnect() if (dataId >= 0) { game["playerstats"][dataId]["isConnected"] = false; + game["playerstats"][dataId]["player"] = undefined; game["playerstats"][dataId]["lastTime"] = getTime(); + game["playerstats"][dataId]["name"] = self.name; // in case player renamed since connect } - - //level thread restartIfEmpty(); } @@ -305,6 +322,15 @@ AddDeath() } } +AddGrenade() +{ + dataId = self getStatId(); + if (dataId >= 0) + { + game["playerstats"][dataId]["grenades"] += 1; + } +} + AddPlant() { dataId = self getStatId(); diff --git a/source/maps/mp/gametypes/_players_left.gsc b/source/maps/mp/gametypes/_players_left.gsc index ac9fe4b..e4709dd 100644 --- a/source/maps/mp/gametypes/_players_left.gsc +++ b/source/maps/mp/gametypes/_players_left.gsc @@ -51,14 +51,12 @@ onCvarChanged(cvar, value, isRegisterTime) onConnected() { + // Enable player list by default, can be overwritten by player settings + if (!isDefined(self.pers["playersleft_list"])) + self.pers["playersleft_list"] = true; + if (level.scr_show_players_left) - { self thread createHUD(); - - // Enable player list by default, can be overwritten by player settings - if (!isDefined(self.pers["playersleft_list"])) - enable(); - } else self hide(); // hide is set from previous map } diff --git a/source/maps/mp/gametypes/_quicksettings.gsc b/source/maps/mp/gametypes/_quicksettings.gsc index f125e6e..8094f36 100644 --- a/source/maps/mp/gametypes/_quicksettings.gsc +++ b/source/maps/mp/gametypes/_quicksettings.gsc @@ -2,21 +2,21 @@ init() { - addEventListener("onConnected", ::onConnected); - addEventListener("onMenuResponse", ::onMenuResponse); + addEventListener("onConnected", ::onConnected); + addEventListener("onMenuResponse", ::onMenuResponse); } onConnected() { - self endon("disconnect"); + self endon("disconnect"); - if (!isDefined(self.pers["quicksettings_saved"])) - self.pers["quicksettings_saved"] = false; + if (!isDefined(self.pers["quicksettings_saved"])) + self.pers["quicksettings_saved"] = false; - wait level.fps_multiplier * 1; + wait level.fps_multiplier * 1; - if (!self.pers["quicksettings_saved"]) - self updateClientSettings(); // write defaults + if (!self.pers["quicksettings_saved"]) + self updateClientSettings(); // write defaults } /* @@ -28,83 +28,96 @@ onMenuResponse(menu, response) { if (menu == game["menu_quicksettings"]) { - self parseString(response); + self parseString(response); return true; } } parseString(string) { - // set server16 "openscriptmenu quicksettings autorecording_0|matchinfo_0|teamscore_0|" + // set server16 "openscriptmenu quicksettings autorecording_0|matchinfo_0|teamscore_0|" + //iprintln(string); + // Settings are formated in format "_|_|..." - // Settings are formated in format "_|_|..." - - if (string.size == 0) - { - self updateClientSettings(); // write defaults - return; - } - - lastItemPos = 0; - for (i = 0; i <= string.size; i++) - { - if (i == string.size) - char = "|"; // used for last item - else - char = string[i]; - - if (char == "|") - { - item = ToLower(getsubstr(string, lastItemPos, i)); //_ - - if (item == "autorecording") self maps\mp\gametypes\_record::toggle(); - else if (item == "autorecording_0") self maps\mp\gametypes\_record::disable(); - else if (item == "autorecording_1") self maps\mp\gametypes\_record::enable(); - - else if (item == "matchinfo") self maps\mp\gametypes\_matchinfo::ingame_toggle(); - else if (item == "matchinfo_0") self maps\mp\gametypes\_matchinfo::ingame_disable(); - else if (item == "matchinfo_1") self maps\mp\gametypes\_matchinfo::ingame_enable(); - - else if (item == "score") self maps\mp\gametypes\_hud_teamscore::toggle(); - else if (item == "score_0") self maps\mp\gametypes\_hud_teamscore::disable(); - else if (item == "score_1") self maps\mp\gametypes\_hud_teamscore::enable(); - - else if (item == "playersleft") self maps\mp\gametypes\_players_left::toggle(); - else if (item == "playersleft_0") self maps\mp\gametypes\_players_left::disable(); - else if (item == "playersleft_1") self maps\mp\gametypes\_players_left::enable(); + if (string.size == 0) + { + self updateClientSettings(); // write defaults + return; + } - lastItemPos = i + 1; - } - } + lastItemPos = 0; + for (i = 0; i <= string.size; i++) + { + if (i == string.size) + char = "|"; // used for last item + else + char = string[i]; + + if (char == "|") + { + item = ToLower(getsubstr(string, lastItemPos, i)); //_ + + if (item == "autorecording") self maps\mp\gametypes\_record::toggle(); + else if (item == "autorecording_0") self maps\mp\gametypes\_record::disable(); + else if (item == "autorecording_1") self maps\mp\gametypes\_record::enable(); + + else if (item == "matchinfo") self maps\mp\gametypes\_matchinfo::ingame_toggle(); + else if (item == "matchinfo_0") self maps\mp\gametypes\_matchinfo::ingame_disable(); + else if (item == "matchinfo_1") self maps\mp\gametypes\_matchinfo::ingame_enable(); + + else if (item == "score") self maps\mp\gametypes\_hud_teamscore::toggle(); + else if (item == "score_0") self maps\mp\gametypes\_hud_teamscore::disable(); + else if (item == "score_1") self maps\mp\gametypes\_hud_teamscore::enable(); + + else if (item == "playersleft") self maps\mp\gametypes\_players_left::toggle(); + else if (item == "playersleft_0") self maps\mp\gametypes\_players_left::disable(); + else if (item == "playersleft_1") self maps\mp\gametypes\_players_left::enable(); + /* TOTO LANG + else if (item == "language") self maps\mp\gametypes\_language::toggle(); + else if (item == "language_-1") self maps\mp\gametypes\_language::select(-1); + else if (item == "language_0") self maps\mp\gametypes\_language::select(0); + else if (item == "language_1") self maps\mp\gametypes\_language::select(1); + else if (item == "language_2") self maps\mp\gametypes\_language::select(2); + else if (item == "language_6") self maps\mp\gametypes\_language::select(6); + else if (item == "language_7") self maps\mp\gametypes\_language::select(7); + else if (item == "language_14") self maps\mp\gametypes\_language::select(14); + else if (item == "language_15") self maps\mp\gametypes\_language::select(15); + */ + lastItemPos = i + 1; + } + } - self updateClientSettings(); + self updateClientSettings(); } updateClientSettings() { - string = "openscriptmenu quicksettings "; - delimiter = "|"; - - recording = self maps\mp\gametypes\_record::isEnabled(); - matchinfo = self maps\mp\gametypes\_matchinfo::ingame_isEnabled(); - score = self maps\mp\gametypes\_hud_teamscore::isEnabled(); - playersleft = self maps\mp\gametypes\_players_left::isEnabled(); - - string = string + "autorecording_" + recording; - string = string + delimiter; - string = string + "matchinfo_" + matchinfo; - string = string + delimiter; - string = string + "score_" + score; - string = string + delimiter; - string = string + "playersleft_" + playersleft; - - self setClientCvar2("server16", string); - - // Cvars for switching text in quick menu - self setClientCvar2("ui_quicksettings_autorecording", recording); - self setClientCvar2("ui_quicksettings_matchinfo", matchinfo); - self setClientCvar2("ui_quicksettings_score", score); - self setClientCvar2("ui_quicksettings_playersleft", playersleft); - - self.pers["quicksettings_saved"] = true; + string = "openscriptmenu quicksettings "; + delimiter = "|"; + + recording = self maps\mp\gametypes\_record::isEnabled(); + matchinfo = self maps\mp\gametypes\_matchinfo::ingame_isEnabled(); + score = self maps\mp\gametypes\_hud_teamscore::isEnabled(); + playersleft = self maps\mp\gametypes\_players_left::isEnabled(); + //language = self maps\mp\gametypes\_language::getValue(); TODO lang + + string = string + "autorecording_" + recording; + string = string + delimiter; + string = string + "matchinfo_" + matchinfo; + string = string + delimiter; + string = string + "score_" + score; + string = string + delimiter; + string = string + "playersleft_" + playersleft;/* + string = string + delimiter; TODO lang + string = string + "language_" + language;*/ + + self setClientCvar2("server16", string); + + // Cvars for switching text in quick menu + self setClientCvar2("ui_quicksettings_autorecording", recording); + self setClientCvar2("ui_quicksettings_matchinfo", matchinfo); + self setClientCvar2("ui_quicksettings_score", score); + self setClientCvar2("ui_quicksettings_playersleft", playersleft); + + self.pers["quicksettings_saved"] = true; } diff --git a/source/maps/mp/gametypes/_readyup.gsc b/source/maps/mp/gametypes/_readyup.gsc index 1693b36..bf46da8 100644 --- a/source/maps/mp/gametypes/_readyup.gsc +++ b/source/maps/mp/gametypes/_readyup.gsc @@ -154,6 +154,10 @@ Start_Readyup_Mode(runned_in_middle_of_game) } } + waittillframeend; // wait until timeout, overtime etc.. init() func are called + + level.playersready = false; + // Create "Ready-up Mode", "Waiting On X Players", "Clock", "Waring: PB is off.." atd... createLevelHUD(); @@ -293,6 +297,9 @@ onPlayerDamaging(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon if (self.flying) return true; + if (sMeansOfDeath == "MOD_GRENADE_SPLASH") + return true; + if (isPlayer(eAttacker) && self != eAttacker) { if (eAttacker.flying) @@ -429,7 +436,7 @@ playerReadyUpThread() } // Dont show readyup for just connected players - while(self.pers["team"] == "none") + while(!isDefined(self.pers["firstTeamSelected"])) wait level.fps_multiplier * 0.1; // Dont show readyup if player is in team but weapon is not selected yet (player is in spectator session state) @@ -460,7 +467,7 @@ playerReadyUpThread() unsetReady(); - // Check if all players are ready + // Check if all players are ready level thread Check_All_Ready(); @@ -473,7 +480,7 @@ playerReadyUpThread() else if (self MeleeButtonPressed() && !level.in_timeout && (self.pers["team"] == "allies" || self.pers["team"] == "axis")) { catch_next = false; - for(i=0; i<=10; i++) + for(i = 0; i <= level.sv_fps * 0.5; i++) { if(catch_next && self meleeButtonPressed()) { @@ -488,12 +495,12 @@ playerReadyUpThread() else if(!(self meleeButtonPressed())) catch_next = true; - wait level.fps_multiplier * 0.01; + wait level.frame; } } else - wait level.fps_multiplier * 0.1; + wait level.frame; } @@ -594,7 +601,7 @@ areAllPlayersReady() PrintTeamAndHowToUse() { - if (self.pers["team"] == "none") + if (!isDefined(self.pers["firstTeamSelected"])) return; // Spawned as spectator when chosing a weapon, wait untill spawned as player or as full spectator @@ -667,8 +674,6 @@ End_Readyup_Mode() wait level.fps_multiplier * level.scr_readyup_start_timer; // (10sec) - level.in_readyup = 0; - // reset flag as readyup was runned game["readyup_first_run"] = false; @@ -677,6 +682,9 @@ End_Readyup_Mode() if (!level.pam_mode_change) map_restart(true); } + else + // Reset only in timeout because normally it will get reseted by map_restart and also this caused to add 1 death to players if in the same frame player was killed + level.in_readyup = 0; } @@ -807,8 +815,6 @@ Update_Players_Count() createLevelHUD() { - level.playersready = false; - // Show name of league + pam version thread maps\mp\gametypes\_pam::PAM_Header(); @@ -929,7 +935,7 @@ HUD_Clock() } -// Ready-Uo Mode / Halft time Ready-Up Mode / Timeout Ready-Up Mode +// Ready-Up Mode / Halft time Ready-Up Mode / Timeout Ready-Up Mode HUD_ReadyUpMode() { level.readyup_mode = newHudElem2(); @@ -1141,7 +1147,7 @@ HUD_ReadyUp_ResumingIn_Delete() // Called each time player is spawned HUD_SelectTeam() { - if (self.pers["team"] == "none") + if (!isDefined(self.pers["firstTeamSelected"])) { if (!isDefined(self.selectTeamInfoBG)) { diff --git a/source/maps/mp/gametypes/_record.gsc b/source/maps/mp/gametypes/_record.gsc index 8e3cf91..fd8817e 100644 --- a/source/maps/mp/gametypes/_record.gsc +++ b/source/maps/mp/gametypes/_record.gsc @@ -18,9 +18,6 @@ init() if (!level.scr_recording) return; - if (game["scr_matchinfo"] == 0) // used to get team names - return; - // Match ID is just random string to avoid demo overwrite if (!isDefined(game["recordingMatchID"])) game["recordingMatchID"] = generateHash(2); @@ -113,7 +110,7 @@ onSpawned() if (!self.pers["recording_executed"]) { // If player connect in the middle of the match, start recording (recording was not runned yet) - if (!level.in_readyup && !level.in_timeout && (self.sessionteam == "allies" || self.sessionteam == "axis")) + if (!level.in_readyup && !level.in_timeout && (self.pers["team"] == "allies" || self.pers["team"] == "axis")) { waittillframeend; // wait until team names are generated self execRecording(); @@ -192,83 +189,96 @@ generateDemoName() // Wait untill team names are generated in case recording is executed right at start of new round waittillframeend; - // Assing my team name as first - myTeamName = game["match_team1_name"]; - enemyTeamName = game["match_team2_name"]; - if (self.pers["team"] == game["match_team2_side"]) - { - myTeamName = game["match_team2_name"]; - enemyTeamName = game["match_team1_name"]; - } - + teamPrefix = ""; - // Protection if team names from match info are empty - if (myTeamName == "" || enemyTeamName == "") + // If team names are turned off (deathmatch) + if (game["scr_matchinfo"] > 0) { - maps\mp\gametypes\_teamname::refreshTeamName("allies"); // will update level.teamname_allies - maps\mp\gametypes\_teamname::refreshTeamName("axis"); // will update level.teamname_axis - - if (self.pers["team"] == "allies") + // Assing my team name as first + myTeamName = game["match_team1_name"]; + enemyTeamName = game["match_team2_name"]; + if (self.pers["team"] == game["match_team2_side"]) { - myTeamName = level.teamname_allies; - enemyTeamName = level.teamname_axis; + myTeamName = game["match_team2_name"]; + enemyTeamName = game["match_team1_name"]; } - else + + + // Protection if team names from match info are empty + if (myTeamName == "" || enemyTeamName == "") { - myTeamName = level.teamname_axis; - enemyTeamName = level.teamname_allies; - } - } + maps\mp\gametypes\_teamname::refreshTeamName("allies"); // will update level.teamname_allies + maps\mp\gametypes\_teamname::refreshTeamName("axis"); // will update level.teamname_axis + if (self.pers["team"] == "allies") + { + myTeamName = level.teamname_allies; + enemyTeamName = level.teamname_axis; + } + else + { + myTeamName = level.teamname_axis; + enemyTeamName = level.teamname_allies; + } + } - // Generated name is empty - if (myTeamName == "") - myTeamName = "!"; - if (enemyTeamName == "") - enemyTeamName = "!"; + // Generated name is empty + if (myTeamName == "") + myTeamName = "!"; + if (enemyTeamName == "") + enemyTeamName = "!"; - // Get only a-z A-Z 0-9 - myTeamName = getSecureString(myTeamName); - enemyTeamName = getSecureString(enemyTeamName); - // Limit length - enemyExtraLen = 11 - enemyTeamName.size; - if (enemyExtraLen < 0) enemyExtraLen = 0; - myExtraLen = 7 - myTeamName.size; - if (myExtraLen < 0) myExtraLen = 0; + // Get only a-z A-Z 0-9 + myTeamName = getSecureString(myTeamName); + enemyTeamName = getSecureString(enemyTeamName); - myTeamName = getsubstr(myTeamName, 0, 7 + enemyExtraLen); - enemyTeamName = getsubstr(enemyTeamName, 0, 11 + myExtraLen); + // Limit length + enemyExtraLen = 11 - enemyTeamName.size; + if (enemyExtraLen < 0) enemyExtraLen = 0; + myExtraLen = 7 - myTeamName.size; + if (myExtraLen < 0) myExtraLen = 0; - // Get number of players - myTeamPlayers = 0; - enemyTeamPlayers = 0; - players = getentarray("player", "classname"); - for(i = 0; i < players.size; i++) - { - player = players[i]; + myTeamName = getsubstr(myTeamName, 0, 7 + enemyExtraLen); + enemyTeamName = getsubstr(enemyTeamName, 0, 11 + myExtraLen); - if (player.pers["team"] == "allies") - { - if (self.pers["team"] == "allies") - myTeamPlayers++; - else - enemyTeamPlayers++; - } - else if (player.pers["team"] == "axis") + // Get number of players + myTeamPlayers = 0; + enemyTeamPlayers = 0; + players = getentarray("player", "classname"); + for(i = 0; i < players.size; i++) { - if (self.pers["team"] == "axis") - myTeamPlayers++; - else - enemyTeamPlayers++; + player = players[i]; + + if (player.pers["team"] == "allies") + { + if (self.pers["team"] == "allies") + myTeamPlayers++; + else + enemyTeamPlayers++; + } + else if (player.pers["team"] == "axis") + { + if (self.pers["team"] == "axis") + myTeamPlayers++; + else + enemyTeamPlayers++; + } } + + teamPrefix = myTeamName + "_" + enemyTeamName; + + // Show xVx text only if it is not 5v5 + if (myTeamPlayers != 5 && enemyTeamPlayers != 5) + teamPrefix += "_" + myTeamPlayers + "v" + enemyTeamPlayers; + } + else + { + teamPrefix = getsubstr(getSecureString(self.name), 0, 18); } - // Shot xVx text only if it is not 5v5 - xVx = ""; - if (myTeamPlayers != 5 && enemyTeamPlayers != 5) - xVx = "_" + myTeamPlayers + "v" + enemyTeamPlayers; + // Map name mapname = level.mapname; @@ -286,14 +296,14 @@ generateDemoName() mapname = getsubstr(mapname, 0, 3); } - demoName = myTeamName + "_" + enemyTeamName+xVx + "_" + mapname + "#" + game["recordingMatchID"]; + demoName = teamPrefix + "_" + mapname; - // Avoiding file overwritting if (level.gametype != "sd") - { demoName += "#" + level.gametype; - } + demoName += "#" + game["recordingMatchID"]; + + // Avoiding file overwritting if ((level.gametype == "sd" || level.gametype == "re") && game["roundsplayed"] > 0 && !game["overtime_active"]) demoName += "_r" + game["roundsplayed"]; // use round-number else if (level.gametype != "sd" && level.gametype != "re" && isDefined(level.matchstarted) && level.matchstarted) @@ -348,7 +358,7 @@ startRecordingForAll() { player = players[i]; - if (!player.pers["recording_executed"] && (player.sessionteam == "allies" || player.sessionteam == "axis")) + if (!player.pers["recording_executed"] && (player.pers["team"] == "allies" || player.pers["team"] == "axis")) player thread execRecording(); } } @@ -433,32 +443,28 @@ stopRecording() // Try to execute the command every second untill its confirmed by openscriptmenu while(!self.pers["recording_stop_executed"]) { - // Exec command on client side - // If some menu is already opened: - // - by player (main menu / quick messages) -> NOT WORKING - command will not be executed - // - by player (by ESC key) -> that menu will be closed - // - by script (via openMenu()) -> that menu will be closed and exec_cmd will not be closed correctly - // (mouse will be visible with clear backgorund.... so closeMenu() is called to close that menu) - self closeMenu(); - self closeInGameMenu(); - self setClientCvar2("exec_cmd", "stoprecord; openScriptMenu exec_cmd stop_recording"); - self openMenu(game["menu_exec_cmd"]); // open menu via script - self closeMenu(); // will only close menu opened by script + // Open menu only if player is alive (to make sure no other menu is opened) + // Because stop recording may be called when matchinfo is cleared - it will close sevrerinfo menu for connected players + if (IsAlive(self)) + { + // Exec command on client side + // If some menu is already opened: + // - by player (main menu / quick messages) -> NOT WORKING - command will not be executed + // - by player (by ESC key) -> that menu will be closed + // - by script (via openMenu()) -> that menu will be closed and exec_cmd will not be closed correctly + // (mouse will be visible with clear backgorund.... so closeMenu() is called to close that menu) + self closeMenu(); + self closeInGameMenu(); + self setClientCvar2("exec_cmd", "stoprecord; openScriptMenu exec_cmd stop_recording"); + self openMenu(game["menu_exec_cmd"]); // open menu via script + self closeMenu(); // will only close menu opened by script + } // Wait a second before next menu opening for (i = 0; i < 9 && !self.pers["recording_executed"]; i++) wait level.fps_multiplier * .1; } - // Serverinfo menu reopen - // Because stop recording may be called when matchinfo is cleared - it will close sevrerinfo menu for connected players - // If they are still in serverinfo menu, open that menu again - if(!isDefined(self.pers["skipserverinfo"])) - { - self closeMenu(); - self openMenu(game["menu_serverinfo"]); - } - self iprintln("Recording stopped."); self show(); // show recording will start automaticallly again diff --git a/source/maps/mp/gametypes/_round_report.gsc b/source/maps/mp/gametypes/_round_report.gsc index 1d2b18b..d2472b3 100644 --- a/source/maps/mp/gametypes/_round_report.gsc +++ b/source/maps/mp/gametypes/_round_report.gsc @@ -138,6 +138,7 @@ onPlayerDamaged(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, lastDamage.wasKilled = false; lastDamage.teamkill = (self != eAttacker) && (self.pers["team"] == eAttacker.pers["team"]); lastDamage.bombPlanted = level.bombplanted; + lastDamage.adjustedBy = eAttacker.hitData[self getEntityNumber()].adjustedBy; lastDamage.time = gettime(); lastDamage.firstTime = gettime(); @@ -289,31 +290,15 @@ print() { log = self.round_report_array[i]; - - string = getTimeString(log.time, log.bombPlanted) + " ^9"; - - /* - - [Kar98k] hit to Body - [Kar98k] kill to Body - [Kar98k] kill to Body, first [Kar98k] hit to Leg - [Pistol] kill to leg, first [Kar98k] hit to Leg - [MP44] kill to Head, first [Grenade] hit - [Bash] kill to Head, first [Bash] hit to Head - - hit to Body (Kar98k) - kill to Body [Kar98k] - kill to Body [Kar98k], first hit to Leg [Kar98k] - kill to leg [Pistol], first hit to Leg [Kar98k] - kill to Head [MP44], first hit [Grenade] - kill to Head [Bash], first hit to Head [Bash] - - */ - if (log.wasKilled) { + // kill 1 to Arm (M1 Garant) + // kill 2 with 1 pellet (M1 Garant) + // kill 3 237hp to Head (KAR) + // kill 4 to Arm (M1 Garant), first hit 45hp to Leg + // Kill if (log.teamkill) string += "^1team kill " + killNum + "^9"; @@ -321,19 +306,26 @@ print() string += "^2kill " + killNum + "^9"; killNum++; + if (log.multipleDamage == false) + { + damage = int(log.firstDamageValue); + if (damage == 0) damage = 1; + string += " " + damage + "hp"; + } + // To - if (log.sWeapon != "shotgun_mp") + if (log.sWeapon == "shotgun_mp" && log.sMeansOfDeath == "MOD_PISTOL_BULLET") + { + string += " with " + log.pellets + " pellet"; + if (log.pellets > 1) string += "s"; + } + else { if (isDefined(hitLocTexts[log.hitLoc])) string += " to " + hitLocTexts[log.hitLoc]; else if (log.hitLoc != "none") string += " to " + log.hitLoc; } - else - { - string += " with " + log.pellets + " pellet"; - if (log.pellets > 1) string += "s"; - } // [Weapon] weapon = getWeapon(log.sMeansOfDeath, log.sWeapon); @@ -350,16 +342,25 @@ print() { if (log.teamkill) string += "^1team^9 "; - string += "hit"; - //if (log.sMeansOfDeath == "MOD_RIFLE_BULLET" || log.sFirstWeapon == "shotgun_mp") - string += " " + int(log.firstDamageValue) + "hp"; + damage = int(log.firstDamageValue); + if (damage == 0) damage = 1; + string += " " + damage + "hp"; - if (log.sFirstWeapon == "shotgun_mp") + if (log.sFirstWeapon == "shotgun_mp" && log.sFirstMeansOfDeath == "MOD_PISTOL_BULLET") { string += " " + log.pellets + " pellet"; if (log.pellets > 1) string += "s"; + + if (log.adjustedBy == "consistent_shotgun_1_kill" || log.adjustedBy == "consistent_shotgun_1_hit") + string += " range-1"; + else if (log.adjustedBy == "consistent_shotgun_2") + string += " range-2"; + else if (log.adjustedBy == "consistent_shotgun_3") + string += " range-3"; + else if (log.adjustedBy == "consistent_shotgun_4") + string += " range-4"; } if (log.sFirstWeapon != "shotgun_mp") @@ -368,7 +369,6 @@ print() string += " to " + hitLocTexts[log.firstHitLoc]; else if (log.firstHitLoc != "none") string += " to " + log.firstHitLoc; - } // Show weapon if only hit is showed or weapons are different @@ -381,6 +381,12 @@ print() } + // Hit was adjusted by fixes + if (log.adjustedBy == "hand_hitbox_fix" || log.adjustedBy == "torso_hitbox_fix") + { + string += " ^1*"; + } + self iprintln(string); } diff --git a/source/maps/mp/gametypes/_spectating_auto.gsc b/source/maps/mp/gametypes/_spectating_auto.gsc index 8b39d90..0957a27 100644 --- a/source/maps/mp/gametypes/_spectating_auto.gsc +++ b/source/maps/mp/gametypes/_spectating_auto.gsc @@ -5,6 +5,7 @@ init() if(game["firstInit"]) { precacheString2("STRING_AUTO_SPECTATING", &"Auto-spectating"); + precacheString2("STRING_AUTO_SPECTATING_OFF", &"Auto-spectating off"); precacheString2("STRING_AUTO_SPECTATING_REASON_MANUAL", &"Manual change"); precacheString2("STRING_AUTO_SPECTATING_REASON_VISIBLE_ENEMY", &"Enemy in sight"); precacheString2("STRING_AUTO_SPECTATING_REASON_VISIBLE_BY_ENEMY", &"Spotted by enemy"); @@ -18,15 +19,14 @@ init() game["STRING_AUTO_SPECT_IS_ENABLED"] = "Auto-spectator is ^2On"; game["STRING_AUTO_SPECT_IS_DISABLED"] = "Auto-spectator is ^1Off"; - game["STRING_AUTO_SPECT_NAMES_ON"] = "Player names ^2On"; - game["STRING_AUTO_SPECT_NAMES_OFF"] = "Player names ^1Off"; + game["STRING_AUTO_SPECT_NAMES_ON"] = "XRAY ^2On"; + game["STRING_AUTO_SPECT_NAMES_OFF"] = "XRAY ^1Off"; } level.autoSpectating_do = false; level.autoSpectating_ID = -1; // spectated player level.autoSpectating_spectatedPlayer = undefined; level.autoSpectating_noSwitchUntill = 0; - level.autoSpectating_refreshPlayerNames = false; level.autoSpectating_HUD_text = ""; if (!isDefined(game["spectatingSystem_recommandedPlayerMode_teamLeft_player"]) || level.gametype != "sd" || game["round"] == 0) // round in case of bash @@ -45,16 +45,16 @@ init() addEventListener("onSpawnedSpectator", ::onSpawnedSpectator); addEventListener("onPlayerDamaged", ::onPlayerDamaged); addEventListener("onPlayerKilled", ::onPlayerKilled); + + //setCvar("debug_spectator", 1); } onConnected() { if (!isDefined(self.pers["autoSpectating"])) self.pers["autoSpectating"] = false; - self.autoSpectating_inCinematic = false; self.freeSpectating = true; // free spectating, not following any player - self.autoSpectating_ESP = true; } onConnectedAll() @@ -76,7 +76,6 @@ onSpawnedSpectator() onSpawnedPlayer() { - level.autoSpectating_refreshPlayerNames = true; } @@ -191,9 +190,9 @@ autoSpectator() autoSpectatorEnable(); // enable by default - self thread playerNames(); + self thread maps\mp\gametypes\_spectating_hud_esp::ESP_Loop(); - self thread keys_help(); + self thread maps\mp\gametypes\_spectating_hud::keys_help(); wait level.frame* 3; @@ -204,6 +203,8 @@ autoSpectator() hud_text_last = ""; + angles_last = undefined; + for(;;) { wait level.frame; @@ -230,14 +231,13 @@ autoSpectator() // Wait untill timeout is over if (level.in_readyup) { - autoSpectatorDisable(); + self autoSpectatorDisable(); + self autoSpectatorExit(); while (level.in_readyup) wait level.fps_multiplier * 1; - autoSpectatorEnable(); - - self thread playerNames(); + self autoSpectatorEnable(); } @@ -274,8 +274,6 @@ autoSpectator() self.freeSpectating = false; // free spectating ended, now following a player } - - // Update text with follow reason if (self.pers["autoSpectating"]) { @@ -374,7 +372,6 @@ handleMeleeButtonPress() if (!self.pers["autoSpectating"]) { self.freeSpectating = true; // free spectating, not following any player - self.autoSpectating_ESP = true; // by default enabled if (level.debug_spectator) self iprintln("meleeBtn> self.freeSpectating = ^2true"); } @@ -417,9 +414,9 @@ handleUseButtonPress() if (holded) { - self.autoSpectating_ESP = !self.autoSpectating_ESP; - if (self.autoSpectating_ESP) self iprintln(game["STRING_AUTO_SPECT_NAMES_ON"]); - else self iprintln(game["STRING_AUTO_SPECT_NAMES_OFF"]); + self.pers["autoSpectatingESP"] = !self.pers["autoSpectatingESP"]; + if (self.pers["autoSpectatingESP"]) self iprintln(game["STRING_AUTO_SPECT_NAMES_ON"]); + else self iprintln(game["STRING_AUTO_SPECT_NAMES_OFF"]); } else { @@ -446,248 +443,6 @@ handleUseButtonPress() -keys_help() -{ - self endon("disconnect"); - - self thread maps\mp\gametypes\_spectating_hud::keys_show(); - - wait level.fps_multiplier * 5; - - self thread maps\mp\gametypes\_spectating_hud::keys_hide(); -} - - - - - - - -playerNames() -{ - self endon("disconnect"); - - wait level.frame; - - // Wait untill readyup is over (used when timeout is called in time based gametypes and somebody connect) - while(level.in_readyup || isDefined(self.spec_waypoint)) - wait level.fps_multiplier * 1; - - level.autoSpectating_refreshPlayerNames = false; - self.spec_waypoint = []; - - players = getentarray("player", "classname"); - for(i = 0; i < players.size; i++) - { - player = players[i]; - if (player != self && (player.pers["team"] == "allies" || player.pers["team"] == "axis") && player.sessionstate == "playing") - { - index = self.spec_waypoint.size; - self.spec_waypoint[index] = addHUDClient(self, 10, 10, 1.2, (1,1,1), "center", "bottom", "subleft", "subtop"); - self.spec_waypoint[index].name = "name"; - self.spec_waypoint[index].player = player; - self.spec_waypoint[index].fontscale = 0.75; - self.spec_waypoint[index].archived = false; - self.spec_waypoint[index] SetPlayerNameString(player); - self.spec_waypoint[index] thread SetPlayerWaypoint(self, player, (0, 0, 10)); - self.spec_waypoint[index] thread hud_watchPlayer(self, player); - } - } - - index = self.spec_waypoint.size; - self.spec_waypoint[index] = addHUDClient(self, 0, 0, undefined, (1,1,1), "center", "middle", "center", "middle"); - self.spec_waypoint[index].name = "cross"; - self.spec_waypoint[index].player = self; - self.spec_waypoint[index] setShader("white", 2, 2); - self.spec_waypoint[index] thread hud_watchPlayer(self); - - - self.spec_follow_text = addHUDClient(self, 0, -85, 1.2, (1,1,1), "center", "middle", "center", "bottom"); - self.spec_follow_text.fontscale = 1; - self.spec_follow_text.alpha = 0; - - - - waypoints = self.spec_waypoint.size; - saved_player_last = undefined; - - for(;;) - { - wait level.frame; - - // All needs to be removed (changed team or new player connected) - if (self.pers["team"] != "spectator" || level.in_readyup || level.autoSpectating_refreshPlayerNames) - { - break; - } - - saved_dist2D = 0; - saved_dist3D = 0; - saved_player = undefined; - - for(i = 0; i < waypoints; i++) - { - hud = self.spec_waypoint[i]; - - // If HUD is not defined, it means player disconnect and HUD object was deleted - if (!isDefined(hud)) - continue; - - if (hud.name != "name" || !isDefined(hud.player) || !isAlive(hud.player)) - continue; - - self.spec_waypoint[i].paused = !self.autoSpectating_ESP && !self.freeSpectating && self.pers["autoSpectating"]; - - if (!self.freeSpectating) - continue; - - - dist3D = distance(self.origin, hud.player.origin); - - // If text is somewhere in rectangle around center - if ((hud.x > 160 && hud.x < 480 && hud.y > 120 && hud.y < 360) || (dist3D < 300 && hud.x > 160 && hud.x < 480)) - { - if (dist3D < 1000) - { - dist2D = distance((hud.x, hud.y, 0), (320, 240, 0)); // Distance of text from center - text is in 640x480 rectangle aligned left top - - if (!isDefined(saved_player) || (dist2D < saved_dist2D && dist3D < saved_dist3D)) - { - saved_dist2D = dist2D; - saved_dist3D = dist3D; - saved_player = hud.player; - } - } - } - } - - time = 0.1; - - if (isDefined(saved_player)) - { - if (isDefined(saved_player_last) && saved_player_last != saved_player) - { - self.spec_follow_text fadeOverTime(time); - self.spec_follow_text.alpha = 0; - wait level.fps_multiplier * time; - } - if (!isDefined(saved_player_last) || saved_player_last != saved_player) - { - self.spec_follow_text SetPlayerNameString(saved_player); - self.spec_follow_text fadeOverTime(time); - self.spec_follow_text.alpha = 1; - wait level.fps_multiplier * time; - } - } - else if (isDefined(saved_player_last)) - { - self.spec_follow_text fadeOverTime(time); - self.spec_follow_text.alpha = 0; - wait level.fps_multiplier * time; - } - - saved_player_last = saved_player; - - self.spec_follow = saved_player; - } - - - // Destroy all - for(i = 0; i < waypoints; i++) - { - hud = self.spec_waypoint[i]; - - // If HUD is not defined, it means player disconnect and HUD object was deleted - if (!isDefined(hud)) - continue; - - hud destroy2(); - } - self.spec_waypoint = undefined; - - self.spec_follow_text destroy2(); - - // Run again - if (level.autoSpectating_refreshPlayerNames) - { - level.autoSpectating_refreshPlayerNames = false; - self thread playerNames(); - } -} - - -// self is HUD, spectator is hud owner and player is waypoined player -hud_watchPlayer(spectator, player) -{ - for (;;) - { - if (!isDefined(self)) - break; - - if (!isDefined(player)) - { - self destroy2(); - break; - } - - if (self.name == "name") - { - color = (0.8, 0.8, 0.8); - if (player.sessionteam == "allies") - { - if(game["allies"] == "american") - color = (0.4, 0.9, .56); - else if(game["allies"] == "british") - color = (0.45, 0.73, 1); - else if(game["allies"] == "russian") - color = (1, 0.4, 0.4); - } - self.color = color; - - // ESP for spectated player - show only enemy - alpha = 0; - if (!isDefined(spectator.killcam) && spectator.autoSpectating_ESP && !spectator.freeSpectating && spectator.pers["autoSpectating"]) - { - if(isAlive(player) && isDefined(level.autoSpectating_spectatedPlayer) && level.autoSpectating_spectatedPlayer.sessionteam != player.sessionteam) - { - alpha = 1; - - // If is in center, add alpha - dist2D = distance((self.x, self.y, 0), (320, 240, 0)); // Distance of text from center - text is in 640x480 rectangle aligned left top - if (dist2D < 100) - { - alpha = dist2D / 100; - } - } - } - else if (!isDefined(spectator.killcam) && spectator.freeSpectating) - { - if (isAlive(player)) - alpha = 1; - else - alpha = 0.4; - } - - self.alpha = alpha; - } - - if (self.name == "cross") - { - if (spectator.freeSpectating) - self.alpha = 1; - else - self.alpha = 0; - } - - wait level.frame; - } -} - - - - - - autoSpectatorEnable() { @@ -705,7 +460,6 @@ autoSpectatorEnable() self.autoSpectatingBG.y = 40; self.autoSpectatingBG.horzAlign = "center"; self.autoSpectatingBG.vertAlign = "top"; - self.autoSpectatingBG.alpha = 0.5; self.autoSpectatingBG setShader("black", 80, 10); } @@ -721,11 +475,12 @@ autoSpectatorEnable() self.autoSpectatingText.y = 42; self.autoSpectatingText.archived = false; self.autoSpectatingText.font = "default"; - self.autoSpectatingText.sort = 2; self.autoSpectatingText.alpha = 0.9; + self.autoSpectatingText.sort = 2; self.autoSpectatingText.fontscale = 0.6; } + self.autoSpectatingBG.alpha = 0.5; self.autoSpectatingText setText(game["STRING_AUTO_SPECTATING"]); } @@ -735,17 +490,8 @@ autoSpectatorDisable() self.pers["autoSpectating"] = false; self.spectatorclient = -1; - - if(isdefined(self.autoSpectatingBG)) - { - self.autoSpectatingBG destroy2(); - self.autoSpectatingBG = undefined; - } - if(isdefined(self.autoSpectatingText)) - { - self.autoSpectatingText destroy2(); - self.autoSpectatingText = undefined; - } + self.autoSpectatingBG.alpha = 0; + self.autoSpectatingText setText(game["STRING_AUTO_SPECTATING_OFF"]); } autoSpectatorExit() diff --git a/source/maps/mp/gametypes/_spectating_hud.gsc b/source/maps/mp/gametypes/_spectating_hud.gsc index c1f8421..e108ba7 100644 --- a/source/maps/mp/gametypes/_spectating_hud.gsc +++ b/source/maps/mp/gametypes/_spectating_hud.gsc @@ -9,26 +9,10 @@ init() if(game["firstInit"]) { - precacheString2("STRING_AUTO_SPECTATOR_KEY", &"Press ^3[{+melee_breath}]^7 to disable auto-spectator\nHold ^3[{+attack}]^7 to enable auto-spectator\nPress ^3[{+activate}]^7 to play killcam\nHold ^3[{+activate}]^7 to toggle player names"); - - precacheString2("STRING_AUTO_SPECTATOR_HIT_HEAD", &"Head"); - precacheString2("STRING_AUTO_SPECTATOR_HIT_NECK", &"Neck"); - precacheString2("STRING_AUTO_SPECTATOR_HIT_BODY_UPPER", &"Body"); - precacheString2("STRING_AUTO_SPECTATOR_HIT_BODY_LOWE", &"Body"); - precacheString2("STRING_AUTO_SPECTATOR_HIT_SHOULDER", &"Shoulder"); - precacheString2("STRING_AUTO_SPECTATOR_HIT_ARM", &"Arm"); - precacheString2("STRING_AUTO_SPECTATOR_HIT_HAND", &"Hand"); - precacheString2("STRING_AUTO_SPECTATOR_HIT_LEG_UPPEER", &"Leg"); - precacheString2("STRING_AUTO_SPECTATOR_HIT_LEG_LOWER", &"Leg"); - precacheString2("STRING_AUTO_SPECTATOR_HIT_FOOT", &"Foot"); - precacheString2("STRING_AUTO_SPECTATOR_HIT_GRENADE", &"Grenade"); - - precacheShader("headicon_dead"); + precacheString2("STRING_AUTO_SPECTATOR_KEY", &"Press ^3[{+melee_breath}]^7 to disable auto-spectator\nHold ^3[{+attack}]^7 to enable auto-spectator\nPress ^3[{+activate}]^7 to play killcam\nHold ^3[{+activate}]^7 to toggle XRAY"); } addEventListener("onSpawnedSpectator", ::onSpawnedSpectator); - addEventListener("onPlayerDamaged", ::onPlayerDamaged); - addEventListener("onPlayerKilled", ::onPlayerKilled); } onConnected() @@ -53,316 +37,21 @@ onSpawnedSpectator() } -/* -Called when player has taken damage. -self is the player that took damage. -*/ -onPlayerDamaged(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime) -{ - if (isDefined(eAttacker) && isPlayer(eAttacker) && self != eAttacker && isDefined(level.autoSpectating_spectatedPlayer) && eAttacker == level.autoSpectating_spectatedPlayer && !level.in_readyup) - { - // Count total damage - id = self getEntityNumber(); - if (!isDefined(eAttacker.autoSpectating_hits)) - eAttacker.autoSpectating_hits = []; - if (!isDefined(eAttacker.autoSpectating_hits[id])) - eAttacker.autoSpectating_hits[id] = 0; - eAttacker.autoSpectating_hits[id] += iDamage; - self thread resetDamage(eAttacker, id); - - // Show to all spectators - players = getentarray("player", "classname"); - for(i = 0; i < players.size; i++) - { - player = players[i]; - if (player.pers["team"] == "spectator" && player.pers["autoSpectating"]) - { - player thread showDamageInfo(eAttacker.autoSpectating_hits[id], sHitLoc, sMeansOfDeath); - } - } - } - - - if (isDefined(level.autoSpectating_spectatedPlayer) && self == level.autoSpectating_spectatedPlayer && !level.in_readyup) - { - // Show to all spectators - players = getentarray("player", "classname"); - for(i = 0; i < players.size; i++) - { - player = players[i]; - if (player.pers["team"] == "spectator" && player.pers["autoSpectating"]) - { - player thread showTakenDamageInfo((self.maxhealth - self.health) + iDamage, sHitLoc, sMeansOfDeath); - } - } - } -} - -/* -Called when player is killed -self is the player that was killed. -*/ -onPlayerKilled(eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration) -{ - if (isDefined(eAttacker) && isPlayer(eAttacker) && self != eAttacker && isDefined(level.autoSpectating_spectatedPlayer) && eAttacker == level.autoSpectating_spectatedPlayer && !level.in_readyup) - { - // Show to all spectators - players = getentarray("player", "classname"); - for(i = 0; i < players.size; i++) - { - player = players[i]; - if (player.pers["team"] == "spectator" && player.pers["autoSpectating"]) - { - player thread showKillInfo(); - } - } - } -} - - - - -resetDamage(eAttacker, id) -{ - //self endon("disconnect"); - eAttacker endon("disconnect"); - - self notify("autoSpectating_resetDamage_end"); - self endon("autoSpectating_resetDamage_end"); - - wait level.fps_multiplier * 5; - - eAttacker.autoSpectating_hits[id] = undefined; -} - - -showDamageInfo(iDamage, sHitLoc, sMeansOfDeath) -{ - hitLocTexts["head"] = game["STRING_AUTO_SPECTATOR_HIT_HEAD"]; - hitLocTexts["neck"] = game["STRING_AUTO_SPECTATOR_HIT_NECK"]; - hitLocTexts["torso_upper"] = game["STRING_AUTO_SPECTATOR_HIT_BODY_UPPER"]; - hitLocTexts["torso_lower"] = game["STRING_AUTO_SPECTATOR_HIT_BODY_LOWE"]; - hitLocTexts["left_arm_upper"] = game["STRING_AUTO_SPECTATOR_HIT_SHOULDER"]; - hitLocTexts["left_arm_lower"] = game["STRING_AUTO_SPECTATOR_HIT_ARM"]; - hitLocTexts["left_hand"] = game["STRING_AUTO_SPECTATOR_HIT_HAND"]; - hitLocTexts["right_arm_upper"] = game["STRING_AUTO_SPECTATOR_HIT_SHOULDER"]; - hitLocTexts["right_arm_lower"] = game["STRING_AUTO_SPECTATOR_HIT_ARM"]; - hitLocTexts["right_hand"] = game["STRING_AUTO_SPECTATOR_HIT_HAND"]; - hitLocTexts["left_leg_upper"] = game["STRING_AUTO_SPECTATOR_HIT_LEG_UPPEER"]; - hitLocTexts["left_leg_lower"] = game["STRING_AUTO_SPECTATOR_HIT_LEG_LOWER"]; - hitLocTexts["left_foot"] = game["STRING_AUTO_SPECTATOR_HIT_FOOT"]; - hitLocTexts["right_leg_upper"] = game["STRING_AUTO_SPECTATOR_HIT_LEG_UPPEER"]; - hitLocTexts["right_leg_lower"] = game["STRING_AUTO_SPECTATOR_HIT_LEG_LOWER"]; - hitLocTexts["right_foot"] = game["STRING_AUTO_SPECTATOR_HIT_FOOT"]; - - self endon("disconnect"); - - if (isDefined(self.killcam)) - return; - - self notify("autoSpectating_showDamageInfo_end"); - self endon("autoSpectating_showDamageInfo_end"); - - if (!isDefined(self.hud_damageinfo)) - { - self.hud_damageinfo = newClientHudElem2(self); - self.hud_damageinfo.horzAlign = "center"; - self.hud_damageinfo.vertAlign = "middle"; - self.hud_damageinfo.x = 50; - self.hud_damageinfo.fontscale = 1.2; - self.hud_damageinfo.archived = false; - } - - if (!isDefined(self.hud_damageinfo_loc)) - { - self.hud_damageinfo_loc = newClientHudElem2(self); - self.hud_damageinfo_loc.horzAlign = "center"; - self.hud_damageinfo_loc.vertAlign = "middle"; - self.hud_damageinfo_loc.x = 80; - self.hud_damageinfo_loc.fontscale = 1.1; - self.hud_damageinfo_loc.archived = false; - } - - if (iDamage > 100) - iDamage = 100; - - self.hud_damageinfo setValue(iDamage); - - if (sMeansOfDeath == "MOD_GRENADE_SPLASH") - self.hud_damageinfo_loc setText(game["STRING_AUTO_SPECTATOR_HIT_GRENADE"]); - else if (isDefined(hitLocTexts[sHitLoc])) - self.hud_damageinfo_loc setText(hitLocTexts[sHitLoc]); - - r = 1; - g = 1 - ((iDamage - 50) / 50); if (g < 0) g = 0; if (g > 1) g = 1; - b = 1 - (iDamage / 50); if (b < 0) b = 0; if (b > 1) b = 1; - - // red to orange to yellow -> add green - // yellow to white -> add blue - - self.hud_damageinfo.color = (r, g, b); - self.hud_damageinfo_loc.color = (1, 1, 1); - - self.hud_damageinfo.y = 0; - self.hud_damageinfo.alpha = 1; - self.hud_damageinfo_loc.y = 0; - self.hud_damageinfo_loc.alpha = 1; - - self.hud_damageinfo moveovertime(2); - self.hud_damageinfo.y = -50; - self.hud_damageinfo_loc moveovertime(2); - self.hud_damageinfo_loc.y = -50; - - wait level.fps_multiplier * 1; - self.hud_damageinfo FadeOverTime(1); - self.hud_damageinfo.alpha = 0; - self.hud_damageinfo_loc FadeOverTime(1); - self.hud_damageinfo_loc.alpha = 0; - wait level.fps_multiplier * 2; - self.hud_damageinfo destroy2(); - self.hud_damageinfo_loc destroy2(); -} - - - -showTakenDamageInfo(iDamage, sHitLoc, sMeansOfDeath) -{ - hitLocTexts["head"] = game["STRING_AUTO_SPECTATOR_HIT_HEAD"]; - hitLocTexts["neck"] = game["STRING_AUTO_SPECTATOR_HIT_NECK"]; - hitLocTexts["torso_upper"] = game["STRING_AUTO_SPECTATOR_HIT_BODY_UPPER"]; - hitLocTexts["torso_lower"] = game["STRING_AUTO_SPECTATOR_HIT_BODY_LOWE"]; - hitLocTexts["left_arm_upper"] = game["STRING_AUTO_SPECTATOR_HIT_SHOULDER"]; - hitLocTexts["left_arm_lower"] = game["STRING_AUTO_SPECTATOR_HIT_ARM"]; - hitLocTexts["left_hand"] = game["STRING_AUTO_SPECTATOR_HIT_HAND"]; - hitLocTexts["right_arm_upper"] = game["STRING_AUTO_SPECTATOR_HIT_SHOULDER"]; - hitLocTexts["right_arm_lower"] = game["STRING_AUTO_SPECTATOR_HIT_ARM"]; - hitLocTexts["right_hand"] = game["STRING_AUTO_SPECTATOR_HIT_HAND"]; - hitLocTexts["left_leg_upper"] = game["STRING_AUTO_SPECTATOR_HIT_LEG_UPPEER"]; - hitLocTexts["left_leg_lower"] = game["STRING_AUTO_SPECTATOR_HIT_LEG_LOWER"]; - hitLocTexts["left_foot"] = game["STRING_AUTO_SPECTATOR_HIT_FOOT"]; - hitLocTexts["right_leg_upper"] = game["STRING_AUTO_SPECTATOR_HIT_LEG_UPPEER"]; - hitLocTexts["right_leg_lower"] = game["STRING_AUTO_SPECTATOR_HIT_LEG_LOWER"]; - hitLocTexts["right_foot"] = game["STRING_AUTO_SPECTATOR_HIT_FOOT"]; - - self endon("disconnect"); - - if (isDefined(self.killcam)) - return; - - self notify("autoSpectating_showTakenDamageInfo_end"); - self endon("autoSpectating_showTakenDamageInfo_end"); - - if (!isDefined(self.hud_takendamageinfo)) - { - self.hud_takendamageinfo = newClientHudElem2(self); - self.hud_takendamageinfo.horzAlign = "center"; - self.hud_takendamageinfo.vertAlign = "middle"; - self.hud_takendamageinfo.x = -20; - self.hud_takendamageinfo.fontscale = 1.2; - self.hud_takendamageinfo.archived = false; - } - - if (!isDefined(self.hud_takendamageinfo_loc)) - { - self.hud_takendamageinfo_loc = newClientHudElem2(self); - self.hud_takendamageinfo_loc.horzAlign = "center"; - self.hud_takendamageinfo_loc.vertAlign = "middle"; - self.hud_takendamageinfo_loc.x = 10; - self.hud_takendamageinfo_loc.fontscale = 1.1; - self.hud_takendamageinfo_loc.archived = false; - } - - if (iDamage > 100) - iDamage = 100; - - self.hud_takendamageinfo setValue(iDamage*-1); - - if (sMeansOfDeath == "MOD_GRENADE_SPLASH") - self.hud_takendamageinfo_loc setText(game["STRING_AUTO_SPECTATOR_HIT_GRENADE"]); - else if (isDefined(hitLocTexts[sHitLoc])) - self.hud_takendamageinfo_loc setText(hitLocTexts[sHitLoc]); - - r = 1; - g = 1 - ((iDamage - 50) / 50); if (g < 0) g = 0; if (g > 1) g = 1; - b = 1 - (iDamage / 50); if (b < 0) b = 0; if (b > 1) b = 1; - - // red to orange to yellow -> add green - // yellow to white -> add blue - - self.hud_takendamageinfo.color = (r, g, b); - self.hud_takendamageinfo_loc.color = (1, 1, 1); - - self.hud_takendamageinfo.y = 80; - self.hud_takendamageinfo.alpha = 1; - self.hud_takendamageinfo_loc.y = 80; - self.hud_takendamageinfo_loc.alpha = 1; - - self.hud_takendamageinfo moveovertime(2); - self.hud_takendamageinfo.y = 120; - self.hud_takendamageinfo_loc moveovertime(2); - self.hud_takendamageinfo_loc.y = 120; - - wait level.fps_multiplier * 1; - - self.hud_takendamageinfo FadeOverTime(1); - self.hud_takendamageinfo.alpha = 0; - self.hud_takendamageinfo_loc FadeOverTime(1); - self.hud_takendamageinfo_loc.alpha = 0; - - wait level.fps_multiplier * 2; - - self.hud_takendamageinfo destroy2(); - self.hud_takendamageinfo_loc destroy2(); -} - - - - -showKillInfo() +keys_help() { self endon("disconnect"); - if (isDefined(self.killcam)) - return; - - self notify("autoSpectating_showKillInfo_end"); - self endon("autoSpectating_showKillInfo_end"); + self thread keys_show(); - if (!isDefined(self.hud_damageinfo_kill)) - { - self.hud_damageinfo_kill = newClientHudElem2(self); - self.hud_damageinfo_kill.horzAlign = "center"; - self.hud_damageinfo_kill.vertAlign = "middle"; - self.hud_damageinfo_kill.x = 30; - self.hud_damageinfo_kill.archived = false; - self.hud_damageinfo_kill setShader("headicon_dead", 23, 23); - } - - self.hud_damageinfo_kill.y = 0; - self.hud_damageinfo_kill.alpha = 1; - self.hud_damageinfo_kill moveovertime(2); - self.hud_damageinfo_kill.y = -50; - - wait level.fps_multiplier * 1; - - self.hud_damageinfo_kill FadeOverTime(1); - self.hud_damageinfo_kill.alpha = 0; - - wait level.fps_multiplier * 2; + wait level.fps_multiplier * 5; - self.hud_damageinfo_kill destroy2(); + self thread keys_hide(); } - - - - - - keys_show() { if(!isdefined(self.autoSpectatingKeyInfoBG)) @@ -421,16 +110,6 @@ keys_hide() - - - - - - - - - - HUD_hideUI() { diff --git a/source/maps/mp/gametypes/_spectating_hud_damage.gsc b/source/maps/mp/gametypes/_spectating_hud_damage.gsc new file mode 100644 index 0000000..d16fa48 --- /dev/null +++ b/source/maps/mp/gametypes/_spectating_hud_damage.gsc @@ -0,0 +1,501 @@ +#include maps\mp\gametypes\global\_global; + +init() +{ + addEventListener("onPlayerDamaged", ::onPlayerDamaged); // In readyup show damage info for regular players + + if(game["firstInit"]) + { + precacheString2("STRING_AUTO_SPECTATOR_HIT_HP", &"&&1 hp"); + + precacheString2("STRING_AUTO_SPECTATOR_HIT_HEAD", &"Head"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_NECK", &"Neck"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_BODY", &"Torso"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_BODY_UPPER", &"Torso-up"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_BODY_LOWER", &"Torso-low"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_SHOULDER", &"Shoulder"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_ARM", &"Arm"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_HAND", &"Hand"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_LEG", &"Leg"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_LEG_UPPEER", &"Leg-up"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_LEG_LOWER", &"Leg-low"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_FOOT", &"Foot"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_GRENADE", &"Grenade"); + + precacheString2("STRING_AUTO_SPECTATOR_HIT_SHOTGUN_1p", &"1 pellet"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_SHOTGUN_2p", &"2 pellets"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_SHOTGUN_3p", &"3 pellets"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_SHOTGUN_4p", &"4 pellets"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_SHOTGUN_5p", &"5 pellets"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_SHOTGUN_6p", &"6 pellets"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_SHOTGUN_7p", &"7 pellets"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_SHOTGUN_8p", &"8 pellets"); + + precacheString2("STRING_AUTO_SPECTATOR_HIT_INFO_SHOTGUN_1_KILL", &"Range 1 (1 pellet needed for kill"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_INFO_SHOTGUN_1_HIT", &"Range 1 (2 pellets needed for kill (body not visible)"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_INFO_SHOTGUN_2", &"Range 2 (2 pellets needed for kill"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_INFO_SHOTGUN_3", &"Range 3 (3 pellets needed for kill"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_INFO_SHOTGUN_4", &"Range 4 (linear damage)"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_INFO_TORSO_HITBOX_FIX", &"Torso hitbox fix applied"); + precacheString2("STRING_AUTO_SPECTATOR_HIT_INFO_HAND_HITBOX_FIX", &"Hand hitbox fix applied"); + + precacheShader("headicon_dead"); + } + + if (!level.spectatingSystem) + return; + + addEventListener("onPlayerKilled", ::onPlayerKilled); +} + + +/* +Called when player has taken damage. +self is the player that took damage. +*/ +onPlayerDamaged(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime) +{ + waittillframeend; // wait untill all hits are processed + + if (isDefined(eAttacker) && isPlayer(eAttacker) && self != eAttacker) + { + // Damage info can be showed in 2 modes: + // - in readyup for regular players + // - for auto-spectators - show info for spectated player + if (level.in_readyup || + (level.spectatingSystem && !level.in_readyup && isDefined(level.autoSpectating_spectatedPlayer) && eAttacker == level.autoSpectating_spectatedPlayer)) + { + self_num = self getEntityNumber(); + isShotgun = sWeapon == "shotgun_mp" && sMeansOfDeath == "MOD_PISTOL_BULLET"; + + pellets = 0; + if (isShotgun) + pellets = eAttacker.hitData[self_num].id; + + adjustedBy = eAttacker.hitData[self_num].adjustedBy; + + // In readyup for regular players + if (level.in_readyup) + { + // For shotgun show accumulated damage + if (isShotgun) damage = eAttacker.hitData[self_num].damage_comulated; + else damage = eAttacker.hitData[self_num].damage; + + eAttacker thread showDamageInfoReadyup(damage, sHitLoc, sMeansOfDeath, pellets, adjustedBy); + } + else // For auto-spactators + { + damage = eAttacker.hitData[self_num].damage_comulated; + + // Show to all spectators + players = getentarray("player", "classname"); + for(i = 0; i < players.size; i++) + { + player = players[i]; + if (player.pers["team"] == "spectator" && player.pers["autoSpectating"] && !isDefined(player.killcam)) + { + player thread showDamageInfo(damage, sHitLoc, sMeansOfDeath, pellets, adjustedBy); + } + } + } + } + } + + if (!level.spectatingSystem) + return; + + if (isDefined(level.autoSpectating_spectatedPlayer) && self == level.autoSpectating_spectatedPlayer && !level.in_readyup) + { + damage = iDamage; + if (isDefined(eAttacker) && isPlayer(eAttacker)) + { + self_num = self getEntityNumber(); + damage = eAttacker.hitData[self_num].damage_comulated; + } + + // Show to all spectators + players = getentarray("player", "classname"); + for(i = 0; i < players.size; i++) + { + player = players[i]; + if (player.pers["team"] == "spectator" && player.pers["autoSpectating"] && !isDefined(player.killcam)) + { + player thread showTakenDamageInfo(damage, sHitLoc, sMeansOfDeath); + } + } + } +} + +/* +Called when player is killed +self is the player that was killed. +*/ +onPlayerKilled(eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration) +{ + if (isDefined(eAttacker) && isPlayer(eAttacker) && self != eAttacker && isDefined(level.autoSpectating_spectatedPlayer) && eAttacker == level.autoSpectating_spectatedPlayer && !level.in_readyup) + { + // Show to all spectators + players = getentarray("player", "classname"); + for(i = 0; i < players.size; i++) + { + player = players[i]; + if (player.pers["team"] == "spectator" && player.pers["autoSpectating"]) + { + player thread showKillInfo(); + } + } + } +} + +showDamageInfo(damage, sHitLoc, sMeansOfDeath, pellets, adjustedBy) +{ + hitLocTexts["head"] = game["STRING_AUTO_SPECTATOR_HIT_HEAD"]; + hitLocTexts["neck"] = game["STRING_AUTO_SPECTATOR_HIT_NECK"]; + hitLocTexts["torso_upper"] = game["STRING_AUTO_SPECTATOR_HIT_BODY"]; + hitLocTexts["torso_lower"] = game["STRING_AUTO_SPECTATOR_HIT_BODY"]; + hitLocTexts["left_arm_upper"] = game["STRING_AUTO_SPECTATOR_HIT_SHOULDER"]; + hitLocTexts["left_arm_lower"] = game["STRING_AUTO_SPECTATOR_HIT_ARM"]; + hitLocTexts["left_hand"] = game["STRING_AUTO_SPECTATOR_HIT_HAND"]; + hitLocTexts["right_arm_upper"] = game["STRING_AUTO_SPECTATOR_HIT_SHOULDER"]; + hitLocTexts["right_arm_lower"] = game["STRING_AUTO_SPECTATOR_HIT_ARM"]; + hitLocTexts["right_hand"] = game["STRING_AUTO_SPECTATOR_HIT_HAND"]; + hitLocTexts["left_leg_upper"] = game["STRING_AUTO_SPECTATOR_HIT_LEG"]; + hitLocTexts["left_leg_lower"] = game["STRING_AUTO_SPECTATOR_HIT_LEG"]; + hitLocTexts["right_leg_upper"] = game["STRING_AUTO_SPECTATOR_HIT_LEG"]; + hitLocTexts["right_leg_lower"] = game["STRING_AUTO_SPECTATOR_HIT_LEG"]; + hitLocTexts["left_foot"] = game["STRING_AUTO_SPECTATOR_HIT_FOOT"]; + hitLocTexts["right_foot"] = game["STRING_AUTO_SPECTATOR_HIT_FOOT"]; + + + self endon("disconnect"); + + if (isDefined(self.killcam)) + return; + + self notify("autoSpectating_showDamageInfo_end"); + self endon("autoSpectating_showDamageInfo_end"); + + if (!isDefined(self.hud_damageinfo)) + { + self.hud_damageinfo = newClientHudElem2(self); + self.hud_damageinfo.horzAlign = "center"; + self.hud_damageinfo.vertAlign = "middle"; + self.hud_damageinfo.alignX = "right"; + self.hud_damageinfo.label = game["STRING_AUTO_SPECTATOR_HIT_HP"]; + self.hud_damageinfo.x = -10; + self.hud_damageinfo.fontscale = 1.1; + self.hud_damageinfo.archived = false; + } + + if (!isDefined(self.hud_damageinfo_loc)) + { + self.hud_damageinfo_loc = newClientHudElem2(self); + self.hud_damageinfo_loc.horzAlign = "center"; + self.hud_damageinfo_loc.vertAlign = "middle"; + self.hud_damageinfo_loc.alignX = "left"; + self.hud_damageinfo_loc.x = 2; + self.hud_damageinfo_loc.fontscale = 1.1; + self.hud_damageinfo_loc.archived = false; + } + + if (damage > 100) + damage = 100; + + self.hud_damageinfo setValue(damage); + + if (sMeansOfDeath == "MOD_GRENADE_SPLASH") + self.hud_damageinfo_loc setText(game["STRING_AUTO_SPECTATOR_HIT_GRENADE"]); + else if (pellets >= 1 && pellets <= 8) // shotgun + self.hud_damageinfo_loc setText(game["STRING_AUTO_SPECTATOR_HIT_SHOTGUN_" + pellets + "p"]); + else if (isDefined(hitLocTexts[sHitLoc])) + self.hud_damageinfo_loc setText(hitLocTexts[sHitLoc]); + + r = 1; + g = 1 - ((damage - 50) / 50); if (g < 0) g = 0; if (g > 1) g = 1; + b = 1 - (damage / 50); if (b < 0) b = 0; if (b > 1) b = 1; + + // red to orange to yellow -> add green + // yellow to white -> add blue + + self.hud_damageinfo.color = (r, g, b); + self.hud_damageinfo_loc.color = (1, 1, 1); + + self.hud_damageinfo.y = 120; + self.hud_damageinfo.alpha = 1; + self.hud_damageinfo_loc.y = 120; + self.hud_damageinfo_loc.alpha = 1; + + self.hud_damageinfo moveovertime(3); + self.hud_damageinfo.y = 100; + self.hud_damageinfo_loc moveovertime(3); + self.hud_damageinfo_loc.y = 100; + + wait level.fps_multiplier * 1; + + self.hud_damageinfo FadeOverTime(2); + self.hud_damageinfo.alpha = 0; + self.hud_damageinfo_loc FadeOverTime(2); + self.hud_damageinfo_loc.alpha = 0; + + wait level.fps_multiplier * 2; + + self.hud_damageinfo destroy2(); + self.hud_damageinfo_loc destroy2(); +} + + + +showDamageInfoReadyup(damage, sHitLoc, sMeansOfDeath, pellets, adjustedBy) +{ + hitLocTexts["head"] = game["STRING_AUTO_SPECTATOR_HIT_HEAD"]; + hitLocTexts["neck"] = game["STRING_AUTO_SPECTATOR_HIT_NECK"]; + hitLocTexts["torso_upper"] = game["STRING_AUTO_SPECTATOR_HIT_BODY_UPPER"]; + hitLocTexts["torso_lower"] = game["STRING_AUTO_SPECTATOR_HIT_BODY_LOWER"]; + hitLocTexts["left_arm_upper"] = game["STRING_AUTO_SPECTATOR_HIT_SHOULDER"]; + hitLocTexts["left_arm_lower"] = game["STRING_AUTO_SPECTATOR_HIT_ARM"]; + hitLocTexts["left_hand"] = game["STRING_AUTO_SPECTATOR_HIT_HAND"]; + hitLocTexts["right_arm_upper"] = game["STRING_AUTO_SPECTATOR_HIT_SHOULDER"]; + hitLocTexts["right_arm_lower"] = game["STRING_AUTO_SPECTATOR_HIT_ARM"]; + hitLocTexts["right_hand"] = game["STRING_AUTO_SPECTATOR_HIT_HAND"]; + hitLocTexts["left_leg_upper"] = game["STRING_AUTO_SPECTATOR_HIT_LEG_UPPEER"]; + hitLocTexts["left_leg_lower"] = game["STRING_AUTO_SPECTATOR_HIT_LEG_LOWER"]; + hitLocTexts["right_leg_upper"] = game["STRING_AUTO_SPECTATOR_HIT_LEG_UPPEER"]; + hitLocTexts["right_leg_lower"] = game["STRING_AUTO_SPECTATOR_HIT_LEG_LOWER"]; + hitLocTexts["left_foot"] = game["STRING_AUTO_SPECTATOR_HIT_FOOT"]; + hitLocTexts["right_foot"] = game["STRING_AUTO_SPECTATOR_HIT_FOOT"]; + + adjuestedByTexts["consistent_shotgun_1_kill"] = game["STRING_AUTO_SPECTATOR_HIT_INFO_SHOTGUN_1_KILL"]; + adjuestedByTexts["consistent_shotgun_1_hit"] = game["STRING_AUTO_SPECTATOR_HIT_INFO_SHOTGUN_1_HIT"]; + adjuestedByTexts["consistent_shotgun_2"] = game["STRING_AUTO_SPECTATOR_HIT_INFO_SHOTGUN_2"]; + adjuestedByTexts["consistent_shotgun_3"] = game["STRING_AUTO_SPECTATOR_HIT_INFO_SHOTGUN_3"]; + adjuestedByTexts["consistent_shotgun_4"] = game["STRING_AUTO_SPECTATOR_HIT_INFO_SHOTGUN_4"]; + adjuestedByTexts["torso_hitbox_fix"] = game["STRING_AUTO_SPECTATOR_HIT_INFO_TORSO_HITBOX_FIX"]; + adjuestedByTexts["hand_hitbox_fix"] = game["STRING_AUTO_SPECTATOR_HIT_INFO_HAND_HITBOX_FIX"]; + + + self endon("disconnect"); + + if (isDefined(self.killcam)) + return; + + self notify("autoSpectating_showDamageInfo_end"); + self endon("autoSpectating_showDamageInfo_end"); + + if (!isDefined(self.hud_damageinfo)) + { + self.hud_damageinfo = newClientHudElem2(self); + self.hud_damageinfo.horzAlign = "center"; + self.hud_damageinfo.vertAlign = "middle"; + self.hud_damageinfo.alignX = "left"; + self.hud_damageinfo.label = game["STRING_AUTO_SPECTATOR_HIT_HP"]; + self.hud_damageinfo.x = -40; + self.hud_damageinfo.fontscale = 1.1; + self.hud_damageinfo.archived = false; + } + + if (!isDefined(self.hud_damageinfo_loc)) + { + self.hud_damageinfo_loc = newClientHudElem2(self); + self.hud_damageinfo_loc.horzAlign = "center"; + self.hud_damageinfo_loc.vertAlign = "middle"; + self.hud_damageinfo_loc.alignX = "right"; + self.hud_damageinfo_loc.x = 40; + self.hud_damageinfo_loc.fontscale = 1.1; + self.hud_damageinfo_loc.archived = false; + } + + if (!isDefined(self.hud_damageinfo_adjustedBy)) + { + self.hud_damageinfo_adjustedBy = newClientHudElem2(self); + self.hud_damageinfo_adjustedBy.horzAlign = "center"; + self.hud_damageinfo_adjustedBy.vertAlign = "middle"; + self.hud_damageinfo_adjustedBy.alignX = "center"; + self.hud_damageinfo_adjustedBy.x = 0; + self.hud_damageinfo_adjustedBy.fontscale = 0.7; + self.hud_damageinfo_adjustedBy.archived = false; + } + + self.hud_damageinfo setValue(damage); + + if (sMeansOfDeath == "MOD_GRENADE_SPLASH") + self.hud_damageinfo_loc setText(game["STRING_AUTO_SPECTATOR_HIT_GRENADE"]); + else if (pellets >= 1 && pellets <= 8) // shotgun + self.hud_damageinfo_loc setText(game["STRING_AUTO_SPECTATOR_HIT_SHOTGUN_" + pellets + "p"]); + else if (isDefined(hitLocTexts[sHitLoc])) + self.hud_damageinfo_loc setText(hitLocTexts[sHitLoc]); + + if (isDefined(adjuestedByTexts[adjustedBy])) + { + self.hud_damageinfo_adjustedBy setText(adjuestedByTexts[adjustedBy]); + self.hud_damageinfo_adjustedBy.alpha = 1; + } + else + self.hud_damageinfo_adjustedBy.alpha = 0; + + r = 1; + g = 1 - ((damage - 50) / 50); if (g < 0) g = 0; if (g > 1) g = 1; + b = 1 - (damage / 50); if (b < 0) b = 0; if (b > 1) b = 1; + + // red to orange to yellow -> add green + // yellow to white -> add blue + + self.hud_damageinfo.color = (r, g, b); + self.hud_damageinfo_loc.color = (1, 1, 1); + self.hud_damageinfo_adjustedBy.color = (1, 1, 1); + + self.hud_damageinfo.y = 120; + self.hud_damageinfo.alpha = 1; + self.hud_damageinfo_loc.y = 120; + self.hud_damageinfo_loc.alpha = 1; + self.hud_damageinfo_adjustedBy.y = 110; + //self.hud_damageinfo_adjustedBy.alpha = 1; + + wait level.fps_multiplier * 3; + + self.hud_damageinfo FadeOverTime(1); + self.hud_damageinfo.alpha = 0; + self.hud_damageinfo_loc FadeOverTime(1); + self.hud_damageinfo_loc.alpha = 0; + self.hud_damageinfo_adjustedBy FadeOverTime(1); + self.hud_damageinfo_adjustedBy.alpha = 0; + + wait level.fps_multiplier * 1; + + self.hud_damageinfo destroy2(); + self.hud_damageinfo_loc destroy2(); + self.hud_damageinfo_adjustedBy destroy2(); +} + + + +showTakenDamageInfo(iDamage, sHitLoc, sMeansOfDeath) +{ + hitLocTexts["head"] = game["STRING_AUTO_SPECTATOR_HIT_HEAD"]; + hitLocTexts["neck"] = game["STRING_AUTO_SPECTATOR_HIT_NECK"]; + hitLocTexts["torso_upper"] = game["STRING_AUTO_SPECTATOR_HIT_BODY"]; + hitLocTexts["torso_lower"] = game["STRING_AUTO_SPECTATOR_HIT_BODY"]; + hitLocTexts["left_arm_upper"] = game["STRING_AUTO_SPECTATOR_HIT_SHOULDER"]; + hitLocTexts["left_arm_lower"] = game["STRING_AUTO_SPECTATOR_HIT_ARM"]; + hitLocTexts["left_hand"] = game["STRING_AUTO_SPECTATOR_HIT_HAND"]; + hitLocTexts["right_arm_upper"] = game["STRING_AUTO_SPECTATOR_HIT_SHOULDER"]; + hitLocTexts["right_arm_lower"] = game["STRING_AUTO_SPECTATOR_HIT_ARM"]; + hitLocTexts["right_hand"] = game["STRING_AUTO_SPECTATOR_HIT_HAND"]; + hitLocTexts["left_leg_upper"] = game["STRING_AUTO_SPECTATOR_HIT_LEG"]; + hitLocTexts["left_leg_lower"] = game["STRING_AUTO_SPECTATOR_HIT_LEG"]; + hitLocTexts["left_foot"] = game["STRING_AUTO_SPECTATOR_HIT_FOOT"]; + hitLocTexts["right_leg_upper"] = game["STRING_AUTO_SPECTATOR_HIT_LEG"]; + hitLocTexts["right_leg_lower"] = game["STRING_AUTO_SPECTATOR_HIT_LEG"]; + hitLocTexts["right_foot"] = game["STRING_AUTO_SPECTATOR_HIT_FOOT"]; + + self endon("disconnect"); + + if (isDefined(self.killcam)) + return; + + self notify("autoSpectating_showTakenDamageInfo_end"); + self endon("autoSpectating_showTakenDamageInfo_end"); + + if (!isDefined(self.hud_takendamageinfo)) + { + self.hud_takendamageinfo = newClientHudElem2(self); + self.hud_takendamageinfo.horzAlign = "center"; + self.hud_takendamageinfo.vertAlign = "middle"; + self.hud_takendamageinfo.alignX = "right"; + self.hud_takendamageinfo.label = game["STRING_AUTO_SPECTATOR_HIT_HP"]; + self.hud_takendamageinfo.x = -10; + self.hud_takendamageinfo.fontscale = 1.1; + self.hud_takendamageinfo.archived = false; + } + + if (!isDefined(self.hud_takendamageinfo_loc)) + { + self.hud_takendamageinfo_loc = newClientHudElem2(self); + self.hud_takendamageinfo_loc.horzAlign = "center"; + self.hud_takendamageinfo_loc.vertAlign = "middle"; + self.hud_takendamageinfo_loc.alignX = "left"; + self.hud_takendamageinfo_loc.x = 2; + self.hud_takendamageinfo_loc.fontscale = 1.1; + self.hud_takendamageinfo_loc.archived = false; + } + + if (iDamage > 100) + iDamage = 100; + + self.hud_takendamageinfo setValue(iDamage*-1); + + if (sMeansOfDeath == "MOD_GRENADE_SPLASH") + self.hud_takendamageinfo_loc setText(game["STRING_AUTO_SPECTATOR_HIT_GRENADE"]); + else if (isDefined(hitLocTexts[sHitLoc])) + self.hud_takendamageinfo_loc setText(hitLocTexts[sHitLoc]); + + r = 1; + g = 1 - ((iDamage - 50) / 50); if (g < 0) g = 0; if (g > 1) g = 1; + b = 1 - (iDamage / 50); if (b < 0) b = 0; if (b > 1) b = 1; + + // red to orange to yellow -> add green + // yellow to white -> add blue + + self.hud_takendamageinfo.color = (r, g, b); + self.hud_takendamageinfo_loc.color = (1, 1, 1); + + self.hud_takendamageinfo.y = 120; + self.hud_takendamageinfo.alpha = 1; + self.hud_takendamageinfo_loc.y = 120; + self.hud_takendamageinfo_loc.alpha = 1; + + self.hud_takendamageinfo moveovertime(3); + self.hud_takendamageinfo.y = 140; + self.hud_takendamageinfo_loc moveovertime(3); + self.hud_takendamageinfo_loc.y = 140; + + wait level.fps_multiplier * 1; + + self.hud_takendamageinfo FadeOverTime(2); + self.hud_takendamageinfo.alpha = 0; + self.hud_takendamageinfo_loc FadeOverTime(2); + self.hud_takendamageinfo_loc.alpha = 0; + + wait level.fps_multiplier * 2; + + self.hud_takendamageinfo destroy2(); + self.hud_takendamageinfo_loc destroy2(); +} + + + + + +showKillInfo() +{ + self endon("disconnect"); + + if (isDefined(self.killcam)) + return; + + self notify("autoSpectating_showKillInfo_end"); + self endon("autoSpectating_showKillInfo_end"); + + if (!isDefined(self.hud_damageinfo_kill)) + { + self.hud_damageinfo_kill = newClientHudElem2(self); + self.hud_damageinfo_kill.horzAlign = "center"; + self.hud_damageinfo_kill.vertAlign = "middle"; + self.hud_damageinfo_kill.x = -65; + self.hud_damageinfo_kill.archived = false; + self.hud_damageinfo_kill setShader("headicon_dead", 23, 23); + } + + self.hud_damageinfo_kill.y = 120 - 2; + self.hud_damageinfo_kill.alpha = 1; + self.hud_damageinfo_kill moveovertime(3); + self.hud_damageinfo_kill.y = 100 - 2; + + wait level.fps_multiplier * 1; + + self.hud_damageinfo_kill FadeOverTime(2); + self.hud_damageinfo_kill.alpha = 0; + + wait level.fps_multiplier * 2; + + self.hud_damageinfo_kill destroy2(); +} diff --git a/source/maps/mp/gametypes/_spectating_hud_esp.gsc b/source/maps/mp/gametypes/_spectating_hud_esp.gsc new file mode 100644 index 0000000..3eb3075 --- /dev/null +++ b/source/maps/mp/gametypes/_spectating_hud_esp.gsc @@ -0,0 +1,424 @@ +#include maps\mp\gametypes\global\_global; + +init() +{ + if (!level.spectatingSystem) + return; + + if(game["firstInit"]) + { + precacheShader("stance_stand_front"); + precacheShader("stance_stand_back"); + precacheShader("stance_stand_left"); + precacheShader("stance_stand_right"); + precacheShader("stance_crouch_front"); + precacheShader("stance_crouch_back"); + precacheShader("stance_crouch_left"); + precacheShader("stance_crouch_right"); + precacheShader("stance_prone_front"); + precacheShader("stance_prone_back"); + precacheShader("stance_prone_left"); + precacheShader("stance_prone_right"); + } + + addEventListener("onConnected", ::onConnected); +} + +onConnected() +{ + if (!isDefined(self.pers["autoSpectatingESP"])) + self.pers["autoSpectatingESP"] = true; +} + + + +ESP_Destroy() +{ + // Destroy all + for(i = 0; i < self.spec_ESP_names.size; i++) + { + // If HUD is not defined, it means player disconnect and HUD object was deleted + if (isDefined(self.spec_ESP_names[i])) + self.spec_ESP_names[i] destroy2(); + if (isDefined(self.spec_ESP_images[i])) + self.spec_ESP_images[i] destroy2(); + } + self.spec_ESP_names = undefined; + self.spec_ESP_images = undefined; + + if (level.debug_spectator) self iprintln("autospec> ESP HUD destroyed ^1ALL"); +} + +/* +self is spectater +*/ +ESP_Loop() +{ + self endon("disconnect"); + + if (isDefined(self.spec_ESP_names)) + self ESP_Destroy(); + self.spec_ESP_names = []; + self.spec_ESP_images = []; + + self thread FollowCloseByPlayer(); + + spectator = self; + i_ESP = 0; + + for(;;) + { + // Clear unused HUD elements + for (i = self.spec_ESP_names.size - 1; i >= i_ESP; i--) + { + // If HUD is not defined, it means player disconnect and HUD object was deleted + if (isDefined(self.spec_ESP_names[i])) + self.spec_ESP_names[i] destroy2(); + if (isDefined(self.spec_ESP_images[i])) + self.spec_ESP_images[i] destroy2(); + + self.spec_ESP_names[i] = undefined; + self.spec_ESP_images[i] = undefined; + + if (level.debug_spectator) self iprintln("autospec> ESP HUD destroyed index " + i); + } + + wait level.frame; + + i_ESP = 0; + + // Player disconnects + if (!isDefined(self)) + break; + // Variables destroyed (not likely) + if (!isDefined(self.spec_ESP_names) || !isDefined(self.spec_ESP_images)) + break; + // All needs to be removed (changed team ) + if (self.pers["team"] != "spectator") + break; + // Hide hud in Readyup or bash + if (level.in_readyup || level.in_bash) + continue; + // Dont show ESP if killcam or its turned off + if (isDefined(spectator.killcam) || !spectator.pers["autoSpectatingESP"]) + continue; + + // Get spectated player + autospectated_player = undefined; + if (spectator.pers["autoSpectating"] && isDefined(level.autoSpectating_spectatedPlayer)) + autospectated_player = level.autoSpectating_spectatedPlayer; + + // Spectating player but not via auto-spectator + if (!isDefined(autospectated_player) && !spectator.freeSpectating) + continue; + + + // Find players that will be showed via ESP + players = getentarray("player", "classname"); + for(i = 0; i < players.size; i++) + { + player = players[i]; + if (player == spectator || !(player.pers["team"] == "allies" || player.pers["team"] == "axis")) + continue; + if (player.sessionstate != "playing" && player.sessionstate != "dead") + continue; + + // Skip spectated player + if (isDefined(autospectated_player) && player == autospectated_player) + continue; + + // When auto-spectating (not flying) and followed player died, hide all (because game does not provide correct angles in this session state) + if (isDefined(autospectated_player) && autospectated_player.sessionstate != "playing") + continue; + + // When auto-spectating show only enemy (except for DM where show all players) + // When free-flying show all players + if (isDefined(autospectated_player) && autospectated_player.sessionteam == player.sessionteam && player.sessionteam != "none") + continue; + + + // Create new HUD element + isNew = false; + if (!isDefined(self.spec_ESP_names[i_ESP])) + { + self.spec_ESP_names[i_ESP] = addHUDClient(self, 10, 10, 1.2, (1,1,1), "center", "bottom", "subleft", "subtop"); + self.spec_ESP_names[i_ESP].name = "name"; + self.spec_ESP_names[i_ESP].fontscale = 0.8; + self.spec_ESP_names[i_ESP].archived = false; + + self.spec_ESP_images[i_ESP] = addHUDClient(self, 10, 10, 1.2, (1,1,1), "center", "bottom", "subleft", "subtop"); + self.spec_ESP_images[i_ESP].name = "layout"; + self.spec_ESP_images[i_ESP].archived = false; + self.spec_ESP_images[i_ESP].sort = -1; + + isNew = true; + + if (level.debug_spectator) self iprintln("autospec> ESP HUD added NEW index " + i_ESP); + } + + // Update HUD + if (isNew || self.spec_ESP_names[i_ESP].player != player) + { + self.spec_ESP_names[i_ESP].player = player; + self.spec_ESP_names[i_ESP].offset = (0, 0, 25); + self.spec_ESP_names[i_ESP].tag = "head"; + self.spec_ESP_names[i_ESP] SetPlayerNameString(player); + self.spec_ESP_names[i_ESP] thread SetPlayerWaypoint(self, player); + self.spec_ESP_names[i_ESP] thread hud_waypoint_animate(self, player); + + self.spec_ESP_images[i_ESP].player = player; + self.spec_ESP_images[i_ESP].offset = (0, 0, -15); + self.spec_ESP_images[i_ESP] thread SetPlayerWaypoint(self, player); + self.spec_ESP_images[i_ESP] thread hud_waypoint_animate(self, player); + } + + i_ESP++; + } + } + + // Destroy HUD (unles player disconnects) + if (isDefined(self)) + self ESP_Destroy(); +} + + +/* +When free-flying check for close-by player according to ESP names +*/ +FollowCloseByPlayer() +{ + self endon("disconnect"); + + self.spec_follow_text = addHUDClient(self, 0, 50, 1.2, (1,1,1), "center", "top", "center", "top"); + self.spec_follow_text.alpha = 0; + + saved_player_last = undefined; + + for(;;) + { + wait level.frame; + + // All needs to be removed (changed team or timeout is called) + if (!isDefined(self) || self.pers["team"] != "spectator" || level.in_readyup) + break; + + if (!self.freeSpectating) + continue; + + saved_dist2D = 0; + saved_dist3D = 0; + saved_player = undefined; + + for(i = 0; i < self.spec_ESP_names.size; i++) + { + hud = self.spec_ESP_names[i]; + + // If HUD is not defined, it means player disconnect and HUD object was deleted + if (!isDefined(hud) || !isDefined(hud.player) || !isAlive(hud.player)) + continue; + + // Find out looking at player to follow on click + dist3D = distance(self.origin, hud.player.origin); + + // If text is somewhere in rectangle around center + if ((hud.x > 160 && hud.x < 480 && hud.y > 120 && hud.y < 360) || (dist3D < 300 && hud.x > 160 && hud.x < 480)) + { + if (dist3D < 1000) + { + dist2D = distance((hud.x, hud.y, 0), (320, 240, 0)); // Distance of text from center - text is in 640x480 rectangle aligned left top + + if (!isDefined(saved_player) || (dist2D < saved_dist2D && dist3D < saved_dist3D)) + { + saved_dist2D = dist2D; + saved_dist3D = dist3D; + saved_player = hud.player; + } + } + } + } + + time = 0.1; + + if (isDefined(saved_player)) + { + if (isDefined(saved_player_last) && saved_player_last != saved_player) + { + self.spec_follow_text fadeOverTime(time); + self.spec_follow_text.alpha = 0; + wait level.fps_multiplier * time; + if (!isDefined(self)) break; // in case player disconnects + } + if (!isDefined(saved_player_last) || saved_player_last != saved_player) + { + self.spec_follow_text SetPlayerNameString(saved_player); + self.spec_follow_text fadeOverTime(time); + self.spec_follow_text.alpha = 1; + wait level.fps_multiplier * time; + if (!isDefined(self)) break; // in case player disconnects + } + } + else if (isDefined(saved_player_last)) + { + self.spec_follow_text fadeOverTime(time); + self.spec_follow_text.alpha = 0; + wait level.fps_multiplier * time; + if (!isDefined(self)) break; // in case player disconnects + } + + saved_player_last = saved_player; + + self.spec_follow = saved_player; + } + + self.spec_follow_text destroy2(); +} + + + + +// self is HUD, spectator is hud owner and player is waypoined player +hud_waypoint_animate(spectator, player) +{ + // Make sure only 1 thread is running on this HUD element + self notify("hud_waypoint_animate"); + self endon("hud_waypoint_animate"); + + alpha_old = 0; + alpha_cnt = 0; + alpha_last = 0; + self.alpha = 0; + + for (;;) + { + wait level.frame; + + if (!isDefined(self) || !isDefined(spectator) || !isDefined(player)) + break; + + // Get spectated player + spectated_player = spectator; + if (!isDefined(spectator.killcam) && spectator.pers["autoSpectating"] && isDefined(level.autoSpectating_spectatedPlayer)) + spectated_player = level.autoSpectating_spectatedPlayer; + + + alpha = 0.0; + if (isAlive(player)) + { + // Player is far way + dist = distance(spectated_player.origin, player.origin); + + if (self.name == "name") + { + // Hide name if player is too far + if (dist < 1500 || spectator.freeSpectating) + alpha = 1; + } + + if (self.name == "layout") + { + // Hide player icon when player is visible + if (!spectated_player isPlayerInSight(player)) + alpha = 0.25; + } + + // Hide if mouse is over + if (!spectator.freeSpectating) + { + // If is in center, add alpha + dist2D = distance((self.x, self.y, 0), (320, 240, 0)); // Distance of text from center - text is in 640x480 rectangle aligned left top + if (dist2D <= 25) + alpha = 0.0; + else if (dist2D > 25 && dist2D <= 150) + alpha = alpha * ((dist2D-25) / 125); + } + } + + // Alpha smooth animation + if (alpha_last != alpha) + { + alpha_old = self.alpha; + alpha_cnt = 10; + alpha_last = alpha; + } + if (alpha_cnt > 0) + { + self.alpha = alpha_old + ((alpha - alpha_old) / 10) * (10-alpha_cnt); + alpha_cnt--; + } + else + self.alpha = alpha; + + + // Item is not visible, no need to continue animation + if (self.alpha == 0) + continue; + + + if (self.name == "name") + { + color = (0.8, 0.8, 0.8); + if (player.pers["team"] == "allies") + { + if(game["allies"] == "american") + color = (0.4, 0.9, .56); + else if(game["allies"] == "british") + color = (0.45, 0.73, 1); + else if(game["allies"] == "russian") + color = (1, 0.4, 0.4); + } + self.color = color; + } + + + if (self.name == "layout") + { + stance = player maps\mp\gametypes\global\player::getStance(); // prone crouch stand + + angles = player getPlayerAngles(); + + diff = (player.origin - spectated_player.origin); + diff = (diff[0], diff[1], 0); + diff = vectortoangles(diff); + + angle = (angles[1] - diff[1]); + + if (angle > 180) angle -= 360; + else if (angle < -180) angle += 360; + angle += 180; // flip direction, now in range 0 <-> 360 + if (angle > 180) angle -= 360; // back to range -180 <-> +180 + + + if ((angle > 135 && angle <= 180) || (angle < -135 && angle >= -180)) + self.shader = "stance_" + stance + "_back"; + else if (angle > 45 && angle < 135) + self.shader = "stance_" + stance + "_right"; + else if (angle < -45 && angle > -135) + self.shader = "stance_" + stance + "_left"; + else + self.shader = "stance_" + stance + "_front"; + + self.w = 25; + self.h = 25; + self.scale = 1400; + + color = (0.9, 0.9, 0.9); + if (player.pers["team"] == "allies") + { + if(game["allies"] == "american") + color = (0.7, 0.95, .8); + else if(game["allies"] == "british") + color = (0.73, 0.86, 1); + else if(game["allies"] == "russian") + color = (1, 0.7, 0.7); + } + if (player.health <= 0) + color = (1, 0, 0); // red + else if (player.health < 100) + { + dmg = (player.health / 100); + color = (color[0] + (1-color[0]) * (1-dmg), color[1] * dmg, color[2] * dmg); + } + self.color = color; + } + } +} diff --git a/source/maps/mp/gametypes/_spectating_killcam.gsc b/source/maps/mp/gametypes/_spectating_killcam.gsc index b5fa1fb..6206bab 100644 --- a/source/maps/mp/gametypes/_spectating_killcam.gsc +++ b/source/maps/mp/gametypes/_spectating_killcam.gsc @@ -191,6 +191,8 @@ potencialAutoKillcam(killId) potencialAutoKillcamForPlayer(killId) { + self endon("disconnect"); + // Wait untill this player does not see enemy no more - then we can replay killcam // If player kills another enemy, this record is deleted, this thread ends and new thread is created time_killer_no_enemy = 0; @@ -476,11 +478,44 @@ watchIntenseSituation() openSpectMenu() { - self endon("disconnect"); + //self endon("disconnect"); + + /* + Open QuickMessage menu trick + - this menu is usefull because it does not hide HUD elements as standart menu does + - but this menu is openable only via command /mp_qucikmessage in client side + - also to open this menu player must be alive player (wich spectator is not) + - trick is is move spectator into "none" team and set him as "dead", in wich case the /mp_qucikmessage works + - only problem is that this game is quite bugged and there are some side effect: + - if players in "allies" or "axis" team are all dead and they are in "spectator" state, + for some reason players with clientId lower then spectator clientId starts following this spectator + - because spectator is spawned outside map and then imidietly back to spectating mode, players + with lower clientId stays outside map + - we need to save current position of players with clientId lower then spectator clientId and + only if all players are dead in their team + */ + allies = 0; + axis = 0; + players = getentarray("player", "classname"); + for(i = 0; i < players.size; i++) + { // Count alive players in teams + if (players[i].sessionteam == "allies" && players[i].sessionstate != "spectator") allies++; + if (players[i].sessionteam == "axis" && players[i].sessionstate != "spectator") axis++; + } + for(i = 0; i < players.size; i++) + { // clientId is lower then spectator and not player are alive in team + if (players[i] GetEntityNumber() < self GetEntityNumber() && + ((allies == 0 && players[i].sessionteam == "allies") || (axis == 0 && players[i].sessionteam == "axis"))) + { + players[i].spectating_killcam_origin = players[i].origin; + players[i].spectating_killcam_angles = players[i].angles; + } + } spectatorclient = self.spectatorclient; origin = self getOrigin(); angles = self getPlayerAngles(); + self.sessionteam = "none"; self.sessionstate = "dead"; // enable quickmessage self.spectatorclient = -1; @@ -501,16 +536,38 @@ openSpectMenu() wait level.frame * 2; - self.sessionteam = "spectator"; - self.sessionstate = "spectator"; - if (self.spectatorclient == -1) - self.spectatorclient = spectatorclient; + // Spectator may disconnect + if (isDefined(self)) + { + self.sessionteam = "spectator"; + self.sessionstate = "spectator"; + if (self.spectatorclient == -1) + self.spectatorclient = spectatorclient; + + wait level.frame; + } - wait level.frame; + // Spawn to previous location + players = getentarray("player", "classname"); + for(i = 0; i < players.size; i++) + { + if (isDefined(players[i].spectating_killcam_origin)) + { + players[i] spawn(players[i].spectating_killcam_origin, players[i].spectating_killcam_angles); + players[i].spectating_killcam_origin = undefined; + players[i].spectating_killcam_angles = undefined; + //players[i] iprintln("^1 APPLIED SPECTATE BUG FIX"); + } + } - self spawn(origin, angles); + // Spawn to previous location + if (isDefined(self)) // Spectator may disconnect + self spawn(origin, angles); } + + + spectMenuSetRows() { self.autoSpectating_killIndexes = []; @@ -572,7 +629,7 @@ replayAction(killId, print) // Already in killcam, wait for end while(isDefined(self.killcam)) - wait level.fps_multiplier * 1; + wait level.frame; record = level.autoSpectating_kills[killId]; diff --git a/source/maps/mp/gametypes/_timeout.gsc b/source/maps/mp/gametypes/_timeout.gsc index 94289ec..5f87e24 100644 --- a/source/maps/mp/gametypes/_timeout.gsc +++ b/source/maps/mp/gametypes/_timeout.gsc @@ -34,8 +34,13 @@ init() game["do_timeout"] = false; // reset request flag } + // Run timeout + if (level.in_timeout) + { + level thread Start_Timeout_Mode(false); // runned_in_middle_of_game = false + } + // Register notifications catchup - addEventListener("onStartGameType", ::onStartGameType); addEventListener("onConnected", ::onConnected); addEventListener("onJoinedTeam", ::onJoinedTeam); addEventListener("onSpawned", ::onSpawned); @@ -56,18 +61,6 @@ onCvarChanged(cvar, value, isRegisterTime) return false; } -// Called after the .gsc::main() and .gsc::main() scripts are called -// At this point game specific variables are defined (like game["allies"], game["axis"], game["american_soldiertype"], ...) -// Called again for every round in round-based gameplay -onStartGameType() -{ - // Run timeout - if (level.in_timeout) - { - level thread Start_Timeout_Mode(false); // runned_in_middle_of_game = false - } -} - onConnected() { diff --git a/source/maps/mp/gametypes/_warnings.gsc b/source/maps/mp/gametypes/_warnings.gsc index a1830ac..2e3c326 100644 --- a/source/maps/mp/gametypes/_warnings.gsc +++ b/source/maps/mp/gametypes/_warnings.gsc @@ -69,7 +69,7 @@ update() errors = ""; /* // ZPAM_RENAME - errors += "^3This is preview version of PAM!^7\n"; + errors += "^3This is testing version of PAM, server may crash!^7\n"; errors += "^3Report feedback to eyza#7930^7\n"; */ if (getcvarint("sv_cheats")) @@ -84,7 +84,10 @@ update() map = level.mapname; if (map == "mp_toujane" || map == "mp_burgundy" || map == "mp_dawnville" || map == "mp_matmata" || map == "mp_carentan") { - errors += "^3This is old version of map, use fixed version^7\n"; + ver = "_v2"; + if (map == "mp_burgundy") ver = "_v1"; + + errors += "^3This is an old map, use " + map + "_fix" + ver + "^7\n"; } if (errors != "") diff --git a/source/maps/mp/gametypes/_weapon_limiter.gsc b/source/maps/mp/gametypes/_weapon_limiter.gsc index 17295a6..84f1d63 100644 --- a/source/maps/mp/gametypes/_weapon_limiter.gsc +++ b/source/maps/mp/gametypes/_weapon_limiter.gsc @@ -236,7 +236,7 @@ isWeaponAvaible(response) isWeaponDropable(weaponname) { - if (maps\mp\gametypes\_weapons::isPistol(weaponname)) + if (maps\mp\gametypes\_weapons::isPistol(weaponname) && getCvarInt("scr_pistol_allow_drop") == 1) return true; if (isDefined(level.weapons[weaponname]) && level.weaponclass[level.weapons[weaponname].classname].allow_drop) @@ -256,7 +256,12 @@ isWeaponPickable(weaponname) { classname = level.weapons[weaponname].classname; if (!level.weaponclass[classname].allow_drop) - return false; + return false; + } + else if (maps\mp\gametypes\_weapons::isPistol(weaponname)) + { + if (getCvarInt("scr_pistol_allow_drop") == 0) + return false; } return true; diff --git a/source/maps/mp/gametypes/_weapons.gsc b/source/maps/mp/gametypes/_weapons.gsc index d259687..c8afcce 100644 --- a/source/maps/mp/gametypes/_weapons.gsc +++ b/source/maps/mp/gametypes/_weapons.gsc @@ -47,7 +47,7 @@ registerCvars() [[var]]("scr_smg_allow_drop", "BOOL", 1); [[var]]("scr_mg_allow_drop", "BOOL", 1); [[var]]("scr_shotgun_allow_drop", "BOOL", 1); - + [[var]]("scr_pistol_allow_drop", "BOOL", 1); // Allow/Disallow Weapons @@ -151,6 +151,9 @@ onCvarChanged(cvar, value, isRegisterTime) if (!isRegisterTime) thread updateDrop(cvar, value); return true; + case "scr_pistol_allow_drop": + return true; + // If some wepaons was enabled/disabled @@ -394,41 +397,41 @@ defineWeapons() switch(game["allies"]) { case "american": - addWeapon("greasegun_mp", "smg", "allies", "scr_allow_greasegun", "ui_allow_greasegun"); + addWeapon("greasegun_mp", "smg", "allies", "scr_allow_greasegun", "ui_allow_greasegun"); addWeapon("m1carbine_mp", "semiautomatic", "allies", "scr_allow_m1carbine", "ui_allow_m1carbine"); addWeapon("m1garand_mp", "semiautomatic", "allies", "scr_allow_m1garand", "ui_allow_m1garand"); - addWeapon("springfield_mp", "sniper", "allies", "scr_allow_springfield", "ui_allow_springfield"); - addWeapon("thompson_mp", "smg", "allies", "scr_allow_thompson", "ui_allow_thompson"); - addWeapon("bar_mp", "mg", "allies", "scr_allow_bar", "ui_allow_bar"); + addWeapon("springfield_mp", "sniper", "allies", "scr_allow_springfield", "ui_allow_springfield"); + addWeapon("thompson_mp", "smg", "allies", "scr_allow_thompson", "ui_allow_thompson"); + addWeapon("bar_mp", "mg", "allies", "scr_allow_bar", "ui_allow_bar"); break; case "british": - addWeapon("sten_mp", "smg", "allies", "scr_allow_sten", "ui_allow_sten"); + addWeapon("sten_mp", "smg", "allies", "scr_allow_sten", "ui_allow_sten"); addWeapon("enfield_mp", "boltaction", "allies", "scr_allow_enfield", "ui_allow_enfield"); addWeapon("m1garand_mp", "semiautomatic", "allies", "scr_allow_m1garand", "ui_allow_m1garand"); - addWeapon("enfield_scope_mp", "sniper", "allies", "scr_allow_enfieldsniper", "ui_allow_enfieldsniper"); - addWeapon("thompson_mp", "smg", "allies", "scr_allow_thompson", "ui_allow_thompson"); - addWeapon("bren_mp", "mg", "allies", "scr_allow_bren", "ui_allow_bren"); + addWeapon("enfield_scope_mp", "sniper", "allies", "scr_allow_enfieldsniper", "ui_allow_enfieldsniper"); + addWeapon("thompson_mp", "smg", "allies", "scr_allow_thompson", "ui_allow_thompson"); + addWeapon("bren_mp", "mg", "allies", "scr_allow_bren", "ui_allow_bren"); break; case "russian": - addWeapon("PPS42_mp", "smg", "allies", "scr_allow_pps42", "ui_allow_pps42"); - addWeapon("mosin_nagant_mp", "boltaction", "allies", "scr_allow_nagant", "ui_allow_nagant"); - addWeapon("SVT40_mp", "semiautomatic", "allies", "scr_allow_svt40", "ui_allow_svt40"); - addWeapon("mosin_nagant_sniper_mp", "sniper", "allies", "scr_allow_nagantsniper", "ui_allow_nagantsniper"); - addWeapon("ppsh_mp", "smg", "allies", "scr_allow_ppsh", "ui_allow_ppsh"); + addWeapon("PPS42_mp", "smg", "allies", "scr_allow_pps42", "ui_allow_pps42"); + addWeapon("mosin_nagant_mp", "boltaction", "allies", "scr_allow_nagant", "ui_allow_nagant"); + addWeapon("SVT40_mp", "semiautomatic", "allies", "scr_allow_svt40", "ui_allow_svt40"); + addWeapon("mosin_nagant_sniper_mp", "sniper", "allies", "scr_allow_nagantsniper", "ui_allow_nagantsniper"); + addWeapon("ppsh_mp", "smg", "allies", "scr_allow_ppsh", "ui_allow_ppsh"); break; } // Germans - addWeapon("mp40_mp", "smg", "axis", "scr_allow_mp40", "ui_allow_mp40"); + addWeapon("mp40_mp", "smg", "axis", "scr_allow_mp40", "ui_allow_mp40"); addWeapon("kar98k_mp", "boltaction", "axis", "scr_allow_kar98k", "ui_allow_kar98k"); - addWeapon("g43_mp", "semiautomatic", "axis", "scr_allow_g43", "ui_allow_g43"); - addWeapon("kar98k_sniper_mp", "sniper", "axis", "scr_allow_kar98ksniper", "ui_allow_kar98ksniper"); - addWeapon("mp44_mp", "mg", "axis", "scr_allow_mp44", "ui_allow_mp44"); + addWeapon("g43_mp", "semiautomatic", "axis", "scr_allow_g43", "ui_allow_g43"); + addWeapon("kar98k_sniper_mp", "sniper", "axis", "scr_allow_kar98ksniper", "ui_allow_kar98ksniper"); + addWeapon("mp44_mp", "mg", "axis", "scr_allow_mp44", "ui_allow_mp44"); // All teams - addWeapon("shotgun_mp", "shotgun", "both", "scr_allow_shotgun", "ui_allow_shotgun"); + addWeapon("shotgun_mp", "shotgun", "both", "scr_allow_shotgun", "ui_allow_shotgun"); // Array of Available Weapon Classes @@ -686,6 +689,11 @@ dropWeapon() if (getCvarInt(level.weaponclass[weapon_class].cvarAllowDrop) == 0) return; } + else if (isPistol(current)) + { + if (getCvarInt("scr_pistol_allow_drop") == 0) + return; + } if(clipsize || reservesize) { self dropItem(current); diff --git a/source/maps/mp/gametypes/dm.gsc b/source/maps/mp/gametypes/dm.gsc index 589e7bc..5fe7d52 100644 --- a/source/maps/mp/gametypes/dm.gsc +++ b/source/maps/mp/gametypes/dm.gsc @@ -243,19 +243,21 @@ onConnected() // Other like self.ownvariable will be undefined after scriped map restart // Except a few special vars, like self.sessionteam, their are defined after map restart, but with default value - // If is players first connect, his team is undefined (in SD is PlayerConnected called every round) - if (isDefined(self.pers["team"]) && self.pers["team"] != "spectator") - { - // Show player in spectator team - self.sessionteam = "none"; - } - else + if (!isDefined(self.pers["team"])) { self.pers["team"] = "spectator"; self.sessionteam = "spectator"; + // Print " Connected" to all iprintln(&"MP_CONNECTED", self.name); } + else + { + if (self.pers["team"] == "allies" || self.pers["team"] == "axis") + self.sessionteam = "none"; + else + self.sessionteam = "spectator"; + } // Define default variables specific for this gametype @@ -277,7 +279,7 @@ onAfterConnected() spawnIntermission(); // If player is just connected and blackout needs to be activated - else if (self.pers["team"] == "none") + else if (!isDefined(self.pers["firstTeamSelected"])) { if (self maps\mp\gametypes\_blackout::isBlackoutNeeded()) self maps\mp\gametypes\_blackout::spawnBlackout(); @@ -948,7 +950,7 @@ menuAxis() menuSpectator() { - if(self.pers["team"] == "spectator") + if(self.pers["team"] == "spectator" && isDefined(self.pers["firstTeamSelected"])) return; self.joining_team = "spectator"; diff --git a/source/maps/mp/gametypes/global/_global.gsc b/source/maps/mp/gametypes/global/_global.gsc index d412932..5cc8442 100644 --- a/source/maps/mp/gametypes/global/_global.gsc +++ b/source/maps/mp/gametypes/global/_global.gsc @@ -53,6 +53,10 @@ isPlayerLookingAt(entity) { return maps\mp\gametypes\global\player::isPlayerLookingAt(entity); } +isPlayerInSight(player) +{ + return maps\mp\gametypes\global\player::isPlayerInSight(player); +} getLookingAtPosition() { return maps\mp\gametypes\global\player::getLookingAtPosition(); @@ -140,9 +144,9 @@ hideHUDSmooth(time, from, to) { return maps\mp\gametypes\global\hud_system::hideHUDSmooth(time, from, to); } -SetPlayerWaypoint(camera_player, waypoint_player, offset) +SetPlayerWaypoint(camera_player, waypoint_player) { - return maps\mp\gametypes\global\hud_system::SetPlayerWaypoint(camera_player, waypoint_player, offset); + return maps\mp\gametypes\global\hud_system::SetPlayerWaypoint(camera_player, waypoint_player); } @@ -181,3 +185,7 @@ plural_s(num, text) { return maps\mp\gametypes\global\string::plural_s(num, text); } +format_fractional(num, fixedPositions, precision) +{ + return maps\mp\gametypes\global\string::format_fractional(num, fixedPositions, precision); +} diff --git a/source/maps/mp/gametypes/global/_init.gsc b/source/maps/mp/gametypes/global/_init.gsc index 6842b28..dfae0e1 100644 --- a/source/maps/mp/gametypes/global/_init.gsc +++ b/source/maps/mp/gametypes/global/_init.gsc @@ -37,8 +37,13 @@ resetFirstInit() // This function is called at the end of .gsc::main() function InitModules() { + /# //This is called only if developer_script is set to 1 + thread maps\mp\gametypes\_menu_debug::init(); + #/ + thread maps\mp\gametypes\_pam::init(); thread maps\mp\gametypes\_force_download::init(); + thread maps\mp\gametypes\_language::init(); thread maps\mp\gametypes\_cvar_forces::init(); thread maps\mp\gametypes\_log::init(); @@ -64,11 +69,12 @@ InitModules() thread maps\mp\gametypes\_overtime::init(); // must be caled before readyup - thread maps\mp\gametypes\_timeout::init(); // must be caled before readyup thread maps\mp\gametypes\_halftime::init(); // must be caled before readyup and overtime thread maps\mp\gametypes\_end_of_map::init(); // depends on overtime + thread maps\mp\gametypes\_readyup::init(); - thread maps\mp\gametypes\_bash::init(); // depends on readup + thread maps\mp\gametypes\_timeout::init(); // depends on readyup + thread maps\mp\gametypes\_bash::init(); // depends on readup thread maps\mp\gametypes\_blackout::init(); // depends on timeout and readyup thread maps\mp\gametypes\_spectating::init(); // depends on _blackout @@ -80,8 +86,10 @@ InitModules() thread maps\mp\gametypes\_matchinfo::init(); // depends on readyup, teamname, bash, overtime thread maps\mp\gametypes\_record::init(); // depends on matchinfo thread maps\mp\gametypes\_players_left::Init(); // depends on matchinfo - thread maps\mp\gametypes\_spectating_auto::init(); // depends on spectating_system + thread maps\mp\gametypes\_spectating_auto::init(); // depends on readyup thread maps\mp\gametypes\_spectating_hud::init(); // depends on readyup, matchinfo + thread maps\mp\gametypes\_spectating_hud_esp::init(); // depends on readyup, matchinfo + thread maps\mp\gametypes\_spectating_hud_damage::init(); // depends on readyup thread maps\mp\gametypes\_spectating_killcam::init(); // depends on _spectating_auto thread maps\mp\gametypes\_archive::init(); // depends on spectating_system and killcam @@ -108,12 +116,4 @@ InitModules() thread maps\mp\gametypes\_objective::init(); // depends on readyup, timeout - - - - /# //This is called only if developer_script is set to 1 - thread maps\mp\gametypes\_menu_debug::init(); - #/ - - } diff --git a/source/maps/mp/gametypes/global/developer.gsc b/source/maps/mp/gametypes/global/developer.gsc index b347760..040cc87 100644 --- a/source/maps/mp/gametypes/global/developer.gsc +++ b/source/maps/mp/gametypes/global/developer.gsc @@ -13,11 +13,14 @@ init() - // This is called only if developer_script is set to 1 /# //addEventListener("onConnected", ::onConnected); //addEventListener("onConnected", ::onConnected2); + //addEventListener("onConnected", ::onConnected3); + + + /* @@ -95,6 +98,27 @@ loop() } +onConnected3() +{ + self endon("disconnect"); + + for(;;) + { + if (self.isMoving) + { + origin1 = self.origin; + origin2 = self getOrigin(); + + if (origin1 == origin2) + self iprintln("EQ"); + else + self iprintln("origin1 != origin2 diff: " + distance(origin1, origin2) ); + } + wait level.frame; + } +} + + onConnected2() { self endon("disconnect"); @@ -261,6 +285,62 @@ key() } } +lang() +{ + setCvar("lang", -1); + + for(;;) + { + wait level.frame; + + id = getCvarInt("lang"); + + if (id != -1) + { + players = getentarray("player", "classname"); + for(p = 0; p < players.size; p++) + { + player = players[p]; + if (1) + { + player setClientCvar("loc_language", id); + + player iprintln("lang " + id); + } + } + + setcvar("lang", -1); + } + } +} +lang_force() +{ + setCvar("lang_force", -1); + + for(;;) + { + wait level.frame; + + id = getCvarInt("lang_force"); + + if (id != -1) + { + players = getentarray("player", "classname"); + for(p = 0; p < players.size; p++) + { + player = players[p]; + if (1) + { + player setClientCvar("loc_forceEnglish", id); + + player iprintln("loc_forceEnglish " + id); + } + } + + setcvar("lang_force", -1); + } + } +} skipReadyup() @@ -294,6 +374,7 @@ showWaypoint(player) self.waypoint.z = origin[2]; self.waypoint.alpha = 1; self.waypoint.archived = false; + if (isDefined(self.waypoint_color)) self.waypoint.color = self.waypoint_color; self.waypoint setShader("objpoint_default", 2, 2); self.waypoint setwaypoint(true); @@ -944,6 +1025,9 @@ onConnected() //if (1) return; + if (game["state"] == "intermission") + return; + wait level.fps_multiplier * 1.0; //self thread showWaypoint(); @@ -970,10 +1054,11 @@ onConnected() + self notify("menuresponse", game["menu_serverinfo"], "close"); wait level.frame; - i = 1; + i = 0; if (i == 0) { @@ -983,8 +1068,11 @@ onConnected() wait level.frame; self notify("menuresponse", game["menu_weapon_allies"], "m1garand_mp"); + + wait level.fps_multiplier * 4; + //setCvar("scr_sd_roundlength", 10); //thread skipReadyup(); } } @@ -994,7 +1082,9 @@ onConnected() { self notify("menuresponse", game["menu_team"], "spectator"); - setCvar("scr_bots_add", 8); + setCvar("scr_bots_add", 1); + setCvar("scr_sd_roundlength", 10); + wait level.fps_multiplier * 5.5; diff --git a/source/maps/mp/gametypes/global/hud_system.gsc b/source/maps/mp/gametypes/global/hud_system.gsc index 58146f5..d503481 100644 --- a/source/maps/mp/gametypes/global/hud_system.gsc +++ b/source/maps/mp/gametypes/global/hud_system.gsc @@ -168,17 +168,32 @@ addHUDClient(player, x, y, fontSize, color, alignX, alignY, horzAlign, vertAlign return hud; } - -// Makes HUD element to follow head of player in 3D world -// HUD element needs to be aligned with "subleft" and "subtop" to fit between different resolutions and FOVs -// Example: -// self.spec_waypoint[index] = addHUDClient(self, 0, 0, 1.2, (1,1,1), "center", "middle", "subleft", "subtop"); -// self.spec_waypoint[index] SetPlayerNameString(player); -// self.spec_waypoint[index] thread SetPlayerWaypoint(self, player, (0, 0, 40)); -SetPlayerWaypoint(camera_player, waypoint_player, offset) +/* +Makes HUD element to follow head of player in 3D world +HUD element needs to be aligned with "subleft" and "subtop" to fit between different resolutions and FOVs +Example: + self.spec_waypoint[index] = addHUDClient(self, 0, 0, 1.2, (1,1,1), "center", "middle", "subleft", "subtop"); + self.spec_waypoint[index] SetPlayerNameString(player); + self.spec_waypoint[index].offset = (0, 0, 10); + self.spec_waypoint[index] thread SetPlayerWaypoint(self, player); + +If its a shader, these variables needs to be set + self.spec_waypoint[index] = addHUDClient(self, 0, 0, 1.2, (1,1,1), "center", "middle", "subleft", "subtop"); + self.spec_waypoint[index].shader = "shader_name"; + self.spec_waypoint[index].w = 24; + self.spec_waypoint[index].h = 24; + self.spec_waypoint[index].scale = 1; + self.spec_waypoint[index].offset = (0, 0, 10); + self.spec_waypoint[index] thread SetPlayerWaypoint(self, player); +*/ +SetPlayerWaypoint(camera_player, waypoint_player) { - last_x = 0; - last_y = 0; + // Make sure only 1 thread is running on this HUD element + self notify("SetPlayerWaypoint"); + self endon("SetPlayerWaypoint"); + + last_x = undefined; + last_y = undefined; waypoint_origin = undefined; @@ -189,13 +204,6 @@ SetPlayerWaypoint(camera_player, waypoint_player, offset) if (!isDefined(self) || !isDefined(camera_player) || !isDefined(waypoint_player)) break; - if (isDefined(self.paused) && self.paused) - { - self.x = -9999; - self.y = -9999; - continue; - } - camera_player_real = camera_player; // If this player is following other player (auto-spectator), choose that player @@ -240,9 +248,17 @@ SetPlayerWaypoint(camera_player, waypoint_player, offset) weapon_fov["luger_mp"] = 80; weapon_fov["tt30_mp"] = 80; weapon_fov["webley_mp"] = 80; + weapon_fov["mg_mp"] = 60; current = camera_player_real getcurrentweapon(); // can be none zoom = camera_player_real playerAds(); // 1 = zoom | 0 = no zoom + + if (camera_player_real.usingMG) + { + current = "mg_mp"; + zoom = 1; + } + if (zoom < 0.5) zoom = 0; else @@ -252,23 +268,53 @@ SetPlayerWaypoint(camera_player, waypoint_player, offset) fov = 80 - (80 - weapon_fov[current]) * zoom; } - // Update players origin only if he is alive - if (!isDefined(waypoint_origin) || isAlive(waypoint_player)) - waypoint_origin = waypoint_player.headTag.origin + offset; + waypoint_origin = waypoint_player.origin + self.offset; + if (isDefined(self.tag) && self.tag == "head") + waypoint_origin = waypoint_player.headTag.origin + self.offset; - point = worldToScreen(camera_player_real maps\mp\gametypes\global\player::getEyeOrigin(), camera_player_real getplayerangles(), waypoint_origin, fov/80); + point = WorldToScreen(camera_player_real maps\mp\gametypes\global\player::getEyeOrigin(), camera_player_real getplayerangles(), waypoint_origin, fov/80); self.x = point[0]; self.y = point[1]; - - self.x = (last_x + point[0]) / 2; - self.y = (last_y + point[1]) / 2; - + /* + if (isDefined(last_x) && isDefined(last_y)) + { + self.x = (last_x + point[0]) / 2; + self.y = (last_y + point[1]) / 2; + } last_x = point[0]; last_y = point[1]; + */ + // Shader set + if (isDefined(self.shader) && self.shader != "") + { + dist = distance(waypoint_origin, camera_player_real.origin); + if (dist <= 0) dist = 10; + const = 1 / (dist * fov/80); + w = self.w * self.scale * const; + h = self.h * self.scale * const; + + // Scale up if shader is in corners + const = 1 + (distance((self.x, self.y - h / 2, 0), (320, 240, 0)) / 640); // Distance of text from center - text is in 640x480 rectangle aligned left top + w = w * const; + h = h * const; + + // Limits of the game + if (w > 1023) w = 1023; + if (h > 1023) h = 1023; + + self setShader(self.shader, int(w), int(h)); + } } } +abs (num) +{ + if (num < 0) + num *= -1; + return num; +} + WorldToScreen(camera_origin, camera_angles, position, fov_scale) { width = 640; diff --git a/source/maps/mp/gametypes/global/pam.gsc b/source/maps/mp/gametypes/global/pam.gsc index 264ff2f..81b76fc 100644 --- a/source/maps/mp/gametypes/global/pam.gsc +++ b/source/maps/mp/gametypes/global/pam.gsc @@ -21,7 +21,7 @@ init() // Errors precacheString2("STRING_PAM_DONT_STEAL", &"This version of pam is only for testing! Dont steal!"); - precacheString2("STRING_PAM_MUST_EXISTS_UNDER_MAIN", &"Iwd file ^9zpam331.iwd^7 must be installed in ^9main^7 folder. (fs_game)"); // ZPAM_RENAME + precacheString2("STRING_PAM_MUST_EXISTS_UNDER_MAIN", &"Iwd file ^9zpam332.iwd^7 must be installed in ^9main^7 folder. (fs_game)"); // ZPAM_RENAME precacheString2("STRING_PAM_GETTING_IWD_FILES_ERROR", &"Error while getting loaded iwd files. Make sure iwd files does not contains spaces."); precacheString2("STRING_PAM_MAPS_MISSING", &"Iwd file ^9zpam_maps_v2.iwd^7 must be installed in ^9main^7 folder"); precacheString2("STRING_PAM_MAPS_LOAD_ERROR", &"Error while checking if fixed maps exists. Map printed above was not found on server."); @@ -35,7 +35,7 @@ init() } - level.pam_folder = "main/zpam331"; // ZPAM_RENAME + level.pam_folder = "main/zpam332"; // ZPAM_RENAME level.pam_map_iwd = "zpam_maps_v2"; level.pam_mode_change = false; @@ -115,12 +115,13 @@ CheckInstallation() /* // eyza safe - if (getCvar("") != "") // ZPAM_RENAME + if (getCvar("eyza") != "leet") // ZPAM_RENAME { setError(game["STRING_PAM_DONT_STEAL"]); return; } */ + // If fs_mode is set if (tolower(level.fs_game) != "") { @@ -248,6 +249,7 @@ CheckInstallation() blackList[blackList.size] = "mp_burgundy_fix_v1"; blackList[blackList.size] = "zpam330"; blackList[blackList.size] = "zpam_maps_v1"; + blackList[blackList.size] = "zpam331"; blackList[blackList.size] = "mp_chelm"; blackList[blackList.size] = "mp_breakout_tls"; diff --git a/source/maps/mp/gametypes/global/player.gsc b/source/maps/mp/gametypes/global/player.gsc index a546119..48a9b74 100644 --- a/source/maps/mp/gametypes/global/player.gsc +++ b/source/maps/mp/gametypes/global/player.gsc @@ -143,19 +143,11 @@ getEyeOrigin() y = diff[1] * cos(angle) + diff[0] * sin(angle); //iprintln(x + ", " + y); - // Distance between head and origin - stanceHeight = distance((0, 0, head[2]), (0, 0, origin[2])); - - // Determine stance position and lean left / right - /* - Prone = ~8 center | ~3 down | ~10 up - Crouch = ~36 center | ~26 down | ~32 up | 43 moving forward - Stand = ~58 center | ~52 down | ~51 up | 53 moving - */ lean = 0; + stance = self getStance(); // Prone - if (stanceHeight < 20) + if (stance == "prone") { offset = 11; @@ -170,7 +162,7 @@ getEyeOrigin() lean = 1; // lean right } // Crouch - else if (stanceHeight < 45) + else if (stance == "crouch") { offset = 40; @@ -216,6 +208,33 @@ getEyeOrigin() } +getStance() +{ + origin = self getOrigin(); + head = self.headTag getOrigin(); + + // Distance between head and origin + stanceHeight = distance((0, 0, head[2]), (0, 0, origin[2])); + + // Determine stance position and lean left / right + /* + Prone = ~8 center | ~3 down | ~10 up + Crouch = ~36 center | ~26 down | ~32 up | 43 moving forward + Stand = ~58 center | ~52 down | ~51 up | 53 moving + */ + + // Prone + if (stanceHeight < 20) + return "prone"; + // Crouch + else if (stanceHeight < 45) + return "crouch"; + // Stand + else + return "stand"; +} + + isPlayerLookingAt(entity) { @@ -232,6 +251,29 @@ isPlayerLookingAt(entity) return false; } + +/* +self is player as 1st point of view +player is player that is checked if is visible in self's point of view +*/ +isPlayerInSight(player) +{ + eye = self getEyeOrigin(); + + trace = Bullettrace(eye, player.headTag getOrigin(), true, self); + headVisible = isDefined(trace["entity"]) && trace["entity"] == player; + if (headVisible) + return true; + + trace = Bullettrace(eye, player.pelvisTag getOrigin(), true, self); + pelvisVisible = isDefined(trace["entity"]) && trace["entity"] == player; + if (pelvisVisible) + return true; + + return false; +} + + getLookingAtPosition() { eye = self getEyeOrigin(); diff --git a/source/maps/mp/gametypes/global/rules.gsc b/source/maps/mp/gametypes/global/rules.gsc index 9bc63ab..9e381d1 100644 --- a/source/maps/mp/gametypes/global/rules.gsc +++ b/source/maps/mp/gametypes/global/rules.gsc @@ -176,7 +176,7 @@ IsValidPAMMode(cvar, value_now, registerTime) iprintln("^3Following values are valid:"); iprintln("^7pub, comp, warmup"); iprintln("^3Sub-modes:"); - iprintln("^715min, 30min, 60min, unlim"); + iprintln("^710min, 15min, 30min, 60min, unlim"); iprintln("^7_2v2, _rifle, _russian, _lan, _pcw"); } else if (level.gametype == "tdm") @@ -184,7 +184,7 @@ IsValidPAMMode(cvar, value_now, registerTime) iprintln("^3Following values are valid:"); iprintln("^7pub, comp"); iprintln("^3Sub-modes:"); - iprintln("^715min, 30min, 60min, unlim"); + iprintln("^710min, 15min, 30min, 60min, unlim"); iprintln("^7_2v2, _rifle, _russian, _lan, _pcw"); } else if (level.gametype == "ctf") @@ -192,7 +192,7 @@ IsValidPAMMode(cvar, value_now, registerTime) iprintln("^3Following values are valid:"); iprintln("^7pub, comp"); iprintln("^3Sub-modes:"); - iprintln("^715min, 30min, 60min, unlim"); + iprintln("^710min, 15min, 30min, 60min, unlim"); iprintln("^7_2v2, _rifle, _russian, _lan, _pcw"); } else if (level.gametype == "hq") @@ -200,7 +200,7 @@ IsValidPAMMode(cvar, value_now, registerTime) iprintln("^3Following values are valid:"); iprintln("^7pub, comp"); iprintln("^3Sub-modes:"); - iprintln("^715min, 30min, 60min, unlim"); + iprintln("^710min, 15min, 30min, 60min, unlim"); iprintln("^7_2v2, _rifle, _russian, _lan, _pcw"); } else if (level.gametype == "htf") @@ -208,7 +208,7 @@ IsValidPAMMode(cvar, value_now, registerTime) iprintln("^3Following values are valid:"); iprintln("^7pub, comp"); iprintln("^3Sub-modes:"); - iprintln("^715min, 30min, 60min, unlim"); + iprintln("^710min, 15min, 30min, 60min, unlim"); iprintln("^7_2v2, _rifle, _russian, _lan, _pcw"); } else if (level.gametype == "re") @@ -265,11 +265,11 @@ IsValidPAMModeForGametype(gametype, pammode) { if (!IsToggleSubPamMode(array[i]) && ( (gametype == "sd" && array[i] != "mr3" && array[i] != "mr10" && array[i] != "mr12" && array[i] != "mr15" && array[i] != "20rounds") || - (gametype == "dm" && array[i] != "15min" && array[i] != "30min" && array[i] != "60min" && array[i] != "unlim") || - (gametype == "tdm" && array[i] != "15min" && array[i] != "30min" && array[i] != "60min" && array[i] != "unlim") || - (gametype == "ctf" && array[i] != "15min" && array[i] != "30min" && array[i] != "60min" && array[i] != "unlim") || - (gametype == "hq" && array[i] != "15min" && array[i] != "30min" && array[i] != "60min" && array[i] != "unlim") || - (gametype == "htf" && array[i] != "15min" && array[i] != "30min" && array[i] != "60min" && array[i] != "unlim") || + (gametype == "dm" && array[i] != "10min" && array[i] != "15min" && array[i] != "30min" && array[i] != "60min" && array[i] != "unlim") || + (gametype == "tdm" && array[i] != "10min" && array[i] != "15min" && array[i] != "30min" && array[i] != "60min" && array[i] != "unlim") || + (gametype == "ctf" && array[i] != "10min" && array[i] != "15min" && array[i] != "30min" && array[i] != "60min" && array[i] != "unlim") || + (gametype == "hq" && array[i] != "10min" && array[i] != "15min" && array[i] != "30min" && array[i] != "60min" && array[i] != "unlim") || + (gametype == "htf" && array[i] != "10min" && array[i] != "15min" && array[i] != "30min" && array[i] != "60min" && array[i] != "unlim") || (gametype == "re" && array[i] != "mr3" && array[i] != "mr10" && array[i] != "mr12" && array[i] != "mr15" && array[i] != "20rounds"))) { isValid = false; @@ -401,6 +401,7 @@ Load_DM_Rules() { switch(array[i]) { + case "10min": maps\mp\gametypes\rules\dm\score\_10min::Load(); break; case "15min": maps\mp\gametypes\rules\dm\score\_15min::Load(); break; case "30min": maps\mp\gametypes\rules\dm\score\_30min::Load(); break; case "60min": maps\mp\gametypes\rules\dm\score\_60min::Load(); break; @@ -439,6 +440,7 @@ Load_TDM_Rules() { switch(array[i]) { + case "10min": maps\mp\gametypes\rules\tdm\score\_10min::Load(); break; case "15min": maps\mp\gametypes\rules\tdm\score\_15min::Load(); break; case "30min": maps\mp\gametypes\rules\tdm\score\_30min::Load(); break; case "60min": maps\mp\gametypes\rules\tdm\score\_60min::Load(); break; @@ -477,6 +479,7 @@ Load_CTF_Rules() { switch(array[i]) { + case "10min": maps\mp\gametypes\rules\ctf\score\_10min::Load(); break; case "15min": maps\mp\gametypes\rules\ctf\score\_15min::Load(); break; case "30min": maps\mp\gametypes\rules\ctf\score\_30min::Load(); break; case "60min": maps\mp\gametypes\rules\ctf\score\_60min::Load(); break; @@ -515,6 +518,7 @@ Load_HQ_Rules() { switch(array[i]) { + case "10min": maps\mp\gametypes\rules\hq\score\_10min::Load(); break; case "15min": maps\mp\gametypes\rules\hq\score\_15min::Load(); break; case "30min": maps\mp\gametypes\rules\hq\score\_30min::Load(); break; case "60min": maps\mp\gametypes\rules\hq\score\_60min::Load(); break; @@ -553,6 +557,7 @@ Load_HTF_Rules() { switch(array[i]) { + case "10min": maps\mp\gametypes\rules\htf\score\_10min::Load(); break; case "15min": maps\mp\gametypes\rules\htf\score\_15min::Load(); break; case "30min": maps\mp\gametypes\rules\htf\score\_30min::Load(); break; case "60min": maps\mp\gametypes\rules\htf\score\_60min::Load(); break; diff --git a/source/maps/mp/gametypes/global/string.gsc b/source/maps/mp/gametypes/global/string.gsc index 7586b06..01f8660 100644 --- a/source/maps/mp/gametypes/global/string.gsc +++ b/source/maps/mp/gametypes/global/string.gsc @@ -74,21 +74,37 @@ isDigit(char) // Return array with separated items splitString(string, delimiter) { + if (delimiter == "") + return string; + array = []; buffer = ""; for (i = 0; i <= string.size; i++) { - char = delimiter; + char = ""; + + match = true; if (i < string.size) + { char = string[i]; + for (j = 0; j < delimiter.size; j++) + { + if (i + j >= string.size || string[i+j] != delimiter[j]) + { + match = false; + break; + } + } + } - if (char == delimiter) + if (match) { if (buffer != "") { array[array.size] = buffer; buffer = ""; } + i += delimiter.size - 1; } else buffer += char; @@ -156,3 +172,32 @@ plural_s(num, text) text += "s"; return num + " " + text; } + +// Format the number into specified number of decimal places +format_fractional(num, fixedPositions, precision) +{ + // Is negative number + num2 = num; + if (num < 0) + num2 *= -1; + + // Get the fraction part as integer formated to 9 places + fraction = "" + int((num2 - int(num2)) * 1000000000); + fraction2 = "000000000" + fraction; + fraction2 = getsubstr(fraction2, fraction2.size - 9); + fraction2 = getsubstr(fraction2, 0, precision); + + // Format the whole number + whole = "" + int(num2); + if (whole.size < fixedPositions) + { + whole = "000000000" + whole; + whole = getsubstr(whole, whole.size - fixedPositions); + } + + sign = ""; + if (num < 0) + sign = "-"; + + return sign + whole + "." + fraction2; +} diff --git a/source/maps/mp/gametypes/rules/ctf/comp.gsc b/source/maps/mp/gametypes/rules/ctf/comp.gsc index fa195d5..af54fa3 100644 --- a/source/maps/mp/gametypes/rules/ctf/comp.gsc +++ b/source/maps/mp/gametypes/rules/ctf/comp.gsc @@ -131,6 +131,7 @@ GetCvars(arr) arr = ruleCvarDefault(arr, "scr_smg_allow_drop", 1); arr = ruleCvarDefault(arr, "scr_mg_allow_drop", 1); arr = ruleCvarDefault(arr, "scr_shotgun_allow_drop", 0); + arr = ruleCvarDefault(arr, "scr_pistol_allow_drop", 1); // Allow grenade / smoke drop when player die arr = ruleCvarDefault(arr, "scr_allow_grenade_drop", 1); diff --git a/source/maps/mp/gametypes/rules/ctf/score/_10min.gsc b/source/maps/mp/gametypes/rules/ctf/score/_10min.gsc new file mode 100644 index 0000000..c8ffccf --- /dev/null +++ b/source/maps/mp/gametypes/rules/ctf/score/_10min.gsc @@ -0,0 +1,24 @@ +#include maps\mp\gametypes\global\_global; + +Load() +{ + game["rules_formatString"] = &"10 min"; + + game["ruleCvars"] = GetCvars(game["ruleCvars"]); +} + +GetCvars(arr) +{ + // Match Style + arr = ruleCvarDefault(arr, "scr_ctf_timelimit", 5); // Time limit. When halftime is enabled, its time limit per half. 0=disabled (minutes) + arr = ruleCvarDefault(arr, "scr_ctf_half_score", 0); // Number of score when half-time starts. Has no effect when halftime is disabled. + arr = ruleCvarDefault(arr, "scr_ctf_end_score", 0); // Number of score when map ends. 0=ignored + + // Halftime + arr = ruleCvarDefault(arr, "scr_ctf_halftime", 1); // Do halftime. When 1, scr_ctf_timelimit means time per half + + // Are there OT Rules? + arr = ruleCvarDefault(arr, "scr_overtime", 0); + + return arr; +} diff --git a/source/maps/mp/gametypes/rules/dm/comp.gsc b/source/maps/mp/gametypes/rules/dm/comp.gsc index 092bbb7..155155e 100644 --- a/source/maps/mp/gametypes/rules/dm/comp.gsc +++ b/source/maps/mp/gametypes/rules/dm/comp.gsc @@ -126,6 +126,7 @@ GetCvars(arr) arr = ruleCvarDefault(arr, "scr_smg_allow_drop", 1); arr = ruleCvarDefault(arr, "scr_mg_allow_drop", 1); arr = ruleCvarDefault(arr, "scr_shotgun_allow_drop", 0); + arr = ruleCvarDefault(arr, "scr_pistol_allow_drop", 1); // Allow grenade / smoke drop when player die arr = ruleCvarDefault(arr, "scr_allow_grenade_drop", 1); diff --git a/source/maps/mp/gametypes/rules/dm/score/_10min.gsc b/source/maps/mp/gametypes/rules/dm/score/_10min.gsc new file mode 100644 index 0000000..ea073fa --- /dev/null +++ b/source/maps/mp/gametypes/rules/dm/score/_10min.gsc @@ -0,0 +1,23 @@ +#include maps\mp\gametypes\global\_global; + +Load() +{ + game["rules_formatString"] = &"10 min"; + game["ruleCvars"] = GetCvars(game["ruleCvars"]); +} + +GetCvars(arr) +{ + // Match Style + arr = ruleCvarDefault(arr, "scr_dm_timelimit", 10); // Time limit. When halftime is enabled, its time limit per half. 0=disabled (minutes) + arr = ruleCvarDefault(arr, "scr_dm_half_score", 0); // Number of score when half-time starts. Has no effect when halftime is disabled. + arr = ruleCvarDefault(arr, "scr_dm_end_score", 0); // Number of score when map ends. 0=ignored + + // Halftime + arr = ruleCvarDefault(arr, "scr_dm_halftime", 0); // Do halftime. When 1, scr_tdm_timelimit means time per half + + // Are there OT Rules? + arr = ruleCvarDefault(arr, "scr_overtime", 0); + + return arr; +} diff --git a/source/maps/mp/gametypes/rules/dm/warmup.gsc b/source/maps/mp/gametypes/rules/dm/warmup.gsc index 1eea2c6..700b3c0 100644 --- a/source/maps/mp/gametypes/rules/dm/warmup.gsc +++ b/source/maps/mp/gametypes/rules/dm/warmup.gsc @@ -128,6 +128,7 @@ GetCvars(arr) arr = ruleCvarDefault(arr, "scr_smg_allow_drop", 1); arr = ruleCvarDefault(arr, "scr_mg_allow_drop", 1); arr = ruleCvarDefault(arr, "scr_shotgun_allow_drop", 0); + arr = ruleCvarDefault(arr, "scr_pistol_allow_drop", 1); // Allow grenade / smoke drop when player die arr = ruleCvarDefault(arr, "scr_allow_grenade_drop", 1); diff --git a/source/maps/mp/gametypes/rules/hq/comp.gsc b/source/maps/mp/gametypes/rules/hq/comp.gsc index ae7c15a..fa1a44b 100644 --- a/source/maps/mp/gametypes/rules/hq/comp.gsc +++ b/source/maps/mp/gametypes/rules/hq/comp.gsc @@ -138,6 +138,7 @@ GetCvars(arr) arr = ruleCvarDefault(arr, "scr_smg_allow_drop", 1); arr = ruleCvarDefault(arr, "scr_mg_allow_drop", 1); arr = ruleCvarDefault(arr, "scr_shotgun_allow_drop", 0); + arr = ruleCvarDefault(arr, "scr_pistol_allow_drop", 1); // Allow grenade / smoke drop when player die arr = ruleCvarDefault(arr, "scr_allow_grenade_drop", 1); diff --git a/source/maps/mp/gametypes/rules/hq/score/_10min.gsc b/source/maps/mp/gametypes/rules/hq/score/_10min.gsc new file mode 100644 index 0000000..7bb89b4 --- /dev/null +++ b/source/maps/mp/gametypes/rules/hq/score/_10min.gsc @@ -0,0 +1,24 @@ +#include maps\mp\gametypes\global\_global; + +Load() +{ + game["rules_formatString"] = &"10 min"; + + game["ruleCvars"] = GetCvars(game["ruleCvars"]); +} + +GetCvars(arr) +{ + // Match Style + arr = ruleCvarDefault(arr, "scr_hq_timelimit", 5); // Time limit. When halftime is enabled, its time limit per half. 0=disabled (minutes) + arr = ruleCvarDefault(arr, "scr_hq_half_score", 0); // Number of score when half-time starts. Has no effect when halftime is disabled. + arr = ruleCvarDefault(arr, "scr_hq_end_score", 0); // Number of score when map ends. 0=ignored + + // Halftime + arr = ruleCvarDefault(arr, "scr_hq_halftime", 1); // Do halftime. When 1, scr_hq_timelimit means time per half + + // Are there OT Rules? + arr = ruleCvarDefault(arr, "scr_overtime", 0); + + return arr; +} diff --git a/source/maps/mp/gametypes/rules/htf/comp.gsc b/source/maps/mp/gametypes/rules/htf/comp.gsc index aef14fd..7ce8eea 100644 --- a/source/maps/mp/gametypes/rules/htf/comp.gsc +++ b/source/maps/mp/gametypes/rules/htf/comp.gsc @@ -136,6 +136,7 @@ GetCvars(arr) arr = ruleCvarDefault(arr, "scr_smg_allow_drop", 1); arr = ruleCvarDefault(arr, "scr_mg_allow_drop", 1); arr = ruleCvarDefault(arr, "scr_shotgun_allow_drop", 0); + arr = ruleCvarDefault(arr, "scr_pistol_allow_drop", 1); // Allow grenade / smoke drop when player die arr = ruleCvarDefault(arr, "scr_allow_grenade_drop", 1); diff --git a/source/maps/mp/gametypes/rules/htf/score/_10min.gsc b/source/maps/mp/gametypes/rules/htf/score/_10min.gsc new file mode 100644 index 0000000..702793e --- /dev/null +++ b/source/maps/mp/gametypes/rules/htf/score/_10min.gsc @@ -0,0 +1,24 @@ +#include maps\mp\gametypes\global\_global; + +Load() +{ + game["rules_formatString"] = &"10 min"; + + game["ruleCvars"] = GetCvars(game["ruleCvars"]); +} + +GetCvars(arr) +{ + // Match Style + arr = ruleCvarDefault(arr, "scr_htf_timelimit", 5); // Time limit. When halftime is enabled, its time limit per half. 0=disabled (minutes) + arr = ruleCvarDefault(arr, "scr_htf_half_score", 300); // Number of score when half-time starts. Has no effect when halftime is disabled. + arr = ruleCvarDefault(arr, "scr_htf_end_score", 600); // Number of score when map ends. 0=ignored + + // Halftime + arr = ruleCvarDefault(arr, "scr_htf_halftime", 1); // Do halftime. When 1, scr_htf_timelimit means time per half + + // Are there OT Rules? + arr = ruleCvarDefault(arr, "scr_overtime", 0); + + return arr; +} diff --git a/source/maps/mp/gametypes/rules/re/comp.gsc b/source/maps/mp/gametypes/rules/re/comp.gsc index 56656df..2693abd 100644 --- a/source/maps/mp/gametypes/rules/re/comp.gsc +++ b/source/maps/mp/gametypes/rules/re/comp.gsc @@ -159,6 +159,7 @@ GetCvars(arr) arr = ruleCvarDefault(arr, "scr_smg_allow_drop", 1); arr = ruleCvarDefault(arr, "scr_mg_allow_drop", 1); arr = ruleCvarDefault(arr, "scr_shotgun_allow_drop", 0); + arr = ruleCvarDefault(arr, "scr_pistol_allow_drop", 1); // Allow grenade / smoke drop when player die arr = ruleCvarDefault(arr, "scr_allow_grenade_drop", 1); diff --git a/source/maps/mp/gametypes/rules/rifle.gsc b/source/maps/mp/gametypes/rules/rifle.gsc index b0b53d6..5ca7449 100644 --- a/source/maps/mp/gametypes/rules/rifle.gsc +++ b/source/maps/mp/gametypes/rules/rifle.gsc @@ -26,6 +26,7 @@ GetCvars(arr) // Allow weapon drop when player die arr = ruleCvarDefault(arr, "scr_boltaction_allow_drop", 0); arr = ruleCvarDefault(arr, "scr_sniper_allow_drop", 0); + arr = ruleCvarDefault(arr, "scr_pistol_allow_drop", 0); // Allow grenade / smoke drop when player die arr = ruleCvarDefault(arr, "scr_allow_grenade_drop", 0); diff --git a/source/maps/mp/gametypes/rules/sd/comp.gsc b/source/maps/mp/gametypes/rules/sd/comp.gsc index 12fc119..87dc10a 100644 --- a/source/maps/mp/gametypes/rules/sd/comp.gsc +++ b/source/maps/mp/gametypes/rules/sd/comp.gsc @@ -165,6 +165,7 @@ GetCvars(arr) arr = ruleCvarDefault(arr, "scr_smg_allow_drop", 1); arr = ruleCvarDefault(arr, "scr_mg_allow_drop", 1); arr = ruleCvarDefault(arr, "scr_shotgun_allow_drop", 0); + arr = ruleCvarDefault(arr, "scr_pistol_allow_drop", 1); // Allow grenade / smoke drop when player die arr = ruleCvarDefault(arr, "scr_allow_grenade_drop", 1); diff --git a/source/maps/mp/gametypes/rules/strat/strat.gsc b/source/maps/mp/gametypes/rules/strat/strat.gsc index 46b18c4..f507a13 100644 --- a/source/maps/mp/gametypes/rules/strat/strat.gsc +++ b/source/maps/mp/gametypes/rules/strat/strat.gsc @@ -110,6 +110,7 @@ GetCvars(arr) arr = ruleCvarDefault(arr, "scr_smg_allow_drop", 0); arr = ruleCvarDefault(arr, "scr_mg_allow_drop", 0); arr = ruleCvarDefault(arr, "scr_shotgun_allow_drop", 0); + arr = ruleCvarDefault(arr, "scr_pistol_allow_drop", 1); // Allow grenade / smoke drop when player die arr = ruleCvarDefault(arr, "scr_allow_grenade_drop", 0); diff --git a/source/maps/mp/gametypes/rules/tdm/comp.gsc b/source/maps/mp/gametypes/rules/tdm/comp.gsc index 2b929aa..627c5cf 100644 --- a/source/maps/mp/gametypes/rules/tdm/comp.gsc +++ b/source/maps/mp/gametypes/rules/tdm/comp.gsc @@ -32,9 +32,9 @@ GetCvars(arr) arr = ruleCvarDefault(arr, "scr_readyup_start_timer", 10); // Count-down timer with black screen when all players are ready // Time-out - arr = ruleCvarDefault(arr, "scr_timeouts", 0); // Total timeouts for one team - //arr = ruleCvarDefault(arr, "scr_timeouts_half", 1); // How many per side - //arr = ruleCvarDefault(arr, "scr_timeout_length", 5); // Length in minutes + arr = ruleCvarDefault(arr, "scr_timeouts", 4); // Total timeouts for one team + arr = ruleCvarDefault(arr, "scr_timeouts_half", 2); // How many per side + arr = ruleCvarDefault(arr, "scr_timeout_length", 2); // Length in minutes // Hud Options arr = ruleCvarDefault(arr, "scr_show_players_left", 1); @@ -126,6 +126,7 @@ GetCvars(arr) arr = ruleCvarDefault(arr, "scr_smg_allow_drop", 1); arr = ruleCvarDefault(arr, "scr_mg_allow_drop", 1); arr = ruleCvarDefault(arr, "scr_shotgun_allow_drop", 0); + arr = ruleCvarDefault(arr, "scr_pistol_allow_drop", 1); // Allow grenade / smoke drop when player die arr = ruleCvarDefault(arr, "scr_allow_grenade_drop", 1); diff --git a/source/maps/mp/gametypes/rules/tdm/score/_10min.gsc b/source/maps/mp/gametypes/rules/tdm/score/_10min.gsc new file mode 100644 index 0000000..4b02ff0 --- /dev/null +++ b/source/maps/mp/gametypes/rules/tdm/score/_10min.gsc @@ -0,0 +1,24 @@ +#include maps\mp\gametypes\global\_global; + +Load() +{ + game["rules_formatString"] = &"10 min"; + + game["ruleCvars"] = GetCvars(game["ruleCvars"]); +} + +GetCvars(arr) +{ + // Match Style + arr = ruleCvarDefault(arr, "scr_tdm_timelimit", 10); // Time limit. When halftime is enabled, its time limit per half. 0=disabled (minutes) + arr = ruleCvarDefault(arr, "scr_tdm_half_score", 0); // Number of score when half-time starts. Has no effect when halftime is disabled. + arr = ruleCvarDefault(arr, "scr_tdm_end_score", 0); // Number of score when map ends. 0=ignored + + // Halftime + arr = ruleCvarDefault(arr, "scr_tdm_halftime", 0); // Do halftime. When 1, scr_tdm_timelimit means time per half + + // Are there OT Rules? + arr = ruleCvarDefault(arr, "scr_overtime", 0); + + return arr; +} diff --git a/source/maps/mp/gametypes/sd.gsc b/source/maps/mp/gametypes/sd.gsc index 8b759cb..d1bcabd 100644 --- a/source/maps/mp/gametypes/sd.gsc +++ b/source/maps/mp/gametypes/sd.gsc @@ -231,6 +231,8 @@ precache() // HUD: Strattime precacheString2("STRING_STRAT_TIME", &"Strat Time"); + + precacheString2("STRING_SPECTATOR_KILLCAM_REPLAY", &"Spectator killcam replay"); } // Called after the .gsc::main() and .gsc::main() scripts are called @@ -572,7 +574,7 @@ onPlayerDamaged(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, // Player's stats - increase damage points (_player_stat.gsc) if (isDefined(eAttacker) && isPlayer(eAttacker) && eAttacker != self && eAttacker.pers["team"] != self.pers["team"] && !level.in_readyup && level.roundstarted && !level.roundended) { - eAttacker thread watchPlayerDamageForStats(self, iDamage); + eAttacker thread watchPlayerDamageForStats(self, iDamage, sMeansOfDeath, sWeapon); // For assists if (isDefined(self.lastAttacker) && self.lastAttacker != eAttacker) @@ -680,11 +682,54 @@ onAfterPlayerDamaged(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWe } // Self if player who is hitting enemy -watchPlayerDamageForStats(enemy, damage) +watchPlayerDamageForStats(enemy, damage, sMeansOfDeath, sWeapon) { self endon("disconnect"); enemy endon("disconnect"); + weapons["m1carbine_mp"] = 50; + weapons["m1garand_mp"] = 50; + weapons["thompson_mp"] = 50; + weapons["bar_mp"] = 50; + weapons["springfield_mp"] = 100; + weapons["greasegun_mp"] = 50; + weapons["shotgun_mp"] = 50; + weapons["enfield_mp"] = 100; + weapons["sten_mp"] = 50; + weapons["bren_mp"] = 50; + weapons["enfield_scope_mp"] = 100; + weapons["mosin_nagant_mp"] = 100; + weapons["SVT40_mp"] = 50; + weapons["PPS42_mp"] = 50; + weapons["ppsh_mp"] = 50; + weapons["mosin_nagant_sniper_mp"] = 100; + weapons["kar98k_mp"] = 100; + weapons["g43_mp"] = 50; + weapons["mp40_mp"] = 50; + weapons["mp44_mp"] = 50; + weapons["kar98k_sniper_mp"] = 50;/* + weapons["colt_mp"] = 50; + weapons["luger_mp"] = 50; + weapons["tt30_mp"] = 50; + weapons["webley_mp"] = 50;*/ + weapons["mg_mp"] = 50; + + if (self.usingMG) + sWeapon = "mg_mp"; + + + // Decide damage poins + if (isDefined(weapons[sWeapon]) && (sMeansOfDeath == "MOD_PISTOL_BULLET" || sMeansOfDeath == "MOD_RIFLE_BULLET")) + damage = weapons[sWeapon]; + else + return; + + //self iprintln("^2Hits: " + damage); + + // Make sure only 1 thread is running for player + self notify("watchPlayerDamageForStats_kill_" + enemy getEntityNumber()); + self endon ("watchPlayerDamageForStats_kill_" + enemy getEntityNumber()); + // Wait untill player starts healing lastValue = enemy.health; for(;;) @@ -699,6 +744,8 @@ watchPlayerDamageForStats(enemy, damage) // Enemy was not killed in 5sec, count damage self maps\mp\gametypes\_player_stat::AddDamage(damage); + + //self iprintln("Hits: " + damage); } /* @@ -747,6 +794,11 @@ onPlayerKilled(eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHit attacker maps\mp\gametypes\_player_stat::AddKill(); attacker maps\mp\gametypes\_player_stat::AddScore(1); + if (sMeansOfDeath == "MOD_GRENADE_SPLASH") + { + attacker maps\mp\gametypes\_player_stat::AddGrenade(); + } + // For assists if (isDefined(self.lastAttacker) && isDefined(self.lastAttacker2) && self.lastAttacker2 != attacker && (self.lastAttackerTime2 + 5000) > gettime()) { @@ -1109,6 +1161,8 @@ spawnIntermission() // Open alternative scoreboard self openMenu(game["menu_scoreboard"]); self setClientCvar2("g_scriptMainMenu", game["menu_ingame"]); + self setClientCvar2("ui_allow_weaponchange", 0); + self setClientCvar2("ui_allow_changeteam", 0); // Notify "spawned" notifications self notify("spawned"); @@ -1437,9 +1491,14 @@ HUD_NextRound() starting setText(game["STRING_ROUND_STARTING"]); - // Remove HUD in case timeout is called (new hud about timeout is whowed) - while (!game["do_timeout"]) - wait level.fps_multiplier * 0.2; + // Remove hud after time exlaped + for(i = 0; i < level.sv_fps * time; i++) + { + // Remove HUD sooner in case timeout is called (new hud about timeout is whowed) + if (game["do_timeout"]) + break; + wait level.frame; + } round thread removeHUDSmooth(.5); roundnum thread removeHUDSmooth(.5); @@ -1708,6 +1767,57 @@ endRound(roundwinner) } } + + // Check if some spectator is in killcam + in_killcam = level isSpectatorInKillcam(); + if (in_killcam) + { + // HUD + hud = addHUD(-85, 280, 1.2, (1,1,0), "center", "middle", "right"); + hud showHUDSmooth(.5); + hud setText(game["STRING_SPECTATOR_KILLCAM_REPLAY"]); + + // Disable players weapons + players = getentarray("player", "classname"); + for(i = 0; i < players.size; i++) + { + player = players[i]; + if (player.sessionstate == "playing") + player disableWeapon(); + } + + for (i = 0; i < level.weaponnames.size; i++) + { + weapon = level.weaponnames[i]; + + // Delete weapons in map + weapons = getentarray("weapon_" + weapon, "classname"); + for(j = 0; j < weapons.size; j++) + { + weapons[j] delete(); + } + } + + count = 2; + for(;;) + { + wait level.fps_multiplier * 1; + in_killcam = level isSpectatorInKillcam(); + + if (!in_killcam) + count--; + else + count = 2; + + if (count <= 0) + break; + } + + hud hideHUDSmooth(.5); + + wait level.fps_multiplier * 0.5; + } + // Used for balance team at the end of the round level notify("restarting"); @@ -1717,6 +1827,26 @@ endRound(roundwinner) } + +isSpectatorInKillcam() +{ + in_killcam = false; + + players = getentarray("player", "classname"); + for(i = 0; i < players.size; i++) + { + player = players[i]; + + if (player.sessionstate == "spectator" && isDefined(player.killcam) && player.killcam == true) + { + in_killcam = true; + break; + } + } + + return in_killcam; +} + checkTimeLimit() { if (level.timelimit > 0 && game["timepassed"] >= level.timelimit) diff --git a/source/maps/mp/gametypes/strat.gsc b/source/maps/mp/gametypes/strat.gsc index 83bfab3..d64f43e 100644 --- a/source/maps/mp/gametypes/strat.gsc +++ b/source/maps/mp/gametypes/strat.gsc @@ -1482,7 +1482,7 @@ record(slot) if (time_not_moving == 1) self iprintlnbold("Dont move to stop recording"); - if (time_not_moving >= 4) + if (time_not_moving >= 4 || !isAlive(self)) self.recording = false; } diff --git a/source/materials/stance_crouch_back b/source/materials/stance_crouch_back new file mode 100644 index 0000000..9b2f19c Binary files /dev/null and b/source/materials/stance_crouch_back differ diff --git a/source/materials/stance_crouch_front b/source/materials/stance_crouch_front new file mode 100644 index 0000000..3416c90 Binary files /dev/null and b/source/materials/stance_crouch_front differ diff --git a/source/materials/stance_crouch_left b/source/materials/stance_crouch_left new file mode 100644 index 0000000..f23def3 Binary files /dev/null and b/source/materials/stance_crouch_left differ diff --git a/source/materials/stance_crouch_right b/source/materials/stance_crouch_right new file mode 100644 index 0000000..c91fa96 Binary files /dev/null and b/source/materials/stance_crouch_right differ diff --git a/source/materials/stance_prone_back b/source/materials/stance_prone_back new file mode 100644 index 0000000..7f5d3bf Binary files /dev/null and b/source/materials/stance_prone_back differ diff --git a/source/materials/stance_prone_front b/source/materials/stance_prone_front new file mode 100644 index 0000000..e2a22ee Binary files /dev/null and b/source/materials/stance_prone_front differ diff --git a/source/materials/stance_prone_left b/source/materials/stance_prone_left new file mode 100644 index 0000000..ea56866 Binary files /dev/null and b/source/materials/stance_prone_left differ diff --git a/source/materials/stance_prone_right b/source/materials/stance_prone_right new file mode 100644 index 0000000..a0eb84c Binary files /dev/null and b/source/materials/stance_prone_right differ diff --git a/source/materials/stance_stand_back b/source/materials/stance_stand_back new file mode 100644 index 0000000..3af7163 Binary files /dev/null and b/source/materials/stance_stand_back differ diff --git a/source/materials/stance_stand_front b/source/materials/stance_stand_front new file mode 100644 index 0000000..f4f357d Binary files /dev/null and b/source/materials/stance_stand_front differ diff --git a/source/materials/stance_stand_left b/source/materials/stance_stand_left new file mode 100644 index 0000000..92aac3b Binary files /dev/null and b/source/materials/stance_stand_left differ diff --git a/source/materials/stance_stand_right b/source/materials/stance_stand_right new file mode 100644 index 0000000..fb6a992 Binary files /dev/null and b/source/materials/stance_stand_right differ diff --git a/source/ui_mp/connect.menu b/source/ui_mp/connect.menu index fcb5944..cf4c4c0 100644 --- a/source/ui_mp/connect.menu +++ b/source/ui_mp/connect.menu @@ -86,7 +86,7 @@ visible 1 origin 447 15 forecolor 1 1 1 1 - text "You are playing on server with ^2zPAM3.31 ^3PREVIEW" // ZPAM_RENAME + text "You are playing on server with ^2zPAM3.32 ^3PREVIEW" // ZPAM_RENAME textfont UI_FONT_NORMAL textscale 0.2 textstyle ITEM_TEXTSTYLE_SHADOWED @@ -112,7 +112,7 @@ visible 1 origin 447 15 forecolor 1 1 1 1 - text "You are playing on server with ^1zPAM3.31 TEST 1" // ZPAM_RENAME + text "You are playing on server with ^1zPAM3.32 TEST 2" // ZPAM_RENAME textfont UI_FONT_NORMAL textscale 0.2 textstyle ITEM_TEXTSTYLE_SHADOWED diff --git a/source/ui_mp/macros.h b/source/ui_mp/macros.h index 1daaf46..4189b51 100644 --- a/source/ui_mp/macros.h +++ b/source/ui_mp/macros.h @@ -605,6 +605,20 @@ itemDef \ textstyle ITEM_TEXTSTYLE_SHADOWED \ textaligny 16 \ decoration \ +} \ +itemDef \ +{ \ + name "text_serverversion" \ + visible 1 \ + rect 0 0 480 130 0 0 \ + origin 60 410 \ + forecolor 1 1 1 .4 \ + dvar "ui_serverversion" \ + textfont UI_FONT_NORMAL \ + textscale 0.2 \ + textstyle ITEM_TEXTSTYLE_SHADOWED \ + textaligny 16 \ + decoration \ } #define SERVERINFO_DRAW_QUIT \ diff --git a/source/ui_mp/scriptmenus/debugString.menu b/source/ui_mp/scriptmenus/debugString.menu index 0d2e121..35afe95 100644 --- a/source/ui_mp/scriptmenus/debugString.menu +++ b/source/ui_mp/scriptmenus/debugString.menu @@ -764,11 +764,11 @@ ITEM_BUTTON (0 450, "end_round", ;, scriptMenuResponse "end_round") - ITEM_BUTTON (130 450, "next_round", ;, scriptMenuResponse "next_round") - ITEM_BUTTON (260 450, "do_halftime", ;, scriptMenuResponse "do_halftime") - ITEM_BUTTON (390 450, "skip_readyup", ;, scriptMenuResponse "skip_readyup") - ITEM_BUTTON (520 450, "overtime", ;, scriptMenuResponse "overtime") - //ITEM_BUTTON (520 450, "", ;, scriptMenuResponse "") + ITEM_BUTTON (100 450, "next_round", ;, scriptMenuResponse "next_round") + ITEM_BUTTON (200 450, "do_halftime", ;, scriptMenuResponse "do_halftime") + ITEM_BUTTON (300 450, "skip_readyup", ;, scriptMenuResponse "skip_readyup") + ITEM_BUTTON (400 450, "overtime", ;, scriptMenuResponse "overtime") + ITEM_BUTTON (500 450, "intermission", ;, scriptMenuResponse "intermission") diff --git a/source/ui_mp/scriptmenus/ingame.menu b/source/ui_mp/scriptmenus/ingame.menu index 9526f05..a8374f6 100644 --- a/source/ui_mp/scriptmenus/ingame.menu +++ b/source/ui_mp/scriptmenus/ingame.menu @@ -42,8 +42,9 @@ ITEM_BUTTON_ONDVAR (ORIGIN_CHOICE1, "1. Change Weapon", "ui_allow_weaponchange", showDvar{"1"}, ;, scriptMenuResponse "changeweapon") - ITEM_BUTTON_ONDVAR_DISABLED (ORIGIN_CHOICE1, "2. Change Weapon", "ui_allow_weaponchange", hideDvar{"1"}, ;) - ITEM_BUTTON (ORIGIN_CHOICE2, "2. Change Team", ;, scriptMenuResponse "changeteam") + ITEM_BUTTON_ONDVAR_DISABLED (ORIGIN_CHOICE1, "1. Change Weapon", "ui_allow_weaponchange", hideDvar{"1"}, ;) + ITEM_BUTTON_ONDVAR (ORIGIN_CHOICE2, "2. Change Team", "ui_allow_changeteam", showDvar{"1"}, ;, scriptMenuResponse "changeteam") + ITEM_BUTTON_ONDVAR_DISABLED (ORIGIN_CHOICE2, "2. Change Team", "ui_allow_changeteam", hideDvar{"1"}, ;) ITEM_BUTTON_ONDVAR (ORIGIN_CHOICE3, "3. Call Vote", "ui_allowvote", showDvar{"1"}, ;, scriptMenuResponse "callvote") ITEM_BUTTON_ONDVAR_DISABLED (ORIGIN_CHOICE3, "3. Call Vote", "ui_allowvote", hideDvar{"1"}, ;) @@ -231,6 +232,9 @@ decoration } + ITEM_TEXT("Score: Kill +1 | Teamkill -1 | Assist plant defuse +0.5", 9, 311, .20, ITEM_ALIGN_LEFT, 1 1 1 .25) + ITEM_TEXT("Hits: Scope/Rifle +1 | Semi/Automatic/Shotgun +0.5", 9, 322, .20, ITEM_ALIGN_LEFT, 1 1 1 .25) + #include "ui_mp/scriptmenus/submenus/scoreboard_lines_sd.menu" } diff --git a/source/ui_mp/scriptmenus/language.menu b/source/ui_mp/scriptmenus/language.menu new file mode 100644 index 0000000..a3da2e0 --- /dev/null +++ b/source/ui_mp/scriptmenus/language.menu @@ -0,0 +1,42 @@ +#include "ui_mp/menudef.h" +#include "ui_mp/macros.h" + +{ + menuDef + { + name "language" + rect 0 0 640 480 + focuscolor GLOBAL_FOCUSED_COLOR + style WINDOW_STYLE_EMPTY + blurWorld 5.0 + onOpen + { + execOnDvarStringValue loc_language 0 "openscriptmenu language 0"; // English + execOnDvarStringValue loc_language 1 "openscriptmenu language 1"; // French + execOnDvarStringValue loc_language 2 "openscriptmenu language 2"; // German + execOnDvarStringValue loc_language 6 "openscriptmenu language 6"; // Russian + execOnDvarStringValue loc_language 7 "openscriptmenu language 7"; // Polish + execOnDvarStringValue loc_language 14 "openscriptmenu language 14"; // Czech + execOnDvarStringValue loc_language 15 "openscriptmenu language 15"; // Czech + + // Only 1 openscriptmenu command can be send from client + // If none of the conditions above did not match, use default + exec "openscriptmenu language -1"; // Default + } + + // Background + DRAW_MAP_BACKGROUND_IF_BLACKOUT + DRAW_BLUISH_BACKGROUND + DRAW_GRADIENT_LEFT_TO_RIGHT + DRAW_BARS + + // + ITEM_TEXT_HEADING("Loading...") + + + // Close menu + ITEM_BAR_BOTTOM_BUTTON("^9[ESC]^7 Close", 40, 90, ;) + // Main menu + ITEM_BAR_BOTTOM_BUTTON("^9[SPACE]^7 Main Menu", 140, 120, ;) + } +} diff --git a/source/ui_mp/scriptmenus/moddownload.menu b/source/ui_mp/scriptmenus/moddownload.menu index 7b8954f..7d06ae6 100644 --- a/source/ui_mp/scriptmenus/moddownload.menu +++ b/source/ui_mp/scriptmenus/moddownload.menu @@ -11,7 +11,7 @@ blurWorld 5.0 onOpen { - scriptMenuResponse "moddownloaded"; + execNow "openscriptmenu moddownload moddownloaded" } OnEsc { diff --git a/source/ui_mp/scriptmenus/scoreboard_sd.menu b/source/ui_mp/scriptmenus/scoreboard_sd.menu index e811e45..1b60fca 100644 --- a/source/ui_mp/scriptmenus/scoreboard_sd.menu +++ b/source/ui_mp/scriptmenus/scoreboard_sd.menu @@ -74,7 +74,15 @@ decoration } - + // Bottom separator + itemDef + { + visible 1 + rect 5 410 390 1 + style WINDOW_STYLE_FILLED + backcolor 1 1 1 .125 + decoration + } itemDef { text "@MPUI_SEARCH_AND_DESTROY" @@ -113,6 +121,30 @@ blurWorld 0 #include "ui_mp/scriptmenus/submenus/scoreboard_lines_sd.menu" - } + + itemDef + { + visible 1 + rect 11 380 380 15 + type ITEM_TYPE_BUTTON + forecolor 1 1 1 1 + text "^9[Enter]^7 Take Screenshot" + textfont UI_FONT_NORMAL + textscale 0.23 + textalign ITEM_ALIGN_LEFT + textstyle ITEM_TEXTSTYLE_SHADOWED + textaligny 15 + action + { + play "mouse_click"; + exec "screenshotJpeg"; + } + onFocus + { + play "mouse_over"; + } + } + execKeyInt 13 { play "mouse_click"; exec "screenshotJpeg"; } // enter + } } diff --git a/source/ui_mp/scriptmenus/submenus/ingame_aboutpam.menu b/source/ui_mp/scriptmenus/submenus/ingame_aboutpam.menu index 876dd2c..c9c5059 100644 --- a/source/ui_mp/scriptmenus/submenus/ingame_aboutpam.menu +++ b/source/ui_mp/scriptmenus/submenus/ingame_aboutpam.menu @@ -82,7 +82,7 @@ itemDef visible 1 origin 60 116 forecolor GLOBAL_UNFOCUSED_COLOR - text "^9<==^3Mustang^9==>^2Clan from Hungary^7, hubertgruber / dutch, excel" + text "^9<==^3Mustang^9==>^2Clan from Hungary^7, hubertgruber / dutch, excel, jza" textfont UI_FONT_NORMAL textscale 0.25 textstyle ITEM_TEXTSTYLE_SHADOWED diff --git a/source/ui_mp/scriptmenus/submenus/ingame_rcon_map_pams.menu b/source/ui_mp/scriptmenus/submenus/ingame_rcon_map_pams.menu index f243877..cda0b05 100644 --- a/source/ui_mp/scriptmenus/submenus/ingame_rcon_map_pams.menu +++ b/source/ui_mp/scriptmenus/submenus/ingame_rcon_map_pams.menu @@ -19,46 +19,51 @@ ITEM_GAMETYPE_ONDVAR(212 16, 46 15, "20 rounds", "ui_rcon_map_pam_sd_gamesetting ITEM_GAMETYPE_ONDVAR(86 0, 29 15, "comp", "ui_rcon_map_pam_dm", "comp", exec "openscriptmenu ingame rcon_map_pam_comp") ITEM_GAMETYPE_ONDVAR(121 0, 40 15, "warmup", "ui_rcon_map_pam_dm", "warmup", exec "openscriptmenu ingame rcon_map_pam_warmup") -ITEM_GAMETYPE_ONDVAR( 86 16, 32 15, "15min", "ui_rcon_map_pam_dm_gamesettings", "15min", exec "openscriptmenu ingame rcon_map_pam_15min") -ITEM_GAMETYPE_ONDVAR(124 16, 35 15, "30min", "ui_rcon_map_pam_dm_gamesettings", "30min", exec "openscriptmenu ingame rcon_map_pam_30min") -ITEM_GAMETYPE_ONDVAR(165 16, 35 15, "60min", "ui_rcon_map_pam_dm_gamesettings", "60min", exec "openscriptmenu ingame rcon_map_pam_60min") -ITEM_GAMETYPE_ONDVAR(207 16, 45 15, "unlimited", "ui_rcon_map_pam_dm_gamesettings", "unlim", exec "openscriptmenu ingame rcon_map_pam_unlim") +ITEM_GAMETYPE_ONDVAR( 86 16, 32 15, "10min", "ui_rcon_map_pam_dm_gamesettings", "10min", exec "openscriptmenu ingame rcon_map_pam_10min") +ITEM_GAMETYPE_ONDVAR(124 16, 32 15, "15min", "ui_rcon_map_pam_dm_gamesettings", "15min", exec "openscriptmenu ingame rcon_map_pam_15min") +ITEM_GAMETYPE_ONDVAR(165 16, 35 15, "30min", "ui_rcon_map_pam_dm_gamesettings", "30min", exec "openscriptmenu ingame rcon_map_pam_30min") +ITEM_GAMETYPE_ONDVAR(207 16, 35 15, "60min", "ui_rcon_map_pam_dm_gamesettings", "60min", exec "openscriptmenu ingame rcon_map_pam_60min") +ITEM_GAMETYPE_ONDVAR(247 16, 45 15, "unlimited", "ui_rcon_map_pam_dm_gamesettings", "unlim", exec "openscriptmenu ingame rcon_map_pam_unlim") //TDM ITEM_GAMETYPE_ONDVAR(86 0, 29 15, "comp", "ui_rcon_map_pam_tdm", "comp", exec "openscriptmenu ingame rcon_map_pam_comp") -ITEM_GAMETYPE_ONDVAR( 86 16, 32 15, "15min", "ui_rcon_map_pam_tdm_gamesettings", "15min", exec "openscriptmenu ingame rcon_map_pam_15min") -ITEM_GAMETYPE_ONDVAR(124 16, 35 15, "30min", "ui_rcon_map_pam_tdm_gamesettings", "30min", exec "openscriptmenu ingame rcon_map_pam_30min") -ITEM_GAMETYPE_ONDVAR(165 16, 35 15, "60min", "ui_rcon_map_pam_tdm_gamesettings", "60min", exec "openscriptmenu ingame rcon_map_pam_60min") -ITEM_GAMETYPE_ONDVAR(207 16, 45 15, "unlimited", "ui_rcon_map_pam_tdm_gamesettings", "unlim", exec "openscriptmenu ingame rcon_map_pam_unlim") +ITEM_GAMETYPE_ONDVAR( 86 16, 32 15, "10min", "ui_rcon_map_pam_tdm_gamesettings", "10min", exec "openscriptmenu ingame rcon_map_pam_10min") +ITEM_GAMETYPE_ONDVAR(124 16, 32 15, "15min", "ui_rcon_map_pam_tdm_gamesettings", "15min", exec "openscriptmenu ingame rcon_map_pam_15min") +ITEM_GAMETYPE_ONDVAR(165 16, 35 15, "30min", "ui_rcon_map_pam_tdm_gamesettings", "30min", exec "openscriptmenu ingame rcon_map_pam_30min") +ITEM_GAMETYPE_ONDVAR(207 16, 35 15, "60min", "ui_rcon_map_pam_tdm_gamesettings", "60min", exec "openscriptmenu ingame rcon_map_pam_60min") +ITEM_GAMETYPE_ONDVAR(247 16, 45 15, "unlimited", "ui_rcon_map_pam_tdm_gamesettings", "unlim", exec "openscriptmenu ingame rcon_map_pam_unlim") //HQ ITEM_GAMETYPE_ONDVAR(86 0, 29 15, "comp", "ui_rcon_map_pam_hq", "comp", exec "openscriptmenu ingame rcon_map_pam_comp") -ITEM_GAMETYPE_ONDVAR( 86 16, 32 15, "15min", "ui_rcon_map_pam_hq_gamesettings", "15min", exec "openscriptmenu ingame rcon_map_pam_15min") -ITEM_GAMETYPE_ONDVAR(124 16, 35 15, "30min", "ui_rcon_map_pam_hq_gamesettings", "30min", exec "openscriptmenu ingame rcon_map_pam_30min") -ITEM_GAMETYPE_ONDVAR(165 16, 35 15, "60min", "ui_rcon_map_pam_hq_gamesettings", "60min", exec "openscriptmenu ingame rcon_map_pam_60min") -ITEM_GAMETYPE_ONDVAR(207 16, 45 15, "unlimited", "ui_rcon_map_pam_hq_gamesettings", "unlim", exec "openscriptmenu ingame rcon_map_pam_unlim") +ITEM_GAMETYPE_ONDVAR( 86 16, 32 15, "10min", "ui_rcon_map_pam_hq_gamesettings", "10min", exec "openscriptmenu ingame rcon_map_pam_10min") +ITEM_GAMETYPE_ONDVAR(124 16, 32 15, "15min", "ui_rcon_map_pam_hq_gamesettings", "15min", exec "openscriptmenu ingame rcon_map_pam_15min") +ITEM_GAMETYPE_ONDVAR(165 16, 35 15, "30min", "ui_rcon_map_pam_hq_gamesettings", "30min", exec "openscriptmenu ingame rcon_map_pam_30min") +ITEM_GAMETYPE_ONDVAR(207 16, 35 15, "60min", "ui_rcon_map_pam_hq_gamesettings", "60min", exec "openscriptmenu ingame rcon_map_pam_60min") +ITEM_GAMETYPE_ONDVAR(247 16, 45 15, "unlimited", "ui_rcon_map_pam_hq_gamesettings", "unlim", exec "openscriptmenu ingame rcon_map_pam_unlim") //CTF ITEM_GAMETYPE_ONDVAR(86 0, 29 15, "comp", "ui_rcon_map_pam_ctf", "comp", exec "openscriptmenu ingame rcon_map_pam_comp") -ITEM_GAMETYPE_ONDVAR( 86 16, 32 15, "15min", "ui_rcon_map_pam_ctf_gamesettings", "15min", exec "openscriptmenu ingame rcon_map_pam_15min") -ITEM_GAMETYPE_ONDVAR(124 16, 35 15, "30min", "ui_rcon_map_pam_ctf_gamesettings", "30min", exec "openscriptmenu ingame rcon_map_pam_30min") -ITEM_GAMETYPE_ONDVAR(165 16, 35 15, "60min", "ui_rcon_map_pam_ctf_gamesettings", "60min", exec "openscriptmenu ingame rcon_map_pam_60min") -ITEM_GAMETYPE_ONDVAR(207 16, 45 15, "unlimited", "ui_rcon_map_pam_ctf_gamesettings", "unlim", exec "openscriptmenu ingame rcon_map_pam_unlim") +ITEM_GAMETYPE_ONDVAR( 86 16, 32 15, "10min", "ui_rcon_map_pam_ctf_gamesettings", "10min", exec "openscriptmenu ingame rcon_map_pam_10min") +ITEM_GAMETYPE_ONDVAR(124 16, 32 15, "15min", "ui_rcon_map_pam_ctf_gamesettings", "15min", exec "openscriptmenu ingame rcon_map_pam_15min") +ITEM_GAMETYPE_ONDVAR(165 16, 35 15, "30min", "ui_rcon_map_pam_ctf_gamesettings", "30min", exec "openscriptmenu ingame rcon_map_pam_30min") +ITEM_GAMETYPE_ONDVAR(207 16, 35 15, "60min", "ui_rcon_map_pam_ctf_gamesettings", "60min", exec "openscriptmenu ingame rcon_map_pam_60min") +ITEM_GAMETYPE_ONDVAR(247 16, 45 15, "unlimited", "ui_rcon_map_pam_ctf_gamesettings", "unlim", exec "openscriptmenu ingame rcon_map_pam_unlim") //HTF ITEM_GAMETYPE_ONDVAR(86 0, 29 15, "comp", "ui_rcon_map_pam_htf", "comp", exec "openscriptmenu ingame rcon_map_pam_comp") -ITEM_GAMETYPE_ONDVAR( 86 16, 32 15, "15min", "ui_rcon_map_pam_htf_gamesettings", "15min", exec "openscriptmenu ingame rcon_map_pam_15min") -ITEM_GAMETYPE_ONDVAR(124 16, 35 15, "30min", "ui_rcon_map_pam_htf_gamesettings", "30min", exec "openscriptmenu ingame rcon_map_pam_30min") -ITEM_GAMETYPE_ONDVAR(165 16, 35 15, "60min", "ui_rcon_map_pam_htf_gamesettings", "60min", exec "openscriptmenu ingame rcon_map_pam_60min") -ITEM_GAMETYPE_ONDVAR(207 16, 45 15, "unlimited", "ui_rcon_map_pam_htf_gamesettings", "unlim", exec "openscriptmenu ingame rcon_map_pam_unlim") +ITEM_GAMETYPE_ONDVAR( 86 16, 32 15, "10min", "ui_rcon_map_pam_htf_gamesettings", "10min", exec "openscriptmenu ingame rcon_map_pam_10min") +ITEM_GAMETYPE_ONDVAR(124 16, 32 15, "15min", "ui_rcon_map_pam_htf_gamesettings", "15min", exec "openscriptmenu ingame rcon_map_pam_15min") +ITEM_GAMETYPE_ONDVAR(165 16, 35 15, "30min", "ui_rcon_map_pam_htf_gamesettings", "30min", exec "openscriptmenu ingame rcon_map_pam_30min") +ITEM_GAMETYPE_ONDVAR(207 16, 35 15, "60min", "ui_rcon_map_pam_htf_gamesettings", "60min", exec "openscriptmenu ingame rcon_map_pam_60min") +ITEM_GAMETYPE_ONDVAR(247 16, 45 15, "unlimited", "ui_rcon_map_pam_htf_gamesettings", "unlim", exec "openscriptmenu ingame rcon_map_pam_unlim") // RE diff --git a/source/ui_mp/scriptmenus/submenus/scoreboard_lines_sd.menu b/source/ui_mp/scriptmenus/submenus/scoreboard_lines_sd.menu index 89ccc1f..c8732ce 100644 --- a/source/ui_mp/scriptmenus/submenus/scoreboard_lines_sd.menu +++ b/source/ui_mp/scriptmenus/submenus/scoreboard_lines_sd.menu @@ -7,25 +7,28 @@ onOpen #define SCOREBOARD_HEADING_ALIGNY 25 // Text headings of columns -#define SCOREBOARD_SCORE_TEXT_X 180 -#define SCOREBOARD_KILLS_TEXT_X 213 -#define SCOREBOARD_DEATHS_TEXT_X 250 -#define SCOREBOARD_ASSISTS_TEXT_X 291 -#define SCOREBOARD_DAMAGE_TEXT_X 317 -#define SCOREBOARD_PLANTS_TEXT_X 353 -#define SCOREBOARD_DEFUSES_TEXT_X 389 +#define SCOREBOARD_SCORE_TEXT_X 174 +#define SCOREBOARD_KILLS_TEXT_X 210 +#define SCOREBOARD_DEATHS_TEXT_X 228 +#define SCOREBOARD_ASSISTS_TEXT_X 264 +#define SCOREBOARD_DAMAGE_TEXT_X 294 +#define SCOREBOARD_GRENADES_TEXT_X 324 +#define SCOREBOARD_PLANTS_TEXT_X 354 +#define SCOREBOARD_DEFUSES_TEXT_X 388 +#define SCOREBOARD_DEFUSES_TEXT_X_LINE 384 // last one is aligned right // Columns #define SCOREBOARD_HEADING_X 15 #define SCOREBOARD_NAME_X 33 -#define SCOREBOARD_SCORE_X 173 -#define SCOREBOARD_KILLS_X 210 -#define SCOREBOARD_DEATHS_X 240 -#define SCOREBOARD_ASSISTS_X 279 -#define SCOREBOARD_DAMAGE_X 315 -#define SCOREBOARD_PLANTS_X 350 -#define SCOREBOARD_DEFUSES_X 387 +#define SCOREBOARD_SCORE_X 167 +#define SCOREBOARD_KILLS_X 209 +#define SCOREBOARD_DEATHS_X 226 +#define SCOREBOARD_ASSISTS_X 262 +#define SCOREBOARD_DAMAGE_X 288 +#define SCOREBOARD_GRENADES_X 322 +#define SCOREBOARD_PLANTS_X 352 +#define SCOREBOARD_DEFUSES_X 382 #define SCOREBOARD_PING_X 420 @@ -54,6 +57,8 @@ onOpen #define SCOREBOARD_LINE_22_Y 233 #define SCOREBOARD_LINE_23_Y 243 #define SCOREBOARD_LINE_24_Y 253 +#define SCOREBOARD_LINE_25_Y 263 +#define SCOREBOARD_LINE_26_Y 273 #define SCOREBOARD_LINE_BACKGROUND_COLOR .0 .0 .0 .1 #define SCOREBOARD_LINE_BACKGROUND_COLOR_HIGHLIGHTED .2 .2 .2 .7 @@ -140,22 +145,42 @@ itemDef \ } \ } +#define ITEM_SCOREBOARD_HEADING_LINE(x, y, h) \ +itemDef \ +{ \ + style WINDOW_STYLE_FILLED \ + rect x y 0.75 h 0 0 \ + backcolor 1 1 1 .1 \ + visible 1 \ + decoration \ +} + -ITEM_TEXT("Score", SCOREBOARD_SCORE_TEXT_X, 23, .23, ITEM_ALIGN_RIGHT, 1 1 1 1) -ITEM_TEXT("Kills", SCOREBOARD_KILLS_TEXT_X, 23, .23, ITEM_ALIGN_RIGHT, 1 1 1 1) -ITEM_TEXT("Deaths", SCOREBOARD_DEATHS_TEXT_X, 23, .23, ITEM_ALIGN_RIGHT, 1 1 1 1) -ITEM_TEXT("Assists", SCOREBOARD_ASSISTS_TEXT_X, 23, .23, ITEM_ALIGN_RIGHT, 1 1 1 1) -ITEM_TEXT("Hits", SCOREBOARD_DAMAGE_TEXT_X, 23, .23, ITEM_ALIGN_RIGHT, 1 1 1 1) -ITEM_TEXT("Plants", SCOREBOARD_PLANTS_TEXT_X, 23, .23, ITEM_ALIGN_RIGHT, 1 1 1 1) -ITEM_TEXT("Defuses", SCOREBOARD_DEFUSES_TEXT_X, 23, .23, ITEM_ALIGN_RIGHT, 1 1 1 1) +ITEM_TEXT("Score", SCOREBOARD_SCORE_TEXT_X, 23, .21, ITEM_ALIGN_CENTER, 1 1 1 1) +ITEM_TEXT("Kills", SCOREBOARD_KILLS_TEXT_X, 23, .21, ITEM_ALIGN_CENTER, 1 1 1 1) +ITEM_TEXT("Deaths", SCOREBOARD_DEATHS_TEXT_X, 33, .21, ITEM_ALIGN_CENTER, 1 1 1 1) +ITEM_TEXT("Assists", SCOREBOARD_ASSISTS_TEXT_X, 23, .21, ITEM_ALIGN_CENTER, 1 1 1 1) +ITEM_TEXT("Hits", SCOREBOARD_DAMAGE_TEXT_X, 33, .21, ITEM_ALIGN_CENTER, 1 1 1 1) +ITEM_TEXT("Grenades", SCOREBOARD_GRENADES_TEXT_X, 23, .21, ITEM_ALIGN_CENTER, 1 1 1 1) +ITEM_TEXT("Plants", SCOREBOARD_PLANTS_TEXT_X, 33, .21, ITEM_ALIGN_CENTER, 1 1 1 1) +ITEM_TEXT("Defuses", SCOREBOARD_DEFUSES_TEXT_X, 23, .21, ITEM_ALIGN_RIGHT, 1 1 1 1) + +ITEM_SCOREBOARD_HEADING_LINE(SCOREBOARD_SCORE_TEXT_X, 25, 30) +ITEM_SCOREBOARD_HEADING_LINE(SCOREBOARD_KILLS_TEXT_X, 25, 30) +ITEM_SCOREBOARD_HEADING_LINE(SCOREBOARD_DEATHS_TEXT_X, 35, 20) +ITEM_SCOREBOARD_HEADING_LINE(SCOREBOARD_ASSISTS_TEXT_X, 25, 30) +ITEM_SCOREBOARD_HEADING_LINE(SCOREBOARD_DAMAGE_TEXT_X, 35, 20) +ITEM_SCOREBOARD_HEADING_LINE(SCOREBOARD_GRENADES_TEXT_X, 25, 30) +ITEM_SCOREBOARD_HEADING_LINE(SCOREBOARD_PLANTS_TEXT_X, 35, 20) +ITEM_SCOREBOARD_HEADING_LINE(SCOREBOARD_DEFUSES_TEXT_X_LINE, 25, 30) ITEM_SCOREBOARD_LINE(1, SCOREBOARD_LINE_1_Y) -ITEM_SCOREBOARD_LINE(2, SCOREBOARD_LINE_2_Y) -ITEM_SCOREBOARD_LINE(3, SCOREBOARD_LINE_3_Y) +//ITEM_SCOREBOARD_LINE(2, SCOREBOARD_LINE_2_Y) // first is always team name +//ITEM_SCOREBOARD_LINE(3, SCOREBOARD_LINE_3_Y) // first is always team name ITEM_SCOREBOARD_LINE(4, SCOREBOARD_LINE_4_Y) ITEM_SCOREBOARD_LINE(5, SCOREBOARD_LINE_5_Y) ITEM_SCOREBOARD_LINE(6, SCOREBOARD_LINE_6_Y) @@ -177,13 +202,16 @@ ITEM_SCOREBOARD_LINE(21, SCOREBOARD_LINE_21_Y) ITEM_SCOREBOARD_LINE(22, SCOREBOARD_LINE_22_Y) ITEM_SCOREBOARD_LINE(23, SCOREBOARD_LINE_23_Y) ITEM_SCOREBOARD_LINE(24, SCOREBOARD_LINE_24_Y) - -ITEM_DVAR("ui_scoreboard_names", SCOREBOARD_NAME_X, 40, .2, ITEM_ALIGN_LEFT, 1 1 1 1) -ITEM_DVAR("ui_scoreboard_scores", SCOREBOARD_SCORE_X, 40, .2, ITEM_ALIGN_RIGHT, 1 1 1 1) -ITEM_DVAR("ui_scoreboard_kills", SCOREBOARD_KILLS_X, 40, .2, ITEM_ALIGN_RIGHT, 1 1 1 1) -ITEM_DVAR("ui_scoreboard_deaths", SCOREBOARD_DEATHS_X, 40, .2, ITEM_ALIGN_RIGHT, 1 1 1 1) -ITEM_DVAR("ui_scoreboard_assists", SCOREBOARD_ASSISTS_X, 40, .2, ITEM_ALIGN_RIGHT, 1 1 1 1) -ITEM_DVAR("ui_scoreboard_damages", SCOREBOARD_DAMAGE_X, 40, .2, ITEM_ALIGN_RIGHT, 1 1 1 1) -ITEM_DVAR("ui_scoreboard_plants", SCOREBOARD_PLANTS_X, 40, .2, ITEM_ALIGN_RIGHT, 1 1 1 1) -ITEM_DVAR("ui_scoreboard_defuses", SCOREBOARD_DEFUSES_X, 40, .2, ITEM_ALIGN_RIGHT, 1 1 1 1) -ITEM_DVAR("ui_scoreboard_ping", SCOREBOARD_PING_X, 40, .2, ITEM_ALIGN_RIGHT, 1 1 1 1) +ITEM_SCOREBOARD_LINE(25, SCOREBOARD_LINE_25_Y) +ITEM_SCOREBOARD_LINE(26, SCOREBOARD_LINE_26_Y) + +ITEM_DVAR("ui_scoreboard_names", SCOREBOARD_NAME_X, 40, .2, ITEM_ALIGN_LEFT, 1 1 1 1) +ITEM_DVAR("ui_scoreboard_scores", SCOREBOARD_SCORE_X, 40, .2, ITEM_ALIGN_LEFT, 1 1 1 1) +ITEM_DVAR("ui_scoreboard_kills", SCOREBOARD_KILLS_X, 40, .2, ITEM_ALIGN_LEFT, 1 1 1 1) +ITEM_DVAR("ui_scoreboard_deaths", SCOREBOARD_DEATHS_X, 40, .2, ITEM_ALIGN_LEFT, 1 1 1 1) +ITEM_DVAR("ui_scoreboard_assists", SCOREBOARD_ASSISTS_X, 40, .2, ITEM_ALIGN_LEFT, 1 1 1 1) +ITEM_DVAR("ui_scoreboard_damages", SCOREBOARD_DAMAGE_X, 40, .2, ITEM_ALIGN_LEFT, 1 1 1 1) +ITEM_DVAR("ui_scoreboard_grenades", SCOREBOARD_GRENADES_X, 40, .2, ITEM_ALIGN_LEFT, 1 1 1 1) +ITEM_DVAR("ui_scoreboard_plants", SCOREBOARD_PLANTS_X, 40, .2, ITEM_ALIGN_LEFT, 1 1 1 1) +ITEM_DVAR("ui_scoreboard_defuses", SCOREBOARD_DEFUSES_X, 40, .2, ITEM_ALIGN_LEFT, 1 1 1 1) +ITEM_DVAR("ui_scoreboard_ping", SCOREBOARD_PING_X, 40, .2, ITEM_ALIGN_LEFT, 1 1 1 1) diff --git a/zip/main/server.cfg b/zip/main/server.cfg index f24a79a..9c20395 100644 --- a/zip/main/server.cfg +++ b/zip/main/server.cfg @@ -38,10 +38,10 @@ set g_gametype "sd" // sd, dm, tdm, hq, ctf, htf, re, strat set pam_mode "comp" // Hostname -set sv_hostname "Awesome zPAM3.31 server" +set sv_hostname "Awesome zPAM3.32 server" // Message of the Day -set scr_motd "Welcome. This server is running zPAM3.31\nhttps://github.com/eyza-cod2/zpam3" +set scr_motd "Welcome. This server is running zPAM3.32\nhttps://github.com/eyza-cod2/zpam3" // Server password set g_password "" @@ -302,6 +302,7 @@ set scr_semiautomatic_allow_drop 1 set scr_smg_allow_drop 1 set scr_mg_allow_drop 1 set scr_shotgun_allow_drop 0 +set scr_pistol_allow_drop 1 // Allow grenade / smoke drop when player die set scr_allow_grenade_drop 1 diff --git a/zip/main/zpam331.iwd b/zip/main/zpam332.iwd similarity index 67% rename from zip/main/zpam331.iwd rename to zip/main/zpam332.iwd index 80df1ec..b8e3a7c 100644 Binary files a/zip/main/zpam331.iwd and b/zip/main/zpam332.iwd differ diff --git a/zip/readme.txt b/zip/readme.txt index fa8caa2..1be95f1 100644 --- a/zip/readme.txt +++ b/zip/readme.txt @@ -1,13 +1,13 @@ Installation Extract files into following locations: - - ./Call of Duty 2/main/zpam331.iwd + - ./Call of Duty 2/main/zpam332.iwd - ./Call of Duty 2/main/zpam_maps_v2.iwd (*required only for 1.3 game version) - ./Call of Duty 2/main/server.cfg Add +exec server.cfg into command line arguments and edit the server.cfg file to configure your server. For game version 1.3: - - Mappack file zpam_maps_v2.iwd needs to be included in main folder. What is zpam_maps_v1.iwd file? + - Mappack file zpam_maps_v2.iwd needs to be included in main folder. - Fast download must be enabled via these settings (custom URL may be used): - sv_wwwDownload 1 - sv_wwwBaseURL "http://cod2x.me/zpam" diff --git a/zpam331.zip b/zpam332.zip similarity index 99% rename from zpam331.zip rename to zpam332.zip index ed74dc1..facd40b 100644 Binary files a/zpam331.zip and b/zpam332.zip differ