0 registered members (),
548
guests, and 2
spiders. |
Key:
Admin,
Global Mod,
Mod
|
|
|
Re: purrfect ai lite-c
[Re: VeT]
#267224
05/22/09 16:04
05/22/09 16:04
|
Joined: Oct 2007
Posts: 5,210 İstanbul, Turkey
Quad
Senior Expert
|
Senior Expert
Joined: Oct 2007
Posts: 5,210
İstanbul, Turkey
|
well if you show me what exactly you want to be converted, i will try to convert.
3333333333
|
|
|
Re: purrfect ai lite-c
[Re: Quad]
#267225
05/22/09 16:11
05/22/09 16:11
|
Joined: May 2009
Posts: 1,816 at my pc (duh)
darkinferno
OP
Serious User
|
OP
Serious User
Joined: May 2009
Posts: 1,816
at my pc (duh)
|
@vet: i'd love to rewrite it myself but its pretty deep and i'd hate having to use c-script maybe if i was already a c-scipt user going to lite-c it wouldnt be that bad but i dont think i want to learn c-script at this point in time. @quadraxas: dont know if this is asking too much but jus the simple demo from the aum or just in an action that i could assign to entities, give them a objective and have them go to it, i could do the rest of fleshing it out but that would be the ground work...
|
|
|
Re: purrfect ai lite-c
[Re: darkinferno]
#267228
05/22/09 16:48
05/22/09 16:48
|
Joined: Oct 2007
Posts: 5,210 İstanbul, Turkey
Quad
Senior Expert
|
Senior Expert
Joined: Oct 2007
Posts: 5,210
İstanbul, Turkey
|
okay, i ll try to convert the aum demo... starting now.
(the pai folder from aum64 is what you need to be converted, right?)
Last edited by Quadraxas; 05/22/09 16:48.
3333333333
|
|
|
Re: purrfect ai lite-c
[Re: darkinferno]
#267241
05/22/09 18:05
05/22/09 18:05
|
Joined: Oct 2007
Posts: 5,210 İstanbul, Turkey
Quad
Senior Expert
|
Senior Expert
Joined: Oct 2007
Posts: 5,210
İstanbul, Turkey
|
here it is, behaves exactly the same with c-script version: pai.c
/////////////////////////////////////////////////////////////////////////////////////////////
// Purrfect AI is being developed by George Pirvu george@acknex.net
//
// the maximum number of nodes that can be placed in the demo is 300
// the distance between two consecutive nodes should be smaller than 1000 quants for this demo
//
// Converted to Lite-C by Quadraxas
/////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////
#include <acknex.h>
#include <default.c>
///////////////////////////////
// maximum number of nodes that can be used in this demo
#define max_nodes 300
// 300 x 300 (max_nodes * max_nodes)
#define max_arrays 90000
/////////////////////////////////////////////////////////////////////////////////////////////
var number_of_nodes = -1; // stores the numbers associated to the nodes (0... up to 299 in this demo)
var current_node = 0; // the current node that scans for the other nodes
var touched_node = 0; // that's the node that is touched with the mouse pointer
var start_node = 0;
var target_node = 0; // closest node to the player that can "see" the player
var node_to_player[max_nodes]; // distance from the node to the player
var see_player[max_nodes]; // sets the corresponding var to 1 if the node can see the player
var nodex[max_nodes]; // x coordinates for the nodes
var nodey[max_nodes]; // y coordinates for the nodes
var node_to_node[max_arrays]; // stores the distance between any two nodes (up to 300 x 300 elements)
var visited[max_arrays]; // stores the actual path from a node to any other node (up to 300 x 300 elements)
var path[max_nodes]; // stores the elements of the actual path
var dist_to_player[max_nodes]; // holds the distance from the player to its surrounding nodes
var min_player;
var closest_distance = 999999; // will hold the distance from the closest visible node to the player
var index = 0; // used as a counter from 0 to 299
var distances_computed = 0; // will be set to 1 when the array is filled with the distances between the nodes
var next_node; // next node on the shortest path
var pathfinding_on = 1; // the player will use (or not) the path finding algorithm to go to the destination
var target_in_solid = 0; // will be set to 1 if the target entity is placed inside a solid (a level block, etc)
var nodes_visible = 0;
var i; // 4 counters with short names to make the code more readable
var j;
var k;
var l;
var test_var; // used for debugging
VECTOR player_pos1;
VECTOR player_pos2;
VECTOR vec_temp;
/////////////////////////////////////////////////////////////////////////////////////////////
STRING* level_wmb = "pai.wmb";
STRING* marker_mdl = "marker.mdl";
STRING* player_mdl = "player.mdl";
STRING* target_mdl = "target.mdl";
STRING* bullet_mdl = "bullet.mdl";
STRING* target_tga = "target.tga";
/////////////////////////////////////////////////////////////////////////////////////////////
BMAP* pointer_pcx = "pointer.pcx";
/////////////////////////////////////////////////////////////////////////////////////////////
SOUND* beep_sound = "beep.wav";
SOUND* door_wav = "door.wav";
SOUND* damaged_wav = "damaged.wav";
SOUND* bullet_wav = "bullet.wav";
/////////////////////////////////////////////////////////////////////////////////////////////
FONT* system_font = "system12.bmp";
/////////////////////////////////////////////////////////////////////////////////////////////
function trace_back();
function run_algorithm(); // Floyd - Dijkstra - George :) algorithm
function follow_path();
function set_target();
function init_target();
/////////////////////////////////////////////////////////////////////////////////////////////
#define health skill40
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "spiders.c"
/////////////////////////////////////////////////////////////////////////////////////////////
ENTITY* d1_marker; // temporary pointer, guides the player along the path
ENTITY* playerd; // player's destination entity
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TEXT* ai_txt = // displays the texts on the screen
{
font = system_font;
pos_x = 0;
pos_y = 0;
string = "Current path: \n\nTouched:\nTarget:\nStart:";
flags = SHOW; // remove the comment to see the debug information
}
//////////////////////////////////////////////////////////////////////////////////////////////
PANEL* ai_pan= // displays the numerical values on the screen
{
pos_x = 0;
pos_y = 0;
layer = 10;
digits = (90, 50, 4, system_font, 1, touched_node);
digits = (90, 75, 4, system_font, 1, target_node);
digits = (90, 100, 4, system_font, 1, start_node);
// digits = 180, 0, 4, system_font, 1, path[0]; // display the first 15 points on the shortest path
// digits = 220, 0, 4, system_font, 1, path[1]; // feel free to display even more if you want to
// digits = 260, 0, 4, system_font, 1, path[2];
// digits = 300, 0, 4, system_font, 1, path[3];
// digits = 340, 0, 4, system_font, 1, path[4];
// digits = 380, 0, 4, system_font, 1, path[5];
// digits = 420, 0, 4, system_font, 1, path[6];
// digits = 460, 0, 4, system_font, 1, path[7];
// digits = 500, 0, 4, system_font, 1, path[8];
// digits = 540, 0, 4, system_font, 1, path[9];
// digits = 580, 0, 4, system_font, 1, path[10];
// digits = 620, 0, 4, system_font, 1, path[11];
// digits = 660, 0, 4, system_font, 1, path[12];
// digits = 700, 0, 4, system_font, 1, path[13];
// digits = 740, 0, 4, system_font, 1, path[14];
digits(0, 0, 4, system_font, 1, player.health);
flags = OVERLAY | SHOW; // remove the comments from the digits to see the debug information
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function set_target();
function toggle_nodes();
function fire_bullets();
function main()
{
video_mode = 8; // set the resolution to 1024x768 pixels
video_depth = 32; // use true color graphics
video_screen = 1; // and start the demo in full screen mode
on_mouse_right = set_target; // click the right mouse button to set a new target
on_space = toggle_nodes;
on_mouse_left = fire_bullets;
vec_set(sky_color,vector(1,1,1));
camera.arc = 80; // set the initial zoom factor
fps_max = 100; // limit the frame rate to 100 fps
clip_size = 0; // show all the triangles for all the models
mouse_range = 50000; // allow the mouse pointer to click any entity up to 50,000 quants away
level_load(level_wmb);
wait (3); // wait for the level to be loaded
while (distances_computed == 0) {wait (1);} // wait until the big array is filled with the distances between the nodes
run_algorithm(); // get the shortest paths between the nodes
media_loop ("track1.mp3", NULL, 60);
while (1)
{
index %= (number_of_nodes + 1); // limit "index" to 0... up to 299 in this demo
if ((node_to_player[index] < closest_distance) && (see_player[index] == 1))
// if the distance from this node to the player is smaller than the current distance to the player
// and we are dealing with a node that can see the player
{
closest_distance = node_to_player[index]; // then we have a new winner!
target_node = index; // and the target is given by the current "index" value
}
else // haven't found a new winner?
{
closest_distance = node_to_player[target_node]; // then use the previous winner
}
index += 1; // move on to the following node
wait (1);
}
}
function init_mouse_startup()//functions ending in _startup is auto-started.
{
mouse_map = pointer_pcx; // set the mouse pointer bitmap
mouse_mode = 2; // and then make it visible
while (1)
{
mouse_pos.x = mouse_cursor.x; // allow the mouse to move
mouse_pos.y = mouse_cursor.y; // on the x and y axis
wait (1);
}
}
function set_camera_startup()
{
while (player == NULL) {wait (1);} // wait until the player entity is loaded
camera.pan += 45;
camera.z = player.z + 500; // place the camera 500 quants above player's head at game start
camera.tilt = -60; // make it look downwards
while (1)
{
camera.x = player.x - camera.z / 2; // place the camera behind the player on the x axis
camera.y = player.y - camera.z / 2;
camera.z += 0.3 * mickey.z; // and allow the player to zoom in / out using the mouse wheel
camera.z += 15 * (key_q - key_a) * time_step; // or the "+" and "-" keys
camera.z = clamp (camera.z, 250, 2000); // limit the height of the camera to 250...2000 quants
wait (1);
}
}
function run_algorithm()
{
i = 0;
j = 0;
while (i < (number_of_nodes + 1))
{
while (j < (number_of_nodes + 1))
{
index = j + i * (number_of_nodes + 1); // compute the correct index in the array
if (node_to_node[index] == 0) // if these nodes can't see each other
{
node_to_node[index] = 999999; // set a huge distance for the nodes that can't see each other
}
j += 1;
}
i += 1;
j = 0;
}
i = 0;
j = 0;
k = 0;
while (i < (number_of_nodes + 1))
{
while (j < (number_of_nodes + 1))
{
while (k < (number_of_nodes + 1)) // go through all the nodes
{
// if dist(2,10) + dist(10,15) < dist(2,15) then 10 is a point on a shorter path
if ( (node_to_node[j + i * (number_of_nodes + 1)] + node_to_node[i + k * (number_of_nodes + 1)]) < (node_to_node[j + k * (number_of_nodes + 1)]))
{
// make the change: don't use the old (2,15) (2, 10, 15 are used just as an example here)
node_to_node[j + k * (number_of_nodes + 1)] = node_to_node[j + i * (number_of_nodes + 1)] + node_to_node[i + k * (number_of_nodes + 1)];
visited[j + k * (number_of_nodes + 1)] = i; // store the visited point
}
if (j == k) // dist(1,1) = dist(2,2) = dist(3,3).... = dist(29,29) should be set to 0 (not necessary but looks nicer)
{
node_to_node[j + k * (number_of_nodes + 1)] = 0; // otherwise we would get d(1,1) = d(1,2) + d(2,1) if "2" is the closest node to "1"
visited[j + k * (number_of_nodes + 1)] = 0; // same thing here; the distance between a visited node and itself should be zero
}
k += 1;
}
k = 0;
j += 1;
}
k = 0;
j = 0;
i += 1;
}
}
function find_path(l, j)
{
i = 0;
while (i < (number_of_nodes + 1)) // search from this node for the rest of the nodes (up to 299 more nodes)
{
if ((i != j) && (visited[i + (number_of_nodes + 1) * j] == 0)) // the current node can "see" these nodes, excepting itself of course (i != j)
{
if (node_to_node[l + (number_of_nodes + 1) * j] == node_to_node[l + (number_of_nodes + 1) * i] + node_to_node[i + (number_of_nodes + 1) * j])
// that's a node on the shortest path because the shortest path includes it
{
k += 1; // move to the next array element
path[k] = i; // and store the node number inside the array
next_node = i; // store the new node on the shortest path because it will loose its value right away
i = (number_of_nodes + 1) - 1; // don't test other values - eliminate other paths that have the same length (that could happen in some levels)
if (path[k] == l) // end of search, reached the starting point (l = start_node, remember?)
{
return; // get out of this function
}
}
}
i += 1; // increase i if the function continues to run
}
j = next_node; // set the next node on the path as target
find_path(l, j); // recursive function, search for the shortest path again (if it searched (2,10) now searches (2,9) and so on)
}
action node() // use up to 300 nodes in this demo
{
set(my,INVISIBLE | TRANSLUCENT | PASSABLE);
my.alpha = 25;
my.emask |= ENABLE_SCAN | ENABLE_TOUCH | ENABLE_CLICK;
my.event = trace_back;
my.skill47 = 1234; // set this weird value for skill47 = I'm a node
number_of_nodes += 1; // get a unique id number (0.. up to 299)
my.skill48 = number_of_nodes; // and store it in skill48
nodex[my.skill48] = my.x; // store x and y
nodey[my.skill48] = my.y; // for this node
wait (-1); // wait until all the nodes are placed in the level
while (current_node <= number_of_nodes)
{
if (current_node == my.skill48) // I'm the current node!
{
c_scan(my.x, my.pan, vector(360, 30, 1000), IGNORE_ME);
wait (1); // not needed but won't hurt anybody
current_node += 1; // move to the next node
}
wait (1);
}
distances_computed = 1;
while (playerd == NULL) {wait (1);} // wait until the player destination entity is created
while (1)
{
node_to_player[my.skill48] = vec_dist(playerd.x, my.x); // store the distance to the player destination entity
if (node_to_player[my.skill48] < 500) // if the player destination is closer than 500 quants to this node
{
// if this node can "see" the player destination entity
if (c_trace (my.x, playerd.x, IGNORE_ME | IGNORE_MODELS | IGNORE_PASSENTS | USE_BOX) == 0)
{
see_player[my.skill48] = 1; // the node can see the player destination
}
else
{
see_player[my.skill48] = 0; // this node can't see the player destination
}
}
wait (1 + random(10)); // spread the cpu load over 10 consecutive frames
if (nodes_visible == 0)
{
set(my,INVISIBLE);
}
else
{
reset(my,INVISIBLE);
}
}
}
function init_target()
{
playerd = my; // I'm the player destination (sets the initial target)
set(my,INVISIBLE | PASSABLE);
}
action players_action()
{
//init vectors -set all components to 0-
vec_zero(vec_temp);
vec_zero(player_pos1);
vec_zero(player_pos2);
player = my;
ent_create (target_mdl, my.x, init_target);
my.skill47 = 5678; // I'm the player
my.health = 100; // and I've got 100 health points
var previous_target;
while (my.health > 0)
{
if (vec_dist (playerd.x, my.x) <= 30)
{
ent_animate(me, "stand",my.skill46, ANM_CYCLE);
my.skill46 += 2 * time_step; // "stand" animation speed
wait (1);
}
else
{
if (pathfinding_on == 1) // need to use the path finding algorithm?
{
min_player = 999999; // set the minimum distance from the player destination to its surrounding nodes to a huge value
c_scan(my.x, my.pan, vector(360, 360, 800), IGNORE_ME);
wait (-0.2);
k = 0;
while (k < (number_of_nodes + 1))
{
path[k] = 0; // reset the array, get rid of the previously stored path
k += 1;
}
k = 0; // start with the first element of path[] array
path[k] = target_node; // write the first path element
previous_target = target_node;
if (start_node != target_node)
{
find_path(start_node, target_node); // find the shortest path between these two nodes
wait (2); // wait for the path to be computed
i = k; // k = number of nodes on the shortest path
vec_temp.x = nodex[path[i-1]]; // get the previously stored coordinates for this node
vec_temp.y = nodey[path[i-1]]; // on x and y
vec_temp.z = my.z; // use player's height for z (you should use a trace to place the z on the ground if your level isn't flat)
d1_marker = ent_create (marker_mdl, vec_temp, follow_path); // create an invisible entity that guides the player
wait (1);
// the player can see the second node on the path directly?
if(c_trace (player.x, d1_marker.x, IGNORE_ME | IGNORE_MODELS | IGNORE_PASSENTS | USE_BOX) == 0)
{
i -= 1; // then ignore the first point of the path (don't turn back to it)
}
while (i >= 0) // decrease i until it goes below zero
{
vec_temp.x = nodex[path[i]]; // get the previously stored coordinates for this node
vec_temp.y = nodey[path[i]]; // on x and y
vec_temp.z = my.z; // use player's height for z (you should use a trace to place the z on the ground if your level isn't flat)
d1_marker = ent_create (marker_mdl, vec_temp, follow_path); // create an invisible entity that guides the player
wait (1);
while (vec_dist (d1_marker.x, my.x) > 30)
{
ent_animate(me, "walk", my.skill46, ANM_CYCLE);
my.skill46 += 8 * time_step; // "walk" animation speed
my.skill1 = 6 * time_step;
my.skill2 = 0;
my.skill3 = 0;
result = c_move (my, my.skill1, nullvector, IGNORE_PASSABLE | GLIDE);
// got stuck or the player has decided to pick a new path while the player was already moving or close to the destination?
if ( (result == 0) || (previous_target != target_node) || (vec_dist (playerd.x, my.x) < 100) )
{
break; // get out of both while loops, find the path again
}
vec_set (player_pos1.x, my.x);
wait (1);
vec_set (player_pos2.x, my.x);
}
// the target is visible from here?
if(c_trace (player.x, playerd.x, IGNORE_ME | IGNORE_MODELS | IGNORE_PASSENTS | USE_BOX) == 0)
{
pathfinding_on = 0; // then bypass the path finding algorithm
i = -1; // and get out of the "while" loop to stop the path finding
}
i -= 1; // move on to the following node
wait (1);
}
// go from the last node that can see the destination (the "playerd" entity) to the actual destination entity
while ((vec_dist (playerd.x, my.x) > 30) && (mouse_right == 0) && (previous_target == target_node))
{
ent_animate(me, "walk", my.skill46, ANM_CYCLE);
my.skill46 += 8 * time_step; // "walk" animation speed
vec_set (vec_temp, playerd.x);
vec_sub (vec_temp, my.x);
vec_to_angle (my.pan, vec_temp);
my.tilt = 0;
my.skill1 = 6 * time_step;
my.skill2 = 0;
my.skill3 = 0;
result = c_move (my, my.skill1, nullvector, IGNORE_PASSABLE | GLIDE);
if (result < (0.5 * my.skill1 * time_step)) // had to slow down or stop?
{
break; // then get out of here and compute a new path
}
vec_set (player_pos1, my.x);
wait (1);
vec_set (player_pos2, my.x);
}
}
}
else // the target is visible directly, so the player can move there without using the path finding algorithm
{
while ((vec_dist (playerd.x, my.x) > 30) && (mouse_right == 0))
{
ent_animate(me, "walk", my.skill46, ANM_CYCLE);
my.skill46 += 8 * time_step; // "walk" animation speed
vec_set (vec_temp, playerd.x);
vec_sub (vec_temp, my.x);
vec_to_angle (my.pan, vec_temp);
my.tilt = 0;
my.skill1 = 8 * time_step;
my.skill2 = 0;
my.skill3 = 0;
result = c_move (my, my.skill1, nullvector, IGNORE_PASSABLE | GLIDE);
if (result < (0.5 * my.skill1 * time_step)) // had to slow down or stop?
{
break; // then get out of here and compute a new path
}
vec_set (player_pos1, my.x);
wait (1);
vec_set (player_pos2, my.x);
}
pathfinding_on = 1; // the player can now use the path finding algorithm again
}
}
}
snd_play (damaged_wav, 80, 0);
while (my.tilt < 90)
{
my.tilt += 10 * time_step;
my.z -= 3 * time_step;
wait (1);
}
wait (-2); // guess why I have used this line of code ;)
}
function trace_back()
{
if (event_type == EVENT_SCAN)
{
if (you.skill47 == 1234) // scanned by a node
{
my.skill45 = handle(you); // store "you" because trace will destroy it
// if this node can "see" the node that scanned it
if (c_trace (my.x, you.x, IGNORE_ME | IGNORE_MODELS | IGNORE_PASSENTS | USE_BOX) == 0)
{
you = ptr_for_handle(my.skill45); // restore the "you" pointer
index = you.skill48 + my.skill48 * (number_of_nodes + 1);
node_to_node[index] = vec_dist(my.x, you.x);
}
}
else // scanned by the player (skill47 = 5678)
{
my.skill45 = handle(you); // store "you" because trace will destroy it
// if this node can "see" the player that scanned it
if (c_trace (my.x, you.x, IGNORE_ME | IGNORE_MODELS | IGNORE_PASSENTS | USE_BOX) == 0)
{
you = ptr_for_handle(my.skill45); // restore the "you" pointer
dist_to_player[my.skill48] = vec_dist (my.x, you.x);
if ((dist_to_player[my.skill48] < min_player) && (dist_to_player[my.skill48] != 0))
{
min_player = dist_to_player[my.skill48];
}
wait (2); // allow the rest of the nodes to change min_player (if they should change it)
if (dist_to_player[my.skill48] == min_player) // this is the closest node to the player?
{
start_node = my.skill48;
}
}
else
{
dist_to_player[my.skill48] = 0;
}
}
}
if (event_type == EVENT_TOUCH)
{
touched_node = my.skill48; // get the number of the node that was touched with the mouse pointer
}
}
function follow_path()
{
set(my,INVISIBLE | PASSABLE);
vec_set (vec_temp.x, my.x);
vec_sub (vec_temp.x, you.x);
vec_to_angle (you.pan, vec_temp); // turn the player towards the path marker
while (d1_marker == my) {wait (1);}
ent_remove (my); // remove the old, unused markers
}
function set_target()
{
while (mouse_right == 1) {wait (1);} // wait for the mouse button to be released
pathfinding_on = 0; // disable the path finding algorithm temporarily
VECTOR pos1;
vec_zero(pos1);
VECTOR pos2;
vec_zero(pos2);
pos1.x = mouse_pos.x;
pos1.y = mouse_pos.y;
pos1.z = 0;
vec_for_screen (pos1, camera);
pos2.x = mouse_pos.x;
pos2.y = mouse_pos.y;
pos2.z = 50000; // use a big value here
vec_for_screen (pos2, camera);
c_trace (pos1.x, pos2.x, IGNORE_ME | IGNORE_MODELS | IGNORE_PASSENTS | USE_BOX);
vec_set (playerd.x, target.x);
playerd.z = player.z; // set the height of the target ("playerd") to player's z coordinate
if (c_content (playerd.x,0) == 3)//content_solid
{
target_in_solid = 1; // for further use
vec_set (playerd.x, player.x); // don't move the player anymore (move the destination entity at its position)
}
if(c_trace (player.x, playerd.x, IGNORE_ME | IGNORE_MODELS | IGNORE_PASSENTS | USE_BOX) == 0) // the player can see the destination directly?
{
pathfinding_on = 0; // then bypass the path finding algorithm
}
else
{
pathfinding_on = 1; // use the path finding algorithm
}
}
function toggle_nodes()
{
nodes_visible += 1;
nodes_visible %= 2;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// pure game code (not related to the AI code) from here on
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ENTITY* bullet_target;
VECTOR bullet_origin;
action passable_door() // these particular doors need to be passable because the nodes need to see each other through them
{
while (player == NULL) {wait (1);}
set(my,PASSABLE);
while (vec_dist (player.x, my.x) > 100) {wait (1);}
my.skill10 = my.y;
snd_play (door_wav, 100, 0);
while (my.y < my.skill10 + 120)
{
my.y += 10 * time_step;
wait (1);
}
}
function remove_bullets() // this function runs when the bullet collides with something
{
wait (1); // wait for a frame
ent_remove (my); // and then remove the bullet
}
function move_bullets()
{
VECTOR temp_angle;
vec_zero(temp_angle);
VECTOR bullet_speed; // this vec will store the speed of the bullet
vec_zero(bullet_speed);
my.skill99 = 135; // uniquely identify a bullet
my.emask |= ENABLE_IMPACT | ENABLE_ENTITY | ENABLE_BLOCK;
set(my,PASSABLE);
vec_set(temp_angle, bullet_target.x);
vec_sub(temp_angle, my.x);
vec_to_angle(my.pan, temp_angle);
if (vec_dist (player_pos1.x, player_pos2.x) == 0) // the player is standing still?
{
player.pan = my.pan; // then rotate the player in the proper direction as well
}
my.event = remove_bullets; // when it collides with something, its event function (remove_bullets) will run
bullet_speed.x = 50 * time_step; // adjust the speed of the bullet here
bullet_speed.y = 0; // the bullet doesn't move sideways
bullet_speed.z = 0; // then don't allow the gravity to have its ways with the bullet
while (my)
{
if (vec_dist (my.x, bullet_origin.x) > 50) {reset(my,PASSABLE);}
c_move (my, bullet_speed, nullvector, IGNORE_PASSABLE);
wait (1);
}
}
function show_target()
{
set(my,BRIGHT);
vec_to_angle (my.pan, normal); // orient the sprite correctly
vec_add(my.x, normal.x); // move the sprite a bit away from the wall
set(my,PASSABLE);
my.scale_x = 0.2;
my.scale_y = my.scale_x;
while (mouse_left == 1) {wait (1);} // wait until the player releases the mouse button
ent_remove (me); // remove the old target
}
function set_bullet_target()
{
VECTOR pos1;
VECTOR pos2;
vec_zero(pos1);
vec_zero(pos2);
pos1.x = mouse_pos.x;
pos1.y = mouse_pos.y;
pos1.z = 0;
vec_for_screen (pos1, camera);
pos2.x = mouse_pos.x;
pos2.y = mouse_pos.y;
pos2.z = 200000; // use a big value here
vec_for_screen (pos2, camera);
c_trace (pos1, pos2, IGNORE_ME | IGNORE_PASSABLE | IGNORE_MODELS | IGNORE_SPRITES);
bullet_target = ent_create (target_tga, target, show_target);
}
function fire_bullets()
{
if (player.health <= 0) {return;} // don't fire bullets if the player is dead
proc_kill(4); // don't allow more than 1 copy of this function to run
set_bullet_target();
while (bullet_target == NULL) {wait (1);} // wait until the target sprite is displayed on the floor
while (mouse_left == 1) // this loop runs for as long as the left mouse button is pressed
{
vec_for_vertex (bullet_origin.x, player, 17); // get the coordinates for the bullets' origin
// create the bullet and attach it the "move_bullets" function
ent_create (bullet_mdl, bullet_origin.x, move_bullets);
snd_play (bullet_wav, 100, 0); // play the bullet sound at a volume of 100
wait (-0.14); // fire 7 bullets per second (0.14 * 7 = 1 second)
}
}
spiders.c
///////////////////////////////////////////////////////////////////////////////////////////////////////
// copy the files inside this folder in your game folder
// don't forget to include spiders.wdl in your main game file
// place a model in your level and attach it the deadly_spider action
///////////////////////////////////////////////////////////////////////////////////////////////////////
SOUND* gotcha_wav = "gotcha.wav";
SOUND* dead_wav = "dead.wav";
///////////////////////////////////////////////////////////////////////////////////////////////////////
STRING* spider_mdl = "spider.mdl";
///////////////////////////////////////////////////////////////////////////////////////////////////////
function hurt_them();
function deadly_spider();
///////////////////////////////////////////////////////////////////////////////////////////////////////
function init_spider()
{
VECTOR movement_speed;
vec_zero(movement_speed);
my.pan = random(360);
movement_speed.x = (20 - random(40));
movement_speed.y = (20 - random(40));
while (my.z < 150)
{
my.x += movement_speed.x * time_step;
my.y += movement_speed.y * time_step;
my.z += 20 * time_step;
wait (1);
}
while (my.z > 45)
{
my.x += movement_speed.x * time_step;
my.y += movement_speed.y * time_step;
my.z -= 10 * time_step;
wait (1);
}
deadly_spider();
}
function generate_spiders_startup()
{
while (player == NULL) {wait (1);}
while (player.x < -100) {wait (1);} // wait until the player enters the big, empty area
var i = 0;
while (i < 5)
{
snd_play (gotcha_wav, 100, 0);
ent_create (spider_mdl, vector (-362, 1335, 45), init_spider);
ent_create (spider_mdl, vector (-286, 762, 45), init_spider);
ent_create (spider_mdl, vector (82, 1195, 45), init_spider);
ent_create (spider_mdl, vector (254, 826, 45), init_spider);
ent_create (spider_mdl, vector (295, 1506, 45), init_spider);
i += 1;
wait (-0.5);
}
}
function deadly_spider()
{
VECTOR spider_speed;
vec_zero(spider_speed);
VECTOR in_front;
vec_zero(in_front);
my.emask |= ENABLE_ENTITY | ENABLE_IMPACT | ENABLE_BLOCK;
my.event = hurt_them;
my.health = 1; // "health" was defined as skill40 inside pai.wdl
while(my.health > 0)
{
spider_speed.x = 8 * time_step;
spider_speed.y = 0;
spider_speed.z = 0;
// spider_speed *= time_step;
in_front.x = my.x + 40 * cos(my.pan);
in_front.y = my.y + 40 * sin(my.pan);
in_front.z = my.z;
if (c_content(in_front,0) == 3)//content_solid
{
my.skill40 = my.pan;
my.skill41 = 30 + random(90);
while (my.pan < my.skill40 + my.skill41) // rotate 30..120 degrees
{
my.pan += 5 * time_step;
wait (1);
}
}
else // free to move
{
ent_animate(me, "run", my.skill20, ANM_CYCLE);
my.skill20 += 10 * time_step;
result = c_move (me, spider_speed, nullvector,IGNORE_PASSABLE);
if (result == 0) // got stuck?
{
spider_speed.x *= -1; // then reverse the movement direction
my.skill40 = my.pan;
my.skill41 = 30 + random(90);
while (my.pan < my.skill40 + my.skill41) // rotate 30..120 degrees
{
my.pan += 5 * time_step;
ent_animate(me, "run", my.skill20, ANM_CYCLE);
my.skill20 -= 10 * time_step;
c_move (me, spider_speed, nullvector,IGNORE_PASSABLE);
wait (1);
}
spider_speed.x *= -1; // restore the initial speed
}
if ((vec_dist (player.x, my.x) < 30) && (player.health > 0)) // collided with the player?
{
snd_play (gotcha_wav, 50, 0);
player.health -= 1 * time_step; // subtract 10 health points from the entity's health
}
}
wait (1);
}
my.skill20 = 0;
set(my,PASSABLE);
snd_play (dead_wav, 90, 0);
while (my.skill20 < 95)
{
if (my.roll < 180) {my.roll += 25 * time_step;}
if (my.z > 30) {my.z -= 5 * time_step;}
ent_animate(me, "death", my.skill20, ANM_CYCLE);
my.skill20 += 10 * time_step;
wait (1);
}
wait(-1);
}
function hurt_them()
{
proc_kill(4);
if (you != NULL) // collided with an entity (the player, a monster, etc)?
{
if (you.skill99 == 135) // hit by player's bullet?
{
my.health = 0; // then this spider is dead
my.event = NULL; // so it doesn't react to events anymore
}
}
}
3333333333
|
|
|
|