1091 lines
27 KiB
Plaintext
1091 lines
27 KiB
Plaintext
/*================================================================================
|
|
waypoints.qc
|
|
|
|
each waypoint can have up to 4 other waypoints it can link to
|
|
if a waypoint is linked, the link does not have to be 2-way, it can just point
|
|
in one direction
|
|
|
|
the waypoints are held in a linked list (way_head, way_foot) for speed to avoid
|
|
using find() with classname's as this is slow
|
|
|
|
many thanks to FrikaC for the FrikBot, whose code this is heavily based upon
|
|
================================================================================*/
|
|
|
|
float waypoint_mode;
|
|
float WM_UNINIT = 0; // waypoints not loaded
|
|
float WM_LOADING = 1; // waypoints are loading
|
|
float WM_LOADED = 2; // waypoints are loaded (also set when there's no waypoints in the map)
|
|
float WM_EDITOR = 3; // editor is currently active
|
|
|
|
float scr_centertime;
|
|
.float menu, menuopt, menutime, menubuttonreleased;
|
|
float MENU_MAIN = 0; // main menu
|
|
float MENU_WAYS = 1; // waypoint sub menu
|
|
float MENU_LINKS = 2; // link sub menu
|
|
float MENU_LINKS_C = 3; // create link
|
|
float MENU_LINKS_D = 4; // delete link
|
|
float MENU_LINKS_C2 = 5; // create link x2
|
|
float MENU_LINKS_D2 = 6; // delete link x2
|
|
|
|
entity way_head, way_foot;
|
|
float waypoints;
|
|
entity fixer;
|
|
.entity target1, target2, target3, target4;
|
|
.entity _next, _last;
|
|
.entity current_way, last_way;
|
|
|
|
/*==========
|
|
wisible
|
|
==========*/
|
|
float (entity monster, entity way) wisible =
|
|
{
|
|
vector spot1 = monster.origin + monster.view_ofs;
|
|
vector spot2 = way.origin;
|
|
traceline (spot1, spot2, TRUE, monster);
|
|
if (trace_fraction == 1 || trace_ent == way)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
};
|
|
|
|
/*==========
|
|
PrintQCWaypoint
|
|
|
|
use thinks to avoid tripping runaway loop counter
|
|
==========*/
|
|
void() PrintQCWaypoint =
|
|
{
|
|
// go to next waypoint in list
|
|
entity t;
|
|
if (self.enemy == world)
|
|
t = way_head;
|
|
else
|
|
t = self.enemy._next;
|
|
|
|
// reached last waypoint
|
|
if (t == world)
|
|
{
|
|
remove(self);
|
|
fixer = world;
|
|
bprint("};\n// End dump\n");
|
|
return;
|
|
}
|
|
|
|
// dump current waypoint
|
|
bprint("\tSpawnWaypoint(");
|
|
|
|
t.origin_x = rint(t.origin_x);
|
|
t.origin_y = rint(t.origin_y);
|
|
t.origin_z = rint(t.origin_z);
|
|
|
|
string h = vtos(t.origin);
|
|
bprint(h);
|
|
bprint(", ");
|
|
|
|
h = ftos(t.target1.count);
|
|
bprint(h);
|
|
bprint(", ");
|
|
|
|
h = ftos(t.target2.count);
|
|
bprint(h);
|
|
bprint(", ");
|
|
|
|
h = ftos(t.target3.count);
|
|
bprint(h);
|
|
bprint(", ");
|
|
|
|
h = ftos(t.target4.count);
|
|
bprint(h);
|
|
bprint(");\n");
|
|
|
|
self.nextthink = time + 0.01;
|
|
self.enemy = t;
|
|
};
|
|
|
|
/*==========
|
|
DumpWaypoints
|
|
==========*/
|
|
void() DumpWaypoints =
|
|
{
|
|
if (!waypoints)
|
|
{
|
|
bprint("No waypoints to dump!\n");
|
|
return;
|
|
}
|
|
|
|
bprint("// Waypoint Dump - ");
|
|
bprint(mapname);
|
|
bprint(".qc\n");
|
|
|
|
bprint("void() waypoints_");
|
|
bprint(mapname);
|
|
bprint(" =\n{\n");
|
|
|
|
if (!fixer)
|
|
fixer = spawn();
|
|
fixer.nextthink = time + 0.01;
|
|
fixer.think = PrintQCWaypoint;
|
|
fixer.enemy = world;
|
|
};
|
|
|
|
/*==========
|
|
CheckLinked
|
|
|
|
returns TRUE if ways are linked
|
|
==========*/
|
|
float (entity e1, entity e2) CheckLinked =
|
|
{
|
|
if ((e1 == e2) || (e2 == world) || (e1 == world))
|
|
return FALSE;
|
|
else if (e1.target1 == e2)
|
|
return TRUE;
|
|
else if (e1.target2 == e2)
|
|
return TRUE;
|
|
else if (e1.target3 == e2)
|
|
return TRUE;
|
|
else if (e1.target4 == e2)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
};
|
|
|
|
/*==========
|
|
LinkWays
|
|
|
|
links e1 to e2 (each way has max of 4 links)
|
|
==========*/
|
|
float (entity e1, entity e2) LinkWays =
|
|
{
|
|
if ((e1 == e2) || (e2 == world) || (e1 == world))
|
|
{
|
|
bprint("tried to link waypoint to itself, or nothing!\n");
|
|
return FALSE;
|
|
}
|
|
else if (CheckLinked(e1, e2))
|
|
{
|
|
bprint("waypoints are already linked!\n");
|
|
return FALSE; // already linked
|
|
}
|
|
|
|
if (e1.target1 == world)
|
|
{
|
|
e1.target1 = e2;
|
|
return TRUE;
|
|
}
|
|
else if (e1.target2 == world)
|
|
{
|
|
e1.target2 = e2;
|
|
return TRUE;
|
|
}
|
|
else if (e1.target3 == world)
|
|
{
|
|
e1.target3 = e2;
|
|
return TRUE;
|
|
}
|
|
else if (e1.target4 == world)
|
|
{
|
|
e1.target4 = e2;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
bprint("waypoint already has max (4) links!\n");
|
|
return FALSE;
|
|
}
|
|
};
|
|
|
|
/*==========
|
|
UnlinkWays
|
|
|
|
unlinks e1 from e2 (one direction only)
|
|
==========*/
|
|
void(entity e1, entity e2) UnlinkWays =
|
|
{
|
|
if ((e1 == e2) || (e2 == world) || (e1 == world))
|
|
{
|
|
bprint("can't unlink waypoint from itself!\n");
|
|
return;
|
|
}
|
|
else if (!CheckLinked(e1, e2))
|
|
{
|
|
bprint("waypoints are not linked!\n");
|
|
return;
|
|
}
|
|
|
|
if (e1.target1 == e2)
|
|
e1.target1 = world;
|
|
if (e1.target2 == e2)
|
|
e1.target2 = world;
|
|
if (e1.target3 == e2)
|
|
e1.target3 = world;
|
|
if (e1.target4 == e2)
|
|
e1.target4 = world;
|
|
};
|
|
|
|
/*==========
|
|
DeleteWaypoint
|
|
==========*/
|
|
void(entity what) DeleteWaypoint =
|
|
{
|
|
if (way_head == what)
|
|
way_head = what._next;
|
|
if (way_foot == what)
|
|
way_foot = what._last;
|
|
if (what._last)
|
|
what._last._next = what._next;
|
|
if (what._next)
|
|
what._next._last = what._last;
|
|
waypoints = 0;
|
|
entity t = way_head;
|
|
while(t)
|
|
{
|
|
waypoints = waypoints + 1;
|
|
t.count = waypoints;
|
|
if (CheckLinked(t, what))
|
|
UnlinkWays(t, what);
|
|
t = t._next;
|
|
}
|
|
if (self.current_way == what)
|
|
self.current_way = world;
|
|
if (self.last_way == what)
|
|
self.last_way = world;
|
|
remove(what);
|
|
};
|
|
|
|
/*==========
|
|
MakeWaypoint
|
|
|
|
used in editor to spawn new waypoint
|
|
the waypoint loading code uses SpawnWaypoint, not this function
|
|
==========*/
|
|
entity(vector org) MakeWaypoint =
|
|
{
|
|
entity way = spawn();
|
|
way.classname = "waypoint";
|
|
way.solid = SOLID_TRIGGER;
|
|
way.movetype = MOVETYPE_NONE;
|
|
|
|
setorigin(way, org);
|
|
setmodel(way, "progs/s_way1.spr");
|
|
setsize(way, VEC_HULL_MIN, VEC_HULL_MAX);
|
|
|
|
waypoints = waypoints + 1;
|
|
if (!way_head) // first waypoint
|
|
{
|
|
way_head = way;
|
|
way_foot = way;
|
|
}
|
|
else
|
|
{
|
|
way_foot._next = way;
|
|
way._last = way_foot;
|
|
way_foot = way;
|
|
}
|
|
way.count = waypoints;
|
|
return way;
|
|
};
|
|
|
|
/*==========
|
|
FindWayPoint
|
|
|
|
finds closest wisible way to self
|
|
only used to select nearest way in the editor
|
|
==========*/
|
|
entity(entity start) FindWayPoint =
|
|
{
|
|
vector org = self.origin;
|
|
|
|
if (start != world)
|
|
{
|
|
float dst = vlen(start.origin - org);
|
|
entity best = start;
|
|
}
|
|
else
|
|
{
|
|
dst = 100000;
|
|
best = world;
|
|
}
|
|
|
|
entity t = way_head;
|
|
while(t)
|
|
{
|
|
if (dst < 20)
|
|
return best;
|
|
|
|
float tdst = vlen(t.origin - org);
|
|
if (tdst < dst)
|
|
{
|
|
if (wisible(self, t))
|
|
{
|
|
dst = tdst;
|
|
best = t;
|
|
}
|
|
}
|
|
t = t._next;
|
|
}
|
|
return best;
|
|
};
|
|
|
|
/*==========
|
|
DrawWaypointLinks
|
|
==========*/
|
|
void() DrawWaypointLinks =
|
|
{
|
|
// if we're in the linking sub-menus, then draw a helper beam (for creation)
|
|
// or lightning (for deletion)
|
|
if (self.menu >= MENU_LINKS_C && self.menu <= MENU_LINKS_D2)
|
|
{
|
|
if (self.current_way && self.last_way)
|
|
{
|
|
if (self.current_way != self.last_way)
|
|
{
|
|
if (self.menu == MENU_LINKS_C || self.menu == MENU_LINKS_C2)
|
|
te_beam(self.current_way.origin, self.last_way.origin, self.current_way);
|
|
else
|
|
te_lightning1(self.current_way.origin, self.last_way.origin, self);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (self.current_way)
|
|
{
|
|
if (self.current_way.target1)
|
|
te_beam(self.current_way.origin, self.current_way.target1.origin, self.current_way);
|
|
if (self.current_way.target2)
|
|
te_beam(self.current_way.origin, self.current_way.target2.origin, self.current_way);
|
|
if (self.current_way.target3)
|
|
te_beam(self.current_way.origin, self.current_way.target3.origin, self.current_way);
|
|
if (self.current_way.target4)
|
|
te_beam(self.current_way.origin, self.current_way.target4.origin, self.current_way);
|
|
}
|
|
};
|
|
|
|
/*==========
|
|
SelectNearestWaypoint
|
|
==========*/
|
|
void() SelectNearestWaypoint =
|
|
{
|
|
entity t = FindWayPoint(self.current_way);
|
|
if (t)
|
|
{
|
|
float dist = vlen(self.origin - t.origin);
|
|
if (dist < 64)
|
|
{
|
|
// new waypoint selected
|
|
if (self.current_way != t)
|
|
{
|
|
// unselect previous waypoint
|
|
if (self.current_way)
|
|
{
|
|
setmodel(self.current_way, "progs/s_way1.spr");
|
|
setsize(self.current_way, VEC_HULL_MIN, VEC_HULL_MAX);
|
|
}
|
|
|
|
// select new waypoint
|
|
setmodel(t, "progs/s_way2.spr");
|
|
setsize(t, VEC_HULL_MIN, VEC_HULL_MAX);
|
|
self.current_way = t;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
/*==========
|
|
DisplayMenu
|
|
|
|
wish i had real string management
|
|
==========*/
|
|
void() DisplayMenu =
|
|
{
|
|
// don't constantly re-draw the menu
|
|
if (time < self.menutime)
|
|
return;
|
|
self.menutime = time + scr_centertime;
|
|
|
|
string s1, s2, s3, s4, s5, s6, s7;
|
|
s1 = s2 = s3 = s4 = s5 = s6 = s7 = string_null;
|
|
|
|
if (self.menu == MENU_MAIN)
|
|
{
|
|
s1 = "\bWaypoint Editor\b\n\n";
|
|
if (self.menuopt == 0) s2 = "\x85 \bWaypoint Management \n"; else s2 = " Waypoint Management \n";
|
|
if (self.menuopt == 1) s3 = "\x85 \bLink Management \n"; else s3 = " Link Management \n";
|
|
if (self.menuopt == 2) s4 = "\x85 \bDisplay Waypoint Info\n"; else s4 = " Display Waypoint Info\n";
|
|
if (self.menuopt == 3) s5 = "\x85 \bDump .qc \n"; else s5 = " Dump .qc \n";
|
|
if (self.menuopt == 4) s6 = "\x85 \bExit \n"; else s6 = " Exit \n";
|
|
}
|
|
else if (self.menu == MENU_WAYS)
|
|
{
|
|
s1 = "\bWaypoint Editor \x85 Waypoint Management\b\n\n";
|
|
if (self.menuopt == 0) s2 = "\x85 \bMove Waypoint \n"; else s2 = " Move Waypoint \n";
|
|
if (self.menuopt == 1) s3 = "\x85 \bDelete Waypoint \n"; else s3 = " Delete Waypoint \n";
|
|
if (self.menuopt == 2) s4 = "\x85 \bMake Waypoint \n"; else s4 = " Make Waypoint \n";
|
|
if (self.menuopt == 3) s5 = "\x85 \bMake Way + Link \n"; else s5 = " Make Way + Link \n";
|
|
if (self.menuopt == 4) s6 = "\x85 \bMake Way + Link x2\n"; else s6 = " Make Way + Link x2\n";
|
|
if (self.menuopt == 5) s7 = "\x85 \bBack \n"; else s7 = " Back \n";
|
|
}
|
|
else if (self.menu == MENU_LINKS)
|
|
{
|
|
s1 = "\bWaypoint Editor \x85 Link Management\b\n\n";
|
|
if (self.menuopt == 0) s2 = "\x85 \bUnlink Waypoint\n"; else s2 = " Unlink Waypoint\n";
|
|
if (self.menuopt == 1) s3 = "\x85 \bCreate Link \n"; else s3 = " Create Link \n";
|
|
if (self.menuopt == 2) s4 = "\x85 \bDelete Link \n"; else s4 = " Delete Link \n";
|
|
if (self.menuopt == 3) s5 = "\x85 \bCreate Link x2 \n"; else s5 = " Create Link x2 \n";
|
|
if (self.menuopt == 4) s6 = "\x85 \bDelete Link x2 \n"; else s6 = " Delete Link x2 \n";
|
|
if (self.menuopt == 5) s7 = "\x85 \bBack \n"; else s7 = " Back \n";
|
|
}
|
|
else // selection sub menus (link, delete, etc)
|
|
{
|
|
if (self.menu == MENU_LINKS_C)
|
|
s1 = "\bWaypoint Editor \x85 Create link (one way)\b\n\n";
|
|
else if (self.menu == MENU_LINKS_D)
|
|
s1 = "\bWaypoint Editor \x85 Delete link (one way))\b\n\n";
|
|
else if (self.menu == MENU_LINKS_C2)
|
|
s1 = "\bWaypoint Editor \x85 Create link (two way))\b\n\n";
|
|
else if (self.menu == MENU_LINKS_D2)
|
|
s1 = "\bWaypoint Editor \x85 Delete link (two way))\b\n\n";
|
|
|
|
s2 = "\bPlease select waypoint\n\n";
|
|
if (self.menuopt == 0) s3 = "\x85 \bSelect \n"; else s3 = " Select \n";
|
|
if (self.menuopt == 1) s4 = "\x85 \bCancel \n"; else s4 = " Cancel \n";
|
|
}
|
|
|
|
centerprint(self, s1, s2, s3, s4, s5, s6, s7);
|
|
};
|
|
|
|
/*==========
|
|
ToggleWaypointMenu
|
|
==========*/
|
|
void() ToggleWaypointMenu =
|
|
{
|
|
// don't allow until all waypoints loaded
|
|
if (waypoint_mode < WM_LOADED)
|
|
return;
|
|
|
|
// reset menu for next use
|
|
self.menu = MENU_MAIN;
|
|
self.menuopt = 0;
|
|
self.menutime = time;
|
|
centerprint (self, string_null);
|
|
|
|
// menu on
|
|
if (waypoint_mode == WM_LOADED)
|
|
{
|
|
stuffcmd(self, "crosshair 0\n");
|
|
stuffcmd(self, "viewsize 120\n");
|
|
stuffcmd(self, "r_drawviewmodel 0\n");
|
|
waypoint_mode = WM_EDITOR;
|
|
entity t = way_head;
|
|
while (t)
|
|
{
|
|
setmodel(t, "progs/s_way1.spr");
|
|
setsize(t, VEC_HULL_MIN, VEC_HULL_MAX);
|
|
t = t._next;
|
|
}
|
|
if (self.current_way)
|
|
{
|
|
setmodel(self.current_way, "progs/s_way2.spr");
|
|
setsize(self.current_way, VEC_HULL_MIN, VEC_HULL_MAX);
|
|
}
|
|
}
|
|
// menu off
|
|
else
|
|
{
|
|
stuffcmd(self, "crosshair 1\n");
|
|
stuffcmd(self, "viewsize 100\n");
|
|
stuffcmd(self, "r_drawviewmodel 1\n");
|
|
waypoint_mode = WM_LOADED;
|
|
t = way_head;
|
|
while (t)
|
|
{
|
|
setmodel(t, "progs/s_null.spr");
|
|
setsize(t, VEC_HULL_MIN, VEC_HULL_MAX);
|
|
t = t._next;
|
|
}
|
|
}
|
|
};
|
|
|
|
/*==========
|
|
WaypointMenuNavigate
|
|
|
|
used for scrolling through the menu options
|
|
uses the keys bound to "next weapon" and "previous weapon"
|
|
==========*/
|
|
void(float dir) WaypointMenuNavigate =
|
|
{
|
|
float options = 0;
|
|
if (self.menu == MENU_MAIN)
|
|
options = 5;
|
|
else if (self.menu == MENU_WAYS || self.menu == MENU_LINKS)
|
|
options = 6;
|
|
else
|
|
options = 2;
|
|
|
|
self.menuopt = self.menuopt + dir;
|
|
if (self.menuopt > options - 1)
|
|
self.menuopt = 0;
|
|
if (self.menuopt < 0)
|
|
self.menuopt = options - 1;
|
|
};
|
|
|
|
/*==========
|
|
WaypointMenuBack
|
|
==========*/
|
|
void() WaypointMenuBack =
|
|
{
|
|
if (self.menu == MENU_MAIN)
|
|
{
|
|
ToggleWaypointMenu();
|
|
return;
|
|
}
|
|
|
|
self.menuopt = 0;
|
|
// go back to the main menu if we're in the waypoint or linking sub-menu
|
|
if (self.menu == MENU_WAYS || self.menu == MENU_LINKS)
|
|
self.menu = MENU_MAIN;
|
|
// otherwise go back to the linking sub-menu
|
|
else
|
|
self.menu = MENU_LINKS;
|
|
};
|
|
|
|
/*==========
|
|
WaypointMenuAction
|
|
==========*/
|
|
void(float command) WaypointMenuAction =
|
|
{
|
|
if (!self.menubuttonreleased)
|
|
return;
|
|
self.menubuttonreleased = FALSE;
|
|
self.attack_finished = time + 0.1;
|
|
|
|
//
|
|
// main menu
|
|
//
|
|
if (self.menu == MENU_MAIN)
|
|
{
|
|
if (command == 1)
|
|
{
|
|
self.menu = MENU_WAYS;
|
|
self.menuopt = 0;
|
|
}
|
|
else if (command == 2)
|
|
{
|
|
self.menu = MENU_LINKS;
|
|
self.menuopt = 0;
|
|
}
|
|
else if (command == 3)
|
|
{
|
|
if (self.current_way)
|
|
{
|
|
bprint("Waypoint #");
|
|
bprint(ftos(self.current_way.count));
|
|
bprint(" - Position ");
|
|
bprint(vtos(self.current_way.origin));
|
|
bprint(" - Links to ");
|
|
if (self.current_way.target1)
|
|
{
|
|
bprint(ftos(self.current_way.target1.count));
|
|
bprint(" ");
|
|
}
|
|
if (self.current_way.target2)
|
|
{
|
|
bprint(ftos(self.current_way.target2.count));
|
|
bprint(" ");
|
|
}
|
|
if (self.current_way.target3)
|
|
{
|
|
bprint(ftos(self.current_way.target3.count));
|
|
bprint(" ");
|
|
}
|
|
if (self.current_way.target4)
|
|
bprint(ftos(self.current_way.target4.count));
|
|
bprint("\n");
|
|
}
|
|
}
|
|
else if (command == 4)
|
|
DumpWaypoints();
|
|
else if (command == 5)
|
|
WaypointMenuBack();
|
|
return;
|
|
}
|
|
|
|
//
|
|
// waypoint menu
|
|
//
|
|
if (self.menu == MENU_WAYS)
|
|
{
|
|
// move waypoint
|
|
if (command == 1)
|
|
{
|
|
if (self.current_way)
|
|
setorigin(self.current_way, self.origin);
|
|
else
|
|
sprint(self, "No waypoint selected - unable to move!\n");
|
|
}
|
|
// delete waypoint
|
|
else if (command == 2)
|
|
{
|
|
if (self.current_way)
|
|
DeleteWaypoint(self.current_way);
|
|
else
|
|
sprint(self, "No waypoint selected - unable to delete!\n");
|
|
}
|
|
// create waypoint - no linking
|
|
else if (command == 3)
|
|
{
|
|
MakeWaypoint(self.origin);
|
|
}
|
|
// create waypoint + link to last
|
|
else if (command == 4)
|
|
{
|
|
entity way = MakeWaypoint(self.origin);
|
|
LinkWays(self.current_way, way);
|
|
}
|
|
// create waypoint + link two ways to last
|
|
else if (command == 5)
|
|
{
|
|
way = MakeWaypoint(self.origin);
|
|
LinkWays(self.current_way, way);
|
|
LinkWays(way, self.current_way);
|
|
}
|
|
else if (command == 6)
|
|
WaypointMenuBack();
|
|
return;
|
|
}
|
|
|
|
//
|
|
// linking menu
|
|
//
|
|
if (self.menu == MENU_LINKS)
|
|
{
|
|
if (command == 1) // unlink all
|
|
{
|
|
if (self.current_way)
|
|
self.current_way.target1 = self.current_way.target2 = self.current_way.target3 = self.current_way.target4 = world;
|
|
else
|
|
sprint(self, "No waypoint selected - unable to unlink!\n");
|
|
}
|
|
else if (command == 2) // create one way link
|
|
{
|
|
if (self.current_way)
|
|
{
|
|
self.menuopt = 0;
|
|
self.last_way = self.current_way;
|
|
self.menu = MENU_LINKS_C;
|
|
}
|
|
else
|
|
sprint(self, "No waypoint selected!\n");
|
|
}
|
|
else if (command == 3) // remove one way link
|
|
{
|
|
if (self.current_way)
|
|
{
|
|
self.menuopt = 0;
|
|
self.last_way = self.current_way;
|
|
self.menu = MENU_LINKS_D;
|
|
}
|
|
else
|
|
sprint(self, "No waypoint selected!\n");
|
|
}
|
|
else if (command == 4) // create two way link
|
|
{
|
|
if (self.current_way)
|
|
{
|
|
self.menuopt = 0;
|
|
self.last_way = self.current_way;
|
|
self.menu = MENU_LINKS_C2;
|
|
}
|
|
else
|
|
sprint(self, "No waypoint selected!\n");
|
|
}
|
|
else if (command == 5) // remove two way link
|
|
{
|
|
if (self.current_way)
|
|
{
|
|
self.menuopt = 0;
|
|
self.last_way = self.current_way;
|
|
self.menu = MENU_LINKS_D2;
|
|
}
|
|
else
|
|
sprint(self, "No waypoint selected!\n");
|
|
}
|
|
else if (command == 6)
|
|
WaypointMenuBack();
|
|
return;
|
|
}
|
|
|
|
//
|
|
// linking submenu
|
|
//
|
|
if (self.menu >= MENU_LINKS_C && self.menu <= MENU_LINKS_D2)
|
|
{
|
|
if (command == 1)
|
|
{
|
|
if (self.menu == MENU_LINKS_C) // create one way link
|
|
LinkWays(self.last_way, self.current_way);
|
|
else if (self.menu == MENU_LINKS_D) // remove one way link
|
|
UnlinkWays(self.last_way, self.current_way);
|
|
else if (self.menu == MENU_LINKS_C2) // create two way link
|
|
{
|
|
LinkWays(self.last_way, self.current_way);
|
|
LinkWays(self.current_way, self.last_way);
|
|
}
|
|
else if (self.menu == MENU_LINKS_D2) // remove two way link
|
|
{
|
|
UnlinkWays(self.last_way, self.current_way);
|
|
UnlinkWays(self.current_way, self.last_way);
|
|
}
|
|
|
|
WaypointMenuBack();
|
|
}
|
|
else if (command == 2)
|
|
WaypointMenuBack();
|
|
}
|
|
};
|
|
|
|
/*==========
|
|
WaypointMenu
|
|
==========*/
|
|
void() WaypointMenu =
|
|
{
|
|
DisplayMenu();
|
|
|
|
// pressing fire will set button0 = TRUE for several frames so we need to track release
|
|
if (!self.button0)
|
|
self.menubuttonreleased = TRUE;
|
|
|
|
// use impulses for next weapon/previous weapon to scroll the menu
|
|
if (self.impulse == 10)
|
|
WaypointMenuNavigate(-1);
|
|
else if (self.impulse == 12)
|
|
WaypointMenuNavigate(1);
|
|
// use fire button to select options
|
|
else if (self.button0)
|
|
WaypointMenuAction(self.menuopt + 1);
|
|
else
|
|
return;
|
|
|
|
self.impulse = 0;
|
|
self.menutime = time; // refresh menu immediately
|
|
};
|
|
|
|
/*==========
|
|
WaypointForNum
|
|
|
|
returns the entity for a given waypoint number
|
|
returns world if not found
|
|
only used in waypoint loading code
|
|
==========*/
|
|
entity(float num) WaypointForNum =
|
|
{
|
|
if (num < 1)
|
|
return world;
|
|
|
|
entity t = way_head;
|
|
while (t)
|
|
{
|
|
if (t.count == num)
|
|
return t;
|
|
t = t._next;
|
|
}
|
|
return world;
|
|
};
|
|
|
|
/*==========
|
|
FixThisWaypoint
|
|
|
|
use thinks to avoid tripping runaway loop counter
|
|
==========*/
|
|
void() FixThisWaypoint =
|
|
{
|
|
self.enemy.target1 = WaypointForNum(self.enemy.ammo_shells);
|
|
self.enemy.target2 = WaypointForNum(self.enemy.ammo_nails);
|
|
self.enemy.target3 = WaypointForNum(self.enemy.ammo_rockets);
|
|
self.enemy.target4 = WaypointForNum(self.enemy.ammo_cells);
|
|
|
|
self.enemy = self.enemy._next;
|
|
self.nextthink = time + 0.01;
|
|
|
|
// reached last waypoint
|
|
if (self.enemy == world)
|
|
{
|
|
bprint("waypoints loaded\n");
|
|
waypoint_mode = WM_LOADED;
|
|
remove(self);
|
|
fixer = world;
|
|
}
|
|
};
|
|
|
|
/*==========
|
|
FixWaypoints
|
|
|
|
once all waypoints have been loaded, link them up
|
|
we want to link target1-4 (entities) for speed
|
|
ammo_shells is the waypoint number for target1, ammo_nails is target2, etc
|
|
==========*/
|
|
void() FixWaypoints =
|
|
{
|
|
if (!fixer)
|
|
fixer = spawn();
|
|
fixer.nextthink = time + 0.01;
|
|
fixer.think = FixThisWaypoint;
|
|
fixer.enemy = way_head; // start waypoint
|
|
};
|
|
|
|
/*==========
|
|
SpawnWaypoint
|
|
|
|
used by the hardcoded qc waypoints
|
|
==========*/
|
|
void(vector org, float t1, float t2, float t3, float t4) SpawnWaypoint =
|
|
{
|
|
entity way = spawn();
|
|
way.classname = "waypoint";
|
|
way.solid = SOLID_TRIGGER;
|
|
way.movetype = MOVETYPE_NONE;
|
|
|
|
setorigin(way, org);
|
|
setmodel(way, "progs/s_null.spr");
|
|
setsize(way, VEC_HULL_MIN, VEC_HULL_MAX);
|
|
|
|
way.ammo_shells = t1;
|
|
way.ammo_nails = t2;
|
|
way.ammo_rockets = t3;
|
|
way.ammo_cells = t4;
|
|
waypoints = waypoints + 1;
|
|
way.count = waypoints;
|
|
|
|
if (!way_head) // first waypoint
|
|
{
|
|
way_head = way;
|
|
way_foot = way;
|
|
}
|
|
else
|
|
{
|
|
way_foot._next = way;
|
|
way._last = way_foot;
|
|
way_foot = way;
|
|
}
|
|
};
|
|
|
|
// Waypoint Dump - e1m2.qc
|
|
void() waypoints_e1m2 =
|
|
{
|
|
SpawnWaypoint('1481.0 1670.0 288.0', 2, 13, 15, 0);
|
|
SpawnWaypoint('1518.0 1504.0 264.0', 1, 3, 4, 5);
|
|
SpawnWaypoint('1711.0 1524.0 264.0', 2, 14, 0, 0);
|
|
SpawnWaypoint('1317.0 1521.0 264.0', 2, 0, 0, 0);
|
|
SpawnWaypoint('1469.0 1277.0 200.0', 2, 6, 9, 18);
|
|
SpawnWaypoint('1679.0 1273.0 200.0', 5, 7, 8, 0);
|
|
SpawnWaypoint('1677.0 1406.0 200.0', 6, 8, 0, 0);
|
|
SpawnWaypoint('1766.0 1289.0 200.0', 6, 7, 0, 0);
|
|
SpawnWaypoint('1368.0 1274.0 200.0', 5, 10, 12, 0);
|
|
SpawnWaypoint('1353.0 1441.0 200.0', 9, 11, 0, 0);
|
|
SpawnWaypoint('1192.0 1441.0 200.0', 10, 12, 0, 0);
|
|
SpawnWaypoint('1201.0 1279.0 200.0', 11, 9, 0, 0);
|
|
SpawnWaypoint('1800.0 1720.0 264.0', 1, 14, 0, 0);
|
|
SpawnWaypoint('1800.0 1614.0 264.0', 13, 3, 0, 0);
|
|
SpawnWaypoint('1310.0 1720.0 264.0', 1, 16, 0, 0);
|
|
SpawnWaypoint('1192.0 1720.0 264.0', 15, 17, 0, 0);
|
|
SpawnWaypoint('1195.0 1584.0 264.0', 16, 0, 0, 0);
|
|
SpawnWaypoint('1484.0 1087.0 204.0', 5, 19, 0, 0);
|
|
SpawnWaypoint('1492.0 905.0 200.0', 18, 20, 0, 0);
|
|
SpawnWaypoint('1498.0 791.0 248.0', 19, 21, 0, 0);
|
|
SpawnWaypoint('1477.0 666.0 264.0', 20, 22, 0, 0);
|
|
SpawnWaypoint('1341.0 656.0 296.0', 21, 23, 0, 0);
|
|
SpawnWaypoint('1232.0 662.0 312.0', 22, 24, 0, 0);
|
|
SpawnWaypoint('1066.0 671.0 312.0', 23, 25, 0, 0);
|
|
SpawnWaypoint('1078.0 527.0 312.0', 24, 26, 0, 0);
|
|
SpawnWaypoint('1082.0 391.0 308.0', 25, 27, 0, 0);
|
|
SpawnWaypoint('1096.0 93.0 308.0', 26, 28, 0, 0);
|
|
SpawnWaypoint('1099.0 -133.0 320.0', 27, 29, 95, 0);
|
|
SpawnWaypoint('1210.0 -115.0 320.0', 28, 30, 0, 0);
|
|
SpawnWaypoint('1373.0 -119.0 320.0', 29, 31, 0, 0);
|
|
SpawnWaypoint('1420.0 -25.0 320.0', 30, 32, 0, 0);
|
|
SpawnWaypoint('1422.0 89.0 320.0', 31, 33, 0, 0);
|
|
SpawnWaypoint('1408.0 337.0 320.0', 32, 34, 0, 0);
|
|
SpawnWaypoint('1513.0 391.0 320.0', 33, 35, 0, 0);
|
|
SpawnWaypoint('1629.0 394.0 312.0', 34, 36, 0, 0);
|
|
SpawnWaypoint('1755.0 391.0 312.0', 35, 37, 0, 0);
|
|
SpawnWaypoint('1795.0 315.0 312.0', 36, 38, 0, 0);
|
|
SpawnWaypoint('1787.0 165.0 312.0', 37, 39, 0, 0);
|
|
SpawnWaypoint('1791.0 43.0 312.0', 38, 40, 0, 0);
|
|
SpawnWaypoint('1849.0 -98.0 312.0', 39, 41, 0, 0);
|
|
SpawnWaypoint('1907.0 -95.0 312.0', 40, 42, 0, 0);
|
|
SpawnWaypoint('1999.0 -109.0 312.0', 41, 43, 0, 0);
|
|
SpawnWaypoint('2046.0 -137.0 312.0', 42, 44, 0, 0);
|
|
SpawnWaypoint('2044.0 -246.0 312.0', 43, 45, 0, 0);
|
|
SpawnWaypoint('2038.0 -360.0 312.0', 44, 46, 0, 0);
|
|
SpawnWaypoint('1969.0 -357.0 312.0', 45, 47, 0, 0);
|
|
SpawnWaypoint('1847.0 -354.0 312.0', 46, 48, 0, 0);
|
|
SpawnWaypoint('1716.0 -359.0 312.0', 47, 49, 0, 0);
|
|
SpawnWaypoint('1556.0 -355.0 312.0', 48, 50, 0, 0);
|
|
SpawnWaypoint('1259.0 -332.0 312.0', 49, 51, 0, 0);
|
|
SpawnWaypoint('1149.0 -391.0 312.0', 50, 52, 0, 0);
|
|
SpawnWaypoint('1093.0 -512.0 312.0', 51, 53, 0, 0);
|
|
SpawnWaypoint('1116.0 -649.0 312.0', 52, 54, 0, 0);
|
|
SpawnWaypoint('1249.0 -730.0 312.0', 53, 55, 0, 0);
|
|
SpawnWaypoint('1376.0 -728.0 312.0', 54, 56, 0, 0);
|
|
SpawnWaypoint('1503.0 -717.0 312.0', 55, 57, 0, 0);
|
|
SpawnWaypoint('1679.0 -705.0 360.0', 56, 58, 0, 0);
|
|
SpawnWaypoint('1675.0 -807.0 392.0', 57, 59, 0, 0);
|
|
SpawnWaypoint('1670.0 -918.0 408.0', 58, 60, 0, 0);
|
|
SpawnWaypoint('1620.0 -916.0 424.0', 59, 61, 0, 0);
|
|
SpawnWaypoint('1489.0 -905.0 440.0', 60, 62, 0, 0);
|
|
SpawnWaypoint('1369.0 -908.0 440.0', 61, 63, 68, 0);
|
|
SpawnWaypoint('1220.0 -911.0 440.0', 62, 64, 0, 0);
|
|
SpawnWaypoint('1073.0 -906.0 440.0', 63, 65, 70, 0);
|
|
SpawnWaypoint('928.0 -900.0 440.0', 64, 66, 71, 0);
|
|
SpawnWaypoint('880.0 -849.0 440.0', 65, 67, 0, 0);
|
|
SpawnWaypoint('882.0 -743.0 440.0', 66, 0, 0, 0);
|
|
SpawnWaypoint('1410.0 -1183.0 440.0', 62, 69, 0, 0);
|
|
SpawnWaypoint('1311.0 -1191.0 440.0', 68, 70, 0, 0);
|
|
SpawnWaypoint('1182.0 -1192.0 440.0', 69, 64, 0, 0);
|
|
SpawnWaypoint('874.0 -1043.0 440.0', 65, 72, 0, 0);
|
|
SpawnWaypoint('870.0 -1130.0 440.0', 71, 73, 0, 0);
|
|
SpawnWaypoint('877.0 -1184.0 432.0', 72, 74, 0, 0);
|
|
SpawnWaypoint('676.0 -1219.0 432.0', 73, 75, 0, 0);
|
|
SpawnWaypoint('586.0 -1199.0 432.0', 74, 76, 97, 0);
|
|
SpawnWaypoint('511.0 -1174.0 432.0', 75, 77, 97, 0);
|
|
SpawnWaypoint('418.0 -1093.0 432.0', 76, 78, 0, 0);
|
|
SpawnWaypoint('391.0 -977.0 432.0', 77, 79, 0, 0);
|
|
SpawnWaypoint('450.0 -864.0 432.0', 78, 80, 0, 0);
|
|
SpawnWaypoint('587.0 -851.0 432.0', 79, 81, 96, 0);
|
|
SpawnWaypoint('612.0 -725.0 432.0', 80, 82, 0, 0);
|
|
SpawnWaypoint('558.0 -628.0 392.0', 81, 83, 0, 0);
|
|
SpawnWaypoint('562.0 -508.0 350.0', 82, 84, 0, 0);
|
|
SpawnWaypoint('567.0 -385.0 320.0', 83, 85, 92, 0);
|
|
SpawnWaypoint('484.0 -407.0 320.0', 84, 86, 0, 0);
|
|
SpawnWaypoint('395.0 -447.0 320.0', 85, 87, 0, 0);
|
|
SpawnWaypoint('267.0 -468.0 320.0', 86, 88, 0, 0);
|
|
SpawnWaypoint('170.0 -383.0 320.0', 87, 89, 0, 0);
|
|
SpawnWaypoint('269.0 -302.0 320.0', 88, 90, 98, 0);
|
|
SpawnWaypoint('403.0 -291.0 320.0', 89, 91, 0, 0);
|
|
SpawnWaypoint('559.0 -269.0 320.0', 90, 92, 0, 0);
|
|
SpawnWaypoint('580.0 -224.0 320.0', 91, 93, 84, 0);
|
|
SpawnWaypoint('613.0 -143.0 320.0', 92, 94, 0, 0);
|
|
SpawnWaypoint('688.0 -102.0 320.0', 93, 95, 0, 0);
|
|
SpawnWaypoint('802.0 -117.0 320.0', 94, 28, 0, 0);
|
|
SpawnWaypoint('585.0 -1005.0 432.0', 80, 97, 0, 0);
|
|
SpawnWaypoint('595.0 -1090.0 432.0', 96, 75, 76, 0);
|
|
SpawnWaypoint('245.0 -224.0 328.0', 89, 99, 0, 0);
|
|
SpawnWaypoint('238.0 -100.0 320.0', 98, 100, 0, 0);
|
|
SpawnWaypoint('246.0 55.0 320.0', 99, 101, 102, 0);
|
|
SpawnWaypoint('253.0 158.0 320.0', 100, 0, 0, 0);
|
|
SpawnWaypoint(' 90.0 59.0 320.0', 100, 103, 111, 0);
|
|
SpawnWaypoint(' 47.0 67.0 320.0', 102, 104, 0, 0);
|
|
SpawnWaypoint('-92.0 91.0 320.0', 103, 105, 111, 110);
|
|
SpawnWaypoint('-243.0 79.0 320.0', 104, 106, 109, 107);
|
|
SpawnWaypoint('-366.0 -26.0 320.0', 105, 107, 0, 0);
|
|
SpawnWaypoint('-375.0 52.0 320.0', 106, 108, 105, 0);
|
|
SpawnWaypoint('-356.0 166.0 320.0', 107, 109, 0, 0);
|
|
SpawnWaypoint('-277.0 274.0 320.0', 108, 110, 105, 0);
|
|
SpawnWaypoint('-29.0 260.0 320.0', 109, 111, 104, 0);
|
|
SpawnWaypoint('121.0 248.0 320.0', 110, 102, 104, 0);
|
|
SpawnWaypoint('-107.0 -47.0 320.0', 104, 113, 0, 0);
|
|
SpawnWaypoint('-107.0 -121.0 320.0', 112, 114, 0, 0);
|
|
SpawnWaypoint('-120.0 -257.0 336.0', 113, 115, 0, 0);
|
|
SpawnWaypoint('-122.0 -277.0 336.0', 114, 116, 0, 0);
|
|
SpawnWaypoint('-108.0 -403.0 384.0', 115, 117, 0, 0);
|
|
SpawnWaypoint('-133.0 -454.0 384.0', 116, 118, 0, 0);
|
|
SpawnWaypoint('-208.0 -493.0 384.0', 117, 119, 0, 0);
|
|
SpawnWaypoint('-314.0 -493.0 416.0', 118, 120, 0, 0);
|
|
SpawnWaypoint('-388.0 -489.0 464.0', 119, 121, 0, 0);
|
|
SpawnWaypoint('-479.0 -488.0 480.0', 120, 122, 123, 0);
|
|
SpawnWaypoint('-488.0 -363.0 480.0', 121, 125, 0, 0);
|
|
SpawnWaypoint('-463.0 -675.0 482.0', 121, 124, 0, 0);
|
|
SpawnWaypoint('-283.0 -698.0 480.0', 123, 0, 0, 0);
|
|
SpawnWaypoint('-264.0 -290.0 480.0', 122, 0, 0, 0);
|
|
};
|
|
// End dump
|
|
|
|
/*==========
|
|
LoadWaypoints
|
|
==========*/
|
|
void() LoadWaypoints =
|
|
{
|
|
waypoint_mode = WM_LOADING;
|
|
|
|
if (mapname == "e1m2")
|
|
waypoints_e1m2();
|
|
|
|
if (waypoints)
|
|
FixWaypoints();
|
|
else
|
|
{
|
|
waypoint_mode = WM_LOADED;
|
|
bprint("no waypoints loaded\n");
|
|
}
|
|
};
|
|
|
|
/*==========
|
|
WaypointPreFrame
|
|
|
|
called from PlayerPreThink
|
|
==========*/
|
|
void() WaypointPreFrame =
|
|
{
|
|
if (waypoint_mode < WM_EDITOR)
|
|
return;
|
|
SelectNearestWaypoint();
|
|
DrawWaypointLinks();
|
|
};
|
|
|
|
/*==========
|
|
WaypointPostFrame
|
|
|
|
called from PlayerPostThink
|
|
==========*/
|
|
void() WaypointPostFrame =
|
|
{
|
|
if (waypoint_mode < WM_LOADED)
|
|
return;
|
|
if (self.impulse == 100)
|
|
{
|
|
dprint("ToggleWaypointMenu\n");
|
|
ToggleWaypointMenu();
|
|
self.impulse = 0;
|
|
return;
|
|
}
|
|
if (waypoint_mode < WM_EDITOR)
|
|
return;
|
|
WaypointMenu();
|
|
};
|
|
|
|
/*==========
|
|
WaypointFrame
|
|
|
|
called from StartFrame
|
|
==========*/
|
|
void() WaypointFrame =
|
|
{
|
|
if (framecount < 5)
|
|
return;
|
|
if (waypoint_mode == WM_UNINIT)
|
|
LoadWaypoints();
|
|
};
|
|
|
|
/*==========
|
|
WaypointInit
|
|
|
|
called from worldspawn
|
|
==========*/
|
|
void() WaypointInit =
|
|
{
|
|
precache_model("progs/beam.mdl");
|
|
precache_model("progs/s_way1.spr");
|
|
precache_model("progs/s_way2.spr");
|
|
precache_model("progs/s_null.spr");
|
|
|
|
waypoint_mode = WM_UNINIT;
|
|
way_head = world;
|
|
way_foot = world;
|
|
waypoints = 0;
|
|
|
|
// used for the menu refresh timer
|
|
scr_centertime = cvar("scr_centertime") - 0.1;
|
|
if (scr_centertime < 0)
|
|
scr_centertime = 0;
|
|
};
|