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