[Workshop Mode] Counterwatch_Rialto v1.0

Note: Despite my best efforts to reduce the risk of server crashes, the game might still crash at times, especially near the end of a match if a lot of players joined and left during the game or if capture points switched sides a lot. Running the mode with fewer players should reduce the risk that the game will crash.

I wanted to see if creating a game mode with custom weapons that use some of the mechanics found in other FPS games would be possible in the workshop while at the same time trying to open up a more linear Overwatch payload map with choke points to make it a suitable map for a capture points mechanic.

Counterwatch_Rialto (by Delwion#2667)

Share Code (v1.0): DEF01

1. Game Mode Description

Custom weapons, custom capture points, and friendly fire is ON! Earn money by damaging and killing your opponents with a variety of weapons and lead your team to victory in a battle that takes place all over Rialto! Except for one tiny part: No fighting in the Gelateria!

Counterwatch_Rialto_Control is a round-based team vs team capture point map for up to 8 players (4 per team) where custom weapons and protective equipment can be purchased at the beginning of each round. Money can be earned by damaging and killing enemies and by staying near a capture point while your team holds it. Damage and kills grant extra money near a capture point. Team killing is possible but will not go unpunished if done repeatedly.

2. Controls

Inside the spawn room:

  • Press Ability 2 (E) to go to next entry shop weapons list.

  • Press Ability 2 (E) + Ability 1 (Shift) to go to previous entry shop weapons list.

  • Press Interact (F) near an in-world text to purchase a weapon or protective equipment.

In combat:

  • Hold Primary Fire (left mouse button) : Fire

  • Hold Secondary Fire (right mouse button): Aimed mode – increased accuracy but lower movement speed

  • Press Ultimate (Q) to switch to your next weapon (if you have multiple weapons).

  • Press Ability 2 (E): Medkit – heal yourself for 50 health total over 1.5 seconds (cooldown: 20 seconds)

  • Reloading is automatic as long as a player is not sprinting or firing (sprinting or firing restarts the reload time).

3. Custom Weapons and Protective Equipment

Firing accurately with custom weapons in this game mode takes some practice. It may help to aim a bit ahead in the direction your target is moving. Headshots deal 2x damage, but a helmet (called “Critical Protected” in the game) will protect players against headshots from most weapons.

Holding left-click for a while will reduce accuracy with every shot (the bloom value is added to the current spread value), so it helps to fire in bursts. Some weapon will be a lot more accurate in aimed mode (sniper rifles have bad accuracy when not using aimed mode).

1 Mercy 2 McCree 3 Tracer 4 Sombra 5 Reaper 6 Roadhog 7 Baptiste 8 Soldier 9 Ashe 10 Widowmaker 11 Bastion
Weapon type Pistol Pistol SMG SMG Shotgun Shotgun AR AR SR SR MG
Price 500 650 1500 2350 1700 3000 2250 2500 2750 4750 5750
Rate of fire (in rounds per minute) 400 200 750 857 68 240 800 600 48 41 600
Number of pellets/shots per burst 9 pellets 8 pellets 3 shots per burst
Magazine capacity 12 7 30 50 8 7 18 30 10 10 100
Reload Time (in seconds) 2.7 2.2 3 2.1 4.6 2.8 2.5 2.5 2 2.5 4.7
Movement speed 100 100 100 96 88 96 88 88 104 84 88
Movement speed in aimed mode 75 75 75 48 66 48 44 44 52 42 44
Bloom per shot 0.2 0.135 0.125 0.15 0 0 0.1 0.12 0 0 0.15
Min spread (in angle degrees) 0.1 0.1 0.2 0.2 2.2 2.8 0.1 0.12 0.3 2 0.25
Max spread (in angle degrees) 0.8 0.5 2.25 2.75 2.2 2.8 0.5 2 0.3 2 3
Max damage (per pellet for shotguns) 36 40 25 20 18 15 30 36 74 116 32
Min damage (per pellet for shotguns) 18 20 15 10 6 5 15 18 50 80 16
Damage drop off start distance 10 20 10 5 5 5 20 15 25 35 25
Damage drop off end distance 35 40 25 20 15 20 50 40 50 70 50
Spread modifier in aimed mode 0.1 0.1 0.5 0.5 0.65 0.75 0.5 0.6 0 0 0.15
Spread modifier when moving (while not crouched) 1.25 1.5 1.25 1.5 1.25 1.1 3 2.5 1.75 3 1.25
Spread modifier while jumping (not on ground) 1.75 2 2 2.25 1.75 1.5 6 4 3 5 2.25
Ignores crit protection Yes Yes Yes
Best at range close to mid mid close to mid close to mid close close mid to high mid mid to high high mid

Protective equipment:

  • Body Armor (called „Life Up“ in game) will increase maximum health to 200 until your next death (the default max health amount in this game mode is 150).

  • Helmet (called “Critical Protected” in game) will protect a player against critical hits from most weapons.

4. User Interface

At the top left corner, players can see their currently equipped weapon (hero name), the amount of shots they have left, as well as the magazine capacity of the currently equipped weapon (small text; lower line), and the amount of money owned (smallest text; upper line).

5. The Phases

5.1. Begin of a Round

All players receive a free 1500 money at the begin of each round (on top of all the money they already have).

5.2. Preparation

All players start in the same spawn room (enemies are invisible; other players cannot be harmed in the spawn room) with no weapon equipped (which is displayed as hero “Doomfist”). Players can spend their money to purchase weapons and protective equipment (see 2. Controls).

When a weapon is purchased, it is automatically equipped and always has a full magazine.

The two blue teleporters allow players to leave the spawn room early (they appear at a random one of 38 spawn points) and start fighting, before any objectives appear, but once a player has left the spawn room they cannot go back in there until the current round ends.

After about 40 seconds, all players who haven’t left the spawn room yet will be teleported out. Players who haven’t purchased a weapon at that point will automatically buy a Mercy pistol for 500 money.

5.2. Combat

Soon after the preparation phase has ended, the first objective will spawn at a random one of 24 capture point spots with a green flag icon indicating its position.

When a player gets on an objective it will change to the player’s team color after a short delay and count as held by that player’s team now. Every two seconds, all players within a 7.5 meters radius of an objective their team owns will receive 25 money and the capture percentage will increase by 5%. Once the percentage has reached 100%, the objective is successfully captured and everyone in the team that captured it receives 100 money.

If both team are on a control point, it will switch back to neutral stay again and stay there until one of the teams has gotten hold of the point again. Both teams have an individual capture progress in % which continues from the previous value, should a team that owned the control before get back control over it.

A round ends as soon as either team has captured two objectives. All players get teleported back to the spawn room and another preparation phase of about 40 seconds begins as soon as the last player has teleported in.

5.3. Death

Players who die will respawn at a random one of 38 spawn points. They will also lose their Body Armor and Helmet, but keep all their weapons. The currently equipped weapon will always have a full magazine when respawning (other weapons still have as many shots left as they had when the player last used them).

(The respawn time is extremely low with 1 second, since corpses block ray cast hit protection as if they player were still standing there with their full body height.)

5.4. Victory Conditions

The game will end when either team has won 3 rounds, or when the match time reaches 30 seconds (can’t let it reach 0 seconds or the game would crash ^^). If both teams have won the same number of rounds when the timer reaches 30 seconds then the match is declared a draw.

6. Navigating the Map

Purple teleporters are shortcuts that link certain spots on the map.

Blue teleporters lead out of the spawn room (there is no way back in until the next round begins).

White teleporters allow players to enter areas that normally would be inaccessible to their team (spawn rooms of the opposing team).

Red teleporters block players from re-entering the spawn room (all players will get ported back in when a round ends).

It’s probably a good idea to explore the map a quickly on your own before hosting or joining a real game, so you can see where some of the purple teleporters lead. If not then the first match could be a very chaotic experience.

7. Friendly Fire

Players can damage and kill other players of the same team with custom weapons. A player who hurts or kills an ally, will however lose money (more than they would have gained from dealing the same amount of damage to or from killing the same number of enemies). On top of that, excessive team killers (and damagers) will be punished.

8. Variables

GLOBAL VARIABLES
Variable Function
A Current Game phase:
0=Game Started
1=Initialize Shopping Phase
2=Shopping Phase Ongoing
3=Spawn New Objective
4=Objective Phase Ongoing
5=End of Objective Phase
B Array:
0: The time (match time) when players will be kicked from the spawn room
1: New objective status (0=no objective is up; 1=not owned; 2=owned by team 1; 3=owned by team 2)
2: Team Killer for Big Message (needs to be saved temporarily or the message is too slow and will show the wrong player)
3: *** unused ***
4: The time (match time) when the objective status wil be checked next
5: forward
6: right
7: backward
8: left
9: Previous/current objective status (0=no objective is up; 1=not owned; 2=owned by team 1; 3=owned by team 2)
10: Match time when team that owns the objective will get the next XP tick
11: *** unused ***
12: Temp objective status (0=no one on objective; 1=team 1 only on objective; 2=team 2 only on obj.; 3=both teams on objective)
C Array with objective positions
D *** unused ***
E *** unused ***
F *** unused ***
G Weapons Array:
0: Mercy
1: McCree
2: Tracer
3: Sombra
4: Reaper
5: Roadhog
6: Baptiste
7: Soldier
8: Ashe
9: Widowmaker
10: Bastion
(11: Doomfist)
12-24: x/y/z component: Fire rate / Price / Magazine size (ammo)
25-35: x/y/z component: Cooldown / Reload speed / Number of pellets
36-46: x/y/z component: Aimed mode speed modifier (1=100%) / Move speed (in %) / Bloom per shot
47-57: x/y/z component: Min spread / Max spread / Damage drop off modifier (the amount of damage the weapon loses for every meter over the start drop off distance)
58-68: x/y/z component: Spread modifier scope (1=100%) / Spread modifier moving (1=100%) / Spread modifier in air (not on ground; 1=100%)
69-79: x/y/z component: Min damage / Max damage / start damage drop off distance
80-103: x/y/z component: Teleporter destinations (the position a teleporter will teleport a player to)
104-141: x/y/z component: Orientation for regular teleporters (direction a player will face after using the corresponding teleporter; 0=forward; 1=right; 2=backward; 3=left) / Orientation for spawn points (direction a player will face when spawning at the corresponding spawn point) 0=forward; 1=right; 2=backward; 3=left)
142-179: Spawn point positions (x/y/z)
H Array with shop positions
I Score/objectives captured - team 1
J Score/objectives captured - team 2
K Rounds won - team 1
L Rounds won - team 2
M All Players (if objective is owned by team 1; otherwise empty; used to show objective effects in color of team 1)
N All Players (if objective is owned by team 2; otherwise empty; used to show objective effects in color of team 2)
O All Players (if neutral objective is up; otherwise empty; used to show green, neutral objective effects)
P Array with teleporter positions
0-23: Regular teleporters (purple)
24-25: Spawn room blockers (red)
26-27: Spawn room teleporters (blue)
28+: Through wall teleporters (white)
Q Capture percentage displayed by in-world text
R Temp array; list of all players that will get XP
S *** unused *** (was: ranking array that ranked players according to (deaths - kills - assists * 0.5; player with lowest value was first in ranking)
T Temporary array (array of objective positions that are at least 50 meters away from previous objective)
U Capture percentage team 1
V Capture percentage team 2
W *** unused ***
X Objective position
Y Objective position + vector up (0/1/0)
Z Y component of objective position - 1
PLAYER VARIABLES
Variable Function
A Array with current weapon stats
0: Fire rate
1: Max damage
2: Min damage
3: Start damage drop off distance
4: Damage drop off modifier
5: Reload time of current weapon
6: Weapon’s default min spread
7: Weapon’s default max spread
8: Weapon’s bloom per shot
9: Spread modifier moving
10: Spread modifier aimed mode
11: Spread modifier in air (not on ground)
12: Aimed mode movement modifier
13: Shots per burst
14: Fire cooldown (burst weapons)
15: Does the current weapon ignore headshots? (0=no; 1=yes)
16: Command to deal damage (true=command given)
17: Amount of damage to deal
B Array Purchased Weapons/Items:
0: Item 0 (Mercy) purchased (false=not purchased; true=purchased)
1: Item 1 (McCree) purchased (false=not purchased; true=purchased)
2: Item 2 (Tracer) purchased (false=not purchased; true=purchased)
…
11: Body Armor purchased (false=not purchased; true=purchased)
12: Helmet purchased (false=not purchased; true=purchased)
C Player that got hit with custom fire (returns a weird buggy value if no player is hit; should be null, but isn’t)
D Current spread
E Current min spread to use
F Current max spread to use
G Array of nearby teleporters (within 30 meters range)
H Deaths
I Ray cast hit position
J Current damage
K Firing direction
L Ray cast hit position
M Y Distance between enemy head (enemy position + vector (0/1.61/0) and hit position (player variable L)
N 0: Is Secondary Fire pressed (false=no; true=yes)
1: Is Q pressed (false=no; true=yes)
2: Has player purchased at least one weapon? (false=no; true=yes)
3: Time (match time) at which the player will respawn
4: Index of picked spawn location
5: Temp (player who killed player that died)
6: Command to upgrade match time based values (true=command given) *** now unused ***
7: *** unused ***
8: Is player blocked from healing and firing? (false=no; true=yes, blocked, inside gelateria or banned, this is checked after using a white through wall teleporter)
9: Has one second passed since the first spawn? (false=no; true=yes) *** now unused ***
10: Is players inside shopping room? (false=no; true=yes)
11: Temp index of used regular teleporter
12: XP modifier
13: Was an enemy hit (when firing) (false=no; true=yes)
14: Command to port to spawn room (true=command given)
15: Selected item in shop
16: *** unused ***
17: Current Item in shop
18: Currently in shop or not (false=not in shop; true=in shop) *** now unused ***
19: Hero of selected shop weapon (in spawn room shop)
20: Command to upgrade XP modifier (true=command given) *** now unused ***
21: Distance to objective
22: Command to upgrade weapon stats
23: Count shot per burst or per bullet? (false=per bullet; true=per burst)
24: Number of shots remaining in current burst
25: The time (match time) when the player can fire again (cooldown of burst weapons)
26: Distance between eye position of player and hit position (used to calculate damage)
27: Is player in air? (false=no; true=yes)
28: Is player moving but not crouched? (false=no; true=yes)
29: Command to update min and max spread (true=command given)
30: Spread multiplier to use (1 by default)
31: Command to kick player from spawn room (1=command given when time elapsed; 2=command given because player stepped into a blue teleporter, no wait time if 2)
32: Price of currently selected weapon (in spawn room shop)
33: Closest shop position *** unused now ***
34: The time (match time) when the game will update the teleporter array (player variable G) for the even player
35: Number of Teamkills
36: Damage dealt to team members
37: Individual wait time of player before kick/new round respawn (the game would crash instantly if it kicked all players from the spawn room or brought them back in there at the same time)
38: Command to create player’s flag distance in-world text (true=command given) *** unused now ***
39: Distance to objective (updated once every 3 seconds)
40: Capture XP (true=check for XP)
O Kills (enemies only, team kills deduct 1 from this value)
P Current default movement speed
Q Money
R Ammo Clip Size of current weapon
S Array:
0: Has the event player dealt damage to enemy in slot 0? (0=no; 1=yes)
1: Has the event player dealt damage to enemy in slot 1? (0=no; 1=yes)
etc.
6: Slot of last opposite team player to deal damage to this player + 1
T Assists
U Bullets left with current weapon
V Current hero
W Currently equipped weapon/current weapon
X Array:
0=Bullets left in weapon 0 (Mercy pistol)
1=Bullets left in weapon 1 (McCree pistol)
etc.
Y Number of pellets/bullets remaining in current burst fire
Z The time when weapon reload will finish

8. Things I learned about the workshop while creating this game mode (unsorted list including some frustration, read at your own risk):

Click to read
  • It’s not possible, as far as I can tell after a lot of testing, to implement a recoil mechanic for custom weapons in a satisfying way. The SET FACING action will add a rubberbanding-like effect to turning around. Only in a game mode where a player has a fixed facing direction would I consider adding something like recoil as a vertical impulse (vector UP). But not in normal aiming.
  • HUD texts are absolute performance killers!! Most of the time, 2 player-specific HUD texts and a few global ones are the absolute limit (12 players * 2 = 24 HUD texts; at least I think that’s how it works ><)! If your game crashes for unknown reasons and at times where it seemingly makes no sense, HUD texts may be at least partially responsible for the crashes!!
  • Having a lower number of rules and conditions seems to help performance a bit (as opposed to having the same number of actions distributed over more rules).
  • Having values in HUD texts defined as "global variable x" instead of "value in array global variable x at index y" seemed to have quite an impact on performance.
  • It seems better (lower server load, may avoid crashes) to have one gigantic array in one global variable, than to have multiple large arrays in several global variables (as long as you don’t need to filter or sort the gigantic array or get the index of array values!).
  • Getting Y component or X component of anything seems to be very heavy on the server.
  • When using a custom camera (better don’t in any complex project, you will eventually have to remove it for performance reasons and will only be disappointed), make sure you define the position of the camera as something very simple like “Global Variable A”. Set a low Blend Speed and update global variable A with a complex calculation like once every 0.25 seconds. Never set complex calculations as camera “eye” or “look at” position. (This may be obvious to others but since I had to learn this the hard way I thought I might as well share my experience here :)).
  • The colors "Team 1" and "Team 2" are reversed on HUD texts (this appears to be a bug in the current workshop version).
  • In any complex workshop mode, USE "SET MATCH TIME(X)" WITH THE UTMOST CAUTION!! Especially if you have many conditions that compare a value to the current match time.
  • The hard part of making any “complex” workshop project is getting it to run without the server crashing. This requires an insane amount of testing and it’s very hard to know what exactly is causing a crash (very often it seems to be a combination of a lot of things).
  • My next workshop project will definitely be something a lot simpler and I’ll start with implementing the core mechanics of the game mode to the point where I have a working prototype that can run without making the server crash. I did this in Counterwatch as well, but then I started adding more complex HUD texts, better effects, and added all weapon stats that I needed for the real project in large arrays. This is when everything turned into a horrible nightmare of 50+ hours (yes, really) of server crashes, testing and trying to find the reason(s). (So yes, any future workshop projects of mine will probably be a lot simpler >< Hopefully. Hopefully, I am capable of learning…)

Mourning all the elements that I had to remove (these were fully implemented in the game mode already, but had to be removed to avoid server crashes), I post a small list of them here:

  • Health Packs that granted an equal amount of health and max health (up to a maximum value of 300), randomly respawned on any of the health pack locations that I had listed in an array for a part of the map already (this was tested and was working, including getting the player to the correct amount of health after collecting a health pack which required saving the previous health value if over default max health since the game will always set the current health to default max health if it is equal or higher than default max health when the action SET MAX HEALTH is executed). But I digress. It was fully implemented and working (and I obviously hated removing it from the game mode :)).
  • A custom zoom function on right-click that put the camera in front of the player (according to the weapon’s zoom value), however at least 2m back towards the player from the ray cast hit position in the player’s facing direction. Again, this was implemented and working, albeit a bit slow (it also allowed players to see through some obstacles with the zoom :), but it was fun to use).
  • HUD texts that showed the capture % of objectives in the color of the team that currently owned the capture point.
  • An HUD text that showed Kills, Assists, and Deaths as "Kill: x / Help: y / Death: z".
  • More complex HUD texts for Money, Current Weapon, Ammo and Shop In-world texts (including the strings “Money, Rounds, Item, Current Item, Price”).
  • A sphere effect for each weapon in the spawn room next to the corresponding In-world text that would only show up when the player was nearby and hadn’t bought the weapon yet. For each weapon type, the sphere had a different color (white=pistol, purple=SMG, yellow=shotgun, red=AR/MG, green=sniper rifle, blue=protective gear).
  • An HUD text that showed the current score (number of objectives captured for both teams) and the number of rounds won for each team.
  • An In-world text for each player that showed the distance of the player to the objective.
  • An In-world text that showed the capture percentage of the team that currently held the point.
  • Extra money gained in the moment when a capture point flipped.
  • A rule that would call for an update of the capture point status in the exact split second when a player stepped on the point.
  • The match time was being reset for each round and preparation phase.
  • Pressing <Interact> outside of the spawn room showed the current objectives and round score for the 2 teams as small message to the event player.
  • Pressing <Interact> while holding <Shift> showed the number of kills, assists, deaths, and the player’s rank (kills + assists * 0.5 – deaths; team kills give -1 kill) as small message to the event player (the game is actually still keeping track of kills, assists, and deaths for each player; there is just nothing left that makes these values visible to the player).

However, I am just glad now that I was able to keep all the remaining features and finally got the game to a state where it runs somewhat stable with 8 players!

9. Final Thoughts

Firing with custom weapons feels a bit clunky at first and the feedback with barely any firing or hit sounds is a bit low, but nonetheless I am happy with the result and think the weapons have a unique distinct feel to it, and after playing for a while you can get a lot better at aiming with them. I’m also happy with how the map was opened up and I especially like the secret alley that can be accessed via teleporters now.

Even though there’s a lot of teleporters, I think I haven’t overdone it and many of them open up paths that previously were dead ends (so there’s more than one way to get to each control point location). I also really like that both teams can access most spawn rooms and the fact that control points can spawn in 24 spots which adds variety to the gameplay. Of course, the result is not nearly as good as the real weapons/hero abilties in Overwatch or any other FPS game, but I still think this could be a fun mode to try out and play for while.

Originally posted on June 16th, 3:20 pm GMT

Edit: Global and player variables have been added to section 8: Variables. There is a chance that a few of the variables listed are actually not in use anymore. I had to remove/repurpose so many variables that I may have missed one or two.

1 Like

I noticed that rule conditions hooked to float values, which change on a very rapid tick rate, have a very high server impact.

Try putting match time on a HUD and see how often it changes.

Look at your conditions regarding match time. I would recommend creating a rule that ticks a “personal” match time on a slower (ex. 0.100) rate, which would lower the amount of events when those conditions need to be checked by the server. This racks up when you have multiple players doing the same rule.

Also the ordering of conditions on a rule have an impact on how often they are checked. So try putting frequently ticking conditions as last at the bottom, and the most rarely changing ones at the top.

Btw this server crash issue also happens on chase variables action, which is why I had to stop using them, and created my own set of “chasing rules” that do not tick so often and risk crashing the server. That might help you mitigate the issues in your other modes.

1 Like

Thank you! This is information is immensely helpful! I will try to optimize the rules in Counterwatch with a custom match time that ticks slower and pay attention to this in future projects.

Edit: About chasing variables: I almost entirely stopped using that action when I noticed problems in one of my first projects. I only chase a max of 1-2 global variables per game mode now, and only for a short amount of times.

Edit2: I changed all actions and conditions that refered to the match time in Counterwatch to refer to a global variable that served as custom “match time” instead and was updated once every 0.1 seconds. While the risk for server crashes did seem lower, this change unfortunately also introduced a new micro-stutter effect that was clearly visible in the movements of bots so I probably won’t implement it in Counterwatch, but will keep a closer eye on conditions that refer to the match time (or any other float values with a fast tick rate) in future projects.