2
|
1 /*
|
|
2 * interface.c
|
|
3 */
|
|
4
|
|
5 #include <stdio.h>
|
|
6 #include <stdlib.h>
|
|
7 #include <string.h>
|
|
8 #include <signal.h>
|
|
9 #include <termios.h>
|
|
10 #include <sys/ioctl.h>
|
|
11 #include <time.h>
|
|
12 #include <struct.h>
|
|
13 #include <curses.h>
|
|
14 #include "common.h"
|
|
15 #include "db.h"
|
|
16 #include "interface.h"
|
|
17 #include "intfdesc.h"
|
|
18 #include "file.h"
|
|
19 #include "data.h"
|
|
20
|
|
21
|
|
22 static char *shrt_royal_names[] = {
|
|
23 "",
|
|
24 "Wes",
|
|
25 "Cen",
|
|
26 "Pra",
|
|
27 "Emp"
|
|
28 };
|
|
29
|
|
30 static char *royal_names[] = {
|
|
31 "none",
|
|
32 "Wesley",
|
|
33 "Centurion",
|
|
34 "Praetor",
|
|
35 "Emperor"
|
|
36 };
|
|
37
|
|
38 static char *shrt_rank_names[] = {
|
|
39 "Recr", "Spec", "Cadt", "Mids", "EnJr", "Ensi", "LtJr",
|
|
40 "Lieu", "LtCm", "Cmdr", "HiCm", "Capt", "FlCp", "Comd",
|
|
41 "Adml", "RAdm", "Moff", "GrMo"
|
|
42 };
|
|
43
|
|
44 static char *rank_names[] = {
|
|
45 "Recruit", "Specialist", "Cadet", "Midshipman",
|
|
46 "Ensn. Jr.", "Ensign", "Lt. Jnr. Gr.", "Lieutenant",
|
|
47 "Lt. Cmdr.", "Commander", "High Cmdr.", "Captain",
|
|
48 "Fleet Capt.", "Commodore", "Admiral", "Rear Adml.",
|
|
49 "Moff", "Grand Moff"
|
|
50 };
|
|
51
|
|
52 void getTTYinfo()
|
|
53 {
|
|
54 struct winsize ws;
|
|
55 char *name, bp[1024], area[1024], *ap = area;
|
|
56
|
|
57 #ifdef SYSV
|
|
58 signal(SIGWINCH, getTTYinfo);
|
|
59 #endif
|
|
60
|
|
61 /* determine # of lines */
|
|
62 ioctl(0, TIOCGWINSZ, &ws);
|
|
63 numLines = ws.ws_row;
|
|
64
|
|
65 /* find terminal sequence to clear the screen */
|
|
66 if(name = getenv("TERM"))
|
|
67 if(tgetent(bp, name) > 0)
|
|
68 clrStr = tgetstr("cl", &ap);
|
|
69 }
|
|
70
|
|
71 void cls()
|
|
72 {
|
|
73 printf("%s", clrStr); fflush(stdout);
|
|
74 }
|
|
75
|
|
76 void Interface()
|
|
77 {
|
|
78 struct plnode *p, *pn;
|
|
79 int lines, top, i, num;
|
|
80 char buf[18], *c;
|
|
81
|
|
82 top = 0;
|
|
83 for(;;) {
|
|
84 lines = numLines - 4;
|
|
85 if(lines < 5) err_fatal("not enough tty lines!");
|
|
86
|
|
87 cls();
|
|
88 printf("\
|
|
89 C # Rnk Ryl Name C # Rnk Ryl Name\n");
|
|
90 printf("\
|
|
91 - --- ---- ---- ----------------- - --- ---- ---- -----------------\n");
|
|
92
|
|
93 for(i = 0; i < lines; i++) {
|
|
94 if(top + i > numDBentries - 1) {
|
|
95 printf("\n");
|
|
96 continue;
|
|
97 }
|
|
98 p = GetNode(top + i);
|
|
99 if(!p) {
|
|
100 printf("\n");
|
|
101 continue;
|
|
102 }
|
|
103 strncpy(buf, p->player.name, 16);
|
|
104 strcat(buf, "_");
|
|
105 printf(" %c%4d %-4s %-4s %-17.17s ",
|
|
106 p->status ? '*':' ', top + i,
|
|
107 shrt_rank_names[p->player.stats.st_rank],
|
|
108 shrt_royal_names[p->player.stats.st_royal],
|
|
109 Strip(buf));
|
|
110
|
|
111 if(top + i + lines > numDBentries - 1) {
|
|
112 printf("\n");
|
|
113 continue;
|
|
114 }
|
|
115 p = GetNode(top + i + lines);
|
|
116 if(!p) {
|
|
117 printf("\n");
|
|
118 continue;
|
|
119 }
|
|
120 strncpy(buf, p->player.name, 16);
|
|
121 strcat(buf, "_");
|
|
122 printf(" %c%4d %-4s %-4s %s\n",
|
|
123 p->status ? '*':' ', top + i + lines,
|
|
124 shrt_rank_names[p->player.stats.st_rank],
|
|
125 shrt_royal_names[p->player.stats.st_royal],
|
|
126 Strip(buf));
|
|
127 }
|
|
128 printf("\nIndex: Command (? for help) -->"); fflush(stdout);
|
|
129 if(fgets(buf, 18, stdin) == NULL)
|
|
130 continue;
|
|
131
|
|
132 switch(buf[0]) {
|
|
133 case '\n':
|
|
134 case 'n':
|
|
135 top += (lines * 2);
|
|
136 if(top >= numDBentries)
|
|
137 top = 0;
|
|
138 break;
|
|
139 case 'p':
|
|
140 if(!top) {
|
|
141 if(numDBentries - 2 * lines > 0)
|
|
142 top = numDBentries - 2 * lines;
|
|
143 else
|
|
144 top = 0;
|
|
145 } else {
|
|
146 top -= (lines * 2);
|
|
147 if(top < 0) top = 0;
|
|
148 }
|
|
149 break;
|
|
150 case 'Q':
|
|
151 GoAway(CheckChanged());
|
|
152 break;
|
|
153 case 's':
|
|
154 DoSave(1);
|
|
155 break;
|
|
156 case 'e':
|
|
157 printf("Enter player name to edit -->");
|
|
158 fflush(stdout);
|
|
159 if(fgets(buf, 18, stdin) == NULL)
|
|
160 break;
|
|
161 if(c = strrchr(buf, '\n'))
|
|
162 *c = (char)0;
|
|
163 num = GetByName(buf);
|
|
164 if(num < 0) {
|
|
165 Report("Couldn't find any players by that name.");
|
|
166 break;
|
|
167 }
|
|
168 Edit(num);
|
|
169 break;
|
|
170 case '?':
|
|
171 Report("\n\
|
|
172 [num] : Edit player [num]\n\
|
|
173 e : Edit player (by name)\n\
|
|
174 n : Next page\n\
|
|
175 [ret] : Next page\n\
|
|
176 p : Previous page\n\
|
|
177 s : Save to file\n\
|
|
178 Q : Quit pped\n");
|
|
179 break;
|
|
180 default:
|
|
181 i = sscanf(buf, "%d", &num);
|
|
182 if(!i || (num < 0) || (num >= numDBentries))
|
|
183 break;
|
|
184 Edit(num);
|
|
185 }
|
|
186 }
|
|
187 }
|
|
188
|
|
189 void Edit(int pnum)
|
|
190 {
|
|
191 struct plnode *p, player;
|
|
192 char buf[18], txt[80];
|
|
193 int i, num, lines, top;
|
|
194
|
|
195 p = GetNode(pnum);
|
|
196 if(!p) return;
|
|
197 player = *p;
|
|
198 player.status = 0;
|
|
199
|
|
200 top = 0;
|
|
201
|
|
202 for(;;) {
|
|
203 lines = numLines - 2;
|
|
204 cls();
|
|
205 Display(&player, top, top+lines);
|
|
206
|
|
207 printf("\nEdit: Command (? for help) -->"); fflush(stdout);
|
|
208 if(fgets(buf, 18, stdin) == NULL)
|
|
209 continue;
|
|
210
|
|
211 switch(buf[0]) {
|
|
212 case '?': /* help */
|
|
213 Report("\n\
|
|
214 n : Next page\n\
|
|
215 p : Previous page\n\
|
|
216 [num] : Change value [num]\n\
|
|
217 s : Save and return to index\n\
|
|
218 w : Save\n\
|
|
219 [ret] : Return to index, don't save\n\
|
|
220 x : Same as [ret]\n\
|
|
221 D : Delete this entry and return to index\n\
|
|
222 r : Revert (undo changes since last save)\n\
|
|
223 Q : Quit pped\n");
|
|
224 break;
|
|
225
|
|
226 case 'n': /* page forward */
|
|
227 top += lines;
|
|
228 if(top > NUMDESC + 1) top = 0;
|
|
229 continue;
|
|
230
|
|
231 case 'p': /* page backward */
|
|
232 top -= lines;
|
|
233 if(top < 0) top = 0;
|
|
234 continue;
|
|
235
|
|
236 case 'D': /* delete (and exit) */
|
|
237 sprintf(txt, "delete entry for player %s", p->player.name);
|
|
238 if(Verify(txt)) {
|
|
239 DeleteNode(pnum);
|
|
240 Report("Player deleted.");
|
|
241 return;
|
|
242 } else {
|
|
243 Report("Canceled.");
|
|
244 }
|
|
245 break;
|
|
246
|
|
247 case 'Q': /* quit */
|
|
248 GoAway(player.status || CheckChanged());
|
|
249 break;
|
|
250
|
|
251 case 's': /* save and exit */
|
|
252 if(player.status) {
|
|
253 *p = player;
|
|
254 player.status = 0;
|
|
255 Report("Player saved.");
|
|
256 }
|
|
257 return;
|
|
258 break;
|
|
259
|
|
260 case 'w': /* save */
|
|
261 if(player.status) {
|
|
262 *p = player;
|
|
263 player.status = 0;
|
|
264 Report("Player saved.");
|
|
265 } else {
|
|
266 Report("No changes to save.");
|
|
267 }
|
|
268 break;
|
|
269
|
|
270 case 'r': /* revert */
|
|
271 if(player.status) {
|
|
272 sprintf(txt, "undo changes for player %s?", p->player.name);
|
|
273 if(Verify(txt)) {
|
|
274 player = *p;
|
|
275 player.status = 0;
|
|
276 Report("Changes discarded.");
|
|
277 } else {
|
|
278 Report("Canceled.");
|
|
279 }
|
|
280 } else {
|
|
281 Report("No changes to undo.");
|
|
282 }
|
|
283 break;
|
|
284
|
|
285 case 0x1B: /* (escape) exit, no changes */
|
|
286 case '\n':
|
|
287 case 'x':
|
|
288 if(player.status)
|
|
289 if(!Verify("exit? There are unsaved changes."))
|
|
290 break;
|
|
291 return;
|
|
292
|
|
293 default:
|
|
294 i = sscanf(buf, "%d", &num);
|
|
295 if(!i || (num < 0) || (num >= NUMDESC))
|
|
296 break;
|
|
297 Change(num, &player);
|
|
298 }
|
|
299 }
|
|
300 }
|
|
301
|
|
302 int Verify(char *str)
|
|
303 {
|
|
304 char buffer[18];
|
|
305
|
|
306 for(;;) {
|
|
307 printf("Verify %s (y/n) -->", str); fflush(stdout);
|
|
308 if(fgets(buffer, 18, stdin) == NULL)
|
|
309 continue;
|
|
310 switch(buffer[0]) {
|
|
311 case 'Y':
|
|
312 case 'y':
|
|
313 return 1;
|
|
314 case 'N':
|
|
315 case 'n':
|
|
316 return 0;
|
|
317 }
|
|
318 }
|
|
319 }
|
|
320
|
|
321 void Report(char *str)
|
|
322 {
|
|
323 char buffer[18];
|
|
324
|
|
325 printf("%s\n", str);
|
|
326 printf("Press return to continue -->"); fflush(stdout);
|
|
327
|
|
328 fgets(buffer, 18, stdin);
|
|
329 }
|
|
330
|
|
331 void Change(int num, struct plnode *p)
|
|
332 {
|
|
333 struct inter_desc *it;
|
|
334 void *ptr;
|
|
335 char str16[16], *c;
|
|
336 char buffer[80];
|
|
337 int intnum, i, col;
|
|
338 float floatnum;
|
|
339
|
|
340 if(num < 0 || num >= NUMDESC) return;
|
|
341 it = &idesc_tab[num];
|
|
342
|
|
343 ptr = (void *)((int)(&p->player) + it->offset);
|
|
344
|
|
345 switch(it->type) {
|
|
346 case DT_CHAR16:
|
|
347 printf("Current value for %s: \"%s\"\n", it->name, (char *)ptr);
|
|
348 printf("Enter new value -->"); fflush(stdout);
|
|
349 str16[0] = 0;
|
|
350 fgets(str16, 16, stdin);
|
|
351 if(c = strrchr(str16, '\n'))
|
|
352 *c = (char)0;
|
|
353
|
|
354 sprintf(buffer, "\"%s\" as new value for %s.", str16, it->name);
|
|
355 if(Verify(buffer)) {
|
|
356 if(strncmp((char *)ptr, str16, 16)) {
|
|
357 strncpy((char *)ptr, str16, 16);
|
|
358 p->status = 1; /* something changed */
|
|
359 }
|
|
360 }
|
|
361 break;
|
|
362
|
|
363 case DT_INT:
|
|
364 case DT_TICKS:
|
|
365 printf("Current value for %s: %d\n", it->name, *((int *)ptr));
|
|
366 printf("Enter new value -->"); fflush(stdout);
|
|
367 fgets(buffer, 30, stdin);
|
|
368 intnum = atoi(buffer);
|
|
369 sprintf(buffer, "%d as new value for %s.", intnum, it->name);
|
|
370 if(Verify(buffer)) {
|
|
371 if(intnum != *((int *)ptr)) {
|
|
372 *((int *)ptr) = intnum;
|
|
373 p->status = 1;
|
|
374 }
|
|
375 }
|
|
376 break;
|
|
377
|
|
378 case DT_FLOAT:
|
|
379 printf("Current value for %s: %f\n", it->name, *((float *)ptr));
|
|
380 printf("Enter new value -->"); fflush(stdout);
|
|
381 fgets(buffer, 30, stdin);
|
|
382 floatnum = (float)atof(buffer);
|
|
383 sprintf(buffer, "%f as new value for %s.", floatnum, it->name);
|
|
384 if(Verify(buffer)) {
|
|
385 if(floatnum != *((float *)ptr)) {
|
|
386 *((float *)ptr) = floatnum;
|
|
387 p->status = 1;
|
|
388 }
|
|
389 }
|
|
390 break;
|
|
391
|
|
392 case DT_RANK:
|
|
393 for(i = 0, col = 0; i < NUMRANKS; i++) {
|
|
394 printf(" %2d: %-7s ", i, shrt_rank_names[i]);
|
|
395 if(++col == 4) {
|
|
396 printf("\n");
|
|
397 col = 0;
|
|
398 }
|
|
399 }
|
|
400 printf("\nCurrent value for %s: %d (%s)\n", it->name,
|
|
401 *((int *)ptr), rank_names[*((int *)ptr)]);
|
|
402 printf("Enter new value -->"); fflush(stdout);
|
|
403 fgets(buffer, 30, stdin);
|
|
404 intnum = atoi(buffer);
|
|
405 sprintf(buffer, "%d (%s) as new value for %s.", intnum,
|
|
406 rank_names[intnum], it->name);
|
|
407 if(Verify(buffer)) {
|
|
408 if(intnum != *((int *)ptr)) {
|
|
409 *((int *)ptr) = intnum;
|
|
410 p->status = 1;
|
|
411 }
|
|
412 }
|
|
413 break;
|
|
414
|
|
415 case DT_ROYAL:
|
|
416 for(i = 0; i < NUMROYALRANKS; i++)
|
|
417 printf(" %2d: %s\n", i, royal_names[i]);
|
|
418
|
|
419 printf("Current value for %s: %d (%s)\n", it->name,
|
|
420 *((int *)ptr), royal_names[*((int *)ptr)]);
|
|
421 printf("Enter new value -->"); fflush(stdout);
|
|
422 fgets(buffer, 30, stdin);
|
|
423 intnum = atoi(buffer);
|
|
424 sprintf(buffer, "%d (%s) as new value for %s.", intnum,
|
|
425 royal_names[intnum], it->name);
|
|
426 if(Verify(buffer)) {
|
|
427 if(intnum != *((int *)ptr)) {
|
|
428 *((int *)ptr) = intnum;
|
|
429 p->status = 1;
|
|
430 }
|
|
431 }
|
|
432 break;
|
|
433 default:
|
|
434 Report("Error in case statement in Change()");
|
|
435 break;
|
|
436 }
|
|
437 }
|
|
438
|
|
439 void Display(struct plnode *n, int from, int to)
|
|
440 {
|
|
441 int i, hour, dt = 0;
|
|
442 char c;
|
|
443 void *ptr;
|
|
444 struct inter_desc *it;
|
|
445 struct tm *stm;
|
|
446 time_t tt;
|
|
447
|
|
448 if(to > NUMDESC) {
|
|
449 to = NUMDESC;
|
|
450 dt = 1;
|
|
451 }
|
|
452
|
|
453 for(i = from; i < to; i++) {
|
|
454 it = &idesc_tab[i];
|
|
455 ptr = (void *)((int)(&n->player) + it->offset);
|
|
456
|
|
457 switch(it->type) {
|
|
458 case DT_CHAR16:
|
|
459 printf(" (%2d) %16s : \"%s\"\n", i, it->name, (char *)ptr);
|
|
460 break;
|
|
461 case DT_INT:
|
|
462 printf(" (%2d) %16s : %d\n", i, it->name, *((int *)ptr));
|
|
463 break;
|
|
464 case DT_FLOAT:
|
|
465 printf(" (%2d) %16s : %.2f\n", i, it->name, *((float *)ptr));
|
|
466 break;
|
|
467 case DT_TICKS:
|
|
468 printf(" (%2d) %16s : %d (%.2f hours)\n",
|
|
469 i, it->name, *((int *)ptr), (*((int *)ptr))/36000.0);
|
|
470 break;
|
|
471 case DT_RANK:
|
|
472 printf(" (%2d) %16s : %d (%s)\n", i, it->name, *((int *)ptr),
|
|
473 rank_names[*((int *)ptr)]);
|
|
474 break;
|
|
475 case DT_ROYAL:
|
|
476 printf(" (%2d) %16s : %d (%s)\n", i, it->name, *((int *)ptr),
|
|
477 royal_names[*((int *)ptr)]);
|
|
478 break;
|
|
479 default:
|
|
480 printf("Yikes! Unknown it->type in Display()\n");
|
|
481 break;
|
|
482 }
|
|
483 }
|
|
484 if(dt) {
|
|
485 tt = n->player.stats.st_lastlogin;
|
|
486 stm = localtime(&tt);
|
|
487 hour = stm->tm_hour;
|
|
488 c = 'A';
|
|
489 if(!hour) {
|
|
490 hour = 12;
|
|
491 } else if(hour > 12) {
|
|
492 hour -= 12;
|
|
493 c = 'P';
|
|
494 }
|
|
495 printf(" Last login: %2d:%02d %cM %02d/%02d/%d\n",
|
|
496 hour, stm->tm_min, c, stm->tm_mon+1, stm->tm_mday, stm->tm_year);
|
|
497 }
|
|
498 }
|
|
499
|
|
500 int CheckChanged()
|
|
501 {
|
|
502 struct plnode *p;
|
|
503
|
|
504 if(dbDirty) return(1);
|
|
505
|
|
506 p = firstEnt;
|
|
507 while(p) {
|
|
508 if(p->status) return(1);
|
|
509 p = p->next;
|
|
510 }
|
|
511 return(0);
|
|
512 }
|
|
513
|
|
514 void ClearChanged()
|
|
515 {
|
|
516 struct plnode *p;
|
|
517
|
|
518 dbDirty = 0;
|
|
519
|
|
520 p = firstEnt;
|
|
521 while(p) {
|
|
522 p->status = 0;
|
|
523 p = p->next;
|
|
524 }
|
|
525 }
|
|
526
|
|
527 /* Strip: convert non-printable control chars to ^L notation */
|
|
528 char *Strip(char *str)
|
|
529 {
|
|
530 static char buff[36], *o;
|
|
531
|
|
532 o = buff;
|
|
533 while(*str) {
|
|
534 *str &= 0x7f;
|
|
535 if((int)*str < (int)' ') {
|
|
536 *o++ = '^';
|
|
537 *o++ = *str + (char)64;
|
|
538 } else if ((int)*str == 127) {
|
|
539 *o++ = '^';
|
|
540 *o++ = '?';
|
|
541 } else {
|
|
542 *o++ = *str;
|
|
543 }
|
|
544 str++;
|
|
545 }
|
|
546 *o = 0;
|
|
547 return(buff);
|
|
548 }
|
|
549
|