2 * This program is free software: you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation, either version 3 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 #ifndef AWISH_NO_SOUND
16 # include "SDL_mixer.h"
22 #include "gameglobals.h"
25 ////////////////////////////////////////////////////////////////////////////////
29 SDL_Surface
*backs
[9];
30 SpriteBank banks
[257];
32 //int disableSound = 0;
44 #define SOUND_DISABLED (vmGVars[GVAR_SOUND_DISABLED]!=0)
47 ////////////////////////////////////////////////////////////////////////////////
48 __attribute__((__noreturn__
)) __attribute__((format(printf
, 1, 2))) void fatal (const char *fmt
, ...) {
51 fprintf(stderr
, "AWISH FATAL: ");
53 vfprintf(stderr
, fmt
, ap
);
55 fprintf(stderr
, "\n");
60 ////////////////////////////////////////////////////////////////////////////////
61 // These values are not magical, just the default values Marsaglia used.
62 // Any pair of unsigned integers should be fine.
63 #define DEFAULT_M_W (521288629LL)
64 #define DEFAULT_M_Z (362436069LL)
66 static Uint32 m_w
= DEFAULT_M_W
;
67 static Uint32 m_z
= DEFAULT_M_Z
;
70 Uint32
getSeedH (void) {
75 Uint32
getSeedL (void) {
80 Uint32
getSeed (void) {
85 /* from system time: long x = dt.ToFileTime(); SetSeed((uint)(x >> 16), (uint)(x % 4294967296)); */
86 void setSeedH (Uint32 u
) {
87 m_z
= u
? u
: DEFAULT_M_Z
;
91 void setSeedL (Uint32 u
) {
92 m_w
= u
? u
: DEFAULT_M_W
;
96 void setSeedHL (Uint32 h
, Uint32 l
) {
102 void setSeed (Uint32 u
) {
107 Uint32
randUInt32 (void) {
110 m_z
= 36969*(m_z
&65535)+(m_z
>>16);
111 m_w
= 18000*(m_w
&65535)+(m_w
>>16);
113 if (m_w
== 0) m_w
= DEFAULT_M_Z
;
114 if (m_z
== 0) m_z
= DEFAULT_M_Z
;
119 // the magic number below is 1/(2^32 + 2)
120 // uniform: (randUInt32()+1.0)*2.328306435454494e-10;
121 // the result is strictly between 0 and 1.
124 ////////////////////////////////////////////////////////////////////////////////
125 // return vm code size
126 int loadCodeFile (ResFile
*resfile
, int pc
, int idx
, int asmodule
) {
127 int rsz
= 0, res
= 0;
128 uint8_t *buf
= loadResFile(resfile
, idx
, &rsz
);
130 if (buf
== NULL
) return -1;
132 res
= vmLoadCodeFileFromDump(buf
, rsz
, pc
, vmMaxGVar
, vmMaxTVar
, asmodule
?NULL
:&vmMaxGVar
, asmodule
?NULL
:&vmMaxTVar
);
138 ////////////////////////////////////////////////////////////////////////////////
139 #include "vm_gamelabelsdef.c"
140 void initLabels (void) {
141 #include "vm_gamelabelsinit.c"
145 ////////////////////////////////////////////////////////////////////////////////
146 #ifndef AWISH_NO_SOUND
147 typedef struct SoundInfo
{
148 struct SoundInfo
*next
;
153 static SoundInfo
*sndlist
= NULL
;
156 static SoundInfo
*findSound (int idx
) {
157 for (SoundInfo
*snd
= sndlist
; snd
!= NULL
; snd
= snd
->next
) if (snd
->idx
== idx
) return snd
;
162 int loadSound (int idx
) {
163 SoundInfo
*snd
= findSound(idx
);
166 Mix_Chunk
*data
= loadSoundFile(&sndfile
, idx
);
169 snd
= malloc(sizeof(SoundInfo
));
180 return (snd
!= NULL
) ? 0 : -1;
184 int unloadSound (int idx
) {
187 for (p
= NULL
, snd
= sndlist
; snd
!= NULL
; p
= snd
, snd
= snd
->next
) {
188 if (snd
->idx
== idx
) {
189 Mix_FreeChunk(snd
->data
);
190 if (p
!= NULL
) p
->next
= snd
->next
; else sndlist
= snd
->next
;
200 int isSoundLoaded (int idx
) {
201 return findSound(idx
) ? 1 : 0;
205 int playSound (int idx
, int chan
) {
206 if (!SOUND_DISABLED
) {
207 SoundInfo
*snd
= findSound(idx
);
210 if (loadSound(idx
) != 0) return -1;
211 snd
= findSound(idx
);
212 if (snd
== NULL
) return -1;
215 return Mix_PlayChannel(chan
, snd
->data
, 0);
221 int stopChannel (int chan
) {
222 if (!SOUND_DISABLED
) Mix_HaltChannel(chan
);
227 int isChannelPlaying (int chan
) {
228 return Mix_Playing(chan
);
232 void unloadAllSounds (void) {
233 Mix_HaltChannel(-1); // stop all sounds
234 while (sndlist
!= NULL
) {
235 SoundInfo
*c
= sndlist
;
238 Mix_FreeChunk(c
->data
);
245 int loadSound (int idx
) {
250 int unloadSound (int idx
) {
255 int isSoundLoaded (int idx
) {
260 int playSound (int idx
, int chan
) {
265 int stopChannel (int chan
) {
270 int isChannelPlaying (int chan
) {
275 void unloadAllSounds (void) {
280 ////////////////////////////////////////////////////////////////////////////////
281 // return # of sprites loaded or <0 on error
282 int loadSpriteBankFromFile (SpriteBank
*bank
, const char *fname
) {
286 if ((buf
= loadDiskFileEx(fname
, &sz
)) == NULL
) return -1;
287 if (sz
< 3) { free(buf
); return -1; }
289 for (int f
= bank
->count
-1; f
>= 0; --f
) {
290 SDL_FreeSurface(bank
->spr
[f
][1]);
291 SDL_FreeSurface(bank
->spr
[f
][0]);
294 while (pos
+4 <= sz
) {
295 int h
= ((Uint32
)buf
[pos
+0])+256*((Uint32
)buf
[pos
+1]);
296 int w
= ((Uint32
)buf
[pos
+2])+256*((Uint32
)buf
[pos
+3]);
299 if (h
> 0 && w
> 0) {
300 SDL_Surface
*s0
= createSurface(w
*2, h
*2);
301 SDL_Surface
*s1
= createSurface(w
*2, h
*2);
303 if (!s0
|| !s1
) { free(buf
); return -1; }
305 for (int y
= 0; y
< h
; ++y
) {
306 for (int x
= 0; x
< w
; ++x
) {
308 putPixel2x(s0
, x
, y
, buf
[pos
]);
309 putPixel2x(s1
, w
-x
-1, y
, buf
[pos
]);
314 bank
->spr
[bank
->count
][0] = s0
;
315 bank
->spr
[bank
->count
][1] = s1
;
324 ////////////////////////////////////////////////////////////////////////////////
336 int size
; // # of slots
341 #define MAX_LAYER (63)
342 static SpriteLayer spLayers
[MAX_LAYER
+1];
343 static int spLayersInitialized
= 0;
346 void clearSpriteLayers (void) {
347 if (!spLayersInitialized
) {
348 for (int f
= 0; f
<= MAX_LAYER
; ++f
) {
349 spLayers
[f
].size
= 0;
350 spLayers
[f
].list
= NULL
;
352 spLayersInitialized
= 1;
354 for (int f
= 0; f
<= MAX_LAYER
; ++f
) spLayers
[f
].count
= 0;
358 void addSpriteToLayer (int x
, int y
, int layer
, int bank
, int num
, int dir
, int inlevel
) {
359 //fprintf(stderr, "*x=%d, y=%d, layer=%d, bank=%d, num=%d, dir=%d, inlevel=%d\n", x, y, layer, bank, num, dir, inlevel);
360 if (layer
>= 0 && layer
<= MAX_LAYER
&&
361 bank
>= 0 && bank
<= 256 &&
362 num
>= 0 && num
< 256) {
364 if (spLayers
[layer
].count
+1 >= spLayers
[layer
].size
) {
365 int newsz
= spLayers
[layer
].size
+64;
366 SpriteInfo
*n
= realloc(spLayers
[layer
].list
, newsz
);
368 if (n
== NULL
) fatal("out of memory");
369 spLayers
[layer
].list
= n
;
370 spLayers
[layer
].size
= newsz
;
373 SpriteInfo
*si
= spLayers
[layer
].list
+(spLayers
[layer
].count
++);
380 si
->inlevel
= inlevel
;
385 void levelDrawSpriteLayers (SDL_Surface
*frame
, int visx
, int visy
, int visw
, int vish
) {
392 SDL_SetClipRect(frame
, &rc
);
393 for (int f
= MAX_LAYER
; f
>= 0; --f
) {
394 SpriteInfo
*list
= spLayers
[f
].list
;
396 if (list
== NULL
&& spLayers
[f
].count
!= 0) {
397 fatal("WTF? f=%d; count=%d", f
, spLayers
[f
].count
);
399 for (int c
= spLayers
[f
].count
; c
> 0; --c
, ++list
) {
401 list
->dir
>= 0 && list
->dir
<= 1 &&
402 list
->bank
>= 0 && list
->bank
<= 256 &&
403 list
->num
>= 0 && list
->num
< banks
[list
->bank
].count
&&
404 banks
[list
->bank
].spr
[list
->num
][list
->dir
]) {
405 blitSurface2x(frame
, visx
+list
->x
, visy
+list
->y
, banks
[list
->bank
].spr
[list
->num
][list
->dir
]);
410 SDL_SetClipRect(frame
, NULL
);
411 for (int f
= MAX_LAYER
; f
>= 0; --f
) {
412 SpriteInfo
*list
= spLayers
[f
].list
;
414 if (list
== NULL
) continue;
415 for (int c
= spLayers
[f
].count
; c
> 0; --c
, ++list
) {
416 //fprintf(stderr, ":x=%d, y=%d, layer=%d, bank=%d, num=%d, dir=%d, inlevel=%d\n", list->x, list->y, f, list->bank, list->num, list->dir, list->inlevel);
417 if (!list
->inlevel
&&
418 list
->dir
>= 0 && list
->dir
<= 1 &&
419 list
->bank
>= 0 && list
->bank
<= 256 &&
420 list
->num
>= 0 && list
->num
< banks
[list
->bank
].count
&&
421 banks
[list
->bank
].spr
[list
->num
][list
->dir
]) {
422 blitSurface2x(frame
, list
->x
, list
->y
, banks
[list
->bank
].spr
[list
->num
][list
->dir
]);
429 ////////////////////////////////////////////////////////////////////////////////
430 typedef struct Poly
{
444 static Poly
*plist
= NULL
, *ptail
= NULL
;
447 void pmClear (void) {
448 while (plist
!= NULL
) {
452 if (c
->points
!= NULL
) free(c
->points
);
455 ptail
= plist
= NULL
;
459 void pmStart (int ofsx
, int ofsy
, int scale
, int angle
) {
460 Poly
*p
= calloc(1, sizeof(Poly
));
462 if (p
== NULL
) fatal("out of memory");
468 p
->used
= p
->size
= 0;
471 if (ptail
!= NULL
) ptail
->next
= p
; else plist
= p
;
476 void pmAddPoint (int x
, int y
) {
478 if (ptail
->used
+2 > ptail
->size
) {
479 int newsz
= ptail
->size
+128;
480 int *np
= realloc(ptail
->points
, newsz
*sizeof(int));
482 if (np
== NULL
) fatal("out of memory");
486 ptail
->points
[ptail
->used
++] = x
;
487 ptail
->points
[ptail
->used
++] = y
;
492 void pmDone (int color
, int alpha
) {
493 if (ptail
!= NULL
&& ptail
->used
> 0) {
494 if (color
< 0) color
= 0; else if (color
> 255) color
= 255;
495 if (alpha
< 0) alpha
= 0; else if (alpha
> 255) alpha
= 255;
496 ptail
->color
= color
;
497 ptail
->alpha
= alpha
;
502 void pmDraw (SDL_Surface
*frame
) {
503 for (Poly
*p
= plist
; p
!= NULL
; p
= p
->next
) {
504 if (p
->used
> 0 && p
->alpha
> 0) {
505 polymodStart(p
->ofsx
, p
->ofsy
, p
->scale
, p
->angle
);
506 for (int f
= 0; f
< p
->used
; f
+= 2) polymodAddPoint(p
->points
[f
], p
->points
[f
+1]);
508 polymodFill(frame
, p
->color
, p
->alpha
);
514 ////////////////////////////////////////////////////////////////////////////////
515 typedef struct Text
{
528 static Text
*tlist
= NULL
, *ttail
= NULL
;
531 void textClear (void) {
532 while (tlist
!= NULL
) {
536 if (c
->str
) free(c
->str
);
543 void textAdd (const char *str
, int len
, int x
, int y
, int scale
, int angle
, int color
, int alpha
) {
546 if (str
== NULL
) return;
547 if (len
< 0) len
= strlen(str
);
548 if ((p
= calloc(1, sizeof(Text
))) == NULL
) fatal("out of memory");
549 if ((p
->str
= calloc(len
+1, 1)) == NULL
) { free(p
); fatal("out of memory"); }
550 if (color
< 0) color
= 0; else if (color
> 255) color
= 255;
551 if (alpha
< 0) alpha
= 0; else if (alpha
> 255) alpha
= 255;
558 if (len
> 0) memcpy(p
->str
, str
, len
);
560 if (ttail
!= NULL
) ttail
->next
= p
; else tlist
= p
;
565 void textDraw (SDL_Surface
*frame
) {
566 for (Text
*t
= tlist
; t
!= NULL
; t
= t
->next
) {
567 polymodStr(frame
, t
->str
, t
->x
, t
->y
, t
->scale
, t
->angle
, t
->color
, t
->alpha
);