Call of Duty 4: Vending Machine: Difference between revisions

From COD Modding & Mapping Wiki
Jump to navigation Jump to search
No edit summary
m (meh.)
 
(7 intermediate revisions by 2 users not shown)
Line 1: Line 1:
[[Category:Call of Duty 4]]
[[Category:Modtools]]
[[Category:Radiant]]
[[Category:Advanced Editing]]
[[Category:Scripting]]
{{warning_forpro}}
''By Kill3r''
''By Kill3r''
 
[[Image:rgn_warning.png|right]]
[[Image:Nutshell.png]] This tutorial will show you how to add a vending machine that when used heals you and a bottle pops out of it like in (or will be in) the rat_house_v2 map.
[[Image:Nutshell.png]] This tutorial will show you how to add a vending machine that when used heals you and a bottle pops out of it like in (or will be in) the rat_house_v2 map.
[[Image:warning.png]] This tutorial presumes that you already know how to create, compile, create the usual
    .gscs and .csvs and create the .ff for your maps.


   [[Image:warning.png]] REMEMBER: Anywhere that says "yourmapname" change to what your map is called, like mp_funny_bunny
   [[Image:warning.png]] REMEMBER: Anywhere that says "yourmapname" change to what your map is called, like mp_funny_bunny
Line 76: Line 79:


  Key: hintstring
  Key: hintstring
  Value: Press [^3USE^7] to have a drink
  Value: Press^3 [{+activate}] ^7to have a drink


  Key: targetname
  Key: targetname
Line 132: Line 135:


<pre>
<pre>
name,sequence,file,vol_min,vol_max,vol_mod,pitch_min,pitch_max,dist_min,dist_max,channel,type,probability,loop,masterslave,loadspec,subtitle,compression,secondaryaliasname,volumefalloffcurve,startdelay,speakermap,reverb,lfe percentage,center percentage,platform,envelop_min,envelop_max,envelop percentage,conversion
vender,,level/ac_unit_window_loop.wav,0.7,0.7,max,1,1,150,300,auto,streamed,,looping
vender,,level/ac_unit_window_loop.wav,0.7,0.7,max,1,1,150,300,auto,streamed,,looping
vender_drop,1,yourmapname/vender_drop1.wav,0.7,0.8,max,0.9,1,150,300,auto,,,
vender_drop,1,yourmapname/vender_drop1.wav,0.7,0.8,max,0.9,1,150,300,auto,,,
Line 143: Line 144:


Go to CoD4\raw\sound and make a new folder called yourmapname, in there place the 2 .wav sounds that can be downloaded (link at the bottom)
Go to CoD4\raw\sound and make a new folder called yourmapname, in there place the 2 .wav sounds that can be downloaded (link at the bottom)


== The Scripts ==
== The Scripts ==
Line 164: Line 164:


<pre>
<pre>
precache();                   // Call the precache function
precache(); // Call the precache function


    venders = getentarray("heal","targetname");    // Get all the entitys that have "heal" for their "targetname"
venders = getentarray("heal","targetname");    // Get all the entitys that have "heal" for their "targetname"
    for(i=0;i<venders.size;i++)
for(i=0;i<venders.size;i++)
        venders[i] thread vender();
venders[i] thread vender();
</pre>
</pre>


Line 176: Line 176:
main()
main()
{
{
    level.tweakfile = true;
level.tweakfile = true;
    setdvar("scr_fog_disable", "0");
setdvar("scr_fog_disable", 0);
    VisionSetNaked("mp_vending", 0);
VisionSetNaked("mp_vending", 0);


    mapsmp_load::main();
maps\mp\_load::main();
    mapsmp_compass::setupMiniMap("compass_map_mp_vending");
maps\mp\_compass::setupMiniMap("compass_map_mp_vending");


    ambientPlay("ambient_pipeline");
ambientPlay("ambient_pipeline");


    game["allies"] = "marines";
game["allies"] = "marines";
    game["axis"] = "opfor";
game["axis"] = "opfor";
    game["attackers"] = "axis";
game["attackers"] = "axis";
    game["defenders"] = "allies";
game["defenders"] = "allies";
    game["allies_soldiertype"] = "desert";
game["allies_soldiertype"] = "desert";
    game["axis_soldiertype"] = "desert";
game["axis_soldiertype"] = "desert";


    setdvar("r_specularcolorscale", "1" );
setdvar("r_specularcolorscale", "1" );
    setdvar("r_glowbloomintensity0",".1");
setdvar("r_glowbloomintensity0",".1");
    setdvar("r_glowbloomintensity1",".1");
setdvar("r_glowbloomintensity1",".1");
    setdvar("r_glowskybleedintensity0",".1");
setdvar("r_glowskybleedintensity0",".1");


    setdvar("compassmaxrange","2048");
setdvar("compassmaxrange","2048");


    precache();// Call the precache function
precache(); // Call the precache function


    venders = getentarray("heal","targetname");// Get all the entitys that have "heal" for their "targetname"
venders = getentarray("heal","targetname"); // Get all the entitys that have "heal" for their "targetname"
    for(i=0;i<venders.size;i++)
for(i=0;i<venders.size;i++)
        venders[i] thread vender();
venders[i] thread vender();
}
}</pre>
</pre>


Add this code UNDER the main() function
Add this code UNDER the main() function


<pre>
<pre>precache()
        if(!level.allow_vender)// If vending machines are not allowed then say a message
{
        {
if(getDvar(getDvar("mapname") + "_allow_vender") == "")
            player iPrintlnBold("^2Sorry, fat rats are not allowed on this server");
setDvar(getDvar("mapname") + "_allow_vender", 1); // This creates the dvar to enable the vending machines
            continue;
 
        }
if(getDvar(getDvar("mapname") + "_health_wait") == "")
setDvar(getDvar("mapname") + "_health_wait", 10); // This creates the dvar to set the time between being able to get health again
 
level.allow_vender = int(getDvar(getDvar("mapname") + "_allow_vender"));
level.vender_wait = int(getDvar(getDvar("mapname") + "_health_wait"));
 
for(i=1;i<5;i++)
precacheModel("com_bottle" + i); // Precache (load) the com_bottle1, com_bottle2, com_bottle3 and com_bottle4 models
 
level.venderbottles = [];
level.venderbottlescurrent = 0;
level.venderbottlesmax = 24; // Max bottles in the map at one time, try not to have this too high as it can cause lag and somtimes crash the server
}
 
vender()
{
self.targetname = undefined;
dir = getent(self.target,"targetname");
if(isDefined(dir))
{
temp = spawnStruct();
temp.origin = dir.origin;
temp.angles = dir.angles; // Spawn a struct which doesnt count as an entity, record the script_origin's origin and angles then delete the script_origin
dir delete();
dir = temp;
}
self.target = undefined;
 
randomMessages = []; // List of random messages when player has had a bottle recently, you can have as many of them as you want.
randomMessages[0] = "^2When was the last time you saw a fat rat?";
randomMessages[1] = "^1Careful! You'll break it!";
randomMessages[2] = "^3Oh no! There's none left!";
randomMessages[3] = "^4You're hungry ain't ya?";
randomMessages[4] = "^5Woof";
 
self playLoopSound("vender"); // Make the trigger play a loop sound
 
for(;;)
{
self waittill("trigger", player); // Wait until its triggered
if(player.sessionstate != "playing")// Make sure the player is playing
continue;
 
if(!level.allow_vender)// If vending machines are not allowed then say a message
{
player iPrintlnBold("^2Sorry, fat rats are not allowed on this server");
continue;
}


        if(isDefined(dir)) // If the script_origin is placed correctly in the map, then make a bottle pop out
if(isDefined(dir))// If the script_origin is placed correctly in the map, then make a bottle pop out
        {
{
            self playSound("vender_drop");   // Play the bottle drop sound
self playSound("vender_drop");// Play the bottle drop sound


            if(isDefined(level.venderbottles[level.venderbottlescurrent]))
if(isDefined(level.venderbottles[level.venderbottlescurrent]))
                level.venderbottles[level.venderbottlescurrent] delete();   // If we have gone over the limit for max bottle in the map, delete the oldest one
level.venderbottles[level.venderbottlescurrent] delete();// If we have gone over the limit for max bottle in the map, delete the oldest one


            level.venderbottles[level.venderbottlescurrent] = spawn("script_model",self.origin);       // Spawn the bottle
level.venderbottles[level.venderbottlescurrent] = spawn("script_model",self.origin);// Spawn the bottle
            level.venderbottles[level.venderbottlescurrent].angles = dir.angles;// Set the angles of the bottle
level.venderbottles[level.venderbottlescurrent].angles = dir.angles; // Set the angles of the bottle
            level.venderbottles[level.venderbottlescurrent] setModel("com_bottle" + (randomInt(4) + 1));    // Set random bottle model
level.venderbottles[level.venderbottlescurrent] setModel("com_bottle" + (randomInt(4) + 1));    // Set random bottle model
            point = dir.origin;
point = dir.origin;
            origin = level.venderbottles[level.venderbottlescurrent].origin + mapsmp_utility::vector_Scale(anglestoup(level.venderbottles[level.venderbottlescurrent].angles),4 + randomFloat(1));
origin = level.venderbottles[level.venderbottlescurrent].origin + maps\mp\_utility::vector_Scale(anglestoup(level.venderbottles[level.venderbottlescurrent].angles),4 + randomFloat(1));
            velocity = VectorNormalize(origin - point);// Calculate velocity and direction of the impact
velocity = VectorNormalize(origin - point);// Calculate velocity and direction of the impact
            velocity = mapsmp_utility::vector_Scale(velocity,10000 + randomInt(5000));
velocity = maps\mp\_utility::vector_Scale(velocity,10000 + randomInt(5000));
            level.venderbottles[level.venderbottlescurrent] physicsLaunch(point, velocity); // Make the bottle fly!
level.venderbottles[level.venderbottlescurrent] physicsLaunch(point, velocity);           // Make the bottle fly!


            level.venderbottlescurrent++;
level.venderbottlescurrent++;


            if(level.venderbottlescurrent >= level.venderbottlesmax)
if(level.venderbottlescurrent >= level.venderbottlesmax)
                level.venderbottlescurrent = 0;
level.venderbottlescurrent = 0;
        }
}


        if(isDefined(player.healthwait))// If the player has already used the vending machine then...
if(isDefined(player.healthwait))// If the player has already used the vending machine then...
        {
{
            num = randomInt(100);
player iPrintlnBold(randomMessages[randomInt(randomMessages.size)]); // display one of the rather insulting messages to the player.
            if(num < 20)
continue;
                player iPrintlnBold("^2When was the last time you saw a fat rat?");
}
            else if(num >= 20 && num < 40)
                player iPrintlnBold("^1Careful! You'll break it!");// Say one of these random messages
            else if(num >= 40 && num < 60)
                player iPrintlnBold("^3Oh no! There's none left!");
            else if(num >= 60 && num < 80)
                player iPrintlnBold("^4You're hungry ain't ya?");
            else
                player iPrintlnBold("^5Woof");
            continue;
        }


        player.healthwait = true;
player.healthwait = true;
        if(player.health < player.maxhealth)// If the players health is not at the max
if(player.health < player.maxhealth)// If the players health is not at the max
        {
{
            player.health = player.maxhealth;// Set the players health to the max
player.health = player.maxhealth;// Set the players health to the max
            player iPrintlnBold("^2mmm... ^1y^2u^3m^4m^5y^6!");// Say these messages if the player was healed
player iPrintlnBold("^2mmm... ^1y^2u^3m^4m^5y^6!");// Say these messages if the player was healed
            player iPrintlnBold("^1Health Restored!");
player iPrintlnBold("^1Health Restored!");
        }
}
        else
else
            player iPrintlnBold("^2You already have full health, but ^1y^2u^3m^4m^5y^6! ^2anyway!");// If the player already has full health then say this message
player iPrintlnBold("^2You already have full health, but ^1y^2u^3m^4m^5y^6! ^2anyway!"); // If the player already has full health then say this message
        player thread healthwait();
player thread healthwait();
    }
}
}
}


healthwait()
healthwait()
{
{
    self endon("disconnect");   // Kill the tread if the player disconnects
self endon("disconnect"); // Kill the thread if the player disconnects
    wait level.vender_wait;       // Wait how long level.vender_wait is
wait level.vender_wait; // Wait how long level.vender_wait is
    self.healthwait = undefined;   // Make self.healthwait undefined
self.healthwait = undefined; // Make self.healthwait undefined
}
}</pre>
</pre>


So, with all the code it should look like this:
So, with all the code it should look like this:
Line 280: Line 315:
main()
main()
{
{
    level.tweakfile = true;
level.tweakfile = true;
    setdvar("scr_fog_disable", "0");
setdvar("scr_fog_disable", 0);
    VisionSetNaked("mp_vending", 0);
VisionSetNaked("mp_vending", 0);


    mapsmp_load::main();
maps\mp\_load::main();
    mapsmp_compass::setupMiniMap("compass_map_mp_vending");
maps\mp\_compass::setupMiniMap("compass_map_mp_vending");


    ambientPlay("ambient_pipeline");
ambientPlay("ambient_pipeline");


    game["allies"] = "marines";
game["allies"] = "marines";
    game["axis"] = "opfor";
game["axis"] = "opfor";
    game["attackers"] = "axis";
game["attackers"] = "axis";
    game["defenders"] = "allies";
game["defenders"] = "allies";
    game["allies_soldiertype"] = "desert";
game["allies_soldiertype"] = "desert";
    game["axis_soldiertype"] = "desert";
game["axis_soldiertype"] = "desert";


    setdvar("r_specularcolorscale", "1" );
setdvar("r_specularcolorscale", "1" );
    setdvar("r_glowbloomintensity0",".1");
setdvar("r_glowbloomintensity0",".1");
    setdvar("r_glowbloomintensity1",".1");
setdvar("r_glowbloomintensity1",".1");
    setdvar("r_glowskybleedintensity0",".1");
setdvar("r_glowskybleedintensity0",".1");


    setdvar("compassmaxrange","2048");
setdvar("compassmaxrange","2048");


    precache();// Call the precache function
precache(); // Call the precache function


    venders = getentarray("heal","targetname");// Get all the entitys that have "heal" for their "targetname"
venders = getentarray("heal","targetname"); // Get all the entitys that have "heal" for their "targetname"
    for(i=0;i<venders.size;i++)
for(i=0;i<venders.size;i++)
        venders[i] thread vender();
venders[i] thread vender();
}
}


precache()
precache()
{
{
    if(getDvar(getDvar("mapname") + "_allow_vender") == "")
if(getDvar(getDvar("mapname") + "_allow_vender") == "")
        setDvar(getDvar("mapname") + "_allow_vender", 1);// This creates the dvar to enable the vending machines
setDvar(getDvar("mapname") + "_allow_vender", 1); // This creates the dvar to enable the vending machines


    if(getDvar(getDvar("mapname") + "_health_wait") == "")
if(getDvar(getDvar("mapname") + "_health_wait") == "")
        setDvar(getDvar("mapname") + "_health_wait", 10);// This creates the dvar to set the time between being able to get health again
setDvar(getDvar("mapname") + "_health_wait", 10); // This creates the dvar to set the time between being able to get health again


    level.allow_vender = int(getDvar(getDvar("mapname") + "_allow_vender"));
level.allow_vender = int(getDvar(getDvar("mapname") + "_allow_vender"));
    level.vender_wait = int(getDvar(getDvar("mapname") + "_health_wait"));
level.vender_wait = int(getDvar(getDvar("mapname") + "_health_wait"));


    for(i=1;i<5;i++)
for(i=1;i<5;i++)
        precacheModel("com_bottle" + i);// Precache (load) the com_bottle1, com_bottle2, com_bottle3 and com_bottle4 models
precacheModel("com_bottle" + i); // Precache (load) the com_bottle1, com_bottle2, com_bottle3 and com_bottle4 models


    level.venderbottles = [];
level.venderbottles = [];
    level.venderbottlescurrent = 0;
level.venderbottlescurrent = 0;
    level.venderbottlesmax = 24;// Max bottles in the map at one time, try not to have this too high as it can cause lag and somtimes crash the server
level.venderbottlesmax = 24; // Max bottles in the map at one time, try not to have this too high as it can cause lag and somtimes crash the server
}
}


vender()
vender()
{
{
    self.targetname = undefined;
self.targetname = undefined;
    dir = getent(self.target,"targetname");
dir = getent(self.target,"targetname");
    if(isDefined(dir))
if(isDefined(dir))
    {
{
        temp = spawnStruct();
temp = spawnStruct();
        temp.origin = dir.origin;
temp.origin = dir.origin;
        temp.angles = dir.angles;// Spawn a struct which doesnt count as an entity, record the script_origin's origin and angles then delete the script_origin
temp.angles = dir.angles; // Spawn a struct which doesnt count as an entity, record the script_origin's origin and angles then delete the script_origin
        dir delete();
dir delete();
        dir = temp;
dir = temp;
    }
}
    self.target = undefined;
self.target = undefined;


    self playLoopSound("vender");// Make the trigger play a loop sound
randomMessages = []; // List of random messages when player has had a bottle recently, you can have as many of them as you want.
randomMessages[0] = "^2When was the last time you saw a fat rat?";
randomMessages[1] = "^1Careful! You'll break it!";
randomMessages[2] = "^3Oh no! There's none left!";
randomMessages[3] = "^4You're hungry ain't ya?";
randomMessages[4] = "^5Woof";


    while(1)
self playLoopSound("vender"); // Make the trigger play a loop sound
    {
        self waittill("trigger", player);// Wait until its triggered
        if(player.sessionstate != "playing")// Make sure the player is playing
            continue;


        if(!level.allow_vender)// If vending machines are not allowed then say a message
for(;;)
        {
{
            player iPrintlnBold("^2Sorry, fat rats are not allowed on this server");
self waittill("trigger", player); // Wait until its triggered
            continue;
if(player.sessionstate != "playing")// Make sure the player is playing
        }
continue;


        if(isDefined(dir))// If the script_origin is placed correctly in the map, then make a bottle pop out
if(!level.allow_vender)// If vending machines are not allowed then say a message
        {
{
            self playSound("vender_drop");// Play the bottle drop sound
player iPrintlnBold("^2Sorry, fat rats are not allowed on this server");
continue;
}


            if(isDefined(level.venderbottles[level.venderbottlescurrent]))
if(isDefined(dir))// If the script_origin is placed correctly in the map, then make a bottle pop out
                level.venderbottles[level.venderbottlescurrent] delete();// If we have gone over the limit for max bottle in the map, delete the oldest one
{
self playSound("vender_drop");// Play the bottle drop sound


            level.venderbottles[level.venderbottlescurrent] = spawn("script_model",self.origin);// Spawn the bottle
if(isDefined(level.venderbottles[level.venderbottlescurrent]))
            level.venderbottles[level.venderbottlescurrent].angles = dir.angles; // Set the angles of the bottle
level.venderbottles[level.venderbottlescurrent] delete();// If we have gone over the limit for max bottle in the map, delete the oldest one
            level.venderbottles[level.venderbottlescurrent] setModel("com_bottle" + (randomInt(4) + 1));    // Set random bottle model
            point = dir.origin;
            origin = level.venderbottles[level.venderbottlescurrent].origin + mapsmp_utility::vector_Scale(anglestoup(level.venderbottles[level.venderbottlescurrent].angles),4 + randomFloat(1));
            velocity = VectorNormalize(origin - point);// Calculate velocity and direction of the impact
            velocity = mapsmp_utility::vector_Scale(velocity,10000 + randomInt(5000));
            level.venderbottles[level.venderbottlescurrent] physicsLaunch(point, velocity);            // Make the bottle fly!


            level.venderbottlescurrent++;
level.venderbottles[level.venderbottlescurrent] = spawn("script_model",self.origin);// Spawn the bottle
level.venderbottles[level.venderbottlescurrent].angles = dir.angles; // Set the angles of the bottle
level.venderbottles[level.venderbottlescurrent] setModel("com_bottle" + (randomInt(4) + 1));    // Set random bottle model
point = dir.origin;
origin = level.venderbottles[level.venderbottlescurrent].origin + maps\mp\_utility::vector_Scale(anglestoup(level.venderbottles[level.venderbottlescurrent].angles),4 + randomFloat(1));
velocity = VectorNormalize(origin - point);// Calculate velocity and direction of the impact
velocity = maps\mp\_utility::vector_Scale(velocity,10000 + randomInt(5000));
level.venderbottles[level.venderbottlescurrent] physicsLaunch(point, velocity);           // Make the bottle fly!


            if(level.venderbottlescurrent >= level.venderbottlesmax)
level.venderbottlescurrent++;
                level.venderbottlescurrent = 0;
        }


        if(isDefined(player.healthwait))// If the player has already used the vending machine then...
if(level.venderbottlescurrent >= level.venderbottlesmax)
        {
level.venderbottlescurrent = 0;
            num = randomInt(100);
}
            if(num < 20)
                player iPrintlnBold("^2When was the last time you saw a fat rat?");
            else if(num >= 20 && num < 40)
                player iPrintlnBold("^1Careful! You'll break it!");// Say one of these random messages
            else if(num >= 40 && num < 60)
                player iPrintlnBold("^3Oh no! There's none left!");
            else if(num >= 60 && num < 80)
                player iPrintlnBold("^4You're hungry ain't ya?");
            else
                player iPrintlnBold("^5Woof");
            continue;
        }


        player.healthwait = true;
if(isDefined(player.healthwait))// If the player has already used the vending machine then...
        if(player.health < player.maxhealth)// If the players health is not at the max
{
        {
player iPrintlnBold(randomMessages[randomInt(randomMessages.size)]); // display one of the rather insulting messages to the player.
            player.health = player.maxhealth;// Set the players health to the max
continue;
            player iPrintlnBold("^2mmm... ^1y^2u^3m^4m^5y^6!");// Say these messages if the player was healed
}
            player iPrintlnBold("^1Health Restored!");
 
        }
player.healthwait = true;
        else
if(player.health < player.maxhealth)// If the players health is not at the max
            player iPrintlnBold("^2You already have full health, but ^1y^2u^3m^4m^5y^6! ^2anyway!");// If the player already has full health then say this message
{
        player thread healthwait();
player.health = player.maxhealth;// Set the players health to the max
    }
player iPrintlnBold("^2mmm... ^1y^2u^3m^4m^5y^6!");// Say these messages if the player was healed
player iPrintlnBold("^1Health Restored!");
}
else
player iPrintlnBold("^2You already have full health, but ^1y^2u^3m^4m^5y^6! ^2anyway!"); // If the player already has full health then say this message
player thread healthwait();
}
}
}


healthwait()
healthwait()
{
{
    self endon("disconnect");   // Kill the thread if the player disconnects
self endon("disconnect"); // Kill the thread if the player disconnects
    wait level.vender_wait;       // Wait how long level.vender_wait is
wait level.vender_wait; // Wait how long level.vender_wait is
    self.healthwait = undefined;   // Make self.healthwait undefined
self.healthwait = undefined; // Make self.healthwait undefined
}
}</pre>
</pre>


[[Image:Data.png]] Prefabs, scripts, sounds and example map with .map can be downloaded [http://clanbfw.com/kill3rcreations/vending_tut.zip here]
[[Image:Data.png]] Prefabs, scripts, sounds and example map with .map can be downloaded [http://clanbfw.com/kill3rcreations/vending_tut.zip here]

Latest revision as of 13:55, 23 February 2012

This tutorial assumes that you already know how to create, compile & create GSCs,CSVs & FastFiles for your maps

By Kill3r

This tutorial will show you how to add a vending machine that when used heals you and a bottle pops out of it like in (or will be in) the rat_house_v2 map.

  REMEMBER: Anywhere that says "yourmapname" change to what your map is called, like mp_funny_bunny



Adding the vending machine model

First off, open the map you want to add the vending machine to. Add a vending machine prefab by right clicking on the 2D area of Radiant > misc > prefab



Go the the misc_models folder, and look for "com_vending_xxx.map" were xxx is which type you want, but its best to use one that has an opening at the bottom.



Creating the trigger

Next we need the trigger, create a brush surrounding the front of the vending machine and texture it with tools > trigger



Also create a small 8x8x8 brush, the center of this brush is where the bottles will spawn (the origin of the bottles is at the bottom) to help position the smaller brush add a misc_model by right clicking on the 2D area of Radiant > misc > model and navigate to your raw/xmodel folder then insert com_bottle1. Also set the angles of the bottle so they lay flat as they would when coming out of the vending machine.



We will be needing the com_bottle1 model again later so dont delete it just yet :P

Unselect everything then select the trigger brush and the small brush, right click in the 2D area of radiant > trigger > (type you want here)

Types of triggers:

  • damage - Shoot the trigger to trigger it
  • disk - a round trigger, cant change the height
  • friendlychain - Used for SP only
  • hurt - Hurts the player... dont use this one lol xD
  • lookat - Look at the trigger to trigger it
  • multiple - Triggered when touched by a player
  • once - Triggered only once
  • radius - like disk but can change the height
  • use - Press the USE button to trigger
  • use_touch - Player must be touching the trigger and press the USE button to trigger it


I recommended to use trigger_use_touch or trigger_use



Unselect everything then texture the small brush with tools > origin. Press N to open the entity box, and type the following in:

Key: hintstring
Value: Press^3 [{+activate}] ^7to have a drink
Key: targetname
Value: heal


Adding where the impact will come from

Next we need to set where the impact is going to come from to force the bottle out of the vending machine (and also set the angle of the bottle when it spawns). To do this we need to pace a script_origin by right clicking on the 2D area of Radiant > script > origin then a red box should appear. Place this corresponding to where you what the impact to come from.

Now use the com_bottle1 model that you used before when adding the trigger, make sure that the angles are as if it was coming out of the vending machine. Now press N to open the entitys box for the bottle and look at the angles, then select the script_origin and set the same angles for that. Now you can delete the com_bottle1 model.



Make sure nothing is selected by pressing Esc few times, now select the trigger THEN the script_origin and press W. A red line should appear from the center of the large or smaller trigger brushes connecting to the script_origin.



The .csv files

(ff .csv and sound .csv)

OK, thats the Radiant part done, now for the .csvs

  • Go to CoD4\zone_source and look for yourmapname.csv

Open that with notepad and add these lines somewhere (xmodel, lines only requierd if the model is not already used in your map)

xmodel,com_bottle1
xmodel,com_bottle2
xmodel,com_bottle3
xmodel,com_bottle4
sound,yourmapname,,,  
  • Save and close


  • Now go to CoD4\raw\soundaliases, make a new .csv called yourmapname.csv (a .txt renamed to .csv)

Open it with notepad and add the following:

vender,,level/ac_unit_window_loop.wav,0.7,0.7,max,1,1,150,300,auto,streamed,,looping
vender_drop,1,yourmapname/vender_drop1.wav,0.7,0.8,max,0.9,1,150,300,auto,,,
vender_drop,2,yourmapname/vender_drop2.wav,0.7,0.8,max,0.9,1,150,300,auto,,,  

Save and close again


Go to CoD4\raw\sound and make a new folder called yourmapname, in there place the 2 .wav sounds that can be downloaded (link at the bottom)

The Scripts

OK then, now the scripty part

New commands that are added with these scripts are:

set yourmapname_allow_vender "1"
set yourmapname_health_wait "10"

yourmapname depends what your map is called, like if your map is mp_funny_bunny then the new commands would be:

set mp_funny_bunny_allow_vender "1"
set mp_funny_bunny_health_wait "10"


Add this part somewhere in the main() function of your map .gsc

	precache(); // Call the precache function

	venders = getentarray("heal","targetname");    // Get all the entitys that have "heal" for their "targetname"
	for(i=0;i<venders.size;i++)
		venders[i] thread vender();

So it should look something like this:

main()
{
	level.tweakfile = true;
	setdvar("scr_fog_disable", 0);
	VisionSetNaked("mp_vending", 0);

	maps\mp\_load::main();
	maps\mp\_compass::setupMiniMap("compass_map_mp_vending");

	ambientPlay("ambient_pipeline");

	game["allies"] = "marines";
	game["axis"] = "opfor";
	game["attackers"] = "axis";
	game["defenders"] = "allies";
	game["allies_soldiertype"] = "desert";
	game["axis_soldiertype"] = "desert";

	setdvar("r_specularcolorscale", "1" );
	setdvar("r_glowbloomintensity0",".1");
	setdvar("r_glowbloomintensity1",".1");
	setdvar("r_glowskybleedintensity0",".1");

	setdvar("compassmaxrange","2048");

	precache(); // Call the precache function

	venders = getentarray("heal","targetname"); // Get all the entitys that have "heal" for their "targetname"
	for(i=0;i<venders.size;i++)
		venders[i] thread vender();
}

Add this code UNDER the main() function

precache()
{
	if(getDvar(getDvar("mapname") + "_allow_vender") == "")
		setDvar(getDvar("mapname") + "_allow_vender", 1); // This creates the dvar to enable the vending machines

	if(getDvar(getDvar("mapname") + "_health_wait") == "")
		setDvar(getDvar("mapname") + "_health_wait", 10); // This creates the dvar to set the time between being able to get health again

	level.allow_vender = int(getDvar(getDvar("mapname") + "_allow_vender"));
	level.vender_wait = int(getDvar(getDvar("mapname") + "_health_wait"));

	for(i=1;i<5;i++)
		precacheModel("com_bottle" + i); // Precache (load) the com_bottle1, com_bottle2, com_bottle3 and com_bottle4 models

	level.venderbottles = [];
	level.venderbottlescurrent = 0;
	level.venderbottlesmax = 24; // Max bottles in the map at one time, try not to have this too high as it can cause lag and somtimes crash the server
}

vender()
{
	self.targetname = undefined;
	dir = getent(self.target,"targetname");
	if(isDefined(dir))
	{
		temp = spawnStruct();
		temp.origin = dir.origin;
		temp.angles = dir.angles; // Spawn a struct which doesnt count as an entity, record the script_origin's origin and angles then delete the script_origin
		dir delete();
		dir = temp;
	}
	self.target = undefined;

	randomMessages = []; // List of random messages when player has had a bottle recently, you can have as many of them as you want.
	randomMessages[0] = "^2When was the last time you saw a fat rat?";
	randomMessages[1] = "^1Careful! You'll break it!";
	randomMessages[2] = "^3Oh no! There's none left!";
	randomMessages[3] = "^4You're hungry ain't ya?";
	randomMessages[4] = "^5Woof";

	self playLoopSound("vender"); // Make the trigger play a loop sound

	for(;;)
	{
		self waittill("trigger", player); // Wait until its triggered
		if(player.sessionstate != "playing")// Make sure the player is playing
			continue;

		if(!level.allow_vender)// If vending machines are not allowed then say a message
		{
			player iPrintlnBold("^2Sorry, fat rats are not allowed on this server");
			continue;
		}

		if(isDefined(dir))// If the script_origin is placed correctly in the map, then make a bottle pop out
		{
			self playSound("vender_drop");// Play the bottle drop sound

			if(isDefined(level.venderbottles[level.venderbottlescurrent]))
				level.venderbottles[level.venderbottlescurrent] delete();// If we have gone over the limit for max bottle in the map, delete the oldest one

			level.venderbottles[level.venderbottlescurrent] = spawn("script_model",self.origin);// Spawn the bottle
			level.venderbottles[level.venderbottlescurrent].angles = dir.angles; // Set the angles of the bottle
			level.venderbottles[level.venderbottlescurrent] setModel("com_bottle" + (randomInt(4) + 1));    // Set random bottle model
			point = dir.origin;
			origin = level.venderbottles[level.venderbottlescurrent].origin + maps\mp\_utility::vector_Scale(anglestoup(level.venderbottles[level.venderbottlescurrent].angles),4 + randomFloat(1));
			velocity = VectorNormalize(origin - point);// Calculate velocity and direction of the impact
			velocity = maps\mp\_utility::vector_Scale(velocity,10000 + randomInt(5000));
			level.venderbottles[level.venderbottlescurrent] physicsLaunch(point, velocity);            // Make the bottle fly!

			level.venderbottlescurrent++;

			if(level.venderbottlescurrent >= level.venderbottlesmax)
				level.venderbottlescurrent = 0;
		}

		if(isDefined(player.healthwait))// If the player has already used the vending machine then...
		{
			player iPrintlnBold(randomMessages[randomInt(randomMessages.size)]); // display one of the rather insulting messages to the player.
			continue;
		}

		player.healthwait = true;
		if(player.health < player.maxhealth)// If the players health is not at the max
		{
			player.health = player.maxhealth;// Set the players health to the max
			player iPrintlnBold("^2mmm... ^1y^2u^3m^4m^5y^6!");// Say these messages if the player was healed
			player iPrintlnBold("^1Health Restored!");
		}
		else
			player iPrintlnBold("^2You already have full health, but ^1y^2u^3m^4m^5y^6! ^2anyway!"); // If the player already has full health then say this message
		player thread healthwait();
	}
}

healthwait()
{
	self endon("disconnect"); // Kill the thread if the player disconnects
	wait level.vender_wait; // Wait how long level.vender_wait is
	self.healthwait = undefined; // Make self.healthwait undefined
}

So, with all the code it should look like this:

main()
{
	level.tweakfile = true;
	setdvar("scr_fog_disable", 0);
	VisionSetNaked("mp_vending", 0);

	maps\mp\_load::main();
	maps\mp\_compass::setupMiniMap("compass_map_mp_vending");

	ambientPlay("ambient_pipeline");

	game["allies"] = "marines";
	game["axis"] = "opfor";
	game["attackers"] = "axis";
	game["defenders"] = "allies";
	game["allies_soldiertype"] = "desert";
	game["axis_soldiertype"] = "desert";

	setdvar("r_specularcolorscale", "1" );
	setdvar("r_glowbloomintensity0",".1");
	setdvar("r_glowbloomintensity1",".1");
	setdvar("r_glowskybleedintensity0",".1");

	setdvar("compassmaxrange","2048");

	precache(); // Call the precache function

	venders = getentarray("heal","targetname"); // Get all the entitys that have "heal" for their "targetname"
	for(i=0;i<venders.size;i++)
		venders[i] thread vender();
}

precache()
{
	if(getDvar(getDvar("mapname") + "_allow_vender") == "")
		setDvar(getDvar("mapname") + "_allow_vender", 1); // This creates the dvar to enable the vending machines

	if(getDvar(getDvar("mapname") + "_health_wait") == "")
		setDvar(getDvar("mapname") + "_health_wait", 10); // This creates the dvar to set the time between being able to get health again

	level.allow_vender = int(getDvar(getDvar("mapname") + "_allow_vender"));
	level.vender_wait = int(getDvar(getDvar("mapname") + "_health_wait"));

	for(i=1;i<5;i++)
		precacheModel("com_bottle" + i); // Precache (load) the com_bottle1, com_bottle2, com_bottle3 and com_bottle4 models

	level.venderbottles = [];
	level.venderbottlescurrent = 0;
	level.venderbottlesmax = 24; // Max bottles in the map at one time, try not to have this too high as it can cause lag and somtimes crash the server
}

vender()
{
	self.targetname = undefined;
	dir = getent(self.target,"targetname");
	if(isDefined(dir))
	{
		temp = spawnStruct();
		temp.origin = dir.origin;
		temp.angles = dir.angles; // Spawn a struct which doesnt count as an entity, record the script_origin's origin and angles then delete the script_origin
		dir delete();
		dir = temp;
	}
	self.target = undefined;

	randomMessages = []; // List of random messages when player has had a bottle recently, you can have as many of them as you want.
	randomMessages[0] = "^2When was the last time you saw a fat rat?";
	randomMessages[1] = "^1Careful! You'll break it!";
	randomMessages[2] = "^3Oh no! There's none left!";
	randomMessages[3] = "^4You're hungry ain't ya?";
	randomMessages[4] = "^5Woof";

	self playLoopSound("vender"); // Make the trigger play a loop sound

	for(;;)
	{
		self waittill("trigger", player); // Wait until its triggered
		if(player.sessionstate != "playing")// Make sure the player is playing
			continue;

		if(!level.allow_vender)// If vending machines are not allowed then say a message
		{
			player iPrintlnBold("^2Sorry, fat rats are not allowed on this server");
			continue;
		}

		if(isDefined(dir))// If the script_origin is placed correctly in the map, then make a bottle pop out
		{
			self playSound("vender_drop");// Play the bottle drop sound

			if(isDefined(level.venderbottles[level.venderbottlescurrent]))
				level.venderbottles[level.venderbottlescurrent] delete();// If we have gone over the limit for max bottle in the map, delete the oldest one

			level.venderbottles[level.venderbottlescurrent] = spawn("script_model",self.origin);// Spawn the bottle
			level.venderbottles[level.venderbottlescurrent].angles = dir.angles; // Set the angles of the bottle
			level.venderbottles[level.venderbottlescurrent] setModel("com_bottle" + (randomInt(4) + 1));    // Set random bottle model
			point = dir.origin;
			origin = level.venderbottles[level.venderbottlescurrent].origin + maps\mp\_utility::vector_Scale(anglestoup(level.venderbottles[level.venderbottlescurrent].angles),4 + randomFloat(1));
			velocity = VectorNormalize(origin - point);// Calculate velocity and direction of the impact
			velocity = maps\mp\_utility::vector_Scale(velocity,10000 + randomInt(5000));
			level.venderbottles[level.venderbottlescurrent] physicsLaunch(point, velocity);            // Make the bottle fly!

			level.venderbottlescurrent++;

			if(level.venderbottlescurrent >= level.venderbottlesmax)
				level.venderbottlescurrent = 0;
		}

		if(isDefined(player.healthwait))// If the player has already used the vending machine then...
		{
			player iPrintlnBold(randomMessages[randomInt(randomMessages.size)]); // display one of the rather insulting messages to the player.
			continue;
		}

		player.healthwait = true;
		if(player.health < player.maxhealth)// If the players health is not at the max
		{
			player.health = player.maxhealth;// Set the players health to the max
			player iPrintlnBold("^2mmm... ^1y^2u^3m^4m^5y^6!");// Say these messages if the player was healed
			player iPrintlnBold("^1Health Restored!");
		}
		else
			player iPrintlnBold("^2You already have full health, but ^1y^2u^3m^4m^5y^6! ^2anyway!"); // If the player already has full health then say this message
		player thread healthwait();
	}
}

healthwait()
{
	self endon("disconnect"); // Kill the thread if the player disconnects
	wait level.vender_wait; // Wait how long level.vender_wait is
	self.healthwait = undefined; // Make self.healthwait undefined
}

Prefabs, scripts, sounds and example map with .map can be downloaded here