~ubuntu-branches/ubuntu/vivid/imaze/vivid

« back to all changes in this revision

Viewing changes to source/client.c

  • Committer: Bazaar Package Importer
  • Author(s): Hans Freitag
  • Date: 2002-11-28 13:24:12 UTC
  • Revision ID: james.westby@ubuntu.com-20021128132412-lw82xl9oq1j36g8b
Tags: upstream-1.4
ImportĀ upstreamĀ versionĀ 1.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
** - - -  iMaze  - - -
 
3
**
 
4
** Copyright (c) 1993-2001 by Hans-Ulrich Kiel & Joerg Czeranski
 
5
** All rights reserved.
 
6
**
 
7
** Redistribution and use in source and binary forms, with or without
 
8
** modification, are permitted provided that the following conditions are
 
9
** met:
 
10
**
 
11
** 1. Redistributions of source code must retain the above copyright
 
12
**    notice, this list of conditions and the following disclaimer.
 
13
** 2. Redistributions in binary form must reproduce the above copyright
 
14
**    notice, this list of conditions and the following disclaimer in the
 
15
**    documentation and/or other materials provided with the distribution.
 
16
** 3. The name of the authors may not be used to endorse or promote
 
17
**    products derived from this software without specific prior written
 
18
**    permission.
 
19
** 4. The name ``iMaze'' may not be used for products derived from this
 
20
**    software unless a prefix or a suffix is added to the name.
 
21
**
 
22
** THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
 
23
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 
24
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 
25
** DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT,
 
26
** INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 
27
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 
28
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
29
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 
30
** STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 
31
** IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
32
** POSSIBILITY OF SUCH DAMAGE.
 
33
**
 
34
**
 
35
** Datei: client.c
 
36
**
 
37
** Kommentar:
 
38
**  Das Hauptprogramm
 
39
**  und die Routinen, die Netzwerk, 3D-Berechnung und Grafik verbinden
 
40
*/
 
41
 
 
42
 
 
43
#include <stdio.h>
 
44
#include <stdlib.h>
 
45
#include <string.h>
 
46
#include <signal.h>
 
47
 
 
48
#include "argv.h"
 
49
#include "global.h"
 
50
#include "fehler.h"
 
51
#include "speicher.h"
 
52
#include "labyrinth.h"
 
53
#include "client.h"
 
54
#include "spieler.h"
 
55
#include "grafik.h"
 
56
#include "signale.h"
 
57
#include "ereignisse.h"
 
58
#include "einaus.h"
 
59
#include "rechne.h"
 
60
#include "netzwerk.h"
 
61
#include "spiel.h"
 
62
 
 
63
static char sccsid[] = "@(#)client.c    3.20 12/3/01";
 
64
 
 
65
 
 
66
struct arg_option argv_opts[] =
 
67
{
 
68
        { Arg_Include, NULL, net_opts },
 
69
        { Arg_Include, NULL, einaus_opts },
 
70
        { Arg_End }
 
71
};
 
72
 
 
73
 
 
74
/* Breite und Laenge des aktuellen Spielfeldes: */
 
75
u_int feldbreite, feldlaenge;
 
76
block **spielfeld;        /* das Spielfeld */
 
77
block **feld_himricht[4]; /* das Spielfeld, in 4 Richtungen gedreht */
 
78
 
 
79
static int puffer_nr = 0;      /* Index auf Spieldaten-Puffer
 
80
                                  (welcher zuletzt gelesen wurde) */
 
81
static int puffer_gueltig = 0; /* Index auf Spieldaten-Puffer
 
82
                                  (welcher zuletzt beschrieben wurde) */
 
83
 
 
84
/* die Spieldaten werden in einem Doppelpuffer gespeichert;
 
85
   einer kann gelesen, der andere beschrieben werden */
 
86
 
 
87
static int spieler_aktiv[2]; /* der Spieler selbst ist im Spiel */
 
88
static int schuss_aktiv[2];  /* der Spieler selbst hat einen Schuss im
 
89
                                Spiel */
 
90
static int gegneranz[2];     /* Anzahl der aktuell sichtbaren Mitspieler */
 
91
static int schussanz[2];     /* Anzahl der sichtbaren Mitspieler-Schuesse */
 
92
static int abgeschossen_durch[2]; /* Farbe des Spielers, von dem man
 
93
                                     abgeschossen wurde */
 
94
static char *abschuss_spruch[2] = { NULL, NULL }; /* Spruch des Spielers, von
 
95
                                                     dem man abgeschossen
 
96
                                                     wurde */
 
97
 
 
98
/* Daten aller sichtbaren Spieler und Schuesse (Position, Farbe, ...): */
 
99
static struct spieler alle_spieler[2][SPIELERANZ];
 
100
static struct schuss alle_schuesse[2][SPIELERANZ];
 
101
 
 
102
static int alle_punkte[2][SPIELERANZ];  /* Punktestand aller Spieler; -1 fuer
 
103
                                           Spieler, die nicht existieren */
 
104
static char ereignisse[2][ERG_ANZ];     /* Ereignisse
 
105
                                           (siehe ereignisse.h) */
 
106
static char ereignisse_uebrig[ERG_ANZ]; /* noch nicht verarbeitete
 
107
                                           Ereignisse (temporaer) */
 
108
 
 
109
static int karteneu = 1; /* Flag, muss der Grundriss der Karte neu
 
110
                            gezeichnet werden?  Dann alles andere auch. */
 
111
static int spieler_farbe = 0; /* letzte bekannte Farbe des eigenen Spielers,
 
112
                                 sonst 0 */
 
113
 
 
114
/* Fehlermeldung und -knopf von milder_fehler (fuer milden_fehler_abfragen) */
 
115
static char **fehlermeldung = NULL, *fehlerknopf = NULL;
 
116
 
 
117
/* fuer das Verhindern ueberfluessigen Zeichnens */
 
118
static int alt_gueltig = 0;
 
119
static struct objektdaten alt_blick_vor, alt_blick_zurueck;
 
120
static int alt_spieler_index, alt_anzkreise;
 
121
static struct kartenkreis *alt_kreise;
 
122
static int alt_kompass;
 
123
static struct punktedaten alt_punkte;
 
124
 
 
125
 
 
126
/*
 
127
** drehlab
 
128
**  dreht das Spielfeld in 4 Richtungen (0, 90, 180, 270 Grad)
 
129
**  (damit die Projektionen nur fuer Richtung Norden implementiert werden
 
130
**  muessen)
 
131
**
 
132
** Seiteneffekte:
 
133
**  feld_himricht wird erzeugt
 
134
*/
 
135
static void drehlab(void)
 
136
{
 
137
        int i;    /* Index ueber die 4 Richtungen */
 
138
        int x, y; /* Index ueber Breite/Laenge des Spielfeldes */
 
139
 
 
140
        /* Speicher fuer 4 Spielfelder anlegen */
 
141
        /* bei ungeradem i Breite und Laenge tauschen */
 
142
        for (i = 1; i < 4; i++)
 
143
                speicher_belegen((void **)&feld_himricht[i],
 
144
                        (i % 2 ? feldlaenge : feldbreite) * sizeof(block *));
 
145
 
 
146
        for (i = 1; i < 4; i++)
 
147
                for (y = 0; y < (i % 2 ? feldlaenge : feldbreite); y++)
 
148
                        speicher_belegen((void **)&feld_himricht[i][y],
 
149
                                (i % 2 ? feldbreite : feldlaenge) * sizeof(block));
 
150
 
 
151
        /* feld_himricht[0] wird nicht gedreht */
 
152
        feld_himricht[0] = spielfeld;
 
153
 
 
154
        /* feld_himricht[0] gedreht in feld_himricht[1,2,3] kopieren */
 
155
        for (y = 0; y < feldlaenge; y++)
 
156
                for (x = 0; x < feldbreite; x++)
 
157
                        /* NORD = 0, WEST = 1, SUED = 2, OST = 3 */
 
158
                        for (i = 0; i < 4; i++)
 
159
                        {
 
160
                                memcpy(&feld_himricht[1][feldlaenge - 1 - y]
 
161
                                        [x][(i + 3) % 4],
 
162
                                        &spielfeld[x][y][i], sizeof(struct wand));
 
163
                                memcpy(&feld_himricht[2][feldbreite - 1 - x]
 
164
                                        [feldlaenge - 1 - y][(i + 2) % 4],
 
165
                                        &spielfeld[x][y][i], sizeof(struct wand));
 
166
                                memcpy(&feld_himricht[3][y]
 
167
                                        [feldbreite - 1 - x][(i + 1) % 4],
 
168
                                        &spielfeld[x][y][i], sizeof(struct wand));
 
169
                        }
 
170
}
 
171
 
 
172
 
 
173
/*
 
174
** objekt_listen_init
 
175
**  Listen anlegen fuer die Grafikobjekte, die rechne3d berechnet
 
176
**
 
177
** Parameter:
 
178
**  objekte: Zeiger auf die Struktur, die die Listen enthaelt
 
179
**
 
180
** Seiteneffekte:
 
181
**  *objekte wird veraendert
 
182
*/
 
183
static void objekt_listen_init(struct objektdaten *objekte)
 
184
{
 
185
        /* Waende- und Kugelliste anlegen */
 
186
        liste_initialisieren(&objekte->anzwaende, (void **)&objekte->waende);
 
187
        liste_initialisieren(&objekte->anzkugeln, (void **)&objekte->kugeln);
 
188
 
 
189
        /* Spruch des Gegners loeschen */
 
190
        objekte->text = NULL;
 
191
}
 
192
 
 
193
 
 
194
/*
 
195
** objekt_listen_freigeben
 
196
**  gibt die Listen mit zu zeichnenden Grafikobjekten wieder frei
 
197
**
 
198
** Parameter:
 
199
**  objekte: Zeiger auf die Struktur, die die Listen enthaelt
 
200
*/
 
201
static void objekt_listen_freigeben(struct objektdaten *objekte)
 
202
{
 
203
        int i; /* Index fuer die Kugelliste */
 
204
 
 
205
        liste_freigeben(&objekte->anzwaende, (void **)&objekte->waende);
 
206
 
 
207
        /* Unterliste (Sichbarkeitsbereiche der Kugeln) freigeben */
 
208
        for (i = 0; i < objekte->anzkugeln; i++)
 
209
                liste_freigeben(&objekte->kugeln[i].sichtanz,
 
210
                        (void **)&objekte->kugeln[i].sichtbar);
 
211
        liste_freigeben(&objekte->anzkugeln, (void **)&objekte->kugeln);
 
212
 
 
213
        /* Speicher fuer Spruch des Gegners freigeben */
 
214
        if (objekte->text != NULL)
 
215
                speicher_freigeben((void **)&objekte->text);
 
216
}
 
217
 
 
218
 
 
219
/*
 
220
** punkte_vergleich
 
221
**  vergleicht zwei Punktestaende und gibt zurueck, in welcher Reihenfolge
 
222
**  sie angezeigt werden sollen
 
223
**
 
224
** Parameter:
 
225
**  p1: Zeiger auf einen Punktestand
 
226
**  p2: Zeiger auf anderen Punktestand
 
227
**
 
228
** Rueckgabewert:
 
229
**  < 0, falls Punktestand 1 vor Punktestand 2
 
230
**  = 0, falls egal
 
231
**  > 0, falls Punktestand 2 vor Punktestand 1
 
232
*/
 
233
static int punkte_vergleich(const void *p1, const void *p2)
 
234
{
 
235
        const struct punktestand *punkte1 = p1;
 
236
        const struct punktestand *punkte2 = p2;
 
237
 
 
238
        /* verschieden viele Punkte? */
 
239
        if (punkte1->punkte != punkte2->punkte)
 
240
                return punkte2->punkte - punkte1->punkte;
 
241
 
 
242
        /* sonst nach Farbe sortieren */
 
243
        return (int)punkte1->farbe - (int)punkte2->farbe;
 
244
}
 
245
 
 
246
 
 
247
static int flaechen_gleich(int n, struct flaeche *f1, struct flaeche *f2)
 
248
{
 
249
        int i, j;
 
250
 
 
251
        for (i = 0; i < n; i++)
 
252
        {
 
253
                for (j = 0; j < 4; j++)
 
254
                        if (f1->ecke[j].x != f2->ecke[j].x ||
 
255
                                f1->ecke[j].y != f2->ecke[j].y)
 
256
                                return 0;
 
257
 
 
258
                if (f1->farbe != f2->farbe || f1->tuer != f2->tuer)
 
259
                        return 0;
 
260
 
 
261
                f1++;
 
262
                f2++;
 
263
        }
 
264
 
 
265
        return 1;
 
266
}
 
267
 
 
268
 
 
269
static int kugeln_gleich(int n, struct kugel *k1, struct kugel *k2)
 
270
{
 
271
        int i, j;
 
272
 
 
273
        for (i = 0; i < n; i++)
 
274
        {
 
275
                struct ausschnitt *a1, *a2;
 
276
 
 
277
                if (k1->mittelpunkt.x != k2->mittelpunkt.x ||
 
278
                        k1->mittelpunkt.y != k2->mittelpunkt.y)
 
279
                        return 0;
 
280
 
 
281
                if (k1->sichtanz != k2->sichtanz ||
 
282
                        k1->radiusx != k2->radiusx ||
 
283
                        k1->radiusy != k2->radiusy ||
 
284
                        k1->schatteny != k2->schatteny ||
 
285
                        k1->schattenry != k2->schattenry ||
 
286
                        k1->blick != k2->blick || k1->farbe != k2->farbe)
 
287
                        return 0;
 
288
 
 
289
                a1 = k1->sichtbar;
 
290
                a2 = k2->sichtbar;
 
291
                for (j = 0; j < k1->sichtanz; j++)
 
292
                {
 
293
                        if (a1->x != a2->x || a1->breite != a2->breite)
 
294
                                return 0;
 
295
 
 
296
                        a1++;
 
297
                        a2++;
 
298
                }
 
299
 
 
300
                k1++;
 
301
                k2++;
 
302
        }
 
303
 
 
304
        return 1;
 
305
}
 
306
 
 
307
 
 
308
static int objektdaten_gleich(struct objektdaten *o1, struct objektdaten *o2)
 
309
{
 
310
        return o1->hintergrund_zeichnen == o2->hintergrund_zeichnen &&
 
311
                o1->anzwaende== o2->anzwaende &&
 
312
                o1->anzkugeln == o2->anzkugeln &&
 
313
                (o1->text == NULL && o2->text == NULL ||
 
314
                        o1->text != NULL && o2->text != NULL &&
 
315
                        !strcmp(o1->text, o2->text)) &&
 
316
                flaechen_gleich(o1->anzwaende, o1->waende, o2->waende) &&
 
317
                kugeln_gleich(o1->anzkugeln, o1->kugeln, o2->kugeln);
 
318
}
 
319
 
 
320
 
 
321
static int kartenkreise_gleich(int n, struct kartenkreis *k1,
 
322
        struct kartenkreis *k2)
 
323
{
 
324
        int i;
 
325
 
 
326
        for (i = 0; i < n; i++)
 
327
        {
 
328
                if (k1->mittelpunkt.x != k2->mittelpunkt.x ||
 
329
                        k1->mittelpunkt.y != k2->mittelpunkt.y ||
 
330
                        k1->radiusx != k2->radiusx ||
 
331
                        k1->radiusy != k2->radiusy ||
 
332
                        k1->farbe != k2->farbe)
 
333
                        return 0;
 
334
 
 
335
                k1++;
 
336
                k2++;
 
337
        }
 
338
 
 
339
        return 1;
 
340
}
 
341
 
 
342
 
 
343
static int punkte_gleich(struct punktedaten *p1, struct punktedaten *p2)
 
344
{
 
345
        return p1->anzpunkte == p2->anzpunkte &&
 
346
                (p1->anzpunkte == 0 || !memcmp(p1->punkte, p2->punkte,
 
347
                        p1->anzpunkte * sizeof *p1->punkte));
 
348
}
 
349
 
 
350
 
 
351
/*
 
352
** neuaufbau
 
353
**  erhaelt die neuen Spieldaten und startet die Grafikberechnung
 
354
**  und -ausgabe
 
355
**
 
356
** Parameter:
 
357
**  spieler_aktiv: Flag, ist der Spieler selbst im Spiel
 
358
**  gegneranz: Anzahl der aktuell sichtbaren Mitspieler
 
359
**  alle_spieler: Feld mit den Daten ueber alle sichtbaren Spieler
 
360
**  schuss_aktiv: Flag, hat der Spieler selbst einen Schuss im Spiel
 
361
**  schussanz: Anzahl der sichtbaren Schuesse der Mitspieler
 
362
**  alle_schuesse: Feld mit den Daten ueber alle sichtbaren Schuesse
 
363
**  abgeschossen_durch: Farbe des Spieler, von dem man abgeschossen wurde
 
364
**  abschuss_spruch: Spruch des Spieler, von dem man abgeschossen wurde
 
365
**  ereignisse: Feld mit den neuen Ereignissen
 
366
**  alle_punkte: Feld mit den Punktestaenden aller Spieler
 
367
**
 
368
** Seiteneffekte:
 
369
**  karteneu wird veraendert
 
370
*/
 
371
static void neuaufbau(int spieler_aktiv, int gegneranz,
 
372
        struct spieler alle_spieler[SPIELERANZ], int schuss_aktiv,
 
373
        int schussanz, struct schuss alle_schuesse[SPIELERANZ],
 
374
        int abgeschossen_durch, char *abschuss_spruch,
 
375
        char ereignisse[ERG_ANZ], int alle_punkte[SPIELERANZ])
 
376
{
 
377
        /* Struktur mit allen Grafik-Daten fuer die 3D-Sicht nach vorn und
 
378
           Rueckspiegel */
 
379
        struct objektdaten blick_vor, blick_zurueck;
 
380
        int anzlinien;                /* Anzahl der Linien auf der Karte */
 
381
        int anzkreise;                /* Anzahl der Kreise auf der karte */
 
382
        struct kartenkreis *kreise;   /* Liste mit den Grafik-Daten der Linien
 
383
                                         auf der Karte */
 
384
        struct kartenlinie *linien;   /* Liste mit den Grafik-Daten der Kreise
 
385
                                         auf der Karte */
 
386
        struct spieler spieler_rueck; /* Daten des Spielers um 180 gedreht */
 
387
        struct punktedaten punkte;    /* Struktur mit den Daten der
 
388
                                         Punktestaende */
 
389
 
 
390
        /* Listen anlegen, in den die Grafik-Daten abgelegt werden */
 
391
        objekt_listen_init(&blick_vor);
 
392
        objekt_listen_init(&blick_zurueck);
 
393
        liste_initialisieren(&anzkreise, (void **)&kreise);
 
394
 
 
395
        /* falls Karten-Grundriss gezeichnet werden muss, Grafik-Daten dafuer
 
396
           berechnen */
 
397
        if (karteneu)
 
398
        {
 
399
                liste_initialisieren(&anzlinien, (void **)&linien);
 
400
 
 
401
                rechne_karte_linien(&anzlinien, &linien);
 
402
        }
 
403
 
 
404
        /* falls der Spieler lebt, muss der Horizont gezeichnet werden */
 
405
        blick_vor.hintergrund_zeichnen = blick_zurueck.hintergrund_zeichnen =
 
406
                spieler_aktiv;
 
407
 
 
408
        /* spieler_rueck entspricht dem Spieler mit Blick um 180 Grad gedreht */
 
409
        memcpy(&spieler_rueck, &alle_spieler[0], sizeof(struct spieler));
 
410
        spieler_rueck.blick = (spieler_rueck.blick + WINKANZ / 2) % WINKANZ;
 
411
 
 
412
        /* falls der Spieler lebt, werden die 3D-Berechungen fuer Front- und
 
413
           Rueckansicht aufgerufen */
 
414
        if (spieler_aktiv)
 
415
        {
 
416
                /* Spielerfarbe merken */
 
417
                spieler_farbe = alle_spieler[0].farbe;
 
418
 
 
419
                rechne3d(&blick_vor, &alle_spieler[0], gegneranz,
 
420
                        &alle_spieler[1], schussanz + schuss_aktiv,
 
421
                        &alle_schuesse[1 - schuss_aktiv]);
 
422
                rechne3d(&blick_zurueck, &spieler_rueck, gegneranz,
 
423
                        &alle_spieler[1], schussanz + schuss_aktiv,
 
424
                        &alle_schuesse[1 - schuss_aktiv]);
 
425
        }
 
426
        else if (abgeschossen_durch >= 0)
 
427
        /* falls der Spieler nach einem Abschuss tot ist, wird das Gesicht des
 
428
           Verursachers angezeigt */
 
429
        {
 
430
                struct kugel *kugel;           /* Daten des Gegnergesichts */
 
431
                struct ausschnitt *ausschnitt; /* Sichtbarkeitsbereich
 
432
                                                  des Gesichts */
 
433
 
 
434
                /* Listen mit Grafik-Daten erweitern */
 
435
                liste_verlaengern(&blick_vor.anzkugeln, (void **)&blick_vor.kugeln,
 
436
                        sizeof(struct kugel));
 
437
                kugel = &blick_vor.kugeln[blick_vor.anzkugeln - 1];
 
438
 
 
439
                /* Grafik-Daten eines Gegnergesichts im Vollbild */
 
440
                kugel->mittelpunkt.x = FENSTER_BREITE / 2;
 
441
                kugel->mittelpunkt.y = FENSTER_HOEHE / 2;
 
442
                kugel->radiusx = FENSTER_BREITE / 4;
 
443
                kugel->radiusy = kugel->radiusx * 3 / 2;
 
444
                kugel->schatteny = kugel->schattenry = 0;
 
445
                kugel->blick = TRIGANZ / 2;
 
446
                kugel->farbe = abgeschossen_durch;
 
447
 
 
448
                /* Liste mit Sichtbarkeitsbereich (Gegner ist voll sichtbar) */
 
449
                liste_initialisieren(&kugel->sichtanz, (void **)&kugel->sichtbar);
 
450
                liste_verlaengern(&kugel->sichtanz, (void **)&kugel->sichtbar,
 
451
                        sizeof(struct ausschnitt));
 
452
                ausschnitt = &kugel->sichtbar[kugel->sichtanz - 1];
 
453
 
 
454
                ausschnitt->x = 0;
 
455
                ausschnitt->breite = FENSTER_BREITE;
 
456
 
 
457
                /* Abschussspruch des Gegners bekannt? */
 
458
                if (abschuss_spruch != NULL)
 
459
                {
 
460
                        /* dann Speicher belegen und kopieren */
 
461
                        speicher_belegen((void **)&blick_vor.text,
 
462
                                strlen(abschuss_spruch) + 1);
 
463
                        strcpy(blick_vor.text, abschuss_spruch);
 
464
                }
 
465
        }
 
466
 
 
467
        /* falls Spieler an Leben, Karte mit ihm berechnen */
 
468
        if (spieler_aktiv)
 
469
                rechne_karte_kreise(&anzkreise, &kreise,
 
470
                        gegneranz + 1, alle_spieler);
 
471
        else
 
472
        /* sonst nur die Mitspieler */
 
473
                rechne_karte_kreise(&anzkreise, &kreise,
 
474
                        gegneranz, &alle_spieler[1]);
 
475
 
 
476
        {
 
477
                int i; /* Index fuer Spieler */
 
478
 
 
479
                /* Punktestaende in Liste kopieren */
 
480
                liste_initialisieren(&punkte.anzpunkte, (void **)&punkte.punkte);
 
481
                for (i = 0; i < SPIELERANZ; i++)
 
482
                        if (alle_punkte[i] >= 0)
 
483
                        {
 
484
                                struct punktestand *stand; /* temporaerer Zeiger in Liste */
 
485
 
 
486
                                /* Punktestand und Farbe des Spielers an Liste haengen */
 
487
                                liste_verlaengern(&punkte.anzpunkte, (void **)&punkte.punkte,
 
488
                                        sizeof(struct punktestand));
 
489
                                stand = &punkte.punkte[punkte.anzpunkte - 1];
 
490
 
 
491
                                /* initialisieren, fuer den Vergleich */
 
492
                                memset(stand, 0, sizeof *stand);
 
493
 
 
494
                                stand->punkte = alle_punkte[i]; /* Punkte */
 
495
                                stand->farbe = i + 1; /* Farbe */
 
496
                                stand->hervorheben =
 
497
                                        spieler_farbe == i + 1; /* ich? */
 
498
                        }
 
499
                        else if (spieler_farbe == i + 1)
 
500
                        /* ich, ohne Punktestand */
 
501
                        {
 
502
                                struct punktestand *stand; /* temporaerer Zeiger in Liste */
 
503
 
 
504
                                /* Punktestand und Farbe des Spielers an Liste haengen */
 
505
                                liste_verlaengern(&punkte.anzpunkte, (void **)&punkte.punkte,
 
506
                                        sizeof(struct punktestand));
 
507
                                stand = &punkte.punkte[punkte.anzpunkte - 1];
 
508
 
 
509
                                /* initialisieren, fuer den Vergleich */
 
510
                                memset(stand, 0, sizeof *stand);
 
511
 
 
512
                                stand->punkte = -1; /* Punkte */
 
513
                                stand->farbe = i + 1; /* Farbe */
 
514
                                stand->hervorheben = 1; /* ja, ich */
 
515
                        }
 
516
 
 
517
                /* Punkte sortieren */
 
518
                if (punkte.anzpunkte)
 
519
                        qsort(punkte.punkte, punkte.anzpunkte,
 
520
                                sizeof(struct punktestand), punkte_vergleich);
 
521
        }
 
522
 
 
523
        /* Zeichenvorgang synchronisieren */
 
524
        zeichne_sync_anfang();
 
525
 
 
526
        /* Karten-Grundriss, falls notwendig, neuzeichnen */
 
527
        if (karteneu)
 
528
                zeichne_grundriss(anzlinien, linien);
 
529
 
 
530
        /* 3D-Frontansicht zeichnen */
 
531
        if (!alt_gueltig || karteneu ||
 
532
                !objektdaten_gleich(&blick_vor, &alt_blick_vor))
 
533
                zeichne_blickfeld(&blick_vor);
 
534
        if (alt_gueltig)
 
535
                objekt_listen_freigeben(&alt_blick_vor);
 
536
        memcpy(&alt_blick_vor, &blick_vor, sizeof alt_blick_vor);
 
537
 
 
538
        /* Rueckspiegel zeichnen */
 
539
        if (!alt_gueltig || karteneu ||
 
540
                !objektdaten_gleich(&blick_zurueck, &alt_blick_zurueck))
 
541
                zeichne_rueckspiegel(&blick_zurueck);
 
542
        if (alt_gueltig)
 
543
                objekt_listen_freigeben(&alt_blick_zurueck);
 
544
        memcpy(&alt_blick_zurueck, &blick_zurueck, sizeof alt_blick_zurueck);
 
545
 
 
546
        /* Kreise auf der Karte zeichnen; falls Spieler tot, ihn selbst nicht */
 
547
        {
 
548
                int spieler_index;
 
549
 
 
550
                spieler_index = spieler_aktiv ? 0 : -1;
 
551
                if (!alt_gueltig || spieler_index != alt_spieler_index ||
 
552
                        anzkreise != alt_anzkreise ||
 
553
                        !kartenkreise_gleich(anzkreise, kreise, alt_kreise))
 
554
                        zeichne_karte(spieler_index, anzkreise, kreise);
 
555
                if (alt_gueltig)
 
556
                        liste_freigeben(&alt_anzkreise, (void **)&alt_kreise);
 
557
                alt_spieler_index = spieler_index;
 
558
                alt_anzkreise = anzkreise;
 
559
                alt_kreise = kreise;
 
560
        }
 
561
 
 
562
        /* Kompass zeichnen */
 
563
        {
 
564
                int kompass;
 
565
 
 
566
                /* falls Spieler tot, Kompass ohne Nadel zeichnen */
 
567
                if (spieler_aktiv)
 
568
                        kompass = alle_spieler[0].blick * (TRIGANZ / WINKANZ);
 
569
                else
 
570
                        kompass = -1;
 
571
 
 
572
                if (!alt_gueltig || karteneu || kompass != alt_kompass)
 
573
                        zeichne_kompass(kompass);
 
574
 
 
575
                alt_kompass = kompass;
 
576
        }
 
577
 
 
578
        /* Punktestand zeichnen */
 
579
        if (!alt_gueltig || karteneu || !punkte_gleich(&punkte, &alt_punkte))
 
580
                zeichne_punkte(&punkte);
 
581
        if (alt_gueltig)
 
582
                liste_freigeben(&alt_punkte.anzpunkte,
 
583
                        (void **)&alt_punkte.punkte);
 
584
        memcpy(&alt_punkte, &punkte, sizeof alt_punkte);
 
585
 
 
586
        /* audio-visuelle Darstellung der Ereignisse */
 
587
        ereignisse_darstellen(ereignisse);
 
588
 
 
589
        /* Zeichenvorgang synchronisieren */
 
590
        zeichne_sync_ende();
 
591
 
 
592
        if (karteneu)
 
593
        {
 
594
                liste_freigeben(&anzlinien, (void **)&linien);
 
595
 
 
596
                /* falls Karten-Grundriss neu gezeichnet wurde, muss dies naechstes
 
597
                   Mal vorerst nicht wiederholt werden */
 
598
                karteneu = 0;
 
599
        }
 
600
 
 
601
        alt_gueltig = 1;
 
602
}
 
603
 
 
604
 
 
605
/*
 
606
** client_ende
 
607
**  beendet das Programm ohne Rueckfrage
 
608
*/
 
609
static void client_ende(void)
 
610
{
 
611
        /* lokale Datenstrukturen aufraeumen */
 
612
        grafik_ende();
 
613
 
 
614
        /* alle Netzverbindungen beenden */
 
615
        netzwerk_ende();
 
616
 
 
617
        exit(0);
 
618
}
 
619
 
 
620
 
 
621
/* bis hier lokaler Teil                       */
 
622
/***********************************************/
 
623
/* ab hier globaler Teil                       */
 
624
 
 
625
 
 
626
/*
 
627
** spiel_puffer_anlegen
 
628
**  ermittelt die Zeiger auf die aktuellen Puffer, in die die neuen
 
629
**  Spieldaten abgelegt werden sollen
 
630
**
 
631
** Parameter:
 
632
**  spieler_aktiv_var: Zeiger auf Zeiger auf Flag,
 
633
**                     ist der Spieler selbst im Spiel?
 
634
**  spieler_var: Zeiger auf Zeiger auf Daten des Spielers selbst
 
635
**  gegneranz_var: Zeiger auf Zeiger auf Anzahl der aktuell
 
636
**                 sichtbaren Mitspieler
 
637
**  gegner_feld: Zeiger auf Liste mit den Daten der sichtbaren Mitspieler
 
638
**  schuss_aktiv_var: Zeiger auf Zeiger auf Flag, hat der Spieler
 
639
**                    selbst einen Schuss im Spiel?
 
640
**  schuss_var: Zeiger auf Zeiger auf Daten des eigenen Schusses
 
641
**  schussanz_var: Zeiger auf Zeiger auf Anzahl der sichtbaren
 
642
**                 Schuesse der Mitspieler
 
643
**  schuesse_feld: Zeiger auf Liste mit den Daten der sichtbaren
 
644
**                 Schuesse der Mitspieler
 
645
**  abgechossen_durch_var: Zeiger auf Zeiger auf Farbe des Spieler,
 
646
**                         von dem man abgeschossen wurde
 
647
**  abschluss_spruch_var: Zeiger auf Zeiger auf Spruch des Spieler,
 
648
**                        von dem man abgeschossen wurde
 
649
**  ereignisse_feld: Zeiger auf Liste mit den neuen Ereignissen
 
650
**  punkte_feld: Zeiger auf Liste mit den Punktestaenden
 
651
**
 
652
** Seiteneffekte:
 
653
**  ereignisse_uebrig wird gesetzt
 
654
*/
 
655
void spiel_puffer_anlegen(int **spieler_aktiv_var,
 
656
        struct spieler **spieler_var, int **gegneranz_var,
 
657
        struct spieler **gegner_feld, int **schuss_aktiv_var,
 
658
        struct schuss **schuss_var, int **schussanz_var,
 
659
        struct schuss **schuesse_feld, int **abgeschossen_durch_var,
 
660
        char ***abschuss_spruch_var, char **ereignisse_feld, int **punkte_feld)
 
661
{
 
662
        /* Speicher fuer alten Spruch freigeben */
 
663
        if (abschuss_spruch[1 - puffer_nr] != NULL)
 
664
                speicher_freigeben((void **)&abschuss_spruch[1 - puffer_nr]);
 
665
 
 
666
        /* Zeiger auf die Puffer ermitteln; jeweils der andere als puffer_nr */
 
667
        *spieler_aktiv_var = &spieler_aktiv[1 - puffer_nr];
 
668
        *spieler_var = alle_spieler[1 - puffer_nr];
 
669
        *gegneranz_var = &gegneranz[1 - puffer_nr];
 
670
        *gegner_feld = &alle_spieler[1 - puffer_nr][1];
 
671
 
 
672
        *schuss_aktiv_var = &schuss_aktiv[1 - puffer_nr];
 
673
        *schuss_var = alle_schuesse[1 - puffer_nr];
 
674
        *schussanz_var = &schussanz[1 - puffer_nr];
 
675
        *schuesse_feld = &alle_schuesse[1 - puffer_nr][1];
 
676
 
 
677
        *abgeschossen_durch_var = &abgeschossen_durch[1 - puffer_nr];
 
678
 
 
679
        *abschuss_spruch_var = &abschuss_spruch[1 - puffer_nr];
 
680
 
 
681
        *ereignisse_feld = ereignisse[1 - puffer_nr];
 
682
 
 
683
        *punkte_feld = alle_punkte[1 - puffer_nr];
 
684
 
 
685
        /* falls die vorigen Pufferinhalte noch nicht abgearbeitet wurden,
 
686
           alle Ereignisse retten */
 
687
        if (puffer_gueltig != puffer_nr)
 
688
        {
 
689
                int i;
 
690
 
 
691
                for (i = 0; i < ERG_ANZ; i++)
 
692
                        ereignisse_uebrig[i] = (*ereignisse)[i];
 
693
        }
 
694
}
 
695
 
 
696
 
 
697
/*
 
698
** netzwerk_spielende
 
699
**  wird aufgerufen, wenn der Server den Client aus dem Spiel genommen hat;
 
700
**  es wird auf der Stelle eine Meldung ausgegben und das Programm beendet
 
701
*/
 
702
void netzwerk_spielende(void)
 
703
{
 
704
        static char *meldung[] = { "iMaze - Fatal Error", "",
 
705
                "Disconnected by server.", NULL };
 
706
 
 
707
        uebler_fehler(meldung, NULL);
 
708
}
 
709
 
 
710
 
 
711
/*
 
712
** signale_abfragen
 
713
**  wird aufgerufen, wenn die neuen Daten in die Puffer uebertragen wurden.
 
714
**  Liest die Eingabe-Signale aus
 
715
**
 
716
** Parameter:
 
717
**  signale: Feld mit allen Signalen
 
718
**
 
719
** Seiteneffekte:
 
720
**  puffer_gueltig wird gesetzt
 
721
*/
 
722
void signale_abfragen(char signale[SIGNALANZ])
 
723
{
 
724
        /* falls der vorige Pufferinhalt noch nicht abgearbeitet wurde,
 
725
           werden die unbearbeiteten Ereignisse wieder uebernommen */
 
726
        if (puffer_gueltig != puffer_nr)
 
727
        {
 
728
                int i;
 
729
 
 
730
                for (i = 0; i < ERG_ANZ; i++)
 
731
                        (*ereignisse)[i] |= ereignisse_uebrig[i];
 
732
        }
 
733
 
 
734
        /* der andere Puffer hat jetzt die aktuelle Daten */
 
735
        puffer_gueltig = 1 - puffer_nr;
 
736
 
 
737
        /* Abfrage der Eingabe-Signale */
 
738
        eingabe_abfragen(signale);
 
739
}
 
740
 
 
741
 
 
742
/*
 
743
** bewegung_deskriptor
 
744
**  liefert einen Deskriptor fuer die Verbindung zum Server im Spiel-Modus
 
745
**
 
746
** Rueckgabewert:
 
747
**  ein Zeiger auf den Deskriptor, NULL, falls es noch keine gibt
 
748
*/
 
749
void *bewegung_deskriptor(void)
 
750
{
 
751
        /* nur den Deskriptor vom Netzwerkteil abfragen und weiterreichen */
 
752
        return spiel_deskriptor();
 
753
}
 
754
 
 
755
 
 
756
/*
 
757
** bewegung
 
758
**  wartet auf Daten vom Server und initiiert evtl. die Neuberechnung und
 
759
**  -zeichnung aller Grafikausgaben
 
760
**
 
761
** Parameter:
 
762
**  ms: Zeit in Millisekunden, die maximal gewartet werden darf;
 
763
**      oder -1 fuer unbegrenztes Warten
 
764
**  zeichnen: Flag, ob die Grafik neu berechnet und gezeichnet werden soll
 
765
**
 
766
** Rueckgabewert:
 
767
**  1 fuer Fehler, sonst 0
 
768
**
 
769
** Seiteneffekt:
 
770
**  puffer_nr wird veraendert
 
771
*/
 
772
int bewegung(int ms, int zeichnen)
 
773
{
 
774
        {
 
775
                static int rekursion = 0; /* Flag, ob spiel_paket_erwarten laeuft */
 
776
 
 
777
                /* Rekursion von spiel_paket_erwarten verhindern */
 
778
                if (rekursion)
 
779
                        /* kein Fehler */
 
780
                        return 0;
 
781
 
 
782
                rekursion = 1;
 
783
 
 
784
                /* Daten vom Server erwarten */
 
785
                if (spiel_paket_erwarten(ms))
 
786
                {
 
787
                        rekursion = 0;
 
788
 
 
789
                        /* Fehler aufgetreten */
 
790
                        return 1;
 
791
                }
 
792
 
 
793
                rekursion = 0;
 
794
        }
 
795
 
 
796
        /* falls nicht gezeichnet werden soll, fertig */
 
797
        if (!zeichnen)
 
798
                /* kein Fehler */
 
799
                return 0;
 
800
 
 
801
        if (puffer_gueltig == puffer_nr)
 
802
                /* in diesem Fall liegen keine neuen Daten vor; kein Fehler */
 
803
                return 0;
 
804
 
 
805
        /* der andere Puffer enthaelt die neuen Daten */
 
806
        puffer_nr = puffer_gueltig;
 
807
 
 
808
        /* Neuberechnung und -zeichnung aller Grafikausgaben mit neuen Daten */
 
809
        neuaufbau(spieler_aktiv[puffer_nr], gegneranz[puffer_nr],
 
810
                alle_spieler[puffer_nr], schuss_aktiv[puffer_nr],
 
811
                schussanz[puffer_nr], alle_schuesse[puffer_nr],
 
812
                abgeschossen_durch[puffer_nr], abschuss_spruch[puffer_nr],
 
813
                ereignisse[puffer_nr], alle_punkte[puffer_nr]);
 
814
 
 
815
        /* kein Fehler */
 
816
        return 0;
 
817
}
 
818
 
 
819
 
 
820
/*
 
821
** client_spiel_starten
 
822
**  wird aufgerufen, um die Verbindung zum Server aufzubauen
 
823
**
 
824
** Parameter:
 
825
**  server_name: Name des Servers
 
826
**  spruch: Spruch des Spielers oder NULL
 
827
**  kamera: Flag, ob der Spieler nur zusehen will
 
828
**
 
829
** Rueckgabewert:
 
830
**  1 fuer Fehler, sonst 0
 
831
**
 
832
** Seiteneffekte:
 
833
**  Daten werden vom Server empfangen; karteneu wird initialisiert
 
834
*/
 
835
int client_spiel_starten(char *server_name, char *spruch, int kamera)
 
836
{
 
837
        /* Verbindung zum angegebenen Server aufbauen */
 
838
        if (verbindung_aufbauen(server_name))
 
839
                return 1;
 
840
 
 
841
        /* Spielparameter / Labyrinth empfangen */
 
842
        if (spielparameter_empfangen("iMaze 3D client JC/HUK 1.4",
 
843
                "Anonymous User", strlen(spruch) ? spruch : NULL, kamera,
 
844
                &feldbreite, &feldlaenge, &spielfeld, NULL, 1 /* starten */))
 
845
                return 1;
 
846
 
 
847
        /* Spielfeld drehen */
 
848
        drehlab();
 
849
 
 
850
        /* Karte neu aufbauen */
 
851
        karteneu = 1;
 
852
 
 
853
        /* Spielerfarbe noch unbekannt */
 
854
        spieler_farbe = 0;
 
855
 
 
856
        /* jetzt kanns losgehen */
 
857
        if (verbindung_auf_spiel())
 
858
                return 1;
 
859
 
 
860
        /* kein Fehler */
 
861
        return 0;
 
862
}
 
863
 
 
864
 
 
865
/*
 
866
**  client_spiel_beenden
 
867
**   wird aufgerufen, wenn eine Spielrunde verlassen wird (disconnect)
 
868
*/
 
869
void client_spiel_beenden(void)
 
870
{
 
871
        /* Verbindung zum Server beenden */
 
872
        spiel_verlassen();
 
873
}
 
874
 
 
875
 
 
876
/*
 
877
** uebler_fehler
 
878
**  zeigt eine Fehlermeldung an und beendet nach Druecken eines Knopfes
 
879
**  das Programm
 
880
**
 
881
** Parameter:
 
882
**  meldung: Feld von Strings, die die Zeilen des auszugebenden Textes
 
883
**           beinhalten
 
884
**  knopf: Text der auf dem Knopf stehen soll;
 
885
**         falls NULL, so wird ein Standardtext verwendet
 
886
*/
 
887
void uebler_fehler(char **meldung, char *knopf)
 
888
{
 
889
        /* Fehler anzeigen */
 
890
        ueblen_fehler_anzeigen(meldung, knopf);
 
891
 
 
892
        /* Programm beenden */
 
893
        client_ende();
 
894
}
 
895
 
 
896
 
 
897
/*
 
898
** milder_fehler
 
899
**  merkt sich eine Fehlermeldung fuer die Routine milden_fehler_abfragen
 
900
**
 
901
** Parameter:
 
902
**  meldung: Feld von Strings, die die Zeilen des auszugebenden Textes
 
903
**           beinhalten
 
904
**  knopf: Text, der auf dem Knopf stehen soll;
 
905
**         falls NULL, so wird ein Standardtext verwendet
 
906
**
 
907
** Seiteneffekte:
 
908
**  fehlermeldung und fehlerknopf werden gesetzt
 
909
*/
 
910
void milder_fehler(char **meldung, char *knopf)
 
911
{
 
912
        int n; /* Anzahl der Fehlerstrings */
 
913
        int i; /* Index fuer Fehlerstrings */
 
914
 
 
915
        /* Speicher fuer vorige Fehlermeldung freigeben */
 
916
        if (fehlermeldung != NULL)
 
917
        {
 
918
                for (i = 0; fehlermeldung[i] != NULL; i++)
 
919
                        speicher_freigeben((void **)&fehlermeldung[i]);
 
920
                speicher_freigeben((void **)&fehlermeldung);
 
921
        }
 
922
 
 
923
        /* Strings zaehlen */
 
924
        for (n = 0; meldung[n] != NULL; n++);
 
925
 
 
926
        /* Speicher fuer das Feld belegen und durch Nullzeiger begrenzen */
 
927
        speicher_belegen((void **)&fehlermeldung, (n + 1) * sizeof *fehlermeldung);
 
928
        fehlermeldung[n] = NULL;
 
929
 
 
930
        /* Fehlerstrings kopieren */
 
931
        for (i = 0; i < n; i++)
 
932
        {
 
933
                speicher_belegen((void **)&fehlermeldung[i], strlen(meldung[i]) + 1);
 
934
                strcpy(fehlermeldung[i], meldung[i]);
 
935
        }
 
936
 
 
937
        /* Speicher fuer vorige Knopfbeschriftung freigeben */
 
938
        if (fehlerknopf != NULL)
 
939
                speicher_freigeben((void **)&fehlerknopf);
 
940
 
 
941
        /* Knopfbeschriftung kopieren */
 
942
        if (knopf == NULL)
 
943
                fehlerknopf = NULL;
 
944
        else
 
945
        {
 
946
                speicher_belegen((void **)&fehlerknopf, strlen(knopf) + 1);
 
947
                strcpy(fehlerknopf, knopf);
 
948
        }
 
949
}
 
950
 
 
951
 
 
952
/*
 
953
** milden_fehler_abfragen
 
954
**  fragt den in milder_fehler gemerkten Fehlertext und -knopf ab
 
955
**
 
956
** Parameter:
 
957
**  meldung: Zeiger auf Feld von Strings, das die Zeilen des
 
958
**           auszugebenden Textes beinhalten soll
 
959
**  knopf: Zeiger auf Text, der auf dem Knopf stehen soll
 
960
**
 
961
** Seiteneffekte:
 
962
**  *meldung und *knopf werden gesetzt
 
963
*/
 
964
void milden_fehler_abfragen(char ***meldung, char **knopf)
 
965
{
 
966
        /* Rueckgabewerte setzen */
 
967
        *meldung = fehlermeldung;
 
968
        *knopf = fehlerknopf;
 
969
}
 
970
 
 
971
 
 
972
char *get_server_name(int *override)
 
973
{
 
974
        return net_get_server_name(override);
 
975
}
 
976
 
 
977
 
 
978
/*
 
979
** main
 
980
**  die Hauptroutine
 
981
**
 
982
** Parameter:
 
983
**  argc: Anzahl der Argumente inklusive Programmname
 
984
**  argv: Argumentliste
 
985
*/
 
986
int main(int argc, char **argv)
 
987
{
 
988
        /* Optionen via argv.h auswerten */
 
989
        process_args(&argc, argv);
 
990
 
 
991
        /* Netzwerkroutinen initialisieren */
 
992
        if (netzwerk_init())
 
993
                /* bei Fehler beenden */
 
994
                exit(1);
 
995
 
 
996
        /* Fenster oeffnen und lokale Datenstrukturen initialisieren */
 
997
        /* XXX argv ist hier immer leer */
 
998
        if (grafik_init(&argc, argv))
 
999
                /* bei Fehler beenden */
 
1000
                exit(1);
 
1001
 
 
1002
        /* Hauptschleife */
 
1003
        grafik_schleife();
 
1004
 
 
1005
        /* Programm beenden */
 
1006
        client_ende();
 
1007
        return 0;
 
1008
}