made dead items list non-transient, 'cause game can be saved inter-frame
[k8vacspelynky.git] / rgenobj.vc
blobb4d700e65b733313048fb621c9431dad09fe69cd
1 /**********************************************************************************
2  * Copyright (c) 2008, 2009 Derek Yu and Mossmouth, LLC
3  * Copyright (c) 2018, Ketmar Dark
4  *
5  * This file is part of Spelunky.
6  *
7  * You can redistribute and/or modify Spelunky, including its source code, under
8  * the terms of the Spelunky User License.
9  *
10  * Spelunky is distributed in the hope that it will be entertaining and useful,
11  * but WITHOUT WARRANTY.  Please see the Spelunky User License for more details.
12  *
13  * The Spelunky User License should be available in "Game Information", which
14  * can be found in the Resource Explorer, or as an external file called COPYING.
15  * If not, please obtain a new copy of Spelunky from <http://spelunkyworld.com/>
16  *
17  **********************************************************************************/
18 // ////////////////////////////////////////////////////////////////////////// //
19 void scrLevGenShopkeeper (int xpos, int ypos, name shopType) {
20   auto obj = MonsterShopkeeper(MakeMapObject(xpos, ypos, 'oShopkeeper'));
21   if (obj) {
22     //if (shopType == 'Ankh') writeln("::: ", shopType, " :::");
23     obj.style = shopType;
24     if (shopType == 'Craps') obj.generatePrizes();
25   }
29 // ////////////////////////////////////////////////////////////////////////// //
30 enum GenItemSet {
31   Crate,
32   Craps,
33   Underground,
36 MapObject scrGenerateItem (int objx, int objy, GenItemSet setType) {
37   MapObject obj = none;
39   switch (setType) {
40     case GenItemSet.Crate: // crate set
41            if (global.randRoom(1, 500) == 1) obj = MakeMapObject(objx, objy, 'oJetpack');
42       else if (global.randRoom(1, 200) == 1) obj = MakeMapObject(objx, objy, 'oCapePickup');
43       else if (global.randRoom(1, 100) == 1) obj = MakeMapObject(objx, objy, 'oShotgun');
44       else if (!global.isTunnelMan && global.randRoom(1, 100) == 1) obj = MakeMapObject(objx, objy, 'oMattock');
45       else if (global.randRoom(1, 100) == 1) obj = MakeMapObject(objx, objy, 'oTeleporter');
46       else if (global.randRoom(1, 90) == 1) obj = MakeMapObject(objx, objy, 'oGloves');
47       else if (global.randRoom(1, 90) == 1) obj = MakeMapObject(objx, objy, 'oSpectacles');
48       else if (global.randRoom(1, 80) == 1) obj = MakeMapObject(objx, objy, 'oWebCannon');
49       else if (global.randRoom(1, 80) == 1) obj = MakeMapObject(objx, objy, 'oPistol');
50       else if (global.randRoom(1, 80) == 1) obj = MakeMapObject(objx, objy, 'oMitt');
51       else if (global.randRoom(1, 60) == 1) obj = MakeMapObject(objx, objy, 'oPaste');
52       else if (global.randRoom(1, 60) == 1) obj = MakeMapObject(objx, objy, 'oSpringShoes');
53       else if (global.randRoom(1, 60) == 1) obj = MakeMapObject(objx, objy, 'oSpikeShoes');
54       else if (global.randRoom(1, 60) == 1) obj = MakeMapObject(objx, objy, 'oMachete');
55       else if (global.randRoom(1, 40) == 1) obj = MakeMapObject(objx, objy, 'oBombBox');
56       else if (global.randRoom(1, 40) == 1) obj = MakeMapObject(objx, objy, 'oBow');
57       else if (global.randRoom(1, 20) == 1) obj = MakeMapObject(objx, objy, 'oCompass');
58       else if (global.randRoom(1, 10) == 1) obj = MakeMapObject(objx, objy, 'oParaPickup');
59       else obj = MakeMapObject(objx, objy, 'oRopePile');
60       obj.forSale = false;
61       break;
62     case GenItemSet.Craps: // high end set -- craps game prizes
63            if (global.randRoom(1, 40) == 1) obj = MakeMapObject(objx, objy, 'oJetpack');
64       else if (global.randRoom(1, 25) == 1) obj = MakeMapObject(objx, objy, 'oCapePickup');
65       else if (global.randRoom(1, 20) == 1) obj = MakeMapObject(objx, objy, 'oShotgun');
66       else if (global.randRoom(1, 10) == 1) obj = MakeMapObject(objx, objy, 'oGloves');
67       else if (global.randRoom(1, 10) == 1) obj = MakeMapObject(objx, objy, 'oTeleporter');
68       else if (!global.isTunnelMan && global.randRoom(1, 8) == 1) obj = MakeMapObject(objx, objy, 'oMattock');
69       else if (global.randRoom(1, 8) == 1) obj = MakeMapObject(objx, objy, 'oPaste');
70       else if (global.randRoom(1, 8) == 1) obj = MakeMapObject(objx, objy, 'oSpringShoes');
71       else if (global.randRoom(1, 8) == 1) obj = MakeMapObject(objx, objy, 'oSpikeShoes');
72       else if (global.randRoom(1, 8) == 1) obj = MakeMapObject(objx, objy, 'oCompass');
73       else if (global.randRoom(1, 8) == 1) obj = MakeMapObject(objx, objy, 'oPistol');
74       else if (global.randRoom(1, 8) == 1) obj = MakeMapObject(objx, objy, 'oMachete');
75       else obj = MakeMapObject(objx, objy, 'oBombBox');
76       break;
77     case GenItemSet.Underground: // Underground Set (items hidden inside solid walls, see oBrick etc)
78       switch (global.randRoom(0, 18)) {
79         case 0: obj = MakeMapObject(objx, objy-2, 'oJetpack'); break;
80         case 1: obj = MakeMapObject(objx, objy, 'oCapePickup'); break;
81         case 2: obj = MakeMapObject(objx, objy, 'oShotgun'); break;
82         case 3:
83           if (global.isTunnelMan) obj = MakeMapObject(objx, objy, 'oRopePile');
84           else obj = MakeMapObject(objx, objy, 'oMattock');
85           break;
86         case 4: obj = MakeMapObject(objx, objy+3, 'oTeleporter'); break;
87         case 5: obj = MakeMapObject(objx, objy-1, 'oGloves'); break;
88         case 6: obj = MakeMapObject(objx, objy, 'oSpectacles'); break;
89         case 7: obj = MakeMapObject(objx-2, objy, 'oWebCannon'); break;
90         case 8: obj = MakeMapObject(objx, objy, 'oPistol'); break;
91         case 9: obj = MakeMapObject(objx, objy-1, 'oMitt'); break;
92         case 10: obj = MakeMapObject(objx, objy, 'oPaste'); break;
93         case 11: obj = MakeMapObject(objx, objy, 'oSpringShoes'); break;
94         case 12: obj = MakeMapObject(objx, objy, 'oSpikeShoes'); break;
95         case 13: obj = MakeMapObject(objx, objy, 'oMachete'); break;
96         case 14: obj = MakeMapObject(objx, objy-2, 'oBombBox'); break;
97         case 15: obj = MakeMapObject(objx, objy, 'oBow'); break;
98         case 16: obj = MakeMapObject(objx, objy, 'oCompass'); break;
99         case 17: obj = MakeMapObject(objx, objy, 'oParaPickup'); break;
100         case 18: obj = MakeMapObject(objx, objy, 'oRopePile'); break;
101       }
102       break;
103   }
105   return obj;
109 // generate shop items
110 MapObject scrShopItemsGen (int xpos, int ypos, name shopType) {
111   MapObject obj = none;
113   writeln("generating items for shop \"", shopType, "\"...");
115   if (shopType == 'Bomb') {
116     for (;;) {
117       if (global.randRoom(1, 5) == 1) {
118         if (!findAnyObjectOfType('oPaste')) { obj = MakeMapObject(xpos+8, ypos+10, 'oPaste'); break; }
119       } else if (global.randRoom(1, 4) == 1) {
120         obj = MakeMapObject(xpos+8, ypos+8, 'oBombBox');
121         break;
122       } else if (global.config.optSGAmmo && global.randRoom(1, 10) == 1) {
123         obj = MakeMapObject(xpos+4, ypos+10, 'oShells');
124         break;
125       } else {
126         if (global.config.optSGAmmo && findAnyObjectOfType('oShotgun')) {
127           obj = MakeMapObject(xpos+4, ypos+10, 'oShells');
128         } else {
129           obj = MakeMapObject(xpos+8, ypos+10, 'oBombBag');
130         }
131         break;
132       }
133     }
134   } else if (shopType == 'Weapon') {
135     int m = 20;
136     for (;;) {
137       int n = global.randRoom(1, 4);
138       if (m <= 0) {
139         obj = MakeMapObject(xpos+8, ypos+10, 'oBombBag');
140         break;
141       } else if (global.randRoom(1, 12) == 1) {
142         if (!findAnyObjectOfType('oWebCannon')) { obj = MakeMapObject(xpos+8, ypos+12, 'oWebCannon'); break; }
143       } else if (global.randRoom(1, 10) == 1) {
144         if (!findAnyObjectOfType('oShotgun')) { obj = MakeMapObject(xpos+8, ypos+12, 'oShotgun'); break; }
145       } else if (global.randRoom(1, 6) == 1) {
146         obj = MakeMapObject(xpos+8, ypos+10, 'oBombBox');
147         break;
148       } else if (n == 1) {
149         if (!findAnyObjectOfType('oPistol')) { obj = MakeMapObject(xpos+8, ypos+12, 'oPistol'); break; }
150       } else if (n == 2) {
151         if (!findAnyObjectOfType('oMachete')) { obj = MakeMapObject(xpos+8, ypos+12, 'oMachete'); break; }
152       } else if (n == 3) {
153         if (global.config.optSGAmmo && findAnyObjectOfType('oShotgun')) {
154           obj = MakeMapObject(xpos+4, ypos+10, 'oShells');
155         } else {
156           obj = MakeMapObject(xpos+8, ypos+10, 'oBombBag');
157         }
158         break;
159       } else if (n == 4) {
160         if (!findAnyObjectOfType('oBow')) { obj = MakeMapObject(xpos+8, ypos+12, 'oBow'); break; }
161       }
162       m -= 1;
163     }
164   } else if (shopType == 'Clothing') {
165     int m = 20;
166     for (;;) {
167       int n = global.randRoom(1, 6);
168            if (global.randRoom(1, m) == 1) { obj = MakeMapObject(xpos+8, ypos+11, 'oRopePile'); break; }
169       else if (n == 1) { if (!findAnyObjectOfType('oSpringShoes')) { obj = MakeMapObject(xpos+8, ypos+10, 'oSpringShoes'); break; } }
170       else if (n == 2) { if (!findAnyObjectOfType('oSpectacles')) { obj = MakeMapObject(xpos+8, ypos+10, 'oSpectacles'); break; } }
171       else if (n == 3) { if (!findAnyObjectOfType('oGloves')) { obj = MakeMapObject(xpos+8, ypos+8, 'oGloves'); break; } }
172       else if (n == 4) { if (!findAnyObjectOfType('oMitt')) { obj = MakeMapObject(xpos+8, ypos+8, 'oMitt'); break; } }
173       else if (n == 5) { if (!findAnyObjectOfType('oCapePickup')) { obj = MakeMapObject(xpos+8, ypos+10, 'oCapePickup'); break; } }
174       else if (n == 6) { if (!findAnyObjectOfType('oSpikeShoes')) { obj = MakeMapObject(xpos+8, ypos+10, 'oSpikeShoes'); break; } }
175       m -= 1;
176     }
177   } else if (shopType == 'Rare') {
178     int m = 20;
179     for (;;) {
180       int n = global.randRoom(1, 11);
181            if (global.randRoom(1, m) == 1) { obj = MakeMapObject(xpos+8, ypos+8, 'oBombBox'); break; }
182       else if (n == 1) { if (!findAnyObjectOfType('oSpringShoes')) { obj = MakeMapObject(xpos+8, ypos+10, 'oSpringShoes'); break; } }
183       else if (n == 2) { if (!findAnyObjectOfType('oCompass')) { obj = MakeMapObject(xpos+8, ypos+10, 'oCompass'); break; } }
184       else if (n == 3) { if (!findAnyObjectOfType('oMattock') && !global.isTunnelMan) { obj = MakeMapObject(xpos+8, ypos+10, 'oMattock'); break; } }
185       else if (n == 4) { if (!findAnyObjectOfType('oSpectacles')) { obj = MakeMapObject(xpos+8, ypos+10, 'oSpectacles'); break; } }
186       else if (n == 5) { if (!findAnyObjectOfType('oJetpack')) { obj = MakeMapObject(xpos+8, ypos+8, 'oJetpack'); break; } }
187       else if (n == 6) { if (!findAnyObjectOfType('oGloves')) { obj = MakeMapObject(xpos+8, ypos+8, 'oGloves'); break; } }
188       else if (n == 7) { if (!findAnyObjectOfType('oMitt')) { obj = MakeMapObject(xpos+8, ypos+8, 'oMitt'); break; } }
189       else if (n == 8) { if (!findAnyObjectOfType('oWebCannon')) { obj = MakeMapObject(xpos+8, ypos+12, 'oWebCannon'); break; } }
190       else if (n == 9) { if (!findAnyObjectOfType('oCapePickup')) { obj = MakeMapObject(xpos+8, ypos+10, 'oCapePickup'); break; } }
191       else if (n == 10) { if (!findAnyObjectOfType('oTeleporter')) { obj = MakeMapObject(xpos+8, ypos+12, 'oTeleporter'); break; } }
192       else if (n == 11) { if (!findAnyObjectOfType('oSpikeShoes')) { obj = MakeMapObject(xpos+8, ypos+10, 'oSpikeShoes'); break; } }
193       m -= 1;
194     }
195   } else {
196     for (;;) {
197       int n = global.randRoom(1, 3);
198       if (global.randRoom(1, 20) == 1) { if (!findAnyObjectOfType('oMattock') && !global.isTunnelMan) { obj = MakeMapObject(xpos+8, ypos+10, 'oMattock'); break; } }
199       else if (global.randRoom(1, 10) == 1) { if (!findAnyObjectOfType('oGloves')) { obj = MakeMapObject(xpos+8, ypos+8, 'oGloves'); break; } }
200       else if (global.randRoom(1, 10) == 1) { if (!findAnyObjectOfType('oCompass')) { obj = MakeMapObject(xpos+8, ypos+10, 'oCompass'); break; } }
201       else if (n == 1) {
202         if (global.config.optSGAmmo && findAnyObjectOfType('oShotgun')) {
203           obj = MakeMapObject(xpos+4, ypos+10, 'oShells');
204         } else {
205           obj = MakeMapObject(xpos+8, ypos+10, 'oBombBag');
206         }
207         break;
208       } else if (n == 2) { obj = MakeMapObject(xpos+8, ypos+11, 'oRopePile'); break; }
209         else if (n == 3) { obj = MakeMapObject(xpos+8, ypos+10, 'oParaPickup'); break; }
210     }
211   }
213   if (obj) {
214     obj.forSale = true;
215     obj.shopType = shopType;
216     /+k8: cost is generated in item creation code
217     if (global.currLevel > 2) {
218       if (obj.cost <= 0) obj.cost = 100;
219       obj.cost += (obj.cost/100)*10*(global.currLevel-2);
220       //if (shopDesc == "") buyMessage = "A "+string_upper(type)+" FOR $"+string(cost)+".";
221       //else buyMessage = shopDesc+" FOR $"+string(cost)+".";
222     }
223     +/
224   }
226   return obj;
230 // ////////////////////////////////////////////////////////////////////////// //
231 //WARNING: keep this in sync with `ItemJar::onDestroy()`!
232 name scrLevGenCreateJarContents () {
233   name ctx;
235        if (global.randRoom(1, 3) == 1) ctx = 'oGoldChunk';
236   else if (global.config.optSGAmmo && global.randRoom(1, 4) == 1) ctx = 'oShellSingle';
237   else if (global.randRoom(1, 6) == 1) ctx = 'oGoldNugget';
238   else if (global.randRoom(1, 12) == 1) ctx = 'oEmeraldBig';
239   else if (global.randRoom(1, 12) == 1) ctx = 'oSapphireBig';
240   else if (global.randRoom(1, 12) == 1) ctx = 'oRubyBig';
241   else if (global.randRoom(1, 6) == 1) ctx = 'oSpider';
242   else if (global.randRoom(1, 12) == 1) { if (global.randRoom(1, 50) == 1) ctx = 'oCobra'; else ctx = 'oSnake'; }
243   else if (global.randRoom(1, 100) == 1) ctx = 'oAlien';
244   else if (global.randRoom(1, 300) == 1) ctx = 'oBlob';
246   /* in the original
247   switch (global.randRoom(0, 2)) {
248     case 0: ctx = 'oEmeraldBig'; break;
249     case 1: ctx = 'oSapphireBig'; break;
250     case 2: ctx = 'oRubyBig'; break;
251   }
252   */
254   return ctx;
258 final MapObject scrLevGenCreateJar (int x, int y) {
259   auto obj = MakeMapObject(x, y, 'oJar');
260   MapItem(obj).contents = scrLevGenCreateJarContents();
261   return obj;
265 // ////////////////////////////////////////////////////////////////////////// //
266 final bool cbIsGoldIdol (MapObject o) { return (o isa ItemGoldIdol); }
267 final bool cbIsGiantSpider (MapObject o) { return (o isa EnemyGiantSpider); }
268 final bool cbIsChestObject (MapObject o) { return (o isa ItemChest); }
270 final bool cbIsTreasureTile (MapTile t) { return !!t.gem; } //K8:FIXME: only real treasures?
271 final bool cbIsBadTile (MapTile t) { return (t.spikes || t.enter || t.exit); }
272 final bool cbIsBlockTile (MapTile t) { return (t.objType == 'oBlock'); }
273 final bool cbIsLiquidTile (MapTile t) { return (t.water || t.lava); }
276 // Generates crates, chests, gold, gems, and bones
277 void scrTreasureGen (int x, int y, optional int bonesChance) {
278   // argument0: bones
280   // alcove
281   if (calcNearestEnterDist(x+8, y+8) < 32) return;
282   if (calcNearestExitDist(x+8, y+8) < 32) return;
283   if (calcNearestObjectDist(x+8, y+8, &cbIsGoldIdol) < 64) return;
285   bool colStuff =
286     isSolidAtPoint(x, y-16) ||
287     checkTileAtPoint(x, y-1, &cbIsTreasureTile) ||
288     isObjectAtTilePix(x, y-8, &cbIsChestObject) || //<-collision_point(x, y-8, oChest, 0, 0) &&
289     checkTileAtPoint(x, y-8, &cbIsBadTile);
291   if (!colStuff) {
292     if (global.randRoom(1, 100) == 1) { MakeMapObject(x+8, y-4, 'oRock'); return; }
293     if (global.randRoom(1, 40) == 1) { scrLevGenCreateJar(x+8, y-6); return; }
294   }
296   // alcove
297   if (!colStuff &&
298       isSolidAtPoint(x, y-32) &&
299       (isSolidAtPoint(x-16, y-16) ||
300        isSolidAtPoint(x+16, y-16) ||
301        checkTileAtPoint(x-16, y-16, &cbIsBlockTile) ||
302        checkTileAtPoint(x+16, y-16, &cbIsBlockTile)))
303   {
304     int n = 60;
305     if (calcNearestObjectDist(x+8, y+8, &cbIsGiantSpider) < 100) n = 5;
306     if (global.levelType != 2 && global.randRoom(1, n) == 1) {
307       MakeMapObject(x, y-16, 'oWeb');
308     } else if (global.genUdjatEye && !global.LockedChest) {
309       if (global.randRoom(1, global.lockedChestChance) == 1) {
310         MakeMapObject(x+8, y-16, 'oLockedChest');
311         global.LockedChest = true;
312         writeln("*** GENERATED LOCKED CHEST");
313       } else {
314         global.lockedChestChance -= 1;
315       }
316     } else if (global.randRoom(1, 10) == 1) {
317       scrLevGenCreateCrate(x+8, y-8);
318     } else if (global.randRoom(1, 15) == 1) {
319       scrLevGenCreateChest(x+8, y-8);
320     } else if (!global.damsel && global.randRoom(1, 8) == 1 && !checkTileAtPoint(x+8, y-8, &cbIsLiquidTile)) {
321       auto obj = MakeMapObject(x+8, y-8, 'oDamsel');
322       if (obj) global.damsel = true;
323     } else if (global.randRoom(1, 40-2*global.currLevel) <= 1+bonesChance) {
324       //writeln("=== BONES ===");
325       if (global.randRoom(1, 8) == 1) {
326         MakeMapObject(x, y-16, 'oFakeBones');
327       } else {
328         MakeMapObject(x, y-16, 'oBones');
329         MakeMapObject(x+12, y-4, 'oSkull');
330       }
331     }
332     else if (global.randRoom(1, 3) == 1) MakeMapObject(x+8, y-4, 'oGoldBar');
333     else if (global.randRoom(1, 6) == 1) MakeMapObject(x+8, y-8, 'oGoldBars');
334     else if (global.randRoom(1, 6) == 1) MakeMapObject(x+8, y-4, 'oEmeraldBig');
335     else if (global.randRoom(1, 8) == 1) MakeMapObject(x+8, y-4, 'oSapphireBig');
336     else if (global.randRoom(1, 10) == 1) MakeMapObject(x+8, y-4, 'oRubyBig');
337     //else if (global.bizarre && randRoom(1, 6) == 1) {obj = MakeMapObject(x+8, y-8, 'oAntidote'); obj.cost = 0; obj.forSale = false} // in the original
338   } // tunnel
339   else if (!colStuff && isSolidAtPoint(x-16, y-16) && isSolidAtPoint(x+16, y-16)) {
340     int n = 60;
341     if (calcNearestObjectDist(x+8, y+8, &cbIsGiantSpider) < 100) n = 10;
342          if (global.levelType != 2 && global.randRoom(1, n) == 1) MakeMapObject(x, y-16, 'oWeb');
343     else if (global.randRoom(1, 4) == 1) MakeMapObject(x+8, y-4, 'oGoldBar');
344     else if (global.randRoom(1, 8) == 1) MakeMapObject(x+8, y-8, 'oGoldBars');
345     else if (global.randRoom(1, 80-global.currLevel) <= 1+bonesChance) {
346       if (global.randRoom(1, 8) == 1) {
347         MakeMapObject(x, y-16, 'oFakeBones');
348       } else {
349         MakeMapObject(x, y-16, 'oBones');
350         MakeMapObject(x+12, y-4, 'oSkull');
351       }
352     }
353     else if (global.randRoom(1, 8) == 1) MakeMapObject(x+8, y-4, 'oEmeraldBig');
354     else if (global.randRoom(1, 9) == 1) MakeMapObject(x+8, y-4, 'oSapphireBig');
355     else if (global.randRoom(1, 10) == 1) MakeMapObject(x+8, y-4, 'oRubyBig');
356     //else if (global.bizarre && randRoom(1, 10) == 1) {obj = MakeMapObject(x+8, y-8, 'oAntidote'); obj.cost = 0; obj.forSale = false} // in the original
357   } // normal
358   else if (!isSolidAtPoint(x, y-16) &&
359            isObjectAtTilePix(x, y-8, &cbIsChestObject) && //<-collision_point(x, y-8, oChest, 0, 0) &&
360            !checkTileAtPoint(x, y-8, &cbIsBadTile))
361   {
362          if (global.randRoom(1, 40) == 1) MakeMapObject(x+8, y-4, 'oGoldBar');
363     else if (global.randRoom(1, 50) == 1) MakeMapObject(x+8, y-8, 'oGoldBars');
364     else if (global.randRoom(1, 140-2*global.currLevel) <= 1+bonesChance) {
365       if (global.randRoom(1, 8) == 1) {
366         MakeMapObject(x, y-16, 'oFakeBones');
367       } else {
368         MakeMapObject(x, y-16, 'oBones');
369         MakeMapObject(x+12, y-4, 'oSkull');
370       }
371     }
372   }
376 // ////////////////////////////////////////////////////////////////////////// //
377 name scrGenGetFrogType () {
378   if (global.config.optEnemyVariations) {
379     int totdeath789 = stats.getDeathCountOnLevel(7)+stats.getDeathCountOnLevel(8)+stats.getDeathCountOnLevel(9);
380     if (totdeath789 < 22) {
381       if (global.randOther(0, 100) >= 99-(global.currLevel-4)*8) return 'oGreenFrog';
382       return 'oFrog';
383     }
384     if (totdeath789 < 32) {
385       if (global.randOther(0, 100) >= 85-(global.currLevel-4)*8) return 'oGreenFrog';
386       return 'oFrog';
387     }
388     if (totdeath789 < 42) {
389       if (global.randOther(0, 100) >= 75-(global.currLevel-4)*8) return 'oGreenFrog';
390       return 'oFrog';
391     }
392     if (totdeath789 < 52) {
393       if (global.randOther(0, 100) >= 65-(global.currLevel-4)*8) return 'oGreenFrog';
394       return 'oFrog';
395     }
396     if (totdeath789 < 62) {
397       if (global.randOther(0, 100) >= 55-(global.currLevel-4)*8) return 'oGreenFrog';
398       return 'oFrog';
399     }
400     if (global.randOther(0, 100) >= 50-(global.currLevel-4)*8) return 'oGreenFrog';
401   }
402   return 'oFrog';
406 // ////////////////////////////////////////////////////////////////////////// //
408 private final bool scrGenEntitiesInMinesCB (int tileX, int tileY, MapTile t) {
409   if (!isInShop(tileX, tileY) && tileY > 1) {
410     if (t.objType != 'Altar') {
411       scrTreasureGen(tileX*16, tileY*16);
412     }
413     int roomX, roomY;
414     tileXY2roomXY(tileX, tileY-1, roomX, roomY); //k8: why -1?
415     // enemies
416     if (roomX != startRoomX || roomY != startRoomY) {
417       if (tileY < GameLevel::NormalTilesHeight-4 &&
418           !checkTilesInRect(tileX*16, (tileY+1)*16, 17, 33, &cbCollisionAnySolidOrLiquid) &&
419           !isObjectAtPoint(tileX*16+8, (tileY+1)*16+8))
420       {
421         if (global.genGiantSpider && !global.giantSpider &&
422             global.randRoom(1, trunc(ceil(40.0/global.config.enemyMult))) == 1 &&
423             !checkTilesInRect((tileX+1)*16, (tileY+1)*16, 17, 33, &cbCollisionAnySolid/*k8:???OrLiquid*/))
424         {
425           MakeMapObject(tileX*16, (tileY+1)*16, 'oGiantSpiderHang');
426           global.giantSpider = true;
427         }
428         else if (global.darkLevel && global.randRoom(1, 60) == 1) MakeMapTile(tileX, tileY+1, 'oLamp');
429         else if (global.darkLevel && global.randRoom(1, 40) == 1) MakeMapObject(tileX*16, (tileY+1)*16, 'oScarab');
430         else if (global.randRoom(1, trunc(ceil(60.0/global.config.enemyMult))) == 1) MakeMapObject(tileX*16, (tileY+1)*16, 'oBat');
431         else if (global.randRoom(1, trunc(ceil(80.0/global.config.enemyMult))) == 1) MakeMapObject(tileX*16, (tileY+1)*16, scrGenGetSpiderType());
432       }
433       if (global.giantSpider && global.config.enemyMult >= 2) {
434         if (global.randRoom(1, trunc(ceil(2400.0/global.config.enemyMult))) == 1) {
435           global.genGiantSpider = true;
436           global.giantSpider = false;
437         }
438       }
439       if (!checkTileAtPoint(tileX*16, (tileY-1)*16, &cbCollisionAnySolid/*k8:???OrLiquid*/)) {
440         if (global.randRoom(1, trunc(ceil(60.0/global.config.enemyMult))) == 1) {
441           MakeMapObject(tileX*16, (tileY-1)*16, scrGenGetSnakeType());
442         } else if (global.randRoom(1, trunc(ceil(800.0/global.config.enemyMult))) == 1) {
443           MakeMapObject(tileX*16, (tileY-1)*16, 'oCaveman');
444         }
445       }
446     }
447   }
448   // `false` means "continue"
449   return false;
454 // ////////////////////////////////////////////////////////////////////////// //
455 final bool isTreasureObjectCB (MapObject o) { return o.isTreasure; }
456 final bool isChestObjectCB (MapObject o) { return (o isa ItemOpenableContainer); } // not only chest, but a crate too
458 //private transient bool ashGraveGenerated;
461 // generates enemies, traps, and treasure
463 final void scrGenerateEntities () {
464   } else if (global.levelType == 2) {
465     // level type 2 (ice caves)
466     /+
467     with (oSolid) {
468       if (!isInShop(x, y)) {
469         // enemies
470         n = 30;
471         if (global.yetiLair) n = 90;
473         if (scrGetRoomX(x) != global.startRoomX || scrGetRoomY(y-16) != global.startRoomY) {
474           if (y < room_height-64 &&
475               !collision_point(x, y+16, oSolid, 0, 0) && !collision_point(x, y+32, oSolid, 0, 0) &&
476               !collision_point(x, y+16, oWater, 0, 0) && !collision_point(x, y+32, oWater, 0, 0))
477           {
478             if (global.darkLevel && global.randRoom(1, 40) == 1) MakeMapObject(x, y+16, 'oScarab');
479           } else if (y > 16 && y < 592 && !collision_point(x, y-16, oSolid, 0, 0) && !isInShop(x, y)) {
480             if (global.randRoom(1, ceil(float(n)/ceil(global.config.enemyMult/2.0))) == 1) MakeMapObject(x, y-16, 'oUFO');
481           }
482         }
484         if (y > 16 && y < 592 &&
485             !collision_point(x, y-16, oSolid, 0, 0) &&
486             !collision_point(x+8, y-8, oEnemy, 0, 0) &&
487             !collision_point(x+8, y-1, oSpikes, 0, 0) &&
488             !collision_point(x+8, y-1, oSpikesWood, 0, 0) &&
489             point_distance(x, y, oEntrance.x, oEntrance.y) > 64 &&
490             !isInShop(x, y))
491         {
492                if (global.randRoom(1, ceil(10.0/global.trapMult)) == 1 && sprite_index == sDark && !collision_rectangle(x, y-64, x+15, y-1, oSolid, 0, 0) && distance_to_object(oExit) > 64) MakeMapObject(x, y-16, 'oSpringTrap');
493           else if (global.randRoom(1, ceil(20.0/global.config.enemyMult)) == 1 && point_distance(x, y, oEntrance.x, oEntrance.y) > 64) MakeMapObject(x, y-16, 'oYeti');
494         }
496         if (type != "Altar") scrTreasureGen();
497       }
498     }
499     +/
500   } else if (global.levelType == 3) {
501     // level type 3 (temple)
502     /+
503     global.TombLord = false;
504     global.totalTombLords = 0;
505     global.gaveSceptre = false;
506     global.genTombLord = false;
507          if (global.currLevel == 13) global.genTombLord = true;
508     else if (global.randRoom(1, ceil(4.0/global.config.enemyMult)) == 1) global.genTombLord = true;
510     global.genGoldEntrance = false;
511     if (global.currLevel == 14) global.genGoldEntrance = true;
512     global.madeGoldEntrance = false;
514     with (oSolid) {
515       // bg
516       if (global.randRoom(1, 100) == 1 && !collision_point(x, y-16, oSolid, 0, 0)) tile_add(bgStatues, 0, 0, 16, 48, x, y-32, 9005);
518       if (!isInShop(x, y)) {
519         // traps
520         if (y > 32 && !collision_point(x, y-16, oSolid, 0, 0) && global.genGoldEntrance && !global.madeGoldEntrance) {
521           if (global.randRoom(1, global.goldChance) == 1) {
522             MakeMapObject(x, y-16, 'oGoldDoor');
523             invincible = true;
524             global.madeGoldEntrance = true;
525           } else {
526             global.goldChance -= 1;
527           }
528         } else if (type != "Tree" && type != "Altar" && y != 0 &&
529                    !collision_point(x, y-16, oSolid, 0, 0) &&
530                    !collision_point(x, y-16, oLava, 0, 0) &&
531                    !collision_rectangle(x, y-16, x+15, y-1, oEnemy, 0, 0) &&
532                    !collision_point(x, y-32, oSolid, 0, 0) &&
533                    (!collision_point(x-16, y, oSolid, 0, 0) || !collision_point(x+16, y, oSolid, 0, 0)) &&
534                    collision_point(x, y+16, oSolid, 0, 0) &&
535                    !isInShop(x, y) &&
536                    x != 160 && x != 176 && x != 320 && x != 336 && x != 480 && x != 496)
537         {
538           if (global.randRoom(1, ceil(12.0/global.trapMult)) == 1 && point_distance(x, y, oEntrance.x, oEntrance.y) > 64) {
539             // to keep the spear trap from plugging up lava passage
540             if (collision_point(x-16, y-32, oSolid, 0, 0) && collision_point(x+16, y-32, oSolid, 0, 0) &&
541                 !collision_point(x, y-32, oSolid, 0, 0))
542             {
543               // do nothing
544             } else {
545               if (collision_point(x, y-16, oSolid, 0, 0)) {
546                 sol = instance_nearest(x, y-16, oSolid);
547                 with (sol) { cleanDeath = true; instance_destroy(); }
548               }
549               MakeMapObject(x, y, 'oSpearTrapBottom');
550               if (global.darkLevel) MakeMapObject(x, y-16, 'oSpearTrapLit');
551               else MakeMapObject(x, y-16, 'oSpearTrapTop');
552               cleanDeath = true;
553               instance_destroy();
554             }
555           }
556         }
558         // enemies
559         if (y < room_height-64 &&
560             !collision_point(x, y+16, oSolid, 0, 0) && !collision_point(x, y+32, oSolid, 0, 0) &&
561             !collision_point(x, y+16, oWater, 0, 0) && !collision_point(x, y+32, oWater, 0, 0))
562         {
563           if (global.darkLevel && global.randRoom(1, 40) == 1) MakeMapObject(x, y+16, 'oScarab');
564         }
566         if (scrGetRoomX(x) != global.startRoomX || scrGetRoomY(y-16) != global.startRoomY &&
567             !collision_point(x, y-16, oEnemy, 0, 0))
568         {
569           if (y > 16 && !collision_point(x, y-16, oSolid, 0, 0)) {
570               if (global.genTombLord &&
571                   !global.TombLord &&
572                   !collision_rectangle(x, y-32, x+32, y-1, oSolid, 0, 0) &&
573                   global.randRoom(1, ceil(40.0/global.config.enemyMult)) == 1)
574               {
575                 obj = MakeMapObject(x, y-32, 'oTombLord');
576                 global.totalTombLords += 1;
577                 if (global.currLevel == 13) {
578                   if (!global.gaveSceptre) {
579                     if (global.randRoom(1, global.config.enemyMult) == 1) {
580                       obj.hasSceptre = true;
581                       global.gaveSceptre = true;
582                     }
583                   }
584                   if (global.randRoom(1, global.config.enemyMult) == 1 || global.totalTombLords >= global.config.enemyMult) global.TombLord = true; // don't make any more tomb lords
585                   if (global.TombLord == true && !global.gaveSceptre) {
586                     obj.hasSceptre = true;
587                     global.gaveSceptre = true;
588                   }
589                 }
590               }
591               else if (global.randRoom(1, ceil(40.0/global.config.enemyMult)) == 1) MakeMapObject(x, y-16, 'oCaveman');
592               else if (global.randRoom(1, ceil(40.0/global.config.enemyMult)) == 1) MakeMapObject(x, y-16, 'oHawkman');
593               else if (global.randRoom(1, ceil(60.0/global.config.trapMult)) == 1) {
594                 if (global.darkLevel) MakeMapObject(x, y-16, 'oSmashTrapLit'); else MakeMapObject(x, y-16, 'oSmashTrap');
595               }
596           }
597         }
599         /*
600         if (scrGetRoomX(x) != global.startRoomX || scrGetRoomY(y) != global.startRoomY) &&
601             y >=16 && y < room_height-64 &&
602             !collision_rectangle(x, y+16, x+15, y+64, oSolid, 0, 0)
603         {
604           if randRoom(1, ceil(60.0/global.trapMult)) == 1 MakeMapObject(x, y+16, 'oThwompTrap');
605         }
606         */
608         if (type != "Altar") scrTreasureGen();
609       }
610     }
612     // force generate tomb lord
613     if (global.currLevel == 13 && global.genTombLord && !global.TombLord) {
614       if (findAnyObjectOfType('oExit')) {
615         obj = MakeMapObject(oExit.x, oExit.y-16, 'oTombLord');
616         global.totalTombLords += 1;
617         obj.hasSceptre = true;
618         global.gaveSceptre = true;
619       }
620     }
622     // force generate gold door
623     if (global.genGoldEntrance && !global.madeGoldEntrance) {
624       with (oSolid) {
625         if (y > 32 && !collision_point(x, y-16, oSolid, 0, 0)) {
626           MakeMapObject(x, y-16, 'oGoldDoor');
627           invincible = true;
628           global.madeGoldEntrance = true;
629           break;
630         }
631       }
632     }
634     with (oBlock) {
635       cleanDeath = true;
636       if (!isInShop(x, y)) {
637         n = point_distance(x, y, oEntrance.x, oEntrance.y);
638         if (!isInShop(x, y) &&
639             global.randRoom(1, ceil(3.0/global.trapMult)) == 1 && !(y == oEntrance.y && n < 144) &&
640             n > 48)
641         {
642           if (collision_point(x+16, y, oSolid, 0, 0) && !collision_rectangle(x-32, y, x-1, y+15, oSolid, 0, 0))
643           {
644             if (global.darkLevel) MakeMapObject(x, y, 'oArrowTrapLeftLit'); else MakeMapObject(x, y, 'oArrowTrapLeft');
645             cleanDeath = true;
646             instance_destroy();
647           } else if (collision_point(x-16, y, oSolid, 0, 0) && !collision_rectangle(x+16, y, x+48, y+15, oSolid, 0, 0))
648           {
649             if (global.darkLevel) MakeMapObject(x, y, 'oArrowTrapRightLit'); else MakeMapObject(x, y, 'oArrowTrapRight');
650             cleanDeath = true;
651             instance_destroy();
652           }
653         }
654       }
655     }
657     if (global.trapMult >= 2) {
658       with (oTemple) {
659         if (!isInShop(x, y)) {
660           n = point_distance(x, y, oEntrance.x, oEntrance.y);
661           if (!isInShop(x, y) &&
662               global.randRoom(1, ceil(60.0/global.trapMult)) == 1 &&
663               x >= 16 && x < room_width -16 && !(y == oEntrance.y && n < 144) &&
664               n > 48)
665           {
666             if (collision_point(x+16, y, oSolid, 0, 0) && !collision_rectangle(x-32, y, x-1, y+15, oSolid, 0, 0))
667             {
668               if (global.darkLevel) MakeMapObject(x, y, 'oArrowTrapLeftLit'); else MakeMapObject(x, y, 'oArrowTrapLeft');
669               cleanDeath = true;
670               instance_destroy();
671             } else if (collision_point(x-16, y, oSolid, 0, 0) && !collision_rectangle(x+16, y, x+48, y+15, oSolid, 0, 0))
672             {
673               if (global.darkLevel) MakeMapObject(x, y, 'oArrowTrapRightLit'); else MakeMapObject(x, y, 'oArrowTrapRight');
674               cleanDeath = true;
675               instance_destroy();
676             }
677           }
678         }
679       }
680     }
681     +/
682   }
684   // add box of flares to dark level
685   /+
686   if (global.darkLevel) {
687     with (oEntrance) {
688            if (!collision_point(x-16, y, oSolid, 0, 0)) MakeMapObject(x-16+8, y+8, 'oFlareCrate');
689       else if (!collision_point(x+16, y, oSolid, 0, 0)) MakeMapObject(x+16+8, y+8, 'oFlareCrate');
690       else MakeMapObject(x+8, y+8, 'oFlareCrate');
691     }
692   }
693   +/
695   //k8: this is hack in the original, so destroyed tiles won't generate treasure
696   //global.cleanSolids = false;