Beginner's corner

Top  Previous  Next

Fogger

 

I simply love fog! It looks good and it is extremely useful if you want to create huge worlds. But how do we set its color and strength? We open the level in Wed, we choose File -> Map Properties -> Fog and then we set the colors. We build the level, we run it and we don't like what we see so we have to start over... This piece of code allows you to set the fog at runtime; click a few buttons and when you like what you've got, simply copy the values to your script!

Let's take a better look at the panel that controls the fog:

 

 

Everything looks normal, isn't it? We can change 5 values (red, green, blue, start and end) using 5 pairs of buttons that increase or decrease the values. This simple yet nice interface was created using a text and a panel:

 

text fog_txt
{
    font = terminal9_font;
    pos_x = 10;
    pos_y = 10;
    string = "red (d3d_fogcolor1.red):\ngreen (d3d_fogcolor1.green):\nblue (d3d_fogcolor1.blue):\nstart (camera.fog_start):\nend (camera.fog_end):";
    flags = d3d, visible;
}

 

The text has a long string; it displays red (d3d_fogcolor1.red): and then \n (newline) moves to the next line. The process repeats and we get 5 different lines of text using a single string. Let's take a look at the panel definition:

panel fog_pan
{
    pos_x = 0;
    pos_y = 0;
    button = 190, 10, arrowup_pcx, arrowup_pcx, arrowup_pcx, change_fog, null, null;
    button = 202, 10, arrowdown_pcx, arrowdown_pcx, arrowdown_pcx, change_fog, null, null;
    button = 190, 22, arrowup_pcx, arrowup_pcx, arrowup_pcx, change_fog, null, null;
    button = 202, 22, arrowdown_pcx, arrowdown_pcx, arrowdown_pcx, change_fog, null, null;
    button = 190, 34, arrowup_pcx, arrowup_pcx, arrowup_pcx, change_fog, null, null;
    button = 202, 34, arrowdown_pcx, arrowdown_pcx, arrowdown_pcx, change_fog, null, null;
    button = 190, 46, arrowup_pcx, arrowup_pcx, arrowup_pcx, change_fog, null, null;
    button = 202, 46, arrowdown_pcx, arrowdown_pcx, arrowdown_pcx, change_fog, null, null;
    button = 190, 58, arrowup_pcx, arrowup_pcx, arrowup_pcx, change_fog, null, null;
    button = 202, 58, arrowdown_pcx, arrowdown_pcx, arrowdown_pcx, change_fog, null, null;
    digits = 155, 10, 3, terminal9_font, 1, d3d_fogcolor1.red;
    digits = 155, 22, 3, terminal9_font, 1, d3d_fogcolor1.green;
    digits = 155, 34, 3, terminal9_font, 1, d3d_fogcolor1.blue;
    digits = 145, 46, 5, terminal9_font, 1, camera.fog_start;
    digits = 145, 58, 5, terminal9_font, 1, camera.fog_end;
    flags = overlay, refresh, d3d, visible;
}

 

This panel might look complicated but it isn't; its definition creates:
- 10 buttons (5 pairs) that can change the 5 values;
- 5 digits, used to display the 5 fog values.

You can see that I'm using only 2 bitmaps (arrowup_pcx and arrowdown_pcx) and all the buttons run the same function when we click them: change_fog.

 

function change_fog(button_number)
{
    if (button_number == 1)
    {
         d3d_fogcolor1.red = min(255, (d3d_fogcolor1.red + 5));
    }
    if (button_number == 2)
    {
         d3d_fogcolor1.red = max(0, (d3d_fogcolor1.red - 5));
    }
    if (button_number == 3)
    {
         d3d_fogcolor1.green = min(255, (d3d_fogcolor1.green + 5));
    }
    if (button_number == 4)
    {
         d3d_fogcolor1.green = max(0, (d3d_fogcolor1.green - 5));
    }
    if (button_number == 5)
    {
         d3d_fogcolor1.blue = min(255, (d3d_fogcolor1.blue + 5));
    }
    if (button_number == 6)
    {
         d3d_fogcolor1.blue = max(0, (d3d_fogcolor1.blue - 5));
    }
    if (button_number == 7)
    {
         camera.fog_start = min(5000, (camera.fog_start + 50));
    }
    if (button_number == 8)
    {
         camera.fog_start = max(0, (camera.fog_start - 50));
    }
    if (button_number == 9)
    {
         camera.fog_end = min(10000, (camera.fog_end + 50));
    }
    if (button_number == 10)
    {
         camera.fog_end = max(0, (camera.fog_end - 50));
    }
}

 

If we click the first button on the panel (the button associated to the first "button" definition in fog_pan) button_number will be set to 1. If we click the 6th button, button_number will be set to 6 and so on. Don't thank me for that, J.C. Lotter has created (inside the engine) the code for these smart panels. This way we can use a single function for all our buttons and then we can make them do different things depending on button_number.

If we click the first button, d3d_fogcolor1.red will be increased until its value equals 255. Every mouse click will add 5 to d3d_fogcolor1.red but if you want smaller steps, use a smaller value here. If we click the second button, d3d_fogcolor1.red will be decreased until it reaches zero. The same thing happens for the rest of the buttons: they set d3d_fogcolor1.green, d3d_fogcolor1.blue, camera.fog_start and camera.fog_end. The last two values can be really big so every mouse click will increase or decrease these values by 50.

You might have noticed that we are playing with d3d_fogcolor1 - this is the first of the four fog colors in Wed. We need to do one more thing; we have to tell the engine that we want to use the first fog color and this tiny function does exactly what we need:

 

starter init_fog()
{
    fog_color = 1;
}

 

This "starter" function is a special function; it will run by itself when you run the level.

Run your level and then set the proper fog values. When you like what you have got, write down the values and then place them at the end of your main function:

 

function main()
{
   ..............
   ..............
   fog_color = 1; // use the first fog color
   d3d_fogcolor1.red = 85; // your values here
   d3d_fogcolor1.green = 45; // your values here
   d3d_fogcolor1.blue = 95; // your values here
   camera.fog_start = 400; // your values here
   camera.fog_end = 2500; // your values here
}

 

If you don't want to use buttons, you can replace them with sliders.

Instant debugger

 

"Instant debugger" sounds too good to be true, isn't it? I'll let you decide if this tool is useful or not: run the engine, press "I" to display the debugger, right click to show the mouse pointer and then move the cursor over any entity in the level. You will see its x, y, z, pan, tilt, roll, red, green, blue, ambient, alpha, skill1... skill8 and frame. If one of these values changes, you will see the change in real-time; this way you can test and improve your code without having to use other painful tools. I'm a shy guy but I could have added the rest of the skills, the flags and many more things on the same panel, trust me!

If you like this debugger you might be anxious to see how it works; however, if you expect to see a lot of complicated code, you will be disappointed. The code includes a text and a panel:

 

text info_txt
{
    font = terminal9_font;
    pos_x = 10;
    pos_y = 10;
    string = "x:\ny:\nz:\npan:\ntilt:\nroll:\nred:\ngreen:\nblue:\nambient:\nalpha:\nskill1:\nskill2:\nskill3:\nskill4:\nskill5:\nskill6:\nskill7:\nskill8:\nframe:";
    flags = d3d, visible;
}

 

The panel has a huge string because I display all the text with the same string, using newline (\n). I use a panel with digits to display the values:

 

panel info_pan
{
    pos_x = 0;
    pos_y = 0;
    digits = 50, 10, 5, terminal9_font, 1, mouse_ent.x;
    digits = 50, 22, 5, terminal9_font, 1, mouse_ent.y;
    digits = 50, 34, 5, terminal9_font, 1, mouse_ent.z;
    digits = 50, 46, 5, terminal9_font, 1, mouse_ent.pan;
    digits = 50, 58, 5, terminal9_font, 1, mouse_ent.tilt;
    digits = 50, 70, 5, terminal9_font, 1, mouse_ent.roll;
    digits = 50, 82, 5, terminal9_font, 1, mouse_ent.red;
    digits = 50, 94, 5, terminal9_font, 1, mouse_ent.green;
    digits = 50, 106, 5, terminal9_font, 1, mouse_ent.blue;
    digits = 50, 118, 5, terminal9_font, 1, mouse_ent.ambient;
    digits = 50, 130, 5, terminal9_font, 1, mouse_ent.alpha;
    digits = 50, 142, 5, terminal9_font, 1, mouse_ent.skill1;
    digits = 50, 154, 5, terminal9_font, 1, mouse_ent.skill2;
    digits = 50, 166, 5, terminal9_font, 1, mouse_ent.skill3;
    digits = 50, 178, 5, terminal9_font, 1, mouse_ent.skill4;
    digits = 50, 190, 5, terminal9_font, 1, mouse_ent.skill5;
    digits = 50, 202, 5, terminal9_font, 1, mouse_ent.skill6;
    digits = 50, 214, 5, terminal9_font, 1, mouse_ent.skill7;
    digits = 50, 226, 5, terminal9_font, 1, mouse_ent.skill8;
    digits = 50, 238, 5, terminal9_font, 1, mouse_ent.frame;
    flags = refresh, d3d, visible;
}

 

I'm using a lot of "digits" instructions. All the values are displayed using up to five figures, with a font named terminal9_font. The values are multiplied by 1 (so they aren't changed). Now comes the weird part: all the values look like this: mouse_ent.x, mouse_ent.roll, mouse_ent.skill2... what's with this mouse_ent thing? According to the manual, mouse_ent is the entity that has the mouse pointer placed over it. If we place the mouse pointer over a door, mouse_ent will point to the door so we will get to see the x, y, z, pan, tilt, roll, ... for that door. The process works the same for any entity in the level; if we don't touch an entity with the mouse pointer, all the values will be zero.

I'm using a single function, but I'm using a "starter" because I need it to run at game start:

 

starter debug_init()
{
    while (1)
    {
         if (key_i == 1)
         {
              while (key_i == 1) {wait (1);}
              info_txt.visible = (info_txt.visible == off); // toggle visibility
              info_pan.visible = (info_txt.visible == on); // same thing here
         }

 

If we press the "I" key we will show / hide the debugger (the text and the panel that displays the figures). We have to wait until the "I" key is released, otherwise the debugger would appear and disappear every frame until we release the "I" key.

 

        if (mouse_ent != null) // entity detected?
         {
              if (total_frames % 100 == 1) // play a sound every 100 frames
              {
                   snd_play(entity_wav, 10, 0);
              }
         }
         wait (1);
    }
}

 

If we move the mouse pointer over an entity, mouse_ent is assigned to that entity so it isn't null. If this happens, we play a small sound every 100 frames, notifying the player that the pointer is placed over an entity so the values shown by the debugger are good.

If you want to display more values, add more "digits" instructions to the panel definition. That's all!