]> git.sur5r.net Git - c128-kasse/blob - src/kasse.c
use correct constant to switch videomode
[c128-kasse] / src / kasse.c
1 /*
2  * RGB2R-C128-Kassenprogramm
3  * © 2007-2009 phil_fry, sECuRE, sur5r
4  * See LICENSE for license information
5  *
6  */
7 #define _IS_KASSE
8 #include <stdio.h>
9 #include <conio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <cbm.h>
13 #include <c128.h>
14
15 #include "general.h"
16 #include "config.h"
17 #include "kasse.h"
18 #include "credit_manager.h"
19 #include "c128time.h"
20 #include "print.h"
21 #include "version.h"
22 // drucker 4 oder 5
23 // graphic 4,0,10
24
25 void print_item(BYTE i) {
26   char profit[10];
27   if (format_euro(profit, sizeof(profit), status.status[i].price) == NULL) {
28     cprintf("Preis %ld konnte nicht umgerechnet werden\r\n",
29             status.status[i].price);
30     exit(1);
31   }
32   textcolor(TC_YELLOW);
33   cprintf("%2d", i);
34   textcolor(TC_LIGHT_GRAY);
35   cprintf(": %-" xstr(MAX_ITEM_NAME_LENGTH) "s \xDD%s, %3dx ",
36           status.status[i].item_name, profit, status.status[i].times_sold);
37 }
38
39 /* Hauptbildschirm ausgeben */
40 static void print_screen(void) {
41   BYTE i = 0;
42   char *time = get_time();
43   char profit[10];
44   clrscr();
45   if (format_euro(profit, 10, money) == NULL) {
46     cprintf("Einnahme %ld konnte nicht umgerechnet werden\r\n", money);
47     exit(1);
48   }
49   textcolor(TC_CYAN);
50   cprintf("C128-Kassenprogramm (phil_fry, sECuRE, sur5r) " GV "\r\n");
51   textcolor(TC_LIGHT_GRAY);
52   cprintf("\r\nUhrzeit:     %s (wird nicht aktualisiert)\r\n"
53           "Eingenommen: %s, Verkauft: %ld Dinge, Drucken: %s\r\n",
54           time, profit, items_sold, (printing == 1 ? "ein" : "aus"));
55   textcolor(TC_LIGHT_GRAY);
56   cprintf("      \xB0"
57           "\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xB2"
58           "\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xB2"
59           "\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xB2"
60           "\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xAE"
61           "\r\n");
62   for (; i < min(status.num_items, 15); ++i) {
63
64     cprintf("      \xDD");
65     print_item(i);
66     cprintf("\xDD");
67
68     /* if we have more than 15 items, use the second column */
69     if ((i + 15) < status.num_items) {
70       print_item(i + 15);
71       cprintf("\xDD");
72     } else {
73       cprintf("              \xDD                \xDD");
74     }
75
76     cprintf("\r\n");
77   }
78   cprintf("      \xAD"
79           "\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xB1"
80           "\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xB1"
81           "\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xB1"
82           "\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xBD"
83           "\r\n");
84   textcolor(TC_YELLOW);
85   cprintf("   s");
86   textcolor(TC_LIGHT_GRAY);
87   cprintf(") Daten sichern                                  ");
88   textcolor(TC_YELLOW);
89   cprintf("g");
90   textcolor(TC_LIGHT_GRAY);
91   cprintf(") Guthabenverwaltung\r\n");
92   textcolor(TC_YELLOW);
93   cprintf("   z");
94   textcolor(TC_LIGHT_GRAY);
95   cprintf(") Zeit setzen         ");
96   textcolor(TC_YELLOW);
97   cprintf("f");
98   textcolor(TC_LIGHT_GRAY);
99   cprintf(") Freitext verkaufen      ");
100   textcolor(TC_YELLOW);
101   cprintf("q");
102   textcolor(TC_LIGHT_GRAY);
103   cprintf(") Beenden\r\n");
104 }
105
106 /*
107  * Prints a line and logs it to file. Every line can be at max 80 characters.
108  *
109  */
110 static void print_log(char *name, int item_price, int einheiten, char *nickname,
111                       char *rest) {
112   char *time = get_time();
113   char price[10];
114   /* Format:
115      Transaction-ID (Anzahl verkaufter Einträge, inklusive des zu druckenden!)
116      -- 6-stellig
117      Uhrzeit -- 8-stellig
118      Eintragname (= Getränk) -- 9-stellig
119      Preis (in Cents) -- 9-stellig
120      Anzahl -- 2-stellig
121      Nickname (falls es vom Guthaben abgezogen wird) -- 10-stellig
122      restguthaben (9-stellig)
123
124      + 7 leerzeichen
125      --> 48 zeichen
126      */
127   if (format_euro(price, 10, item_price) == NULL) {
128     cprintf("Preis %d konnte nicht umgerechnet werden\r\n", item_price);
129     exit(1);
130   }
131
132   sprintf(print_buffer, "%c[%3u] %s - %-" xstr(
133                             MAX_ITEM_NAME_LENGTH) "s - %s - %s - %d - an %s\r",
134           17, status.transaction_id, time, name, price, rest, einheiten,
135           (*nickname != '\0' ? nickname : "Unbekannt"));
136   status.transaction_id++;
137   print_the_buffer();
138 }
139
140 /* dialog which is called for each bought item */
141 static signed int buy(char *name, unsigned int price) {
142   int negative = 1;
143   char entered[5] = {'1', 0, 0, 0, 0};
144   BYTE i = 0, matches = 0;
145   BYTE c, x, y, nickname_len;
146   int einheiten;
147   char nickname[NICKNAME_MAX_LEN + 1];
148   char rest[11];
149   struct credits_t *credit;
150
151   memset(nickname, '\0', sizeof(nickname));
152   memset(rest, ' ', sizeof(rest));
153   rest[8] = '\0';
154
155   clrscr();
156   cprintf("Wieviel Einheiten \"%s\"? [1] \r\n", name);
157   x = wherex();
158   y = wherey();
159   while (1) {
160     /* Buffer-Ende erreicht? */
161     if (i == 4)
162       break;
163
164     c = cgetc();
165     /* Enter */
166     if (c == PETSCII_CR)
167       break;
168     /* Backspace */
169     if (c == PETSCII_DEL) {
170       if (i == 0)
171         continue;
172       entered[--i] = '\0';
173       cputcxy(x + i, y, ' ');
174       gotoxy(x + i, y);
175       continue;
176     }
177     if (c == 27) {
178       cprintf("Kauf abgebrochen, druecke RETURN...\r\n");
179       get_input();
180       return 1;
181     }
182     if (c == '-' && i == 0) {
183       negative = -1;
184       cputc(c);
185     } else if (c >= PETSCII_0 && c <= PETSCII_9) {
186       entered[i++] = c;
187       cputc(c);
188     }
189
190     /* Ungültige Eingabe (keine Ziffer), einfach ignorieren */
191   }
192   einheiten = atoi(entered) * negative;
193
194   if (einheiten > 100 || einheiten < -100 || einheiten == 0) {
195     cprintf("\r\nEinheit nicht in [-100, 100] oder 0, Abbruch, druecke "
196             "RETURN...\r\n");
197     cgetc();
198     return 1;
199   }
200
201   cprintf("\r\nAuf ein Guthaben kaufen? Wenn ja, Nickname eingeben:\r\n");
202   {
203     BYTE i;
204     BYTE x;
205     BYTE y;
206     BYTE matches;
207     char *uniquematch;
208     input_terminator_t terminator;
209     while (1) {
210       terminator = get_input_terminated_by(INPUT_TERMINATOR_RETURN |
211                                                INPUT_TERMINATOR_SPACE,
212                                            nickname, sizeof(nickname));
213
214       /* Clear the screen from any previous completions */
215       x = wherex();
216       y = wherey();
217       for (i = 1; i < 7; i++) {
218         /* "Completion:" is longer than NICKNAME_MAX_LEN */
219         cclearxy(0, y + i, strlen("Completion:"));
220       }
221       gotoxy(x, y);
222
223       if (terminator != INPUT_TERMINATOR_SPACE) {
224         break;
225       }
226
227       matches = 0;
228       uniquematch = NULL;
229       for (i = 0; i < credits.num_items; i++) {
230         if (strncmp(nickname, credits.credits[i].nickname, strlen(nickname)) !=
231             0) {
232           continue;
233         }
234         matches++;
235         if (matches > 1) {
236           break;
237         }
238         uniquematch = credits.credits[i].nickname;
239       }
240       if (matches == 1) {
241         /* Display the rest of the nickname */
242         textcolor(TC_LIGHT_GREEN);
243         cprintf("%s", uniquematch + strlen(nickname));
244         textcolor(TC_LIGHT_GRAY);
245         strcat(nickname, uniquematch + strlen(nickname));
246       } else {
247         /* Multiple nicknames match what was entered so far. Abort and
248          * display all matches, then prompt the user again. */
249         char completion[NICKNAME_MAX_LEN + 1];
250         BYTE len = strlen(nickname);
251         x = wherex();
252         y = wherey();
253         cprintf("\r\nCompletion:\r\n");
254         matches = 0;
255         for (i = 0; i < credits.num_items; i++) {
256           if (strncmp(nickname, credits.credits[i].nickname, len) != 0) {
257             continue;
258           }
259           if (++matches == 5) {
260             cprintf("...\r\n");
261             break;
262           }
263           strcpy(completion, credits.credits[i].nickname);
264           *(completion + len) = '\0';
265           cprintf("%s", completion);
266           textcolor(TC_LIGHT_GREEN);
267           cprintf("%c", *(credits.credits[i].nickname + len));
268           textcolor(TC_LIGHT_GRAY);
269           cprintf("%s\r\n", completion + len + 1);
270         }
271         gotoxy(x, y);
272       }
273     }
274   }
275
276   if (*nickname != '\0' && *nickname != 32) {
277     nickname_len = strlen(nickname);
278     /* go through credits and remove the amount of money or set nickname
279      * to NULL if no such credit could be found */
280     credit = find_credit(nickname);
281     if (credit != NULL) {
282       while ((signed int)credit->credit < ((signed int)price * einheiten)) {
283         if (format_euro(rest, 10, credit->credit) == NULL) {
284           cprintf("Preis %d konnte nicht umgerechnet werden\r\n",
285                   credit->credit);
286           exit(1);
287         }
288         cprintf(
289             "\r\n%s hat nicht genug Geld (%s). e) einzahlen a) abbruch \r\n",
290             nickname, rest);
291         c = cgetc();
292         if (c == 'e') {
293           deposit_credit(nickname);
294         } else {
295           return 0;
296         }
297       }
298       /* substract money */
299       credit->credit -= (price * einheiten);
300
301       if (format_euro(rest, 10, credit->credit) == NULL) {
302         cprintf("Preis %d konnte nicht umgerechnet werden\r\n", credit->credit);
303         exit(1);
304       }
305
306       textcolor(TC_LIGHT_GREEN);
307       cprintf("\r\nVerbleibendes Guthaben fuer %s: %s. Druecke RETURN...\r\n",
308               nickname, rest);
309       textcolor(TC_LIGHT_GRAY);
310       get_input();
311       matches++;
312     } else {
313       textcolor(TC_LIGHT_RED);
314       cprintf("\r\nNickname nicht gefunden in der Guthabenverwaltung! Abbruch, "
315               "druecke RETURN...\r\n");
316       textcolor(TC_LIGHT_GRAY);
317       get_input();
318       return 0;
319     }
320   } else {
321     /* Ensure that nickname is NULL if it's empty because it's used in print_log
322      */
323     *nickname = '\0';
324   }
325
326   money += price * einheiten;
327   items_sold += einheiten;
328   if (printing == 1)
329     print_log(name, price, einheiten, nickname, rest);
330
331   return einheiten;
332 }
333
334 void buy_stock(BYTE n) {
335   if (n >= status.num_items || status.status[n].item_name == NULL) {
336     cprintf("FEHLER: Diese Einheit existiert nicht.\r\n");
337     get_input();
338     return;
339   }
340
341   status.status[n].times_sold +=
342       buy(status.status[n].item_name, status.status[n].price);
343 }
344
345 void buy_custom(void) {
346   BYTE c = 0, i = 0;
347   int negative = 1;
348   char entered[5] = {'1', 0, 0, 0, 0};
349   char *input, name[20];
350   int price;
351
352   clrscr();
353   memset(name, '\0', 20);
354   cprintf("\r\nWas soll gekauft werden?\r\n");
355   input = get_input();
356   strncpy(name, input, 20);
357   if (*name == '\0')
358     return;
359
360   cprintf("\r\nWie teuer ist \"%s\" (in cents)?\r\n", name);
361   while (1) {
362     c = cgetc();
363     if (c == 13)
364       break;
365     cputc(c);
366     if (c == 27) {
367       cprintf("Kauf abgebrochen, druecke RETURN...\r\n");
368       get_input();
369       return;
370     } else if (c == '-' && i == 0)
371       negative = -1;
372     else if (c > 47 && c < 58)
373       entered[i++] = c;
374   }
375   price = atoi(entered) * negative;
376
377   cprintf("\r\n");
378
379   buy(name, price);
380 }
381
382 void set_time_interactive(void) {
383   BYTE part[3] = {'0', '0', '\0'};
384   BYTE tp1, tp2, tp3;
385   char *time_input, *time;
386   cprintf("Gib die aktuelle Uhrzeit ein (Format HHMMSS):\r\n");
387   time_input = get_input();
388   part[0] = time_input[0];
389   part[1] = time_input[1];
390   tp1 = atoi(part);
391   part[0] = time_input[2];
392   part[1] = time_input[3];
393   tp2 = atoi(part);
394   part[0] = time_input[4];
395   part[1] = time_input[5];
396   tp3 = atoi(part);
397   set_time(tp1, tp2, tp3);
398
399   time = get_time();
400   cprintf("\r\nZeit gesetzt: %s\r\n", time);
401 }
402
403 int main(void) {
404   char *c;
405   char *time;
406
407   videomode(VIDEOMODE_80x25);
408
409   /* clock CPU at double the speed (a whopping 2 Mhz!) */
410   fast();
411
412   clrscr();
413
414   /* Allocate logging buffer memory */
415   init_log();
416
417   /* Set time initially, c128 doesn't know it */
418   set_time_interactive();
419
420   /* disable interrupt driven VIC screen editor */
421   POKE(0xD8, 255);
422
423   /* Load configuration */
424   load_config();
425
426   /* Load items (= drinks) */
427   load_items();
428   /* Load credits */
429   load_credits();
430
431   time = get_time();
432   sprintf(print_buffer, "%c----------------------------------------------------"
433                         "----------------------------\r",
434           17);
435   print_the_buffer();
436   sprintf(print_buffer, "%cC128-Kasse Version " GV "\r", 17);
437   print_the_buffer();
438
439   sprintf(print_buffer,
440           "%cKasse gestartet um %s. Nutze logfile log-%u, offset %d.\r", 17,
441           time, log_num, log_heap_offset);
442   print_the_buffer();
443
444   print_header();
445
446   while (1) {
447     print_screen();
448     c = get_input();
449     /* ...display dialogs eventually */
450     if (*c > 47 && *c < 58) {
451       /* if the input starts with a digit, we will interpret it as a number
452        * for the item to be sold */
453       buy_stock(atoi(c));
454     } else if (*c == 'f') {
455       buy_custom();
456     } else if (*c == 's') {
457       save_items();
458       save_credits();
459       log_flush();
460       cprintf("\r\nStatefile/Creditfile/Log gesichert, druecke RETURN...\r\n");
461       get_input();
462     } else if (*c == 'g') {
463       credit_manager();
464     } else if (*c == 'z') {
465       set_time_interactive();
466     } else if (*c == 'q')
467       break;
468   }
469   clrscr();
470   cprintf("\r\nBYEBYE\r\n");
471
472   return 0;
473 }