3 ======================================
\r
4 FrikBot X (Version 0.10.1)
\r
5 ======================================
\r
7 This program is in the Public Domain. My crack legal
\r
8 team would like to add:
\r
10 RYAN "FRIKAC" SMITH IS PROVIDING THIS SOFTWARE "AS IS"
\r
11 AND MAKES NO WARRANTY, EXPRESS OR IMPLIED, AS TO THE
\r
12 ACCURACY, CAPABILITY, EFFICIENCY, MERCHANTABILITY, OR
\r
13 FUNCTIONING OF THIS SOFTWARE AND/OR DOCUMENTATION. IN
\r
14 NO EVENT WILL RYAN "FRIKAC" SMITH BE LIABLE FOR ANY
\r
15 GENERAL, CONSEQUENTIAL, INDIRECT, INCIDENTAL,
\r
16 EXEMPLARY, OR SPECIAL DAMAGES, EVEN IF RYAN "FRIKAC"
\r
17 SMITH HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
\r
18 DAMAGES, IRRESPECTIVE OF THE CAUSE OF SUCH DAMAGES.
\r
20 You accept this software on the condition that you
\r
21 indemnify and hold harmless Ryan "FrikaC" Smith from
\r
22 any and all liability or damages to third parties,
\r
23 including attorney fees, court costs, and other
\r
24 related costs and expenses, arising out of your use
\r
25 of this software irrespective of the cause of said
\r
28 The export from the United States or the subsequent
\r
29 reexport of this software is subject to compliance
\r
30 with United States export control and munitions
\r
31 control restrictions. You agree that in the event you
\r
32 seek to export this software, you assume full
\r
33 responsibility for obtaining all necessary export
\r
34 licenses and approvals and for assuring compliance
\r
35 with applicable reexport restrictions.
\r
37 Any reproduction of this software must contain
\r
38 this notice in its entirety.
\r
40 ======================================
\r
41 These installation instructions only apply to Normal Quake (as does this
\r
42 entire file). For QuakeWorld, please refer to bot_qw.qc
\r
44 --------------------------------------
\r
45 To install on a new mod, do all this:
\r
46 --------------------------------------
\r
47 Place all included bot*.qc files in the subdirectory "frikbot"
\r
48 in your source folder, then...
\r
50 * Add the following lines to progs.src right after the defs.qc line
\r
53 frikbot/bot_fight.qc
\r
60 --------------------------------------
\r
61 * Comment out the following functions in defs.qc
\r
62 sound, stuffcmd, sprint, aim, centerprint, setspawnparms
\r
63 WriteByte, WriteChar, WriteShort, WriteLong, WriteCoord
\r
64 WriteAngle, WriteString, WriteEntity
\r
65 --------------------------------------
\r
66 * Add this to worldspawn() in world.qc, right at the very top, before InitBodyQue();
\r
67 BotInit(); // FrikBot
\r
68 --------------------------------------
\r
69 * add this line to StartFrame() in world.qc, at the very top
\r
70 BotFrame(); // FrikBot
\r
71 --------------------------------------
\r
72 * Add these two lines to PlayerPreThink in client.qc at the very top
\r
73 if (BotPreFrame()) // FrikBot
\r
75 --------------------------------------
\r
76 * Add this line to PlayerPostThink in client.qc at the very top
\r
77 if (BotPostFrame()) // FrikBot
\r
79 --------------------------------------
\r
80 * Add the following line to the very top of Client Connect in client.qc
\r
81 ClientInRankings(); // FrikBot
\r
82 --------------------------------------
\r
83 * Add these lines to the very top of ClientDisconnect in client.qc
\r
84 ClientDisconnected(); // FrikBot
\r
85 --------------------------------------
\r
88 void() bot_map_load =
\r
90 // place your qc loaded waypoints here
\r
91 //if (mapname == "mattrye1_nex")
\r
92 // map_mattrye1_nex();
\r
96 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
98 Variables and shtuff
\r
100 bot.qc has become pretty much a header file
\r
101 for all variable in the bot...
\r
103 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
106 // ----- entity fields ---
\r
107 .float wallhug, keys, oldkeys, ishuman;
\r
108 .float b_frags, b_clientno, b_shirt, b_pants;
\r
109 .float ai_time, b_sound, missile_speed;
\r
110 .float portal_time, b_skill, switch_wallhug;
\r
111 .float b_aiflags, b_num, b_chattime;
\r
112 .float b_menu, b_menu_time, b_menu_value;
\r
113 .float route_failed, dyn_flags, dyn_time;
\r
115 .entity temp_way, last_way, phys_obj;
\r
116 .entity target1, target2, target3, target4;
\r
117 .entity _next, _last;
\r
118 .entity current_way;
\r
119 .vector b_angle, mouse_emu, obs_dir;
\r
120 .vector movement, b_dir;
\r
123 .float search_time;
\r
124 .vector dest1, dest2;
\r
126 // --------defines-----
\r
127 //float SVC_UPDATENAME = 13;
\r
128 //float SVC_UPDATEFRAGS = 14;
\r
129 //float SVC_UPDATECOLORS = 17;
\r
131 // used for the physics & movement AI
\r
132 float KEY_MOVEUP = 1;
\r
133 float KEY_MOVEDOWN = 2;
\r
134 float KEY_MOVELEFT = 4;
\r
135 float KEY_MOVERIGHT = 8;
\r
136 float KEY_MOVEFORWARD = 16;
\r
137 float KEY_MOVEBACK = 32;
\r
138 float KEY_LOOKUP = 64;
\r
139 float KEY_LOOKDOWN = 128;
\r
140 float KEY_LOOKLEFT = 256;
\r
141 float KEY_LOOKRIGHT = 512;
\r
143 // these are aiflags for waypoints
\r
144 // some overlap to the bot
\r
145 float AI_TELELINK_1 = 1; // link type
\r
146 float AI_TELELINK_2 = 2; // link type
\r
147 float AI_TELELINK_3 = 4; // link type
\r
148 float AI_TELELINK_4 = 8; // link type
\r
149 float AI_DOORFLAG = 16; // read ahead
\r
150 float AI_PRECISION = 32; // read ahead + point
\r
151 float AI_SURFACE = 64; // point
\r
152 float AI_BLIND = 128; // read ahead + point
\r
153 float AI_JUMP = 256; // point + ignore
\r
154 float AI_DIRECTIONAL = 512; // read ahead + ignore
\r
155 float AI_PLAT_BOTTOM = 1024; // read ahead
\r
156 float AI_RIDE_TRAIN = 2048; // read ahead
\r
157 float AI_SUPER_JUMP = 4096; // point + ignore + route test
\r
158 float AI_SNIPER = 8192; // point type
\r
159 float AI_AMBUSH = 16384; // point type
\r
160 float AI_DOOR_NO_OPEN = 32768; // read ahead
\r
161 float AI_DIFFICULT = 65536; // route test
\r
162 float AI_TRACE_TEST = 131072; // route test
\r
163 float AI_CARELESS = 262144; // Electro - jumppads, bot doesn't have to touch this entity, only get close
\r
165 // these are flags for bots/players (dynamic/editor flags)
\r
166 float AI_OBSTRUCTED = 1;
\r
167 float AI_HOLD_SELECT = 2;
\r
168 float AI_ROUTE_FAILED = 2;
\r
170 float AI_DANGER = 8;
\r
174 float AI_POINT_TYPES = 29152;
\r
175 float AI_READAHEAD_TYPES = 36528;
\r
176 float AI_IGNORE_TYPES = 4864;
\r
178 float WM_UNINIT = 0;
\r
179 float WM_DYNAMIC = 1;
\r
180 float WM_LOADING = 2;
\r
181 float WM_LOADED = 3;
\r
182 float WM_EDITOR = 4;
\r
183 float WM_EDITOR_DYNAMIC = 5;
\r
184 float WM_EDITOR_DYNLINK = 6;
\r
187 float OPT_SAVEBOTS = 1;
\r
188 float OPT_NOCHAT = 2;
\r
190 // -------globals-----
\r
191 float active_clients;
\r
192 float max_clients, real_frametime;
\r
193 float bot_count, b_options;
\r
194 float waypoint_mode, dump_mode;
\r
195 float waypoints, direct_route;
\r
196 float sv_friction, sv_gravity;
\r
197 float sv_accelerate, sv_maxairspeed, sv_maxspeed, sv_stopspeed;
\r
199 entity route_table;
\r
200 entity b_temp1, b_temp2, b_temp3;
\r
201 entity player_head, phys_head, way_head;
\r
202 float busy_waypoints;
\r
203 float saved_bots, saved_skills1, saved_skills2, current_bots;
\r
205 // -------ProtoTypes------
\r
207 void() ClientConnect;
\r
208 void() ClientDisconnect;
\r
209 void() SetNewParms;
\r
212 float(float clientno) ClientBitFlag;
\r
213 float() ClientNextAvailable;
\r
214 void(float whichteam, float whatbot, float whatskill) BotConnect;
\r
215 void(entity bot) BotDisconnect;
\r
216 void(float clientno) BotInvalidClientNo;
\r
217 void(entity who) UpdateClient;
\r
220 void() DynamicWaypoint;
\r
221 entity(vector org) make_waypoint;
\r
222 void() ClearAllWays;
\r
223 void() FixWaypoints;
\r
224 float() begin_route;
\r
225 void(entity this, float direct) bot_get_path;
\r
226 void() WaypointThink;
\r
227 entity(entity start) FindWayPoint;
\r
229 // physics & movement
\r
230 float(entity e) bot_can_rj;
\r
232 void() frik_bot_roam;
\r
233 float(vector weird) frik_walkmove;
\r
234 void() frik_movetogoal;
\r
235 void() frik_obstacles;
\r
236 float(float flag) frik_recognize_plat;
\r
237 float(vector sdir) frik_KeysForDir;
\r
238 void(vector whichway, float danger) frik_obstructed;
\r
239 void() SV_Physics_Client;
\r
240 void() SV_ClientThink;
\r
244 string() PickARandomName;
\r
245 float(entity targ) fov;
\r
246 float(float y1, float y2) angcomp;
\r
247 float(entity targ1, entity targ2) wisible;
\r
248 float(entity targ) sisible;
\r
249 float(entity targ) fisible;
\r
250 vector(entity ent) realorigin;
\r
251 void(entity ent) target_drop;
\r
252 void(entity ent) target_add;
\r
254 void() BotImpulses;
\r
255 void(entity targ, float success) bot_lost;
\r
256 string(float r) BotName;
\r
257 float(float v) frik_anglemod;
\r
259 void(float tpic) bot_start_topic;
\r
264 void() bot_way_edit;
\r
265 void() bot_menu_display;
\r
268 // ----------Commands---------
\r
269 void(entity e, float chan, string samp, float vol, float atten) frik_sound = #8;
\r
270 void(entity client, string s) frik_stuffcmd = #21;
\r
271 void(entity client, string s) frik_sprint = #24;
\r
272 vector(entity e, float sped) frik_aim = #44;
\r
273 void(entity client, string s) frik_centerprint = #73;
\r
274 void(entity e) frik_setspawnparms = #78;
\r
275 void(float to, float f) frik_WriteByte = #52;
\r
276 void(float to, float f) frik_WriteChar = #53;
\r
277 void(float to, float f) frik_WriteShort = #54;
\r
278 void(float to, float f) frik_WriteLong = #55;
\r
279 void(float to, float f) frik_WriteCoord = #56;
\r
280 void(float to, float f) frik_WriteAngle = #57;
\r
281 void(float to, string s) frik_WriteString = #58;
\r
282 void(float to, entity s) frik_WriteEntity = #59;
\r
284 void(entity client, string s1, string s2, string s3, string s4, string s5, string s6, string s7)
\r
285 frik_big_centerprint = #73;
\r
287 //----------------------------------------------------------------------------
\r
290 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
292 Function redclarations. These allow function
\r
293 designed to work for clients (sprint, so forth)
\r
294 to mainly not complain when working with a bot
\r
296 Although these shouldn't be needed anymore,
\r
297 as the bots truly are clients now, if you don't
\r
298 stop the SZ_ buffer from filling up by disabling
\r
299 direct messages to the bots, it crashes quake :-(
\r
301 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
303 void(entity client, string s) stuffcmd =
\r
305 if (client.ishuman == 1)
\r
306 frik_stuffcmd(client, s);
\r
307 b_temp1 = player_head;
\r
311 if (b_temp1.classname == "botcam")
\r
313 if ((b_temp1.enemy == client) && b_temp1.ishuman)
\r
314 frik_stuffcmd(b_temp1, s);
\r
316 b_temp1 = b_temp1._next;
\r
320 void(entity e) setspawnparms =
\r
322 if (e.ishuman == 1)
\r
323 frik_setspawnparms(e);
\r
326 b_temp1 = player_head;
\r
329 if (b_temp1.ishuman)
\r
331 frik_setspawnparms(b_temp1);
\r
334 b_temp1 = b_temp1._next;
\r
339 void(entity client, string s) sprint =
\r
341 if (client.ishuman == 1)
\r
342 frik_sprint(client, s);
\r
343 b_temp1 = player_head;
\r
347 if (b_temp1.classname == "botcam")
\r
349 if ((b_temp1.enemy == client) && b_temp1.ishuman)
\r
350 frik_sprint(b_temp1, s);
\r
352 b_temp1 = b_temp1._next;
\r
356 void(entity client, string s) centerprint =
\r
358 if (client.ishuman == 1)
\r
359 frik_centerprint(client, s);
\r
360 b_temp1 = player_head;
\r
364 if (b_temp1.classname == "botcam")
\r
366 if ((b_temp1.enemy == client) && b_temp1.ishuman)
\r
367 frik_centerprint(b_temp1, s);
\r
369 b_temp1 = b_temp1._next;
\r
373 vector(entity e, float sped) aim =
\r
375 e.missile_speed = sped;
\r
376 return frik_aim(e, sped);
\r
379 void(entity e, float chan, string samp, float vol, float atten) sound =
\r
382 frik_sound(e, chan, samp, vol, atten);
\r
383 if (samp == "items/inv3.wav")
\r
385 else if (e.classname == "player")
\r
386 e.b_sound = time + 1;
\r
387 else if (other.classname == "player")
\r
388 other.b_sound = time + 1;
\r
391 void(float to, float f) WriteByte =
\r
393 if ((to == MSG_ONE) && (msg_entity.ishuman != TRUE))
\r
395 frik_WriteByte(to, f);
\r
397 void(float to, float f) WriteChar =
\r
399 if ((to == MSG_ONE) && (msg_entity.ishuman != TRUE))
\r
401 frik_WriteChar(to, f);
\r
403 void(float to, float f) WriteShort =
\r
405 if ((to == MSG_ONE) && (msg_entity.ishuman != TRUE))
\r
407 frik_WriteShort(to, f);
\r
409 void(float to, float f) WriteLong =
\r
411 if ((to == MSG_ONE) && (msg_entity.ishuman != TRUE))
\r
413 frik_WriteLong(to, f);
\r
415 void(float to, float f) WriteCoord =
\r
417 if ((to == MSG_ONE) && (msg_entity.ishuman != TRUE))
\r
419 frik_WriteCoord(to, f);
\r
421 void(float to, float f) WriteAngle =
\r
423 if ((to == MSG_ONE) && (msg_entity.ishuman != TRUE))
\r
425 frik_WriteAngle(to, f);
\r
427 void(float to, string s) WriteString =
\r
429 if ((to == MSG_ONE) && (msg_entity.ishuman != TRUE))
\r
431 frik_WriteString(to, s);
\r
433 void(float to, entity s) WriteEntity =
\r
435 if ((to == MSG_ONE) && (msg_entity.ishuman != TRUE))
\r
437 frik_WriteEntity(to, s);
\r
440 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
442 Bot Cam, see what the bot sees (or any other player)
\r
444 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
449 if (self.classname != "botcam")
\r
451 setorigin(self, self.enemy.origin);
\r
452 self.items = self.enemy.items;
\r
453 self.weapon = self.enemy.weapon;
\r
454 self.weaponmodel = self.enemy.weaponmodel;
\r
455 self.currentammo = self.enemy.currentammo;
\r
456 self.weaponframe = self.enemy.weaponframe;
\r
457 self.ammo_shells = self.enemy.ammo_shells;
\r
458 self.ammo_nails = self.enemy.ammo_nails;
\r
459 self.ammo_rockets= self.enemy.ammo_rockets;
\r
460 self.ammo_cells = self.enemy.ammo_cells;
\r
461 self.view_ofs = self.enemy.view_ofs;
\r
462 self.health = self.enemy.health;
\r
463 self.armorvalue = self.enemy.armorvalue;
\r
464 self.dmg_take = self.enemy.dmg_take;
\r
465 self.dmg_save = self.enemy.dmg_save;
\r
466 self.dmg_inflictor = self.enemy.dmg_inflictor;
\r
467 self.punchangle = self.enemy.punchangle;
\r
468 self.deadflag = self.enemy.deadflag;
\r
470 WriteByte (MSG_ONE,5);
\r
471 WriteEntity (MSG_ONE, self.enemy);
\r
472 WriteByte (MSG_ONE, 10);
\r
473 WriteAngle (MSG_ONE,self.enemy.v_angle_x);
\r
474 WriteAngle (MSG_ONE,self.enemy.v_angle_y);
\r
475 WriteAngle (MSG_ONE,self.enemy.v_angle_z);
\r
476 self.modelindex = 0;
\r
486 // sloppy cycling code
\r
487 if (self.classname != "botcam")
\r
489 self.enemy = player_head;
\r
494 self.enemy = self.enemy._next;
\r
495 while (self.enemy.classname == "botcam");
\r
497 if (self.enemy == self)
\r
500 self.enemy = self.enemy._next;
\r
501 while (self.enemy.classname == "botcam");
\r
504 self.classname = "botcam";
\r
505 self.solid = SOLID_NOT;
\r
506 self.movetype = MOVETYPE_NONE;
\r
507 self.takedamage = DAMAGE_NO;
\r
512 sprint(self, "No one left to track!\n");
\r
514 WriteByte (MSG_ONE,5);
\r
515 WriteEntity (MSG_ONE, self);
\r
516 PutClientInServer();
\r
519 if (!self.enemy.ishuman)
\r
521 self.enemy.dmg_take = 0;
\r
522 self.enemy.dmg_save = 0;
\r
524 sprint(self, "Now tracking ");
\r
525 sprint(self, self.enemy.netname);
\r
526 sprint(self, "\n");
\r
532 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
534 Stuff mentioned up top
\r
535 it just links the bot into the mod
\r
537 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
540 void() ClientFixRankings =
\r
543 if (self.switch_wallhug > time)
\r
545 self.switch_wallhug = 0;
\r
547 b_temp2 = nextent(world);
\r
550 while (cno < max_clients)
\r
552 if ((!b_temp2.ishuman) && (active_clients & ClientBitFlag(cno)))
\r
553 UpdateClient(b_temp2);
\r
555 b_temp2 = nextent(b_temp2);
\r
559 void() ClientInRankings =
\r
563 player_head._last = self;
\r
565 self._next = player_head;
\r
566 self._last = world;
\r
567 player_head = self;
\r
569 if (!self.phys_obj)
\r
571 b_temp2 = phys_head;
\r
572 while (b_temp2 != world && b_temp2.owner != self)
\r
573 b_temp2 = b_temp2._next;
\r
574 self.phys_obj = b_temp2;
\r
577 if (self.ishuman == 2)
\r
579 self.ishuman = FALSE;
\r
582 cno = self.colormap - 1;
\r
583 BotInvalidClientNo (cno);
\r
584 active_clients = active_clients | ClientBitFlag(cno);
\r
586 self.b_clientno = cno;
\r
587 self.ishuman = TRUE;
\r
588 self.switch_wallhug = time + 1;
\r
592 void() ClientDisconnected =
\r
594 if (player_head == self)
\r
595 player_head = self._next;
\r
597 self._next._last = self._last;
\r
599 self._last._next = self._next;
\r
601 active_clients = active_clients - active_clients & ClientBitFlag(self.b_clientno);
\r
604 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
606 BotPreFrame & BotPostFrame, used to make the
\r
607 bot easier to install
\r
609 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
611 float () BotPreFrame =
\r
613 if (self.b_clientno == -1)
\r
617 if (self.switch_wallhug)
\r
618 ClientFixRankings();
\r
619 if (self.classname == "botcam")
\r
622 if (self.b_frags != self.frags)
\r
625 if (self.b_frags > self.frags)
\r
627 if (pointcontents(self.origin) == CONTENT_LAVA)
\r
628 bot_start_topic(10);
\r
630 bot_start_topic(9);
\r
633 bot_start_topic(2);
\r
634 self.b_frags = self.frags;
\r
639 float () BotPostFrame =
\r
641 if (self.b_clientno == -1)
\r
646 if (waypoint_mode > WM_LOADED)
\r
647 bot_menu_display();
\r
658 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
662 The rest of this code is in bot_misc.qc
\r
664 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
666 void(string h) BotSay = // simulate talking by composing a 'chat' message
\r
668 WriteByte(MSG_ALL, 8);
\r
669 WriteByte(MSG_ALL, 1);
\r
670 WriteString(MSG_ALL, self.netname);
\r
671 WriteByte(MSG_ALL, 8);
\r
672 WriteByte(MSG_ALL, 2);
\r
673 WriteString(MSG_ALL, h);
\r
675 void() BotSayInit =
\r
677 WriteByte(MSG_ALL, 8);
\r
678 WriteByte(MSG_ALL, 1);
\r
679 WriteString(MSG_ALL, self.netname);
\r
681 void(string h) BotSay2 =
\r
683 WriteByte(MSG_ALL, 8);
\r
684 WriteByte(MSG_ALL, 2);
\r
685 WriteString(MSG_ALL, h);
\r
687 void(string h) BotSayTeam =
\r
695 if (t.team == self.team)
\r
698 WriteByte(MSG_ONE, 8);
\r
699 WriteByte(MSG_ONE, 1);
\r
700 WriteByte(MSG_ONE, 40);
\r
701 WriteString(MSG_ONE, self.netname);
\r
702 WriteByte(MSG_ONE, 8);
\r
703 WriteByte(MSG_ONE, 2);
\r
704 WriteByte(MSG_ONE, 41);
\r
705 WriteString(MSG_ONE, h);
\r
711 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
715 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
721 local entity ent, fisent;
\r
722 local float numents;
\r
724 // spawn entities for the physics
\r
725 ent = nextent(world);
\r
728 while(ent != world)
\r
730 max_clients = max_clients + 1;
\r
731 ent = nextent(ent);
\r
733 if (max_clients > 16)
\r
736 ent = nextent(world);
\r
738 while (numents < max_clients)
\r
741 phys_head = spawn();
\r
743 fisent._next = phys_head;
\r
744 phys_head._last = fisent;
\r
745 fisent = phys_head;
\r
746 ent.phys_obj = phys_head;
\r
747 phys_head.classname = "phys_obj";
\r
748 phys_head.owner = ent;
\r
749 numents = numents + 1;
\r
750 ent = nextent(ent);
\r
752 //precache_model("progs/s_light.spr"); // file missing from nexuiz
\r
753 //precache_model("progs/s_bubble.spr"); // file missing from nexuiz
\r
754 // the bots return!
\r
755 b_options = cvar("saved1");
\r
756 if (coop || (b_options & OPT_SAVEBOTS))
\r
758 saved_bots = cvar("scratch1");
\r
759 saved_skills1 = cvar("scratch2");
\r
760 saved_skills2 = cvar("scratch3");
\r
762 cvar_set ("saved4", "0");
\r
763 if (max_clients > 1)
\r
765 localcmd("exec maps/");
\r
767 localcmd(".way\n");
\r
768 waypoint_mode = WM_DYNAMIC;
\r
772 waypoint_mode = WM_LOADED;
\r
777 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
779 Rankings 'utilities'. Written by Alan Kivlin,
\r
780 this code just fools clients by sending precisely
\r
781 the same network messages as when a real player
\r
782 signs on to the server.
\r
784 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
788 void(entity who) UpdateClient =
\r
790 WriteByte (MSG_ALL, SVC_UPDATENAME);
\r
791 WriteByte (MSG_ALL, who.b_clientno);
\r
792 WriteString (MSG_ALL, who.netname);
\r
793 WriteByte (MSG_ALL, SVC_UPDATECOLORS);
\r
794 WriteByte (MSG_ALL, who.b_clientno);
\r
795 WriteByte (MSG_ALL, who.b_shirt * 16 + who.b_pants);
\r
796 WriteByte (MSG_ALL, SVC_UPDATEFRAGS);
\r
797 WriteByte (MSG_ALL, who.b_clientno);
\r
798 WriteShort (MSG_ALL, who.frags);
\r
801 float(float clientno) ClientBitFlag =
\r
803 // bigger, but faster
\r
806 else if (clientno == 1)
\r
808 else if (clientno == 2)
\r
810 else if (clientno == 3)
\r
812 else if (clientno == 4)
\r
814 else if (clientno == 5)
\r
816 else if (clientno == 6)
\r
818 else if (clientno == 7)
\r
820 else if (clientno == 8)
\r
822 else if (clientno == 9)
\r
824 else if (clientno == 10)
\r
826 else if (clientno == 11)
\r
828 else if (clientno == 12)
\r
830 else if (clientno == 13)
\r
832 else if (clientno == 14)
\r
834 else if (clientno == 15)
\r
839 float() ClientNextAvailable =
\r
841 local float clientno;
\r
843 clientno = max_clients;
\r
844 while(clientno > 0)
\r
846 clientno = clientno - 1;
\r
848 if(!(active_clients & ClientBitFlag(clientno)))
\r
856 void(entity e1, entity e2, float flag) DeveloperLightning =
\r
858 // used to show waypoint links for debugging
\r
859 WriteByte (MSG_BROADCAST, 23);
\r
861 WriteByte (MSG_BROADCAST, 6);
\r
863 WriteByte (MSG_BROADCAST, 13);
\r
864 WriteEntity (MSG_BROADCAST, e2);
\r
865 WriteCoord (MSG_BROADCAST, e1.origin_x);
\r
866 WriteCoord (MSG_BROADCAST, e1.origin_y);
\r
867 WriteCoord (MSG_BROADCAST, e1.origin_z);
\r
868 WriteCoord (MSG_BROADCAST, e2.origin_x);
\r
869 WriteCoord (MSG_BROADCAST, e2.origin_y);
\r
870 WriteCoord (MSG_BROADCAST, e2.origin_z);
\r
874 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
880 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
883 float(float tcolor) FindAnotherColor =
\r
885 local float bestbet, scolor, pcount, bestp;
\r
890 if (scolor != tcolor)
\r
892 b_temp2 = player_head;
\r
894 while(b_temp2 != world)
\r
896 if (b_temp2.team == scolor + 1)
\r
897 pcount = pcount + 1;
\r
898 b_temp2 = b_temp2._next;
\r
900 if ((pcount < bestp) && pcount)
\r
906 scolor = scolor + 1;
\r
911 while (bestbet == tcolor)
\r
913 bestbet = floor(random() * 13);
\r
920 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
922 BotConnect and related functions.
\r
924 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
926 entity(float num) GetClientEntity =
\r
934 upsy = nextent(upsy);
\r
939 void(float whichteam, float whatbot, float whatskill) BotConnect =
\r
943 local entity uself;
\r
945 f = ClientNextAvailable();
\r
949 bprint("Unable to connect a bot, server is full.\n");
\r
955 active_clients = active_clients | ClientBitFlag(f);
\r
956 bot_count = bot_count + 1;
\r
957 self = GetClientEntity(f);
\r
959 bot_start_topic(1);
\r
960 self.b_clientno = f;
\r
961 self.colormap = f + 1;
\r
963 self.netname = BotName(whatbot);
\r
965 self.netname = PickARandomName();
\r
968 // players can set skill all weird, so leave these checks in
\r
969 whatskill = rint(whatskill);
\r
972 else if (whatskill < 0)
\r
974 self.b_skill = whatskill;
\r
976 if (teamplay && !coop)
\r
979 self.b_pants = FindAnotherColor(uself.team - 1);
\r
981 self.b_pants = uself.team - 1;
\r
982 self.b_shirt = self.b_pants;
\r
985 self.team = self.b_pants + 1;
\r
986 UpdateClient(self);
\r
990 PutClientInServer();
\r
992 // this is risky... could corrupt .way files if done wrong
\r
993 // If you're not the gambling type, comment this out
\r
995 f = ClientBitFlag(self.b_num - 1);
\r
996 current_bots = current_bots | f;
\r
998 if (self.b_num <= 8)
\r
999 saved_skills1 = (saved_skills1 & (65536 - (3 * f)) | (self.b_skill * f));
\r
1002 f = ClientBitFlag(self.b_num - 9);
\r
1003 saved_skills2 = (saved_skills2 & (65536 - (3 * f)) | (self.b_skill * f));
\r
1006 h = ftos(current_bots);
\r
1007 cvar_set("scratch1", h);
\r
1008 h = ftos(saved_skills1);
\r
1009 cvar_set("scratch2", h);
\r
1010 h = ftos(saved_skills2);
\r
1011 cvar_set("scratch3", h);
\r
1016 void(entity bot) BotDisconnect =
\r
1019 local entity uself;
\r
1023 bot_count = bot_count - 1;
\r
1024 current_bots = current_bots - (current_bots & ClientBitFlag(self.b_num - 1));
\r
1025 h = ftos(current_bots);
\r
1026 cvar_set("scratch1", h);
\r
1029 ClientDisconnect();
\r
1031 if (self.b_clientno != -1)
\r
1033 // the bot's client number is not in use by a real player so we
\r
1034 // must remove it's entry in the rankings
\r
1035 // Quake engine sets all fields to 0, can only do the most important here
\r
1036 self.b_frags = self.frags = 0;
\r
1037 self.netname = "";
\r
1038 self.classname = "";
\r
1041 self.armorvalue = 0;
\r
1042 self.weaponmodel = "";
\r
1045 self.ammo_shells = self.ammo_nails = self.ammo_rockets = self.ammo_cells = 0;
\r
1046 UpdateClient(self);
\r
1047 active_clients = active_clients - (active_clients & ClientBitFlag(self.b_clientno));
\r
1048 self.b_clientno = -1;
\r
1053 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
1055 BotInvalidClientNo
\r
1056 kicks a bot if a player connects and takes the bot's space
\r
1058 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
1061 void(float clientno) BotInvalidClientNo =
\r
1065 bot = GetClientEntity(clientno);
\r
1066 if(bot.b_clientno > 0)
\r
1070 bot.b_clientno = -1;
\r
1071 BotDisconnect(bot);
\r
1072 active_clients = active_clients | ClientBitFlag(self.b_clientno);
\r
1073 BotConnect(0, bot.b_num, bot.b_skill);
\r
1080 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
1082 Waypoint Loading from file
\r
1084 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
1086 void() LoadWaypoint =
\r
1091 org_x = cvar("saved1");
\r
1092 org_y = cvar("saved2");
\r
1093 org_z = cvar("saved3");
\r
1095 tep = make_waypoint(org);
\r
1097 r = cvar("saved4");
\r
1099 tep.b_aiflags = floor(r / 4);
\r
1100 tep.b_pants = cvar("scratch1");
\r
1101 tep.b_skill = cvar("scratch2");
\r
1102 tep.b_shirt = cvar("scratch3");
\r
1103 tep.b_frags = cvar("scratch4");
\r
1106 void() bot_return =
\r
1110 if ((waypoint_mode == WM_DYNAMIC) || (waypoint_mode == WM_LOADED))
\r
1112 // minor precaution
\r
1114 if (saved_bots & 1) BotConnect(0, 1, saved_skills1 & 3);
\r
1115 if (saved_bots & 2) BotConnect(0, 2, (saved_skills1 & 12) / 4);
\r
1116 if (saved_bots & 4) BotConnect(0, 3, (saved_skills1 & 48) / 16);
\r
1117 if (saved_bots & 8) BotConnect(0, 4, (saved_skills1 & 192) / 64);
\r
1118 if (saved_bots & 16) BotConnect(0, 5, (saved_skills1 & 768) / 256);
\r
1119 if (saved_bots & 32) BotConnect(0, 6, (saved_skills1 & 3072) / 1024);
\r
1120 if (saved_bots & 64) BotConnect(0, 7, (saved_skills1 & 12288) / 4096);
\r
1121 if (saved_bots & 128) BotConnect(0, 8, (saved_skills1 & 49152) / 16384);
\r
1122 if (saved_bots & 256) BotConnect(0, 9, saved_skills2 & 3);
\r
1123 if (saved_bots & 512) BotConnect(0, 10, (saved_skills2 & 12) / 4);
\r
1124 if (saved_bots & 1024) BotConnect(0, 11, (saved_skills2& 48) / 16);
\r
1125 if (saved_bots & 2048) BotConnect(0, 12, (saved_skills2 & 192) / 64);
\r
1126 if (saved_bots & 4096) BotConnect(0, 13, (saved_skills2 & 768) / 256);
\r
1127 if (saved_bots & 8192) BotConnect(0, 14, (saved_skills2 & 3072) / 1024);
\r
1128 if (saved_bots & 16384) BotConnect(0, 15, (saved_skills2 & 12288) / 4096);
\r
1129 if (saved_bots & 32768) BotConnect(0, 16, (saved_skills2 & 49152) / 16384);
\r
1136 void() WaypointWatch =
\r
1138 // Waypoint Baywatch
\r
1139 local float bigboobs;
\r
1142 if (max_clients < 2)
\r
1144 if (waypoint_mode != WM_UNINIT)
\r
1146 bigboobs = cvar("saved4");
\r
1147 if (bigboobs != 0)
\r
1149 if ((bigboobs & 3) == 1)
\r
1151 else if ((bigboobs & 3) == 3)
\r
1154 h = ftos(b_options);
\r
1155 cvar_set("saved1", h);
\r
1156 cvar_set("saved4", "0");
\r
1157 cvar_set("scratch1", "0");
\r
1158 waypoint_mode = WM_LOADED;
\r
1162 waypoint_mode = WM_LOADING;
\r
1163 cvar_set("saved4", "0");
\r
1171 // for the sake of speed
\r
1172 sv_maxairspeed = cvar("sv_maxairspeed");
\r
1173 sv_maxspeed = cvar("sv_maxspeed");
\r
1174 sv_gravity = cvar("sv_gravity");
\r
1175 sv_friction = cvar("sv_friction");
\r
1176 sv_accelerate = cvar("sv_accelerate");
\r
1177 sv_stopspeed = cvar("sv_stopspeed");
\r
1178 real_frametime = frametime; // in NQ this is alright
\r
1180 self = nextent(world);
\r
1182 while (num < max_clients)
\r
1184 if (self.ishuman == FALSE)
\r
1186 if (active_clients & ClientBitFlag(num))
\r
1191 SV_Physics_Client();
\r
1194 self = nextent(self);
\r
1204 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
1206 Bot Impulses. Allows the player to perform bot
\r
1207 related functions.
\r
1209 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
1212 void() BotImpulses =
\r
1215 if (self.impulse == 100)
\r
1217 f = cvar("skill");
\r
1218 BotConnect(0, 0, f);
\r
1220 if (self.impulse == 101)
\r
1222 f = cvar("skill");
\r
1223 BotConnect(1, 0, f);
\r
1225 else if (self.impulse == 102)
\r
1227 else if (self.impulse == 103)
\r
1229 else if (self.impulse == 104)
\r