1 /* NetHack 3.6	winstr.c	$NHDT-Date: 1432512795 2015/05/25 00:13:15 $  $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */
2 /* Copyright (c) Gregg Wonderly, Naperville, Illinois,  1991,1992,1993. */
3 /* NetHack may be freely redistributed.  See license for details. */
4 
5 #ifndef CROSS_TO_AMIGA
6 #include "NH:sys/amiga/windefs.h"
7 #include "NH:sys/amiga/winext.h"
8 #include "NH:sys/amiga/winproto.h"
9 #else
10 #include "windefs.h"
11 #include "winext.h"
12 #include "winproto.h"
13 #endif
14 /* Put a string into the indicated window using the indicated attribute */
15 
16 void
amii_putstr(window,attr,str)17 amii_putstr(window, attr, str)
18 winid window;
19 int attr;
20 const char *str;
21 {
22     int fudge;
23     int len;
24     struct Window *w;
25     register struct amii_WinDesc *cw;
26     char *ob;
27     int i, j, n0, bottom, totalvis, wheight;
28     static int wrapping = 0;
29 
30     /* Always try to avoid a panic when there is no window */
31     if (window == WIN_ERR) {
32         window = WIN_BASE;
33         if (window == WIN_ERR)
34             window = WIN_BASE = amii_create_nhwindow(NHW_BASE);
35     }
36 
37     if (window == WIN_ERR || (cw = amii_wins[window]) == NULL) {
38         iflags.window_inited = 0;
39         panic(winpanicstr, window, "putstr");
40     }
41 
42     w = cw->win;
43 
44     if (!str)
45         return;
46     amiIDisplay->lastwin = window; /* do we care??? */
47 
48     /* NHW_MENU windows are not opened immediately, so check if we
49      * have the window pointer yet
50      */
51 
52     if (w) {
53         /* Set the drawing mode and pen colors */
54         SetDrMd(w->RPort, JAM2);
55         amii_sethipens(w, cw->type, attr);
56     } else if (cw->type != NHW_MENU && cw->type != NHW_TEXT) {
57         panic("NULL window pointer in putstr 2: %d", window);
58     }
59 
60     /* Okay now do the work for each type */
61 
62     switch (cw->type) {
63     case NHW_MESSAGE:
64         if (WINVERS_AMIV)
65             fudge = 2;
66         else {
67             /* 8 for --more--, 1 for preceeding sp, 1 for putstr pad */
68             fudge = 10;
69         }
70 
71         /* There is a one pixel border at the borders, so subtract two */
72         bottom = amii_msgborder(w);
73 
74         wheight = (w->Height - w->BorderTop - w->BorderBottom - 3)
75                   / w->RPort->TxHeight;
76 
77         if (scrollmsg || wheight > 1)
78             fudge = 0;
79 
80         amii_scrollmsg(w, cw);
81 
82         while (isspace(*str))
83             str++;
84         strncpy(g.toplines, str, TBUFSZ);
85         g.toplines[TBUFSZ - 1] = 0;
86 
87         /* For initial message to be visible, we need to explicitly position
88          * the
89          * cursor.  This flag, cw->curx == -1 is set elsewhere to force the
90          * cursor to be repositioned to the "bottom".
91          */
92         if (cw->curx == -1) {
93             amii_curs(WIN_MESSAGE, 1, bottom);
94             cw->curx = 0;
95         }
96 
97         /* If used all of history lines, move them down */
98         if (cw->maxrow >= iflags.msg_history) {
99             if (cw->data[0])
100                 free(cw->data[0]);
101             memcpy(cw->data, &cw->data[1],
102                    (iflags.msg_history - 1) * sizeof(char *));
103             cw->data[iflags.msg_history - 1] =
104                 (char *) alloc(strlen(g.toplines) + 5);
105             strcpy(cw->data[i = iflags.msg_history - 1] + SOFF
106                        + (scrollmsg != 0),
107                    g.toplines);
108         } else {
109             /* Otherwise, allocate a new one and copy the line in */
110             cw->data[cw->maxrow] = (char *) alloc(strlen(g.toplines) + 5);
111             strcpy(cw->data[i = cw->maxrow++] + SOFF + (scrollmsg != 0),
112                    g.toplines);
113         }
114         cw->data[i][SEL_ITEM] = 1;
115         cw->data[i][VATTR] = attr + 1;
116 
117         if (scrollmsg) {
118             cw->curx = 0;
119             cw->data[i][2] = (cw->wflags & FLMSG_FIRST) ? '>' : ' ';
120         }
121 
122         str = cw->data[i] + SOFF;
123         if (cw->curx + strlen(str) >= (cw->cols - fudge)) {
124             int i;
125             char *ostr = (char *) str;
126             char *p;
127 
128             while (cw->curx + strlen(str) >= (cw->cols - fudge)) {
129                 for (p = ((char *) &str[cw->cols - 1 - cw->curx]) - fudge;
130                      !isspace(*p) && p > str;)
131                     --p;
132                 if (p < str)
133                     p = (char *) str;
134 
135                 if (p == str) {
136                     /*    p = (char *)&str[ cw->cols ]; */
137                     outmore(cw);
138                     continue;
139                 }
140 
141                 i = (long) p - (long) str;
142                 outsubstr(cw, (char *) str, i, fudge);
143                 cw->curx += i;
144 
145                 while (isspace(*p))
146                     p++;
147                 str = p;
148 
149 #if 0
150 		if( str != ostr ) {
151 		    outsubstr( cw, "+", 1, fudge );
152 		    cw->curx+=2;
153 		}
154 #endif
155                 if (*str)
156                     amii_scrollmsg(w, cw);
157                 amii_cl_end(cw, cw->curx);
158             }
159 
160             if (*str) {
161                 if (str != ostr) {
162                     outsubstr(cw, "+", 1, fudge);
163                     cw->curx += 2;
164                 }
165                 while (isspace(*str))
166                     ++str;
167                 outsubstr(cw, (char *) str, i = strlen((char *) str), fudge);
168                 cw->curx += i;
169                 amii_cl_end(cw, cw->curx);
170             }
171         } else {
172             outsubstr(cw, (char *) str, i = strlen((char *) str), fudge);
173             cw->curx += i;
174             amii_cl_end(cw, cw->curx);
175         }
176         cw->wflags &= ~FLMSG_FIRST;
177         len = 0;
178         if (scrollmsg) {
179             totalvis = CountLines(window);
180             SetPropInfo(w, &MsgScroll,
181                         (w->Height - w->BorderTop - w->BorderBottom)
182                             / w->RPort->TxHeight,
183                         totalvis, totalvis);
184         }
185         i = strlen(g.toplines + SOFF);
186         cw->maxcol = max(cw->maxcol, i);
187         cw->vwy = cw->maxrow;
188         break;
189 
190     case NHW_STATUS:
191         if (cw->data[cw->cury] == NULL)
192             panic("NULL pointer for status window");
193         ob = &cw->data[cw->cury][j = cw->curx];
194         if (g.context.botlx)
195             *ob = 0;
196 
197         /* Display when beam at top to avoid flicker... */
198         WaitTOF();
199         Text(w->RPort, (char *) str, strlen((char *) str));
200         if (cw->cols > strlen(str))
201             TextSpaces(w->RPort, cw->cols - strlen(str));
202 
203         (void) strncpy(cw->data[cw->cury], str, cw->cols);
204         cw->data[cw->cury][cw->cols - 1] = '\0'; /* null terminate */
205         cw->cury = (cw->cury + 1) % 2;
206         cw->curx = 0;
207         break;
208 
209     case NHW_MAP:
210     case NHW_BASE:
211         if (cw->type == NHW_BASE && wrapping) {
212             amii_curs(window, cw->curx + 1, cw->cury);
213             TextSpaces(w->RPort, cw->cols);
214             if (cw->cury < cw->rows) {
215                 amii_curs(window, cw->curx + 1, cw->cury + 1);
216                 TextSpaces(w->RPort, cw->cols);
217                 cw->cury--;
218             }
219         }
220         amii_curs(window, cw->curx + 1, cw->cury);
221         Text(w->RPort, (char *) str, strlen((char *) str));
222         cw->curx = 0;
223         /* CR-LF is automatic in these windows */
224         cw->cury++;
225         if (cw->type == NHW_BASE && cw->cury >= cw->rows) {
226             cw->cury = 0;
227             wrapping = 1;
228         }
229         break;
230 
231     case NHW_MENU:
232     case NHW_TEXT:
233 
234         /* always grows one at a time, but alloc 12 at a time */
235 
236         if (cw->cury >= cw->rows || !cw->data) {
237             char **tmp;
238 
239             /* Allocate 12 more rows */
240             cw->rows += 12;
241             tmp = (char **) alloc(sizeof(char *) * cw->rows);
242 
243             /* Copy the old lines */
244             for (i = 0; i < cw->cury; i++)
245                 tmp[i] = cw->data[i];
246 
247             if (cw->data) {
248                 free(cw->data);
249                 cw->data = NULL;
250             }
251 
252             cw->data = tmp;
253 
254             /* Null out the unused entries. */
255             for (i = cw->cury; i < cw->rows; i++)
256                 cw->data[i] = 0;
257         }
258 
259         if (!cw->data)
260             panic("no data storage");
261 
262         /* Shouldn't need to do this, but... */
263 
264         if (cw->data && cw->data[cw->cury]) {
265             free(cw->data[cw->cury]);
266             cw->data[cw->cury] = NULL;
267         }
268 
269         n0 = strlen(str) + 1;
270         cw->data[cw->cury] = (char *) alloc(n0 + SOFF);
271 
272         /* avoid nuls, for convenience */
273         cw->data[cw->cury][VATTR] = attr + 1;
274         cw->data[cw->cury][SEL_ITEM] = 0;
275         Strcpy(cw->data[cw->cury] + SOFF, str);
276 
277         if (n0 > cw->maxcol)
278             cw->maxcol = n0;
279         if (++cw->cury > cw->maxrow)
280             cw->maxrow = cw->cury;
281         break;
282 
283     default:
284         panic("Invalid or unset window type in putstr()");
285     }
286 }
287 
288 void
amii_scrollmsg(w,cw)289 amii_scrollmsg(w, cw)
290 register struct Window *w;
291 register struct amii_WinDesc *cw;
292 {
293     int bottom, wheight;
294 
295     bottom = amii_msgborder(w);
296 
297     wheight =
298         (w->Height - w->BorderTop - w->BorderBottom - 3) / w->RPort->TxHeight;
299 
300     if (scrollmsg) {
301         if (++cw->disprows > wheight) {
302             outmore(cw);
303             cw->disprows = 1; /* count this line... */
304         } else {
305             ScrollRaster(w->RPort, 0, w->RPort->TxHeight, w->BorderLeft,
306                          w->BorderTop + 1, w->Width - w->BorderRight - 1,
307                          w->Height - w->BorderBottom - 1);
308         }
309         amii_curs(WIN_MESSAGE, 1, bottom);
310     }
311 }
312 
313 int
amii_msgborder(w)314 amii_msgborder(w)
315 struct Window *w;
316 {
317     register int bottom;
318 
319     /* There is a one pixel border at the borders, so subtract two */
320     bottom = w->Height - w->BorderTop - w->BorderBottom - 2;
321     bottom /= w->RPort->TxHeight;
322     if (bottom > 0)
323         --bottom;
324     return (bottom);
325 }
326 
327 void
outmore(cw)328 outmore(cw)
329 register struct amii_WinDesc *cw;
330 {
331     struct Window *w = cw->win;
332 
333     if ((cw->wflags & FLMAP_SKIP) == 0) {
334         if (scrollmsg) {
335             int bottom;
336 
337             bottom = amii_msgborder(w);
338 
339             ScrollRaster(w->RPort, 0, w->RPort->TxHeight, w->BorderLeft,
340                          w->BorderTop + 1, w->Width - w->BorderRight - 1,
341                          w->Height - w->BorderBottom - 1);
342             amii_curs(WIN_MESSAGE, 1, bottom); /* -1 for inner border */
343             Text(w->RPort, "--more--", 8);
344         } else
345             Text(w->RPort, " --more--", 9);
346 
347         /* Make sure there are no events in the queue */
348         flushIDCMP(HackPort);
349 
350         /* Allow mouse clicks to clear --more-- */
351         WindowGetchar();
352         if (lastevent.type == WEKEY && lastevent.un.key == '\33')
353             cw->wflags |= FLMAP_SKIP;
354     }
355     if (!scrollmsg) {
356         amii_curs(WIN_MESSAGE, 1, 0);
357         amii_cl_end(cw, cw->curx);
358     }
359 }
360 
361 void
outsubstr(cw,str,len,fudge)362 outsubstr(cw, str, len, fudge)
363 register struct amii_WinDesc *cw;
364 char *str;
365 int len;
366 int fudge;
367 {
368     struct Window *w = cw->win;
369 
370     if (cw->curx) {
371         /* Check if this string and --more-- fit, if not,
372          * then put out --more-- and wait for a key.
373          */
374         if ((len + fudge) + cw->curx >= cw->cols) {
375             if (!scrollmsg)
376                 outmore(cw);
377         } else {
378             /* Otherwise, move and put out a blank separator */
379             Text(w->RPort, spaces, 1);
380             cw->curx += 1;
381         }
382     }
383 
384     Text(w->RPort, str, len);
385 }
386 
387 /* Put a graphics character onto the screen */
388 
389 void
amii_putsym(st,i,y,c)390 amii_putsym(st, i, y, c)
391 winid st;
392 int i, y;
393 CHAR_P c;
394 {
395     amii_curs(st, i, y);
396     Text(amii_wins[st]->win->RPort, &c, 1);
397 }
398 
399 /* Add to the last line in the message window */
400 
401 void
amii_addtopl(s)402 amii_addtopl(s)
403 const char *s;
404 {
405     register struct amii_WinDesc *cw = amii_wins[WIN_MESSAGE];
406 
407     while (*s) {
408         if (cw->curx == cw->cols - 1)
409             amii_putstr(WIN_MESSAGE, 0, "");
410         amii_putsym(WIN_MESSAGE, cw->curx + 1, amii_msgborder(cw->win), *s++);
411         cw->curx++;
412     }
413 }
414 
415 void
TextSpaces(rp,nr)416 TextSpaces(rp, nr)
417 struct RastPort *rp;
418 int nr;
419 {
420     if (nr < 1)
421         return;
422 
423     while (nr > sizeof(spaces) - 1) {
424         Text(rp, spaces, (long) sizeof(spaces) - 1);
425         nr -= sizeof(spaces) - 1;
426     }
427     if (nr > 0)
428         Text(rp, spaces, (long) nr);
429 }
430 
431 void
amii_remember_topl()432 amii_remember_topl()
433 {
434     /* ignore for now.  I think this will be done automatically by
435      * the code writing to the message window, but I could be wrong.
436      */
437 }
438 
439 int
amii_doprev_message()440 amii_doprev_message()
441 {
442     struct amii_WinDesc *cw;
443     struct Window *w;
444     char *str;
445 
446     if (WIN_MESSAGE == WIN_ERR || (cw = amii_wins[WIN_MESSAGE]) == NULL
447         || (w = cw->win) == NULL) {
448         panic(winpanicstr, WIN_MESSAGE, "doprev_message");
449     }
450 
451     /* When an interlaced/tall screen is in use, the scroll bar will be there
452      */
453     /* Or in some other cases as well */
454     if (scrollmsg) {
455         struct Gadget *gd;
456         struct PropInfo *pip;
457         int hidden, topidx, i, total, wheight;
458 
459         for (gd = w->FirstGadget; gd && gd->GadgetID != 1;)
460             gd = gd->NextGadget;
461 
462         if (gd) {
463             pip = (struct PropInfo *) gd->SpecialInfo;
464             wheight = (w->Height - w->BorderTop - w->BorderBottom - 2)
465                       / w->RPort->TxHeight;
466             hidden = max(cw->maxrow - wheight, 0);
467             topidx = (((ULONG) hidden * pip->VertPot) + (MAXPOT / 2)) >> 16;
468             for (total = i = 0; i < cw->maxrow; ++i) {
469                 if (cw->data[i][1] != 0)
470                     ++total;
471             }
472 
473             i = 0;
474             topidx -= wheight / 4 + 1;
475             if (topidx < 0)
476                 topidx = 0;
477             SetPropInfo(w, &MsgScroll, wheight, total, topidx);
478             DisplayData(WIN_MESSAGE, topidx);
479         }
480         return (0);
481     }
482 
483     if (--cw->vwy < 0) {
484         cw->maxcol = 0;
485         DisplayBeep(NULL);
486         str = "\0\0No more history saved...";
487     } else
488         str = cw->data[cw->vwy];
489 
490     amii_cl_end(cw, 0);
491     amii_curs(WIN_MESSAGE, 1, 0);
492     amii_setdrawpens(amii_wins[WIN_MESSAGE]->win, NHW_MESSAGE);
493     Text(w->RPort, str + SOFF, strlen(str + SOFF));
494     cw->curx = cw->cols + 1;
495 
496     return (0);
497 }
498