Better project documentation.
[super-star-trek.git] / ai.c
1 #include "sst.h"\r
2 \r
3 static int tryexit(int lookx, int looky, int ienm, int loccom, int irun) {\r
4         int iqx, iqy, l;\r
5 \r
6         iqx = quadx+(lookx+9)/10 - 1;\r
7         iqy = quady+(looky+9)/10 - 1;\r
8         if (iqx < 1 || iqx > 8 || iqy < 1 || iqy > 8 ||\r
9                 game.state.galaxy[iqx][iqy] > 899)\r
10                 return 0; /* no can do -- neg energy, supernovae, or >8 Klingons */\r
11         if (ienm == IHR) return 0; /* Romulans cannot escape! */\r
12         if (irun == 0) {\r
13                 /* avoid intruding on another commander's territory */\r
14                 if (ienm == IHC) {\r
15                         for (l = 1; l <= game.state.remcom; l++)\r
16                                 if (game.state.cx[l]==iqx && game.state.cy[l]==iqy) return 0;\r
17                         /* refuse to leave if currently attacking starbase */\r
18                         if (batx==quadx && baty==quady) return 0;\r
19                 }\r
20                 /* don't leave if over 1000 units of energy */\r
21                 if (game.kpower[loccom] > 1000.) return 0;\r
22         }\r
23         /* print escape message and move out of quadrant.\r
24            We know this if either short or long range sensors are working */\r
25         if (game.damage[DSRSENS] == 0.0 || game.damage[DLRSENS] == 0.0 ||\r
26                 condit == IHDOCKED) {\r
27                 proutn("***");\r
28                 cramen(ienm);\r
29                 proutn(" escapes to %s (and regains strength).",\r
30                        cramlc(quadrant, iqx, iqy));\r
31         }\r
32         /* handle local matters related to escape */\r
33         game.kx[loccom] = game.kx[nenhere];\r
34         game.ky[loccom] = game.ky[nenhere];\r
35         game.kavgd[loccom] = game.kavgd[nenhere];\r
36         game.kpower[loccom] = game.kpower[nenhere];\r
37         game.kdist[loccom] = game.kdist[nenhere];\r
38         klhere--;\r
39         nenhere--;\r
40         if (condit != IHDOCKED) newcnd();\r
41         /* Handle global matters related to escape */\r
42         game.state.galaxy[quadx][quady] -= 100;\r
43         game.state.galaxy[iqx][iqy] += 100;\r
44         if (ienm==IHS) {\r
45                 ishere=0;\r
46                 iscate=0;\r
47                 ientesc=0;\r
48                 isatb=0;\r
49                 game.future[FSCMOVE]=0.2777+game.state.date;\r
50                 game.future[FSCDBAS]=1e30;\r
51                 game.state.isx=iqx;\r
52                 game.state.isy=iqy;\r
53         }\r
54         else {\r
55                 for (l=1; l<=game.state.remcom; l++) {\r
56                         if (game.state.cx[l]==quadx && game.state.cy[l]==quady) {\r
57                                 game.state.cx[l]=iqx;\r
58                                 game.state.cy[l]=iqy;\r
59                                 break;\r
60                         }\r
61                 }\r
62                 comhere = 0;\r
63         }\r
64         return 1; /* success */\r
65 }\r
66 \r
67 \r
68 static void movebaddy(int comx, int comy, int loccom, int ienm) {\r
69         int motion, mdist, nsteps, mx, my, nextx, nexty, lookx, looky, ll;\r
70         int irun = 0;\r
71         int krawlx, krawly;\r
72         int success;\r
73         int attempts;\r
74         /* This should probably be just comhere + ishere */\r
75         int nbaddys = skill > 3 ?\r
76                                   (int)((comhere*2 + ishere*2+klhere*1.23+irhere*1.5)/2.0):\r
77                                   (comhere + ishere);\r
78         double dist1, forces;\r
79 \r
80         dist1 = game.kdist[loccom];\r
81         mdist = dist1 + 0.5; /* Nearest integer distance */\r
82 \r
83         /* If SC, check with spy to see if should hi-tail it */\r
84         if (ienm==IHS &&\r
85                 (game.kpower[loccom] <= 500.0 || (condit==IHDOCKED && game.damage[DPHOTON]==0))) {\r
86                 irun = 1;\r
87                 motion = -10;\r
88         }\r
89         else {\r
90                 /* decide whether to advance, retreat, or hold position */\r
91 /* Algorithm:\r
92    * Enterprise has "force" based on condition of phaser and photon torpedoes.\r
93      If both are operating full strength, force is 1000. If both are damaged,\r
94          force is -1000. Having shields down subtracts an additional 1000.\r
95 \r
96    * Enemy has forces equal to the energy of the attacker plus\r
97      100*(K+R) + 500*(C+S) - 400 for novice through good levels OR\r
98          346*K + 400*R + 500*(C+S) - 400 for expert and emeritus.\r
99 \r
100          Attacker Initial energy levels (nominal):\r
101                   Klingon   Romulan   Commander   Super-Commander\r
102          Novice    400        700        1200        \r
103          Fair      425        750        1250\r
104          Good      450        800        1300        1750\r
105          Expert    475        850        1350        1875\r
106          Emeritus  500        900        1400        2000\r
107      VARIANCE   75        200         200         200\r
108 \r
109          Enemy vessels only move prior to their attack. In Novice - Good games\r
110          only commanders move. In Expert games, all enemy vessels move if there\r
111          is a commander present. In Emeritus games all enemy vessels move.\r
112 \r
113   *  If Enterprise is not docked, an agressive action is taken if enemy\r
114      forces are 1000 greater than Enterprise.\r
115 \r
116          Agressive action on average cuts the distance between the ship and\r
117          the enemy to 1/4 the original.\r
118 \r
119   *  At lower energy advantage, movement units are proportional to the\r
120      advantage with a 650 advantage being to hold ground, 800 to move forward\r
121          1, 950 for two, 150 for back 4, etc. Variance of 100.\r
122 \r
123          If docked, is reduced by roughly 1.75*skill, generally forcing a\r
124          retreat, especially at high skill levels.\r
125 \r
126   *  Motion is limited to skill level, except for SC hi-tailing it out.\r
127   */\r
128 \r
129                 forces = game.kpower[loccom]+100.0*nenhere+400*(nbaddys-1);\r
130                 if (shldup==0) forces += 1000; /* Good for enemy if shield is down! */\r
131                 if (game.damage[DPHASER] == 0.0 || game.damage[DPHOTON] == 0.0) {\r
132                         if (game.damage[DPHASER] != 0) /* phasers damaged */\r
133                                 forces += 300.0;\r
134                         else\r
135                                 forces -= 0.2*(energy - 2500.0);\r
136                         if (game.damage[DPHOTON] != 0) /* photon torpedoes damaged */\r
137                                 forces += 300.0;\r
138                         else\r
139                                 forces -= 50.0*torps;\r
140                 }\r
141                 else {\r
142                         /* phasers and photon tubes both out! */\r
143                         forces += 1000.0;\r
144                 }\r
145                 motion = 0;\r
146                 if (forces <= 1000.0 && condit != IHDOCKED) /* Typical situation */\r
147                         motion = ((forces+200.0*Rand())/150.0) - 5.0;\r
148                 else {\r
149                         if (forces > 1000.0) /* Very strong -- move in for kill */\r
150                                 motion = (1.0-square(Rand()))*dist1 + 1.0;\r
151                         if (condit==IHDOCKED) /* protected by base -- back off ! */\r
152                                 motion -= skill*(2.0-square(Rand()));\r
153                 }\r
154 #ifdef DEBUG\r
155                 if (idebug) {\r
156                         proutn("MOTION = %1.2f", motion);\r
157                         proutn("  FORCES = %1,2f", forces);\r
158                 }\r
159 #endif\r
160                 /* don't move if no motion */\r
161                 if (motion==0) return;\r
162                 /* Limit motion according to skill */\r
163                 if (abs(motion) > skill) motion = (motion < 0) ? -skill : skill;\r
164         }\r
165         /* calcuate preferred number of steps */\r
166         nsteps = motion < 0 ? -motion : motion;\r
167         if (motion > 0 && nsteps > mdist) nsteps = mdist; /* don't overshoot */\r
168         if (nsteps > 10) nsteps = 10; /* This shouldn't be necessary */\r
169         if (nsteps < 1) nsteps = 1; /* This shouldn't be necessary */\r
170 #ifdef DEBUG\r
171         if (idebug) {\r
172                 prout("NSTEPS = %d", nsteps);\r
173         }\r
174 #endif\r
175         /* Compute preferred values of delta X and Y */\r
176         mx = sectx - comx;\r
177         my = secty - comy;\r
178         if (2.0 * abs(mx) < abs(my)) mx = 0;\r
179         if (2.0 * abs(my) < abs(sectx-comx)) my = 0;\r
180         if (mx != 0) mx = mx*motion < 0 ? -1 : 1;\r
181         if (my != 0) my = my*motion < 0 ? -1 : 1;\r
182         nextx = comx;\r
183         nexty = comy;\r
184         game.quad[comx][comy] = IHDOT;\r
185         /* main move loop */\r
186         for (ll = 1; ll <= nsteps; ll++) {\r
187 #ifdef DEBUG\r
188                 if (idebug) {\r
189                         prout("%d", ll);\r
190                 }\r
191 #endif\r
192                 /* Check if preferred position available */\r
193                 lookx = nextx + mx;\r
194                 looky = nexty + my;\r
195                 krawlx = mx < 0 ? 1 : -1;\r
196                 krawly = my < 0 ? 1 : -1;\r
197                 success = 0;\r
198                 attempts = 0; /* Settle mysterious hang problem */\r
199                 while (attempts++ < 20 && !success) {\r
200                         if (lookx < 1 || lookx > 10) {\r
201                                 if (motion < 0 && tryexit(lookx, looky, ienm, loccom, irun))\r
202                                         return;\r
203                                 if (krawlx == mx || my == 0) break;\r
204                                 lookx = nextx + krawlx;\r
205                                 krawlx = -krawlx;\r
206                         }\r
207                         else if (looky < 1 || looky > 10) {\r
208                                 if (motion < 0 && tryexit(lookx, looky, ienm, loccom, irun))\r
209                                         return;\r
210                                 if (krawly == my || mx == 0) break;\r
211                                 looky = nexty + krawly;\r
212                                 krawly = -krawly;\r
213                         }\r
214                         else if (game.quad[lookx][looky] != IHDOT) {\r
215                                 /* See if we should ram ship */\r
216                                 if (game.quad[lookx][looky] == ship &&\r
217                                         (ienm == IHC || ienm == IHS)) {\r
218                                         ram(1, ienm, comx, comy);\r
219                                         return;\r
220                                 }\r
221                                 if (krawlx != mx && my != 0) {\r
222                                         lookx = nextx + krawlx;\r
223                                         krawlx = -krawlx;\r
224                                 }\r
225                                 else if (krawly != my && mx != 0) {\r
226                                         looky = nexty + krawly;\r
227                                         krawly = -krawly;\r
228                                 }\r
229                                 else break; /* we have failed */\r
230                         }\r
231                         else success = 1;\r
232                 }\r
233                 if (success) {\r
234                         nextx = lookx;\r
235                         nexty = looky;\r
236 #ifdef DEBUG\r
237                         if (idebug) {\r
238                                 prout(cramlc(neither, nextx, nexty));\r
239                         }\r
240 #endif\r
241                 }\r
242                 else break; /* done early */\r
243         }\r
244         /* Put commander in place within same quadrant */\r
245         game.quad[nextx][nexty] = ienm;\r
246         if (nextx != comx || nexty != comy) {\r
247                 /* it moved */\r
248                 game.kx[loccom] = nextx;\r
249                 game.ky[loccom] = nexty;\r
250                 game.kdist[loccom] = game.kavgd[loccom] =\r
251                                         sqrt(square(sectx-nextx)+square(secty-nexty));\r
252                 if (game.damage[DSRSENS] == 0 || condit == IHDOCKED) {\r
253                         proutn("***");\r
254                         cramen(ienm);\r
255                         if (game.kdist[loccom] < dist1) proutn(" advances to");\r
256                         else proutn(" retreats to ");\r
257                         prout(cramlc(sector, nextx, nexty));\r
258                 }\r
259         }\r
260 }\r
261 \r
262 void movcom(void) {\r
263         int ix, iy, i;\r
264 \r
265 #ifdef DEBUG\r
266         if (idebug) prout("MOVCOM");\r
267 #endif\r
268 \r
269         /* Figure out which Klingon is the commander (or Supercommander)\r
270            and do move */\r
271         if (comhere) for (i = 1; i <= nenhere; i++) {\r
272                 ix = game.kx[i];\r
273                 iy = game.ky[i];\r
274                 if (game.quad[ix][iy] == IHC) {\r
275                         movebaddy(ix, iy, i, IHC);\r
276                         break;\r
277                 }\r
278         }\r
279         if (ishere) for (i = 1; i <= nenhere; i++) {\r
280                 ix = game.kx[i];\r
281                 iy = game.ky[i];\r
282                 if (game.quad[ix][iy] == IHS) {\r
283                         movebaddy(ix, iy, i, IHS);\r
284                         break;\r
285                 }\r
286         }\r
287         /* if skill level is high, move other Klingons and Romulans too!\r
288            Move these last so they can base their actions on what the\r
289        commander(s) do. */\r
290         if (skill > 3) for (i = 1; i <= nenhere; i++) {\r
291                 ix = game.kx[i];\r
292                 iy = game.ky[i];\r
293                 if (game.quad[ix][iy] == IHK || game.quad[ix][iy] == IHR)\r
294                         movebaddy(ix, iy, i, game.quad[ix][iy]);\r
295         }\r
296 \r
297         sortkl();\r
298 }\r
299 \r
300 static int checkdest(int iqx, int iqy, int flag, int *ipage) {\r
301         int i, j;\r
302 \r
303         if ((iqx==quadx && iqy==quady) ||\r
304                 iqx < 1 || iqx > 8 || iqy < 1 || iqy > 8 ||\r
305                 game.state.galaxy[iqx][iqy] > 899) return 1;\r
306         if (flag) {\r
307                 /* Avoid quadrants with bases if we want to avoid Enterprise */\r
308                 for (i = 1; i <= game.state.rembase; i++)\r
309                         if (game.state.baseqx[i]==iqx && game.state.baseqy[i]==iqy) return 1;\r
310         }\r
311 \r
312         /* do the move */\r
313         game.state.galaxy[game.state.isx][game.state.isy] -= 100;\r
314         game.state.isx = iqx;\r
315         game.state.isy = iqy;\r
316         game.state.galaxy[game.state.isx][game.state.isy] += 100;\r
317         if (iscate) {\r
318                 /* SC has scooted, Remove him from current quadrant */\r
319                 iscate=0;\r
320                 isatb=0;\r
321                 ishere=0;\r
322                 ientesc=0;\r
323                 game.future[FSCDBAS]=1e30;\r
324                 for (i = 1; i <= nenhere; i++) \r
325                         if (game.quad[game.kx[i]][game.ky[i]] == IHS) break;\r
326                 game.quad[game.kx[i]][game.ky[i]] = IHDOT;\r
327                 game.kx[i] = game.kx[nenhere];\r
328                 game.ky[i] = game.ky[nenhere];\r
329                 game.kdist[i] = game.kdist[nenhere];\r
330                 game.kavgd[i] = game.kavgd[nenhere];\r
331                 game.kpower[i] = game.kpower[nenhere];\r
332                 klhere--;\r
333                 nenhere--;\r
334                 if (condit!=IHDOCKED) newcnd();\r
335                 sortkl();\r
336         }\r
337         /* check for a helpful planet */\r
338         for (i = 0; i < inplan; i++) {\r
339                 if (game.state.plnets[i].x==game.state.isx && game.state.plnets[i].y==game.state.isy &&\r
340                         game.state.plnets[i].crystals == 1) {\r
341                         /* destroy the planet */\r
342                         DESTROY(&game.state.plnets[i]);\r
343                         game.state.newstuf[game.state.isx][game.state.isy] -= 1;\r
344                         if (game.damage[DRADIO] == 0.0 || condit == IHDOCKED) {\r
345                                 if (*ipage==0) pause(1);\r
346                                 *ipage = 1;\r
347                                 prout("Lt. Uhura-  \"Captain, Starfleet Intelligence reports");\r
348                                 proutn("   a planet in ");\r
349                                 proutn(cramlc(quadrant, game.state.isx, game.state.isy));\r
350                                 prout(" has been destroyed");\r
351                                 prout("   by the Super-commander.\"");\r
352                         }\r
353                         break;\r
354                 }\r
355         }\r
356         return 0; /* looks good! */\r
357 }\r
358                         \r
359                 \r
360         \r
361 \r
362 \r
363 void scom(int *ipage) {\r
364         int i, i2, j, ideltax, ideltay, ibqx, ibqy, sx, sy, ifindit, iwhichb;\r
365         int iqx, iqy;\r
366         int basetbl[6];\r
367         double bdist[6];\r
368         int flag;\r
369 #ifdef DEBUG\r
370         if (idebug) prout("SCOM");\r
371 #endif\r
372 \r
373         /* Decide on being active or passive */\r
374         flag = ((game.state.killc+game.state.killk)/(game.state.date+0.01-indate) < 0.1*skill*(skill+1.0) ||\r
375                         (game.state.date-indate) < 3.0);\r
376         if (iscate==0 && flag) {\r
377                 /* compute move away from Enterprise */\r
378                 ideltax = game.state.isx-quadx;\r
379                 ideltay = game.state.isy-quady;\r
380                 if (sqrt(ideltax*(double)ideltax+ideltay*(double)ideltay) > 2.0) {\r
381                         /* circulate in space */\r
382                         ideltax = game.state.isy-quady;\r
383                         ideltay = quadx-game.state.isx;\r
384                 }\r
385         }\r
386         else {\r
387                 /* compute distances to starbases */\r
388                 if (game.state.rembase <= 0) {\r
389                         /* nothing left to do */\r
390                         game.future[FSCMOVE] = 1e30;\r
391                         return;\r
392                 }\r
393                 sx = game.state.isx;\r
394                 sy = game.state.isy;\r
395                 for (i = 1; i <= game.state.rembase; i++) {\r
396                         basetbl[i] = i;\r
397                         ibqx = game.state.baseqx[i];\r
398                         ibqy = game.state.baseqy[i];\r
399                         bdist[i] = sqrt(square(ibqx-sx) + square(ibqy-sy));\r
400                 }\r
401                 if (game.state.rembase > 1) {\r
402                         /* sort into nearest first order */\r
403                         int iswitch;\r
404                         do {\r
405                                 iswitch = 0;\r
406                                 for (i=1; i < game.state.rembase-1; i++) {\r
407                                         if (bdist[i] > bdist[i+1]) {\r
408                                                 int ti = basetbl[i];\r
409                                                 double t = bdist[i];\r
410                                                 bdist[i] = bdist[i+1];\r
411                                                 bdist[i+1] = t;\r
412                                                 basetbl[i] = basetbl[i+1];\r
413                                                 basetbl[i+1] =ti;\r
414                                                 iswitch = 1;\r
415                                         }\r
416                                 }\r
417                         } while (iswitch);\r
418                 }\r
419                 /* look for nearest base without a commander, no Enterprise, and\r
420                    without too many Klingons, and not already under attack. */\r
421                 ifindit = iwhichb = 0;\r
422 \r
423                 for (i2 = 1; i2 <= game.state.rembase; i2++) {\r
424                         i = basetbl[i2];        /* bug in original had it not finding nearest*/\r
425                         ibqx = game.state.baseqx[i];\r
426                         ibqy = game.state.baseqy[i];\r
427                         if ((ibqx == quadx && ibqy == quady) ||\r
428                                 (ibqx == batx && ibqy == baty) ||\r
429                                 game.state.galaxy[ibqx][ibqy] > 899) continue;\r
430                         /* if there is a commander, an no other base is appropriate,\r
431                            we will take the one with the commander */\r
432                         for (j = 1; j <= game.state.remcom; j++) {\r
433                                 if (ibqx==game.state.cx[j] && ibqy==game.state.cy[j] && ifindit!= 2) {\r
434                                                 ifindit = 2;\r
435                                                 iwhichb = i;\r
436                                                 break;\r
437                                 }\r
438                         }\r
439                         if (j > game.state.remcom) { /* no commander -- use this one */\r
440                                 ifindit = 1;\r
441                                 iwhichb = i;\r
442                                 break;\r
443                         }\r
444                 }\r
445                 if (ifindit==0) return; /* Nothing suitable -- wait until next time*/\r
446                 ibqx = game.state.baseqx[iwhichb];\r
447                 ibqy = game.state.baseqy[iwhichb];\r
448                 /* decide how to move toward base */\r
449                 ideltax = ibqx - game.state.isx;\r
450                 ideltay = ibqy - game.state.isy;\r
451         }\r
452         /* Maximum movement is 1 quadrant in either or both axis */\r
453         if (ideltax > 1) ideltax = 1;\r
454         if (ideltax < -1) ideltax = -1;\r
455         if (ideltay > 1) ideltay = 1;\r
456         if (ideltay < -1) ideltay = -1;\r
457 \r
458         /* try moving in both x and y directions */\r
459         iqx = game.state.isx + ideltax;\r
460         iqy = game.state.isy + ideltax;\r
461         if (checkdest(iqx, iqy, flag, ipage)) {\r
462                 /* failed -- try some other maneuvers */\r
463                 if (ideltax==0 || ideltay==0) {\r
464                         /* attempt angle move */\r
465                         if (ideltax != 0) {\r
466                                 iqy = game.state.isy + 1;\r
467                                 if (checkdest(iqx, iqy, flag, ipage)) {\r
468                                         iqy = game.state.isy - 1;\r
469                                         checkdest(iqx, iqy, flag, ipage);\r
470                                 }\r
471                         }\r
472                         else {\r
473                                 iqx = game.state.isx + 1;\r
474                                 if (checkdest(iqx, iqy, flag, ipage)) {\r
475                                         iqx = game.state.isx - 1;\r
476                                         checkdest(iqx, iqy, flag, ipage);\r
477                                 }\r
478                         }\r
479                 }\r
480                 else {\r
481                         /* try moving just in x or y */\r
482                         iqy = game.state.isy;\r
483                         if (checkdest(iqx, iqy, flag, ipage)) {\r
484                                 iqy = game.state.isy + ideltay;\r
485                                 iqx = game.state.isx;\r
486                                 checkdest(iqx, iqy, flag, ipage);\r
487                         }\r
488                 }\r
489         }\r
490         /* check for a base */\r
491         if (game.state.rembase == 0) {\r
492                 game.future[FSCMOVE] = 1e30;\r
493         }\r
494         else for (i=1; i<=game.state.rembase; i++) {\r
495                 ibqx = game.state.baseqx[i];\r
496                 ibqy = game.state.baseqy[i];\r
497                 if (ibqx==game.state.isx && ibqy == game.state.isy && game.state.isx != batx && game.state.isy != baty) {\r
498                         /* attack the base */\r
499                         if (flag) return; /* no, don't attack base! */\r
500                         iseenit = 0;\r
501                         isatb=1;\r
502                         game.future[FSCDBAS] = game.state.date + 1.0 +2.0*Rand();\r
503                         if (batx != 0) game.future[FSCDBAS] += game.future[FCDBAS]-game.state.date;\r
504                         if (game.damage[DRADIO] > 0 && condit != IHDOCKED)\r
505                                 return; /* no warning */\r
506                         iseenit = 1;\r
507                         if (*ipage == 0)  pause(1);\r
508                         *ipage=1;\r
509                         proutn("Lt. Uhura-  \"Captain, the starbase in ");\r
510                         proutn(cramlc(quadrant, game.state.isx, game.state.isy));\r
511                         skip(1);\r
512                         prout("   reports that it is under attack from the Klingon Super-commander.");\r
513                         proutn("   It can survive until stardate %d.\"",\r
514                                (int)game.future[FSCDBAS]);\r
515                         if (resting==0) return;\r
516                         prout("Mr. Spock-  \"Captain, shall we cancel the rest period?\"");\r
517                         if (ja()==0) return;\r
518                         resting = 0;\r
519                         Time = 0.0; /* actually finished */\r
520                         return;\r
521                 }\r
522         }\r
523         /* Check for intelligence report */\r
524         if (\r
525 #ifdef DEBUG\r
526                 idebug==0 &&\r
527 #endif\r
528                 (Rand() > 0.2 ||\r
529                  (game.damage[DRADIO] > 0.0 && condit != IHDOCKED) ||\r
530                  game.starch[game.state.isx][game.state.isy] > 0))\r
531                 return;\r
532         if (*ipage==0) pause(1);\r
533         *ipage = 1;\r
534         prout("Lt. Uhura-  \"Captain, Starfleet Intelligence reports");\r
535         proutn("   the Super-commander is in ");\r
536         proutn(cramlc(quadrant, game.state.isx, game.state. isy));\r
537         prout(".\"");\r
538         return;\r
539 }\r
540 \r
541 void movetho(void) {\r
542         int idx, idy, im, i, dum, my;\r
543         /* Move the Tholian */\r
544         if (ithere==0 || justin == 1) return;\r
545 \r
546         if (ithx == 1 && ithy == 1) {\r
547                 idx = 1; idy = 10;\r
548         }\r
549         else if (ithx == 1 && ithy == 10) {\r
550                 idx = 10; idy = 10;\r
551         }\r
552         else if (ithx == 10 && ithy == 10) {\r
553                 idx = 10; idy = 1;\r
554         }\r
555         else if (ithx == 10 && ithy == 1) {\r
556                 idx = 1; idy = 1;\r
557         }\r
558         else {\r
559                 /* something is wrong! */\r
560                 ithere = 0;\r
561                 return;\r
562         }\r
563 \r
564         /* Do nothing if we are blocked */\r
565         if (game.quad[idx][idy]!= IHDOT && game.quad[idx][idy]!= IHWEB) return;\r
566         game.quad[ithx][ithy] = IHWEB;\r
567 \r
568         if (ithx != idx) {\r
569                 /* move in x axis */\r
570                 im = fabs((double)idx - ithx)/((double)idx - ithx);\r
571                 while (ithx != idx) {\r
572                         ithx += im;\r
573                         if (game.quad[ithx][ithy]==IHDOT) game.quad[ithx][ithy] = IHWEB;\r
574                 }\r
575         }\r
576         else if (ithy != idy) {\r
577                 /* move in y axis */\r
578                 im = fabs((double)idy - ithy)/((double)idy - ithy);\r
579                 while (ithy != idy) {\r
580                         ithy += im;\r
581                         if (game.quad[ithx][ithy]==IHDOT) game.quad[ithx][ithy] = IHWEB;\r
582                 }\r
583         }\r
584         game.quad[ithx][ithy] = IHT;\r
585 \r
586         /* check to see if all holes plugged */\r
587         for (i = 1; i < 11; i++) {\r
588                 if (game.quad[1][i]!=IHWEB && game.quad[1][i]!=IHT) return;\r
589                 if (game.quad[10][i]!=IHWEB && game.quad[10][i]!=IHT) return;\r
590                 if (game.quad[i][1]!=IHWEB && game.quad[i][1]!=IHT) return;\r
591                 if (game.quad[i][10]!=IHWEB && game.quad[i][10]!=IHT) return;\r
592         }\r
593         /* All plugged up -- Tholian splits */\r
594         game.quad[ithx][ithy]=IHWEB;\r
595         dropin(IHBLANK, &dum, &my);\r
596         crmena(1,IHT, 2, ithx, ithy);\r
597         prout(" completes web.");\r
598         ithere = ithx = ithy = 0;\r
599         return;\r
600 }\r