runrobot.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961
  1. /* $Id$
  2. * MegaZeux
  3. *
  4. * Copyright (C) 1996 Greg Janson
  5. * Copyright (C) 1998 Matthew D. Williams - dbwilli@scsn.net
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21. // Functions for running those robots during gameplay
  22. #include "profile.h"
  23. #include "error.h"
  24. #include "ezboard.h"
  25. #include "saveload.h"
  26. #include <stdio.h>
  27. #include "palette.h"
  28. #include "egacode.h"
  29. #include "intake.h"
  30. #include "edit.h"
  31. #include "random.h"
  32. #include "beep.h"
  33. #include "getkey.h"
  34. #include "graphics.h"
  35. #include "arrowkey.h"
  36. #include "scrdisp.h"
  37. #include "window.h"
  38. #include "sfx.h"
  39. extern int topindex,backindex;
  40. #include "mod.h"
  41. #include "idarray.h"
  42. #include "runrobot.h"
  43. #include "struct.h"
  44. #include "const.h"
  45. #include "data.h"
  46. #include "string.h"
  47. #include "counter.h"
  48. #include "game.h"
  49. #include "game2.h"
  50. #include "roballoc.h"
  51. #include "expr.h"
  52. // Strings! - Exo
  53. #include "mstring.h"
  54. #include <stdlib.h>
  55. #pragma warn -sig
  56. char far *item_to_counter[9]={
  57. "GEMS",
  58. "AMMO",
  59. "TIME",
  60. "SCORE",
  61. "HEALTH",
  62. "LIVES",
  63. "LOBOMBS",
  64. "HIBOMBS",
  65. "COINS" };
  66. // Send all robots or robot ID to default labels. For easy
  67. // interface to ASM. Label ids-
  68. //
  69. // 0=touch
  70. // 1=bombed
  71. // 2=invinco } automatically sent to "all"
  72. // 3=pushed
  73. // 4=playershot \
  74. // 5=neutralshot } if no find, try shot
  75. // 6=enemyshot /
  76. // 7=playerhit } automatically sent to "all"
  77. // 8=lazer
  78. // 9=spitfire
  79. //10=justloaded } automatically sent to "all"
  80. //11=justentered } automatically sent to "all"
  81. //12=touchgoop } automatically sent to "all"
  82. //13=playerhurt } automatically sent to "all"
  83. void send_robot_def(int robot_id,char mesg_id) {
  84. enter_func("send_robot_def");
  85. switch(mesg_id) {
  86. case 0:
  87. send_robot_id(robot_id,"TOUCH");
  88. break;
  89. case 1:
  90. send_robot_id(robot_id,"BOMBED");
  91. break;
  92. case 2:
  93. send_robot("ALL","INVINCO");
  94. break;
  95. case 3:
  96. send_robot_id(robot_id,"PUSHED");
  97. break;
  98. case 4:
  99. if(!send_robot_id(robot_id,"PLAYERSHOT")) break;
  100. shot:
  101. send_robot_id(robot_id,"SHOT");
  102. break;
  103. case 5:
  104. if(send_robot_id(robot_id,"NEUTRALSHOT")) goto shot;
  105. break;
  106. case 6:
  107. if(send_robot_id(robot_id,"ENEMYSHOT")) goto shot;
  108. break;
  109. case 7:
  110. send_robot("ALL","PLAYERHIT");
  111. break;
  112. case 8:
  113. send_robot_id(robot_id,"LAZER");
  114. break;
  115. case 9:
  116. send_robot_id(robot_id,"SPITFIRE");
  117. break;
  118. case 10:
  119. send_robot("ALL","JUSTLOADED");
  120. break;
  121. case 11:
  122. send_robot("ALL","JUSTENTERED");
  123. break;
  124. case 12:
  125. send_robot("ALL","GOOPTOUCHED");
  126. break;
  127. case 13:
  128. send_robot("ALL","PLAYERHURT");
  129. break;
  130. }
  131. exit_func();
  132. }
  133. void send_robot(char far *robot,char far *mesg,char ignore_lock) {
  134. int t1,t2,t3,t4,x,y;
  135. char under;
  136. enter_func("send_robot");
  137. if(!str_cmp(robot,"ALL")) {
  138. //Sent to all
  139. for(t1=1;t1<=NUM_ROBOTS;t1++)
  140. if(robots[t1].used)
  141. send_robot_id(t1,mesg,ignore_lock);
  142. }
  143. else {
  144. t1=1;
  145. do {
  146. if(!str_cmp(robot,robots[t1].robot_name))
  147. if(robots[t1].used)
  148. send_robot_id(t1,mesg,ignore_lock);
  149. } while(++t1<=NUM_ROBOTS);
  150. }
  151. //Sensors
  152. //Set t2 to cmd- 0-3 move, 4 die, 256+# char, 512+# color (hex)
  153. t2=-1;//No command yet
  154. //Check movement commands
  155. if(mesg[1]==0) {
  156. t1=mesg[0]; if((t1>='a')&&(t1<='z')) t1-=32;
  157. switch(t1) {
  158. case 'N': t2=0; break;
  159. case 'S': t2=1; break;
  160. case 'E': t2=2; break;
  161. case 'W': t2=3; break;
  162. }
  163. }
  164. //Die?
  165. if(!str_cmp("DIE",mesg)) t2=4;
  166. //Char___? (___ can be ### or 'c')
  167. t1=mesg[4];
  168. mesg[4]=0;
  169. if(!str_cmp("CHAR",mesg)) t2=256;
  170. mesg[4]=t1;
  171. //Color__? (__ is hex)
  172. t1=mesg[5];
  173. mesg[5]=0;
  174. if(!str_cmp("COLOR",mesg)) t2=512;
  175. mesg[5]=t1;
  176. //Get char/color value
  177. if(t2==256) {
  178. if(mesg[4]=='\'') t2+=(unsigned char)(mesg[5]);
  179. else t2+=(unsigned char)(atoi(&mesg[4])&255);
  180. }
  181. else if(t2==512) t2+=(unsigned char)strtol(&mesg[5],NULL,16);
  182. if(t2==-1) {
  183. exit_func();
  184. return;//Not a legal command
  185. }
  186. //Run the sensor cmd
  187. for(t1=1;t1<NUM_SENSORS;t1++) {
  188. if(sensors[t1].used) {
  189. if((!str_cmp(sensors[t1].sensor_name,robot))||
  190. (!str_cmp(robot,"ALL"))) {
  191. //Find sensor
  192. if((t2<256)||(t2>511)) {//Don't bother for a char cmd
  193. under=0;
  194. if(level_under_id[player_x+player_y*max_bxsiz]==122) {
  195. if(level_under_param[player_x+player_y*max_bxsiz]==t1) {
  196. under=1;
  197. x=player_x;
  198. y=player_y;
  199. goto gotit;
  200. }
  201. }
  202. for(x=0;x<board_xsiz;x++) {
  203. for(y=0;y<board_ysiz;y++) {
  204. t3=x+y*max_bxsiz;
  205. if((level_id[t3]==122)&&(level_param[t3]==t1)) goto gotit;
  206. }
  207. }
  208. continue;//??? Not found!
  209. }
  210. gotit:
  211. //Cmd
  212. switch(t2) {
  213. case 0:
  214. case 1:
  215. case 2:
  216. case 3:
  217. if(under) {
  218. //Attempt to move player, then if ok,
  219. //put sensor underneath and delete from
  220. //original space.
  221. t3=_move(x,y,t2,1|2|4|8|16);
  222. if(t3==0) {
  223. //Moved! Find player...
  224. find_player();
  225. goto player_met;
  226. }
  227. else //Sensorthud!
  228. send_robot(sensors[t1].robot_to_mesg,"SENSORTHUD");
  229. //Done.
  230. }
  231. else {
  232. //Attempt to move sensor.
  233. t3=_move(x,y,t2,1|2|4|8|16|128);
  234. if(t3==2) {
  235. step_sensor(t1);
  236. player_met:
  237. t4=player_x+player_y*max_bxsiz;
  238. //Met player- so put under player!
  239. under_player_id=level_under_id[t4];
  240. under_player_param=level_under_param[t4];
  241. under_player_color=level_under_color[t4];
  242. level_under_id[t4]=122;
  243. level_under_param[t4]=t1;
  244. level_under_color[t4]=level_color[x+y*max_bxsiz];
  245. id_remove_top(x,y);
  246. }
  247. else if(t3!=0) {
  248. //Sensorthud!
  249. send_robot(sensors[t1].robot_to_mesg,"SENSORTHUD");
  250. }
  251. //Done.
  252. }
  253. break;
  254. case 4:
  255. if(under) {
  256. id_remove_under(x,y);
  257. clear_sensor(t1);
  258. }
  259. else {
  260. id_remove_top(x,y);
  261. clear_sensor(t1);
  262. }
  263. break;
  264. default:
  265. if((t2>255)&&(t2<512)) sensors[t1].sensor_char=t2-256;
  266. else {
  267. if(under) level_under_color[x+y*max_bxsiz]=t2-512;
  268. else level_color[x+y*max_bxsiz]=t2-512;
  269. }
  270. break;
  271. }
  272. }
  273. }
  274. }
  275. //Done.
  276. exit_func();
  277. }
  278. char send_robot_id(int id,char far *mesg,char ignore_lock) {
  279. unsigned int t1=1;
  280. unsigned char far *robot;
  281. char mesgcopy[257];
  282. enter_func("send_robot_id");
  283. char temp=curr_rmem_status;
  284. if((robots[id].is_locked)&&(!ignore_lock)) {
  285. exit_func();
  286. return 1;//Locked
  287. }
  288. if(robots[id].program_length<3) {
  289. exit_func();
  290. return 2;//No program!
  291. }
  292. str_cpy(mesgcopy,mesg);
  293. prepare_robot_mem(id==NUM_ROBOTS);
  294. robot=&robot_mem[robots[id].program_location];
  295. // Are we going to a subroutine? Returning? - Exo
  296. if(mesgcopy[0] == '#')
  297. {
  298. char far *robot_begin = robot_mem + robots[id].program_location;
  299. // Is there a stack?
  300. if((robot_begin[2] == 107) && (robot_begin[4] == '#') &&
  301. robot_begin[3] > 4)
  302. {
  303. int stack_pos = (int)robot_begin[5];
  304. // Check if the stack position is unitialized (*)
  305. if(stack_pos == '*')
  306. {
  307. stack_pos = 0;
  308. }
  309. // returning?
  310. if((!str_cmp(mesgcopy, "#return")) && (stack_pos != 0))
  311. {
  312. // So return there... but the stack pos must NOT be 0...
  313. robots[id].cur_prog_line =
  314. *((int far *)(robot_begin + 6 + (stack_pos << 1)));
  315. robots[id].pos_within_line=0;
  316. robots[id].cycle_count=robots[id].robot_cycle-1;
  317. prepare_robot_mem(temp);
  318. if(robots[id].status==1) robots[id].status=2;
  319. // And decrease the stack pos.
  320. robot_begin[5] = (char)stack_pos - 1;
  321. exit_func();
  322. return(0); // "Yippee?" :p
  323. }
  324. else
  325. {
  326. // returning to the TOP?
  327. if((!str_cmp(mesgcopy, "#top")) && (stack_pos != 0))
  328. {
  329. // So return there... but the stack pos must NOT be 0...
  330. robots[id].cur_prog_line =
  331. *((int far *)(robot_begin + 6 + 2));
  332. robots[id].pos_within_line=0;
  333. robots[id].cycle_count=robots[id].robot_cycle-1;
  334. prepare_robot_mem(temp);
  335. if(robots[id].status==1) robots[id].status=2;
  336. // And reset the stack pos.
  337. robot_begin[5] = 0;
  338. exit_func();
  339. return(0); // "Yippee?" :p
  340. }
  341. else
  342. {
  343. // Sending.. well it'll continue with the jump, just has to
  344. // put the return address on the stack.
  345. // Stack must NOT be full though. What's the stack size? (robot_begin[3] - 3)/2.
  346. if(stack_pos != ((robot_begin[3] - 3) >> 1))
  347. {
  348. stack_pos++;
  349. // The return position is the NEXT command.
  350. *((int far *)(robot_begin + 6 + (stack_pos << 1))) =
  351. robots[id].cur_prog_line +
  352. *(robot_begin + robots[id].cur_prog_line) + 2;
  353. // Fix stack pos.
  354. robot_begin[5] = (char)stack_pos;
  355. // Continue.
  356. }
  357. }
  358. }
  359. }
  360. }
  361. do {
  362. if(robot[t1+1]==106) {
  363. //Label- is it so?
  364. if(!str_cmp(&robot[t1+3],mesgcopy)) {
  365. robots[id].cur_prog_line=t1;
  366. robots[id].pos_within_line=0;
  367. robots[id].cycle_count=robots[id].robot_cycle-1;
  368. prepare_robot_mem(temp);
  369. if(robots[id].status==1) robots[id].status=2;
  370. exit_func();
  371. return 0;//Yippe!
  372. }
  373. }
  374. next_cmd:
  375. t1+=robot[t1]+2;
  376. } while(robot[t1]);
  377. prepare_robot_mem(temp);
  378. exit_func();
  379. return 2;
  380. }
  381. char first_prefix=0;//1-3 normal 5-7 is 1-3 but from a REL FIRST cmd
  382. char mid_prefix=0;
  383. char last_prefix=0;//See first_prefix
  384. //Run a set of x/y pairs through the prefixes
  385. void prefix_xy(int&fx,int&fy,int&mx,int&my,int&lx,int&ly,int robotx,
  386. int roboty) {
  387. enter_func("prefix_xy");
  388. if(level_id[player_x+player_y*max_bxsiz]!=127) find_player();
  389. switch(first_prefix) {
  390. case 1:
  391. case 5:
  392. fx+=robotx;
  393. fy+=roboty;
  394. break;
  395. case 2:
  396. case 6:
  397. fx+=player_x;
  398. fy+=player_y;
  399. break;
  400. case 3:
  401. fx+=get_counter("FIRSTXPOS");
  402. fy+=get_counter("FIRSTYPOS");
  403. break;
  404. case 7:
  405. fx+=get_counter("XPOS");
  406. fy+=get_counter("YPOS");
  407. break;
  408. }
  409. switch(mid_prefix) {
  410. case 1:
  411. mx+=robotx;
  412. my+=roboty;
  413. break;
  414. case 2:
  415. mx+=player_x;
  416. my+=player_y;
  417. break;
  418. case 3:
  419. mx+=get_counter("XPOS");
  420. my+=get_counter("YPOS");
  421. break;
  422. }
  423. switch(last_prefix) {
  424. case 1:
  425. case 5:
  426. lx+=robotx;
  427. ly+=roboty;
  428. break;
  429. case 2:
  430. case 6:
  431. lx+=player_x;
  432. ly+=player_y;
  433. break;
  434. case 3:
  435. lx+=get_counter("LASTXPOS");
  436. ly+=get_counter("LASTYPOS");
  437. break;
  438. case 7:
  439. lx+=get_counter("XPOS");
  440. ly+=get_counter("YPOS");
  441. break;
  442. }
  443. if(fx<0) fx=0;
  444. if(fy<0) fy=0;
  445. if(mx<0) mx=0;
  446. if(my<0) my=0;
  447. if(lx<0) lx=0;
  448. if(ly<0) ly=0;
  449. if(fx>=board_xsiz) fx=board_xsiz-1;
  450. if(fy>=board_ysiz) fy=board_ysiz-1;
  451. if(mx>=board_xsiz) mx=board_xsiz-1;
  452. if(my>=board_ysiz) my=board_ysiz-1;
  453. if(lx>=board_xsiz) lx=board_xsiz-1;
  454. if(ly>=board_ysiz) ly=board_ysiz-1;
  455. exit_func();
  456. }
  457. //Move an x/y pair in a given direction. Returns non-0 if edge reached.
  458. char move_dir(int&x,int&y,char dir) {
  459. enter_func("move_dir");
  460. switch(dir) {
  461. case 0:
  462. if(y==0) {
  463. exit_func();
  464. return 1;
  465. }
  466. y--;
  467. break;
  468. case 1:
  469. if(y==board_ysiz-1) {
  470. exit_func();
  471. return 1;
  472. }
  473. y++;
  474. break;
  475. case 2:
  476. if(x==board_xsiz-1) {
  477. exit_func();
  478. return 1;
  479. }
  480. x++;
  481. break;
  482. case 3:
  483. if(x==0) {
  484. exit_func();
  485. return 1;
  486. }
  487. x--;
  488. break;
  489. }
  490. exit_func();
  491. return 0;
  492. }
  493. //Returns the numeric value pointed to OR the numeric value represented
  494. //by the counter string pointed to. (the ptr is at the param within the
  495. //command)
  496. //NOTE- CLIPS COUNTER NAMES!
  497. int parse_param(unsigned char far *robot,int id) {
  498. enter_func("parse_param");
  499. if(robot[0]==0) {//Numeric
  500. #ifdef PROFILE
  501. int t1=(int)robot[1]+(int)(robot[2]<<8);
  502. exit_func();
  503. return t1;
  504. #else
  505. // Why Greg, why? - Exo
  506. // return (int)robot[1]+(int)(robot[2]<<8);
  507. return(*((int *)(robot + 1)));
  508. #endif
  509. }
  510. // Expression - Exo
  511. if(robot[1] == '(')
  512. //if((robot[1] == '(') && version_loaded >= 0x241)
  513. {
  514. char far *e_ptr = robot + 2;
  515. int error, val;
  516. val = parse_expression(&e_ptr, error, id);
  517. if(!error)
  518. {
  519. return(val);
  520. }
  521. }
  522. tr_msg(&robot[1],id,ibuff2);
  523. //String
  524. if(str_len(ibuff)>=COUNTER_NAME_SIZE)
  525. ibuff2[COUNTER_NAME_SIZE-1]=0;
  526. #ifdef PROFILE
  527. int t1=get_counter(ibuff2,id);
  528. exit_func();
  529. return t1;
  530. #else
  531. return get_counter(ibuff2,id);
  532. #endif
  533. }
  534. //Returns location of next parameter (pos is loc of current parameter)
  535. unsigned int next_param(unsigned char far *ptr,unsigned int pos) {
  536. return pos+(ptr[pos]?ptr[pos]:2)+1;
  537. }
  538. #define parsedir(a,b,c,d) parsedir(a,b,c,d,_bl[0],_bl[1],_bl[2],_bl[3])
  539. //Internal only. NOTE- IF WE EVER ALLOW ZAPPING OF LABELS NOT IN CURRENT
  540. //ROBOT, USE A COPY OF THE *LABEL BEFORE THE PREPARE_ROBOT_MEM!
  541. char restore_label(unsigned char far *robot,unsigned char far *label) {
  542. unsigned int t1=1,last=0;
  543. do {
  544. if(robot[t1+1]==108) {
  545. //Zapped Label- is it so?
  546. if(!str_cmp(&robot[t1+3],label))
  547. last=t1;
  548. }
  549. next_cmd:
  550. t1+=robot[t1]+2;
  551. } while(robot[t1]);
  552. if(!last) return 0;
  553. robot[last+1]=106;
  554. return 1;
  555. }
  556. char zap_label(unsigned char far *robot,unsigned char far *label) {
  557. unsigned int t1=1;
  558. do {
  559. if(robot[t1+1]==106) {
  560. //Zapped Label- is it so?
  561. if(!str_cmp(&robot[t1+3],label)) {
  562. robot[t1+1]=108;
  563. return 1;
  564. }
  565. }
  566. t1+=robot[t1]+2;
  567. } while(robot[t1]);
  568. return 0;
  569. }
  570. //Turns a color (including those w/??) to a real color (0-255)
  571. unsigned char fix_color(int color,unsigned char def) {
  572. if(color<256) return color;
  573. if(color<272) return (color&15)+(def&240);
  574. if(color<288) return ((color-272)<<4)+(def&15);
  575. return def;
  576. }
  577. void robot_box_display(unsigned char far *robot,int id,char far *label_storage) {
  578. //Important status vars (insert kept in intake.cpp)
  579. long pos=0,old_pos;//Where IN robot?
  580. int key;//Key
  581. int t1,t2;
  582. int old_keyb=curr_table;
  583. label_storage[0]=0;
  584. m_show();
  585. switch_keyb_table(1);
  586. //Draw screen
  587. save_screen(current_pg_seg);
  588. scroll_edging(4);
  589. //Write robot name
  590. if(!robots[id].robot_name[0]) write_string("Interaction",35,4,
  591. scroll_title_color,current_pg_seg);
  592. else write_string(robots[id].robot_name,40-str_len(robots[id].robot_name)/2,
  593. 4,scroll_title_color,current_pg_seg);
  594. //Scan section and mark all invalid counter-controlled options as codes
  595. //249.
  596. do {
  597. if(robot[pos+1]==249) robot[pos+1]=105;
  598. if(robot[pos+1]!=105) goto not_cco;
  599. t1=parse_param(&robot[pos+2],id);
  600. if(!t1) robot[pos+1]=249;
  601. not_cco:
  602. pos+=robot[pos]+2;
  603. } while(robot[pos]);
  604. pos=0;
  605. //Backwards
  606. do {
  607. if(robot[pos+1]==249) robot[pos+1]=105;
  608. if(robot[pos+1]!=105) goto not_cco2;
  609. t1=parse_param(&robot[pos+2],id);
  610. if(!t1) robot[pos+1]=249;
  611. not_cco2:
  612. if(robot[pos-1]==0xFF) break;
  613. pos-=robot[pos-1]+2;
  614. } while(1);
  615. pos=0;
  616. //Loop
  617. do {
  618. //Display scroll
  619. robot_frame(&robot[pos],id);
  620. key=getkey();
  621. old_pos=pos;
  622. switch(key) {
  623. case MOUSE_EVENT:
  624. //Move to line clicked on if mouse is in scroll, else exit
  625. if((mouse_event.cy>=6)&&(mouse_event.cy<=18)&&
  626. (mouse_event.cx>=8)&&(mouse_event.cx<=71)) {
  627. t2=mouse_event.cy-12;
  628. if(t2==0) goto select;
  629. //t2<0 = PGUP t2 lines
  630. //t2>0 = PGDN t2 lines
  631. if(t2<0) goto pgup;
  632. goto pgdn;
  633. }
  634. key=27;
  635. break;
  636. case -72://Up
  637. up_a_line:
  638. //Go back a line (if possible)
  639. if(robot[pos-1]==0xFF) break;//Can't.
  640. pos-=robot[pos-1]+2;
  641. t1=robot[pos+1];
  642. if((t1==106)||(t1==249)) goto up_a_line;
  643. if(((t1<103)&&(t1!=47))||((t1>106)&&(t1<116))||(t1>117)) pos=old_pos;
  644. //Done.
  645. break;
  646. case -80://Down
  647. down_a_line:
  648. //Go forward a line (if possible)
  649. pos+=robot[pos]+2;
  650. if(robot[pos]==0) pos=old_pos;
  651. else {
  652. t1=robot[pos+1];
  653. if((t1==106)||(t1==249)) goto down_a_line;
  654. if(((t1<103)&&(t1!=47))||((t1>106)&&(t1<116))||(t1>117)) pos=old_pos;
  655. }
  656. //Done.
  657. break;
  658. case 13://Enter
  659. select:
  660. if((robot[pos+1]!=104)&&(robot[pos+1]!=105)) {//No option
  661. key=27;
  662. break;
  663. }
  664. if(robot[pos+1]==105) t1=1+next_param(robot,pos+2);
  665. else t1=pos+3;
  666. //Goto option! Stores in label_storage
  667. str_cpy(label_storage,&robot[t1]);
  668. //Restore screen and exit
  669. restore_screen(current_pg_seg);
  670. switch_keyb_table(old_keyb);
  671. m_hide();
  672. return;
  673. case -81://Pagedown (by 6 lines)
  674. for(t2=6;t2>0;t2--) {
  675. pgdn:
  676. //Go forward a line (if possible)
  677. old_pos=pos;
  678. pgdn2:
  679. pos+=robot[pos]+2;
  680. if(robot[pos]==0) {
  681. pos=old_pos;
  682. break;
  683. }
  684. t1=robot[pos+1];
  685. if((t1==106)||(t1==249)) goto pgdn2;
  686. if(((t1<103)&&(t1!=47))||((t1>106)&&(t1<116))||(t1>117)) {
  687. pos=old_pos;
  688. break;
  689. }
  690. }
  691. break;
  692. case -73://Pageup (by 6 lines)
  693. for(t2=-6;t2<0;t2++) {
  694. pgup:
  695. //Go back a line (if possible)
  696. if(robot[pos-1]==0xFF) break;
  697. pos-=robot[pos-1]+2;
  698. t1=robot[pos+1];
  699. if((t1==106)||(t1==249)) goto pgup;
  700. if(((t1<103)&&(t1!=47))||((t1>106)&&(t1<116))||(t1>117)) {
  701. pos=old_pos;
  702. break;
  703. }
  704. }
  705. break;
  706. case -71://Home
  707. t2=-30000;
  708. goto pgup;
  709. case -79://End
  710. t2=30000;
  711. goto pgdn;
  712. default:
  713. beep();
  714. case 27:
  715. case 0:
  716. break;
  717. }
  718. //Continue?
  719. } while(key!=27);
  720. //Scan section and mark all invalid counter-controlled options as codes
  721. //105.
  722. pos=0;
  723. do {
  724. if(robot[pos+1]!=249) goto not_cco3;
  725. robot[pos+1]=105;
  726. not_cco3:
  727. pos+=robot[pos]+2;
  728. } while(robot[pos]);
  729. pos=0;
  730. //Backwards
  731. do {
  732. if(robot[pos+1]!=249) goto not_cco4;
  733. robot[pos+1]=105;
  734. not_cco4:
  735. if(robot[pos-1]==0xFF) break;
  736. pos-=robot[pos-1]+2;
  737. } while(1);
  738. //Restore screen and exit
  739. restore_screen(current_pg_seg);
  740. switch_keyb_table(old_keyb);
  741. m_hide();
  742. }
  743. void robot_frame(unsigned char far *robot,int id) {
  744. //Displays one frame of a robot. The scroll edging, arrows, and title
  745. //must already be shown. Simply prints each line. The pointer points
  746. //to the center line.
  747. int t1,t2,pos=0;
  748. int old_pos=pos;
  749. m_hide();
  750. //Display center line
  751. fill_line(64,8,12,32+(scroll_base_color<<8),current_pg_seg);
  752. display_robot_line(robot,12,id);
  753. //Display lines above center line
  754. for(t1=11;t1>=6;t1--) {
  755. fill_line(64,8,t1,32+(scroll_base_color<<8),current_pg_seg);
  756. //Go backward to previous line
  757. bk2:
  758. if(robot[pos-1]<0xFF) {
  759. pos-=robot[pos-1]+2;
  760. t2=robot[pos+1];
  761. if((t2==106)||(t2==249)) goto bk2;
  762. if(((t2<103)&&(t2!=47))||((t2>106)&&(t2<116))||(t2>117)) {
  763. pos+=robot[pos]+2;
  764. continue;
  765. }
  766. display_robot_line(&robot[pos],t1,id);
  767. }
  768. //Next line...
  769. }
  770. //Display lines below center line
  771. pos=old_pos;
  772. for(t1=13;t1<=18;t1++) {
  773. fill_line(64,8,t1,32+(scroll_base_color<<8),current_pg_seg);
  774. if(robot[pos]==0) continue;
  775. ps2:
  776. pos+=robot[pos]+2;
  777. t2=robot[pos+1];
  778. if((t2==106)||(t2==249)) goto ps2;
  779. if(((t2<103)&&(t2!=47))||((t2>106)&&(t2<116))||(t2>117)) {
  780. pos-=robot[pos-1]+2;
  781. continue;
  782. }
  783. if(robot[pos]) display_robot_line(&robot[pos],t1,id);
  784. //Next line...
  785. }
  786. m_show();
  787. }
  788. void display_robot_line(unsigned char far *robot,int y,int id) {
  789. int t1;
  790. switch(robot[1]) {
  791. case 103://Normal message
  792. tr_msg(&robot[3],id);
  793. ibuff[64]=0;//Clip
  794. write_string(ibuff,8,y,scroll_base_color,current_pg_seg);
  795. break;
  796. case 104://Option
  797. //Skip over label...
  798. t1=1+next_param(robot,2);//t1 is pos of string
  799. color_string(tr_msg(&robot[t1],id),10,y,scroll_base_color,current_pg_seg);
  800. draw_char('',scroll_arrow_color,8,y,current_pg_seg);
  801. break;
  802. case 105://Counter-based option
  803. //Check counter
  804. t1=parse_param(&robot[2],id);
  805. if(!t1) break;//Nothing
  806. //Skip over counter and label...
  807. t1=1+next_param(robot,next_param(robot,2));//t1 is pos of string
  808. color_string(tr_msg(&robot[t1],id),10,y,scroll_base_color,current_pg_seg);
  809. draw_char('',scroll_arrow_color,8,y,current_pg_seg);
  810. break;
  811. case 116://Colored message
  812. color_string(tr_msg(&robot[3],id),8,y,scroll_base_color,current_pg_seg);
  813. break;
  814. case 117://Centered message
  815. t1=str_len_color(tr_msg(&robot[3],id));
  816. t1=40-t1/2;
  817. color_string(ibuff,t1,y,scroll_base_color,current_pg_seg);
  818. break;
  819. }
  820. //Others, like 47 and 106, are blank lines
  821. }
  822. void push_sensor(int id) {
  823. send_robot(sensors[id].robot_to_mesg,"SENSORPUSHED");
  824. }
  825. void step_sensor(int id) {
  826. send_robot(sensors[id].robot_to_mesg,"SENSORON");
  827. }
  828. //Translates message at target to internal buffer, returning location
  829. //of this buffer. && becomes &, &INPUT& becomes the last input string,
  830. //and &COUNTER& becomes the value of COUNTER. The size of the string is
  831. //clipped to 80 chars.
  832. unsigned char ibuff[161];
  833. unsigned char ibuff2[161];//For another use of tr_msg (parse_param)
  834. unsigned char cnam[COUNTER_NAME_SIZE];
  835. unsigned char far *tr_msg(unsigned char far *orig_mesg,int id,
  836. unsigned char far *buffer) {
  837. int sp=0,dp=0,t1;
  838. enter_func("tr_msg");
  839. do {
  840. // Expression!
  841. if(orig_mesg[sp] == '(')
  842. //if((orig_mesg[sp] == '(') && (version_loaded >= 0x241))
  843. {
  844. char far *arg = orig_mesg + sp + 1;
  845. int error;
  846. int val = parse_expression(&arg, error, id);
  847. if(!error)
  848. {
  849. char temp[8];
  850. itoa(val, temp, 10);
  851. str_cpy(buffer + dp, temp);
  852. dp += str_len(temp);
  853. sp = arg - orig_mesg + 1;
  854. }
  855. }
  856. if(orig_mesg[sp]!='&') buffer[dp++]=orig_mesg[sp++];
  857. else {
  858. if(orig_mesg[++sp]=='&') {
  859. buffer[dp++]='&';
  860. sp++;
  861. }
  862. else {
  863. //Input or Counter?
  864. for(t1=0;t1<(COUNTER_NAME_SIZE-1);t1++) {
  865. cnam[t1]=orig_mesg[sp++];
  866. if(orig_mesg[sp]==0) break;
  867. if(orig_mesg[sp]=='&') {
  868. sp++;
  869. break;
  870. }
  871. }
  872. cnam[++t1]=0;
  873. if(!str_cmp(cnam,"INPUT")) {
  874. //Input
  875. str_cpy(&buffer[dp],input_string);
  876. dp+=str_len(input_string);
  877. }
  878. else {
  879. //Counter
  880. // Now could also be a string
  881. if(string_type(cnam) == 1)
  882. {
  883. // Write the value of the counter name
  884. char t_buf[64];
  885. get_string(cnam, t_buf);
  886. str_cpy(&buffer[dp], t_buf);
  887. dp+=str_len(t_buf);
  888. }
  889. else
  890. {
  891. // #(counter) is a hex representation.
  892. if(cnam[0] == '+')
  893. {
  894. sprintf(cnam, "%x", get_counter(cnam + 1, id));
  895. }
  896. else
  897. {
  898. if(cnam[0] == '#')
  899. {
  900. char temp[4];
  901. sprintf(temp, "%x", get_counter(cnam + 1, id));
  902. if(temp[1] == 0)
  903. {
  904. temp[2] = 0;
  905. temp[1] = temp[0];
  906. temp[0] = '0';
  907. }
  908. mem_cpy(cnam, temp, 4);
  909. }
  910. else
  911. {
  912. itoa(get_counter(cnam,id),cnam,10);
  913. }
  914. }
  915. str_cpy(&buffer[dp],cnam);
  916. dp+=str_len(cnam);
  917. }
  918. }
  919. }
  920. }
  921. if(dp>80) {
  922. dp=80;
  923. break;
  924. }
  925. } while(orig_mesg[sp]);
  926. buffer[dp]=0;
  927. exit_func();
  928. return buffer;
  929. }