top of page
SmallWorld_Map.png
SmallWorld_Carte.png

Small World is a medium-sized multiplayer map designed for intense, tactical 6v6 combat.
Set on a
movie set, players battle through miniature recreations of iconic locations such as Paris, Tokyo, New York, Los Angeles, and even London!

The design skillfully balances areas with predefined playstyles while allowing players to adapt to their own preferences. Players can engage in
close-quarters combat in Los Angeles and New York or opt for tactical mid-range firefights in Paris and Tokyo.

A standout feature of the map is the
interactive hangar door, which, when activated, plunges the map into darkness for a few seconds. This twist forces players to adapt their gameplay and introduces a secondary objective during the match. However, controlling this area won’t be easy—it’s very open, and danger can come from any direction!

SmallWorld_MapLayout.png

POI Overview

Explore the following points of interest based on key areas around Small World.

POI_SmallWorld_OpFor incursion.png
SmallWorld_MapSheet.png

Engine Overview

Map_InEngine_2DView

Here, you can see the 2D view of the map from the engine. Even though there is a lot of noise due to the map's geometry and multiple 3D models, it’s still possible to distinguish the five POIs and the two main spawns.

In-Engine

And here is the 3D view of the map, still within the engine.

In-Engine
Map_InEngine
In-Engine
In-Engine

Map Scripting

main()

{

    maps\mp\_load::main();

 

    ambientPlay("ambient_backlot_ext");

 

    game["allies"] = "sas";

    game["axis"] = "opfor";

    game["attackers"] = "axis";

    game["defenders"] = "allies";

    game["allies_soldiertype"] = "woodland";

    game["axis_soldiertype"] = "woodland";

 

    setdvar("r_specularcolorscale", "1");

 

    setdvar("r_glowbloomintensity0", ".25");

    setdvar("r_glowbloomintensity1", ".25");

    setdvar("r_glowskybleedintensity0", ".3");

    setdvar("compassmaxrange", "1800");

 

    // ALL THREAD FOR THIS LEVEL

    thread leftDoor();  

    thread rightDoor();  

    thread bigben();

 

    // Handle areas' automatic doors closing/opening

    thread areaDoors();

}

This part of the script is used to set up the global settings of the game (ambient sound, team names, soldier skins, map global luminosity, etc.).

At the end, you can find the three threads I used for the button to interact with the hangar doors, as well as the sliding button that hides it.
AKA leftDoor (handling the left hangar door), rightDoor (handling the right hangar door), and bigben (handling the hidden button located on Big Ben in London).

The last thread handles the movement of the "area's doors".

This script handles the hidden Big Ben button. When a player or AI approaches, it moves 50 units up for 4 seconds. It can't be reactivated, controlled by 'level.bigbenActivated'.

// Handle the big ben's hidden hangar's door button

bigben()

{

    level.bigbenActivated = 0; // Set bool as false

    bigben = getent("bigben_button", "targetname"); // Retrieve the button for big ben

    bigben_trigger = getent("trigger_bigben_button", "targetname"); // Retrieve the trigger for the big ben's button


 

    while (1)

    {

        if (level.bigbenActivated == 0)  // Check if it hasn't been activated yet

        {

            bigben_trigger waittill("trigger");  // Wait for the trigger event

 

            level.bigbenActivated = 1;  // Set the bool as true for ever as I want the trigger to be activated only once

 

            // Move 50 units along the Z-axis over 4 seconds

            bigben movez(50, 4, 1, 1);

            wait(2);  // Wait for movement to finish

 

        }

        else

        {

            wait(0.1);  // Avoid hogging CPU if nothing is happening

        }

    }

}

Those two threads handles the left hangar's and the right hangar's door movement on the X axis.

// Handle the left hangar's door​

leftDoor()

{

    leftdoor = getent("leftdoor", "targetname"); // Retrieve the left door

    leftdoor_trigger = getent("left_trigger", "targetname"); // Retrieve the trigger for the left door


 

    while (1)

    {

        leftdoor_trigger waittill("trigger");  // Wait for the trigger event

 

    iprintlnbold("Moving Hangar's Doors"); // Feedback for hangar's door

 

        // Move 440 units along the X-axis over 10 seconds

        leftdoor movex(440, 10, 1, 1);

        wait(30);  // Wait duration before closing the left door

 

        leftdoor movex(-440, 10, 1, 1);

        wait(2);  // Wait for movement to finish

    }

}

// Handle the right hangar's door

rightDoor()

{

    rightdoor = getent("rightdoor", "targetname"); // Retrieve the right door

    rightdoor_trigger = getent("right_trigger", "targetname"); // Retrieve the trigger for the right door


 

    while (1)

    {

        rightdoor_trigger waittill("trigger");  // Wait for the trigger event

 

        // Move -440 units along the X-axis over 10 seconds

        rightdoor movex(-440, 10, 1, 1);

        wait(30);  // Wait duration before closing the right door

 

        rightdoor movex(440, 10, 1, 1);

        wait(2);  // Wait for movement to finish

    }

}

This thread handles the movement of the area's doors, which are triggered when the activator is shot.
Each thread handles the doors of a specific area to ensure that all of them can be activated simultaneously if needed.

// THE FOLLOWING HANDLES THE AREA'S DOOR CLOSING WHEN SHOOTING AT THE ACTIVATOR

​

shootableDoorsActivatorParis()

{

    doorsInteractableParis_trigger = getent("doorInteractableParis_trigger", "targetname");

    level.ParisCanBeActivated = 1; // PARIS CAN BE ACTIVATED ON START

    // Paris' doors

    leftsmalldoorParis = getent("leftsmalldoorParis","targetname");

    rightsmalldoorParis = getent("rightsmalldoorParis","targetname");


 

    // Constantly check

    while (1)

    {

        // ONLY PARIS WORKS, FOR SURE JUST A LOGIC PROBLEM, TO CHECK

 

        // PARIS DOORS

        doorsInteractableParis_trigger waittill("trigger");  // Wait for the trigger event

        if(level.ParisCanBeActivated == 1)

        {

            iprintlnbold("Moving Paris");

            level.ParisCanBeActivated = 0;

            leftsmalldoorParis movex(200,5,1,1);

            rightsmalldoorParis movex(-200,5,1,1);

 

            wait(10);

            leftsmalldoorParis movex(-200,5,1,1);

            rightsmalldoorParis movex(200,5,1,1);

 

            wait(5);

            level.ParisCanBeActivated = 1;

        }    

    }

}

 

shootableDoorsActivatorTokyo()

{

    doorsInteractableTokyo_trigger = getent("doorInteractableTokyo_trigger", "targetname");

    level.TokyoCanBeActivated = 1;

    // Tokyo's doors

    leftsmalldoorTokyo = getent("leftsmalldoorTokyo","targetname");

    rightsmalldoorTokyo = getent("rightsmalldoorTokyo","targetname");


 

    // Constantly check

    while (1)

    {

        // TOKYO DOORS

        doorsInteractableTokyo_trigger waittill("trigger");  // Wait for the trigger event

        if(level.TokoyCanBeActivated == 1)

        {

            iprintlnbold("Moving Tokyo");

            level.TokyoCanBeActivated = 0;

            leftsmalldoorTokyo movex(200,5,1,1);

            rightsmalldoorTokyo movex(-200,5,1,1);

 

            wait(10);

            leftsmalldoorTokyo movex(-200,5,1,1);

            rightsmalldoorTokyo movex(200,5,1,1);

 

            wait(5);

            level.TokyoCanBeActivated = 1;

        }  

    }

}

 

shootableDoorsActivatorNY()

{

    doorsInteractableNY_trigger = getent("doorInteractableNY_trigger", "targetname");

    level.NYCanBeActivated = 1;

    // NY's doors

    leftsmalldoorNY = getent("leftsmalldoorNY","targetname");

    rightsmalldoorNY = getent("rightsmalldoorNY","targetname");


 

    // Constantly check

    while (1)

    {

        // NY DOORS

        doorsInteractableNY_trigger waittill("trigger");  // Wait for the trigger event

        if(level.NYCanBeActivated == 1)

        {

            iprintlnbold("Moving NY");

            level.NYCanBeActivated = 0;

            leftsmalldoorNY movex(200,5,1,1);

            rightsmalldoorNY movex(-200,5,1,1);

 

            wait(10);

            leftsmalldoorNY movex(-200,5,1,1);

            rightsmalldoorNY movex(200,5,1,1);

 

            wait(5);

            level.NYCanBeActivated = 1;

        }        

    }

}

 

shootableDoorsActivatorLA()

{

    doorsInteractableLA_trigger = getent("doorInteractableLA_trigger", "targetname");

    level.LACanBeActivated = 1;

    // LA' doors

    leftsmalldoorLA = getent("leftsmalldoorLA","targetname");

    rightsmalldoorLA = getent("rightsmalldoorLA","targetname");


 

    // Constantly check

    while (1)

    {

        // LA DOORS

        doorsInteractableLA_trigger waittill("trigger");  // Wait for the trigger event

        if(level.LACanBeActivated == 1)

        {

            iprintlnbold("Moving LA");

            level.LACanBeActivated = 0;

            leftsmalldoorLA movex(200,5,1,1);

            rightsmalldoorLA movex(-200,5,1,1);

 

            wait(10);

            leftsmalldoorLA movex(-200,5,1,1);

            rightsmalldoorLA movex(200,5,1,1);

 

            wait(5);

            level.LACanBeActivated = 1;

        }      

    }

}

Improvements and Next Steps:

- Conduct Closed Playtests: Run multiplayer playtests to gather gameplay data, assess balance, and fine-tune the design to enhance the player experience.

- Optimize Lighting: Adjust in-engine lighting for better visibility and to enhance the map’s atmosphere.

- Polish Visuals: Apply final textures and models to complete the map’s aesthetics.

- Reflect on Player Flow: Document insights from playtesting regarding movement flow and chokepoints, applying them to refine future map designs.

bottom of page