1 #include <SDL/SDL.h>
2 #include <SDL/SDL_image.h>
3 #include <SDL/SDL_ttf.h>
4 #include <SDL/SDL_mixer.h>
5 #include <math.h>
6 #include "tile.h"
7 #include "thing.h"
8 #include "physics.h"
9 #include "game.h"
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #ifndef __WIN32__
14 #include <sys/stat.h>
15 #include <unistd.h>
16 #include <errno.h>
17 #include <pwd.h>
18 #endif
19
20 #define CAMSCROLL 15
21 #define SCR_WIDTH 780
22 #define SCR_HEIGHT 600
23 #define SCR_BPP 32
24 #define SPR_SIZE 30
25 #define CAMSENSE 60
26 #define LVLMAX 500
27 #define THINGMAX 250
28 #define BOSSMAX 10
29 #define PARTICLEMAX 2500
30 #define ROOMMAX 100
31 #define TELERADIUS 8
32 #define TELEMODIF 0.175
33 #define TELECAP 17.5
34 #define TELEDELAY 12
35 #define TELEACCEL 3
36 #define TELEFAILSPARKS 5
37 #define DEATHDELAY 25
38 #define SNAPSIZE 3
39 #define SNAPVEL 2
40 #define TEXTSHADOW -1
41 #define BKGSCROLL 0.5
42 #define CURSORRADIUS 4
43 #define SOUNDDIST 150
44 #define MFRAGTOTAL 100
45
46 #define WALK_SPEED 2.5
47 #define RUN_SPEED 4
48
49 #define WMEDPOS 75
50 #define OMEDPOS 165
51 #define BMEDPOS 255
52 #define RMEDPOS 375
53 #define GMEDPOS 510
54 #define PMEDPOS 675
55 #define MEDINFODIST 45
56
57 #define GREENFLAG 0x1
58 #define REDFLAG 0x2
59 #define CREATORFLAG 0x4
60 #define NOCOLLIDEFLAG 0x8
61 #define KEYPRESSED 0x10
62 #define REINCARNATE 0x20
63
64 #define GAMEMAX 25
65 #define MEDALMAX 600
66 #define BKG_MAX 15
67 #define MUSIC_MAX 14
68 #define NUM_CHANNELS 8
69
70 #define FPS_LIMIT 60
71
72 #define GAME_TITLE "Beret"
73
74 #define LAST_LEVEL 67
75
76 #define A_ 0x1
77 #define B_ 0x2
78 #define C_ 0x4
79 #define D_ 0x8
80 #define E_ 0x10
81 #define F_ 0x20
82 #define G_ 0x40
83 #define H_ 0x80
84
85 #ifdef __WIN32__
86 #define DIRSEP "\\"
87 #else
88 #define DIRSEP "/"
89 #endif
90
91 #ifndef RESOURCE_PATH
92 #if defined __APPLE__
93 #define RESOURCE_PATH "Beret.app/Contents/Resources/"
94 #elif defined __WIN32__
95 #define RESOURCE_PATH ""
96 #else
97 #define RESOURCE_PATH "/usr/local/share/beret/"
98 #endif
99 #endif
100
101 #ifndef SUPPORT_PATH
102 #if defined __APPLE__
103 #define SUPPORT_PATH "Library/Application Support/Beret/"
104 #elif defined __WIN32__
105 #else
106 #define SUPPORT_PATH ".beret/"
107 #endif
108 #endif
109
110 #define QUITMOD_WIN KMOD_ALT
111 #define QUITKEY_WIN SDLK_F4
112 #define QUITMOD_LIN KMOD_CTRL
113 #define QUITKEY_LIN SDLK_c
114 #define QUITMOD_MAC KMOD_META
115 #define QUITKEY_MAC SDLK_q
116
117 #define MAX(a,b) ((a)>(b))?(a):(b)
118
119 #define UNF 1000
120 #define STORYLEN 21
121 #define CREAT1LEN 21
122 #define CREAT2LEN 21
123 #define CREAT3LEN 18
124 #define CONTROLLEN 19
125 #define MSGMAX 60
126
127
128
129 const char* creat1[CREAT1LEN] =
130 {" ",
131 "Escape - Menu (Playtest Room)",
132 "Q - Display this guide",
133 " ",
134 "F1 - Save Room",
135 "F4 - Load Room",
136 "F9 - Set time limit for level, check blue fragments, get enemy counts",
137 "F12 - All of above except set time limit",
138 " ",
139 "Home/End - Decrease/Increase room width",
140 "Page Up/Page Down - Decrease/Increase room height",
141 "- or + - Change background",
142 "[ or ] - Change music",
143 " ",
144 "I - Open object select screen - Click to select object/tile",
145 "U - Place tile at cursor or fill selection with tiles",
146 "Y - Delete tile at cursor or delete tiles in selection",
147 "O - Place object at cursor",
148 "Tab - Change selected object subtype",
149 " ",
150 "Continue to next page..."};
151
152 const char* creat2[CREAT2LEN] =
153 {" ",
154 "Left click and drag - Move object",
155 "Right click and drag - Select objects",
156 "ASDW/Arrow Keys - Move selected objects",
157 "Shift + ASDW/Arrow Keys - Move selected objects slowly",
158 "Delete/Backspace - Delete selected objects",
159 "V - Copy selected objects",
160 "< or > - Change object direction",
161 "L - Choose link for selected link blocks",
162 " ",
163 "G - Change grid",
164 "H - Toggle snap to grid",
165 "C - Toggle collision detection",
166 "R - Clear room",
167 "P - Set Beret's start position to cursor",
168 " ",
169 "1-0 - Choose number of entrance",
170 "Shift + 1-0 - Choose entrance number to connect to",
171 "E - Set room number to exit to",
172 " ",
173 "Continue to next page..."};
174
175 const char* creat3[CREAT3LEN] =
176 {" ",
177 "Notes for creating a level:",
178 " ",
179 "Room 0 is the starting room for the level. Set Beret's",
180 "position in room 0 to the desired level entry point.",
181 " ",
182 "Doors and Exit Signs have an entrance number assigned",
183 "to them, as well as an entrance number and a room number",
184 "that they connect to. Make sure these match up between",
185 "rooms or the player will get a \"file not found\" error.",
186 " ",
187 "When a level is finished, use F12 to check that all 100",
188 "Blue Medallion fragments have been placed and to assign",
189 "the fragments indices. This helps keep track of exactly",
190 "which fragments have been collected. F12 also counts the",
191 "enemies in each room so that the Red Medallion can be",
192 "collected. Use F9 to set a time limit for the level on",
193 "top of these checks."};
194
195 const char* story[STORYLEN] =
196 {"For many years, Beret was a researcher and experiment in",
197 "the Department of Telekinetics at a large research company",
198 "called the Evil Corporation. While studying telekinetics,",
199 "Beret and his research assistants succeeded in granting",
200 "Beret the power of telekinesis. Shortly after this, Beret",
201 "became disgusted with the injustices committed in the name",
202 "of scientific advance by his employers, the Three Evils of",
203 "the Evil Corporation. Beret has decided to single-handedly",
204 "destroy the entire corporation and defeat the Three Evils",
205 "using his remarkable power - a quite daunting task, due to",
206 "the high security of the Evil Corporation. Each Department",
207 "is inaccessible to anyone without the proper clearance level,",
208 "which is determined by the number of Medallions owned by that",
209 "person. Therefore, in order to reach the Three Evils, who",
210 "reside in extremely well-protected Departments, Beret will",
211 "need to collect as many Medallions as possible in each",
212 "Department that he visits in order to gain access to the next.",
213 " ",
214 "Despite his amazing power, Beret has a perilous journey ahead",
215 "of him. Only by exhibiting great cunning as well as skill",
216 "will he be able to accomplish his goal."};
217 const char* controls[CONTROLLEN] =
218 {"Running: A and D, or left arrow key and right arrow key",
219 "Walking: Hold shift",
220 "Jumping: W, up arrow key, or spacebar",
221 "Entering Doors/Reading Signs: S or down arrow key",
222 " ",
223 "Save State: F1 or 1",
224 "Load State: F4 or 4 (hold Ctrl for backup)",
225 "Restart Room: R",
226 "Exit Level: Escape",
227 "Pause Game: P",
228 " ",
229 "Telekinesis: Left mouse button",
230 "Toggle Telekinesis Guide: G or right mouse button",
231 "Toggle Cursor Movement Mode: M",
232 " ",
233 "Move Camera: I, J, K, or L",
234 " ",
235 "Toggle Full Screen: Alt+Enter",
236 "Toggle Sound: Slash"};
237 const int levelentry[5][20] = {{UNF,UNF,2,0,6,10,UNF,UNF,16,UNF,21,UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF},
238 {UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF,0,37,UNF,30,43,UNF,UNF,UNF,48,55},
239 {UNF,UNF,UNF,UNF,84,80,95,UNF,UNF,UNF,88,UNF,68,UNF,74,UNF,UNF,0,65,UNF},
240 {UNF,UNF,UNF,UNF,UNF,UNF,UNF,100,UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF},
241 {120,120,120,120,120,120,120,120,120,120,120,UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF}};
242 const int levelnums[5][20] = {{UNF,UNF,2,1,3,4,UNF,UNF,5,UNF,6,UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF},
243 {UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF,7,9,UNF,8,10,UNF,UNF,UNF,11,12},
244 {UNF,UNF,UNF,UNF,18,17,20,UNF,UNF,UNF,19,UNF,15,UNF,16,UNF,UNF,13,14,UNF},
245 {UNF,UNF,UNF,UNF,UNF,UNF,UNF,21,UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF},
246 {1,2,3,4,5,6,7,8,9,10,22,UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF,UNF}};
247 const int numofst[22] = {1,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1};
248 const int maplastlevel[5] = {10, 39, 46, 67, 99};
249 const char* wingnames[5] = {"West Wing", "North Wing", "East Wing", "South Wing", "Tower"};
250 const char* deptnames[5][20] = {{" "," ","Telekinetics","Telekinetics","Telekinetics","Telekinetics"," "," ","Connectivity"," ",
251 "Connectivity"," "," "," "," "," "," "," "," "," "},
252 {" "," "," "," "," "," "," "," "," "," ",
253 "Detonation","Detonation"," ","Detonation","Detonation"," "," "," ","Infection","Infection"},
254 {" "," "," "," ","Parapsychology","Parapsychology","Antimatter"," "," "," ",
255 "Antimatter"," ","Gravitation"," ","Gravitation"," "," ","Gravitation","Gravitation"," "},
256 {" "," "," "," "," "," "," ","Evil"," "," "," "," "," "," "," "," "," "," "," "," "},
257 {"Your Design","Your Design","Your Design","Your Design","Your Design","Your Design",
258 "Your Design","Your Design","Your Design","Your Design","Creation"," "," "," "," "," "," "," "," "," "}};
259 const char* divnames[5][20] = {{" "," ","Main","Inner","Experimental","Defense"," "," ","Collaboration"," ",
260 "Main"," "," "," "," "," "," "," "," "," "},
261 {" "," "," "," "," "," "," "," "," "," ",
262 "Metaphysics","Spiky Death"," ","Pyrotechnics","Adhesives"," "," "," ","Asphyxiation","Contagion"},
263 {" "," "," "," ","Unknown","Spectral","Main"," "," "," ",
264 "Motion"," ","Localization"," ","Ubiquitous"," "," ","Object Specific","Hub"," "},
265 {" "," "," "," "," "," "," ","-"," "," "," "," "," "," "," "," "," "," "," "," "},
266 {"1st","2nd","3rd","4th","5th","6th","7th","8th","9th","10th","-"," "," "," "," "," "," "," "," "," "}};
267 const char* msgs[MSGMAX][8] =
268 {{"This is the map screen, on which you can view a",
269 "floor plan of the Evil Corporation. Each level",
270 "that you can access is shown, as is the level that",
271 "you are closest to opening. Move the cursor over any",
272 "level to view information such as which Medallions",
273 "have been collected in the level, or the number of",
274 "Medallions that are required for entry to that level.",
275 "Click on a level to enter it."},
276 {"[ Basic Controls ]"," ",
277 "Walk with A and D or the left and right arrow keys.",
278 "Jump with W, the up arrow key, or the spacebar.",
279 "Read signs and enter doors with S or",
280 "the down arrow key.",
281 "Hold the shift key to walk slowly.",
282 "Pause the game by pressing P."},
283 {"[ Medallions ]"," ",
284 "In each level there are six Medallions to collect.",
285 "Here is an introduction to the first three:"," ",
286 "White Medallion - Collect somewhere in the level",
287 "Orange Medallion - Collect four Medallion Corners",
288 "Blue Medallion - Collect 100 Medallion Fragments"},
289 {"[ Telekinesis ]"," ",
290 "Click and hold down the left mouse button to use",
291 "telekinesis. Most objects can be picked up and moved",
292 "around. Press G or click the right mouse button to",
293 "toggle the telekinesis range guide. Note that Beret must",
294 "be able to see the object he is using telekinesis on,",
295 "and he can not see through solid walls."},
296 {"[ Enemies ]", " ",
297 "Even with the power of telekinesis on your side,",
298 "enemies can still be a large threat. Many enemies,",
299 "such as Robots, will be destroyed if they are",
300 "smashed into a wall or object. You can also destroy",
301 "enemies by smashing an object such as a block",
302 "into them."},
303 {"[ Clearing a Room ]"," ",
304 "You will obtain the Red Medallion once all the rooms",
305 "in the level have been cleared. To clear a room, you",
306 "must destroy all the enemies in the room and then exit",
307 "that room. If you then return to that room, the",
308 "enemies will be back, but the room will still be cleared."," "},
309 {"[ Save States ]", " "," ",
310 "Press F1 to save the the current state of a room.",
311 "This state can then be loaded at any time, even after",
312 "dying, by pressing F4. Once you leave a room, you can",
313 "no longer load save states created in that room.",
314 " "},
315 {"[ Medallions ]", " ",
316 "Here is a description of the rest of the Medallions:",
317 "Red Medallion - Defeat all enemies in each room",
318 "Green Medallion - Reach the exit before the timer on",
319 "the status bar reaches zero",
320 "Purple Medallion - Simply reach the exit",
321 " "},
322 {"[ Block Types ]", " ",
323 "There are several types of blocks that you will",
324 "encounter, but the three that you will see most",
325 "often are Wood Blocks, Ice Blocks, and Stone Blocks.",
326 "Wood Blocks have no special properties, but Ice Blocks",
327 "are very slippery and slide a lot when thrown.",
328 "Stone Blocks are too heavy to be lifted."},
329 {"[ X Only Walls ]", " ", " ",
330 "Certain types of walls only let specific types of",
331 "things through. Beret Only Walls are blue, and only",
332 "let Beret go through them. Object Only Walls are red,",
333 "and they let everything except Beret through.", " "},
334 {"[ Doors ]", " ",
335 "To enter a door, press S or the down arrow key.", " ",
336 "This large door is the level's exit. Go through it",
337 "when you are ready to end the level!",
338 " ", " "},
339 {"[ Clearing a Room ]",
340 "A flashing red X on the status bar indicates that the",
341 "current room has not yet been cleared and that there",
342 "are still enemies in the room. A red circle means that",
343 "there are no enemies left in the room, but that the room",
344 "has not yet been cleared - you will need to leave the room",
345 "to clear it. If there is a green circle on the status bar,",
346 "the current room has already been cleared."},
347 {"[ Restarting and Leaving ]", " ",
348 "If you need to restart a room for any reason, you can",
349 "do so by pressing R. If you need to return to the map",
350 "screen, press Escape. Note that your progress in the",
351 "level will not be saved - in order to save your",
352 "progress you must reach the exit of the level", " "},
353 {"[ Spike Balls ]", " ",
354 "Robots are not the only danger that you will face within",
355 "the Evil Corporation. Another common type of enemy is",
356 "the Spike Ball, which floats back and forth either",
357 "horizontally or vertically. Like Robots, they can be",
358 "smashed into walls or objects and destroyed.", " "},
359 {"[ Telekinesis Blocks ]", " ",
360 "Telekinesis Blocks are blocks that become solid if",
361 "they detect the use of telekinesis, but are otherwise",
362 "insubstantial. Anything trapped inside a Telekinesis",
363 "Block when it materializes will be destroyed. This",
364 "includes Beret, so watch out!", " "},
365 {"[ Teleseekers and Superbots ]",
366 "Unfortunately, the Robots and Spike Balls that you have",
367 "encountered this far are some of the least troublesome of",
368 "the enemies that you will face. Superbots are a speedy",
369 "version of Robots. Red Teleseekers will chase you if they",
370 "detect that you are using telekinesis, and Yellow",
371 "Teleseekers will chase you if they detect that you are not.",
372 "Teleseekers can not be destroyed by smashing."},
373 {"[ Exiting a Level ]"," ",
374 "When you leave a level through the exit door, all of the",
375 "Medallions that you have collected in the level are added",
376 "to your Medallion collection. All other collectables that",
377 "you have gathered in the level will also be saved, and",
378 "they will appear transparent the next time you play the",
379 "level to indicate that they have already been collected."},
380 {"[ Medallion Fragments ]", " ",
381 "Medallion Fragments can be picked up and moved around with",
382 "telekinesis. Try picking up the Fragments in the",
383 "enclosure to the right of this sign.", " ",
384 "A blue circle in the Blue Medallion section on the status",
385 "bar indicates that there are no more Fragments in the room."},
386 {"[ Aura Drops ]"," "," ",
387 "Aura Drops are enemies that create an aura of deadly",
388 "poison around themselves. This aura can kill Beret",
389 "and other enemies - only Aura Drops are immune to it.",
390 "Even if an Aura Drop is killed, its aura will remain in",
391 "the location of its death."},
392 {"[ Continuing Play ]", " ",
393 "If you exit the game in the middle of a level, you can",
394 "choose to continue your game the next time you play.",
395 "If you do, you will start in the same room that you were",
396 "in when you quit.",
397 "You will also be able to load a save state that you",
398 "had made in that room."},
399 {"[ Moving the Camera ]"," "," ",
400 "In some situations you may need to look around the room you",
401 "are in. To do this, press I to move the camera upwards,",
402 "J to move it to the left, K to move it downwards,",
403 "and L to move it to the right."," "},
404 {"[ Spikes and Hoppers ]", " ",
405 "Be very careful around spikes - a single touch will kill",
406 "you. Enemies will also be destroyed if they touch spikes.", " ",
407 "Hoppers are a slightly more dangerous enemy than Robots",
408 "and Spike Balls, since they are a bit smarter and can hop",
409 "over low obstacles and even up stairs."},
410 {"[ Link Blocks ]", " ",
411 "Link Blocks are the main topic of research in the",
412 "Department of Connectivity. These types of blocks link to",
413 "another object and either influence that object's movements",
414 "or are influenced by its movements. You can not use your",
415 "telekinesis to move any object that is being influenced,",
416 "whether that object is a Link Block or some other object."},
417 {"[ Sign Colors ]", " ",
418 "Because of the astounding size of the Evil Corporation,",
419 "it was a common occurrence for a researcher to get dreadfully",
420 "lost in a Department. To remedy this issue, the path to the",
421 "exit of each Department has been marked by signs with green",
422 "arrows on them. Golden arrows on signs mark paths to other",
423 "rooms that are not directly on the path to the exit."},
424 {"[ Fireworks ]", " ",
425 "Researchers in the Department of Detonation study various",
426 "sorts of explosives - in the Pyrotechnics Division several",
427 "dangerous types of Fireworks have been created. Explosions",
428 "can kill any animate object and also destroy Cracked Blocks.",
429 "Orange Fireworks are the least explosive, then Red Fireworks,",
430 "and Green Fireworks are the most explosive."},
431 {"[ Fake Blocks ]", " ",
432 "Fake Blocks are extremely sneaky enemies that disguise",
433 "themselves as normal Blocks until Beret comes too close, and",
434 "then they attack. The Stone Fake Block variety can not be",
435 "picked up, and none of the Fake Block types can be smashed.",
436 "As long as a Fake Block is disguised, it is not dangerous to",
437 "touch or even stand on."},
438 {"[ Choice Only Walls ]", " ", " ",
439 "If a Choice Only Wall is touched by Beret, it will become a",
440 "Beret Only Wall. If a Choice Only Wall is touched by any",
441 "other object, it will become an Object Only Wall."," "," "},
442 {"[ Cursor Movement Modes ]"," ",
443 "The alternate cursor movement mode is that the cursor",
444 "remains stationary relative to the room, even if the",
445 "screen scrolls. Press M you would like to toggle the",
446 "cursor movement mode. You can also change this option",
447 "on the options menu by pressing Escape and",
448 "selecting \"Options\"."},
449 {"[ Save and Load State Shortcuts ]"," "," ",
450 "Since saving and loading your state quickly can",
451 "be crucial while trying to get the Green Medallion,",
452 "you can use F1 or the 1 key to save your state, and",
453 "you can use F4 or the 4 key to load state."," "},
454 {"[ A Few Notes About This Door ]"," "," ",
455 "Don't forget that going through this door will cause all the",
456 "enemies in this room to come back when you return. If you are",
457 "trying to get the Red Medallion, you may want to kill all the",
458 "enemies and then come back to this door.",
459 " "},
460 {"[ Super Hoppers ]"," "," ",
461 "Super Hoppers are an upgraded version of Hoppers",
462 "that have far superior jumping ability. They can",
463 "jump as high as Beret can!",
464 " "," "},
465 {"[ Solidity Blocks and Switches ]", " ",
466 "When you hit a Solidity Switch with an object, all the Solidity",
467 "Blocks in the room will toggle their solidity. Just as with",
468 "Telekinesis Blocks, anything that is caught inside a Solidity",
469 "Block when it becomes solid will be destroyed. Explosions can",
470 "also trigger Solidity Switches."," "},
471 {"[ Sticky Bombs ]",
472 "In the Adhesives Division of the Department of Detonation, a",
473 "type of explosive called Sticky Bombs has been created. Sticky",
474 "Bombs can be attached to any surface, but then they will not",
475 "come off. Once a Sticky Bomb is attached to something, it will",
476 "begin a countdown, and when its timer runs out, it will explode.",
477 "The explosion of a Sticky Bomb is of the same magnitude as",
478 "that of an Orange Firework."},
479 {"[ Annoying Blocks ]", " ",
480 "Annoying Blocks come in two varieties - ones that move",
481 "horizontally and ones that move vertically. Both types",
482 "will try to match Beret's position. So, the horizontal",
483 "Annoying Blocks will try to stay above or below Beret,",
484 "and the vertical Annoying Blocks will try to stay to",
485 "Beret's left or right."},
486 {"[ Infectlings ]", " ", " ",
487 "Infectlings are objects that can change another object",
488 "into an Infectling when they touch it. Black Infectlings",
489 "affect only animate objects, but White Infectlings affect",
490 "all objects."," "},
491 {"[ Pumping Platforms ]"," "," ",
492 "A Platform can be \"pumped\" if you block its movement path",
493 "and jump on it repeatedly. This technique can be used to",
494 "force a Platform to travel a large distance.",
495 " ", " "},
496 {"[ Save States ]"," "," ",
497 "If you haven't tried out save states yet, this is a good spot",
498 "to do so - you wouldn't want to fall all the way down and have",
499 "to climb back up, would you? Save your state using F1, and then",
500 "if you fall to the bottom you can load your state using F4.",
501 " "},
502 {"[ Department of Infection ]"," ",
503 "The Department of Infection is the last department in the North",
504 "Wing of the Evil Corporation, and so the second of the Three",
505 "Evils, Stoney, resides here. The Medallions in this level are",
506 "very tricky to get, so if you get stuck keep in mind that you",
507 "only need to get to the end of the level and defeat Stoney to",
508 "progress to the East Wing of the Evil Corporation."},
509 {"[ Stoney ]"," "," ",
510 "Behind this menacing door awaits the second of the Three",
511 "Evils. Stoney is a worthy foe - you have a difficult battle",
512 "ahead of you. Once you manage to defeat him, though, you will",
513 "be able to continue on to the East Wing of the Evil Corporation.",
514 " "},
515 {"[ Save States ]"," ",
516 "While save states can take a bit of time to get used to, it",
517 "is certainly worth it, as they can make tricky parts of the",
518 "Evil Corporation much less frustrating. If you have not yet",
519 "begun using save states, you may want to try them out here,",
520 "where save stating after you climb parts of this room can",
521 "save you a lot of time if you fall."},
522 {"[ Gravity Blocks and Floating Blocks ]"," ",
523 "In the Object Specific Division of the Department of",
524 "Gravitation, blocks that are affected by gravity in various",
525 "ways have been designed. Gravity Blocks always fall in the",
526 "direction that the arrow on them indicates. Floating Blocks",
527 "are not affected by gravity at all.",
528 " "},
529 {"[ Force Fields ]"," ",
530 "If anything touches a Force Field, that object will be forced",
531 "to move in the direction that the Force Field indicates. It",
532 "can sometimes be very difficult to get an object out of a",
533 "Force Field, so be careful. Beret is also affected by Force",
534 "Fields, which can be helpful at times but sometimes very",
535 "dangerous."},
536 {"[ More Teleseekers ]"," ",
537 "The Red and Yellow Teleseekers that you have now come to",
538 "know so well are only two of the four types of Teleseekers",
539 "that inhabit the Evil Corporation. The other two types are",
540 "the Blue and Purple Teleseekers. Blue Teleseekers will always",
541 "chase Beret, regardless of his use of telekinesis, and Purple",
542 "Teleseekers will always fly away from Beret."},
543 {"[ Gravity Switches ]"," ",
544 "In the Ubiquitous Division of the Department of",
545 "Gravitation, researchers have created a type of switch that",
546 "can change the gravity in a room. These switches can be",
547 "switched in the same ways that Solidity Switches can:",
548 "by hitting them with an object or an explosive. Only",
549 "inanimate objects are affected by the gravity shift."},
550 {"[ Turrets ]"," ",
551 "The enemies that you must face will continue to grow more",
552 "and more fiendish as you delve deeper into the Evil",
553 "Corporation. Turrets are enemies that rapidly shoot bullets",
554 "which can destroy anything that is animate. They can not be",
555 "destroyed by smashing. Beret will not be harmed by touching",
556 "the body of a Turret."},
557 {"[ Reincarnators ]"," ",
558 "Researchers in the Department of Parapsychology have",
559 "created machines called Reincarnators. Once a Reincarnator",
560 "is activated by the touch of a person, it will be able to",
561 "sense that person's death and pull their spirit into a copy",
562 "of their body, which is created at the machine. Only one",
563 "Reincarnator can be active at a time."},
564 {"[ Ghosts ]", " ",
565 "Due to the research on spiritual energy within the",
566 "Department of Parapsychology, the department has become",
567 "infested with Ghosts. Ghosts will not become visible until",
568 "they are fairly close to Beret, but they are still there even",
569 "while invisible. Ghosts can be smashed, as if they move too",
570 "quickly, they will be forced to be solid."},
571 {"[ Ghost Blocks ]", " ", " ",
572 "If they are moved with enough speed, Ghost Blocks become",
573 "immaterial and can pass through anything, even walls. They",
574 "can still be moved with telekinesis even when they are not",
575 "solid.", " "},
576 {"[ Blockster ]", " ",
577 "The last department in each wing of the Evil Corporation is",
578 "home to one of the Three Evils. The Evil in command of the",
579 "West Wing is named Blockster, and his lair is on the other",
580 "side of this door. Once you defeat Blockster, you will be",
581 "able to continue on to the North Wing and the departments it",
582 "contains."},
583 {"[ Antimatter ]", " ",
584 "The researchers in the Department of Antimatter have",
585 "succeeded in creating chunks of Antimatter, as well as walls",
586 "made out of Antimatter. Antimatter destroys anything it",
587 "touches, even walls. It must be handled with caution, or the",
588 "entire department could be destroyed... and you don't want",
589 "that, do you?"},
590 {"[ Platforms ]", " ",
591 "Platforms come in four varieties, one for each orthogonal",
592 "direction. When they detect the presence and then absence of",
593 "pressure from above (for example, if Beret steps on a Platform",
594 "and then jumps off), they will move in the direction associated",
595 "with that type of Platform.",
596 " "},
597 {"[ Fake Fireworks ]", " ",
598 "Similarly to Fake Blocks, Fake Fireworks appear to be normal",
599 "Fireworks until Beret comes close, and then they lunge for the",
600 "kill. They retain the explosive nature of Fireworks, making them",
601 "quite dangerous, as even if they miss Beret they may still",
602 "explode nearby.", " "},
603 {"[ Matterly ]", " ",
604 "The third and final Evil, Matterly, is waiting for you behind",
605 "this door. She is trickier and more fiendish than the Evils",
606 "you have defeated so far, and there are rumors that Matterly",
607 "has been developing experimental weapons that she has kept",
608 "secret even from the other Evils, so be on your guard!", " "},
609 {"[ Enemies ]", " ", " ",
610 "Don't forget to defeat all the enemies in this room",
611 "if you want to get the Red Medallion!", " ", " ", " "},
612 {"[ Top Hat ]", " ",
613 "The Three Evils have now been defeated, but Beret's quest",
614 "is not quite over! His long-lost evil twin brother, Top Hat,",
615 "has been the true power behind the Evil Corporation the",
616 "whole time, using the Evils as pawns in his evil plots! Now",
617 "Beret must stop Top Hat before it's too late!!!!!", " "},
618 {"[ Antiseekers ]", " ", " ",
619 "Antiseekers chase Beret all the time, like Blue",
620 "Teleseekers, and they are made of Antimatter.",
621 "They have fancy visors as well.", " ", " "},
622 {"[ Top Hat ]", " ",
623 "The final battle! Top Hat has protected himself with a",
624 "field of telekinetic energy that will repel any object",
625 "inside it. In other words, nothing can touch him! However,",
626 "the field is sustained by five Field Generators in this",
627 "room. If they can all be destroyed, Beret will have a",
628 "chance to strike at Top Hat and defeat him!"},
629 {"[ The End ]", " ",
630 "Congratulations!",
631 "Top Hat has been defeated, and Beret has finally",
632 "succeeded in destroying the Evil Corporation! You can",
633 "now play as Top Hat by pressing T. When you have all",
634 "of the Medallions, you will open something very special",
635 "in the Tower of the Evil Corporation."},
636 {"[ Alternate Run Controls ]", " ",
637 "If you would like to use double-tapping to run instead",
638 "of holding shift to walk slowly, you can change this",
639 "setting in the options menu, which is accessed by",
640 "pressing Escape and selecting \"Options\". If you use",
641 "the alternate control scheme, double-tap the direction",
642 "you would like to run in."},
643 {"[ Backup Save State ]", " ", " ",
644 "If you ever accidentally save state in a bad spot, such",
645 "as right before Beret dies, you can load the save state",
646 "that you had saved before the current one by pressing",
647 "Ctrl when you load state.", " "}};
648
649 const int medalsprx[6] = {5,5,5,5,5,3};
650 const int medalspry[6] = {15,18,19,16,17,11};
651
652 const char *copyright = "Beret v1.2.1 Copyright 2011 Nigel Kilmer";
653
654 int i, j;
655 int quit=0;
656 int inactive = 0, paused = 0, guides = 0, getinput = 0, statusbar = 1;
657 int istophat = 0;
658 int fullscreenmode = 0;
659 int camx=0, camy=0;
660 int mx, my, telething = -1, canbetelething = -1, touchtele, telestat;
661 int telesource = -1;
662 int cantele = 0, alwaystele = 0, teleon = 0;
663 int mousecammode = 0, runningmode = 0, deathstateload = 0, opencreator = 0, secretcode = 0;
664 int count = 0, svstcount = 0;
665 int deathtime = 0, fadetime=0, fadereason, walkaway;
666 int curparticle = 0;
667 int curmusic = 0, musicon = 1, curbkg = 1;
668 int startx, starty, startdir;
669
670 int spminutes, spseconds, spframes, bspminutes, bspseconds, bspframes;
671 int enemdead[ROOMMAX], enemdeadhere, enemalldead, benemalldead, bbossvar;
672 int gotmwht, bgotmwht, gotgmed, bgotgmed, gotpmed, bgotpmed;
673 int gotmcrn[4], bgotmcrn[4];
674 int gotmfrag[MFRAGTOTAL], bgotmfrag[MFRAGTOTAL], mfragcount, bmfragcount;
675 int hassavestate, hasbkpsavestate, loadedbkpsavestate, usedsavestate;
676 int hasgmed, haspmed, hasrmed, hasomed, hasbmed, haswmed;
677
678 int credittime;
679 int creatormode = 0, crtgridsize, crtgridsnap, crtplacetile;
680 int crtselect, crtplacetype, crtplacesubtype, crtlinking, crtinventory;
681 int crtplacedir, crtentrance, crtexit, crtexitroom, crtmessage;
682 int selx, sely;
683
684 int ingame, ingamereturn, bwalkaway;
685 int cancont, contlvl;
686 int initmapmsg, initgamemsg;
687 int trgentrance, nextopenlevel, trgmap;
688 int hassaved, loaderror, yesno, optselect, optmax, gotallfrags;
689
690 int mouse_visible;
691
692 int tiles[LVLMAX][LVLMAX][3], tilebackup[LVLMAX][LVLMAX][3];
693 Thing beret;
694 Thing things[THINGMAX], thingbackup[THINGMAX];
695 int selection[THINGMAX];
696 Particle particles[PARTICLEMAX];
697
698 int lvlWidth, lvlHeight;
699 int lvlCode, areaCode, gameNum, mapCode, tempAreaCode, msgcode;
700 int mapselect;
701 int gamemedals;
702 char gamename[25];
703 int gotmedals[MEDALMAX];
704 char game_gotfrags[100][MFRAGTOTAL];
705 char game_gotcorners[100][4];
706 char game_enemdead[100][ROOMMAX];
707 int beatlevel[100];
708 int gravdir, switchflags;
709
710 char support_path[250];
711
712 char msgline[250];
713
714 SDL_Surface* screen = NULL;
715 SDL_Surface* background = NULL;
716 SDL_Surface* invbackground = NULL;
717 SDL_Surface* spritesheet = NULL;
718 SDL_Surface* tilesheet = NULL;
719 SDL_Surface* teleguide = NULL;
720 SDL_Surface* title = NULL;
721 SDL_Surface* credits = NULL;
722 SDL_Surface* mapbkg = NULL;
723 SDL_Surface* pit = NULL;
724 SDL_Surface* lvlnumbkg = NULL;
725 SDL_Surface* gameselect = NULL;
726 SDL_Surface* msgback = NULL;
727 SDL_Surface* optback= NULL;
728 SDL_Surface* getinputback = NULL;
729 SDL_Surface* message = NULL;
730 SDL_Surface* fades[5];
731
732 char messagestr[200], inputstr[25], getinputstr[50];
733 int inputpos, inputlength;
734
735 FILE* file;
736 FILE* msgfile;
737
738 Uint32 selcolor;
739
740 SDL_Event event;
741 int key1=NONE, key2=NONE, key3=NONE;
742 int remkey1;
743 int camxkey=NONE, camykey=NONE;
744 int freecam;
745
746 TTF_Font *font = NULL, *smfont = NULL, *medfont = NULL;
747 SDL_Color textcolor = {0, 0, 0}, textcolor2 = {220,220,220};
748 Uint32 redColor, whiteColor, greenColor, blueColor;
749
750 Mix_Music* music[MUSIC_MAX];
751 Mix_Chunk* sound[SOUND_MAX];
752
753
f_sqr(float x)754 float f_sqr(float x) {return x*x;}
f_abs(float x)755 float f_abs(float x) {return x<0?-x:x;}
756
757
758 void resolve_fade(void);
759 void resolve_input(SDLKey);
760 void start_map(void);
761
init_fade(int ftype)762 void init_fade(int ftype) {
763 if (fadetime == 0) {
764 fadetime = 14;
765 fadereason = ftype;
766 svstcount = 0;
767 }
768 }
769
load_img(char * filename)770 SDL_Surface* load_img(char* filename) {
771 SDL_Surface* loadImg = NULL;
772 SDL_Surface* optImg = NULL;
773
774 loadImg = IMG_Load(filename);
775
776 // Create the optimized image
777 if (loadImg != NULL) {
778 optImg = SDL_DisplayFormatAlpha(loadImg);
779 SDL_FreeSurface(loadImg);
780 }
781
782 return optImg;
783 }
784
785
apply_surface(int x,int y,SDL_Surface * source,SDL_Surface * dest)786 void apply_surface(int x, int y, SDL_Surface* source, SDL_Surface* dest) {
787 SDL_Rect offset;
788 offset.x = x;
789 offset.y = y;
790
791 SDL_BlitSurface(source, NULL, dest, &offset);
792 }
793
794
apply_particle(int x,int y,int color)795 void apply_particle(int x, int y, int color) {
796 SDL_Rect offset;
797 offset.x = x-2;
798 offset.y = y-2;
799
800 // Create the rectangle specifying area of sprite sheet to apply
801 SDL_Rect clip;
802 clip.x = 19*SPR_SIZE+4*(color%7);
803 clip.y = 4*SPR_SIZE+4*(color/7);
804 clip.w = 4;
805 clip.h = 4;
806
807 SDL_BlitSurface(spritesheet, &clip, screen, &offset);
808 }
809
810
apply_sprite(int x,int y,int sprx,int spry,int sprw,int sprh,SDL_Surface * source,SDL_Surface * dest)811 void apply_sprite(int x, int y, int sprx, int spry, int sprw, int sprh,
812 SDL_Surface* source, SDL_Surface* dest) {
813 SDL_Rect offset;
814 offset.x = x;
815 offset.y = y;
816
817 // Create the rectangle specifying area of sprite sheet to apply
818 SDL_Rect clip;
819 clip.x = sprx*SPR_SIZE;
820 clip.y = spry*SPR_SIZE;
821 clip.w = sprw*SPR_SIZE;
822 clip.h = sprh*SPR_SIZE;
823
824 SDL_BlitSurface(source, &clip, dest, &offset);
825 }
826
827
init()828 int init() {
829
830 #ifdef __WIN32__
831 sprintf(support_path, "");
832 #else
833 char filestr[512];
834 // Get the home directory of the user.
835 struct passwd *pwd = getpwuid(getuid());
836 if (pwd) {
837 // Create the directory for application data.
838 sprintf(support_path, "%s/%s", pwd->pw_dir, SUPPORT_PATH);
839 mkdir(support_path, S_IRWXU);
840 // Create the directory for custom room data.
841 sprintf(filestr, "%s/rooms", support_path);
842 mkdir(filestr, S_IRWXU);
843 // Create the directory for save data.
844 sprintf(filestr, "%s/saves", support_path);
845 mkdir(filestr, S_IRWXU);
846 }
847 #endif
848
849 if (SDL_Init(SDL_INIT_EVERYTHING) == -1) {
850 printf("Error: couldn't initialize SDL\n");
851 return 0;
852 }
853
854 // For some reason this causes X windows (at least under Awesome WM)
855 // to refuse to accept keyboard input.
856 SDL_Surface* icon = SDL_LoadBMP(RESOURCE_PATH "images" DIRSEP "block.bmp");
857 SDL_WM_SetIcon(icon, NULL);
858
859 screen = SDL_SetVideoMode(SCR_WIDTH, SCR_HEIGHT, SCR_BPP, SDL_FULLSCREEN);
860 fullscreenmode = 1;
861 if (screen == NULL) {
862 printf("Error: couldn't initialize the screen\n");
863 return 0;
864 }
865
866 if (TTF_Init() == -1) {
867 printf("Error: couldn't initalize fonts\n");
868 return 0;
869 }
870
871 if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024) == -1) {
872 printf("Error: couldn't initalize sound handling\n");
873 return 0;
874 }
875 Mix_AllocateChannels(NUM_CHANNELS);
876
877 SDL_ShowCursor(SDL_DISABLE);
878 mouse_visible = 0;
879
880 selcolor = SDL_MapRGB(screen->format, 0, 0xd0, 0x20);
881
882 SDL_WM_SetCaption(GAME_TITLE, NULL);
883
884 return 1;
885 }
886
887
load_files()888 int load_files() {
889 char bkgstr[512];
890
891 // Load images
892 tilesheet = load_img(RESOURCE_PATH "images" DIRSEP "tilesheet.png");
893 spritesheet = load_img(RESOURCE_PATH "images" DIRSEP "spritesheet.png");
894 invbackground = load_img(RESOURCE_PATH "images" DIRSEP "inventory.png");
895 background = load_img(RESOURCE_PATH "images" DIRSEP "bkg1.png");
896 teleguide = load_img(RESOURCE_PATH "images" DIRSEP "teleguide.png");
897 title = load_img(RESOURCE_PATH "images" DIRSEP "title.png");
898 credits = load_img(RESOURCE_PATH "images" DIRSEP "credits.png");
899 mapbkg = load_img(RESOURCE_PATH "images" DIRSEP "mapbkg.png");
900 pit = load_img(RESOURCE_PATH "images" DIRSEP "pit.png");
901 lvlnumbkg = load_img(RESOURCE_PATH "images" DIRSEP "lvlnum.png");
902 gameselect = load_img(RESOURCE_PATH "images" DIRSEP "gameselect.png");
903 msgback = load_img(RESOURCE_PATH "images" DIRSEP "msg.png");
904 optback = load_img(RESOURCE_PATH "images" DIRSEP "opt.png");
905 getinputback = load_img(RESOURCE_PATH "images" DIRSEP "getinput.png");
906 for (i=1;i<=5; i++) {
907 sprintf(bkgstr, "%simages%sfade%d.png", RESOURCE_PATH, DIRSEP, i);
908 fades[i-1] = load_img(bkgstr);
909 }
910
911 // Load fonts
912 font = TTF_OpenFont(RESOURCE_PATH "AveriaSansGWF-Regular.ttf", 24);
913 smfont = TTF_OpenFont(RESOURCE_PATH "AveriaSansGWF-Regular.ttf", 9);
914 medfont = TTF_OpenFont(RESOURCE_PATH "AveriaSansGWF-Regular.ttf", 16);
915
916 // Load music
917 for (i=0; i<MUSIC_MAX; i++) {
918 sprintf(bkgstr, "%smusic%sberet%d.ogg", RESOURCE_PATH, DIRSEP, i);
919 if (!(music[i] = Mix_LoadMUS(bkgstr)))
920 return 0;
921 }
922
923 //Load sound effects
924 sound[SND_KNOCK] = Mix_LoadWAV(RESOURCE_PATH "sfx/knock.wav");
925 sound[SND_KNOCK+1] = Mix_LoadWAV(RESOURCE_PATH "sfx/knock2.wav");
926 sound[SND_KNOCK+2] = Mix_LoadWAV(RESOURCE_PATH "sfx/knock3.wav");
927 sound[SND_CLINK] = Mix_LoadWAV(RESOURCE_PATH "sfx/clink.wav");
928 sound[SND_CLINK+1] = Mix_LoadWAV(RESOURCE_PATH "sfx/clink2.wav");
929 sound[SND_CLINK+2] = Mix_LoadWAV(RESOURCE_PATH "sfx/clink3.wav");
930 sound[SND_CRUNCH] = Mix_LoadWAV(RESOURCE_PATH "sfx/crunch.wav");
931 sound[SND_CRUNCH+1] = Mix_LoadWAV(RESOURCE_PATH "sfx/crunch2.wav");
932 sound[SND_CRUNCH+2] = Mix_LoadWAV(RESOURCE_PATH "sfx/crunch3.wav");
933 sound[SND_SQUELCH] = Mix_LoadWAV(RESOURCE_PATH "sfx/squelch.wav");
934 sound[SND_SQUELCH+1] = Mix_LoadWAV(RESOURCE_PATH "sfx/squelch2.wav");
935 sound[SND_SQUELCH+2] = Mix_LoadWAV(RESOURCE_PATH "sfx/squelch3.wav");
936 sound[SND_STEP] = Mix_LoadWAV(RESOURCE_PATH "sfx/step1.wav");
937 sound[SND_STEP+1] = Mix_LoadWAV(RESOURCE_PATH "sfx/step2.wav");
938 sound[SND_STEP+2] = Mix_LoadWAV(RESOURCE_PATH "sfx/step3.wav");
939 sound[SND_JUMP] = Mix_LoadWAV(RESOURCE_PATH "sfx/jump1.wav");
940 sound[SND_JUMP+1] = Mix_LoadWAV(RESOURCE_PATH "sfx/jump2.wav");
941 sound[SND_JUMP+2] = Mix_LoadWAV(RESOURCE_PATH "sfx/jump3.wav");
942 sound[SND_COLLECT] = Mix_LoadWAV(RESOURCE_PATH "sfx/frag1.wav");
943 sound[SND_COLLECT+1] = Mix_LoadWAV(RESOURCE_PATH "sfx/frag2.wav");
944 sound[SND_COLLECT+2] = Mix_LoadWAV(RESOURCE_PATH "sfx/frag3.wav");
945 sound[SND_COLLECT+3] = Mix_LoadWAV(RESOURCE_PATH "sfx/frag4.wav");
946 sound[SND_COLLECT+4] = Mix_LoadWAV(RESOURCE_PATH "sfx/frag5.wav");
947 sound[SND_COLLECT+5] = Mix_LoadWAV(RESOURCE_PATH "sfx/frag6.wav");
948 sound[SND_BOOM] = Mix_LoadWAV(RESOURCE_PATH "sfx/boom1.wav");
949 sound[SND_BOOM+1] = Mix_LoadWAV(RESOURCE_PATH "sfx/boom2.wav");
950 sound[SND_BOOM+2] = Mix_LoadWAV(RESOURCE_PATH "sfx/boom3.wav");
951 sound[SND_TICK] = Mix_LoadWAV(RESOURCE_PATH "sfx/tick1.wav");
952 sound[SND_TICK+1] = Mix_LoadWAV(RESOURCE_PATH "sfx/tick2.wav");
953 sound[SND_TICK+2] = Mix_LoadWAV(RESOURCE_PATH "sfx/tick3.wav");
954 sound[SND_HOP] = Mix_LoadWAV(RESOURCE_PATH "sfx/hop1.wav");
955 sound[SND_HOP+1] = Mix_LoadWAV(RESOURCE_PATH "sfx/hop2.wav");
956 sound[SND_HOP+2] = Mix_LoadWAV(RESOURCE_PATH "sfx/hop3.wav");
957 sound[SND_INFECT] = Mix_LoadWAV(RESOURCE_PATH "sfx/infect.wav");
958 sound[SND_SWITCHGR] = Mix_LoadWAV(RESOURCE_PATH "sfx/switch-gr1.wav");
959 sound[SND_SWITCHGR+1] = Mix_LoadWAV(RESOURCE_PATH "sfx/switch-gr2.wav");
960 sound[SND_SWITCHGR+2] = Mix_LoadWAV(RESOURCE_PATH "sfx/switch-gr3.wav");
961 sound[SND_SWITCHRD] = Mix_LoadWAV(RESOURCE_PATH "sfx/switch-rd1.wav");
962 sound[SND_SWITCHRD+1] = Mix_LoadWAV(RESOURCE_PATH "sfx/switch-rd2.wav");
963 sound[SND_SWITCHRD+2] = Mix_LoadWAV(RESOURCE_PATH "sfx/switch-rd3.wav");
964 sound[SND_SWITCHGV] = Mix_LoadWAV(RESOURCE_PATH "sfx/switch-gv1.wav");
965 sound[SND_SWITCHGV+1] = Mix_LoadWAV(RESOURCE_PATH "sfx/switch-gv2.wav");
966 sound[SND_SWITCHGV+2] = Mix_LoadWAV(RESOURCE_PATH "sfx/switch-gv3.wav");
967 sound[SND_CHOICEBERET] = Mix_LoadWAV(RESOURCE_PATH "sfx/choice-beret1.wav");
968 sound[SND_CHOICEBERET+1] = Mix_LoadWAV(RESOURCE_PATH "sfx/choice-beret2.wav");
969 sound[SND_CHOICEBERET+2] = Mix_LoadWAV(RESOURCE_PATH "sfx/choice-beret3.wav");
970 sound[SND_CHOICEOBJECT] = Mix_LoadWAV(RESOURCE_PATH "sfx/choice-object1.wav");
971 sound[SND_CHOICEOBJECT+1] = Mix_LoadWAV(RESOURCE_PATH "sfx/choice-object2.wav");
972 sound[SND_CHOICEOBJECT+2] = Mix_LoadWAV(RESOURCE_PATH "sfx/choice-object3.wav");
973 sound[SND_TURRET] = Mix_LoadWAV(RESOURCE_PATH "sfx/shot1.wav");
974 sound[SND_TURRET+1] = Mix_LoadWAV(RESOURCE_PATH "sfx/shot2.wav");
975 sound[SND_TURRET+2] = Mix_LoadWAV(RESOURCE_PATH "sfx/shot3.wav");
976 sound[SND_PLATFORM] = Mix_LoadWAV(RESOURCE_PATH "sfx/platform1.wav");
977 sound[SND_PLATFORM+1] = Mix_LoadWAV(RESOURCE_PATH "sfx/platform2.wav");
978 sound[SND_PLATFORM+2] = Mix_LoadWAV(RESOURCE_PATH "sfx/platform3.wav");
979 sound[SND_STICK] = Mix_LoadWAV(RESOURCE_PATH "sfx/stick.wav");
980 sound[SND_ANTIMATTER] = Mix_LoadWAV(RESOURCE_PATH "sfx/antimatter1.wav");
981 sound[SND_ANTIMATTER+1] = Mix_LoadWAV(RESOURCE_PATH "sfx/antimatter2.wav");
982 sound[SND_ANTIMATTER+2] = Mix_LoadWAV(RESOURCE_PATH "sfx/antimatter3.wav");
983 sound[SND_FAKE] = Mix_LoadWAV(RESOURCE_PATH "sfx/fake.wav");
984 sound[SND_FAKE+1] = Mix_LoadWAV(RESOURCE_PATH "sfx/fake2.wav");
985 sound[SND_POP] = Mix_LoadWAV(RESOURCE_PATH "sfx/pop.wav");
986 sound[SND_POP+1] = Mix_LoadWAV(RESOURCE_PATH "sfx/pop2.wav");
987 sound[SND_POP+2] = Mix_LoadWAV(RESOURCE_PATH "sfx/pop3.wav");
988 sound[SND_REGEN] = Mix_LoadWAV(RESOURCE_PATH "sfx/regen.wav");
989 sound[SND_REGENINIT] = Mix_LoadWAV(RESOURCE_PATH "sfx/regeninit.wav");
990 sound[SND_MEDW] = Mix_LoadWAV(RESOURCE_PATH "sfx/med-w.wav");
991 sound[SND_MEDO] = Mix_LoadWAV(RESOURCE_PATH "sfx/med-o.wav");
992 sound[SND_MEDB] = Mix_LoadWAV(RESOURCE_PATH "sfx/med-b.wav");
993 sound[SND_MEDR] = Mix_LoadWAV(RESOURCE_PATH "sfx/med-r.wav");
994 sound[SND_MEDG] = Mix_LoadWAV(RESOURCE_PATH "sfx/med-g.wav");
995 sound[SND_MEDP] = Mix_LoadWAV(RESOURCE_PATH "sfx/med-p.wav");
996 sound[SND_CORNER] = Mix_LoadWAV(RESOURCE_PATH "sfx/corner.wav");
997
998 return 1;
999 }
1000
1001
clean_up()1002 void clean_up() {
1003
1004 // Free surfaces
1005 SDL_FreeSurface(screen);
1006 SDL_FreeSurface(invbackground);
1007 SDL_FreeSurface(background);
1008 for (i=0; i<5; i++)
1009 SDL_FreeSurface(fades[i]);
1010 SDL_FreeSurface(tilesheet);
1011 SDL_FreeSurface(spritesheet);
1012 SDL_FreeSurface(teleguide);
1013 SDL_FreeSurface(title);
1014 SDL_FreeSurface(credits);
1015 SDL_FreeSurface(mapbkg);
1016 SDL_FreeSurface(pit);
1017 SDL_FreeSurface(lvlnumbkg);
1018 SDL_FreeSurface(gameselect);
1019 SDL_FreeSurface(msgback);
1020 SDL_FreeSurface(optback);
1021 SDL_FreeSurface(getinputback);
1022
1023 // Free music and sounds
1024 for (i=0; i<SOUND_MAX; i++) Mix_FreeChunk(sound[i]);
1025 for (i=0; i<MUSIC_MAX; i++) Mix_FreeMusic(music[i]);
1026 Mix_CloseAudio();
1027
1028 // Free fonts
1029 TTF_CloseFont(font);
1030 TTF_CloseFont(smfont);
1031 TTF_CloseFont(medfont);
1032 TTF_Quit();
1033
1034 SDL_Quit();
1035 }
1036
1037
1038 /*
1039 * Taken from the SDL documentation and modified.
1040 * Set the pixel at (x, y) to the given value
1041 * NOTE: The surface must be locked before calling this!
1042 * Set alpha = -1 to invert color
1043 */
putpixel(SDL_Surface * surface,int x,int y,Uint32 pixel,int alpha)1044 void putpixel(SDL_Surface *surface, int x, int y,
1045 Uint32 pixel, int alpha) {
1046 int bpp = surface->format->BytesPerPixel;
1047 /* Here p is the address to the pixel we want to set */
1048 Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
1049
1050 Uint32 oldpix = *(Uint32 *)p;
1051 if (alpha == -1) {
1052 *(Uint32 *)p = ~oldpix;
1053 } else {
1054 float falpha = (float)alpha/0xff;
1055 int r =((pixel&0xff0000)>>16)*falpha+((oldpix&0xff0000)>>16)*(1-falpha);
1056 int g =((pixel&0xff00)>>8)*falpha+((oldpix&0xff00)>>8)*(1-falpha);
1057 int b =(pixel&0xff)*falpha+(oldpix&0xff)*(1-falpha);
1058 *(Uint32 *)p = (r<<16)+(g<<8)+b;
1059 }
1060 }
1061
1062
1063 // draws a line from (x1, y1) to (x2, y2)
draw_line(SDL_Surface * surface,int x1,int y1,int x2,int y2,Uint32 pixel)1064 void draw_line(SDL_Surface* surface, int x1, int y1,
1065 int x2, int y2, Uint32 pixel) {
1066 int curx = x1, cury = y1;
1067 float slope = 2;
1068 if (x2 != x1) slope = 1.0*(y2-y1)/(x2-x1);
1069
1070 while (!((f_abs(slope)>=1 && cury == y2) ||
1071 (f_abs(slope)<1 && curx == x2))) {
1072 if (curx >= 0 && curx < SCR_WIDTH &&
1073 cury >= 0 && cury < SCR_HEIGHT)
1074 putpixel(surface, curx, cury, pixel, 0xff);
1075 if (x1 == x2) {
1076 cury += cury < y2 ? 1 : -1;
1077 } else {
1078 if (slope <= -1 || slope >= 1) {
1079 cury += cury < y2 ? 1 : -1;
1080 curx = x1 + (cury-y1)/slope;
1081 } else {
1082 curx += curx < x2 ? 1 : -1;
1083 cury = y1 + slope*(curx-x1);
1084 }
1085 }
1086 }
1087 if (curx >= 0 && curx < SCR_WIDTH &&
1088 cury >= 0 && cury < SCR_HEIGHT)
1089 putpixel(surface, curx, cury, pixel, 0xff);
1090 }
1091
1092
1093 // draws a semi-transparent rectangle to the surface
draw_rect(SDL_Surface * surface,int x1,int y1,int x2,int y2,Uint32 pixel,int alpha)1094 void draw_rect(SDL_Surface* surface, int x1, int y1,
1095 int x2, int y2, Uint32 pixel, int alpha) {
1096 int curx, cury;
1097 if ( SDL_MUSTLOCK(screen) ) {
1098 if ( SDL_LockSurface(screen) < 0 ) {
1099 fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
1100 return;
1101 }
1102 }
1103 for (curx=x1; curx<=x2; curx++) {
1104 for (cury=y1; cury<=y2; cury++) {
1105 putpixel(surface, curx, cury, pixel, alpha);
1106 }
1107 }
1108 draw_line(surface, x1, y1, x2, y1, 0);
1109 draw_line(surface, x1, y1, x1, y2, 0);
1110 draw_line(surface, x2, y1, x2, y2, 0);
1111 draw_line(surface, x1, y2, x2, y2, 0);
1112 if (SDL_MUSTLOCK(screen)) {
1113 SDL_UnlockSurface(screen);
1114 }
1115 }
1116
1117
1118 // draws the screen fading out
draw_fade()1119 void draw_fade() {
1120 apply_surface(0,0,fades[fadereason==0?(fadetime-2)/3:5-((fadetime+2)/3)],screen);
1121 }
1122
1123
1124 // draws the particles to the screen
draw_particles()1125 void draw_particles() {
1126 for (i=0; i<PARTICLEMAX; i++) {
1127 if (particles[i].time > 0) {
1128 apply_particle(particles[i].x-camx,particles[i].y-camy,particles[i].color);
1129 }
1130 }
1131 }
1132
1133
create_particle(int x,int y,float vx,float vy,int color,int time)1134 void create_particle(int x, int y, float vx, float vy,
1135 int color, int time) {
1136 particles[curparticle].x = x;
1137 particles[curparticle].y = y;
1138 particles[curparticle].vx = vx/1.5;
1139 particles[curparticle].vy = vy/1.5;
1140 particles[curparticle].color = color;
1141 particles[curparticle].time = time*1.5;
1142 curparticle++;
1143 curparticle %= PARTICLEMAX;
1144 }
1145
1146
stop_telekinesis()1147 void stop_telekinesis() {
1148 things[telething].telething = 0;
1149 things[telething].teledelay = TELEDELAY;
1150 telething = -1;
1151 canbetelething = -1;
1152 teleon = 0;
1153 }
1154
1155
display_message(int x,int y,TTF_Font * mfont,const char * msg,int bktext)1156 void display_message(int x, int y, TTF_Font *mfont, const char* msg, int bktext) {
1157 message = TTF_RenderText_Blended(mfont, msg?msg:messagestr, textcolor);
1158 apply_surface(x-message->w/2,y-message->h/2,message,screen);
1159 SDL_FreeSurface(message);
1160 if (!bktext) {
1161 message = TTF_RenderText_Blended(mfont, msg?msg:messagestr, textcolor2);
1162 apply_surface(x-message->w/2+TEXTSHADOW,y-message->h/2+TEXTSHADOW,message,screen);
1163 SDL_FreeSurface(message);
1164 }
1165 }
1166
1167
start_telekinesis()1168 void start_telekinesis() {
1169 if (((alwaystele && teleon) || (!alwaystele && cantele)) &&
1170 telething == -1 && canbetelething != -1) {
1171 telething = canbetelething;
1172 things[telething].telething = 1;
1173 }
1174 }
1175
1176
fix_camera()1177 void fix_camera() {
1178 if (camx < 0) camx = 0;
1179 if (camx > lvlWidth-SCR_WIDTH) camx = lvlWidth-SCR_WIDTH;
1180 if (camy < 0) camy = 0;
1181 if (camy > lvlHeight-SCR_HEIGHT) camy = lvlHeight-SCR_HEIGHT;
1182 }
1183
1184
clear_room()1185 void clear_room() {
1186 // clear position
1187 startx = 0;
1188 starty = 0;
1189
1190 // clear things
1191 for (i=0; i<THINGMAX; i++) {
1192 things[i].type = NOTYPE;
1193 thingbackup[i].type = NOTYPE;
1194 things[i].islinked = -1;
1195 thingbackup[i].islinked = -1;
1196 }
1197
1198 // clear tiles
1199 for (i=0; i<LVLMAX; i++)
1200 for (j=0; j<LVLMAX; j++) {
1201 tiles[i][j][0] = EMPTY;
1202 tilebackup[i][j][0] = EMPTY;
1203 }
1204
1205 lvlWidth = SCR_WIDTH;
1206 lvlHeight = SCR_HEIGHT;
1207 fix_camera();
1208
1209 hassaved = 0;
1210 }
1211
1212
center_camera()1213 void center_camera() {
1214 int curcamx = camx, curcamy = camy;
1215 camx = beret.x+beret.width/2-SCR_WIDTH/2;
1216 camy = beret.y+beret.height/2-SCR_HEIGHT/2;
1217 fix_camera();
1218 mx -= curcamx-camx;
1219 my -= curcamy-camy;
1220 }
1221
1222
load_backups()1223 void load_backups() {
1224 // reset flags
1225 switchflags &= ~GREENFLAG;
1226 switchflags &= ~REDFLAG;
1227 switchflags &= ~REINCARNATE;
1228 gravdir = DOWN;
1229
1230 // reset collectibles
1231 mfragcount = bmfragcount;
1232 for (i=0; i<MFRAGTOTAL; i++) gotmfrag[i] = bgotmfrag[i];
1233 for (i=0; i<4; i++) gotmcrn[i] = bgotmcrn[i];
1234 gotmwht = bgotmwht;
1235 gotgmed = bgotgmed;
1236 gotpmed = bgotpmed;
1237 spframes = bspframes;
1238 spseconds = bspseconds;
1239 spminutes = bspminutes;
1240 enemalldead = benemalldead;
1241
1242 // set up vars
1243 deathtime = 0;
1244 curparticle = 0;
1245 gotallfrags = 0;
1246 int* bossvars = get_bossvars();
1247 for (i=0; i<BOSSMAX-1; i++) bossvars[i] = 0;
1248 bossvars[BOSSMAX-1] = bbossvar;
1249
1250
1251 // reset particles
1252 for (i=0; i<PARTICLEMAX; i++) particles[i].time = 0;
1253
1254 // set up beret
1255 if (telething > -1) stop_telekinesis();
1256 int bspeed = beret.speed;
1257 make_beret(&beret, BERET, istophat, startx, starty, 1, things);
1258 beret.speed = bspeed?bspeed:WALK_SPEED;
1259 beret.dir = startdir;
1260 walkaway = bwalkaway;
1261 center_camera();
1262
1263 // load things
1264 enemdeadhere = enemdead[areaCode] || game_enemdead[lvlCode][areaCode];
1265 for (i=0; i<THINGMAX; i++) {
1266 if (thingbackup[i].type == NOTYPE) things[i].type = NOTYPE;
1267 else copy_thing(&thingbackup[i], things, i);
1268 }
1269
1270 // load tiles
1271 int k;
1272 for (i=0; i<LVLMAX; i++)
1273 for (j=0; j<LVLMAX; j++)
1274 for (k=0; k<3; k++)
1275 tiles[i][j][k] = tilebackup[i][j][k];
1276 }
1277
1278
check_room_dead()1279 void check_room_dead() {
1280 int foundone = 0;
1281 int iter;
1282 for (iter=0; iter<THINGMAX; iter++) {
1283 if (things[iter].type != NOTYPE && !things[iter].dead && things[iter].animate) {
1284 foundone = 1;
1285 break;
1286 }
1287 }
1288 if (!foundone) {
1289 enemdeadhere = 1;
1290 for (iter=0; iter<ROOMMAX; iter++) {
1291 if (iter != areaCode && !enemdead[iter] && !game_enemdead[lvlCode][iter]) {foundone = 1; break;}
1292 }
1293 if (!foundone && !enemalldead && !hasrmed) {
1294 enemalldead = 1;
1295 play_sound(SND_MEDR);
1296 if (statusbar) {
1297 make_expl(RMEDPOS+15+camx,30+camy,0,0,RED,6,100);
1298 make_expl(RMEDPOS+15+camx,30+camy,0,0,PINK,6,40);
1299 }
1300 }
1301 }
1302 }
1303
1304
go_to_room(int entr,int roomnum)1305 void go_to_room(int entr, int roomnum) {
1306 trgentrance = entr;
1307 tempAreaCode = roomnum;
1308 init_fade(5);
1309 }
1310
1311
switch_music(int newmusic,int forceswitch)1312 void switch_music(int newmusic, int forceswitch) {
1313 if (newmusic != curmusic || forceswitch || (Mix_PlayingMusic() && (musicon == 0 || musicon == 3))) {
1314 curmusic = newmusic;
1315 if (Mix_PlayingMusic()) Mix_HaltMusic();
1316 if (musicon == 1 || musicon == 2) Mix_PlayMusic(music[curmusic], -1);
1317 }
1318 }
1319
1320
1321 // saves the state of the room and collectables
1322 // for returning to this point
save_room_return(int flag)1323 void save_room_return(int flag) {
1324 char filestr[512];
1325 sprintf(filestr, "%ssaves%sgame%d.ret", support_path, DIRSEP, gameNum);
1326 file = fopen(filestr, "wb");
1327 if (file) {
1328 fwrite(&lvlCode, sizeof(int), 1, file);
1329 fwrite(&areaCode, sizeof(int), 1, file);
1330 fwrite(&bgotmwht, sizeof(int), 1, file);
1331 fwrite(bgotmcrn, sizeof(int), 4, file);
1332 fwrite(&bmfragcount, sizeof(int), 1, file);
1333 fwrite(bgotmfrag, sizeof(int), MFRAGTOTAL, file);
1334 fwrite(&bgotgmed, sizeof(int), 1, file);
1335 fwrite(&bgotpmed, sizeof(int), 1, file);
1336 fwrite(&trgentrance, sizeof(int), 1, file);
1337 fwrite(&bspminutes, sizeof(int), 1, file);
1338 fwrite(&bspseconds, sizeof(int), 1, file);
1339 fwrite(&bspframes, sizeof(int), 1, file);
1340 fwrite(&benemalldead, sizeof(int), 1, file);
1341 fwrite(enemdead, sizeof(int), ROOMMAX, file);
1342 fwrite(&haswmed, sizeof(int), 1, file);
1343 fwrite(&hasomed, sizeof(int), 1, file);
1344 fwrite(&hasbmed, sizeof(int), 1, file);
1345 fwrite(&hasrmed, sizeof(int), 1, file);
1346 fwrite(&hasgmed, sizeof(int), 1, file);
1347 fwrite(&haspmed, sizeof(int), 1, file);
1348 fwrite(&usedsavestate, sizeof(int), 1, file);
1349 fwrite(&hassavestate, sizeof(int), 1, file);
1350 fwrite(&flag, sizeof(int), 1, file);
1351 fwrite(&((get_bossvars())[BOSSMAX-1]), sizeof(int), 1, file);
1352
1353 fclose(file);
1354 }
1355 }
1356
1357
1358 // sets up the room data for playing
init_play(int flag,int savereturn)1359 void init_play(int flag, int savereturn) {
1360 char filestr[512];
1361
1362 // reset or set collectible backup data
1363 if (flag) {
1364 // Set backups to the current state
1365 bgotmwht = gotmwht;
1366 for (i=0;i<4;i++) bgotmcrn[i] = gotmcrn[i];
1367 bmfragcount = mfragcount;
1368 for (i=0;i<MFRAGTOTAL;i++) bgotmfrag[i] = gotmfrag[i];
1369 bgotgmed = gotgmed;
1370 bgotpmed = gotpmed;
1371 } else {
1372 // Starting the level, reset backups
1373 bgotmwht = 0;
1374 for (i=0;i<4;i++) bgotmcrn[i] = 0;
1375 bmfragcount = 0;
1376 for (i=0;i<MFRAGTOTAL;i++) {
1377 bgotmfrag[i] = 0;
1378 if (game_gotfrags[lvlCode][i]) bmfragcount++;
1379 }
1380 bgotgmed = 0;
1381 bgotpmed = 0;
1382 }
1383
1384 if (!flag) {
1385 startdir = 1;
1386 bwalkaway = 0;
1387 bbossvar = 0;
1388 }
1389 // set room backups
1390 if (flag && (get_bossvars())[BOSSMAX-1]) bbossvar = 1;
1391 for (i=0; i<THINGMAX; i++) {
1392 if (things[i].type == NOTYPE) thingbackup[i].type = NOTYPE;
1393 else copy_thing(&things[i], thingbackup, i);
1394 if (flag && things[i].type == DOOR && things[i].timer == trgentrance) {
1395 startx = things[i].x+things[i].width/2-10;
1396 starty = things[i].y+things[i].height-24;
1397 bwalkaway = 0;
1398 }
1399 if (flag && things[i].type == SIGN && things[i].timer == trgentrance &&
1400 (things[i].x <= SPR_SIZE*2 || things[i].x >= lvlWidth-SPR_SIZE*3)) {
1401 startx = things[i].subtype%2?lvlWidth-20:0;
1402 starty = things[i].y+things[i].height-24;
1403 startdir = things[i].subtype%2?0:1;
1404 bwalkaway = 2-things[i].subtype%2;
1405 }
1406 if (things[i].type == WHITEMEDAL) {
1407 if (bgotmwht) thingbackup[i].type = NOTYPE;
1408 if (haswmed) thingbackup[i].subtype = 1;
1409 }
1410 if (things[i].type == MEDALCORNER) {
1411 if (bgotmcrn[things[i].subtype]) thingbackup[i].type = NOTYPE;
1412 if (game_gotcorners[lvlCode][things[i].subtype]) thingbackup[i].subtype += 4;
1413 }
1414 if (things[i].type == MEDALFRAGMENT && things[i].dir > -1) {
1415 if (bgotmfrag[things[i].dir]) thingbackup[i].type = NOTYPE;
1416 if (game_gotfrags[lvlCode][things[i].dir]) thingbackup[i].subtype += 2;
1417 }
1418 }
1419 int k;
1420 for (i=0; i<LVLMAX; i++)
1421 for (j=0; j<LVLMAX; j++)
1422 for (k=0; k<3; k++)
1423 tilebackup[i][j][k] = tiles[i][j][k];
1424 hassavestate = 0;
1425 hasbkpsavestate = 0;
1426 loadedbkpsavestate = 0;
1427 if (!flag) usedsavestate = 0;
1428 freecam = 0;
1429
1430 // load rooms with enemies in them from level metadata
1431 // load timer from level metadata
1432 if (!flag) {
1433 char lcode;
1434 if (lvlCode < 80) {
1435 sprintf(filestr, RESOURCE_PATH "rooms/metas");
1436 } else {
1437 sprintf(filestr, "%srooms%slvl%d.meta", support_path, DIRSEP, lvlCode);
1438 }
1439 file = fopen(filestr, "rb");
1440 if (file) {
1441 do {
1442 if (lvlCode < 80) fread(&lcode, sizeof(char), 1, file);
1443 fread(enemdead, sizeof(int), ROOMMAX, file);
1444 fread(&bspminutes, sizeof(int), 1, file);
1445 fread(&bspseconds, sizeof(int), 1, file);
1446 } while (lvlCode < 80 && lcode != lvlCode && !feof(file));
1447 fclose(file);
1448 } else {
1449 for (i=0; i<ROOMMAX; i++) enemdead[i] = 0;
1450 bspminutes = 0;
1451 bspseconds = 0;
1452 }
1453 bspframes = 0;
1454 benemalldead = 0;
1455 } else {
1456 bspminutes = spminutes;
1457 bspseconds = spseconds;
1458 bspframes = spframes;
1459 if (enemdeadhere) enemdead[tempAreaCode] = 1;
1460 benemalldead = enemalldead;
1461 }
1462
1463 if (!flag) {
1464 haswmed = gotmedals[lvlCode*6];
1465 hasomed = gotmedals[lvlCode*6+1];
1466 hasbmed = gotmedals[lvlCode*6+2];
1467 hasrmed = gotmedals[lvlCode*6+3];
1468 hasgmed = gotmedals[lvlCode*6+4];
1469 haspmed = gotmedals[lvlCode*6+5];
1470 }
1471
1472 if (ingame == 3 && savereturn) save_room_return(flag);
1473
1474 load_backups();
1475 }
1476
1477
game_init()1478 void game_init() {
1479 gravdir = DOWN;
1480 switchflags = 0;
1481 lvlCode = 0;
1482 areaCode = 0;
1483 gameNum = 1;
1484 mfragcount = 0;
1485 enemalldead = 0;
1486 freecam = 0;
1487
1488 initialize_thingnodes();
1489
1490 initmapmsg = 0;
1491 initgamemsg = 0;
1492
1493 mousecammode = 1;
1494
1495 ingame = 0;
1496 walkaway = 0;
1497
1498 switch_music(0, 1);
1499
1500 crtplacetile = PURPLETILE;
1501 crtplacetype = WOODBLOCK;
1502 crtplacesubtype = 0;
1503 crtplacedir = 0;
1504 crtentrance = 0;
1505 crtexit = 0;
1506 crtexitroom = 0;
1507 crtmessage = 0;
1508
1509 read_level();
1510 init_play(1,1);
1511 }
1512
1513
clear_selection()1514 void clear_selection() {
1515 for (i=0; i<THINGMAX; i++) {
1516 selection[i] = 0;
1517 }
1518 }
1519
1520
init_creator()1521 void init_creator() {
1522 crtgridsize = 1;
1523 crtgridsnap = 1;
1524 crtlinking = 0;
1525 crtinventory = 0;
1526 switchflags |= NOCOLLIDEFLAG;
1527 crtselect = 0;
1528 clear_selection();
1529 load_backups();
1530 }
1531
1532
1533 // removes the room return data
remove_room_return()1534 void remove_room_return() {
1535 char filestr[512];
1536 sprintf(filestr, "%ssaves%sgame%d.ret", support_path, DIRSEP, gameNum);
1537 remove(filestr);
1538 }
1539
1540
1541 // reloads room return data
load_room_return()1542 void load_room_return() {
1543 char filestr[512];
1544 int flag, hsvsttemp;
1545 sprintf(filestr, "%ssaves%sgame%d.ret", support_path, DIRSEP, gameNum);
1546 file = fopen(filestr, "rb");
1547 #define daskjdf
1548
1549 if (file) {
1550 fread(&lvlCode, sizeof(int), 1, file);
1551 fread(&areaCode, sizeof(int), 1, file);
1552 fread(&gotmwht, sizeof(int), 1, file);
1553 fread(gotmcrn, sizeof(int), 4, file);
1554 fread(&mfragcount, sizeof(int), 1, file);
1555 fread(gotmfrag, sizeof(int), MFRAGTOTAL, file);
1556 fread(&gotgmed, sizeof(int), 1, file);
1557 fread(&gotpmed, sizeof(int), 1, file);
1558 fread(&trgentrance, sizeof(int), 1, file);
1559 fread(&spminutes, sizeof(int), 1, file);
1560 fread(&spseconds, sizeof(int), 1, file);
1561 fread(&spframes, sizeof(int), 1, file);
1562 fread(&enemalldead, sizeof(int), 1, file);
1563 fread(enemdead, sizeof(int), ROOMMAX, file);
1564 fread(&haswmed, sizeof(int), 1, file);
1565 fread(&hasomed, sizeof(int), 1, file);
1566 fread(&hasbmed, sizeof(int), 1, file);
1567 fread(&hasrmed, sizeof(int), 1, file);
1568 fread(&hasgmed, sizeof(int), 1, file);
1569 fread(&haspmed, sizeof(int), 1, file);
1570 fread(&usedsavestate, sizeof(int), 1, file);
1571 fread(&hsvsttemp, sizeof(int), 1, file);
1572 fread(&flag, sizeof(int), 1, file);
1573 if (!fread(&((get_bossvars())[BOSSMAX-1]), sizeof(int), 1, file))
1574 (get_bossvars())[BOSSMAX-1] = 0;
1575 mapCode = lvlCode / 20;
1576
1577 fclose(file);
1578
1579 read_level();
1580
1581 if (!loaderror) {
1582 ingame = 3;
1583 init_play(flag, 0);
1584 } else {
1585 ingame = 2;
1586 start_map();
1587 }
1588
1589 hassavestate = hsvsttemp;
1590 hasbkpsavestate = 0;
1591 loadedbkpsavestate = 0;
1592 }
1593 }
1594
1595
switch_background(int newbkg)1596 void switch_background(int newbkg) {
1597 char filestr[512];
1598
1599 if (newbkg != curbkg) {
1600 curbkg = newbkg;
1601 if (curbkg > 0) {
1602 SDL_FreeSurface(background);
1603 sprintf(filestr, RESOURCE_PATH "images%sbkg%d.png", DIRSEP, curbkg);
1604 background = load_img(filestr);
1605 }
1606 }
1607 }
1608
1609
1610 // Plays the sound with the given index once on the first free channel.
play_sound(int index)1611 void play_sound(int index) {
1612 if (musicon == 1 || musicon == 3) Mix_PlayChannel(-1, sound[index], 0);
1613 }
1614
1615
1616 // Determines if the object is on the visible screen.
on_screen(int xpos,int ypos,int xsize,int ysize)1617 int on_screen(int xpos, int ypos, int xsize, int ysize) {
1618 return xpos + xsize > camx - SOUNDDIST &&
1619 xpos < camx + SCR_WIDTH + SOUNDDIST &&
1620 ypos + ysize > camy - SOUNDDIST &&
1621 ypos < camy + SCR_HEIGHT + SOUNDDIST;
1622 }
1623
1624
set_up_input(char * inptstr,int inputtype,int ilength,int deflt)1625 void set_up_input(char* inptstr, int inputtype,
1626 int ilength, int deflt) {
1627 sprintf(getinputstr, "%s", inptstr);
1628 getinput = inputtype;
1629 inputlength = ilength;
1630 inputpos = 0;
1631 if (deflt > -1) {
1632 sprintf(inputstr, "%d", deflt);
1633 inputpos = strlen(inputstr);
1634 } else strcpy(inputstr, "-");
1635 yesno = 0;
1636 }
1637
1638
1639 /* // Read level data stored in the executable. */
1640 /* void read_intern_level() { */
1641 /* int k; */
1642 /* clear_room(); */
1643 /* char *stp, *enp; */
1644 /* int musictemp, bkgtemp; */
1645 /* if (get_intern_ptrs(&stp, &enp)) { */
1646 /* hassaved = 1; */
1647 /* bkgtemp = *(int*)stp; */
1648 /* stp += sizeof(int); */
1649 /* musictemp = *(int*)stp; */
1650 /* stp += sizeof(int); */
1651 /* lvlWidth = *(int*)stp; */
1652 /* stp += sizeof(int); */
1653 /* lvlHeight = *(int*)stp; */
1654 /* stp += sizeof(int); */
1655 /* startx = *(int*)stp; */
1656 /* stp += sizeof(int); */
1657 /* starty = *(int*)stp; */
1658 /* stp += sizeof(int); */
1659 /* for (i = 0; i < THINGMAX; i++) { */
1660 /* memcpy(&things[i], stp, sizeof(Thing)); */
1661 /* stp += sizeof(Thing); */
1662 /* } */
1663 /* for (i = 0; i < lvlWidth/SPR_SIZE; i++) */
1664 /* for (j = 0; j < lvlHeight/SPR_SIZE; j++) */
1665 /* for (k = 0; k < 3; k++) { */
1666 /* tiles[i][j][k] = *(int*)stp; */
1667 /* stp += sizeof(int); */
1668 /* } */
1669 /* if (bkgtemp < 1 || bkgtemp > BKG_MAX - 1) bkgtemp = 1; */
1670 /* if (musictemp < 0 || musictemp > MUSIC_MAX - 1) musictemp = 0; */
1671 /* clear_selection(); */
1672 /* switch_music(musictemp, 0); */
1673 /* switch_background(bkgtemp); */
1674 /* } else { */
1675 /* loaderror = 1; */
1676 /* set_up_input("The file was not found",1,-1,-1); */
1677 /* } */
1678 /* } */
1679
1680
read_level()1681 void read_level() {
1682 clear_room();
1683 char filestr[512];
1684 int musictemp, bkgtemp, k;
1685 char lcode, acode;
1686 if (lvlCode < 80) {
1687 sprintf(filestr, RESOURCE_PATH "rooms/rooms");
1688 } else {
1689 sprintf(filestr, "%srooms%sl%dr%d.room", support_path, DIRSEP, lvlCode, areaCode);
1690 }
1691 file = fopen(filestr, "rb");
1692 if (file) {
1693 hassaved = 1;
1694 do {
1695 if (lvlCode < 80) {
1696 fread(&lcode, sizeof(char), 1, file);
1697 fread(&acode, sizeof(char), 1, file);
1698 }
1699 fread(&bkgtemp, sizeof(int), 1, file);
1700 fread(&musictemp, sizeof(int), 1, file);
1701 fread(&lvlWidth, sizeof(int), 1, file);
1702 fread(&lvlHeight, sizeof(int), 1, file);
1703 fread(&startx, sizeof(int), 1, file);
1704 fread(&starty, sizeof(int), 1, file);
1705 fread(things, sizeof(Thing), THINGMAX, file);
1706 for (i=0;i<lvlWidth/SPR_SIZE;i++)
1707 for (j=0;j<lvlHeight/SPR_SIZE;j++)
1708 for (k=0;k<3;k++)
1709 fread(&tilebackup[i][j][k], sizeof(int), 1, file);
1710 } while ((lcode != lvlCode || acode != areaCode) &&
1711 !feof(file) && lvlCode < 80);
1712 for (i=0;i<lvlWidth/SPR_SIZE;i++)
1713 for (j=0;j<lvlHeight/SPR_SIZE;j++)
1714 for (k=0;k<3;k++)
1715 tiles[i][j][k] = tilebackup[i][j][k];
1716 if (bkgtemp < 1 || bkgtemp > BKG_MAX - 1) bkgtemp = 1;
1717 if (musictemp < 0 || musictemp > MUSIC_MAX - 1) musictemp = 0;
1718 clear_selection();
1719 switch_music(musictemp, 0);
1720 switch_background(bkgtemp);
1721 fclose(file);
1722 } else {
1723 loaderror = 1;
1724 if (lvlCode < 80 || creatormode)
1725 set_up_input("The file was not found",1,-1,-1);
1726 else set_up_input("Make the level first!",1,-1,-1);
1727 }
1728 }
1729
1730
check_level_exists()1731 int check_level_exists() {
1732 char filestr[512];
1733 if (lvlCode < 80) {
1734 sprintf(filestr, RESOURCE_PATH "rooms/rooms");
1735 } else {
1736 sprintf(filestr, "%srooms%sl%dr%d.room", support_path, DIRSEP, lvlCode, areaCode);
1737 }
1738 file = fopen(filestr, "rb");
1739 if (file) {
1740 fclose(file);
1741 return 1;
1742 }
1743 return 0;
1744 }
1745
1746
write_level()1747 void write_level() {
1748 char filestr[512];
1749 int k;
1750 sprintf(filestr, "%srooms%sl%dr%d.room", support_path, DIRSEP, lvlCode, areaCode);
1751 file = fopen(filestr, "wb");
1752 if (file) {
1753 hassaved = 1;
1754 fwrite(&curbkg, sizeof(int), 1, file);
1755 fwrite(&curmusic, sizeof(int), 1, file);
1756 fwrite(&lvlWidth, sizeof(int), 1, file);
1757 fwrite(&lvlHeight, sizeof(int), 1, file);
1758 fwrite(&startx, sizeof(int), 1, file);
1759 fwrite(&starty, sizeof(int), 1, file);
1760 fwrite(things, sizeof(Thing), THINGMAX, file);
1761 for (i=0;i<lvlWidth/SPR_SIZE;i++)
1762 for (j=0;j<lvlHeight/SPR_SIZE;j++)
1763 for (k=0;k<3;k++)
1764 fwrite(&tiles[i][j][k], sizeof(int), 1, file);
1765 fclose(file);
1766 } else {
1767 set_up_input("The file was not opened",1,-1,-1);
1768 }
1769 }
1770
1771
write_metalevel()1772 void write_metalevel() {
1773 char filestr[512];
1774 int oldroom = areaCode, oldbkg = curbkg, oldmusic = curmusic;
1775 int fragcount=0;
1776 int iter=0;
1777
1778 for (iter=0; iter<ROOMMAX; iter++) {
1779 enemdead[iter] = 1;
1780 areaCode = iter;
1781 sprintf(filestr, "%srooms%sl%dr%d.room", support_path, DIRSEP, lvlCode, areaCode);
1782 file = fopen(filestr, "rb");
1783 if (file) {
1784 fread(&curbkg, sizeof(int), 1, file);
1785 fread(&curmusic, sizeof(int), 1, file);
1786 fread(&lvlWidth, sizeof(int), 1, file);
1787 fread(&lvlHeight, sizeof(int), 1, file);
1788 fread(&startx, sizeof(int), 1, file);
1789 fread(&starty, sizeof(int), 1, file);
1790 fread(things, sizeof(Thing), THINGMAX, file);
1791 for (i=0;i<lvlWidth/SPR_SIZE;i++)
1792 for (j=0;j<lvlHeight/SPR_SIZE;j++)
1793 fread(tiles[i][j], sizeof(int), 3, file);
1794 for (i=0; i<THINGMAX; i++) {
1795 if (things[i].type != NOTYPE && things[i].animate) {
1796 enemdead[iter] = 0;
1797 }
1798 if (things[i].type == MEDALFRAGMENT) {
1799 things[i].dir = fragcount++;
1800 }
1801 }
1802 fclose(file);
1803 write_level();
1804 }
1805 }
1806
1807 sprintf(filestr, "%srooms%slvl%d.meta", support_path, DIRSEP, lvlCode);
1808 file = fopen(filestr, "wb");
1809 if (file) {
1810 fwrite(enemdead, sizeof(int), ROOMMAX, file);
1811 fwrite(&spminutes, sizeof(int), 1, file);
1812 fwrite(&spseconds, sizeof(int), 1, file);
1813 fclose(file);
1814 } else {
1815 set_up_input("The file was not opened",1,-1,-1);
1816 }
1817
1818 if (fragcount != MFRAGTOTAL) {
1819 sprintf(filestr, "%d fragments found", fragcount);
1820 set_up_input(filestr,1,-1,-1);
1821 }
1822
1823 areaCode = oldroom;
1824 curbkg = oldbkg;
1825 curmusic = oldmusic;
1826 read_level();
1827 }
1828
1829
set_start_pos()1830 void set_start_pos() {
1831 int temp1 = mx, temp2 = my;
1832 if (crtgridsnap && crtgridsize > 0) {
1833 if (crtgridsize == 1) {
1834 temp1 = temp1-temp1%SPR_SIZE+SPR_SIZE/2;
1835 temp2 = temp2-temp2%SPR_SIZE+SPR_SIZE-beret.height/2;
1836 } else {
1837 temp1 = temp1-temp1%(SPR_SIZE/2)+SPR_SIZE/4;
1838 temp2 = temp2-temp2%(SPR_SIZE/2)+SPR_SIZE/2-beret.height/2;
1839 }
1840 }
1841 startx = temp1-beret.width/2;
1842 starty = temp2-beret.height/2;
1843 }
1844
1845
paste_helper(int leftmost,int topmost,int copyindices[250],int index,int flag)1846 void paste_helper(int leftmost, int topmost,
1847 int copyindices[250], int index, int flag) {
1848 int copyindex;
1849 if (key3 != SHIFT) selection[index] = 0;
1850 if ((copyindex = copy_thing(&things[index], things, -1)) == -1) return;
1851 copyindices[index] = copyindex;
1852 things[copyindex].x = things[index].x-leftmost+mx;
1853 things[copyindex].y = things[index].y-topmost+my;
1854 if (things[copyindex].x > lvlWidth-things[copyindex].width)
1855 things[copyindex].x = lvlWidth-things[copyindex].width;
1856 if (things[copyindex].y > lvlHeight-things[copyindex].height)
1857 things[copyindex].y = lvlHeight-things[copyindex].height;
1858 things[copyindex].vx = 0.01;
1859 things[copyindex].vy = 0.01;
1860 if (flag && things[index].link > -1) {
1861 if (copyindices[things[index].link] > -1) {
1862 things[copyindex].link = copyindices[things[index].link];
1863 if (things[index].subtype % 2 == 0)
1864 things[copyindices[things[index].link]].islinked = copyindex;
1865 else things[copyindex].islinked = copyindices[things[index].link];
1866 }
1867 }
1868 selection[copyindex] = (copyindex<i?1:-1);
1869 }
1870
1871
1872 // copies every selected object and pastes them to the mouse position
paste_objects()1873 void paste_objects() {
1874 int leftmost = lvlWidth, topmost = lvlHeight;
1875 int copyindices[250];
1876 for (i=0; i<THINGMAX; i++) {
1877 if (things[i].type != NOTYPE && selection[i]) {
1878 if (things[i].x < leftmost) leftmost = things[i].x;
1879 if (things[i].y < topmost) topmost = things[i].y;
1880 }
1881 copyindices[i] = -1;
1882 }
1883 for (j=0; j < 2; j++) {
1884 for (i=0; i<THINGMAX; i++) {
1885 if (things[i].type != NOTYPE && (things[i].type == LINKBLOCK) == j) {
1886 if (selection[i] == 1) {
1887 paste_helper(leftmost, topmost, copyindices, i, j);
1888 } else if (selection[i] == -1) selection[i] = 1;
1889 }
1890 }
1891 }
1892 }
1893
1894
1895 // creates an instance of the current object
create_object()1896 void create_object() {
1897 if (key3 != SHIFT) clear_selection();
1898 int empty;
1899 if ((empty = find_empty(things)) == -1) return;
1900 make_thing(empty, crtplacetype, crtplacesubtype, mx, my,
1901 get_param(crtplacetype, crtplacedir, -1), things);
1902 if (things[empty].x > lvlWidth-things[empty].width)
1903 things[empty].x = lvlWidth-things[empty].width;
1904 if (things[empty].y > lvlHeight-things[empty].height)
1905 things[empty].y = lvlHeight-things[empty].height;
1906 things[empty].vx = 0.01;
1907 things[empty].vy = 0.01;
1908 things[empty].islinked = -1;
1909 selection[empty] = 1;
1910 if (crtplacetype == DOOR || crtplacetype == SIGN) {
1911 things[empty].timer = crtentrance;
1912 things[empty].status = crtexit;
1913 things[empty].dir = crtexitroom;
1914 }
1915 if (crtplacetype == READSIGN) {
1916 things[empty].dir = crtmessage;
1917 }
1918 hassaved = 0;
1919 }
1920
1921
1922 // looks at adjacent tiles and makes the tile borders pretty
fix_tile_borders(int xpos,int ypos,int recurse)1923 void fix_tile_borders(int xpos, int ypos, int recurse) {
1924
1925 /* ABC
1926 H D
1927 GFE */
1928
1929 int dirflags = 0;
1930 int b = BLANK;
1931 int type = tiles[xpos][ypos][0];
1932 int rside = lvlWidth/SPR_SIZE-1, bside = lvlHeight/SPR_SIZE-1;
1933
1934 if (xpos == 0) dirflags |= (A_ | H_ | G_);
1935 if (ypos == 0) dirflags |= (A_ | B_ | C_);
1936 if (xpos == rside) dirflags |= (C_|D_|E_);
1937 if (ypos == bside) dirflags |= (E_|F_|G_);
1938 if (xpos > 0) {
1939 if (tiles[xpos-1][ypos][0] == type) dirflags |= H_;
1940 if (recurse) fix_tile_borders(xpos-1,ypos,0);
1941 }
1942 if (ypos > 0) {
1943 if (tiles[xpos][ypos-1][0] == type) dirflags |= B_;
1944 if (recurse) fix_tile_borders(xpos,ypos-1,0);
1945 }
1946 if (xpos < rside) {
1947 if (tiles[xpos+1][ypos][0] == type) dirflags |= D_;
1948 if (recurse) fix_tile_borders(xpos+1,ypos,0);
1949 }
1950 if (ypos < bside) {
1951 if (tiles[xpos][ypos+1][0] == type) dirflags |= F_;
1952 if (recurse) fix_tile_borders(xpos, ypos+1, 0);
1953 }
1954 if (xpos > 0 && ypos > 0) {
1955 if (tiles[xpos-1][ypos-1][0] == type) dirflags |= A_;
1956 if (recurse) fix_tile_borders(xpos-1,ypos-1,0);
1957 }
1958 if (xpos < rside) {
1959 if (ypos > 0 && tiles[xpos+1][ypos-1][0] == type) dirflags |= C_;
1960 if (recurse) fix_tile_borders(xpos+1,ypos-1,0);
1961 }
1962 if (xpos < rside && ypos < bside) {
1963 if (tiles[xpos+1][ypos+1][0] == type) dirflags |= E_;
1964 if (recurse) fix_tile_borders(xpos+1,ypos+1,0);
1965 }
1966 if (xpos > 0 && ypos < bside) {
1967 if (tiles[xpos-1][ypos+1][0] == type) dirflags |= G_;
1968 if (recurse) fix_tile_borders(xpos-1,ypos+1,0);
1969 }
1970
1971 if (type == OBJONLY || type == BERETONLY || type == CHOICEONLY ||
1972 (type >= SPIKEU && type <= SPIKEL) || (type >= MOVERU && type <= MOVERL) || type == DARKNESSTILE) {
1973 tiles[xpos][ypos][2] = BLANK;
1974 return;
1975 }
1976
1977 if (!(dirflags & (B_|D_|F_|H_))) b = ALL;
1978 else if (dirflags == 0xff) b = BLANK;
1979 else if (dirflags == (B_|D_|F_|H_)) b = ALLDOTS;
1980 else if (dirflags == (B_|C_|D_|E_|F_|G_|H_)) b = ULDOT;
1981 else if (dirflags == (A_|B_|D_|E_|F_|G_|H_)) b = URDOT;
1982 else if (dirflags == (A_|B_|C_|D_|E_|F_|H_)) b = DLDOT;
1983 else if (dirflags == (A_|B_|C_|D_|F_|G_|H_)) b = DRDOT;
1984 else if (dirflags == (B_|D_|E_|F_|G_|H_)) b = UDOTS;
1985 else if (dirflags == (A_|B_|D_|F_|G_|H_)) b = RDOTS;
1986 else if (dirflags == (A_|B_|C_|D_|F_|H_)) b = DDOTS;
1987 else if (dirflags == (B_|C_|D_|E_|F_|H_)) b = LDOTS;
1988 else if (dirflags == (A_|B_|D_|F_|H_)) b = NULDOT;
1989 else if (dirflags == (C_|B_|D_|F_|H_)) b = NURDOT;
1990 else if (dirflags == (E_|B_|D_|F_|H_)) b = NDRDOT;
1991 else if (dirflags == (G_|B_|D_|F_|H_)) b = NDLDOT;
1992 else if (dirflags == (B_|C_|D_|F_|G_|H_)) b = ULDRDOTS;
1993 else if (dirflags == (A_|B_|D_|E_|F_|H_)) b = URDLDOTS;
1994 else if ((dirflags | (A_|B_|C_)) == 0xff) b = U;
1995 else if ((dirflags | (C_|D_|E_)) == 0xff) b = R;
1996 else if ((dirflags | (E_|F_|G_)) == 0xff) b = D;
1997 else if ((dirflags | (G_|H_|A_)) == 0xff) b = L;
1998 else if ((dirflags | (A_|B_|C_|E_|G_)) == 0xff) {
1999 if (dirflags & E_) b = UWLDOT;
2000 else if (dirflags & G_) b = UWRDOT;
2001 else b = UW2DOTS;
2002 } else if ((dirflags | (C_|D_|E_|G_|A_)) == 0xff) {
2003 if (dirflags & A_) b = RWDDOT;
2004 else if (dirflags & G_) b = RWUDOT;
2005 else b = RW2DOTS;
2006 } else if ((dirflags | (E_|F_|G_|A_|C_)) == 0xff) {
2007 if (dirflags & A_) b = DWRDOT;
2008 else if (dirflags & C_) b = DWLDOT;
2009 else b = DW2DOTS;
2010 } else if ((dirflags | (G_|H_|A_|C_|E_)) == 0xff) {
2011 if (dirflags & C_) b = LWDDOT;
2012 else if (dirflags & E_) b = LWUDOT;
2013 else b = LW2DOTS;
2014 }
2015 else if ((dirflags | (A_|H_|G_|C_|D_|E_)) == 0xff) b = LR;
2016 else if ((dirflags | (A_|B_|C_|G_|E_|F_)) == 0xff) b = UD;
2017 else if ((dirflags | (A_|B_|C_|D_|E_)) == 0xff) b = UR;
2018 else if ((dirflags | (C_|D_|E_|F_|G_)) == 0xff) b = DR;
2019 else if ((dirflags | (A_|H_|G_|F_|E_)) == 0xff) b = DL;
2020 else if ((dirflags | (A_|B_|C_|G_|H_)) == 0xff) b = UL;
2021 else if ((dirflags | (A_|B_|C_|D_|E_|G_)) == 0xff) b = URWDOT;
2022 else if ((dirflags | (C_|D_|E_|F_|G_|A_)) == 0xff) b = DRWDOT;
2023 else if ((dirflags | (A_|H_|G_|F_|E_|C_)) == 0xff) b = DLWDOT;
2024 else if ((dirflags | (A_|B_|C_|G_|H_|E_)) == 0xff) b = ULWDOT;
2025 else if ((dirflags | (A_|C_|D_|E_|F_|G_|H_)) == 0xff) b = NU;
2026 else if ((dirflags | (A_|B_|C_|E_|F_|G_|H_)) == 0xff) b = NR;
2027 else if ((dirflags | (A_|B_|C_|D_|E_|G_|H_)) == 0xff) b = ND;
2028 else if ((dirflags | (A_|B_|C_|D_|E_|F_|G_)) == 0xff) b = NL;
2029
2030 tiles[xpos][ypos][2] = b;
2031
2032 /* ABC
2033 H D
2034 GFE */
2035 }
2036
2037
2038 // returns 1 if given type is transparent but not an "only" wall
see_through(int type)2039 int see_through(int type) {
2040 return (type >= WHITEFUZZSEE && type <= GREENFUZZSEE) ||
2041 type == GLASS || (type >= PURPLETILESEE && type <= WHITETILESEE) ||
2042 type == CLEAR || type == REDFUZZSEE || type == BLACKTILESEE ||
2043 (type >= WHITESPRSEE && type <= PURPLESPRSEE) ||
2044 (type >= REDSEECRPT && type <= BLUESEECRPT) || type == ANTITILE ||
2045 (type >= SPIKEU && type <= SPIKEL);
2046 }
2047
2048
2049 // creates a grid of the current tile type
create_tiles(int type)2050 void create_tiles(int type) {
2051 int sell, selr, selt, selb;
2052 if (crtselect) {
2053 if (selx < mx) {
2054 sell = selx; selr = mx;
2055 } else {
2056 sell = mx; selr = selx;
2057 }
2058 if (sely < my) {
2059 selt = sely; selb = my;
2060 } else {
2061 selt = my; selb = sely;
2062 }
2063 sell /= SPR_SIZE;
2064 selr /= SPR_SIZE;
2065 selt /= SPR_SIZE;
2066 selb /= SPR_SIZE;
2067 } else {
2068 sell = mx/SPR_SIZE;
2069 selr = mx/SPR_SIZE;
2070 selt = my/SPR_SIZE;
2071 selb = my/SPR_SIZE;
2072 }
2073 for (i=sell;i<=selr;i++) {
2074 for (j=selt;j<=selb;j++) {
2075 tiles[i][j][0] = type;
2076 switch (type) {
2077 case OBJONLY : tiles[i][j][1] = OBJONLYF; break;
2078 case BERETONLY : tiles[i][j][1] = BERETONLYF; break;
2079 case MOVERU : case MOVERR : case MOVERD : case MOVERL :
2080 case CHOICEONLY : case DARKNESSTILE: tiles[i][j][1] = NOTSOLIDF; break;
2081 default : tiles[i][j][1] = SOLID;
2082 }
2083 if (see_through(type)) tiles[i][j][1] = SOLIDF;
2084 fix_tile_borders(i,j,1);
2085 }
2086 }
2087 hassaved = 0;
2088 }
2089
2090
load_state(int backup)2091 void load_state(int backup) {
2092 if (hassavestate) {
2093 int trash; // dump unneeded values
2094 int oldcamx = camx, oldcamy = camy;
2095 char filestr[512];
2096 char bkpstr[5];
2097 if (backup && hasbkpsavestate) sprintf(bkpstr, "bkp");
2098 else bkpstr[0] = 0;
2099 sprintf(filestr, "%ssaves%sgame%d.sav%s", support_path, DIRSEP, gameNum, bkpstr);
2100 file = fopen(filestr, "rb");
2101 if (file) {
2102 if (backup && hasbkpsavestate) loadedbkpsavestate = 1;
2103 else loadedbkpsavestate = 0;
2104 fread(&beret, sizeof(Thing), 1, file);
2105 beret.subtype = istophat;
2106 fread(&camx, sizeof(int),1,file);
2107 fread(&camy, sizeof(int),1,file);
2108 fread(things, sizeof(Thing), THINGMAX, file);
2109 for (i=0;i<lvlWidth/SPR_SIZE;i++)
2110 for (j=0;j<lvlHeight/SPR_SIZE;j++)
2111 fread(tiles[i][j], sizeof(int), 3, file);
2112 fread(particles, sizeof(Particle), PARTICLEMAX, file);
2113 fread(&mfragcount, sizeof(int), 1, file);
2114 fread(gotmfrag, sizeof(int), MFRAGTOTAL, file);
2115 fread(gotmcrn, sizeof(int), 4, file);
2116 fread(&gotmwht, sizeof(int), 1, file);
2117 fread(&gotgmed, sizeof(int), 1, file);
2118 fread(&gotpmed, sizeof(int), 1, file);
2119 fread(&enemdeadhere, sizeof(int), 1, file);
2120 fread(&enemalldead, sizeof(int), 1, file);
2121 fread(&spframes, sizeof(int), 1, file);
2122 fread(&spseconds, sizeof(int), 1, file);
2123 fread(&spminutes, sizeof(int), 1, file);
2124 fread(&telething, sizeof(int), 1, file);
2125 fread(&switchflags, sizeof(int), 1, file);
2126 if (!mousecammode) {
2127 fread(&mx, sizeof(int), 1, file);
2128 fread(&my, sizeof(int), 1, file);
2129 } else {
2130 fread(&trash, sizeof(int), 1, file);
2131 fread(&trash, sizeof(int), 1, file);
2132 }
2133 if (!fread(&gotallfrags, sizeof(int), 1, file))
2134 gotallfrags = 0;
2135 fread(get_bossvars(), sizeof(int), BOSSMAX, file);
2136 fread(&gravdir, sizeof(int), 1, file);
2137 int jumpgrace, runmargin;
2138 if (!fread(&jumpgrace, sizeof(int), 1, file)) jumpgrace = 0;
2139 if (!fread(&runmargin, sizeof(int), 1, file)) runmargin = 0;
2140 set_jumpgrace(jumpgrace);
2141 set_runmargin(runmargin);
2142
2143 if (!mousecammode) SDL_WarpMouse(mx-camx, my-camy);
2144 else {
2145 mx -= oldcamx - camx;
2146 my -= oldcamy - camy;
2147 }
2148
2149 fix_camera();
2150 deathtime = 0;
2151 fadetime = 0;
2152 walkaway = 0;
2153
2154 if (telething > -1 &&
2155 !(alwaystele && teleon) && !(!alwaystele && cantele))
2156 stop_telekinesis();
2157
2158 usedsavestate = 1;
2159 svstcount = -30;
2160
2161 fclose(file);
2162 } else {
2163 set_up_input("The file was not found",1,-1,-1);
2164 }
2165 }
2166 }
2167
2168
save_map(int num)2169 void save_map(int num) {
2170 char filestr[512];
2171 sprintf(filestr, "%srooms%sbr%d.mp", support_path, DIRSEP, num);
2172 file = fopen(filestr, "wb");
2173 if (file) {
2174 for (i=0;i<SCR_WIDTH/SPR_SIZE;i++)
2175 for (j=0;j<(SCR_HEIGHT-150)/SPR_SIZE;j++)
2176 fwrite(tiles[i][j], sizeof(int), 3, file);
2177 fclose(file);
2178 } else {
2179 set_up_input("The file was not opened",1,-1,-1);
2180 }
2181 }
2182
2183
load_map(int num)2184 void load_map(int num) {
2185 char filestr[512];
2186 char mcode;
2187 // sprintf(filestr, "rooms%sbr%d.mp", DIRSEP, num);
2188 sprintf(filestr, RESOURCE_PATH "rooms/maps");
2189 file = fopen(filestr, "rb");
2190 if (file) {
2191 do {
2192 fread(&mcode, sizeof(char), 1, file);
2193 for (i=0;i<SCR_WIDTH/SPR_SIZE;i++)
2194 for (j=0;j<(SCR_HEIGHT-150)/SPR_SIZE;j++)
2195 fread(tiles[i][j], sizeof(int), 3, file);
2196 } while (mcode != num && !feof(file));
2197 fclose(file);
2198 } else {
2199 set_up_input("The file was not found",1,-1,-1);
2200 }
2201
2202 sprintf(filestr, "%ssaves%sgame%d.ret", support_path, DIRSEP, gameNum);
2203 file = fopen(filestr, "rb");
2204 if (file) {
2205 fread(&contlvl, sizeof(int), 1, file);
2206 fclose(file);
2207 if (contlvl / 20 == mapCode) cancont = 1;
2208 else cancont = 0;
2209 } else {
2210 cancont = 0;
2211 }
2212 }
2213
2214
start_map()2215 void start_map() {
2216 int minabovegm = UNF;
2217 nextopenlevel = -1;
2218 for (i=0; i<20; i++)
2219 if (levelentry[mapCode][i] < minabovegm &&
2220 levelentry[mapCode][i] > gamemedals) {
2221 minabovegm = levelentry[mapCode][i];
2222 nextopenlevel = i;
2223 }
2224 switch_music(1, 0);
2225 mapselect = -1;
2226 int curcamx = camx, curcamy = camy;
2227 camx = 0;
2228 camy = 0;
2229 mx += camx-curcamx;
2230 my += camy-curcamy;
2231 load_map(mapCode);
2232 }
2233
2234
check_map_select()2235 void check_map_select() {
2236 if (mx >= 0 && my >= 0) {
2237 mapselect = tiles[mx/SPR_SIZE][my/SPR_SIZE][0] - MAPTILE;
2238 if (mapselect + MAPTILE == CLEAR) {
2239 if (cancont) mapselect = contlvl - mapCode*20;
2240 else mapselect = -1;
2241 } else if (mapselect < 0 ||
2242 (levelentry[mapCode][mapselect] > gamemedals && mapselect != nextopenlevel && mapCode < 4))
2243 mapselect = -1;
2244 }
2245 }
2246
2247
draw_map_status()2248 void draw_map_status() {
2249 display_message(74,15,smfont,"S TO VIEW THE STORY",1);
2250 display_message(74,30,smfont,"C TO VIEW THE CONTROLS",1);
2251 display_message(74,45,smfont,"A TO VIEW THE CREDITS",1);
2252 display_message(SCR_WIDTH/4,500,font,"Evil Corporation",1);
2253 display_message(SCR_WIDTH/4,530,medfont,wingnames[mapCode],1);
2254 sprintf(messagestr, "%d", gamemedals);
2255 display_message(SCR_WIDTH/4+30, 565, font, 0,1);
2256 apply_sprite(SCR_WIDTH/4-message->w/2-45,565-message->h/2,5,15,
2257 1,1,spritesheet,screen);
2258 if (mapselect > -1) {
2259 apply_surface((SCR_WIDTH-lvlnumbkg->w)/2, 400, lvlnumbkg, screen);
2260 sprintf(messagestr, "%d", levelnums[mapCode][mapselect]);
2261 display_message(SCR_WIDTH/2+numofst[levelnums[mapCode][mapselect]-1],422,font,0,0);
2262 sprintf(messagestr, "Department of %s", deptnames[mapCode][mapselect]);
2263 int deptnameofst = (mapCode==3||(mapCode==4 && mapselect==10))?30:(mapCode==4?15:0);
2264 display_message(3*SCR_WIDTH/4,500+deptnameofst,font,0,1);
2265 if (strcmp(divnames[mapCode][mapselect], "-")) {
2266 sprintf(messagestr, "%s Division", divnames[mapCode][mapselect]);
2267 display_message(3*SCR_WIDTH/4,530+deptnameofst,medfont,0,1);
2268 }
2269 if (levelentry[mapCode][mapselect] > gamemedals) {
2270 sprintf(messagestr, "%d Medallions required for entry", levelentry[mapCode][mapselect]);
2271 display_message(3*SCR_WIDTH/4,565,medfont,0,1);
2272 } else {
2273 if (mapCode < 3) {
2274 for (i=0; i<6; i++) {
2275 if (gotmedals[(mapCode*20+mapselect)*6+i])
2276 apply_sprite(3*SCR_WIDTH/4-165+i*60, 547, medalsprx[i],
2277 medalspry[i], 1, 1, spritesheet, screen);
2278 else
2279 apply_sprite(3*SCR_WIDTH/4-165+i*60, 547, 17, 17,
2280 1, 1, spritesheet, screen);
2281 }
2282 }
2283 display_message(3*SCR_WIDTH/4,590,smfont,"CLICK TO ENTER",1);
2284 }
2285 }
2286 if (cancont && contlvl > -1) {
2287 display_message(3*SCR_WIDTH/4, 45,smfont,"CONTINUE LAST PLAY",0);
2288 }
2289 if ((mapCode > 0 || (mapCode == 0 && (opencreator || beatlevel[LAST_LEVEL]))) &&
2290 !(mapCode == 4 && !beatlevel[LAST_LEVEL])) {
2291 if (mx >= 30 && mx <= 120 && my >= 195 && my <= 285)
2292 apply_sprite(30, 195, 3, 10, 3, 3, tilesheet, screen);
2293 else apply_sprite(30, 195, 3, 7, 3, 3, tilesheet, screen);
2294 display_message(75, 240, smfont, "PREVIOUS MAP",0);
2295 }
2296 if ((mapCode < 4 && beatlevel[maplastlevel[mapCode]]) || mapCode == 4) {
2297 if (mx >= SCR_WIDTH-120 && mx <= SCR_WIDTH-30 && my >= 195 && my <= 285)
2298 apply_sprite(SCR_WIDTH-120, 195, 0, 10, 3, 3, tilesheet, screen);
2299 else apply_sprite(SCR_WIDTH-120, 195, 0, 7, 3, 3, tilesheet, screen);
2300 display_message(SCR_WIDTH-75, 240, smfont, "NEXT MAP",0);
2301 }
2302 }
2303
2304
draw_creat(int page)2305 void draw_creat(int page) {
2306 apply_surface(0,0,background,screen);
2307 display_message(SCR_WIDTH/2, 30,font,"Creator Guide",1);
2308 for (i=0;i<(page==0?CREAT1LEN:(page==1?CREAT2LEN:CREAT3LEN));i++)
2309 display_message(SCR_WIDTH/2, 60+25*i, medfont,
2310 (page==0?creat1[i]:(page==1?creat2[i]:creat3[i])),1);
2311 }
2312
draw_story()2313 void draw_story() {
2314 apply_surface(0,0,background,screen);
2315 display_message(SCR_WIDTH/2, 30,font,"Story",1);
2316 for (i=0;i<STORYLEN;i++)
2317 display_message(SCR_WIDTH/2, 60+25*i, medfont, story[i],1);
2318 }
2319
draw_controls()2320 void draw_controls() {
2321 apply_surface(0,0,background,screen);
2322 display_message(SCR_WIDTH/2, 45,font,"Game Controls",1);
2323 for (i=0;i<CONTROLLEN;i++)
2324 display_message(SCR_WIDTH/2, 100+25*i, medfont, controls[i],1);
2325 }
2326
draw_map()2327 void draw_map() {
2328 int maptype, addto;
2329 apply_surface(0,0,mapbkg,screen);
2330 for (i = 0; i < SCR_WIDTH/SPR_SIZE; i++) {
2331 for (j = 0; j < 15; j++) {
2332 if (tiles[i][j][0] == CLEAR) {
2333 if (cancont) {
2334 apply_sprite(i*SPR_SIZE, j*SPR_SIZE,
2335 (CLEAR-1)%24,(CLEAR-1)/24,
2336 1,1,tilesheet,screen);
2337 apply_sprite(i*SPR_SIZE, j*SPR_SIZE,
2338 tiles[i][j][2]%24,22+tiles[i][j][2]/24,
2339 1,1,tilesheet,screen);
2340 }
2341 } else if (tiles[i][j][0] == GLASS) {
2342 apply_sprite(i*SPR_SIZE, j*SPR_SIZE,
2343 (GLASS-1)%24,(GLASS-1)/24,
2344 1,1,tilesheet,screen);
2345 apply_sprite(i*SPR_SIZE, j*SPR_SIZE,
2346 tiles[i][j][2]%24,22+tiles[i][j][2]/24,
2347 1,1,tilesheet,screen);
2348 } else if (tiles[i][j][0] > 0) {
2349 maptype = tiles[i][j][0] - MAPTILE;
2350 if (levelentry[mapCode][maptype] <= gamemedals ||
2351 maptype == nextopenlevel || mapCode == 4) {
2352 addto = 0;
2353 if (mapselect == maptype) addto++;
2354 if (levelentry[mapCode][maptype] > gamemedals && !(mapCode == 4 && opencreator)) addto+=2;
2355 apply_sprite(i*SPR_SIZE, j*SPR_SIZE,
2356 (tiles[i][j][0]-1)%24,(tiles[i][j][0]-1)/24+addto,
2357 1,1,tilesheet,screen);
2358 if (addto < 2)
2359 apply_sprite(i*SPR_SIZE, j*SPR_SIZE,
2360 tiles[i][j][2]%24,22+tiles[i][j][2]/24,
2361 1,1,tilesheet,screen);
2362 }
2363 }
2364 }
2365 }
2366 }
2367
2368 // Copies the main savestate file to a backup file.
copy_save_state(char * sf1,char * sf2)2369 int copy_save_state(char *sf1, char *sf2) {
2370 char buf[4096];
2371 int cread;
2372 int successcopy = 0;
2373 FILE *sf1h, *sf2h;
2374 sf1h = fopen(sf1, "rb");
2375 sf2h = fopen(sf2, "wb");
2376 if (sf1h && sf2h) {
2377 while (!feof(sf1h)) {
2378 cread = fread(buf, sizeof(char), 4096, sf1h);
2379 fwrite(buf, sizeof(char), cread, sf2h);
2380 }
2381 successcopy = 1;
2382 }
2383 if (sf1h) fclose(sf1h);
2384 if (sf2h) fclose(sf2h);
2385 return successcopy;
2386 }
2387
2388
save_state()2389 void save_state() {
2390 if (!beret.dead && !fadetime) {
2391 char filestr[512];
2392 sprintf(filestr, "%ssaves%sgame%d.sav", support_path, DIRSEP, gameNum);
2393 if (hassavestate && !loadedbkpsavestate) {
2394 char filestr2[512];
2395 sprintf(filestr2, "%sbkp", filestr);
2396 hasbkpsavestate = copy_save_state(filestr, filestr2);
2397 }
2398 loadedbkpsavestate = 0;
2399 file = fopen(filestr, "wb");
2400 if (file) {
2401 fwrite(&beret, sizeof(Thing), 1, file);
2402 fwrite(&camx, sizeof(int),1,file);
2403 fwrite(&camy, sizeof(int),1,file);
2404 fwrite(things, sizeof(Thing), THINGMAX, file);
2405 for (i=0;i<lvlWidth/SPR_SIZE;i++)
2406 for (j=0;j<lvlHeight/SPR_SIZE;j++)
2407 fwrite(tiles[i][j], sizeof(int), 3, file);
2408 fwrite(particles, sizeof(Particle), PARTICLEMAX, file);
2409 fwrite(&mfragcount, sizeof(int), 1, file);
2410 fwrite(gotmfrag, sizeof(int), MFRAGTOTAL, file);
2411 fwrite(gotmcrn, sizeof(int), 4, file);
2412 fwrite(&gotmwht, sizeof(int), 1, file);
2413 fwrite(&gotgmed, sizeof(int), 1, file);
2414 fwrite(&gotpmed, sizeof(int), 1, file);
2415 fwrite(&enemdeadhere, sizeof(int), 1, file);
2416 fwrite(&enemalldead, sizeof(int), 1, file);
2417 fwrite(&spframes, sizeof(int), 1, file);
2418 fwrite(&spseconds, sizeof(int), 1, file);
2419 fwrite(&spminutes, sizeof(int), 1, file);
2420 fwrite(&telething, sizeof(int), 1, file);
2421 fwrite(&switchflags, sizeof(int), 1, file);
2422 fwrite(&mx, sizeof(int), 1, file);
2423 fwrite(&my, sizeof(int), 1, file);
2424 fwrite(&gotallfrags, sizeof(int), 1, file);
2425 fwrite(get_bossvars(), sizeof(int), BOSSMAX, file);
2426 fwrite(&gravdir, sizeof(int), 1, file);
2427 int jumpgrace = get_jumpgrace(), runmargin = get_runmargin();
2428 fwrite(&jumpgrace, sizeof(int), 1, file);
2429 fwrite(&runmargin, sizeof(int), 1, file);
2430
2431 hassavestate = 1;
2432 svstcount = 30;
2433 fclose(file);
2434
2435 save_room_return(trgentrance == -1 ? 0 : 1);
2436 } else {
2437 set_up_input("The file was not opened",1,-1,-1);
2438 }
2439 }
2440 }
2441
2442
load_options()2443 void load_options() {
2444 char filestr[512];
2445 sprintf(filestr, "%ssaves%sgame%d.opt", support_path, DIRSEP, gameNum);
2446 file = fopen(filestr, "rb");
2447 if (file) {
2448 if (!fread(&mousecammode, sizeof(int), 1, file))
2449 mousecammode = 1;
2450 if (!fread(&runningmode, sizeof(int), 1, file))
2451 runningmode = 1;
2452 if (!fread(&deathstateload, sizeof(int), 1, file))
2453 deathstateload = 0;
2454 if (!fread(&opencreator, sizeof(int), 1, file))
2455 opencreator = 0;
2456 if (!fread(&musicon, sizeof(int), 1, file))
2457 musicon = 1;
2458 if (!fread(&guides, sizeof(int), 1, file))
2459 guides = 0;
2460 if (!fread(&istophat, sizeof(int), 1, file))
2461 istophat = 0;
2462 fclose(file);
2463 } else {
2464 mousecammode = 1;
2465 runningmode = 1;
2466 deathstateload = 0;
2467 opencreator = 0;
2468 musicon = 1;
2469 }
2470 if (ingame != 1 && (musicon == 0 || musicon == 3)) {
2471 Mix_HaltMusic();
2472 }
2473 }
2474
2475
load_game_data()2476 void load_game_data() {
2477 load_options();
2478 char filestr[512];
2479 sprintf(filestr, "%ssaves%sgame%d.gm", support_path, DIRSEP, gameNum);
2480 file = fopen(filestr, "rb");
2481 if (file) {
2482 fread(gamename, sizeof(char), 25, file);
2483 fread(gotmedals, sizeof(int), MEDALMAX, file);
2484 fread(&mapCode, sizeof(int), 1, file);
2485 fread(&initgamemsg, sizeof(int), 1, file);
2486 if (!fread(beatlevel, sizeof(int), 100, file)) {
2487 for (i=0; i<100; i++) beatlevel[i] = 0;
2488 }
2489 for (i = 0; i < 100; i++) {
2490 if (!fread(game_gotfrags[i], sizeof(char), 100, file)) {
2491 for (j = 0; j < 100; j++) {
2492 if (gotmedals[i*6+2]) game_gotfrags[i][j] = 1;
2493 else game_gotfrags[i][j] = 0;
2494 }
2495 }
2496 if (!fread(game_gotcorners[i], sizeof(char), 4, file)) {
2497 for (j = 0; j < 4; j++) {
2498 if (gotmedals[i*6+1]) game_gotcorners[i][j] = 1;
2499 else game_gotcorners[i][j] = 0;
2500 }
2501 }
2502 }
2503 for (i = 0; i < 100; i++) {
2504 if (!fread(game_enemdead[i], sizeof(char), ROOMMAX, file)) {
2505 for (j = 0; j < ROOMMAX; j++) {
2506 if (gotmedals[i*6+3]) game_enemdead[i][j] = 1;
2507 else game_enemdead[i][j] = 0;
2508 }
2509 }
2510 }
2511 fclose(file);
2512 gamemedals = 0;
2513 for (i=0; i<MEDALMAX; i++)
2514 if (gotmedals[i]) {
2515 gamemedals++;
2516 }
2517 initmapmsg = 1;
2518 } else {
2519 strcpy(gamename, "---New---");
2520 for (i=0; i<MEDALMAX; i++) gotmedals[i] = 0;
2521 for (i=0; i<100; i++) beatlevel[i] = 0;
2522 for (i=0; i<100; i++) {
2523 for (j=0; j<100; j++) game_gotfrags[i][j] = 0;
2524 for (j=0; j<4; j++) game_gotcorners[i][j] = 0;
2525 for (j=0; j<ROOMMAX; j++) game_enemdead[i][j] = 0;
2526 }
2527 gamemedals = 0;
2528 mapCode = 0;
2529 initmapmsg = 0;
2530 initgamemsg = 0;
2531 }
2532 }
2533
2534
save_options()2535 void save_options() {
2536 char filestr[512];
2537 sprintf(filestr, "%ssaves%sgame%d.opt", support_path, DIRSEP, gameNum);
2538 file = fopen(filestr, "wb");
2539 if (file) {
2540 fwrite(&mousecammode, sizeof(int), 1, file);
2541 fwrite(&runningmode, sizeof(int), 1, file);
2542 fwrite(&deathstateload, sizeof(int), 1, file);
2543 fwrite(&opencreator, sizeof(int), 1, file);
2544 fwrite(&musicon, sizeof(int), 1, file);
2545 fwrite(&guides, sizeof(int), 1, file);
2546 fwrite(&istophat, sizeof(int), 1, file);
2547 fclose(file);
2548 } else {
2549 set_up_input("The file was not opened",1,-1,-1);
2550 }
2551 }
2552
2553
save_game_data()2554 void save_game_data() {
2555 char filestr[512];
2556 sprintf(filestr, "%ssaves%sgame%d.gm", support_path, DIRSEP, gameNum);
2557 file = fopen(filestr, "wb");
2558 if (file) {
2559 fwrite(gamename, sizeof(char), 25, file);
2560 fwrite(gotmedals, sizeof(int), MEDALMAX, file);
2561 fwrite(&mapCode, sizeof(int), 1, file);
2562 fwrite(&initgamemsg, sizeof(int), 1, file);
2563 fwrite(beatlevel, sizeof(int), 100, file);
2564 for (i = 0; i < 100; i++) {
2565 fwrite(game_gotfrags[i], sizeof(char), 100, file);
2566 fwrite(game_gotcorners[i], sizeof(char), 4, file);
2567 }
2568 for (i = 0; i < 100; i++) {
2569 fwrite(game_enemdead[i], sizeof(char), ROOMMAX, file);
2570 }
2571 fclose(file);
2572 } else {
2573 set_up_input("The file was not opened",1,-1,-1);
2574 }
2575 }
2576
2577
start_new_game()2578 void start_new_game() {
2579 char filestr[512];
2580 sprintf(filestr, "%ssaves%sgame%d.ret", support_path, DIRSEP, gameNum);
2581 remove(filestr);
2582 strcpy(gamename, inputstr);
2583 save_game_data();
2584 }
2585
2586
delete_game()2587 void delete_game() {
2588 char filestr[512];
2589 sprintf(filestr, "%ssaves%sgame%d.gm", support_path, DIRSEP, gameNum);
2590 remove(filestr);
2591 sprintf(filestr, "%ssaves%sgame%d.ret", support_path, DIRSEP, gameNum);
2592 remove(filestr);
2593 sprintf(filestr, "%ssaves%sgame%d.sav", support_path, DIRSEP, gameNum);
2594 remove(filestr);
2595 sprintf(filestr, "%ssaves%sgame%d.savbkp", support_path, DIRSEP, gameNum);
2596 remove(filestr);
2597 sprintf(filestr, "%ssaves%sgame%d.opt", support_path, DIRSEP, gameNum);
2598 remove(filestr);
2599 load_game_data();
2600 }
2601
2602
init_leave_select(int getinputset)2603 void init_leave_select(int getinputset) {
2604 getinput = getinputset;
2605 inputlength = -3;
2606 optselect = 0;
2607 optmax = 4;
2608 paused = 0;
2609 }
2610
2611
init_opt_select()2612 void init_opt_select() {
2613 getinput = 15;
2614 inputlength = -3;
2615 optselect = 0;
2616 optmax = 5;
2617 }
2618
2619
init_sign(int mgnum)2620 void init_sign(int mgnum) {
2621 msgcode = mgnum;
2622 getinput = 3;
2623 inputlength = -1;
2624 }
2625
2626
use_door()2627 void use_door() {
2628 Thing door = things[beret.timer];
2629
2630 if (door.type == FINISHDOOR) {
2631 if (spminutes > 0 || spseconds > 0 || spframes > 0) {
2632 gotgmed = 1;
2633 spminutes = 0;
2634 spseconds = 0;
2635 spframes = 0;
2636 play_sound(SND_MEDG);
2637 if (statusbar) {
2638 make_expl(GMEDPOS+15+camx,30+camy,0,0,GREEN,6,100);
2639 make_expl(GMEDPOS+15+camx,30+camy,0,0,GRYELLOW,6,40);
2640 }
2641 }
2642 if (!gotpmed && lvlCode != LAST_LEVEL) {
2643 gotpmed = 1;
2644 play_sound(SND_MEDP);
2645 if (statusbar) {
2646 make_expl(PMEDPOS+15+camx,30+camy,0,0,PURPLE,6,120);
2647 make_expl(PMEDPOS+15+camx,30+camy,0,0,RED,6,20);
2648 }
2649 }
2650 }
2651 if (door.type == READSIGN && key2 == DOWN && beret.vx == 0) {
2652 init_sign(door.dir);
2653 } else if (door.type == SIGN) {
2654 if (door.subtype%2 == 0 && beret.x <= 0 && !walkaway) {
2655 if (ingame == -1) init_fade(1);
2656 else go_to_room(door.status, door.dir);
2657 walkaway = 1;
2658 }
2659 if (door.subtype%2 == 1 && beret.x+beret.width>=lvlWidth && !walkaway) {
2660 if (ingame == -1) init_fade(1);
2661 else go_to_room(door.status, door.dir);
2662 walkaway = 2;
2663 }
2664 } else if ((door.type == FINISHDOOR || door.type == DOOR) &&
2665 key2 == DOWN && beret.vx == 0 && fadetime == 0) {
2666 if (ingame == -1) {
2667 init_fade(1);
2668 } else {
2669 if (door.type == FINISHDOOR) {
2670 set_up_input("Exit this level?",-14,-2,-1);
2671 } else if (door.type == DOOR) {
2672 go_to_room(door.status, door.dir);
2673 }
2674 }
2675 }
2676 }
2677
2678
begin_game()2679 void begin_game() {
2680 if (strcmp(gamename, "---New---") == 0)
2681 set_up_input("Enter your name:",2,13,-1);
2682 else {
2683 char filestr[512];
2684 sprintf(filestr, "%ssaves%sgame%d.ret", support_path, DIRSEP, gameNum);
2685 file = fopen(filestr, "rb");
2686 if (file) {
2687 cancont = 1;
2688 initgamemsg = 1;
2689 fread(&contlvl, sizeof(int), 1, file);
2690 fclose(file);
2691 set_up_input("Continue last play?",-15,-2,-1);
2692 yesno = 1;
2693 } else {
2694 cancont = 0;
2695 init_fade(2);
2696 }
2697 }
2698 }
2699
2700
handle_key_down(SDLKey key)2701 void handle_key_down(SDLKey key) {
2702 SDLMod mod = SDL_GetModState();
2703
2704 if ((key == QUITKEY_WIN && (mod & QUITMOD_WIN)) ||
2705 (key == QUITKEY_LIN && (mod & QUITMOD_LIN)) ||
2706 (key == QUITKEY_MAC && (mod & QUITMOD_MAC))) {
2707 save_options();
2708 quit = 1;
2709 }
2710
2711 if (ingame == 0) {
2712 if (key == SDLK_ESCAPE) {
2713 quit = 1;
2714 return;
2715 }
2716 ingame = 1;
2717 load_game_data();
2718 return;
2719 } else if (key == SDLK_SLASH) {
2720 musicon = !musicon;
2721 if (musicon) switch_music(curmusic, 1);
2722 else Mix_HaltMusic();
2723 if (ingame != 0 && ingame != 1) save_options();
2724 } else if ((mod & KMOD_ALT) && key == SDLK_RETURN) {
2725 fullscreenmode = !fullscreenmode;
2726 if (fullscreenmode) {
2727 screen = SDL_SetVideoMode(SCR_WIDTH, SCR_HEIGHT,
2728 SCR_BPP, SDL_FULLSCREEN);
2729 } else {
2730 screen = SDL_SetVideoMode(SCR_WIDTH, SCR_HEIGHT,
2731 SCR_BPP, SDL_SWSURFACE);
2732 }
2733 }
2734
2735 if (ingame == 4 || ingame == 5) {
2736 ingame = (ingame == 4 ? ingamereturn : 2);
2737 return;
2738 }
2739
2740 if (ingame == 10 || ingame == 11) {
2741 ingame++;
2742 return;
2743 }
2744
2745 if (ingame == 12) {
2746 ingame = -1;
2747 return;
2748 }
2749
2750 if (ingame == 13 && key == SDLK_ESCAPE) {
2751 init_fade(4);
2752 return;
2753 }
2754
2755 if (ingame == 2 && !getinput) {
2756 if (key == SDLK_e) {
2757 if (secretcode % 4 == 0) secretcode++;
2758 } else if (key == SDLK_v) {
2759 if (secretcode % 4 == 1) secretcode++;
2760 } else if (key == SDLK_i) {
2761 if (secretcode % 4 == 2) secretcode++;
2762 } else if (key == SDLK_l) {
2763 if (secretcode % 4 == 3) secretcode++;
2764 if (secretcode == 12) {
2765 opencreator = 1;
2766 play_sound(SND_SWITCHGV);
2767 save_options();
2768 }
2769 } else secretcode = 0;
2770 if (key == SDLK_ESCAPE) init_leave_select(13);
2771 else if (key == SDLK_c) {
2772 ingamereturn = ingame;
2773 ingame = 4;
2774 switch_background(2);
2775 } else if (key == SDLK_s) {
2776 ingame = 5;
2777 switch_background(2);
2778 } else if (key == SDLK_a) {
2779 init_fade(9);
2780 }
2781 return;
2782 }
2783
2784 if (ingame == 1 && !getinput) {
2785 if ((key == SDLK_RIGHT || key == SDLK_d) && gameNum < GAMEMAX) {
2786 gameNum++;
2787 load_game_data();
2788 }
2789 if ((key == SDLK_LEFT || key == SDLK_a) && gameNum > 1) {
2790 gameNum--;
2791 load_game_data();
2792 }
2793 if (key == SDLK_RETURN || key == SDLK_SPACE || key == SDLK_LSHIFT ||
2794 key == SDLK_RSHIFT) {
2795 begin_game();
2796 return;
2797 }
2798 if (key == SDLK_ESCAPE) {
2799 ingame = 0;
2800 return;
2801 }
2802 if ((key == SDLK_DELETE || key == SDLK_BACKSPACE) &&
2803 strcmp(gamename, "---New---")) {
2804 set_up_input("Delete this game?",-10,-2,-1);
2805 }
2806 }
2807
2808 if (getinput) {
2809 if (key == SDLK_RETURN || key == SDLK_ESCAPE ||
2810 ((getinput == 1 || getinput == 3) &&
2811 (key == SDLK_w || key == SDLK_s || key == SDLK_a || key == SDLK_d ||
2812 key == SDLK_UP || key == SDLK_DOWN || key == SDLK_LEFT || key == SDLK_RIGHT))) {
2813 // take care of different reasons for getting input
2814 resolve_input(key);
2815 } else if (inputpos < inputlength && ((key >= SDLK_0 && key <= SDLK_9) ||
2816 (getinput > 0 && key >= SDLK_a && key <= SDLK_z))) {
2817 if (!(mod & KMOD_SHIFT) || (key >= SDLK_0 && key <= SDLK_9))
2818 inputstr[inputpos++] = key;
2819 else inputstr[inputpos++] = key - 'a' + 'A';
2820 inputstr[inputpos] = '\0';
2821 } else if (inputlength != -1 && inputpos > 0 && key == SDLK_BACKSPACE) {
2822 inputstr[--inputpos] = '\0';
2823 if (inputpos == 0) sprintf(inputstr, "-");
2824 } else if (inputlength == -2) {
2825 if (key == SDLK_a || key == SDLK_LEFT) yesno = 0;
2826 if (key == SDLK_d || key == SDLK_RIGHT) yesno = 1;
2827 } else if (inputlength == -3) {
2828 if (key == SDLK_s || key ==SDLK_DOWN) optselect++;
2829 if (key == SDLK_w || key ==SDLK_UP) optselect--;
2830 if (optselect >= optmax) optselect = optmax-1;
2831 if (optselect < 0) optselect = 0;
2832 if (getinput == 15) {
2833 if (key == SDLK_a || key == SDLK_LEFT ||
2834 key == SDLK_d || key == SDLK_RIGHT) {
2835 if (optselect == 0) {
2836 if (key == SDLK_a || key == SDLK_LEFT) musicon--;
2837 else musicon++;
2838 if (musicon == 4) musicon = 0;
2839 else if (musicon == -1) musicon = 3;
2840 if (musicon == 1 || musicon == 2) switch_music(curmusic, 1);
2841 else Mix_HaltMusic();
2842 }
2843 if (optselect == 1) mousecammode = !mousecammode;
2844 if (optselect == 2) runningmode = !runningmode;
2845 if (optselect == 3) deathstateload = !deathstateload;
2846 if (optselect == 4) statusbar = !statusbar;
2847 save_options();
2848 }
2849 }
2850 }
2851 } else {
2852 if (key == SDLK_LSHIFT || key == SDLK_RSHIFT) {
2853 key3 = SHIFT;
2854 } else if (key == SDLK_ESCAPE && ingame < 0) {
2855 if (creatormode) init_leave_select(16);
2856 else init_leave_select(17);
2857 }
2858
2859 if (creatormode) {
2860 // creator keys
2861 if (key == SDLK_g) {
2862 crtgridsize++;
2863 crtgridsize %= 3;
2864 } else if (key == SDLK_c) {
2865 switchflags ^= NOCOLLIDEFLAG;
2866 } else if (key == SDLK_q) {
2867 ingame = 10;
2868 } else if (key == SDLK_h) {
2869 crtgridsnap = !crtgridsnap;
2870 } else if (key == SDLK_l) {
2871 crtlinking = !crtlinking;
2872 hassaved = 0;
2873 } else if (key == SDLK_p) {
2874 set_start_pos();
2875 } else if (key == SDLK_EQUALS) {
2876 if (curbkg < BKG_MAX-1) switch_background(curbkg+1);
2877 if (curbkg == 0) switch_background(1);
2878 hassaved = 0;
2879 } else if (key == SDLK_MINUS) {
2880 if (curbkg > 1) switch_background(curbkg-1);
2881 else switch_background(-1);
2882 hassaved = 0;
2883 } else if (key == SDLK_RIGHTBRACKET) {
2884 if (curmusic < MUSIC_MAX-1) switch_music(curmusic+1, 0);
2885 hassaved = 0;
2886 } else if (key == SDLK_LEFTBRACKET) {
2887 if (curmusic > 0) switch_music(curmusic-1, 0);
2888 hassaved = 0;
2889 } else if (key == SDLK_i) {
2890 crtinventory = !crtinventory;
2891 crtlinking = 0;
2892 crtselect = 0;
2893 } else if (key == SDLK_COMMA) {
2894 crtplacedir = 0;
2895 } else if (key == SDLK_PERIOD) {
2896 crtplacedir = 1;
2897 } else if (key == SDLK_TAB) {
2898 crtplacesubtype++;
2899 crtplacesubtype %= subtype_count(crtplacetype);
2900 } else if (key == SDLK_o) {
2901 create_object();
2902 } else if (key == SDLK_u) {
2903 create_tiles(crtplacetile);
2904 } else if (key == SDLK_y) {
2905 create_tiles(EMPTY);
2906 } else if (key == SDLK_e) {
2907 set_up_input("Doors exit to room:", -1, 4, -1);
2908 } else if (key == SDLK_m) {
2909 set_up_input("Set sign message:", -13, 4, -1);
2910 } else if (key == SDLK_r) {
2911 set_up_input("Really clear the room?",-20,-2,-1);
2912 yesno = 0;
2913 } else if (key == SDLK_F1) {
2914 set_up_input("Save room in division:", -2, 2, lvlCode - 79);
2915 } else if (key == SDLK_F4) {
2916 set_up_input("Load room in division:", -3, 2, lvlCode - 79);
2917 /* } else if (key == SDLK_F5) { */
2918 /* set_up_input("Save map number:", -6, 4, -1); */
2919 /* } else if (key == SDLK_F8) { */
2920 /* set_up_input("Load map number:", -7, 4, -1); */
2921 } else if (key == SDLK_F9) {
2922 if (hassaved) set_up_input("Set timer minutes:", -8, 2, -1);
2923 else set_up_input("First save the room", 1, -1, -1);
2924 } else if (key == SDLK_F12) {
2925 if (hassaved) {
2926 spminutes = 0;
2927 spseconds = 0;
2928 write_metalevel();
2929 } else set_up_input("First save the room", 1, -1, -1);
2930 } else if (key >= SDLK_0 && key <= SDLK_9) {
2931 if (key3 == SHIFT) crtexit = key - '0';
2932 else crtentrance = key - '0';
2933 } else if (key == SDLK_END) {
2934 if (lvlWidth < 19*SCR_WIDTH) {
2935 lvlWidth += SCR_WIDTH;
2936 for (i=0; i< lvlHeight/SPR_SIZE; i++)
2937 fix_tile_borders((lvlWidth-SCR_WIDTH)/SPR_SIZE-1,i,0);
2938 }
2939 hassaved = 0;
2940 } else if (key == SDLK_HOME) {
2941 if (lvlWidth > SCR_WIDTH) {
2942 lvlWidth -= SCR_WIDTH;
2943 for (i=0; i< lvlHeight/SPR_SIZE; i++)
2944 fix_tile_borders(lvlWidth/SPR_SIZE-1,i,0);
2945 }
2946 fix_camera();
2947 hassaved = 0;
2948 } else if (key == SDLK_PAGEDOWN) {
2949 if (lvlHeight < 25*SCR_HEIGHT) {
2950 lvlHeight += SCR_HEIGHT;
2951 for (i=0; i< lvlWidth/SPR_SIZE; i++)
2952 fix_tile_borders(i,(lvlHeight-SCR_HEIGHT)/SPR_SIZE-1,0);
2953 }
2954 hassaved = 0;
2955 } else if (key == SDLK_PAGEUP) {
2956 if (lvlHeight > SCR_HEIGHT) {
2957 lvlHeight -= SCR_HEIGHT;
2958 for (i=0; i< lvlWidth/SPR_SIZE; i++)
2959 fix_tile_borders(i,lvlHeight/SPR_SIZE-1,0);
2960 }
2961 fix_camera();
2962 hassaved = 0;
2963 } else if (key == SDLK_v) {
2964 paste_objects();
2965 hassaved = 0;
2966 } else if (key == SDLK_DELETE || key == SDLK_BACKSPACE) {
2967 for (i=0; i<THINGMAX; i++) {
2968 if (selection[i] || telething == i) {
2969 destroy_thing(&things[i], PIT, things, i);
2970 things[i].type = NOTYPE;
2971 selection[i]=0;
2972 }
2973 }
2974 hassaved = 0;
2975 }
2976 } else if (ingame == 3 || ingame == -1) {
2977 if (key == SDLK_F4 || key == SDLK_4) {
2978 load_state(mod & KMOD_CTRL);
2979 } else if (!fadetime) {
2980
2981 // standard keys
2982 if (key == SDLK_F1 || key == SDLK_1) {
2983 save_state();
2984 } else if (key == SDLK_p && !fadetime) {
2985 paused = !paused;
2986 } else if (key == SDLK_m) {
2987 mousecammode = !mousecammode;
2988 save_options();
2989 } else if (key == SDLK_g) {
2990 guides = !guides;
2991 } else if (ingame == 3 && key == SDLK_ESCAPE) {
2992 init_leave_select(14);
2993 save_options();
2994 } else if (key == SDLK_i) {
2995 camykey = UP;
2996 freecam = 1;
2997 } else if (key == SDLK_j) {
2998 camxkey = LEFT;
2999 freecam = 1;
3000 } else if (key == SDLK_k) {
3001 camykey = DOWN;
3002 freecam = 1;
3003 } else if (key == SDLK_l) {
3004 camxkey = RIGHT;
3005 freecam = 1;
3006 } else if (key == SDLK_r) {
3007 init_fade(6);
3008 } else if (key == SDLK_t && !beret.dead && beatlevel[LAST_LEVEL]) {
3009 istophat = !istophat;
3010 beret.subtype = istophat;
3011 float cx = beret.x+beret.width/2, cy = beret.y+beret.height/2;
3012 make_expl(cx,cy,0,0,beret.subtype?PURPLE:GREEN,8,150);
3013 make_expl(cx,cy,0,0,beret.subtype?GRAY:SKY,6,75);
3014 make_expl(cx,cy,0,0,BROWN,7,25);
3015 }
3016 }
3017 }
3018
3019 if (key == SDLK_w || key == SDLK_UP || key == SDLK_SPACE) {
3020 key2 = UP;
3021 freecam = 0;
3022 } else if (key == SDLK_a || key == SDLK_LEFT) {
3023 remkey1 = key1;
3024 key1 = LEFT;
3025 freecam = 0;
3026 } else if (key == SDLK_s || key == SDLK_DOWN) {
3027 key2 = DOWN;
3028 freecam = 0;
3029 } else if (key == SDLK_d || key == SDLK_RIGHT) {
3030 remkey1 = key1;
3031 key1 = RIGHT;
3032 freecam = 0;
3033 }
3034 }
3035 }
3036
3037
handle_key_up(SDLKey key)3038 void handle_key_up(SDLKey key) {
3039 if (key == SDLK_w || key == SDLK_UP || key == SDLK_SPACE) {
3040 if (key2 == UP) key2 = NONE;
3041 } else if (key == SDLK_a || key == SDLK_LEFT) {
3042 if (key1 == LEFT) {key1 = remkey1; remkey1 = NONE;}
3043 if (remkey1 == LEFT) remkey1 = NONE;
3044 } else if (key == SDLK_s || key == SDLK_DOWN) {
3045 if (key2 == DOWN) key2 = NONE;
3046 } else if (key == SDLK_d || key == SDLK_RIGHT) {
3047 if (key1 == RIGHT) {key1 = remkey1; remkey1 = NONE;};
3048 if (remkey1 == RIGHT) remkey1 = NONE;
3049 } else if (key == SDLK_LSHIFT || key == SDLK_RSHIFT) {
3050 key3 = NONE;
3051 } else if (key == SDLK_i) {
3052 if (camykey == UP) camykey = NONE;
3053 } else if (key == SDLK_j) {
3054 if (camxkey == LEFT) camxkey = NONE;
3055 } else if (key == SDLK_k) {
3056 if (camykey == DOWN) camykey = NONE;
3057 } else if (key == SDLK_l) {
3058 if (camxkey == RIGHT) camxkey = NONE;
3059 }
3060 }
3061
3062
handle_tele_check()3063 void handle_tele_check() {
3064 int cursrad;
3065 canbetelething = -1;
3066 for (cursrad = 0; cursrad <= CURSORRADIUS; cursrad += CURSORRADIUS) {
3067 if (canbetelething == -1) {
3068 for (i=THINGMAX-1; i >= 0; i--) {
3069 if (things[i].type != NOTYPE && things[i].infront &&
3070 (creatormode || (things[i].pickup && !things[i].teledelay)) &&
3071 mx+cursrad >= things[i].x && mx-cursrad < things[i].x+things[i].width &&
3072 my+cursrad >= things[i].y && my-cursrad < things[i].y+things[i].height) {
3073 canbetelething = i;
3074 break;
3075 }
3076 }
3077 } else break;
3078 if (canbetelething == -1) {
3079 for (i=THINGMAX-1; i >= 0; i--) {
3080 if (things[i].type != NOTYPE && !things[i].infront &&
3081 (creatormode || (things[i].pickup && !things[i].teledelay)) &&
3082 mx+cursrad >= things[i].x && mx-cursrad < things[i].x+things[i].width &&
3083 my+cursrad >= things[i].y && my-cursrad < things[i].y+things[i].height) {
3084 canbetelething = i;
3085 break;
3086 }
3087 }
3088 } else break;
3089 }
3090 }
3091
3092
3093 // handle the setup of a link from selected Link Blocks to the
3094 // object that the mouse is over
set_link()3095 void set_link() {
3096 crtlinking = 0;
3097 for (i=0; i<THINGMAX; i++)
3098 if (things[i].type == LINKBLOCK && selection[i]) {
3099 things[i].link = canbetelething;
3100 if (things[i].subtype % 2 == 1)
3101 things[i].islinked = canbetelething;
3102 else if (canbetelething > -1) things[canbetelething].islinked = i;
3103 }
3104 }
3105
3106
handle_mouse_down(int x,int y,int button)3107 void handle_mouse_down(int x, int y, int button) {
3108 if (ingame == 0) {
3109 ingame = 1;
3110 load_game_data();
3111 return;
3112 } else if (ingame == 1 && !getinput) {
3113 begin_game();
3114 return;
3115 }
3116
3117 if (ingame == 4 || ingame == 5) {
3118 ingame = (ingame == 4 ? ingamereturn : 2);
3119 return;
3120 }
3121
3122 if (ingame == 10 || ingame == 11) {
3123 ingame++;
3124 return;
3125 }
3126
3127 if (ingame == 12) {
3128 ingame = -1;
3129 return;
3130 }
3131
3132 if (getinput) {
3133 resolve_input(0);
3134 return;
3135 }
3136
3137 if (ingame== 2 && !getinput) {
3138 if (mapselect > -1 &&
3139 (button == SDL_BUTTON_LEFT || button == SDL_BUTTON_RIGHT) &&
3140 (levelentry[mapCode][mapselect] <= gamemedals || (mapCode == 4 && opencreator))) {
3141 if (my/SPR_SIZE == 1) init_fade(7);
3142 else if (mapCode == 4 && mapselect == 10) {
3143 char filestr[512];
3144 sprintf(filestr, "%ssaves%sgame%d.ret", support_path, DIRSEP, gameNum);
3145 remove(filestr);
3146 init_fade(1);
3147 }
3148 else init_fade(3);
3149
3150 }
3151 if ((mapCode > 0 || (mapCode == 0 && (opencreator || beatlevel[LAST_LEVEL]))) &&
3152 !(mapCode == 4 && !beatlevel[LAST_LEVEL])) {
3153 if (mx >= 30 && mx <= 120 && my >= 195 && my <= 285) {
3154 trgmap = mapCode-1;
3155 if (trgmap < 0) trgmap = 4;
3156 init_fade(8);
3157 }
3158 }
3159 if ((mapCode < 4 && beatlevel[maplastlevel[mapCode]]) || mapCode == 4) {
3160 if (mx >= SCR_WIDTH-120 && mx <= SCR_WIDTH-30 && my >= 195 && my <= 285) {
3161 trgmap = mapCode+1;
3162 if (trgmap > 4) trgmap = 0;
3163 init_fade(8);
3164 }
3165 }
3166 return;
3167 }
3168
3169 if (creatormode &&
3170 (button == SDL_BUTTON_LEFT || button == SDL_BUTTON_RIGHT)) {
3171 if (crtlinking) {
3172 set_link();
3173 } else if (crtinventory) {
3174 int xtile = x/SPR_SIZE-1, ytile = y/SPR_SIZE-1, tindex;
3175 if (xtile > -1 && xtile < 24 && ytile > -1 && ytile < 18) {
3176 if (ytile < 10) {
3177 tindex = xtile+ytile*24+2;
3178 if ((tindex < TOPHAT && tindex != STONEY &&
3179 tindex != BLOCKSTER && tindex != MATTERLY) || tindex == MATTERFRAG) {
3180 crtplacetype = tindex;
3181 crtplacesubtype = 0;
3182 }
3183 } else {
3184 tindex = xtile+(ytile-10)*24;
3185 if (tindex < TILEMAX) crtplacetile = tindex;
3186 }
3187 }
3188 crtinventory = 0;
3189 }
3190 }
3191 if (!paused && !getinput) {
3192 if (button == SDL_BUTTON_RIGHT) {
3193 if (creatormode) {
3194 crtselect = 1;
3195 selx = mx;
3196 sely = my;
3197 }
3198 else guides = !guides;
3199 } else if (button == SDL_BUTTON_LEFT) {
3200 cantele = 1;
3201 teleon = !teleon;
3202 if (alwaystele && !teleon && telething > -1) {
3203 stop_telekinesis();
3204 }
3205 if (creatormode) clear_selection();
3206 }
3207 }
3208 }
3209
3210
handle_mouse_up(int x,int y,int button)3211 void handle_mouse_up(int x, int y, int button) {
3212 if (button == SDL_BUTTON_LEFT) {
3213 cantele = 0;
3214 if (!alwaystele && telething > -1) {
3215 stop_telekinesis();
3216 }
3217 }
3218 if (button == SDL_BUTTON_RIGHT && creatormode && crtselect) {
3219 if (key3 != SHIFT) clear_selection();
3220 crtselect = 0;
3221 int sell, selr, selt, selb;
3222 if (selx < mx) {
3223 sell = selx; selr = mx;
3224 } else {
3225 sell = mx; selr = selx;
3226 }
3227 if (sely < my) {
3228 selt = sely; selb = my;
3229 } else {
3230 selt = my; selb = sely;
3231 }
3232 for (i=0; i<THINGMAX; i++) {
3233 if (things[i].type != NOTYPE && things[i].x <= selr &&
3234 things[i].y <= selb && things[i].x+things[i].width > sell &&
3235 things[i].y+things[i].height > selt)
3236 selection[i] = 1;
3237 }
3238 }
3239 }
3240
3241
draw_sprites(int front)3242 void draw_sprites(int front) {
3243 int args[6];
3244
3245 for (i=0; i<THINGMAX; i++) {
3246 if (things[i].type != NOTYPE &&
3247 ((things[i].infront == front && !things[i].inback) ||
3248 (things[i].inback && front == -1))) {
3249 draw_thing(&things[i], args);
3250 if (args[2] > -1) {
3251 apply_sprite(args[0]-camx,args[1]-camy,args[2],args[3],
3252 args[4],args[5],spritesheet,screen);
3253 // Handle Top Hat's glowing eyes
3254 if (things[i].type == TOPHAT) {
3255 // If Top Hat is telekineticize-o-rama-ing something
3256 if ((get_bossvars())[6] > 0)
3257 apply_sprite(args[0]-camx+(things[i].dir?14:5),
3258 args[1]-camy+((things[i].jump && things[i].vy>0)?14:13),
3259 18,5-things[i].dir,1,1,spritesheet,screen);
3260 }
3261 }
3262 if (creatormode) {
3263 if (things[i].type == LINKBLOCK && selection[i] &&
3264 (things[i].link > -1 || crtlinking)) {
3265 draw_line(screen,things[i].x+things[i].width/2-camx,
3266 things[i].y+things[i].height/2-camy,
3267 (crtlinking?mx:(things[things[i].link].x+things[things[i].link].width/2))-camx,
3268 (crtlinking?my:(things[things[i].link].y+things[things[i].link].height/2))-camy, 0);
3269 }
3270 if (things[i].type == SPIKEBALL)
3271 apply_sprite(things[i].startx-camx,things[i].starty-camy,
3272 19-things[i].subtype, 16+things[i].dir,1,1,
3273 spritesheet, screen);
3274 else if (things[i].type == FAKEBLOCK) {
3275 things[i].anim = 3;
3276 draw_thing(&things[i], args);
3277 apply_sprite(args[0]-camx,args[1]-camy,args[2],args[3],
3278 args[4],args[5],spritesheet,screen);
3279 things[i].anim = 0;
3280 } else if ((things[i].type == DOOR || things[i].type == SIGN ||
3281 things[i].type == READSIGN) && selection[i]) {
3282 if (things[i].type == READSIGN) sprintf(messagestr, "%d", things[i].dir);
3283 else sprintf(messagestr, "%d, %d, %d", things[i].timer, things[i].status, things[i].dir);
3284 message = TTF_RenderText_Blended(smfont, messagestr, textcolor);
3285 apply_surface(things[i].x-camx, things[i].y-12-camy, message, screen);
3286 SDL_FreeSurface(message);
3287 }
3288 if (selection[i]) {
3289 apply_sprite(things[i].startx+things[i].width-SPR_SIZE-camx,
3290 things[i].starty-camy,
3291 19,9,1,1,spritesheet,screen);
3292 apply_sprite(things[i].startx-camx,
3293 things[i].starty+things[i].height-SPR_SIZE-camy,
3294 19,10,1,1,spritesheet,screen);
3295 }
3296 }
3297 }
3298 }
3299 }
3300
3301
draw_beret()3302 void draw_beret() {
3303 if (creatormode) {
3304 apply_sprite(startx-5-camx,starty-6-camy,
3305 0,0,1,1,spritesheet,screen);
3306 } else {
3307 int args[6];
3308 draw_thing(&beret, args);
3309 apply_sprite(args[0]-camx,args[1]-camy,args[2],args[3],
3310 args[4],args[5],spritesheet,screen);
3311 if (telething > -1)
3312 apply_sprite(args[0]-camx+(beret.dir?14:5),
3313 args[1]-camy+((beret.jump && beret.vy>0)?(istophat?14:13):(istophat?13:11)),
3314 18,5-beret.dir,1,1,spritesheet,screen);
3315 }
3316 }
3317
3318
3319 // draws a haze showing that the bottom of the screen is
3320 // a deadly pit of doom
draw_pit()3321 void draw_pit() {
3322 apply_surface(0,lvlHeight-15-camy,pit,screen);
3323 }
3324
3325
draw_tiles(int infront)3326 void draw_tiles(int infront) {
3327 int tl = camx/SPR_SIZE, tr = (camx+SCR_WIDTH)/SPR_SIZE;
3328 int tt = camy/SPR_SIZE, tb = (camy+SCR_HEIGHT)/SPR_SIZE;
3329 for (i = tl; i <= tr; i++) {
3330 for (j = tt; j <= tb; j++) {
3331 if (tiles[i][j][0] > 0 && (tiles[i][j][1] > 0) == infront) {
3332 apply_sprite((i-tl)*SPR_SIZE-(camx%SPR_SIZE),
3333 (j-tt)*SPR_SIZE-(camy%SPR_SIZE),
3334 (tiles[i][j][0]-1)%24,(tiles[i][j][0]-1)/24,1,1,
3335 tilesheet,screen);
3336 apply_sprite((i-tl)*SPR_SIZE-(camx%SPR_SIZE),
3337 (j-tt)*SPR_SIZE-(camy%SPR_SIZE),
3338 tiles[i][j][2]%24,22-(see_through(tiles[i][j][0])?2:0)+
3339 tiles[i][j][2]/24,1,1,tilesheet,screen);
3340 }
3341 }
3342 }
3343 if (creatormode && crtgridsize > 0 && !getinput) {
3344 for (i = tl; i <= tr; i++) {
3345 for (j = tt; j <= tb; j++) {
3346 apply_sprite((i-tl)*SPR_SIZE-(camx%SPR_SIZE),
3347 (j-tt)*SPR_SIZE-(camy%SPR_SIZE),
3348 19,4+crtgridsize,1,1,
3349 spritesheet,screen);
3350 }
3351 }
3352 }
3353 }
3354
3355
draw_bkg(int flag)3356 void draw_bkg(int flag) {
3357 if (curbkg > -1 && !flag) {
3358 apply_surface(0,0,background,screen);
3359 } else if (flag) apply_surface(0,0,invbackground,screen);
3360 else apply_surface(0,0,mapbkg,screen);
3361 }
3362
3363
3364 // determines if one point can see another point
check_vision(int x1,int y1,int x2,int y2,int * r_tilecx,int * r_tilecy)3365 int check_vision(int x1, int y1, int x2, int y2, int *r_tilecx, int *r_tilecy) {
3366 int tilecx = x1/SPR_SIZE, tilecy = y1/SPR_SIZE;
3367 int tilemx = x2/SPR_SIZE, tilemy = y2/SPR_SIZE;
3368 float slope = 1.0*(y2-y1)/(x2-x1);
3369
3370 // y = slope*(x-x1) + y1
3371 int checked = 0;
3372 while (!checked) {
3373 checked = tilecx == tilemx && tilecy == tilemy;
3374
3375 int tt=tilecy*SPR_SIZE, tb=(tilecy+1)*SPR_SIZE;
3376 int tl=tilecx*SPR_SIZE, tr=(tilecx+1)*SPR_SIZE;
3377
3378 if (tiles[tilecx][tilecy][0] && ((tiles[tilecx][tilecy][1] == SOLID || tiles[tilecx][tilecy][0] == DARKNESSTILE) &&
3379 !(tiles[tilecx][tilecy][0] >= SPIKEU && tiles[tilecx][tilecy][0] <= SPIKEL))) {
3380 *r_tilecx = tilecx;
3381 *r_tilecy = tilecy;
3382 return 0;
3383 }
3384
3385 if (tilecx == tilemx) {
3386 tilecy += tilecy<tilemy?1:-1;
3387 } else {
3388 float y;
3389 if (tilecx < tilemx) {
3390 y = (tr-x1)*slope+y1;
3391 } else {
3392 y = (tl-x1)*slope+y1;
3393 }
3394 if (y < tt) tilecy--;
3395 else if (y > tb) tilecy++;
3396 else tilecx += tilecx<tilemx?1:-1;
3397 }
3398 }
3399 return 1;
3400 }
3401
3402
3403 // set that the last level has been beaten
set_beat_last_level()3404 void set_beat_last_level() {
3405 beatlevel[LAST_LEVEL] = 1;
3406 }
3407
3408
3409 // note that a fragment has been destroyed
kill_fragment()3410 void kill_fragment() {
3411 gotallfrags = -1;
3412 }
3413
3414
3415 // store that the given object has been collected
collect_thing(Thing * this)3416 void collect_thing(Thing* this) {
3417 if (this->type == MEDALFRAGMENT) {
3418 play_sound(SND_COLLECT+rand_to(6));
3419 if (this->dir > -1) gotmfrag[this->dir] = 1;
3420 if (this->subtype < 2) {
3421 mfragcount++;
3422 if (mfragcount == MFRAGTOTAL) {
3423 play_sound(SND_MEDB);
3424 if (statusbar) {
3425 make_expl(BMEDPOS+15+camx,30+camy,0,0,AQUA,6,150);
3426 make_expl(BMEDPOS+15+camx,30+camy,0,0,BLUE,6,60);
3427 }
3428 }
3429 }
3430 } else if (this->type == MEDALCORNER) {
3431 gotmcrn[this->subtype % 4] = 1;
3432 play_sound(SND_CORNER);
3433 if (this->subtype < 4) {
3434 if ((gotmcrn[0] || game_gotcorners[lvlCode][0]) && (gotmcrn[1] || game_gotcorners[lvlCode][1]) &&
3435 (gotmcrn[2] || game_gotcorners[lvlCode][2]) && (gotmcrn[3] || game_gotcorners[lvlCode][3])) {
3436 play_sound(SND_MEDO);
3437 if (statusbar) {
3438 make_expl(OMEDPOS+15+camx,30+camy,0,0,ORANGE,6,150);
3439 make_expl(OMEDPOS+15+camx,30+camy,0,0,BROWN,6,60);
3440 }
3441 }
3442 }
3443 } else if (this->type == WHITEMEDAL) {
3444 gotmwht = 1;
3445 play_sound(SND_MEDW);
3446 if (statusbar && this->subtype == 0) {
3447 make_expl(WMEDPOS+15+camx,30+camy,0,0,WHITE,6,150);
3448 make_expl(WMEDPOS+15+camx,30+camy,0,0,YELLOW,6,60);
3449 }
3450 }
3451 }
3452
3453
3454 // determine if a point is within telekinesis range of another point
check_range(int x1,int y1,int x2,int y2,int cx,int cy)3455 int check_range(int x1, int y1, int x2, int y2, int cx, int cy) {
3456 int tilecx = 0, tilecy = 0, check_vision_ret = 0;
3457 check_vision_ret = check_vision(x1, y1, x2, y2, &tilecx, &tilecy);
3458 return sqrt(f_sqr(x2-cx) + f_sqr(y2-cy)) <= SPR_SIZE*TELERADIUS &&
3459 check_vision_ret;
3460 }
3461
3462
3463 // helper functions for check_can_see
get_x_see_coord(Thing this,int which)3464 int get_x_see_coord(Thing this, int which) {
3465 switch (which) {
3466 case 0: return this.x;
3467 case 1: return this.x+this.width/2;
3468 case 2: return this.x+this.width;
3469 default : return 0;
3470 }
3471 }
get_y_see_coord(Thing this,int which)3472 int get_y_see_coord(Thing this, int which) {
3473 switch (which) {
3474 case 0: return this.y;
3475 case 1: return this.y+this.height/2;
3476 case 2: return this.y+this.height;
3477 default : return 0;
3478 }
3479 }
3480
3481
3482 // determine if the first thing can see the second thing
check_can_see(Thing t1,Thing t2)3483 int check_can_see(Thing t1, Thing t2) {
3484 int coordi, coordj;
3485 for (coordi=0; coordi<9; coordi++)
3486 for (coordj=0; coordj<9; coordj++)
3487 if (check_range(get_x_see_coord(t1,coordi/3),
3488 get_y_see_coord(t1,coordi%3),
3489 get_x_see_coord(t2,coordj/3),
3490 get_y_see_coord(t2,coordj%3),
3491 t1.x+t1.width/2, t1.y+t1.height/2))
3492 return 1;
3493 return 0;
3494 }
3495
3496
3497 // necessary functionality for moving objects, checking
3498 // telekinesis bounds
do_telekinesis()3499 void do_telekinesis() {
3500 // int part_x = beret.dir?14:5, part_y = (beret.jump && beret.vy>0)?13:11;
3501 telestat = 0;
3502 if (telething > -1) {
3503 // Make particles stream from Beret's eyes
3504 /* if (rand_to(5) == 0) */
3505 /* create_particle(beret.x+part_x-3+rand_to(3), beret.y+part_y-3+rand_to(3), 0, 0, (rand_to(3) == 0?BLUE:WHITE), */
3506 /* 3+rand_to(4)); */
3507 /* if (rand_to(5) == 0) */
3508 /* create_particle(beret.x+part_x+2+rand_to(3), beret.y+part_y+(beret.dir?-1:1)-3+rand_to(3), 0, 0, */
3509 /* (rand_to(3) == 0?BLUE:WHITE), 3+rand_to(4)); */
3510 // Do the actual telekinesis
3511 Thing ttt = things[telething];
3512 if (!creatormode && (ttt.type == NOTYPE || !ttt.pickup ||
3513 !check_can_see(beret, ttt))) {
3514 telestat = 1;
3515 stop_telekinesis();
3516 } else if (creatormode || (!things[telething].infront && things[telething].islinked == -1)) {
3517 float cx = things[telething].x+things[telething].width/2;
3518 float cy = things[telething].y+things[telething].height/2;
3519 things[telething].vx = approach(things[telething].vx,
3520 cap_val((mx-cx)*TELEMODIF,TELECAP),
3521 TELEACCEL);
3522 things[telething].vy = approach(things[telething].vy,
3523 cap_val((my-cy)*TELEMODIF,TELECAP),
3524 TELEACCEL);
3525 if (things[telething].solid) {
3526 if ((things[telething].collide[LEFT] && things[telething].vx < 0) ||
3527 (things[telething].collide[RIGHT] && things[telething].vx > 0))
3528 things[telething].vx = 0;
3529 if ((things[telething].collide[UP] && things[telething].vy < 0) ||
3530 (things[telething].collide[DOWN] && things[telething].vy > 0))
3531 things[telething].vy = 0;
3532 }
3533 }
3534 } else if (canbetelething > -1) {
3535 Thing cbtt = things[canbetelething];
3536 if (!creatormode && !check_can_see(beret, cbtt)) {
3537 telestat = 1;
3538 }
3539 } else if (!creatormode && !check_range(beret.x+beret.width/2, beret.y+beret.height/2, mx, my,
3540 beret.x+beret.width/2, beret.y+beret.height/2)) {
3541 telestat = 1;
3542 }
3543 if (!telestat)
3544 telestat = telething > -1 ? 0 : (canbetelething > -1 ? 3 : 2);
3545 }
3546
3547
draw_cursor()3548 void draw_cursor() {
3549 apply_sprite(mx-camx-7,my-camy-7,19,telestat,1,1,spritesheet,screen);
3550 }
3551
3552
draw_inventory()3553 void draw_inventory() {
3554 Thing displthing;
3555 int xpos, ypos;
3556 int args[6];
3557 displthing.subtype = 0;
3558 displthing.dir = 0;
3559 displthing.status = 0;
3560 displthing.anim = 0;
3561 displthing.telething = 0;
3562
3563 for (i=2; i <= TOPHATSHIELD; i++) {
3564 if (i == STONEY || i == BLOCKSTER || i == MATTERLY ||
3565 i == TOPHAT || i == SHIELDGEN ||
3566 (i >= TYPEMAX && i <= SPIKEBLOCK) || i == TOPHATSHIELD) continue;
3567 displthing.type = i;
3568 displthing.x = ((i-2)%24)*SPR_SIZE+SPR_SIZE;
3569 displthing.y = ((i-2)/24)*SPR_SIZE+SPR_SIZE;
3570 displthing.startx = displthing.x;
3571 displthing.starty = displthing.y;
3572
3573 draw_thing(&displthing, args);
3574 apply_sprite(args[0],args[1],args[2],args[3],
3575 1,1,spritesheet,screen);
3576 }
3577
3578 apply_sprite(30,330,19,7,1,1,spritesheet,screen);
3579 for (i=1; i < TILEMAX; i++) {
3580 xpos = (i%24)*SPR_SIZE+SPR_SIZE;
3581 ypos = (i/24)*SPR_SIZE+SPR_SIZE+SCR_HEIGHT/2;
3582 apply_sprite(xpos,ypos,(i-1)%24,(i-1)/24,1,1,tilesheet,screen);
3583 }
3584
3585 for (i = 0; i < SCR_WIDTH; i+=SPR_SIZE) {
3586 for (j = 0; j < SCR_HEIGHT; j+=SPR_SIZE) {
3587 apply_sprite(i,j,19,5,1,1,spritesheet,screen);
3588 }
3589 }
3590 }
3591
3592
draw_get_input()3593 void draw_get_input() {
3594 if (getinput == 3) { // Show message
3595 apply_surface(SCR_WIDTH/2-msgback->w/2, SCR_HEIGHT/2-msgback->h/2,msgback,screen);
3596 if(lvlCode < 80){
3597 for (i=0; i<8; i++) {
3598 display_message(SCR_WIDTH/2,SCR_HEIGHT/2-msgback->h/2+24+20*i,medfont,msgs[msgcode][i],1);
3599 }
3600 } else {
3601 char filestr[250];
3602 char msgstr[250];
3603 int msglen;
3604 sprintf(filestr, "%srooms%ssign%d-%d.txt", support_path, DIRSEP, lvlCode, msgcode);
3605 msgfile = fopen(filestr, "r");
3606 if(msgfile){
3607 for (i=0; i<8; i++) {
3608 if(fgets(msgstr, sizeof msgstr, msgfile) != NULL) {
3609 msglen = strlen(msgstr);
3610 if(msglen > 0 && (msgstr[msglen - 1] == '\r' || msgstr[msglen - 1] == '\n')){
3611 msgstr[msglen - 1] = '\0';
3612 msglen--;
3613 }
3614 if(msglen > 0 && msgstr[msglen - 1] == '\r'){
3615 msgstr[msglen - 1] = '\0';
3616 msglen--;
3617 }
3618 if(msglen > 0){
3619 display_message(SCR_WIDTH/2,SCR_HEIGHT/2-msgback->h/2+24+20*i,medfont,msgstr,1);
3620 }
3621 }
3622 }
3623 fclose(msgfile);
3624 }
3625 }
3626 display_message(SCR_WIDTH/2,SCR_HEIGHT/2+msgback->h/2-14,smfont,"PRESS ENTER TO CONTINUE",1);
3627 } else if (getinput == 14 || getinput == 13 || getinput == 17) { // Get input to go back to map screen
3628 apply_surface(SCR_WIDTH/2-getinputback->w/2, SCR_HEIGHT/2-getinputback->h/2,getinputback,screen);
3629 display_message(SCR_WIDTH/2,SCR_HEIGHT/2-getinputback->h/2+20,font,"Return to game",0);
3630 display_message(SCR_WIDTH/2,SCR_HEIGHT/2-getinputback->h/2+50,font,
3631 (getinput == 14 ? "Exit to map" : (getinput == 17 ? "Exit to creator" : "Exit to title")),0);
3632 display_message(SCR_WIDTH/2,SCR_HEIGHT/2-getinputback->h/2+80,font,"Options",0);
3633 display_message(SCR_WIDTH/2,SCR_HEIGHT/2-getinputback->h/2+110,font,"Controls",0);
3634 apply_sprite(SCR_WIDTH/2-125,SCR_HEIGHT/2-getinputback->h/2+20+30*optselect-7,0,15,1,1,spritesheet,screen);
3635 apply_sprite(SCR_WIDTH/2+110,SCR_HEIGHT/2-getinputback->h/2+20+30*optselect-7,0,15,1,1,spritesheet,screen);
3636 display_message(SCR_WIDTH/2,SCR_HEIGHT/2+getinputback->h/2-14,smfont,"PRESS ENTER TO CONTINUE",0);
3637 } else if (getinput == 16) { // Get input in level creator
3638 apply_surface(SCR_WIDTH/2-getinputback->w/2, SCR_HEIGHT/2-getinputback->h/2,getinputback,screen);
3639 display_message(SCR_WIDTH/2,SCR_HEIGHT/2-getinputback->h/2+20,font,"Return to creator",0);
3640 display_message(SCR_WIDTH/2,SCR_HEIGHT/2-getinputback->h/2+50,font,"Test room",0);
3641 display_message(SCR_WIDTH/2,SCR_HEIGHT/2-getinputback->h/2+80,font,"Exit to map",0);
3642 display_message(SCR_WIDTH/2,SCR_HEIGHT/2-getinputback->h/2+110,font,"Controls",0);
3643 apply_sprite(SCR_WIDTH/2-125,SCR_HEIGHT/2-getinputback->h/2+20+30*optselect-7,0,15,1,1,spritesheet,screen);
3644 apply_sprite(SCR_WIDTH/2+110,SCR_HEIGHT/2-getinputback->h/2+20+30*optselect-7,0,15,1,1,spritesheet,screen);
3645 display_message(SCR_WIDTH/2,SCR_HEIGHT/2+getinputback->h/2-14,smfont,"PRESS ENTER TO CONTINUE",0);
3646 } else if (getinput == 15) { // Options screen
3647 apply_surface(SCR_WIDTH/2-optback->w/2, SCR_HEIGHT/2-optback->h/2,optback,screen);
3648 display_message(SCR_WIDTH/2-70,SCR_HEIGHT/2-optback->h/2+20,font,"Sound on:",0);
3649 if (musicon == 0) {
3650 display_message(SCR_WIDTH/2+110,SCR_HEIGHT/2-optback->h/2+20,font,"No",0);
3651 } else if (musicon == 1) {
3652 display_message(SCR_WIDTH/2+110,SCR_HEIGHT/2-optback->h/2+20,font,"Yes",0);
3653 } else if (musicon == 2) {
3654 display_message(SCR_WIDTH/2+110,SCR_HEIGHT/2-optback->h/2+20,font,"Music Only",0);
3655 } else if (musicon == 3) {
3656 display_message(SCR_WIDTH/2+110,SCR_HEIGHT/2-optback->h/2+20,font,"SFX Only",0);
3657 }
3658 display_message(SCR_WIDTH/2-70,SCR_HEIGHT/2-optback->h/2+55,font,"Mouse mode:",0);
3659 if (mousecammode) {
3660 display_message(SCR_WIDTH/2+110,SCR_HEIGHT/2-optback->h/2+55,font,"Normal",0);
3661 } else {
3662 display_message(SCR_WIDTH/2+110,SCR_HEIGHT/2-optback->h/2+55,font,"Alternate",0);
3663 }
3664 display_message(SCR_WIDTH/2-70,SCR_HEIGHT/2-optback->h/2+90,font,"Running mode:",0);
3665 if (runningmode) {
3666 display_message(SCR_WIDTH/2+110,SCR_HEIGHT/2-optback->h/2+90,font,"Walk with shift",0);
3667 } else {
3668 display_message(SCR_WIDTH/2+110,SCR_HEIGHT/2-optback->h/2+90,font,"Double tap",0);
3669 }
3670 display_message(SCR_WIDTH/2-50,SCR_HEIGHT/2-optback->h/2+125,font,"Load state on death:",0);
3671 if (deathstateload) {
3672 display_message(SCR_WIDTH/2+110,SCR_HEIGHT/2-optback->h/2+125,font,"Yes",0);
3673 } else {
3674 display_message(SCR_WIDTH/2+110,SCR_HEIGHT/2-optback->h/2+125,font,"No",0);
3675 }
3676 display_message(SCR_WIDTH/2-50,SCR_HEIGHT/2-optback->h/2+160,font,"Display status bar:",0);
3677 if (statusbar) {
3678 display_message(SCR_WIDTH/2+110,SCR_HEIGHT/2-optback->h/2+160,font,"Yes",0);
3679 } else {
3680 display_message(SCR_WIDTH/2+110,SCR_HEIGHT/2-optback->h/2+160,font,"No",0);
3681 }
3682 apply_sprite(SCR_WIDTH/2-215,SCR_HEIGHT/2-optback->h/2+20+35*optselect-7,0,15,1,1,spritesheet,screen);
3683 apply_sprite(SCR_WIDTH/2+200,SCR_HEIGHT/2-optback->h/2+20+35*optselect-7,0,15,1,1,spritesheet,screen);
3684 display_message(SCR_WIDTH/2,SCR_HEIGHT/2+optback->h/2-14,smfont,"PRESS ENTER TO CONTINUE",0);
3685 } else { // Other
3686 apply_surface(SCR_WIDTH/2-getinputback->w/2, SCR_HEIGHT/2-90,getinputback,screen);
3687 display_message(SCR_WIDTH/2, SCR_HEIGHT/2-60, font,getinputstr,0);
3688 if (inputlength > -1) {
3689 display_message(SCR_WIDTH/2,SCR_HEIGHT/2-15, font,inputstr,0);
3690 }
3691 if (inputlength == -2) {
3692 display_message(SCR_WIDTH/2-60,SCR_HEIGHT/2-15,font,"No",0);
3693 if (!yesno) {
3694 apply_sprite(SCR_WIDTH/2-60-message->w/2-20, SCR_HEIGHT/2-22,0,15,1,1,spritesheet,screen);
3695 apply_sprite(SCR_WIDTH/2-60+message->w/2+5, SCR_HEIGHT/2-22,0,15,1,1,spritesheet,screen);
3696 }
3697 display_message(SCR_WIDTH/2+60,SCR_HEIGHT/2-15,font,"Yes",0);
3698 if (yesno) {
3699 apply_sprite(SCR_WIDTH/2+60-message->w/2-20, SCR_HEIGHT/2-22,0,15,1,1,spritesheet,screen);
3700 apply_sprite(SCR_WIDTH/2+60+message->w/2+5, SCR_HEIGHT/2-22,0,15,1,1,spritesheet,screen);
3701 }
3702 }
3703 display_message(SCR_WIDTH/2,SCR_HEIGHT/2+30,smfont,"PRESS ENTER TO CONTINUE",0);
3704 }
3705 }
3706
3707
draw_paused()3708 void draw_paused() {
3709 apply_surface(SCR_WIDTH/2-getinputback->w/2, SCR_HEIGHT/2-75,getinputback,screen);
3710 message = TTF_RenderText_Blended(font, "Paused", textcolor);
3711 apply_surface(SCR_WIDTH/2-message->w/2, SCR_HEIGHT/2-30, message, screen);
3712 SDL_FreeSurface(message);
3713 message = TTF_RenderText_Blended(smfont, "PRESS P TO CONTINUE", textcolor);
3714 apply_surface(SCR_WIDTH/2-message->w/2, SCR_HEIGHT/2+15, message, screen);
3715 SDL_FreeSurface(message);
3716 message = TTF_RenderText_Blended(font, "Paused", textcolor2);
3717 apply_surface(SCR_WIDTH/2-message->w/2+TEXTSHADOW, SCR_HEIGHT/2-30+TEXTSHADOW, message, screen);
3718 SDL_FreeSurface(message);
3719 message = TTF_RenderText_Blended(smfont, "PRESS P TO CONTINUE", textcolor2);
3720 apply_surface(SCR_WIDTH/2-message->w/2+TEXTSHADOW, SCR_HEIGHT/2+15+TEXTSHADOW, message, screen);
3721 SDL_FreeSurface(message);
3722 }
3723
3724
draw_svst_msg()3725 void draw_svst_msg() {
3726 if (svstcount > 0) {
3727 svstcount--;
3728 display_message(150, SCR_HEIGHT-60,font,"Saved State",0);
3729 } else if (svstcount < 0) {
3730 svstcount++;
3731 display_message(150, SCR_HEIGHT-60,font,"Loaded State",0);
3732 }
3733 }
3734
3735
draw_status_bar()3736 void draw_status_bar() {
3737
3738 if (gotmwht || haswmed) apply_sprite(WMEDPOS,15,5,15,1,1,spritesheet,screen);
3739 else apply_sprite(WMEDPOS,15,17,17,1,1,spritesheet,screen);
3740
3741 if (!hasomed && !((gotmcrn[0] || game_gotcorners[lvlCode][0]) && (gotmcrn[1] || game_gotcorners[lvlCode][1]) &&
3742 (gotmcrn[2] || game_gotcorners[lvlCode][2]) && (gotmcrn[3] || game_gotcorners[lvlCode][3]))) {
3743 apply_sprite(OMEDPOS,15,17,17,1,1,spritesheet,screen);
3744 for (i=0;i<4;i++)
3745 if (gotmcrn[i] || game_gotcorners[lvlCode][i])
3746 apply_sprite(OMEDPOS+(i>0&&i<3?15:0),15+(i>1?15:0),
3747 (i<3?4:3),(i<3?8+i:10),1,1,spritesheet,screen);
3748 }
3749 else apply_sprite(OMEDPOS,15,5,18,1,1,spritesheet,screen);
3750
3751 if (mfragcount < MFRAGTOTAL && !hasbmed) {
3752 if (gotallfrags == 1) apply_sprite(BMEDPOS-2,15,18,9,1,1,spritesheet,screen);
3753 apply_sprite(BMEDPOS+2,17,2,6,1,1,spritesheet,screen);
3754 apply_sprite(BMEDPOS+18,25,2,6,1,1,spritesheet,screen);
3755 apply_sprite(BMEDPOS+2,33,2,7,1,1,spritesheet,screen);
3756 if (gotallfrags == -1) apply_sprite(BMEDPOS-2,15,18,15,1,1,spritesheet,screen);
3757 } else apply_sprite(BMEDPOS,15,5,19,1,1,spritesheet,screen);
3758 sprintf(messagestr, "%d", mfragcount);
3759 message = TTF_RenderText_Blended(font, messagestr, textcolor);
3760 apply_surface(BMEDPOS+MEDINFODIST,15,message,screen);
3761 SDL_FreeSurface(message);
3762 message = TTF_RenderText_Blended(font, messagestr, textcolor2);
3763 apply_surface(BMEDPOS+MEDINFODIST+TEXTSHADOW,15+TEXTSHADOW,message,screen);
3764 SDL_FreeSurface(message);
3765
3766 if (!enemalldead && !hasrmed) apply_sprite(RMEDPOS,15,17,17,1,1,spritesheet,screen);
3767 else apply_sprite(RMEDPOS,15,5,16,1,1,spritesheet,screen);
3768 if (enemdead[areaCode] || game_enemdead[lvlCode][areaCode]) apply_sprite(RMEDPOS+MEDINFODIST,15,18,8,1,1,spritesheet,screen);
3769 else if (enemdeadhere) apply_sprite(RMEDPOS+MEDINFODIST,15,19,8,1,1,spritesheet,screen);
3770 else {
3771 int cmod = (count/3)%8;
3772 apply_sprite(RMEDPOS+MEDINFODIST,15,19,(cmod<5?11+cmod:20-cmod),1,1,spritesheet,screen);
3773 }
3774
3775 if (hasgmed || gotgmed) apply_sprite(GMEDPOS,15,5,17,1,1,spritesheet,screen);
3776 else apply_sprite(GMEDPOS,15,17,17,1,1,spritesheet,screen);
3777 if (!(spframes < 10 && spminutes == 0 && spseconds > 0 && spseconds < 15)) {
3778 sprintf(messagestr, "%d : %02d", spminutes, spseconds);
3779 message = TTF_RenderText_Blended(font, messagestr, textcolor);
3780 apply_surface(GMEDPOS+MEDINFODIST,15,message,screen);
3781 SDL_FreeSurface(message);
3782 message = TTF_RenderText_Blended(font, messagestr, textcolor2);
3783 apply_surface(GMEDPOS+MEDINFODIST+TEXTSHADOW,15+TEXTSHADOW,message,screen);
3784 SDL_FreeSurface(message);
3785 }
3786
3787 if (haspmed || gotpmed) apply_sprite(PMEDPOS,15,3,11,1,1,spritesheet,screen);
3788 else {
3789 apply_sprite(PMEDPOS,15,17,17,1,1,spritesheet,screen);
3790 // if (usedsavestate) apply_sprite(PMEDPOS,15,19,7,1,1,spritesheet,screen);
3791 }
3792 }
3793
3794
draw_guides()3795 void draw_guides() {
3796 int midx = (telesource == -1 ? beret.x+beret.width/2 :
3797 things[telesource].x+things[telesource].width/2);
3798 int midy = (telesource == -1 ? beret.y+beret.height/2 :
3799 things[telesource].y+things[telesource].height/2);
3800 apply_surface(midx-camx-SPR_SIZE*TELERADIUS,
3801 midy-camy-SPR_SIZE*TELERADIUS,
3802 teleguide, screen);
3803 }
3804
3805
draw_select_game()3806 void draw_select_game() {
3807 apply_surface(SCR_WIDTH/2-gameselect->w/2, 330, gameselect, screen);
3808 sprintf(messagestr, "Game %d", gameNum);
3809 display_message(SCR_WIDTH/2, 355, font, 0,0);
3810 display_message(SCR_WIDTH/2, 400, font, gamename,0);
3811 display_message(SCR_WIDTH/2, 470, smfont, "PRESS ENTER TO BEGIN",0);
3812 if (gamemedals > -1) {
3813 sprintf(messagestr, "%d", gamemedals);
3814 display_message(SCR_WIDTH/2+30, 435, font, 0,0);
3815 apply_sprite(SCR_WIDTH/2-message->w/2-35,435-message->h/2,5,15,
3816 1,1,spritesheet,screen);
3817 }
3818 if (gameNum > 1) apply_sprite(SCR_WIDTH/2-gameselect->w/2+15, 445,
3819 19,16,1,1,spritesheet,screen);
3820 if (gameNum < GAMEMAX) apply_sprite(SCR_WIDTH/2+gameselect->w/2-30, 445,
3821 19,17,1,1,spritesheet,screen);
3822 }
3823
3824
draw_title_screen()3825 void draw_title_screen() {
3826 apply_surface(0,0,title,screen);
3827 sprintf(messagestr, "Beret 1.2.1");
3828 display_message(45, 15, smfont, 0, 1);
3829 }
3830
3831
square(int x)3832 int square(int x) {
3833 return x * x;
3834 }
3835
3836
cube(int x)3837 int cube(int x) {
3838 return x * x * x;
3839 }
3840
3841
credit_square(int shift,int div)3842 int credit_square(int shift, int div) {
3843 return square(credittime-shift)/div;
3844 }
3845
3846
credit_cube(int shift,int div)3847 int credit_cube(int shift, int div) {
3848 return cube(credittime-shift)/div;
3849 }
3850
3851
draw_credits()3852 void draw_credits() {
3853 apply_surface(0,0,fades[4],screen);
3854 apply_surface(0,0,credits,screen);
3855 // Game By: - Nigel Kilmer
3856 display_message(300 - credit_square(150,200), 350 - credit_cube(150,4000), font, "Game by:", 0);
3857 display_message(SCR_WIDTH - 300 + credit_square(170,200), 400 + credit_cube(170,4000), font, "Nigel Kilmer", 0);
3858 display_message(SCR_WIDTH - 250 + credit_square(170,200), 450 + credit_cube(170,4000), smfont, "(Kiwisauce)", 0);
3859 /*
3860 // Design
3861 display_message(320 - credit_square(350,200), 350 - credit_cube(350,4000), font, "Design:", 0);
3862 display_message(SCR_WIDTH - 320 + credit_square(370,200), 400 + credit_cube(370,4000), font, "Nigel Kilmer", 0);
3863 // Programming
3864 display_message(300 - credit_square(550,200), 370 - credit_cube(550,4000), font, "Programming:", 0);
3865 display_message(SCR_WIDTH - 300 + credit_square(570,200), 420 + credit_cube(570,4000), font, "Nigel Kilmer", 0);
3866 // Level Design
3867 display_message(350 - credit_square(750,200), 440 - credit_cube(750,4000), font, "Level Design:", 0);
3868 display_message(SCR_WIDTH - 300 + credit_square(770,200), 490 + credit_cube(770,4000), font, "Nigel Kilmer", 0);
3869 // Art
3870 display_message(310 - credit_square(950,200), 340 - credit_cube(950,4000), font, "Art:", 0);
3871 display_message(SCR_WIDTH - 310 + credit_square(970,200), 390 + credit_cube(970,4000), font, "Nigel Kilmer", 0);
3872 // Music
3873 display_message(270 - credit_square(1150,200), 320 - credit_cube(1150,4000), font, "Music:", 0);
3874 display_message(SCR_WIDTH - 400 + credit_square(1170,200), 370 + credit_cube(1170,4000), font, "Nigel Kilmer", 0);
3875 // Sound
3876 display_message(330 - credit_square(1350,200), 440 - credit_cube(1350,4000), font, "Sound:", 0);
3877 display_message(SCR_WIDTH - 350 + credit_square(1370,200), 490 + credit_cube(1370,4000), font, "Nigel Kilmer", 0);
3878 */
3879 // Playtesters
3880 display_message(250 - credit_square(350,200), 350 - credit_cube(350,4000), font, "Thanks to all playtesters!", 0);
3881 display_message(SCR_WIDTH - 250 - credit_square(500,200), 490 + credit_cube(500,4000), font, "Stefan Roger", 0);
3882 display_message(SCR_WIDTH - 550 + credit_square(575,200), 400 + credit_cube(575,4000), font, "Bret Sepulveda", 0);
3883 display_message(SCR_WIDTH - 450 + credit_square(650,200), 320 + credit_cube(650,4000), font, "Kyle Kilmer", 0);
3884 display_message(SCR_WIDTH - 320 + credit_square(725,200), 280 + credit_cube(725,4000), font, "Nathan Weizenbaum", 0);
3885 display_message(SCR_WIDTH - 350 + credit_square(800,200), 420 + credit_cube(800,4000), font, "KC Gidewall", 0);
3886 display_message(SCR_WIDTH - 470 + credit_square(875,200), 300 + credit_cube(875,4000), font, "Alyssa Gidewall", 0);
3887 display_message(SCR_WIDTH - 450 + credit_square(950,200), 410 + credit_cube(950,4000), font, "Ivan Kozlov", 0);
3888 display_message(SCR_WIDTH - 350 + credit_square(1025,200), 500 + credit_cube(1025,4000), font, "Daniel Mills", 0);
3889 display_message(SCR_WIDTH - 250 + credit_square(1100,200), 430 + credit_cube(1100,4000), font, "Raymond Zhang", 0);
3890 display_message(SCR_WIDTH - 550 + credit_square(1175,200), 290 + credit_cube(1175,4000), font, "Jonathan Kane", 0);
3891 display_message(SCR_WIDTH - 300 + credit_square(1250,200), 400 + credit_cube(1250,4000), font, "Tristan Pearson", 0);
3892 display_message(SCR_WIDTH - 460 + credit_square(1325,200), 250 + credit_cube(1325,4000), font, "Beau Pearson", 0);
3893 // Special thanks
3894 display_message(340 - credit_square(1450,200), 350 - credit_cube(1450, 4000), font, "Special thanks to:", 0);
3895 display_message(380 - credit_square(1525,200), 420 - credit_cube(1525, 4000), font, "Mitchell", 0);
3896 display_message(300 - credit_square(1600,200), 400 - credit_cube(1600, 4000), font, "Isocitration", 0);
3897 display_message(340 - credit_square(1675,200), 330 - credit_cube(1675, 4000), font, "FrostyFish88", 0);
3898 // Copyright
3899 if (credittime < 1800) {
3900 display_message(300, 420 + credit_square(1800,200), font, "Copyright 2012 Nigel Kilmer", 0);
3901 } else {
3902 display_message(300, 420, font, "Copyright 2012 Nigel Kilmer", 0);
3903 display_message(400, 470, smfont, "Thanks for playing!", 0);
3904 display_message(400, 500, smfont, "kiwisauce.com", 0);
3905 }
3906 }
3907
3908
draw_creator_guides()3909 void draw_creator_guides() {
3910 Thing displthing;
3911 int args[6];
3912
3913 if (crtselect) {
3914 int sell, selr, selt, selb;
3915 if (selx < mx) {
3916 sell = selx-camx; selr = mx-camx;
3917 } else {
3918 sell = mx-camx; selr = selx-camx;
3919 }
3920 if (sely < my) {
3921 selt = sely-camy; selb = my-camy;
3922 } else {
3923 selt = my-camy; selb = sely-camy;
3924 }
3925 if (sell < 0) sell = 0;
3926 if (sell >= SCR_WIDTH) sell = SCR_WIDTH-1;
3927 if (selt < 0) selt = 0;
3928 if (selt >= SCR_HEIGHT) selt = SCR_HEIGHT-1;
3929 if (selr < 0) selr = 0;
3930 if (selr >= SCR_WIDTH) selr = SCR_WIDTH-1;
3931 if (selb < 0) selb = 0;
3932 if (selb >= SCR_HEIGHT) selb = SCR_HEIGHT-1;
3933 draw_rect(screen, sell, selt, selr, selb, selcolor, 0x50);
3934 }
3935 int xoffst=15, yoffst=15;
3936 if (mx-camx < SCR_WIDTH/4 && my-camy < SCR_HEIGHT/4)
3937 xoffst = SCR_WIDTH/3;
3938 apply_sprite(xoffst,yoffst,16,18,4,2,spritesheet,screen);
3939 if (crtplacetile > 0)
3940 apply_sprite(xoffst+15,yoffst+15,(crtplacetile-1)%24,
3941 (crtplacetile-1)/24,1,1,tilesheet,screen);
3942 displthing.type = crtplacetype;
3943 displthing.subtype = crtplacesubtype;
3944 displthing.dir = crtplacedir;
3945 displthing.status = 0;
3946 displthing.anim = 0;
3947 displthing.telething = 0;
3948 displthing.x = xoffst+60;
3949 displthing.y = yoffst+15;
3950 displthing.startx = displthing.x;
3951 displthing.starty = displthing.y;
3952 draw_thing(&displthing, args);
3953 apply_sprite(args[0],args[1],args[2],args[3],
3954 1,1,spritesheet,screen);
3955 if (crtplacetype == SPIKEBALL)
3956 apply_sprite(displthing.x,displthing.y,
3957 19-crtplacesubtype, 16+crtplacedir,1,1,
3958 spritesheet, screen);
3959 else if (crtplacetype == DOOR || crtplacetype == SIGN || crtplacetype == READSIGN) {
3960 if (crtplacetype == READSIGN) sprintf(messagestr, "%d", crtmessage);
3961 else sprintf(messagestr, "%d, %d, %d", crtentrance, crtexit, crtexitroom);
3962 message = TTF_RenderText_Blended(smfont, messagestr, textcolor);
3963 apply_surface(displthing.x, displthing.y-12, message, screen);
3964 SDL_FreeSurface(message);
3965 }
3966 }
3967
3968
handle_grid_snap()3969 void handle_grid_snap() {
3970 int gridsize = crtgridsize == 1 ? SPR_SIZE : SPR_SIZE/2;
3971 int tx, ty, cx, cy;
3972 for (i=0; i<THINGMAX; i++) {
3973 if (things[i].type != NOTYPE) {
3974 if (abs(things[i].vx) < SNAPVEL && !things[i].nomove) {
3975 tx = things[i].x;
3976 cx = things[i].x+things[i].width/2;
3977 if (tx % gridsize < SNAPSIZE)
3978 things[i].x -= tx % gridsize;
3979 else if (tx % gridsize >= gridsize - SNAPSIZE)
3980 things[i].x += gridsize - tx % gridsize;
3981 else if ((tx+things[i].width) % gridsize < SNAPSIZE)
3982 things[i].x -= (tx+things[i].width) % gridsize;
3983 else if (crtgridsize == 1) {
3984 if ((tx+things[i].width) % gridsize >= gridsize - SNAPSIZE)
3985 things[i].x += gridsize - (tx+things[i].width) % gridsize;
3986 else if (cx % gridsize < gridsize/2+SNAPSIZE &&
3987 cx % gridsize >= gridsize/2-SNAPSIZE)
3988 things[i].x += gridsize/2 - cx % gridsize;
3989 }
3990 }
3991 if (abs(things[i].vy) < SNAPVEL && !things[i].nomove) {
3992 ty = things[i].y;
3993 cy = things[i].y+things[i].height/2;
3994 if (ty % gridsize < SNAPSIZE)
3995 things[i].y -= ty % gridsize;
3996 else if (ty % gridsize >= gridsize - SNAPSIZE)
3997 things[i].y += gridsize - ty % gridsize;
3998 else if ((ty+things[i].height) % gridsize < SNAPSIZE)
3999 things[i].y -= (ty+things[i].height) % gridsize;
4000 else if (crtgridsize == 1) {
4001 if ((ty+things[i].height) % gridsize >= gridsize - SNAPSIZE)
4002 things[i].y += gridsize - (ty+things[i].height) % gridsize;
4003 else if (cy % gridsize < gridsize/2+SNAPSIZE &&
4004 cy % gridsize >= gridsize/2-SNAPSIZE)
4005 things[i].y += gridsize/2 - cy % gridsize;
4006 }
4007 }
4008 }
4009
4010 things[i].x = (int)things[i].x;
4011 things[i].y = (int)things[i].y;
4012 }
4013 }
4014
4015
handle_start_pos()4016 void handle_start_pos() {
4017 for (i=0; i<THINGMAX; i++) {
4018 if (things[i].type != NOTYPE) {
4019 things[i].startx = things[i].x;
4020 things[i].starty = things[i].y;
4021 }
4022 }
4023 }
4024
4025
handle_mvmt()4026 void handle_mvmt() {
4027 for (i=0;i<THINGMAX;i++) {
4028 if (things[i].type != NOTYPE && selection[i]) {
4029 if (key1 == LEFT) things[i].vx = (key3==SHIFT?-1:-8);
4030 else if (key1 == RIGHT) things[i].vx = (key3==SHIFT?1:8);
4031 if (key2 == UP) things[i].vy = (key3==SHIFT?-1:-8);
4032 else if (key2 == DOWN) things[i].vy = (key3==SHIFT?1:8);
4033 }
4034 }
4035 }
4036
4037
update_timer()4038 void update_timer() {
4039 if (spframes > 0 || spseconds > 0 || spminutes > 0) {
4040 spframes--;
4041 if (spframes < 0) {spseconds--; spframes=59;}
4042 if (spseconds < 0) {spminutes--; spseconds=59;}
4043 }
4044 }
4045
4046
update_fade()4047 void update_fade() {
4048 if (fadetime > 0) {
4049 draw_fade();
4050 fadetime--;
4051 if (fadetime == 0) resolve_fade();
4052 }
4053 }
4054
4055
reincarnate_beret(int bdir,int bspeed)4056 void reincarnate_beret(int bdir, int bspeed) {
4057 for (i = 0; i < THINGMAX; i++) {
4058 if (things[i].type == REINCARNATOR && things[i].subtype == 1) {
4059 make_beret(&beret, BERET, istophat, things[i].x+5,
4060 things[i].y+66, 1, things);
4061 beret.dir = bdir;
4062 beret.speed = bspeed;
4063 play_sound(SND_REGEN);
4064 make_expl(beret.x+beret.width/2,beret.y+beret.height/2,
4065 0,0,ORANGE,5,125);
4066 make_expl(beret.x+beret.width/2,beret.y+beret.height/2,
4067 0,0,WHITE,5,125);
4068 center_camera();
4069 deathtime = 0;
4070 break;
4071 }
4072 }
4073 }
4074
4075
main(int argc,char * argv[])4076 int main(int argc, char* argv[]) {
4077
4078 // Initalize and load necessary files
4079 if (!init()) {printf("Initialization error\n"); return 1;}
4080 if (!load_files()) {printf("File load error\n"); return 1;}
4081
4082 game_init();
4083
4084 Uint32 curTime, nextTime = SDL_GetTicks();
4085
4086 // Enter main game loop
4087 while (!quit) {
4088 curTime = SDL_GetTicks();
4089 if (curTime >= nextTime) {
4090 nextTime = SDL_GetTicks() + (1000 / FPS_LIMIT);
4091
4092 // Fixes mouse-in-corner bug - no it doesn't, silly
4093 /* if (SDL_GetAppState() & SDL_APPMOUSEFOCUS) { */
4094 /* if (mouse_visible) { */
4095 /* SDL_ShowCursor(SDL_DISABLE); */
4096 /* mouse_visible = 0; */
4097 /* } */
4098 /* } else { */
4099 /* if (!mouse_visible) { */
4100 /* SDL_ShowCursor(SDL_ENABLE); */
4101 /* mouse_visible = 1; */
4102 /* } */
4103 /* } */
4104
4105 // Check events
4106 while (SDL_PollEvent(&event)) {
4107 if (event.type == SDL_QUIT) {
4108 creatormode = 0;
4109 clean_up();
4110 return 0;
4111 } else if (event.type == SDL_ACTIVEEVENT) {
4112 inactive = !event.active.gain;
4113 } else if (event.type == SDL_KEYDOWN) {
4114 handle_key_down(event.key.keysym.sym);
4115 } else if (event.type == SDL_KEYUP) {
4116 handle_key_up(event.key.keysym.sym);
4117 } else if (event.type == SDL_MOUSEMOTION) {
4118 mx = event.motion.x+camx;
4119 my = event.motion.y+camy;
4120 // Adjust the mouse position near the edge of the screen to make smashing enemies easier.
4121 if (event.motion.x <= 0) mx -= SPR_SIZE * 2;
4122 else if (event.motion.x >= SCR_WIDTH - 1) mx += SPR_SIZE * 2;
4123 if (event.motion.y <= 0) my -= SPR_SIZE * 2;
4124 else if (event.motion.y >= SCR_HEIGHT - 1) my += SPR_SIZE * 2;
4125 // Handle option choices
4126 if (getinput) {
4127 if (inputlength == -2) {
4128 yesno = (event.motion.x > SCR_WIDTH / 2);
4129 } else if (inputlength == -3 && getinput != 15) {
4130 if (optmax == 4) optselect = (event.motion.y - (SCR_HEIGHT/2-getinputback->h/2+10)) / 30;
4131 else optselect = (event.motion.y - (SCR_HEIGHT/2-getinputback->h/2+15)) / 40;
4132 if (optselect < 0) optselect = 0;
4133 else if (optselect >= optmax) optselect = optmax - 1;
4134 }
4135 }
4136 } else if (event.type == SDL_MOUSEBUTTONDOWN) {
4137 handle_mouse_down(event.button.x, event.button.y,
4138 event.button.button);
4139 } else if (event.type == SDL_MOUSEBUTTONUP) {
4140 handle_mouse_up(event.button.x, event.button.y,
4141 event.button.button);
4142 }
4143 }
4144
4145 if (ingame == 4 || ingame == 5 || (ingame >= 10 && ingame <= 12)) {
4146 telestat = 2;
4147 if (ingame == 4) draw_controls();
4148 else if (ingame == 5) draw_story();
4149 else draw_creat(ingame - 10);
4150 if (!inactive) draw_cursor();
4151 if (SDL_Flip(screen) == -1) return 1;
4152 continue;
4153 }
4154
4155 if (ingame == 13) {
4156 credittime++;
4157 draw_credits();
4158 if (credittime >= 1950) init_fade(4);
4159 if (!inactive) draw_cursor();
4160 update_fade();
4161 if (SDL_Flip(screen) == -1) return 1;
4162 continue;
4163 }
4164
4165 if (ingame == 0 || ingame == 1) {
4166 telestat = 2;
4167 for (i=0; i < THINGMAX; i++) {
4168 if (things[i].type != NOTYPE)
4169 update_thing(&things[i], tiles, things, &beret,
4170 lvlWidth, lvlHeight, i, &gravdir,
4171 &switchflags, telething > -1);
4172 }
4173 draw_bkg(0);
4174 draw_pit();
4175 draw_tiles(0);
4176 draw_sprites(-1);
4177 draw_sprites(0);
4178 draw_sprites(1);
4179 draw_tiles(1);
4180 draw_title_screen();
4181 if (ingame == 1) draw_select_game();
4182 if (getinput) draw_get_input();
4183 if (!inactive) draw_cursor();
4184 update_fade();
4185 if (SDL_Flip(screen) == -1) return 1;
4186 continue;
4187 }
4188
4189 if (ingame == 2) {
4190 telestat = 2;
4191 draw_map();
4192 draw_map_status();
4193 if (!getinput && !fadetime) check_map_select();
4194 if (getinput) draw_get_input();
4195 if (!inactive) draw_cursor();
4196 update_fade();
4197 if (SDL_Flip(screen) == -1) return 1;
4198 continue;
4199 }
4200
4201 if (!crtinventory) handle_tele_check();
4202
4203 // int curbx = beret.x, curby = beret.y;
4204
4205 if (!paused && !creatormode && !getinput) {
4206 beret.timer = -1;
4207 if (gotallfrags > -1) gotallfrags = 1;
4208 update_timer();
4209 update_particles(particles, gravdir);
4210 for (i=0; i < THINGMAX; i++) {
4211 if (things[i].type != NOTYPE && !things[i].infront)
4212 update_thing(&things[i], tiles, things, &beret,
4213 lvlWidth, lvlHeight, i, &gravdir,
4214 &switchflags, telething > -1);
4215 if (things[i].type == MEDALFRAGMENT && things[i].subtype < 2 && gotallfrags > -1)
4216 gotallfrags = 0;
4217 }
4218 if (!beret.dead) handle_key_input(key1, key2, key3, &beret,
4219 tiles, things, lvlWidth,
4220 lvlHeight, &gravdir,
4221 &switchflags, walkaway,
4222 runningmode);
4223 for (i=0; i < THINGMAX; i++) {
4224 if (things[i].type != NOTYPE && things[i].infront)
4225 update_thing(&things[i], tiles, things, &beret,
4226 lvlWidth, lvlHeight, i, &gravdir,
4227 &switchflags, telething > -1);
4228 }
4229 for (i=0; i < THINGMAX; i++) {
4230 if (things[i].type != NOTYPE && things[i].dead)
4231 things[i].type = NOTYPE;
4232 }
4233 if (beret.dead) {
4234 if (telething > -1) stop_telekinesis();
4235 if (deathtime == DEATHDELAY - 5 && switchflags & REINCARNATE)
4236 reincarnate_beret(beret.dir, beret.speed);
4237 else if (deathtime < DEATHDELAY) deathtime++;
4238 else if (deathstateload && hassavestate) load_state(0);
4239 else if (!fadetime) init_fade(6);
4240 }
4241 if (beret.ontele == 1) {
4242 things[telething].teledelay = TELEDELAY;
4243 stop_telekinesis();
4244 }
4245 if (beret.timer > -1 && !beret.jump) use_door();
4246 start_telekinesis();
4247 if (!beret.dead) do_telekinesis();
4248 } else if (creatormode && !getinput) {
4249 if (!crtinventory) {
4250 start_telekinesis();
4251 do_telekinesis();
4252 handle_mvmt();
4253 for (i=0; i < THINGMAX; i++) {
4254 if (things[i].type != NOTYPE)
4255 update_thing(&things[i], tiles, things, &beret,
4256 lvlWidth, lvlHeight, i, &gravdir,
4257 &switchflags, telething > -1);
4258 }
4259 if (crtgridsnap && crtgridsize) handle_grid_snap();
4260 handle_start_pos();
4261 } else {
4262 telestat = 2;
4263 }
4264 }
4265
4266 // Update camera
4267 if (!creatormode) {
4268 int curcamx = camx, curcamy = camy;
4269 if (freecam) {
4270 if (!paused) {
4271 if (camxkey == LEFT) camx -= CAMSCROLL;
4272 if (camxkey == RIGHT) camx += CAMSCROLL;
4273 if (camykey == UP) camy -= CAMSCROLL;
4274 if (camykey == DOWN) camy += CAMSCROLL;
4275 }
4276 } else {
4277 int midx = (telesource == -1 ? beret.x+beret.width/2 :
4278 things[telesource].x+things[telesource].width/2);
4279 int midy = (telesource == -1 ? beret.y+beret.height/2 :
4280 things[telesource].y+things[telesource].height/2);
4281 int bvy = abs(beret.vy);
4282 if (midx < camx + 2*SCR_WIDTH/5)
4283 camx = approach(camx, midx-2*SCR_WIDTH/5, MAX(CAMSCROLL*2,bvy));
4284 if (midx > camx + 3*SCR_WIDTH/5)
4285 camx = approach(camx, midx-3*SCR_WIDTH/5, MAX(CAMSCROLL*2,bvy));
4286 if (midy < camy + 2*SCR_HEIGHT/5)
4287 camy = approach(camy, midy-2*SCR_HEIGHT/5, MAX(CAMSCROLL*2,bvy));
4288 if (midy > camy + 3*SCR_HEIGHT/5)
4289 camy = approach(camy, midy-3*SCR_HEIGHT/5, MAX(CAMSCROLL*2,bvy));
4290 }
4291
4292 fix_camera();
4293 /* if (!inactive && */
4294 /* ((!mousecammode && (curcamx != camx || curcamy != camy)) || */
4295 /* (mousecammode && (curbx != (int)beret.x || curby != (int)beret.y)))) { */
4296 if (!inactive && (curcamx != camx || curcamy != camy)) {
4297 /* if (mousecammode) { */
4298 /* mx -= curbx - (int)beret.x; */
4299 /* my -= curby - (int)beret.y; */
4300 /* SDL_WarpMouse(mx-camx,my-camy); */
4301 /* } else { */
4302 if (!mousecammode) {
4303 int tox = mx-camx, toy = my-camy;
4304 if (tox < 0) tox = 0;
4305 if (toy < 0) toy = 0;
4306 if (tox > SCR_WIDTH-1) tox = SCR_WIDTH-1;
4307 if (toy > SCR_HEIGHT-1) toy = SCR_HEIGHT-1;
4308 SDL_WarpMouse(tox,toy);
4309 } else {
4310 mx -= curcamx - camx;
4311 my -= curcamy - camy;
4312 }
4313 /* } */
4314 }
4315 } else if (!crtinventory && !getinput) {
4316 int cammove;
4317 if (mx < camx+CAMSENSE) {
4318 cammove = (CAMSENSE-(mx-camx))/2;
4319 camx -= cammove; mx -= cammove;
4320 }
4321 if (mx > camx+SCR_WIDTH-CAMSENSE) {
4322 cammove = (CAMSENSE-(camx+SCR_WIDTH-mx))/2;
4323 camx += cammove; mx += cammove;
4324 }
4325 if (my < camy+CAMSENSE) {
4326 cammove = (CAMSENSE-(my-camy))/2;
4327 camy -= cammove; my -= cammove;
4328 }
4329 if (my > camy+SCR_HEIGHT-CAMSENSE) {
4330 cammove = (CAMSENSE-(camy+SCR_HEIGHT-my))/2;
4331 camy += cammove; my +=cammove;
4332 }
4333 int dmx = camx, dmy = camy;
4334 fix_camera();
4335 dmx = dmx-camx, dmy = dmy-camy;
4336 mx -= dmx;
4337 my -= dmy;
4338 }
4339
4340 // Draw sprites and background
4341 if (!creatormode || !crtinventory) {
4342 draw_bkg(0);
4343 if (camy+SCR_HEIGHT >= lvlHeight - 30) draw_pit();
4344 draw_tiles(0);
4345 draw_sprites(-1);
4346 draw_sprites(0);
4347 if (!beret.dead || creatormode) draw_beret();
4348 draw_sprites(1);
4349 draw_tiles(1);
4350 } else {
4351 draw_bkg(1);
4352 draw_inventory();
4353 }
4354
4355 if (paused) draw_paused();
4356
4357 // Draw the mouse cursor and guides
4358 if (!creatormode && guides) draw_guides();
4359 if (!creatormode && statusbar && lvlCode != LAST_LEVEL)
4360 draw_status_bar();
4361 if (!creatormode && svstcount != 0) draw_svst_msg();
4362 if (creatormode && !crtinventory && !getinput)
4363 draw_creator_guides();
4364 if (!creatormode) draw_particles();
4365
4366 if (getinput) draw_get_input();
4367 if (!inactive) draw_cursor();
4368
4369 update_fade();
4370
4371 // Draw the screen
4372 if (SDL_Flip(screen) == -1) return 1;
4373
4374 // update the misc counter
4375 count++;
4376 } else {
4377 SDL_Delay(nextTime - curTime);
4378 }
4379 }
4380
4381 clean_up();
4382 return 0;
4383 }
4384
4385
4386 // takes necessary action after fading has finished
resolve_fade()4387 void resolve_fade() {
4388 int temp, tempcx, tempcy;
4389
4390 switch (fadereason) {
4391 case 1 :
4392 if (ingame >= 0) {
4393 hassaved = 0;
4394 creatormode = 1;
4395 clear_room();
4396 } else {
4397 creatormode = !creatormode;
4398 }
4399 ingame = -1;
4400 switchflags ^= CREATORFLAG;
4401 if (creatormode) init_creator();
4402 else init_play(0,1);
4403 break;
4404 case 2 :
4405 ingame = 2;
4406 creatormode = 0;
4407 switchflags &= ~CREATORFLAG;
4408 start_map();
4409 if (!initmapmsg) {
4410 init_sign(0);
4411 initmapmsg = 1;
4412 }
4413 break;
4414 case 3 :
4415 lvlCode = mapCode*20+mapselect;
4416 areaCode = 0;
4417 (get_bossvars())[BOSSMAX-1] = 0;
4418 trgentrance = -1;
4419 loaderror = 0;
4420 read_level();
4421 if (!loaderror) {
4422 ingame = 3;
4423 init_play(0,1);
4424 if (!initgamemsg) {
4425 init_sign(1);
4426 initgamemsg = 1;
4427 }
4428 } else {
4429 load_map(mapCode);
4430 }
4431 break;
4432 case 4:
4433 game_init();
4434 break;
4435 case 5 :
4436 temp = areaCode;
4437 areaCode = tempAreaCode;
4438 tempAreaCode = temp;
4439 tempcx = camx;
4440 tempcy = camy;
4441 read_level();
4442 camx = tempcx;
4443 camy = tempcy;
4444 init_play(1,1);
4445 break;
4446 case 6 :
4447 load_backups();
4448 break;
4449 case 7 :
4450 loaderror = 0;
4451 load_room_return();
4452 break;
4453 case 8 :
4454 mapCode = trgmap;
4455 start_map();
4456 break;
4457 case 9 :
4458 credittime = 0;
4459 ingame = 13;
4460 switch_music(13, 0);
4461 break;
4462 }
4463 if (fadereason > 0) init_fade(0);
4464 else walkaway = 0;
4465 }
4466
resolve_input(SDLKey key)4467 void resolve_input(SDLKey key) {
4468 int temp = getinput;
4469 getinput = 0;
4470 if ((key == SDLK_RETURN || key == SDLK_SPACE || !key) &&
4471 inputlength == -2 && !yesno && temp == -15)
4472 init_fade(2);
4473 if ((key == SDLK_RETURN || key == SDLK_SPACE || !key) &&
4474 (inputstr[0] != '-' || (inputlength == -2 && yesno) || inputlength == -3)) {
4475 switch (temp) {
4476 case -13 :
4477 crtmessage = atoi(inputstr);
4478 if (crtmessage >= MSGMAX) crtmessage = 0;
4479 break;
4480 case -15 :
4481 init_fade(7);
4482 break;
4483 case -20 :
4484 areaCode = -1;
4485 clear_room();
4486 break;
4487 case -21 :
4488 write_level();
4489 break;
4490 case -1 :
4491 crtexitroom = atoi(inputstr);
4492 if (crtexitroom >= ROOMMAX) crtexitroom = 0;
4493 break;
4494 case -2 :
4495 lvlCode = atoi(inputstr) + 79;
4496 if (lvlCode >= 80 && lvlCode <= 89)
4497 set_up_input("Save room number:",-4,2,areaCode);
4498 else set_up_input("Must be 1 - 10",1,-1,-1);
4499 break;
4500 case -3 :
4501 lvlCode = atoi(inputstr) + 79;
4502 if (lvlCode >= 80 && lvlCode <= 89)
4503 set_up_input("Load room number:",-5,2,-1);
4504 else set_up_input("Must be 1 - 10",1,-1,-1);
4505 break;
4506 case -4 :
4507 areaCode = atoi(inputstr);
4508 if (check_level_exists()) {
4509 set_up_input("Overwrite existing room?",-21,-2,-1);
4510 yesno = 0;
4511 break;
4512 }
4513 write_level();
4514 break;
4515 case -5 :
4516 areaCode = atoi(inputstr);
4517 read_level();
4518 break;
4519 case -6 :
4520 save_map(atoi(inputstr));
4521 break;
4522 case -7 :
4523 load_map(atoi(inputstr));
4524 break;
4525 case -8 :
4526 spminutes = atoi(inputstr);
4527 set_up_input("Set timer seconds:", -9, 2, -1);
4528 break;
4529 case -9 :
4530 spseconds = atoi(inputstr);
4531 if (spseconds >= 60) spseconds = 0;
4532 write_metalevel();
4533 break;
4534 case -10 :
4535 delete_game();
4536 break;
4537 case -11 :
4538 init_fade(4);
4539 break;
4540 case 13 :
4541 case 14 :
4542 case 17 :
4543 // Go back to map screen, title, or creator.
4544 if (optselect == 1) init_fade(temp == 13 ? 4 : (temp == 17 ? 1 : 2));
4545 else if (optselect == 2) init_opt_select();
4546 else if (optselect == 3) {
4547 if (ingame == 2) switch_background(2);
4548 ingamereturn = ingame;
4549 ingame = 4;
4550 }
4551 break;
4552 case 16 :
4553 if (optselect == 1) init_fade(1);
4554 else if (optselect == 2) init_fade(2);
4555 break;
4556 case -12 :
4557 init_fade(2);
4558 break;
4559 case -14 :
4560 if (enemdeadhere) enemdead[areaCode] = 1;
4561 beatlevel[lvlCode] = 1;
4562 if (lvlCode < LAST_LEVEL) {
4563 // Check which medals the player collected.
4564 if (gotmwht && !haswmed) {gotmedals[lvlCode*6] = 1; gamemedals++;}
4565 if (!hasomed && (gotmcrn[0] || game_gotcorners[lvlCode][0]) && (gotmcrn[1] || game_gotcorners[lvlCode][1]) &&
4566 (gotmcrn[2] || game_gotcorners[lvlCode][2]) && (gotmcrn[3] || game_gotcorners[lvlCode][3])) {
4567 gotmedals[lvlCode*6+1] = 1; gamemedals++;
4568 }
4569 if (!hasbmed && mfragcount == MFRAGTOTAL) {gotmedals[lvlCode*6+2] = 1; gamemedals++;}
4570 if (!hasrmed && enemalldead) {gotmedals[lvlCode*6+3] = 1; gamemedals++;}
4571 if (!hasgmed && gotgmed) {gotmedals[lvlCode*6+4] = 1; gamemedals++;}
4572 if (!haspmed && gotpmed) {gotmedals[lvlCode*6+5] = 1; gamemedals++;}
4573 // Check which pieces of medals the player collected.
4574 for (i = 0; i < 4; i++) {
4575 if (gotmcrn[i]) game_gotcorners[lvlCode][i] = 1;
4576 }
4577 for (i = 0; i < MFRAGTOTAL; i++) {
4578 if (gotmfrag[i]) game_gotfrags[lvlCode][i] = 1;
4579 }
4580 for (i = 0; i < ROOMMAX; i++) {
4581 if (enemdead[i]) game_enemdead[lvlCode][i] = 1;
4582 }
4583 }
4584 save_game_data();
4585 remove_room_return();
4586 if (lvlCode != LAST_LEVEL) {
4587 init_fade(2);
4588 } else {
4589 init_fade(9);
4590 }
4591 break;
4592 case 2 :
4593 start_new_game();
4594 init_fade(2);
4595 break;
4596 }
4597 }
4598 }
4599