Tag Archives: round

Eliminating Teams

So far one can win rounds by defending or destroying the goals.
Another aspect of the gameplay is eliminating the whole opponent team.


Until now players immediately respawn as soon as they are eliminated, like that you just can’t eliminate all opponents.
So it’s needed to not spawn players anymore as soon as the round has started. This leads to spectating for the rest of the round which might not be fun for some players so I also added a setting to enable respawning during rounds. (As I said this will automatically prevent winning rounds by eliminating the opponent team.)

When the script is about to spawn a player I simply check if the StartTime is over:

if (!S_EnableRoundRespawn && Now > StartTime) {
     // Round has already started
     continue;
}

Now all members of a team can be eliminated which will lead to a win for the other team.


For knowing how many players of each team are alive I will use the property ClansNbPlayersAlive of CSmMode.
In the round end conditions I check if this numbers drops to 0 for a team and appoint the respective opponent team to the round winner.

Pay attention to a case where a team doesn’t immediately lose by being eliminated!
If the attacking team already planted the bomb it can still win because the defense has to defuse the bomb in order to save the goal and win the round. Because of this I protect the attacking team from losing as long as the bomb is planted.


In my SpeedBall game mode I implemented Friendly Fire which brought the competitive play to another level because you have to care even more about each shot you make to not hit your team members.
Defusing will have the same feature because I really like it. ;)
It can be easily disabled via a new script setting (which is in fact disabled by default).

For preventing hitting team members I checked if an OnHit event represents a hit between players of the same team and discard the event if it’s the case.
From now on the script only checks it as long as the FriendlyFire setting is disabled. While it’s enabled the events will still be handled and passed on leading to damage for the victim.

if (!S_FriendlyFire && Event.Shooter.CurrentClan == Event.Victim.CurrentClan) {
     // Invalid Team Hit
     Discard(Event);
     continue;
}

As players who are hitting their own team members shouldn’t be rewarded for that action I grant them negative points leading to a loss of total points.

if (Event.Shooter.CurrentClan == Event.Victim.CurrentClan) {
     // Team Hit
     Points *= -1;
}

That’s all that needs to be done for friendly fire! An easy but great feature.


During testing the mode you might have noticed that you can’t press backspace yet.
That’s caused by the fact that I Discard() all events that I don’t explicitly handle.
Whenever a player presses backspace there is an OnPlayerRequestRespawn event risen which I from now on simply PassOn().

case CSmModeEvent::EType::OnPlayerRequestRespawn: {
     // Player wants to be despawned
     PassOn(Event);
}

Now you can be despawned by pressing backspace. Keep in mind that you will have to spectate for the rest of the round if the respawning during rounds is disabled. ;)


I’ve also added some delay between rounds to let players breathe a bit. ;)

MB_Sleep(1000);

The function MB_Sleep() is implemented in the ModeBase (a general hint for that is the MB_ prefix) and lets the script wait for the given amount of milliseconds.


You can find the new version of the script here: Defusing6.Script.txt

Have fun eliminating your opponents (and not your team members! :P).

Preparing the Playground

Having built the map type and a first script test map I will let the mode load and prepare the map properly and let players spawn in their correct spawns.

When the match is about to start I call my own function PrepareMap(). The function initialises the “Bases” of the map and collects all spawns and goals in global arrays.
I save the blocks because then I don’t have to search for them when I need them: For example when I want to check if a player is planting the bomb.
Pay attention to the fact that instead of saving the blocks I only save their ids. It’s an important approach that I will explain in another post.

The ids of the spawn blocks are saved in a two-dimensional array according to their orders which have been set by the map editor while building the map.
So I know which spawns belong to which team.

As bomb spots are represented by goal posts I save their ids as well in an additional array. This one doesn’t need to have any special keys because during each round only one team attacks and tries to plant the bomb while the other team needs to defend. There is no “owning” of goals involved.

Another global variable is the number of the currently attacking team.
This number is generated randomly for the first round of each match and switches between 1 (blue) and 2 (red) before each following round.
So Defusing will for now let the attacking and defending team switch while in the Bomb Defuse mode of Counter Strike you choose your team at the beginning of a match and you will always defend or attack based on that choice.
Later I will probably add a script setting that allows you to use the Counter Strike game play.

In order to properly switch sides I switch the spawn arrays. That may be difficult to understand so I will take a closer look at the idea behind it.

Imagine the spawns array like that:
G_ClanSpawnIds =
[1 => [SpawnId11, SpawnId12], // Spawns Team 1
2 => [SpawnId21, SpawnId22]]; // Spawns Team 2

This is how the array looks after the PrepareMap() function. In the array saved for the key 1 spawn ids for the attacking side are saved while key 2 holds the defender spawns.

Start: The blue team (clan 1) attacks. When I need to spawn a player I can simply take the array referenced by the current clan of the player.

declare SpawnIds = G_ClanSpawnIds[_Player.RequestedClan];

Now I can easily choose one out these spawn ids in order to find a correct spawn for the player.

// Choose a random id out of the array
declare SpawnId = G_ClanSpawnIds[MathLib::Rand(0, G_ClanSpawnIds.count-1)];

// Take the spawn block with the chosen id
declare Spawn <=> BlockSpawns[SpawnId];

The round ends.
For taking all necessary steps before the next round starts if have a function PrepareRound().
An example is that teams need to switch sides, so in order to accomplish that I will simply switch the spawn arrays saved for the keys 1 & 2.

declare Temp = G_ClanSpawnIds[1];
G_ClanSpawnIds[1] = G_ClanSpawnIds[2];
G_ClanSpawnIds[2] = Temp;

Thanks to these 3 lines I don’t have to worry about finding a proper spawn for a player during the running match because I can simply refer to the array of spawns referenced by her/his current/requested clan number.

Additionally to collecting and managing the spawns and poles I constantly update the Clan of the Bases.
So what exactly are “Bases”?
Well, when a map is loaded the game itself automatically connects blocks and pools them into Bases. The blocks considered for these collections are all block types that have lights or colourable elements on them. Especially Spawn, Goals, Heal/Laser/Arrow Pads, Speed Paths and similar stuff.

The class CSmBase has a property Clan that can be used to colour the blocks connected by that base. This colouring gives the map a better look as you spawn in or around blocks that are coloured like your own team. You feel like actually defending your own base instead of just fighting for no reason. That’s why I always try to pay attention to proper colouring of bases.

Each CSmBase needs to be “activated” first though. That’s easily done by setting it active during the preparation of maps. It will turn on the lights of the blocks so that you will be able to see their colours.

Base.IsActive = True;
Base.Clan = 1; // Base will have color of Team 1 (usually Blue)

Now we got a proper map on which the action will take place. Next step will be to actually let the action begin. :)
You can find the current version of the script here: Defusing3.Script.txt

It’s probably quite difficult to understand the steps I’m taking only by reading the posts. A suggestion by me would be to actually load up the script ingame and analyse what the lines I added do. Maybe even try to play around with other values like switching the Base coloring by changing their “Clan”.

I’m sorry if anything is badly described. I still need to figure out which parts I have to explain extensively and which I can leave behind.

Cheerio,
steeffeen