Energy balls

Hundreds of years ago, an evil wizard lived in a cave. He used to throw energy balls all day long but after a few years he ran out of balls and died. His art was lost forever... wait, don't loose your hope! I have found the cave and the script was written on its walls! Ok, it used old synthax wdl code but I have brushed it and it looks ok now :)

action wizard
{
   clip_size = 0;
   while (1)
   {
      while (my.skill10 < 95)
      {
         ent_cycle ("attack", my.skill10); // play the attack animation frames
         my.skill10 += 3 * time;
         wait (1);
      }
      eball_pos.x = my.x;
      eball_pos.y = my.y;
      eball_pos.z = my.z + 25; // the energy ball appears betwen wizard's hands
      ent_create (energyball_mdl, eball_pos, energy_ball);
      snd_play (energy_snd, 70, 0);
      waitt (16);
      while (my.skill10 > 2)
      {
         ent_cycle ("attack", my.skill10); // play the attack animation frames
         my.skill10 -= 2 * time;
         wait (1);
      }
      waitt (32);
    }
}

The first line in the action tells the engine to draw all the triangles for all the models. The wizard will move his hands ("attack"); the energy ball is created 25 quants above wizard's origin. The wizard will move his hands again (this time in a reversed "attack" animation) and after 2 seconds everything will repeat.

function energy_ball()
{
   wait (1);
   my.enable_entity = on;
   my.enable_block = on;
   my.event = remove_eball;
   my.pan = you.pan;
   my.tilt = you.tilt;
   my.lightred = 250;
   my.lightgreen = 150;
   my.lightrange = 200;
   eball_speed.x = 20;
   eball_speed.y = 0;
   eball_speed.z = 0;
   eball_speed *= time;
   while (my != null)
   {
      my.roll += 20 * time;
      move_mode = ignore_you + ignore_passents;
      ent_move (eball_speed, nullvector);
      wait (1);
   }
}

function remove_eball()
{
   wait (1);
   if (you == player)
   {
      player._health -= 60; // decrease player's health
   }
   ent_remove (me);
}

The ball is sensitive to entities and level blocks. If the ball collides with an entity (the player, an elevator, etc) or with a level block (a wall, etc) its remove_eball event is executed. The ball has the same pan and tilt with its creator (the wizard) and it generates orange light up to 200 quants around it. As long as the ball exists, it moves with the speed given by eball_speed.x and rotates by changing its roll angle.

If the ball collides with something, it checks if it collided with the player. If this is true, it decreases player's health by 60 points. At the end of its event function, the ball is removed.
 

Disco

This snippet combines music and colored lights. I have created a standalone project but you can easily insert the code in your own projects.

Take a look at function main:

function main()
{
   d3d_lightres = 1; 
   fps_max = 50; 
   level_load (disco_wmb);
   wait (2); // wait for the level to be loaded
   set_camera();
   waitt (80);
   while (1)
   {
      if (sound_handle == 0)
      {
         snd_loop (music_snd, 80, 0);
         sound_handle = result;
      }
      wait (1);
   }
}

First of all we're setting d3d_lightres to 1; this improves the quality of the dynamic lights. We lock the frame rate at 50 fps, we load the level, we set the camera and them we play the music wav file in a loop. I have used a small music sample but you can replace it with any wave file.

function set_camera()
{
 camera.tilt = -90;
 camera.y = -100;
 camera.z = 800;
 wait (1);
}

Function set_camera chooses a convenient position and angle for the camera; play with the values above to get a different position / angle.

But what's so special with this disco light code? I could use an invisible entity that walks on a path and generates light or similar stuff, right?
Sure you could do that, but this piece of code places the light on the floor in a position that is determined by the light spot on the wall, like in the picture below:

Every light color has two entities and two actions; we have disco_red (the action attached to the red light on the floor) and red_spot (the action attached to the red light spot), etc.

Let's take a look at the action that will create the red light on the floor:

entity* redspot_pnt;

action disco_red
{
   my.invisible = on;
   my.passable = on;
   my.lightrange = 0;
   my.lightred = 250;
   waitt (16 + random(32));
   snd_play (poweron_snd, 30, 0);
   my.lightrange = 200;
   while (1)
   {
      my.x = redspot_pnt.z * tan (redspot_pnt.pan);
      my.y = redspot_pnt.z * tan (redspot_pnt.roll);
      wait (1);
   }
}

The entity is invisible, passable and will generate red light (lightred = 250). After 1..3 seconds we play the power on sound and we give the light a range of 200 quants. The light will move on the floor by changing its x
and y coords depending on the position and angles of the redspot_pnt, a pointer to the red light spot.

action red_spot
{
   redspot_pnt = me;
   my.light = on;
   my.lightrange = 0;
   my.lightred = 250;
   waitt (80);
   while (1)
   {
      my.pan = 30 - random(60);
      my.roll = -10 - random(50);
      waitt (2);
   }
}

The red spot glows red; I use the same model for all the light spots (red, green, blue) and I have used different lightred, lightgreen, lightblue values to change their appearance.

The spot waits for about 5 seconds (I'm using the same value in main, remember?) and then it starts changing its pan and roll angles in a wild (1) loop ;)
The values for pan and roll depend on your level geometry so you might need to play with them. You can control any other angles (pan and tilt, tilt and roll, etc) as long as you use the same angles in action disco_red. Before I forget, here's the math behind the code:

The code for the green and blue spots is similar.