]> git.sur5r.net Git - c128-kasse/blob - src/kasse.c
update the clock on the main menu via an irq handler
[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 #include <stdio.h>
8 #include <conio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <cbm.h>
12 #include <c128.h>
13 #include <6502.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 #include "vdc_patch_charset.h"
23 #include "globals.h"
24 // drucker 4 oder 5
25 // graphic 4,0,10
26
27 void print_item(BYTE i) {
28   char profit[EUR_FORMAT_MINLEN + 1];
29   if (format_euro(profit, sizeof(profit), status.status[i].price) == NULL) {
30     cprintf("Preis %ld konnte nicht umgerechnet werden\r\n",
31             status.status[i].price);
32     exit(1);
33   }
34   textcolor(TC_YELLOW);
35   cprintf("%2d", i);
36   textcolor(TC_LIGHT_GRAY);
37   cprintf(": %-" xstr(MAX_ITEM_NAME_LENGTH) "s \xDD%s,   %3dx ",
38           status.status[i].item_name, profit, status.status[i].times_sold);
39 }
40
41 /* Hauptbildschirm ausgeben */
42 static void print_screen(void) {
43   BYTE i = 0;
44   char profit[EUR_FORMAT_MINLEN + 1];
45   clrscr();
46   if (format_euro(profit, sizeof(profit), money) == NULL) {
47     cprintf("Einnahme %ld konnte nicht umgerechnet werden\r\n", money);
48     profit[0] = '\0';
49   }
50   textcolor(TC_CYAN);
51   cprintf("C128-Kassenprogramm (phil_fry, sECuRE, sur5r, mxf) " GV "\r\n");
52   textcolor(TC_LIGHT_GRAY);
53   cprintf("\r\n\r\n"
54           "Ertrag: %s (%ld Artikel); Drucken: %s\r\n",
55           profit, items_sold, (printing == 1 ? "ein" : "aus"));
56   textcolor(TC_LIGHT_GRAY);
57   cprintf("      \xB0"
58           "\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\xC0\xC0\xB2"
60           "\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xB2"
61           "\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xAE"
62           "\r\n");
63   for (; i < min(status.num_items, 15); ++i) {
64
65     cprintf("      \xDD");
66     print_item(i);
67     cprintf("\xDD");
68
69     /* if we have more than 15 items, use the second column */
70     if ((i + 15) < status.num_items) {
71       print_item(i + 15);
72       cprintf("\xDD");
73     } else {
74       cprintf("              \xDD                \xDD");
75     }
76
77     cprintf("\r\n");
78   }
79   cprintf("      \xAD"
80           "\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\xC0\xC0\xB1"
82           "\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xB1"
83           "\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xC0\xBD"
84           "\r\n");
85   textcolor(TC_YELLOW);
86   cprintf("   s");
87   textcolor(TC_LIGHT_GRAY);
88   cprintf(") Daten sichern                                  ");
89   textcolor(TC_YELLOW);
90   cprintf("g");
91   textcolor(TC_LIGHT_GRAY);
92   cprintf(") Guthabenverwaltung\r\n");
93   textcolor(TC_YELLOW);
94   cprintf("   z");
95   textcolor(TC_LIGHT_GRAY);
96   cprintf(") Zeit setzen         ");
97   textcolor(TC_YELLOW);
98   cprintf("f");
99   textcolor(TC_LIGHT_GRAY);
100   cprintf(") Freitext verkaufen      ");
101   textcolor(TC_YELLOW);
102   cprintf("q");
103   textcolor(TC_LIGHT_GRAY);
104   cprintf(") Beenden\r\n");
105 }
106
107 /*
108  * Prints a line and logs it to file. Every line can be at max 80 characters.
109  *
110  */
111 static void print_log(char *name, int32_t item_price, int16_t einheiten,
112                       char *nickname, char *rest) {
113   char *time = get_time();
114   uint8_t n;
115   char price[EUR_FORMAT_MINLEN + 1];
116   if (format_euro(price, sizeof(price), item_price) == NULL) {
117     cprintf("Preis %d konnte nicht umgerechnet werden\r\n", item_price);
118     exit(1);
119   }
120
121   /* TODO: teach the EUR sign to the printer.
122    * Until then, we just overwrite it with "E" */
123   price[EUR_FORMAT_MINLEN - 1] = 'E';
124   rest[EUR_FORMAT_MINLEN - 1] = 'E';
125
126   /* clang-format off */
127   n = snprintf(print_buffer, sizeof(print_buffer),
128         /* enable lower case letters -- 1 */
129         "%c"
130         /*  Transaction-ID (Anzahl verkaufter Einträge, inklusive des zu druckenden!)
131             -- 6-stellig */
132         "[%3u] "
133         /* Uhrzeit -- 8-stellig + 3 */
134         "%8s - "
135         /*  Eintragname (= Getränk) -- 9-stellig + 3 */
136         "%-" xstr(MAX_ITEM_NAME_LENGTH) "s - "
137         /*  Preis (in Cents) -- 8-stellig  + 3 */
138         "%" xstr(EUR_FORMAT_MINLEN) "s - "
139         /*  restguthaben (8-stellig) + 3 */
140         "%" xstr(EUR_FORMAT_MINLEN) "s - "
141         /*  Anzahl -- 2-stellig + 3 */
142         "%2d - "
143         /*  Nickname (falls es vom Guthaben abgezogen wird) -- 10-stellig + 4 */
144         "an %" xstr(NICKNAME_MAX_LEN)"s\r",
145         17, status.transaction_id, time, name, price, rest, einheiten,
146         (*nickname != '\0' ? nickname : "Unbekannt"));
147   /* clang-format on */
148   if (n > sizeof(print_buffer)) {
149     cprintf("\r\nprint_log(): print_buffer overflowed!\r\n"
150             "Wanted to write %d bytes\r\n%s\r\n",
151             n, print_buffer);
152     exit(1);
153   }
154
155   status.transaction_id++;
156   print_the_buffer();
157 }
158
159 /* dialog which is called for each bought item */
160 static signed int buy(char *name, int32_t price) {
161   BYTE matches = 0;
162   BYTE c, nickname_len;
163   int16_t einheiten;
164   char nickname[NICKNAME_MAX_LEN + 1];
165   char rest[EUR_FORMAT_MINLEN + 1];
166   struct credits_t *credit;
167
168   clrscr();
169   cprintf("Wieviel Einheiten \"%s\"? [1] \r\n", name);
170
171   einheiten = cget_number(1);
172
173   if (einheiten > 100 || einheiten < -100 || einheiten == 0) {
174     cprintf("\r\nEinheit nicht in [-100, 100] oder 0, Abbruch, dr" uUML "cke "
175             "RETURN...\r\n");
176     cget_return();
177     return 1;
178   }
179
180   cprintf("\r\nAuf ein Guthaben kaufen? Wenn ja, Nickname eingeben:\r\n");
181   nickname_len = cget_nickname(nickname, sizeof(nickname));
182
183   if (nickname_len && *nickname != '\0' && *nickname != PETSCII_SP) {
184     /* go through credits and remove the amount of money or set nickname
185      * to NULL if no such credit could be found */
186     credit = find_credit(nickname);
187     if (credit != NULL) {
188       while ((int32_t)credit->credit < (price * einheiten)) {
189         if (format_euro(rest, sizeof(rest), credit->credit) == NULL) {
190           cprintf("Preis %d konnte nicht umgerechnet werden\r\n",
191                   credit->credit);
192           exit(1);
193         }
194         cprintf(
195             "\r\n%s hat nicht genug Geld (%s). e) einzahlen a) abbruch \r\n",
196             nickname, rest);
197         c = cgetc();
198         if (c == 'e') {
199           deposit_credit(nickname);
200         } else {
201           return 0;
202         }
203       }
204       /* substract money */
205       credit->credit -= (price * einheiten);
206
207       if (format_euro(rest, sizeof(rest), credit->credit) == NULL) {
208         cprintf("Preis %d konnte nicht umgerechnet werden\r\n", credit->credit);
209         exit(1);
210       }
211
212       textcolor(TC_LIGHT_GREEN);
213       cprintf("\r\nVerbleibendes Guthaben f" uUML "r %s: %s. Dr" uUML
214               "cke RETURN...\r\n",
215               nickname, rest);
216       textcolor(TC_LIGHT_GRAY);
217       cget_return();
218       matches++;
219     } else {
220       textcolor(TC_LIGHT_RED);
221       cprintf("\r\nNickname nicht gefunden in der Guthabenverwaltung! Abbruch, "
222               "dr" uUML "cke RETURN...\r\n");
223       textcolor(TC_LIGHT_GRAY);
224       cget_return();
225       return 0;
226     }
227   }
228
229   money += price * einheiten;
230   items_sold += einheiten;
231   if (printing == 1)
232     print_log(name, price, einheiten, nickname, rest);
233
234   return einheiten;
235 }
236
237 void buy_stock(BYTE n) {
238   if (n >= status.num_items || status.status[n].item_name == NULL) {
239     cprintf("FEHLER: Diese Einheit existiert nicht.\r\n");
240     cget_return();
241     return;
242   }
243
244   status.status[n].times_sold +=
245       buy(status.status[n].item_name, status.status[n].price);
246 }
247
248 void buy_custom(void) {
249   char name[MAX_ITEM_NAME_LENGTH + 1];
250   int price;
251
252   clrscr();
253   cprintf("\r\nWas soll gekauft werden?\r\n");
254   if (cgetn_input(name, sizeof(name)) == 0)
255     return;
256
257   cprintf("\r\nWie teuer ist \"%s\" (in cents)?\r\n", name);
258
259   price = cget_number(0);
260
261   if (price == 0) {
262     cprintf("Kauf abgebrochen, dr" uUML "cke RETURN...\r\n");
263     cget_return();
264     return;
265   }
266
267   buy(name, price);
268 }
269
270 void set_time_interactive(void) {
271   char part[3] = {'\0', '\0', '\0'};
272   uint8_t day, tp1, tp2, tp3;
273   char *time_input, *time;
274   cprintf("Gib den aktuellen Tag des Events und Uhrzeit ein\r\n"
275           "(Format DHHMMSS):\r\n");
276   time_input = get_input();
277   part[0] = time_input[0];
278   day = atoi(part);
279   part[0] = time_input[1];
280   part[1] = time_input[2];
281   tp1 = atoi(part);
282   part[0] = time_input[3];
283   part[1] = time_input[4];
284   tp2 = atoi(part);
285   part[0] = time_input[5];
286   part[1] = time_input[6];
287   tp3 = atoi(part);
288   set_time(day, tp1, tp2, tp3);
289
290   time = get_time();
291   cprintf("\r\nZeit gesetzt: %s\r\n", time);
292 }
293
294 int main(void) {
295   char *c;
296   char *time;
297
298   init_globals();
299
300   videomode(VIDEOMODE_80x25);
301
302   /* clock CPU at double the speed (a whopping 2 Mhz!) */
303   fast();
304
305   /* Manipulate the VDC with IRQs turned off.
306    * KERNALs default IRQ handler will also try to read the VDC status
307    * register, which could interfere with our code trying to read it.
308    */
309   SEI();
310   vdc_patch_charset();
311   CLI();
312
313   clrscr();
314
315   install_daytime_irq();
316
317   /* Allocate logging buffer memory */
318   init_log();
319
320   /* Set time initially, c128 doesn't know it */
321   set_time_interactive();
322
323   /* disable interrupt driven VIC screen editor */
324   POKE(0xD8, 255);
325
326   /* Load configuration */
327   load_config();
328
329   /* Load items (= drinks) */
330   load_items();
331   /* Load credits */
332   load_credits();
333
334   time = get_time();
335   sprintf(print_buffer, "%c----------------------------------------------------"
336                         "----------------------------\r",
337           17);
338   print_the_buffer();
339   sprintf(print_buffer, "%cC128-Kasse Version " GV "\r", 17);
340   print_the_buffer();
341
342   sprintf(print_buffer,
343           "%cKasse gestartet um %s. Nutze logfile log-%u, offset %d.\r", 17,
344           time, log_num, log_heap_offset);
345   print_the_buffer();
346
347   print_header();
348
349   while (1) {
350     print_screen();
351     kasse_menu = MENU_MAIN;
352     c = get_input();
353     kasse_menu = MENU_UNDEFINED;
354     /* ...display dialogs eventually */
355     if (*c >= PETSCII_0 && *c <= PETSCII_9) {
356       /* if the input starts with a digit, we will interpret it as a number
357        * for the item to be sold */
358       buy_stock(atoi(c));
359     } else if (*c == 'f') {
360       buy_custom();
361     } else if (*c == 's') {
362       cprintf("\r\nsaving items.. ");
363       save_items();
364       cprintf("ok\r\nsaving credits.. ");
365       save_credits();
366       cprintf("ok\r\nflushing log.. ");
367       log_flush();
368       cprintf("ok\r\nStatefile/Creditfile/Log gesichert, dr" uUML
369               "cke RETURN...\r\n");
370       cget_return();
371     } else if (*c == 'g') {
372       credit_manager();
373     } else if (*c == 'z') {
374       set_time_interactive();
375     } else if (*c == 'q')
376       break;
377   }
378   clrscr();
379   cprintf("\r\nBYEBYE\r\n");
380
381   return 0;
382 }