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