cGameLib_12.c 96.8 KB
Newer Older
Peter Achten's avatar
Peter Achten committed
1
2
3

/* Clean Game Library by Mike Wiering, Nijmegen */

4
5
#include "util.h"
#include "intrface.h"
Peter Achten's avatar
Peter Achten committed
6

7
#include "cGameLib.h"
Peter Achten's avatar
Peter Achten committed
8

9
#include "cOSGameLib.h"  /* OS specific functions */
Peter Achten's avatar
Peter Achten committed
10
11
12
13


// #define SMART_DRAW

14
/* defined in cCrossCall.h and cCrossCall.c */
Peter Achten's avatar
Peter Achten committed
15
16
17
18
19
20
extern CrossCallInfo gCci;
extern char *gAppName;
extern HWND ghMainWindow;
extern HINSTANCE ghInst;

extern void SendMessageToClean (int mess,
21
                         int p1,int p2,int p3, int p4,int p5,int p6);
Peter Achten's avatar
Peter Achten committed
22
23
24
25
26
27
28
29
30
31
32
33
34

#define SendMessage0ToClean(mess)                   SendMessageToClean((mess), 0,0,0,0,0,0)
#define SendMessage1ToClean(mess,p1)                SendMessageToClean((mess), (int)(p1),0,0,0,0,0)
#define SendMessage2ToClean(mess,p1,p2)             SendMessageToClean((mess), (int)(p1),(int)(p2),0,0,0,0)
#define SendMessage3ToClean(mess,p1,p2,p3)          SendMessageToClean((mess), (int)(p1),(int)(p2),(int)(p3),0,0,0)
#define SendMessage4ToClean(mess,p1,p2,p3,p4)       SendMessageToClean((mess), (int)(p1),(int)(p2),(int)(p3),(int)(p4),0,0)
#define SendMessage5ToClean(mess,p1,p2,p3,p4,p5)    SendMessageToClean((mess), (int)(p1),(int)(p2),(int)(p3),(int)(p4),(int)(p5),0)
#define SendMessage6ToClean(mess,p1,p2,p3,p4,p5,p6) SendMessageToClean((mess), (int)(p1),(int)(p2),(int)(p3),(int)(p4),(int)(p5),(int)(p6))



typedef struct SPRITEANIMATION
{
35
    int iSpriteID;
Peter Achten's avatar
Peter Achten committed
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
    int iBitmapID;
    int iSequenceLength;
    char *sSequence;
    int iPosition;
    int iCounter;
    struct SPRITEANIMATION *saNext;
    BOOL bLoop;
} SPRITEANIMATION;

typedef struct OBJECTREC
{
    int iObjectID;
    int iMapX;
    int iMapY;
    int iObjType;
    int iSubType;
52
    BOOL bActive;
Peter Achten's avatar
Peter Achten committed
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
    int iXPos;
    int iYPos;
    int iXSize;
    int iYSize;
    int iXOffset;
    int iYOffset;
    int iSpriteID;
    int iSpriteIndex;
    int iDisplayOptions;
    int iOwnBounds;
    int iBounceBounds;
    int iCollideBounds;
    int iForgetX;
    int iForgetY;
    int iLastXPos;
    int iLastYPos;
    int iTimeCounter;
    int iLayer;
    int iXAcc;
    int iYAcc;
    int iXSpeed;
    int iYSpeed;
    int iXBounce;
    int iYBounce;
    int iMaxXSpeed;
    int iMaxYSpeed;
    int iXSlowDown;
    int iYSlowDown;
    int iSkipMove;
    int iOptions;

    int iFixedXPos;
    int iFixedYPos;
    int iLastFixedXPos;
    int iLastFixedYPos;
    int iLastSprite;
    int iPosition;
    int iCounter;
91
92
93
94
95
96
97
98
99
100

    int iDiag;
    int iDiagUpDn;
    int iDiagX;
    int iDiagY;
    int iDiagLeftX;
    int iDiagLeftY;
    int iDiagRightX;
    int iDiagRightY;

Peter Achten's avatar
Peter Achten committed
101
102
103
104
105
106
    struct OBJECTREC *objNext;
} OBJECTREC;


typedef struct GAMELAYERMAPINFO
{
107
    int iMapID;
Peter Achten's avatar
Peter Achten committed
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
    int iBitmapID;
    int iMapWidth;
    int iMapHeight;
    char *sMap;
    int iTotalXSize;
    int iTotalYSize;
    BOOL bTile;
    struct GAMELAYERMAPINFO *glmipNext;
} GAMELAYERMAPINFO;


extern BOOL bGameActive;
extern HWND ghGameWindow;
extern int ScreenWidth;
extern int ScreenHeight;
extern int BitsPerPixel;
extern BOOL FullScreen;

126
127
128
extern int XShiftScreen;
extern int YShiftScreen;

Peter Achten's avatar
Peter Achten committed
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
int iFrameCounter;

static GAMELAYERMAPINFO *glmipGameLayerMapInfo = NULL;
static SPRITEANIMATION *saSprites = NULL;
static OBJECTREC *objObjects = NULL;

static int XView = 0;
static int YView = 0;
static int XScrollSpeed = 0;
static int YScrollSpeed = 0;

static int iNextLayer = 0;

/* bound map */
static char *sBoundMap = NULL;
static int BoundMapWidth = 0;
static int BoundMapHeight = 0;
static int BoundBlockWidth = 0;
static int BoundBlockHeight = 0;
static int TotalWidth = 0;
static int TotalHeight = 0;

#ifdef SMART_DRAW
/* smart draw data (only draw changed tiles) */
static char *sLastTile = NULL;
static int iLastTileW;
static int iLastTileH;
static int iTopLayerLastX;
static int iTopLayerLastY;
static int bSmartDraw;
static int bAllowSmartDraw;
#endif

/* min. value for objects */
163
static int iObjectValueStart;
Peter Achten's avatar
Peter Achten committed
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204

/* smallest distance to visible screen before initializing object */
static int iStartObjX = 5;
static int iStartObjY = 5;

/* ID of the object that is performing a crosscall */
static int iCCObjectID = 0;

static BOOL bCheckEscape = TRUE;
static BOOL DebugScroll = FALSE;
static BOOL bFillBackground = TRUE;
static COLORREF FillBackgroundRGB = 0;
static BOOL bFadeIn = FALSE;
static BOOL bFadeOut = FALSE;

static char FullScreenGameWindowClassName[] = "__CleanFullScreenGameWindow";
static char GameWindowClassName[] = "__CleanGameWindow";


/* focusing the main character */
static int iFollowID = 0;
static int iFollowX1 = 0;
static int iFollowY1 = 0;
static int iFollowX2 = 0;
static int iFollowY2 = 0;

static int iMaxXScrollSpeed = 1;
static int iMaxYScrollSpeed = 1;
static int iActualXView = 0;
static int iActualYView = 0;

/* info for user defined events and scheduled */
typedef struct USER_EVENT_INFO
{
    int iEventID;
    int iEventParameter1;
    int iEventParameter2;
    int iEventParameter3;
    int iEventParameter4;
    int iDestination;
    int iSubDestination;
205
    int iTimeCounter;
Peter Achten's avatar
Peter Achten committed
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
    struct USER_EVENT_INFO *ueiNext;
} USER_EVENT_INFO;

static USER_EVENT_INFO *ueiUserEventInfo = NULL;

#define EV_PLAY_SOUND  (-1)


ClearUserEvents ()
{
    struct USER_EVENT_INFO *ueiNext;

    while (ueiUserEventInfo)
    {
        ueiNext = ueiUserEventInfo->ueiNext;
        rfree (ueiUserEventInfo);
        ueiUserEventInfo = ueiNext;
    }
}


int NextFrame (int);


/* use one integer to save info for both pages */
static int setflipint (int x, int value)
{
    if ((iFrameCounter % 2) == 0)
        return ((x & 0xFFFF0000) + (value & 0xFFFF));
    else
        return ((x & 0xFFFF) + (value << 16));
}

static int getflipint (int value)
{
    if ((iFrameCounter % 2) == 0)
        return (value & 0xFFFF);
    else
        return (value >> 16);
}

static BOOL cmpflipint (int x, int value)
{
    if ((iFrameCounter % 2) == 0)
        return ((x & 0xFFFF0000) == (value << 16));
    else
        return ((x & 0xFFFF) == (value & 0xFFFF));
}



/*
258
259
     3 / 2 =  1
     2 / 2 =  1
Peter Achten's avatar
Peter Achten committed
260
261
     1 / 2 =  0
     0 / 2 =  0
262
    -1 / 2 =  0   <-- fill up this gap
Peter Achten's avatar
Peter Achten committed
263
264
265
266
267
268
    -2 / 2 = -1
    -3 / 2 = -1
*/

int intdiv (int x, int y)
{
269
    return (x < 0)? (x - y + 1) / y : x / y;
Peter Achten's avatar
Peter Achten committed
270
271
272
273
}

int Min (int x, int y)
{
274
    return (x < y)? x : y;
Peter Achten's avatar
Peter Achten committed
275
276
277
278
}

int Max (int x, int y)
{
279
    return (x > y)? x : y;
Peter Achten's avatar
Peter Achten committed
280
281
282
283
284
285
286
287
288
}


/* get a pointer to the SPRITEANIMATION structure with id ID */
SPRITEANIMATION *GetSpriteAnimation (int ID)
{
    SPRITEANIMATION *sa = saSprites;
    BOOL bFound = FALSE;

289
    while (sa && (!bFound))
Peter Achten's avatar
Peter Achten committed
290
    {
291
292
        if (sa->iSpriteID == ID)
            bFound = TRUE;
Peter Achten's avatar
Peter Achten committed
293
        else
294
            sa = sa->saNext;
Peter Achten's avatar
Peter Achten committed
295
296
    }
    if (bFound)
297
        return sa;
Peter Achten's avatar
Peter Achten committed
298
299
300
301
302
303
304
305
306
    else
        return NULL;
}

/* free the SPRITEANIMATION list */
void FreeSpriteAnimationList ()
{
    SPRITEANIMATION *sa;

307
    while (saSprites)
Peter Achten's avatar
Peter Achten committed
308
    {
309
310
311
312
313
314
        sa = saSprites->saNext;
        if (saSprites->sSequence)
        {
            rfree (saSprites->sSequence);
            saSprites->sSequence = NULL;
        }
Peter Achten's avatar
Peter Achten committed
315
316
317
318
319
320
321
322
323
324
325
        rfree (saSprites);
        saSprites = sa;
    }
}

/* get a pointer to the GAMELAYERMAPINFO structure with id MID */
GAMELAYERMAPINFO *GetGameLayerMapInfo (int MapID)
{
    GAMELAYERMAPINFO *glmip = glmipGameLayerMapInfo;
    BOOL bFound = FALSE;

326
    while (glmip && (!bFound))
Peter Achten's avatar
Peter Achten committed
327
    {
328
329
        if (glmip->iMapID == MapID)
            bFound = TRUE;
Peter Achten's avatar
Peter Achten committed
330
        else
331
            glmip = glmip->glmipNext;
Peter Achten's avatar
Peter Achten committed
332
    }
333
    return glmip;
Peter Achten's avatar
Peter Achten committed
334
335
336
337
338
339
340
}

/* free the GAMELAYERMAPINFO list and all the map strings */
void FreeGameLayerMapInfoList ()
{
    GAMELAYERMAPINFO *glmip;

341
    while (glmipGameLayerMapInfo)
Peter Achten's avatar
Peter Achten committed
342
    {
343
        glmip = glmipGameLayerMapInfo->glmipNext;
Peter Achten's avatar
Peter Achten committed
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
        if (glmipGameLayerMapInfo->sMap != NULL)
        {
            rfree (glmipGameLayerMapInfo->sMap);
            glmipGameLayerMapInfo->sMap = NULL;
        }
        rfree (glmipGameLayerMapInfo);
        glmipGameLayerMapInfo = glmip;
    }
}


/* get a pointer to the OBJECTREC structure with id ID */
OBJECTREC *GetObjectRec (int ID)
{
    OBJECTREC *obj = objObjects;
    BOOL bFound = FALSE;

361
    while (obj && (!bFound))
Peter Achten's avatar
Peter Achten committed
362
    {
363
364
        if (obj->iObjectID == ID)
            bFound = TRUE;
Peter Achten's avatar
Peter Achten committed
365
        else
366
            obj = obj->objNext;
Peter Achten's avatar
Peter Achten committed
367
    }
368
    return obj;
Peter Achten's avatar
Peter Achten committed
369
370
}

Mike Wiering's avatar
Mike Wiering committed
371
372
373
374
375
376
377
378
379
380
381
382
383
/* update last position if pos has been changed during an event */
void UpdatePosition (OBJECTREC *obj)
{
    obj->iLastXPos = obj->iXPos;
    obj->iLastYPos = obj->iYPos;

    obj->iFixedXPos = obj->iXPos << 8;
    obj->iFixedYPos = obj->iYPos << 8;
    obj->iLastFixedXPos = obj->iFixedXPos;
    obj->iLastFixedYPos = obj->iFixedYPos;
}


Peter Achten's avatar
Peter Achten committed
384
385
386
387
388
389
390
391
392
393
394
395

/* initialize a new game object */
void InitGameObject (int mapx, int mapy)
{
    OBJECTREC *objNew;
    OBJECTREC *obj1;
    OBJECTREC *obj2;
    int mappos;
    int origmapval, mapval, above;
    int newid;

    if ((mapx < 0) || (mapy < 0))
396
        return;
Peter Achten's avatar
Peter Achten committed
397
398
399
400
401
402
    if ((mapx > BoundMapWidth - 1) || (mapy > BoundMapHeight - 1))
        return;
    mappos = (mapy * BoundMapWidth + mapx) * sizeof (int);
    origmapval = (*(int *) &sBoundMap[mappos]);
    mapval = origmapval >> 8;
    if (mapval < iObjectValueStart)
403
        return;
Peter Achten's avatar
Peter Achten committed
404
405
406
407
408

    (*(int *) &sBoundMap[mappos]) = origmapval & 0x00FF;  // remove object

    // create a unique id number
    newid = 1;
409
    while (GetObjectRec (newid))
Peter Achten's avatar
Peter Achten committed
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
        newid++;

    objNew = rmalloc (sizeof (OBJECTREC));
    objNew->objNext = NULL;
    objNew->iMapX = mapx;
    objNew->iMapY = mapy;
  /*
    objNew->iObjType = mapval;
    objNew->iSubType = above >> 8;
  */
    if (mapy == 0)
        above = 0;
    else
    {
        origmapval = (*(int *) &sBoundMap[mappos - BoundMapWidth * sizeof (int)]);
        above = origmapval >> 8;
    }

    if (above >= iObjectValueStart)
        above = 0;

    if (above > 0)
        (*(int *) &sBoundMap[mappos - BoundMapWidth * sizeof (int)]) =
            origmapval & 0x00FF;  // remove subcode

    objNew->iObjectID = newid;
    objNew->bActive = FALSE;

    objNew->iPosition = 0;
    objNew->iCounter = 0;

    obj1 = objObjects;
    obj2 = NULL;

    while (obj1)
    {
446
        obj2 = obj1;
Peter Achten's avatar
Peter Achten committed
447
448
449
450
451
        obj1 = obj1->objNext;
    }

    if (obj2)
    {
452
        obj2->objNext = objNew;
Peter Achten's avatar
Peter Achten committed
453
454
455
456
457
    }
    else
    {
        objObjects = objNew;
    }
458
459


Peter Achten's avatar
Peter Achten committed
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
    // inform Clean that new object has been created
    iCCObjectID = newid;
    SendMessage6ToClean (CcWmINITOBJECT, mapval, above, newid,
                           mapx * BoundBlockWidth,
                           mapy * BoundBlockHeight, iFrameCounter);
    iCCObjectID = 0;

    UpdatePosition (objNew);
}

/* remove game object with id ID and all objects that are not active (id==0) */
void GameObjectDone (int id)
{
    OBJECTREC *objCur = objObjects;
    OBJECTREC *objNext = NULL;
    OBJECTREC *objPrev = NULL;
    int mappos, mapval;

    while (objCur)
    {
        if ((id != -1) &&
            (((id > 0) && (objCur->iObjectID != id)) ||
             ((id == 0) && (objCur->bActive))
            )
           )
        {
486
487
            /* skip this object */
            objPrev = objCur;
Peter Achten's avatar
Peter Achten committed
488
489
490
491
            objNext = objCur->objNext;
        }
        else
        {
492
            /* remove this object */
Peter Achten's avatar
Peter Achten committed
493

494
495
            if (objCur->iObjectID == iFollowID)
                iFollowID = 0;
Peter Achten's avatar
Peter Achten committed
496

497
498
499
            /* link previous node to next node */
            if (objPrev)
                objPrev->objNext = objCur->objNext;
Peter Achten's avatar
Peter Achten committed
500
501
502
503
504
505
506
507
508
            else
                objObjects = objCur->objNext;

            objNext = objCur->objNext;

            /* call object's done function */

            if (id != -1)
            {
509
510
511
                iCCObjectID = objCur->iObjectID;
                SendMessage2ToClean (CcWmOBJECTDONE, objCur->iObjType, objCur->iObjectID);
                iCCObjectID = 0;
Peter Achten's avatar
Peter Achten committed
512
513
514
515
516
517
518
519
520

              /*  UpdatePosition (objCur);  */
            }
         /*
            objCur->iObjType = gCci.p1;
            objCur->iSubType = gCci.p2;
         */
            /* put ObjType and SubType back into map if >= 0 */
            if (!(objCur->iOptions & OO_REMOVE_MAP_CODE))
521
522
523
524
525
526
527
528
529
530
531
532
533
534
                if ((objCur->iMapX >= 0) && (objCur->iMapY >= 0))
                    if (objCur->iObjType >= 0)
                    {
                        mappos = (objCur->iMapY * BoundMapWidth + objCur->iMapX) * sizeof (int);
                        mapval = (*(int *) &sBoundMap[mappos]);
                        (*(int *) &sBoundMap[mappos]) = mapval | (objCur->iObjType << 8);

                        if (objCur->iSubType >= 0)
                        {
                            mappos = ((objCur->iMapY - 1) * BoundMapWidth + objCur->iMapX) * sizeof (int);
                            mapval = (*(int *) &sBoundMap[mappos]);
                            (*(int *) &sBoundMap[mappos]) = mapval | (objCur->iSubType << 8);
                        }
                    }
Peter Achten's avatar
Peter Achten committed
535
536

            /* free the current node */
537
            rfree (objCur);
Peter Achten's avatar
Peter Achten committed
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
        }
        objCur = objNext;
    }
}


void InitGameGlobals ()
{
    ghGameWindow = NULL;
    bGameActive = FALSE;
    iFrameCounter = 0;
}



/* GameTranslateKey translates WM_KEYDOWN wPara fields to GameKey values */
static int
GameTranslateKey (WPARAM wPara)
{
557
558
559
    switch (wPara)
    {
        case VK_BACK:        return GK_BACKSPACE; break;
Peter Achten's avatar
Peter Achten committed
560
        case VK_RETURN:      return GK_RETURN;    break;
561
562
        case VK_ESCAPE:      return GK_ESCAPE;    break;
        case VK_UP:          return GK_UP;        break;
Peter Achten's avatar
Peter Achten committed
563
        case VK_DOWN:        return GK_DOWN;      break;
564
565
        case VK_LEFT:        return GK_LEFT;      break;
        case VK_RIGHT:       return GK_RIGHT;     break;
Peter Achten's avatar
Peter Achten committed
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
        case VK_HOME:        return GK_HOME;      break;
        case VK_END:         return GK_END;       break;
//        case VK_PAGE_UP:     return GK_PAGE_UP;   break;
//        case VK_PAGE_DOWN:   return GK_PAGE_DOWN; break;
        case VK_F1:          return GK_F1;        break;
        case VK_F2:          return GK_F2;        break;
        case VK_F3:          return GK_F3;        break;
        case VK_F4:          return GK_F4;        break;
        case VK_F5:          return GK_F5;        break;
        case VK_F6:          return GK_F6;        break;
        case VK_F7:          return GK_F7;        break;
        case VK_F8:          return GK_F8;        break;
        case VK_F9:          return GK_F9;        break;
        case VK_F10:         return GK_F10;       break;
        case VK_F11:         return GK_F11;       break;
        case VK_F12:         return GK_F12;       break;
        case VK_SPACE:       return GK_SPACE;     break;
583
        default:
Peter Achten's avatar
Peter Achten committed
584
585
586
587
588
589
590
        {
             if ((wPara > 32) && (wPara <= 127))
                 return wPara;
             else
                 return GK_UNKNOWN;
             break;
        }
591
    }
Peter Achten's avatar
Peter Achten committed
592
593
594
595
596
597
}



/* buffer which holds the last state of each key */
static BOOL gk_state[GK_MAX_KEY + 1] =
598
    {FALSE};
Peter Achten's avatar
Peter Achten committed
599
600
601
602
603
604
605
606
607


//   MessageBox (NULL, "", NULL, MB_OK);


/* GameWindowProcedure is the Windows callback routine for a game window. */
static LRESULT CALLBACK
GameWindowProcedure (HWND hWin, UINT uMess, WPARAM wPara, LPARAM lPara)
{
608
609
610
    printMessage ("Game Window", hWin, uMess, wPara, lPara);
    switch (uMess)
    {
Peter Achten's avatar
Peter Achten committed
611
612
613
614
615
616
617
618
619
        case WM_CLOSE:
            bGameActive = FALSE;
            return 0;
            break;

        case WM_DESTROY:
            bGameActive = FALSE;
            ClearUserEvents ();
            GameObjectDone (-1);
620
            FreeGameLayerMapInfoList ();
Peter Achten's avatar
Peter Achten committed
621
            FreeSpriteAnimationList ();
622
            OSFreeGameBitmaps ();
Peter Achten's avatar
Peter Achten committed
623
624
625
626
627
628
629
            OSStopMusic ();
            OSDeInitSound ();
            OSDeInitGameWindow ();
            ShowCursor (TRUE);
            return 0;
            break;
        case MCI_NOTIFY:
630
            {
Peter Achten's avatar
Peter Achten committed
631
                // MessageBeep (MB_ICONASTERISK);
632
                if (wPara == MCI_NOTIFY_SUCCESSFUL)
Peter Achten's avatar
Peter Achten committed
633
                    OSPlayMusic (NULL, TRUE);  /* restart music */
634
635
            }
            break;
Peter Achten's avatar
Peter Achten committed
636
637
638
        case WM_PAINT:
            if (!FullScreen)
            {
639
640
                PAINTSTRUCT ps;
                HDC hdc = BeginPaint (hWin, &ps);
Peter Achten's avatar
Peter Achten committed
641
642

                NextFrame (0);
643
                EndPaint (hWin, &ps);
Peter Achten's avatar
Peter Achten committed
644
            }
645
            break;
Peter Achten's avatar
Peter Achten committed
646
647
        case WM_KEYUP:
            {
648
                int keycode = GameTranslateKey (wPara);
Peter Achten's avatar
Peter Achten committed
649
650
651
652
653
654

                if (gk_state[keycode])
                {
                    OBJECTREC *obj = objObjects;
                    while (obj)
                    {
655
                        if ((obj->bActive) && (obj->iOptions & OO_CHECK_KEYBOARD))
Peter Achten's avatar
Peter Achten committed
656
657
658
659
660
                        {
                            int ix = obj->iXPos;
                            int iy = obj->iYPos;

                            iCCObjectID = obj->iObjectID;
661
                            SendMessage3ToClean (CcWmOBJECTKEYUP, obj->iObjType, obj->iObjectID, keycode);
Peter Achten's avatar
Peter Achten committed
662
663
664
665
666
                            iCCObjectID = 0;

                            if ((ix != obj->iXPos) || (iy != obj->iYPos))
                                UpdatePosition (obj);
                        }
667
                        obj = obj->objNext;
Peter Achten's avatar
Peter Achten committed
668
                    }
669
                    gk_state[keycode] = FALSE;
Peter Achten's avatar
Peter Achten committed
670
671
672
673
                }
            }
            break;
        case WM_KEYDOWN:
674
675
            {
                int keycode = GameTranslateKey (wPara);
Peter Achten's avatar
Peter Achten committed
676
677
678
679
                if (keycode == GK_ESCAPE)
                    if (bCheckEscape)
                        bGameActive = FALSE;

680
681
                switch (keycode)
                {
Peter Achten's avatar
Peter Achten committed
682
                    case GK_UNKNOWN:
683
684
685
686
                        return DefWindowProc (hWin, uMess, wPara, lPara);
                        break;
                    default:
                        {
Peter Achten's avatar
Peter Achten committed
687
688
689
690
691
                            BOOL found = FALSE;
                            OBJECTREC *obj = objObjects;

                            while (obj)
                            {
692
                                if ( (obj->bActive) &&
Peter Achten's avatar
Peter Achten committed
693
694
695
696
697
698
699
700
701
                                     (obj->iOptions & OO_CHECK_KEYBOARD) &&
                                     ( (!gk_state[keycode]) ||
                                       (obj->iOptions & OO_ALLOW_KEYBOARD_REPEAT)
                                     )
                                   )
                                {
                                    int ix = obj->iXPos;
                                    int iy = obj->iYPos;

702
703
704
                                    iCCObjectID = obj->iObjectID;
                                    SendMessage3ToClean (CcWmOBJECTKEYDOWN, obj->iObjType, obj->iObjectID, keycode);
                                    iCCObjectID = 0;
Peter Achten's avatar
Peter Achten committed
705
706
707
708
709
710

                                    if ((ix != obj->iXPos) || (iy != obj->iYPos))
                                        UpdatePosition (obj);

                                    found = TRUE;
                                }
711
                                obj = obj->objNext;
Peter Achten's avatar
Peter Achten committed
712
713
714
                            }

                            gk_state[keycode] = TRUE;
715
                        }
Peter Achten's avatar
Peter Achten committed
716

717
718
                        // debugging level, just move around
                        if (DebugScroll == TRUE)
Peter Achten's avatar
Peter Achten committed
719
                        {
720
721
722
                            SendMessage3ToClean (CcWmGAMEKEYBOARD, keycode, XScrollSpeed, YScrollSpeed);
                            XScrollSpeed = gCci.p1;
                            YScrollSpeed = gCci.p2;
Peter Achten's avatar
Peter Achten committed
723
724
725
                            iMaxXScrollSpeed = 8;
                            iMaxYScrollSpeed = 8;
                        }
726
727
728
729
730
                }
            }
            break;
        default:
            return DefWindowProc (hWin, uMess, wPara, lPara);
Peter Achten's avatar
Peter Achten committed
731
            break;
732
733
    }
    return 0;
Peter Achten's avatar
Peter Achten committed
734
735
736
737
738
739
740
}


/* move XView and YView towards iActualXView and iActualYView */
void CorrectView ()
{
    if (iActualXView > XView)
741
        XView = Min (XView + iMaxXScrollSpeed, iActualXView);
Peter Achten's avatar
Peter Achten committed
742
    if (iActualYView > YView)
743
        YView = Min (YView + iMaxYScrollSpeed, iActualYView);
Peter Achten's avatar
Peter Achten committed
744
    if (iActualXView < XView)
745
        XView = Max (XView - iMaxXScrollSpeed, iActualXView);
Peter Achten's avatar
Peter Achten committed
746
    if (iActualYView < YView)
747
        YView = Max (YView - iMaxYScrollSpeed, iActualYView);
Peter Achten's avatar
Peter Achten committed
748

749
750
751
    if (XView > TotalWidth - ScreenWidth)
    {
        XView = TotalWidth - ScreenWidth;
Peter Achten's avatar
Peter Achten committed
752
        iActualXView = XView;
753
754
755
756
757
        XScrollSpeed = 0;
    }
    if (YView > TotalHeight - ScreenHeight)
    {
        YView = TotalHeight - ScreenHeight;
Peter Achten's avatar
Peter Achten committed
758
        iActualYView = YView;
759
760
        YScrollSpeed = 0;
    }
Peter Achten's avatar
Peter Achten committed
761

762
763
764
    if (XView < 0)
    {
        XView = 0;
Peter Achten's avatar
Peter Achten committed
765
        iActualXView = XView;
766
767
768
769
770
        XScrollSpeed = 0;
    }
    if (YView < 0)
    {
        YView = 0;
Peter Achten's avatar
Peter Achten committed
771
        iActualYView = YView;
772
773
        YScrollSpeed = 0;
    }
Peter Achten's avatar
Peter Achten committed
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
}


void RunGame ()
{
    MSG msg;
    int i, j, x, y, w, h;
    int lastx, lasty;
    int fade;

    int result;
    int oos;

    iFrameCounter = 0;
    CorrectView ();

    x = XView / BoundBlockWidth;
    y = YView / BoundBlockHeight;
    w = ScreenWidth / BoundBlockWidth;
    h = ScreenHeight / BoundBlockHeight;
    for (i = -iStartObjX - 1; i < w + iStartObjX + 2; i++)
        for (j = -iStartObjY - 1; j < h + iStartObjY + 2; j++)
796
            InitGameObject (x + i, y + j);
Peter Achten's avatar
Peter Achten committed
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814

    lastx = x;
    lasty = y;

#ifdef SMART_DRAW
    bSmartDraw = 0;
    bAllowSmartDraw = 0;
#endif

    /* initialize autoinit object */
    CreateGameObject (0, 0, -1, -1, &result);

    fade = (bFadeIn)? -1 : 0;
    bGameActive = TRUE;
    while (bGameActive)
    {
        if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
        {
815
816
            TranslateMessage (&msg);
            DispatchMessage (&msg);
Peter Achten's avatar
Peter Achten committed
817
818
819
820
821
        }

        if (iFollowID == 0)
        {
            iActualXView += XScrollSpeed;
822
            iActualYView += YScrollSpeed;
Peter Achten's avatar
Peter Achten committed
823
824
825
826
        }

        CorrectView ();

827
828
        x = XView / BoundBlockWidth;
        y = YView / BoundBlockHeight;
Peter Achten's avatar
Peter Achten committed
829
        if (y != lasty)
830
            for (i = -iStartObjX - 1; i < w + iStartObjX + 2; i++)
Peter Achten's avatar
Peter Achten committed
831
832
833
834
835
836
837
838
839
            {
                j = -iStartObjY;
                if (y < lasty)
                    InitGameObject (x + i, y + j);
                j = h + iStartObjY + 1;
                if (y > lasty)
                    InitGameObject (x + i, y + j);
             }
        if (x != lastx)
840
841
842
            for (j = -iStartObjY - 1; j < h + iStartObjY + 2; j++)
            {
                i = -iStartObjX;
Peter Achten's avatar
Peter Achten committed
843
                if (x < lastx)
844
845
                    InitGameObject (x + i, y + j);
                i = w + iStartObjX + 1;
Peter Achten's avatar
Peter Achten committed
846
                if (x > lastx)
847
848
                    InitGameObject (x + i, y + j);
            }
Peter Achten's avatar
Peter Achten committed
849
850
851
        lastx = x;
        lasty = y;

852
        NextFrame (fade);
Peter Achten's avatar
Peter Achten committed
853
        fade = 0;
854
        iFrameCounter++;
Peter Achten's avatar
Peter Achten committed
855

856
        SendMessage0ToClean (CcWmCHECKQUIT);
Peter Achten's avatar
Peter Achten committed
857
        if ((BOOL) gCci.p1)
858
            bGameActive = FALSE;
Peter Achten's avatar
Peter Achten committed
859
860
861
862
863
864
865
866

    }

    if (bFadeOut)
    {
        fade = 1;
        NextFrame (fade);
    }
867
    bGameActive = FALSE;
Peter Achten's avatar
Peter Achten committed
868
869

    ClearUserEvents ();
870
    GameObjectDone (-1);
Peter Achten's avatar
Peter Achten committed
871
872
873

    iFollowID = 0;

874
    //  MessageBeep (MB_ICONASTERISK);
Peter Achten's avatar
Peter Achten committed
875
876
877
}


Mike Wiering's avatar
Mike Wiering committed
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
/* create a new event */
void ScheduleEvent (int event, int par1, int par2, int par3, int par4,
                    int target, int subtarget, int time)
{
    struct USER_EVENT_INFO *uei;

    uei = rmalloc (sizeof (USER_EVENT_INFO));
    uei->iEventID = event;
    uei->iEventParameter1 = par1;
    uei->iEventParameter2 = par2;
    uei->iEventParameter3 = par3;
    uei->iEventParameter4 = par4;
    uei->iDestination = target;
    uei->iSubDestination = subtarget;
    uei->iTimeCounter = time;
    uei->ueiNext = ueiUserEventInfo;
    ueiUserEventInfo = uei;
}


Peter Achten's avatar
Peter Achten committed
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
/* play (actually schedule) a sound sample */
void PlaySoundSample (int id, int vol, int pan, int freq, int delay)
{
    ScheduleEvent (EV_PLAY_SOUND, id, vol, pan, freq, 0, -1, delay);
}

/* schedule any user event */
void ScheduleUserGameEvent (int event, int par1, int par2,
                            int target, int subtarget, int time)
{
    struct USER_EVENT_INFO *uei;

    if (event >= 0)
    {
        uei = rmalloc (sizeof (USER_EVENT_INFO));
        uei->iEventID = event;
        uei->iEventParameter1 = par1;
        uei->iEventParameter2 = par2;
        uei->iEventParameter3 = 0;
        uei->iEventParameter4 = 0;
        if (target == 0)
            uei->iDestination = -iCCObjectID;  /* only target current object */
        else
            if (target == -1)
                uei->iDestination = 0;  /* all objects */
            else
                uei->iDestination = target;  /* bounds */
        uei->iSubDestination = subtarget;
        uei->iTimeCounter = time;
        uei->ueiNext = ueiUserEventInfo;
        ueiUserEventInfo = uei;
    }
}


/* create the game window */
int CreateGameWindow (int w, int h, int bpp, BOOL fs)
{
    ScreenWidth = w;
    ScreenHeight = h;
    BitsPerPixel = bpp;
    FullScreen = fs;

    if (FullScreen)
        ghGameWindow =
            CreateWindowEx (WS_EX_TOPMOST,       /* extended style */
                            (LPCTSTR) FullScreenGameWindowClassName,  /* class */
                            (LPCTSTR) gAppName,  /* title */
                            WS_POPUP,            /* window style */
                            0, 0, ScreenWidth, ScreenHeight,
                            ghMainWindow,        /* ??? parent */
                            NULL,                /* menu */
                            (HANDLE) ghInst,
                            NULL                 /* window creation data */
                           );
    else
        ghGameWindow =
955
            CreateWindowEx (WS_OVERLAPPED,
Peter Achten's avatar
Peter Achten committed
956
957
958
959
960
961
962
963
964
965
966
967
968
                            (LPCTSTR) GameWindowClassName,
                            (LPCTSTR) gAppName,
                            WS_THICKFRAME,
                            CW_USEDEFAULT,
                            CW_USEDEFAULT,
                            ScreenWidth,
                            ScreenHeight,
                            ghMainWindow,
                            NULL,
                            (HANDLE) ghInst,
                            NULL
                           );

969
970
    ShowWindow (ghGameWindow, SW_SHOWNORMAL);
    UpdateWindow (ghGameWindow);
Peter Achten's avatar
Peter Achten committed
971
972
973
974

    if (OSInitGameWindow ())
    {
        OSClearScreen ();
975
976
977
        if (FullScreen)
            OSFlip ();
        OSClearScreen ();
Peter Achten's avatar
Peter Achten committed
978
979
980
981
982
983
        OSClearVirtualScreen (FillBackgroundRGB);
        OSInitSound ();
    }
    else
        ErrorExit ("Game Window could not be created");

984
    iFrameCounter = 0;
Peter Achten's avatar
Peter Achten committed
985
986
987
988
989
990
991
992

    return ((int) ghGameWindow);
}


/* register game window class */
void RegisterGameWindowClass ()
{
993
    WNDCLASS wclass;
Peter Achten's avatar
Peter Achten committed
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024

    wclass.style = CS_HREDRAW | CS_VREDRAW;
    wclass.lpfnWndProc = (WNDPROC) GameWindowProcedure;
    wclass.cbClsExtra = 0;
    wclass.cbWndExtra = 0;
    wclass.hInstance = ghInst;
    wclass.hIcon = LoadIcon (ghInst, IDI_APPLICATION);
    wclass.hCursor = NULL;
    wclass.hbrBackground = NULL;
    wclass.lpszMenuName = NULL;
    wclass.lpszClassName = FullScreenGameWindowClassName;
    RegisterClass (&wclass);

    wclass.style = CS_HREDRAW | CS_VREDRAW;
    wclass.lpfnWndProc = (WNDPROC) GameWindowProcedure;
    wclass.cbClsExtra = 0;
    wclass.cbWndExtra = 0;
    wclass.hInstance = ghInst;
    wclass.hIcon = LoadIcon (ghInst, IDI_APPLICATION);
    wclass.hCursor = NULL;
    wclass.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
    wclass.lpszMenuName = NULL;
    wclass.lpszClassName = GameWindowClassName;
    RegisterClass (&wclass);
}


/* convert an integer to a 4-byte string */
extern EXPORT_TO_CLEAN CLEAN_STRING
WinBinaryIntStr (int x)
{
1025
    static CLEAN_STRING result = NULL;
Peter Achten's avatar
Peter Achten committed
1026
1027

    if (result)
1028
        rfree (result);
Peter Achten's avatar
Peter Achten committed
1029
1030

    result = rmalloc (sizeof (x) + 1 + sizeof (int));
1031
1032
    result->length = sizeof (x);
    rsncopy (result->characters, (const char *) &x, sizeof (x));
Peter Achten's avatar
Peter Achten committed
1033

1034
    return result;
Peter Achten's avatar
Peter Achten committed
1035
1036
1037
1038
1039
1040
}

/* convert a boolean value to a Clean string */
extern EXPORT_TO_CLEAN CLEAN_STRING
WinBinaryBoolStr (BOOL b)
{
1041
    static CLEAN_STRING result = NULL;
Peter Achten's avatar
Peter Achten committed
1042
1043

    if (result)
1044
        rfree (result);
Peter Achten's avatar
Peter Achten committed
1045
1046

    result = rmalloc (sizeof (b) + 1 + sizeof (int));
1047
1048
    result->length = sizeof (b);
    rsncopy (result->characters, (const char *) &b, sizeof (b));
Peter Achten's avatar
Peter Achten committed
1049

1050
    return result;
Peter Achten's avatar
Peter Achten committed
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
}

/* read a new bitmap into (offscreen) memory (id==0: create new id: result) */
extern EXPORT_TO_CLEAN void
WinInitGameBitmap (int id, CLEAN_STRING name,
                   int bitmapwidth, int bitmapheight,
                   int blockwidth, int blockheight,
                   OS ios, int *result, OS *oos)
{
    int resultcode = OSInitGameBitmap (id, cstring (name),
                                       bitmapwidth, bitmapheight,
                                       blockwidth, blockheight);

    *result = resultcode;
1065
    *oos = ios;
Peter Achten's avatar
Peter Achten committed
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
}

/* remove all bitmaps from memory, including all sprites */
extern EXPORT_TO_CLEAN void
WinClearAllGameBitmaps (OS ios, int *result, OS* oos)
{
    FreeSpriteAnimationList ();
    OSFreeGameBitmaps ();

    *result = GR_OK;
1076
    *oos = ios;
Peter Achten's avatar
Peter Achten committed
1077
1078
1079
1080
1081
1082
1083
}

/* remove bitmap from memory */
extern EXPORT_TO_CLEAN void
WinGameBitmapDone (int id, OS ios, int *result, OS* oos)
{
    *result = OSFreeGameBitmap (id);
1084
    *oos = ios;
Peter Achten's avatar
Peter Achten committed
1085
1086
1087
1088
1089
1090
1091
}

/* set the transparent color for a bitmap: (x,y) is a transparent pixel */
extern EXPORT_TO_CLEAN void
WinSetTransparentColor (int id, int x, int y, OS ios, int *result, OS* oos)
{
    *result = OSSetTransparentColor (id, x, y);
1092
    *oos = ios;
Peter Achten's avatar
Peter Achten committed
1093
1094
1095
1096
1097
1098
1099
1100
1101
}

/* initialize a block animation sequence (list of repeating blocks) */
extern EXPORT_TO_CLEAN void
WinInitBlockSequence (int bitmapid, int seqid, CLEAN_STRING seq,
                      OS ios, int *result, OS *oos)
{
    *result = OSInitBlockSequence (bitmapid, seqid,
                                     cstring (seq), seq->length);
1102
    *oos = ios;
Peter Achten's avatar
Peter Achten committed
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
}

/* initialize the bound map */
extern EXPORT_TO_CLEAN void
WinSetGameBoundMap (int blockwidth, int blockheight, CLEAN_STRING map,
                    int mapwidth, int mapheight, int objectstartvalue,
                    int startobjx, int startobjy,
                    OS ios, int *result, OS *oos)
{
    int resultcode = GR_OK;

    BoundMapWidth = mapwidth;
    BoundMapHeight = mapheight;
    BoundBlockWidth = blockwidth;
    BoundBlockHeight = blockheight;
    TotalWidth = mapwidth * blockwidth;
    TotalHeight = mapheight * blockheight;

#ifdef SMART_DRAW
    if (sLastTile)
1123
        rfree (sLastTile);
Peter Achten's avatar
Peter Achten committed
1124
1125
1126
1127
1128
1129
1130
    iLastTileW = ScreenWidth / BoundBlockWidth + 1;
    iLastTileH = ScreenHeight / BoundBlockHeight + 1;
    sLastTile = rmalloc (((iLastTileW + 1) * (iLastTileH + 1) + 1) *
                           sizeof (int));
#endif

    if (sBoundMap)
1131
        rfree (sBoundMap);
Peter Achten's avatar
Peter Achten committed
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
    sBoundMap = rmalloc ((map->length) + 1);

    rsncopy (sBoundMap, map->characters, map->length);
    iObjectValueStart = objectstartvalue;
    iStartObjX = startobjx;
    iStartObjY = startobjy;

    XView = 0;
    YView = 0;
    XScrollSpeed = 0;
    YScrollSpeed = 0;

    *result = resultcode;
1145
    *oos = ios;
Peter Achten's avatar
Peter Achten committed
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
}


/* set the level's initial position */
extern EXPORT_TO_CLEAN void
WinMoveScreenTo (int x, int y, OS ios, int *result ,OS *oos)
{
    XView = x;  // ((x * BoundBlockWidth) + BoundBlockWidth / 2) - ScreenWidth / 2;
    YView = y;  // ((y * BoundBlockHeight) + BoundBlockHeight / 2) - ScreenHeight / 2;
    iActualXView = XView;
    iActualYView = YView;

    CorrectView ();

    *result = GR_OK;
1161
    *oos = ios;
Peter Achten's avatar
Peter Achten committed
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
}


/* initialize a new layer map */
extern EXPORT_TO_CLEAN void
WinInitGameLayerMap (int mapid, int bitmapid, CLEAN_STRING map,
                     int mapwidth, int mapheight,
                     BOOL tile,
                   /*  int scrollspeed,  */
                     OS ios, int *result, OS *oos)
{
    int resultcode;
    GAMELAYERMAPINFO *glmip1;
    GAMELAYERMAPINFO *glmip2;

    resultcode = GR_INVALID_MAP_ID;
    if (!GetGameLayerMapInfo (mapid))  /* identifier not used yet */
    {
        int gbW, gbH, gbBW, gbBH, gbCX, gbCY;
1181
        resultcode = GR_INVALID_BITMAP_ID;
Peter Achten's avatar
Peter Achten committed
1182
1183
1184

        if (OSGetGameBitmapInfo (bitmapid,
                                    &gbW, &gbH, &gbBW, &gbBH, &gbCX, &gbCY))
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
        {
            /* find last element of linked list */
            glmip1 = glmipGameLayerMapInfo;
            glmip2 = NULL;
            while (glmip1)
            {
                glmip2 = glmip1;
                glmip1 = glmip1->glmipNext;
            }

            /* create new node */
            glmip1 = rmalloc (sizeof (GAMELAYERMAPINFO));
            glmip1->iMapID = mapid;
            glmip1->iBitmapID = bitmapid;
            glmip1->iMapWidth = mapwidth;
            glmip1->iMapHeight = mapheight;
            glmip1->sMap = rmalloc ((map->length) + 1);
            rsncopy (glmip1->sMap, map->characters, map->length);
Peter Achten's avatar
Peter Achten committed
1203
1204
1205
            glmip1->iTotalXSize = (mapwidth * gbBW);
            glmip1->iTotalYSize = (mapheight * gbBH);
            glmip1->bTile = tile;
1206
1207
1208
1209
1210
1211
1212
1213
1214
            glmip1->glmipNext = NULL;

            /* glmip2 points to the last element or is NULL */
            if (glmip2)
                glmip2->glmipNext = glmip1;
            else
                glmipGameLayerMapInfo = glmip1;  /* first element */

            resultcode = GR_OK;
Peter Achten's avatar
Peter Achten committed
1215
1216
1217
1218
        }
    }

    *result = resultcode;
1219
    *oos = ios;
Peter Achten's avatar
Peter Achten committed
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
}

/* remove layer map from memory */
extern EXPORT_TO_CLEAN void
WinGameLayerMapDone (int mapid, OS ios, int *result, OS* oos)
{
    GAMELAYERMAPINFO *glmipCurrent = glmipGameLayerMapInfo;
    GAMELAYERMAPINFO *glmipNext = NULL;
    GAMELAYERMAPINFO *glmipPrevious = NULL;

    *result = GR_INVALID_MAP_ID;
1231
    while (glmipCurrent)
Peter Achten's avatar
Peter Achten committed
1232
1233
1234
    {
        if (glmipCurrent->iMapID != mapid)
        {
1235
1236
            glmipPrevious = glmipCurrent;
            glmipNext = glmipCurrent->glmipNext;
Peter Achten's avatar
Peter Achten committed
1237
        }
1238
        else
Peter Achten's avatar
Peter Achten committed
1239
        {
1240
            /* link previous node to next node */
Peter Achten's avatar
Peter Achten committed
1241
            if (glmipPrevious)
1242
                glmipPrevious->glmipNext = glmipCurrent->glmipNext;
Peter Achten's avatar
Peter Achten committed
1243
1244
1245
            else
                glmipGameLayerMapInfo = glmipCurrent->glmipNext;

1246
            glmipNext = glmipCurrent->glmipNext;
Peter Achten's avatar
Peter Achten committed
1247
1248

            /* free the current node */
1249
            if (glmipCurrent->sMap)
Peter Achten's avatar
Peter Achten committed
1250
            {
1251
                rfree (glmipCurrent->sMap);
Peter Achten's avatar
Peter Achten committed
1252
1253
                glmipCurrent->sMap = NULL;
            }
1254
            rfree (glmipCurrent);
Peter Achten's avatar
Peter Achten committed
1255
1256
1257
1258
1259
1260

            *result = GR_OK;
        }
        glmipCurrent = glmipNext;
    }

1261
    *oos = ios;
Peter Achten's avatar
Peter Achten committed
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
}


/* initialize an animation sequence (if succes, result = id) */
extern EXPORT_TO_CLEAN void
WinInitSpriteAnimation (int bitmapid, CLEAN_STRING seq, BOOL loop,
                        OS ios, int* result, OS* oos)
{
    SPRITEANIMATION *saNew;
    SPRITEANIMATION *sa1;
    SPRITEANIMATION *sa2;
    int newid = 1;
    int resultcode;

    int gbW, gbH, gbBW, gbBH, gbCX, gbCY;

    resultcode = GR_INVALID_BITMAP_ID;
    if (OSGetGameBitmapInfo (bitmapid,
                                &gbW, &gbH, &gbBW, &gbBH, &gbCX, &gbCY))
    {
       /* if (loop) */
        {
1284
1285
            /* first look if animation sequence already is initialized */
            SPRITEANIMATION *sa = saSprites;
Peter Achten's avatar
Peter Achten committed
1286
1287
1288
            int slen = seq->length / (2 * sizeof (int));
            BOOL equal;
            int i, j, k;
1289
1290
1291
1292
1293
1294

            while (sa)
            {
                if (sa->iBitmapID == bitmapid)
                {
                    if ((sa->bLoop == loop) && (sa->iSequenceLength == slen))
Peter Achten's avatar
Peter Achten committed
1295
                    {
1296
                        equal = TRUE;
Peter Achten's avatar
Peter Achten committed
1297
1298
1299
1300
                        for (k = 0; k < slen; k++)
                        {
                            i = (*(int *) &seq->characters[k * sizeof (int)]);
                            j = (*(int *) &sa->sSequence[k * sizeof (int)]);
1301
1302
                            if (i != j)
                                equal = FALSE;
Peter Achten's avatar
Peter Achten committed
1303
                        }
1304
                        if (equal)
Peter Achten's avatar
Peter Achten committed
1305
                        {
1306
                            *result = sa->iSpriteID;
Peter Achten's avatar
Peter Achten committed
1307
1308
1309
1310
                            *oos = ios;
                            return;
                        }
                    }
1311
1312
1313
                }
                sa = sa->saNext;
            }
Peter Achten's avatar
Peter Achten committed
1314
1315
1316
1317
1318
1319
1320
        }

        saNew = rmalloc (sizeof (SPRITEANIMATION));
        saNew->iBitmapID = bitmapid;
        saNew->iSequenceLength = seq->length / (2 * sizeof (int));
        saNew->sSequence = rmalloc ((seq->length) + 1);
        rsncopy (saNew->sSequence, seq->characters, seq->length);
1321
        saNew->iPosition = 0;  // saNew->iSequenceLength;
Peter Achten's avatar
Peter Achten committed
1322
        saNew->iCounter = (*(int *) &saNew->sSequence[sizeof (int)]);  // 0
1323
        saNew->saNext = NULL;
Peter Achten's avatar
Peter Achten committed
1324
1325
1326
1327
1328
1329
1330
        saNew->bLoop = loop;

        sa1 = saSprites;
        sa2 = NULL;
        while (sa1)
        {
            if (sa1->iSpriteID >= newid)
1331
1332
                newid = sa1->iSpriteID + 1;
            sa2 = sa1;
Peter Achten's avatar
Peter Achten committed
1333
1334
            sa1 = sa1->saNext;
        }
1335
1336
1337
        saNew->iSpriteID = newid;
        if (sa2)
            sa2->saNext = saNew;
Peter Achten's avatar
Peter Achten committed
1338
1339
1340
        else
            saSprites = saNew;

1341
        resultcode = GR_OK;
Peter Achten's avatar
Peter Achten committed
1342
1343
    }

1344
    if (resultcode == GR_OK)
Peter Achten's avatar
Peter Achten committed
1345
1346
        *result = newid;
    else
1347
1348
        *result = resultcode;
    *oos = ios;
Peter Achten's avatar
Peter Achten committed
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
}


/* get value of boundmap[x,y] */
int ReadBoundMapValue (int x, int y, int options, int bounds, int mccode)
{
    int mappos;
    int result;

    // off map: all bounds, code 0xFF
    if ((x < 0) ||
        (y < 0) ||
        (x > BoundMapWidth - 1) ||
        (y > BoundMapHeight - 1))
    {
        if (options & OO_IGNORE_LEVEL_BOUNDS)
1365
            result = 0x0000;
Peter Achten's avatar
Peter Achten committed
1366
        else
1367
            result = 0xFF0F;
Peter Achten's avatar
Peter Achten committed
1368
1369
1370
    }
    else
    {
1371
        mappos = (y * BoundMapWidth + x) * sizeof (int);
Peter Achten's avatar
Peter Achten committed
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
        result = (*(int *) &sBoundMap[mappos]);
    }

    if (!(bounds & BND_STATIC_BOUNDS))
        result &= 0xFF00;
    if (bounds & BND_MAP_CODES)
    {
        if ((result >> 8) > 0)
            result |= mccode;
    }
    else
        result &= 0x00FF;

1385
1386
1387
1388
1389
/// diagonal bounds
    if ((result & 0x00F0) != 0)
      result = (result << 16) | 0x00F0;
///

Peter Achten's avatar
Peter Achten committed
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
    return result;
}


Bounce (OBJECTREC *obj, int bound)
{
    int xb = obj->iXBounce;
    int yb = obj->iYBounce;

    if (xb < 0)
1400
        xb = abs (xb * obj->iXSpeed) / 256;
Peter Achten's avatar
Peter Achten committed
1401
    if (yb < 0)
1402
        yb = abs (yb * obj->iYSpeed) / 256;
Peter Achten's avatar
Peter Achten committed
1403

1404
    if ((bound & UPPER_BOUND) > 0)
Peter Achten's avatar
Peter Achten committed
1405
1406
1407
1408
1409
    {
        obj->iYPos = obj->iLastYPos;
        obj->iFixedYPos = obj->iLastFixedYPos;
        obj->iYSpeed = -yb;
    }
1410
    if ((bound & LEFT_BOUND) > 0)
Peter Achten's avatar
Peter Achten committed
1411
1412
1413
1414
1415
    {
        obj->iXPos = obj->iLastXPos;
        obj->iFixedXPos = obj->iLastFixedXPos;
        obj->iXSpeed = -xb;
    }
1416
    if ((bound & LOWER_BOUND) > 0)
Peter Achten's avatar
Peter Achten committed
1417
1418
1419
1420
1421
    {
        obj->iYPos = obj->iLastYPos;
        obj->iFixedYPos = obj->iLastFixedYPos;
        obj->iYSpeed = yb;
    }
1422
    if ((bound & RIGHT_BOUND) > 0)
Peter Achten's avatar
Peter Achten committed
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
    {
        obj->iXPos = obj->iLastXPos;
        obj->iFixedXPos = obj->iLastFixedXPos;
        obj->iXSpeed = xb;
    }
}


/* move objects around */
void MoveObjects ()
{
    OBJECTREC *obj;
    int x, y, w, h, i, j, k, xbnd, ybnd, code, bound, Bound;
    int oldmapx1, oldmapy1, oldmapx2, oldmapy2;
    int newmapx1, newmapy1, newmapx2, newmapy2;
    int newx, newy;
    BOOL xblock, yblock, xbump, ybump;
    SPRITEANIMATION *sa;
    int iObjectCount = 0;
    struct USER_EVENT_INFO *uei;
    struct USER_EVENT_INFO *ueiNext;
    struct USER_EVENT_INFO *ueiPrev;

    // broadcast user events
    uei = ueiUserEventInfo;
    ueiPrev = NULL;
    while (uei)
    {
        ueiNext = uei->ueiNext;
        if (--uei->iTimeCounter <= 0)
        {
            if (uei->iEventID == EV_PLAY_SOUND)
            {
                int id     = uei->iEventParameter1;
                int volume = uei->iEventParameter2;
                int pan    = uei->iEventParameter3;
                int freq   = uei->iEventParameter4;

                OSPlaySoundSample (id, volume, pan, freq);
            }
            else
            {
1465
1466
1467
1468
1469
1470
1471
1472
                obj = objObjects;
                while (obj)
                {
                    if (obj->bActive)
                    {
                        if (((uei->iDestination == 0) ||
                             (uei->iDestination == -obj->iObjectID) ||
                             ((uei->iDestination > 0) &&