1 /**********************************************************************************
2 * Copyright (c) 2008, 2009 Derek Yu and Mossmouth, LLC
3 * Copyright (c) 2018, Ketmar Dark
5 * This file is part of Spelunky.
7 * You can redistribute and/or modify Spelunky, including its source code, under
8 * the terms of the Spelunky User License.
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.
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/>
17 **********************************************************************************/
18 // ////////////////////////////////////////////////////////////////////////// //
19 void scrLevGenShopkeeper (int xpos, int ypos, name shopType) {
20 auto obj = MonsterShopkeeper(MakeMapObject(xpos, ypos, 'oShopkeeper'));
22 //if (shopType == 'Ankh') writeln("::: ", shopType, " :::");
24 if (shopType == 'Craps') obj.generatePrizes();
29 // ////////////////////////////////////////////////////////////////////////// //
36 MapObject scrGenerateItem (int objx, int objy, GenItemSet 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');
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');
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;
83 if (global.isTunnelMan) obj = MakeMapObject(objx, objy, 'oRopePile');
84 else obj = MakeMapObject(objx, objy, 'oMattock');
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;
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') {
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');
122 } else if (global.config.optSGAmmo && global.randRoom(1, 10) == 1) {
123 obj = MakeMapObject(xpos+4, ypos+10, 'oShells');
126 if (global.config.optSGAmmo && findAnyObjectOfType('oShotgun')) {
127 obj = MakeMapObject(xpos+4, ypos+10, 'oShells');
129 obj = MakeMapObject(xpos+8, ypos+10, 'oBombBag');
134 } else if (shopType == 'Weapon') {
137 int n = global.randRoom(1, 4);
139 obj = MakeMapObject(xpos+8, ypos+10, 'oBombBag');
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');
149 if (!findAnyObjectOfType('oPistol')) { obj = MakeMapObject(xpos+8, ypos+12, 'oPistol'); break; }
151 if (!findAnyObjectOfType('oMachete')) { obj = MakeMapObject(xpos+8, ypos+12, 'oMachete'); break; }
153 if (global.config.optSGAmmo && findAnyObjectOfType('oShotgun')) {
154 obj = MakeMapObject(xpos+4, ypos+10, 'oShells');
156 obj = MakeMapObject(xpos+8, ypos+10, 'oBombBag');
160 if (!findAnyObjectOfType('oBow')) { obj = MakeMapObject(xpos+8, ypos+12, 'oBow'); break; }
164 } else if (shopType == 'Clothing') {
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; } }
177 } else if (shopType == 'Rare') {
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; } }
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; } }
202 if (global.config.optSGAmmo && findAnyObjectOfType('oShotgun')) {
203 obj = MakeMapObject(xpos+4, ypos+10, 'oShells');
205 obj = MakeMapObject(xpos+8, ypos+10, 'oBombBag');
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; }
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)+".";
230 // ////////////////////////////////////////////////////////////////////////// //
231 //WARNING: keep this in sync with `ItemJar::onDestroy()`!
232 name scrLevGenCreateJarContents () {
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';
247 switch (global.randRoom(0, 2)) {
248 case 0: ctx = 'oEmeraldBig'; break;
249 case 1: ctx = 'oSapphireBig'; break;
250 case 2: ctx = 'oRubyBig'; break;
258 final MapObject scrLevGenCreateJar (int x, int y) {
259 auto obj = MakeMapObject(x, y, 'oJar');
260 MapItem(obj).contents = scrLevGenCreateJarContents();
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) {
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;
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);
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; }
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)))
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");
314 global.lockedChestChance -= 1;
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');
328 MakeMapObject(x, y-16, 'oBones');
329 MakeMapObject(x+12, y-4, 'oSkull');
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
339 else if (!colStuff && isSolidAtPoint(x-16, y-16) && isSolidAtPoint(x+16, y-16)) {
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');
349 MakeMapObject(x, y-16, 'oBones');
350 MakeMapObject(x+12, y-4, 'oSkull');
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
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))
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');
368 MakeMapObject(x, y-16, 'oBones');
369 MakeMapObject(x+12, y-4, 'oSkull');
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';
384 if (totdeath789 < 32) {
385 if (global.randOther(0, 100) >= 85-(global.currLevel-4)*8) return 'oGreenFrog';
388 if (totdeath789 < 42) {
389 if (global.randOther(0, 100) >= 75-(global.currLevel-4)*8) return 'oGreenFrog';
392 if (totdeath789 < 52) {
393 if (global.randOther(0, 100) >= 65-(global.currLevel-4)*8) return 'oGreenFrog';
396 if (totdeath789 < 62) {
397 if (global.randOther(0, 100) >= 55-(global.currLevel-4)*8) return 'oGreenFrog';
400 if (global.randOther(0, 100) >= 50-(global.currLevel-4)*8) return 'oGreenFrog';
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);
414 tileXY2roomXY(tileX, tileY-1, roomX, roomY); //k8: why -1?
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))
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*/))
425 MakeMapObject(tileX*16, (tileY+1)*16, 'oGiantSpiderHang');
426 global.giantSpider = true;
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());
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;
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');
448 // `false` means "continue"
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)
468 if (!isInShop(x, y)) {
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))
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');
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 &&
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');
496 if (type != "Altar") scrTreasureGen();
500 } else if (global.levelType == 3) {
501 // level type 3 (temple)
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;
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)) {
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');
524 global.madeGoldEntrance = true;
526 global.goldChance -= 1;
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) &&
536 x != 160 && x != 176 && x != 320 && x != 336 && x != 480 && x != 496)
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))
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(); }
549 MakeMapObject(x, y, 'oSpearTrapBottom');
550 if (global.darkLevel) MakeMapObject(x, y-16, 'oSpearTrapLit');
551 else MakeMapObject(x, y-16, 'oSpearTrapTop');
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))
563 if (global.darkLevel && global.randRoom(1, 40) == 1) MakeMapObject(x, y+16, 'oScarab');
566 if (scrGetRoomX(x) != global.startRoomX || scrGetRoomY(y-16) != global.startRoomY &&
567 !collision_point(x, y-16, oEnemy, 0, 0))
569 if (y > 16 && !collision_point(x, y-16, oSolid, 0, 0)) {
570 if (global.genTombLord &&
572 !collision_rectangle(x, y-32, x+32, y-1, oSolid, 0, 0) &&
573 global.randRoom(1, ceil(40.0/global.config.enemyMult)) == 1)
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;
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;
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');
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)
604 if randRoom(1, ceil(60.0/global.trapMult)) == 1 MakeMapObject(x, y+16, 'oThwompTrap');
608 if (type != "Altar") scrTreasureGen();
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;
622 // force generate gold door
623 if (global.genGoldEntrance && !global.madeGoldEntrance) {
625 if (y > 32 && !collision_point(x, y-16, oSolid, 0, 0)) {
626 MakeMapObject(x, y-16, 'oGoldDoor');
628 global.madeGoldEntrance = 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) &&
642 if (collision_point(x+16, y, oSolid, 0, 0) && !collision_rectangle(x-32, y, x-1, y+15, oSolid, 0, 0))
644 if (global.darkLevel) MakeMapObject(x, y, 'oArrowTrapLeftLit'); else MakeMapObject(x, y, 'oArrowTrapLeft');
647 } else if (collision_point(x-16, y, oSolid, 0, 0) && !collision_rectangle(x+16, y, x+48, y+15, oSolid, 0, 0))
649 if (global.darkLevel) MakeMapObject(x, y, 'oArrowTrapRightLit'); else MakeMapObject(x, y, 'oArrowTrapRight');
657 if (global.trapMult >= 2) {
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) &&
666 if (collision_point(x+16, y, oSolid, 0, 0) && !collision_rectangle(x-32, y, x-1, y+15, oSolid, 0, 0))
668 if (global.darkLevel) MakeMapObject(x, y, 'oArrowTrapLeftLit'); else MakeMapObject(x, y, 'oArrowTrapLeft');
671 } else if (collision_point(x-16, y, oSolid, 0, 0) && !collision_rectangle(x+16, y, x+48, y+15, oSolid, 0, 0))
673 if (global.darkLevel) MakeMapObject(x, y, 'oArrowTrapRightLit'); else MakeMapObject(x, y, 'oArrowTrapRight');
684 // add box of flares to dark level
686 if (global.darkLevel) {
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');
695 //k8: this is hack in the original, so destroyed tiles won't generate treasure
696 //global.cleanSolids = false;