]> git.sur5r.net Git - c128-kasse/blob - src/kasse.c
kasse: move inputting nicknames w/ completion in its own function
[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   /* Format:
117      Transaction-ID (Anzahl verkaufter Einträge, inklusive des zu druckenden!)
118      -- 6-stellig
119      Uhrzeit -- 8-stellig
120      Eintragname (= Getränk) -- 9-stellig
121      Preis (in Cents) -- 9-stellig
122      Anzahl -- 2-stellig
123      Nickname (falls es vom Guthaben abgezogen wird) -- 10-stellig
124      restguthaben (9-stellig)
125
126      + 7 leerzeichen
127      --> 48 zeichen
128      */
129   if (format_euro(price, sizeof(price), item_price) == NULL) {
130     cprintf("Preis %d konnte nicht umgerechnet werden\r\n", item_price);
131     exit(1);
132   }
133
134   sprintf(print_buffer, "%c[%3u] %s - %-" xstr(
135                             MAX_ITEM_NAME_LENGTH) "s - %s - %s - %d - an %s\r",
136           17, status.transaction_id, time, name, price, rest, einheiten,
137           (*nickname != '\0' ? nickname : "Unbekannt"));
138   status.transaction_id++;
139   print_the_buffer();
140 }
141
142 /* dialog which is called for each bought item */
143 static signed int buy(char *name, unsigned int price) {
144   BYTE matches = 0;
145   BYTE c, nickname_len;
146   int einheiten;
147   char nickname[NICKNAME_MAX_LEN + 1];
148   char rest[EUR_FORMAT_MINLEN];
149   struct credits_t *credit;
150
151   clrscr();
152   cprintf("Wieviel Einheiten \"%s\"? [1] \r\n", name);
153
154   einheiten = cget_number(1);
155
156   if (einheiten > 100 || einheiten < -100 || einheiten == 0) {
157     cprintf("\r\nEinheit nicht in [-100, 100] oder 0, Abbruch, dr" uUML "cke "
158             "RETURN...\r\n");
159     cget_return();
160     return 1;
161   }
162
163   cprintf("\r\nAuf ein Guthaben kaufen? Wenn ja, Nickname eingeben:\r\n");
164   nickname_len = cget_nickname(nickname, sizeof(nickname));
165
166   if (nickname_len && *nickname != '\0' && *nickname != PETSCII_SP) {
167     /* go through credits and remove the amount of money or set nickname
168      * to NULL if no such credit could be found */
169     credit = find_credit(nickname);
170     if (credit != NULL) {
171       while ((signed int)credit->credit < ((signed int)price * einheiten)) {
172         if (format_euro(rest, sizeof(rest), credit->credit) == NULL) {
173           cprintf("Preis %d konnte nicht umgerechnet werden\r\n",
174                   credit->credit);
175           exit(1);
176         }
177         cprintf(
178             "\r\n%s hat nicht genug Geld (%s). e) einzahlen a) abbruch \r\n",
179             nickname, rest);
180         c = cgetc();
181         if (c == 'e') {
182           deposit_credit(nickname);
183         } else {
184           return 0;
185         }
186       }
187       /* substract money */
188       credit->credit -= (price * einheiten);
189
190       if (format_euro(rest, sizeof(rest), credit->credit) == NULL) {
191         cprintf("Preis %d konnte nicht umgerechnet werden\r\n", credit->credit);
192         exit(1);
193       }
194
195       textcolor(TC_LIGHT_GREEN);
196       cprintf("\r\nVerbleibendes Guthaben f" uUML "r %s: %s. Dr" uUML
197               "cke RETURN...\r\n",
198               nickname, rest);
199       textcolor(TC_LIGHT_GRAY);
200       cget_return();
201       matches++;
202     } else {
203       textcolor(TC_LIGHT_RED);
204       cprintf("\r\nNickname nicht gefunden in der Guthabenverwaltung! Abbruch, "
205               "dr" uUML "cke RETURN...\r\n");
206       textcolor(TC_LIGHT_GRAY);
207       cget_return();
208       return 0;
209     }
210   }
211
212   money += price * einheiten;
213   items_sold += einheiten;
214   if (printing == 1)
215     print_log(name, price, einheiten, nickname, rest);
216
217   return einheiten;
218 }
219
220 void buy_stock(BYTE n) {
221   if (n >= status.num_items || status.status[n].item_name == NULL) {
222     cprintf("FEHLER: Diese Einheit existiert nicht.\r\n");
223     cget_return();
224     return;
225   }
226
227   status.status[n].times_sold +=
228       buy(status.status[n].item_name, status.status[n].price);
229 }
230
231 void buy_custom(void) {
232   char name[MAX_ITEM_NAME_LENGTH + 1];
233   int price;
234
235   clrscr();
236   cprintf("\r\nWas soll gekauft werden?\r\n");
237   if (cgetn_input(name, sizeof(name)) == 0)
238     return;
239
240   cprintf("\r\nWie teuer ist \"%s\" (in cents)?\r\n", name);
241
242   price = cget_number(0);
243
244   if (price == 0) {
245     cprintf("Kauf abgebrochen, dr" uUML "cke RETURN...\r\n");
246     cget_return();
247     return;
248   }
249
250   buy(name, price);
251 }
252
253 void set_time_interactive(void) {
254   BYTE part[3] = {'0', '0', '\0'};
255   BYTE tp1, tp2, tp3;
256   char *time_input, *time;
257   cprintf("Gib die aktuelle Uhrzeit ein (Format HHMMSS):\r\n");
258   time_input = get_input();
259   part[0] = time_input[0];
260   part[1] = time_input[1];
261   tp1 = atoi(part);
262   part[0] = time_input[2];
263   part[1] = time_input[3];
264   tp2 = atoi(part);
265   part[0] = time_input[4];
266   part[1] = time_input[5];
267   tp3 = atoi(part);
268   set_time(tp1, tp2, tp3);
269
270   time = get_time();
271   cprintf("\r\nZeit gesetzt: %s\r\n", time);
272 }
273
274 int main(void) {
275   char *c;
276   char *time;
277
278   init_globals();
279
280   videomode(VIDEOMODE_80x25);
281
282   /* clock CPU at double the speed (a whopping 2 Mhz!) */
283   fast();
284
285   /* Manipulate the VDC with IRQs turned off.
286    * KERNALs default IRQ handler will also try to read the VDC status
287    * register, which could interfere with our code trying to read it.
288    */
289   SEI();
290   vdc_patch_charset();
291   CLI();
292
293   clrscr();
294
295   /* Allocate logging buffer memory */
296   init_log();
297
298   /* Set time initially, c128 doesn't know it */
299   set_time_interactive();
300
301   /* disable interrupt driven VIC screen editor */
302   POKE(0xD8, 255);
303
304   /* Load configuration */
305   load_config();
306
307   /* Load items (= drinks) */
308   load_items();
309   /* Load credits */
310   load_credits();
311
312   time = get_time();
313   sprintf(print_buffer, "%c----------------------------------------------------"
314                         "----------------------------\r",
315           17);
316   print_the_buffer();
317   sprintf(print_buffer, "%cC128-Kasse Version " GV "\r", 17);
318   print_the_buffer();
319
320   sprintf(print_buffer,
321           "%cKasse gestartet um %s. Nutze logfile log-%u, offset %d.\r", 17,
322           time, log_num, log_heap_offset);
323   print_the_buffer();
324
325   print_header();
326
327   while (1) {
328     print_screen();
329     c = get_input();
330     /* ...display dialogs eventually */
331     if (*c >= PETSCII_0 && *c <= PETSCII_9) {
332       /* if the input starts with a digit, we will interpret it as a number
333        * for the item to be sold */
334       buy_stock(atoi(c));
335     } else if (*c == 'f') {
336       buy_custom();
337     } else if (*c == 's') {
338       cprintf("\r\nsaving items.. ");
339       save_items();
340       cprintf("ok\r\nsaving credits.. ");
341       save_credits();
342       cprintf("ok\r\nflushing log.. ");
343       log_flush();
344       cprintf("ok\r\nStatefile/Creditfile/Log gesichert, dr" uUML
345               "cke RETURN...\r\n");
346       cget_return();
347     } else if (*c == 'g') {
348       credit_manager();
349     } else if (*c == 'z') {
350       set_time_interactive();
351     } else if (*c == 'q')
352       break;
353   }
354   clrscr();
355   cprintf("\r\nBYEBYE\r\n");
356
357   return 0;
358 }