1 /* coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
2 * Understanding is not required. Only obedience.
3 * Based on Jet-Set Willy, v1.0.1 by <Florent.Guillaume@ens.fr>
4 * Linux port and preliminary sound by jmd@dcs.ed.ac.uk
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 import arsd
.simpledisplay
;
22 import arsd
.simpleaudio
;
31 // ////////////////////////////////////////////////////////////////////////// //
32 __gshared
bool debugHarmlessMonsters
= false;
33 __gshared WillySavePos
[10] gameSaves
;
34 __gshared
bool gamePaused
= false;
35 __gshared
int gvGameFlash
= 0;
36 __gshared
bool gameJustStarted
= true;
39 // ////////////////////////////////////////////////////////////////////////// //
40 void jumpToRoom (ref Willy willy
, int dir
) {
41 auto room
= gameRooms
[willy
.roomnum
];
42 if (room
.exits
[dir
] < 0) return;
43 willy
.gotoRoom(room
.exits
[dir
]);
47 // ////////////////////////////////////////////////////////////////////////// //
48 __gshared
int gvTitleFadingOut
;
50 void gsTitleEnter (ref Willy willy
) {
52 blitType
= BlitType
.Normal
;
54 jssPlaySfx("jss_titl");
57 void gsTitleExit (ref Willy willy
) {
59 gameJustStarted
= true;
62 void gsTitleKeys (ref Willy willy
, KeyEvent evt
) {
63 if (!evt
.pressed
) return;
65 case Key
.Space
: case Key
.Enter
:
66 if (gvTitleFadingOut
) {
68 willy
.switchState(GameState
.Playing
);
77 void gsTitleStep (ref Willy willy
) {
80 void gsTitleDraw (ref Willy willy
) {
81 //drawStr(4, vbufH-12, "items: %s".format(countAllItems()), rgbcol(255, 127, 0));
82 drawStr
!"d10"(10, 10, "Jet Set Willy II", rgbcol(255, 127, 0));
83 drawStr
!"dos"(10, 22, "Jet Set Willy II", rgbcol(255, 127, 0));
84 drawStrProp
!"dos"(10, 32, "Jet Set Willy II", rgbcol(255, 127, 0));
85 drawStrProp(10, 42, "Jet Set Willy II", rgbcol(255, 127, 0));
86 if (gvTitleFadingOut
) {
87 blitShine
= -gvTitleFadingOut
*10;
88 if (++gvTitleFadingOut
>= 20) {
90 willy
.switchState(GameState
.Playing
);
96 // ////////////////////////////////////////////////////////////////////////// //
97 void gsGameKeysRestoreSaves (ref Willy willy
, KeyEvent evt
) {
101 if (evt
.modifierState
&ModifierState
.shift
) { willy
.restartGame(); willy
.switchState(GameState
.Playing
); break; }
102 if (evt
.modifierState
&ModifierState
.alt
) { if (willy
.restoreSavePos()) willy
.switchState(GameState
.Playing
); break; }
107 if (evt
.modifierState
&ModifierState
.shift
) { willy
.restartGame(); willy
.switchState(GameState
.Playing
); break; }
108 if (evt
.modifierState
&ModifierState
.alt
) { if (willy
.restoreSavePosPrev()) willy
.switchState(GameState
.Playing
); break; }
109 gamePaused
= !gamePaused
;
112 case Key
.N0
: .. case Key
.N9
:
115 if (evt
.modifierState
&ModifierState
.shift
) {
116 if (willy
.restoreSave(gameSaves
[evt
.key
-Key
.N0
])) willy
.switchState(GameState
.Playing
);
120 if (evt
.modifierState
&ModifierState
.alt
) {
121 if (!willy
.dead
&& willy
.gstate
!= GameState
.Title
&& willy
.gstate
!= GameState
.Dead
) {
122 gameSaves
[evt
.key
-Key
.N0
] = willy
.saveSave();
133 // shared by all states
134 void gsGameKeys (ref Willy willy
, KeyEvent evt
) {
135 willy
.gsGameKeysRestoreSaves(evt
);
139 if (evt
.modifierState
&ModifierState
.shift
) { willy
.jumpToRoom(JSWRoom
.Exit
.Left
); break; }
141 willy
.goleft
= (evt
.pressed ?
1 : 0);
145 if (evt
.modifierState
&ModifierState
.shift
) { willy
.jumpToRoom(JSWRoom
.Exit
.Right
); break; }
147 willy
.goright
= (evt
.pressed ?
1 : 0);
151 if (evt
.modifierState
&ModifierState
.shift
) { willy
.jumpToRoom(JSWRoom
.Exit
.Up
); break; }
153 willy
.dojump
= (evt
.pressed ?
1 : 0);
157 if (evt
.modifierState
&ModifierState
.shift
) { willy
.jumpToRoom(JSWRoom
.Exit
.Down
); break; }
161 willy
.dojump
= (evt
.pressed ?
1 : 0);
165 if (evt
.modifierState
&ModifierState
.alt
) { debugHarmlessMonsters
= !debugHarmlessMonsters
; break; }
168 case Key
.Space
: case Key
.Enter
:
171 if (!willy
.restoreSavePos()) willy
.restartGame();
172 willy
.switchState(GameState
.Playing
);
176 case Key
.W
: // alt+shift+w: collect all items
178 if (evt
.modifierState
&ModifierState
.shift
&& evt
.modifierState
&ModifierState
.alt
) { JSWRoom
.cheatCollectAllItems(); break; }
186 // shared by all states
187 void gsGameStep (ref Willy willy
) {
188 if (gamePaused
) return;
189 auto room
= gameRooms
[willy
.roomnum
];
190 if (room
is null) assert(0, "wtf?!");
191 if (willy
.dead
) return;
193 if (willy
.dead
) willy
.switchState(GameState
.Dead
); // willy just died, switch state
195 ++frameno
; // let it move! (animate lifts, items, etc.)
196 willy
.room
.stepSpecial(willy
);
198 if (willy
.dead
) return; // willy just died
201 room
.buildColMap(willy
);
202 // check monster collision here
203 if (!debugHarmlessMonsters
&& !willy
.dead
&& willy
.invulnTimer
== 0 && willy
.checkMonsterCollision()) {
207 // if willy should exit to another room, do it here
212 // shared by all states
213 void gsGameDraw (ref Willy willy
) {
214 auto room
= gameRooms
[willy
.roomnum
];
217 room
.drawMonsters(willy
);
218 willy
.draw(debugHarmlessMonsters
);
223 // ////////////////////////////////////////////////////////////////////////// //
224 void gsPlayingEnter (ref Willy willy
) {
226 if (willy
.dead
) willy
.newLife();
229 blitType
= BlitType
.Normal
;
230 if (gameJustStarted
) {
231 gameJustStarted
= false;
233 //willy.gotoRoom(0x21); // bedroom
234 //{ willy.gotoRoom(0x77); willy.setXY(120, 90); } // rocket
235 //willy.gotoRoom(0x4b); // rigor mortis
236 //willy.gotoRoom(0x4c); // crypt
237 //willy.gotoRoom(0x3b); // hell
238 //{ willy.gotoRoom(0x71); willy.setXY(10, 38); } // tribbles
239 //willy.gotoRoom(0x7e); // eggoids
240 //willy.gotoRoom(0x67); // foot
241 //willy.gotoRoom(0x60); // beam down
242 //willy.gotoRoom(0x7f); // beam up
243 //{ willy.gotoRoom(0x50); willy.setXY(50, 88); } // isle
244 //{ willy.gotoRoom(0x44); willy.setXY(50, 88); } // bell
245 //willy.gotoRoom(0x79); // invasion
246 //willy.gotoRoom(0x47); // trip switch
247 //{ willy.gotoRoom(0x38); willy.setXY(10, 96); } // yacht
251 void gsPlayingExit (ref Willy willy
) {
254 void gsPlayingKeys (ref Willy willy
, KeyEvent evt
) {
255 willy
.gsGameKeys(evt
);
258 void gsPlayingStep (ref Willy willy
) {
260 auto room
= willy
.room
;
261 switch (room
.sptype
) {
262 case JSWRoom
.SpType
.Rocket
:
263 if (room
.countItems
== 0 && willy
.y
== 0x30) {
264 willy
.rocket_cnt
= 0x80;
265 willy
.switchState(GameState
.Rocket
);
272 void gsPlayingDraw (ref Willy willy
) {
273 if (gvGameFlash
> 0) {
281 blitType
= BlitType
.Green
;
283 blitType
= BlitType
.Normal
;
289 // ////////////////////////////////////////////////////////////////////////// //
290 __gshared
int gvDeathFadingOut
;
292 void gsDeadEnter (ref Willy willy
) {
293 jssPlaySfx("jss_dead");
295 blitType
= BlitType
.Red
;
296 gvDeathFadingOut
= 0;
299 void gsDeadExit (ref Willy willy
) {
302 void gsDeadKeys (ref Willy willy
, KeyEvent evt
) {
304 case Key
.Space
: case Key
.Enter
:
306 if (!willy
.restoreSavePos()) willy
.restartGame();
307 willy
.switchState(GameState
.Playing
);
313 willy
.gsGameKeysRestoreSaves(evt
);
316 void gsDeadStep (ref Willy willy
) {
317 //willy.gsGameStep();
318 if (blitShine
> -180) --blitShine
;
321 void gsDeadDraw (ref Willy willy
) {
326 // ////////////////////////////////////////////////////////////////////////// //
327 void gsRocketEnter (ref Willy willy
) {
330 void gsRocketExit (ref Willy willy
) {
333 void gsRocketKeys (ref Willy willy
, KeyEvent evt
) {
334 willy
.gsGameKeys(evt
);
337 void gsRocketStep (ref Willy willy
) {
341 void gsRocketDraw (ref Willy willy
) {
346 // ////////////////////////////////////////////////////////////////////////// //
347 void gsTeleportEnter (ref Willy willy
) {
350 void gsTeleportExit (ref Willy willy
) {
353 void gsTeleportKey (ref Willy willy
, KeyEvent evt
) {
354 willy
.gsGameKeys(evt
);
357 void gsTeleportStep (ref Willy willy
) {
361 void gsTeleportDraw (ref Willy willy
) {
366 // ////////////////////////////////////////////////////////////////////////// //
367 void gsBoatEnter (ref Willy willy
) {
370 void gsBoatExit (ref Willy willy
) {
373 void gsBoatKey (ref Willy willy
, KeyEvent evt
) {
374 willy
.gsGameKeys(evt
);
377 void gsBoatStep (ref Willy willy
) {
381 void gsBoatDraw (ref Willy willy
) {
386 // ////////////////////////////////////////////////////////////////////////// //
387 // if forced, do leave/enter even if state wasn't changed
388 void switchState (ref Willy willy
, GameState newstate
, bool force
=false) {
389 if (!force
&& willy
.gstate
== newstate
) return;
390 int newdead
= 0; // 0: don't change; <0: dead; >0: alive
391 final switch (willy
.gstate
) {
392 case GameState
.Title
: gsTitleExit(willy
); break;
393 case GameState
.Playing
: gsPlayingExit(willy
); newdead
= 1; break;
394 case GameState
.Dead
: gsDeadExit(willy
); newdead
= -1; break;
395 case GameState
.Rocket
: gsRocketExit(willy
); newdead
= 1; break;
396 case GameState
.Teleport
: gsTeleportExit(willy
); newdead
= 1; break;
397 case GameState
.Boat
: gsBoatExit(willy
); newdead
= 1; break;
399 willy
.gstate
= newstate
;
401 if (willy
.dead
&& newdead
> 0) willy
.newLife();
402 if (!willy
.dead
&& newdead
< 0) willy
.dead
= true; //FIXME
404 final switch (willy
.gstate
) {
405 case GameState
.Title
: gsTitleEnter(willy
); break;
406 case GameState
.Playing
: gsPlayingEnter(willy
); break;
407 case GameState
.Dead
: gsDeadEnter(willy
); break;
408 case GameState
.Rocket
: gsRocketEnter(willy
); break;
409 case GameState
.Teleport
: gsTeleportEnter(willy
); break;
410 case GameState
.Boat
: gsBoatEnter(willy
); break;
415 void stepState (ref Willy willy
) {
416 final switch (willy
.gstate
) {
417 case GameState
.Title
: gsTitleStep(willy
); break;
418 case GameState
.Playing
: gsPlayingStep(willy
); break;
419 case GameState
.Dead
: gsDeadStep(willy
); break;
420 case GameState
.Rocket
: gsRocketStep(willy
); break;
421 case GameState
.Teleport
: gsTeleportStep(willy
); break;
422 case GameState
.Boat
: gsBoatStep(willy
); break;
427 void drawState (ref Willy willy
) {
428 final switch (willy
.gstate
) {
429 case GameState
.Title
: gsTitleDraw(willy
); break;
430 case GameState
.Playing
: gsPlayingDraw(willy
); break;
431 case GameState
.Dead
: gsDeadDraw(willy
); break;
432 case GameState
.Rocket
: gsRocketDraw(willy
); break;
433 case GameState
.Teleport
: gsTeleportDraw(willy
); break;
434 case GameState
.Boat
: gsBoatDraw(willy
); break;
439 void keysState (ref Willy willy
, KeyEvent evt
) {
440 final switch (willy
.gstate
) {
441 case GameState
.Title
: gsTitleKeys(willy
, evt
); break;
442 case GameState
.Playing
: gsPlayingKeys(willy
, evt
); break;
443 case GameState
.Dead
: gsDeadKeys(willy
, evt
); break;
444 case GameState
.Rocket
: gsRocketKeys(willy
, evt
); break;
445 case GameState
.Teleport
: gsTeleportKey(willy
, evt
); break;
446 case GameState
.Boat
: gsBoatKey(willy
, evt
); break;
451 // ////////////////////////////////////////////////////////////////////////// //
452 void main (string
[] args
) {
453 registerWad("data/jetset.wad");
454 registerWad("data/music.wad", true);
456 for (int idx
= 1; idx
< args
.length
; ++idx
) {
457 if (args
[idx
] == "-file") {
458 if (args
.length
-idx
< 2) assert(0, "arg?!");
459 registerWad(args
[idx
+1]);
462 assert(0, "invalid arg");
469 scope(exit
) jssAbortSound();
471 auto sdwin
= x11gfxInit("Jet Set Willy");
481 willy
.onTakeItem
= delegate () {
483 jssPlaySfx("jss_pick");
490 willy
.switchState(GameState
.Title
, true); // forced switch
492 sdwin
.eventLoop(1000/20,
495 if (sdwin
.closed
) return;
500 import std
.format
: format
;
501 drawStr(4, vbufH
-12, "items: %s".format(countAllItems()), rgbcol(255, 127, 0));
507 delegate (KeyEvent evt
) {
508 if (sdwin
.closed
) return;
512 if (evt
.modifierState
&ModifierState
.ctrl
) { doQuit
= true; break; }
513 if (evt
.modifierState
&ModifierState
.alt
) { willy
.switchState(GameState
.Title
); break; }
518 if (evt
.modifierState
&ModifierState
.ctrl
) { willy
.switchState(GameState
.Title
); break; }
523 if (evt
.modifierState
&ModifierState
.alt
) { doQuit
= true; break; }
531 if (doQuit
) { sdwin
.close(); return; }
532 willy
.keysState(evt
);
535 delegate (MouseEvent evt
) {
536 if (sdwin
.closed
) return;
537 if (willy
.gstate
== GameState
.Title
) return;
538 if (evt
.type
== MouseEventType
.buttonPressed
) {
539 if (evt
.button
== MouseButton
.left
) {
540 willy
.setXY(evt
.x
/2, evt
.y
/2);
545 delegate (dchar ch
) {
546 if (sdwin
.closed
) return;