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];
44 ////////////////////////////////////////////////////////////////////////////////
45 __attribute__((__noreturn__
)) __attribute__((format(printf
, 1, 2))) void fatal (const char *fmt
, ...) {
48 fprintf(stderr
, "AWISH FATAL: ");
50 vfprintf(stderr
, fmt
, ap
);
52 fprintf(stderr
, "\n");
57 ////////////////////////////////////////////////////////////////////////////////
58 // These values are not magical, just the default values Marsaglia used.
59 // Any pair of unsigned integers should be fine.
60 #define DEFAULT_M_W (521288629LL)
61 #define DEFAULT_M_Z (362436069LL)
63 static Uint32 m_w
= DEFAULT_M_W
;
64 static Uint32 m_z
= DEFAULT_M_Z
;
67 Uint32
getSeedH (void) {
72 Uint32
getSeedL (void) {
77 Uint32
getSeed (void) {
82 /* from system time: long x = dt.ToFileTime(); SetSeed((uint)(x >> 16), (uint)(x % 4294967296)); */
83 void setSeedH (Uint32 u
) {
84 m_z
= u
? u
: DEFAULT_M_Z
;
88 void setSeedL (Uint32 u
) {
89 m_w
= u
? u
: DEFAULT_M_W
;
93 void setSeedHL (Uint32 h
, Uint32 l
) {
99 void setSeed (Uint32 u
) {
104 Uint32
randUInt32 (void) {
107 m_z
= 36969*(m_z
&65535)+(m_z
>>16);
108 m_w
= 18000*(m_w
&65535)+(m_w
>>16);
110 if (m_w
== 0) m_w
= DEFAULT_M_Z
;
111 if (m_z
== 0) m_z
= DEFAULT_M_Z
;
116 // the magic number below is 1/(2^32 + 2)
117 // uniform: (randUInt32()+1.0)*2.328306435454494e-10;
118 // the result is strictly between 0 and 1.
121 ////////////////////////////////////////////////////////////////////////////////
122 // return vm code size
123 int loadCodeFile (ResFile
*resfile
, int pc
, int idx
, int asmodule
) {
124 int rsz
= 0, res
= 0;
125 uint8_t *buf
= loadResFile(resfile
, idx
, &rsz
);
127 if (buf
== NULL
) return -1;
129 res
= vmLoadCodeFileFromDump(buf
, rsz
, pc
, vmMaxGVar
, vmMaxTVar
, asmodule
?NULL
:&vmMaxGVar
, asmodule
?NULL
:&vmMaxTVar
);
135 ////////////////////////////////////////////////////////////////////////////////
136 #include "vm_gamelabelsdef.c"
137 void initLabels (void) {
138 #include "vm_gamelabelsinit.c"
142 ////////////////////////////////////////////////////////////////////////////////
143 #ifndef AWISH_NO_SOUND
144 typedef struct SoundInfo
{
145 struct SoundInfo
*next
;
150 static SoundInfo
*sndlist
= NULL
;
153 static SoundInfo
*findSound (int idx
) {
154 for (SoundInfo
*snd
= sndlist
; snd
!= NULL
; snd
= snd
->next
) if (snd
->idx
== idx
) return snd
;
159 int loadSound (int idx
) {
160 SoundInfo
*snd
= findSound(idx
);
163 Mix_Chunk
*data
= loadSoundFile(&sndfile
, idx
);
166 snd
= malloc(sizeof(SoundInfo
));
177 return (snd
!= NULL
) ? 0 : -1;
181 int unloadSound (int idx
) {
184 for (p
= NULL
, snd
= sndlist
; snd
!= NULL
; p
= snd
, snd
= snd
->next
) {
185 if (snd
->idx
== idx
) {
186 Mix_FreeChunk(snd
->data
);
187 if (p
!= NULL
) p
->next
= snd
->next
; else sndlist
= snd
->next
;
197 int isSoundLoaded (int idx
) {
198 return findSound(idx
) ? 1 : 0;
202 int playSound (int idx
, int chan
) {
204 SoundInfo
*snd
= findSound(idx
);
207 if (loadSound(idx
) != 0) return -1;
208 snd
= findSound(idx
);
209 if (snd
== NULL
) return -1;
212 return Mix_PlayChannel(chan
, snd
->data
, 0);
218 int stopChannel (int chan
) {
219 if (!disableSound
) Mix_HaltChannel(chan
);
224 int isChannelPlaying (int chan
) {
225 return Mix_Playing(chan
);
229 void unloadAllSounds (void) {
230 Mix_HaltChannel(-1); // stop all sounds
231 while (sndlist
!= NULL
) {
232 SoundInfo
*c
= sndlist
;
235 Mix_FreeChunk(c
->data
);
242 int loadSound (int idx
) {
247 int unloadSound (int idx
) {
252 int isSoundLoaded (int idx
) {
257 int playSound (int idx
, int chan
) {
262 int stopChannel (int chan
) {
267 int isChannelPlaying (int chan
) {
272 void unloadAllSounds (void) {
277 ////////////////////////////////////////////////////////////////////////////////
278 // return # of sprites loaded or <0 on error
279 int loadSpriteBankFromFile (SpriteBank
*bank
, const char *fname
) {
283 if ((buf
= loadDiskFileEx(fname
, &sz
)) == NULL
) return -1;
284 if (sz
< 3) { free(buf
); return -1; }
286 for (int f
= bank
->count
-1; f
>= 0; --f
) {
287 SDL_FreeSurface(bank
->spr
[f
][1]);
288 SDL_FreeSurface(bank
->spr
[f
][0]);
291 while (pos
+4 <= sz
) {
292 int h
= ((Uint32
)buf
[pos
+0])+256*((Uint32
)buf
[pos
+1]);
293 int w
= ((Uint32
)buf
[pos
+2])+256*((Uint32
)buf
[pos
+3]);
296 if (h
> 0 && w
> 0) {
297 SDL_Surface
*s0
= createSurface(w
*2, h
*2);
298 SDL_Surface
*s1
= createSurface(w
*2, h
*2);
300 if (!s0
|| !s1
) { free(buf
); return -1; }
302 for (int y
= 0; y
< h
; ++y
) {
303 for (int x
= 0; x
< w
; ++x
) {
305 putPixel2x(s0
, x
, y
, buf
[pos
]);
306 putPixel2x(s1
, w
-x
-1, y
, buf
[pos
]);
311 bank
->spr
[bank
->count
][0] = s0
;
312 bank
->spr
[bank
->count
][1] = s1
;
321 ////////////////////////////////////////////////////////////////////////////////
333 int size
; // # of slots
338 #define MAX_LAYER (63)
339 static SpriteLayer spLayers
[MAX_LAYER
+1];
340 static int spLayersInitialized
= 0;
343 void clearSpriteLayers (void) {
344 if (!spLayersInitialized
) {
345 for (int f
= 0; f
<= MAX_LAYER
; ++f
) {
346 spLayers
[f
].size
= 0;
347 spLayers
[f
].list
= NULL
;
349 spLayersInitialized
= 1;
351 for (int f
= 0; f
<= MAX_LAYER
; ++f
) spLayers
[f
].count
= 0;
355 void addSpriteToLayer (int x
, int y
, int layer
, int bank
, int num
, int dir
, int inlevel
) {
356 //fprintf(stderr, "*x=%d, y=%d, layer=%d, bank=%d, num=%d, dir=%d, inlevel=%d\n", x, y, layer, bank, num, dir, inlevel);
357 if (layer
>= 0 && layer
<= MAX_LAYER
&&
358 bank
>= 0 && bank
<= 256 &&
359 num
>= 0 && num
< 256) {
361 if (spLayers
[layer
].count
+1 >= spLayers
[layer
].size
) {
362 int newsz
= spLayers
[layer
].size
+64;
363 SpriteInfo
*n
= realloc(spLayers
[layer
].list
, newsz
);
365 if (n
== NULL
) fatal("out of memory");
366 spLayers
[layer
].list
= n
;
367 spLayers
[layer
].size
= newsz
;
370 SpriteInfo
*si
= spLayers
[layer
].list
+(spLayers
[layer
].count
++);
377 si
->inlevel
= inlevel
;
382 void levelDrawSpriteLayers (SDL_Surface
*frame
, int visx
, int visy
, int visw
, int vish
) {
389 SDL_SetClipRect(frame
, &rc
);
390 for (int f
= MAX_LAYER
; f
>= 0; --f
) {
391 SpriteInfo
*list
= spLayers
[f
].list
;
393 if (list
== NULL
&& spLayers
[f
].count
!= 0) {
394 fatal("WTF? f=%d; count=%d", f
, spLayers
[f
].count
);
396 for (int c
= spLayers
[f
].count
; c
> 0; --c
, ++list
) {
398 list
->dir
>= 0 && list
->dir
<= 1 &&
399 list
->bank
>= 0 && list
->bank
<= 256 &&
400 list
->num
>= 0 && list
->num
< banks
[list
->bank
].count
&&
401 banks
[list
->bank
].spr
[list
->num
][list
->dir
]) {
402 blitSurface2x(frame
, visx
+list
->x
, visy
+list
->y
, banks
[list
->bank
].spr
[list
->num
][list
->dir
]);
407 SDL_SetClipRect(frame
, NULL
);
408 for (int f
= MAX_LAYER
; f
>= 0; --f
) {
409 SpriteInfo
*list
= spLayers
[f
].list
;
411 if (list
== NULL
) continue;
412 for (int c
= spLayers
[f
].count
; c
> 0; --c
, ++list
) {
413 //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);
414 if (!list
->inlevel
&&
415 list
->dir
>= 0 && list
->dir
<= 1 &&
416 list
->bank
>= 0 && list
->bank
<= 256 &&
417 list
->num
>= 0 && list
->num
< banks
[list
->bank
].count
&&
418 banks
[list
->bank
].spr
[list
->num
][list
->dir
]) {
419 blitSurface2x(frame
, list
->x
, list
->y
, banks
[list
->bank
].spr
[list
->num
][list
->dir
]);
426 ////////////////////////////////////////////////////////////////////////////////
427 typedef struct Poly
{
441 static Poly
*plist
= NULL
, *ptail
= NULL
;
444 void pmClear (void) {
445 while (plist
!= NULL
) {
449 if (c
->points
!= NULL
) free(c
->points
);
452 ptail
= plist
= NULL
;
456 void pmStart (int ofsx
, int ofsy
, int scale
, int angle
) {
457 Poly
*p
= calloc(1, sizeof(Poly
));
459 if (p
== NULL
) fatal("out of memory");
465 p
->used
= p
->size
= 0;
468 if (ptail
!= NULL
) ptail
->next
= p
; else plist
= p
;
473 void pmAddPoint (int x
, int y
) {
475 if (ptail
->used
+2 > ptail
->size
) {
476 int newsz
= ptail
->size
+128;
477 int *np
= realloc(ptail
->points
, newsz
*sizeof(int));
479 if (np
== NULL
) fatal("out of memory");
483 ptail
->points
[ptail
->used
++] = x
;
484 ptail
->points
[ptail
->used
++] = y
;
489 void pmDone (int color
, int alpha
) {
490 if (ptail
!= NULL
&& ptail
->used
> 0) {
491 if (color
< 0) color
= 0; else if (color
> 255) color
= 255;
492 if (alpha
< 0) alpha
= 0; else if (alpha
> 255) alpha
= 255;
493 ptail
->color
= color
;
494 ptail
->alpha
= alpha
;
499 void pmDraw (SDL_Surface
*frame
) {
500 for (Poly
*p
= plist
; p
!= NULL
; p
= p
->next
) {
501 if (p
->used
> 0 && p
->alpha
> 0) {
502 polymodStart(p
->ofsx
, p
->ofsy
, p
->scale
, p
->angle
);
503 for (int f
= 0; f
< p
->used
; f
+= 2) polymodAddPoint(p
->points
[f
], p
->points
[f
+1]);
505 polymodFill(frame
, p
->color
, p
->alpha
);
511 ////////////////////////////////////////////////////////////////////////////////
512 typedef struct Text
{
525 static Text
*tlist
= NULL
, *ttail
= NULL
;
528 void textClear (void) {
529 while (tlist
!= NULL
) {
533 if (c
->str
) free(c
->str
);
540 void textAdd (const char *str
, int len
, int x
, int y
, int scale
, int angle
, int color
, int alpha
) {
543 if (str
== NULL
) return;
544 if (len
< 0) len
= strlen(str
);
545 if ((p
= calloc(1, sizeof(Text
))) == NULL
) fatal("out of memory");
546 if ((p
->str
= calloc(len
+1, 1)) == NULL
) { free(p
); fatal("out of memory"); }
547 if (color
< 0) color
= 0; else if (color
> 255) color
= 255;
548 if (alpha
< 0) alpha
= 0; else if (alpha
> 255) alpha
= 255;
555 if (len
> 0) memcpy(p
->str
, str
, len
);
557 if (ttail
!= NULL
) ttail
->next
= p
; else tlist
= p
;
562 void textDraw (SDL_Surface
*frame
) {
563 for (Text
*t
= tlist
; t
!= NULL
; t
= t
->next
) {
564 polymodStr(frame
, t
->str
, t
->x
, t
->y
, t
->scale
, t
->angle
, t
->color
, t
->alpha
);