1 /**********************************************************************************
2 * Copyright (c) 2008, 2009 Derek Yu and Mossmouth, LLC
3 * Copyright (c) 2010, Moloch
4 * Copyright (c) 2018, Ketmar Dark
6 * This file is part of Spelunky.
8 * You can redistribute and/or modify Spelunky, including its source code, under
9 * the terms of the Spelunky User License.
11 * Spelunky is distributed in the hope that it will be entertaining and useful,
12 * but WITHOUT WARRANTY. Please see the Spelunky User License for more details.
14 * The Spelunky User License should be available in "Game Information", which
15 * can be found in the Resource Explorer, or as an external file called COPYING.
16 * If not, please obtain a new copy of Spelunky from <http://spelunkyworld.com/>
18 **********************************************************************************/
19 // bottom: sSpearTrap2 (100)
20 // top: sSpearTrap1 (100)
21 // toplit: sSpearTrapLit (100)
22 class MapTileSpearTrapBase : MapTile abstract;
24 const int firedMax = 50;
32 override void setupTile () {
33 if (global.cityOfGold == 1) {
39 if (global.cityOfGold != 1)
41 if (smashed) scrSprayRubble(3, sRubbleTan, sRubbleTanSmall);
42 scrDropRubble(3, sRubbleTan, sRubbleTanSmall);
46 for (i = 0; i < 3; i += 1)
48 gold = instance_create(x+8+rand(0,4)-rand(0,4), y+8+rand(0,4)-rand(0,4), oGoldChunk);
49 gold.xVel = rand(0,3) - rand(0,3);
50 gold.yVel = rand(2,4) * 1;
52 gold = instance_create(x+8+rand(0,4)-rand(0,4), y+8+rand(0,4)-rand(0,4), oGoldNugget);
53 gold.xVel = rand(0,3) - rand(0,3);
54 gold.yVel = rand(2,4) * 1;
61 override void drawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
62 ::drawWithOfs(xpos, ypos, scale, currFrameDelta);
64 auto oclr = GLVideo.color;
65 GLVideo.color = 0x7f_00_ff_00;
66 GLVideo.fillRect(checkerX*scale-xpos, checkerY*scale-ypos, checkerW*scale, checkerH*scale);
73 final bool needToCheckForActivation () {
74 return (!firedLeft || !firedRight);
78 final void activateTrap (bool atLeft) {
81 level.MakeMapObject(ix-16, iy, 'oSpearsLeft');
86 level.MakeMapObject(ix+16, iy, 'oSpearsRight');
87 firedRight = firedMax;
93 // return `true` to stop checking
94 final bool checkTrapActivationSolid (MapTile obj) {
95 if (obj !isa MapTileSpearTrapBase && obj.solid && obj.moveable) {
97 if (abs(obj.iy-y) < prox && (obj.ix < x || obj.iy > x) && pointDistance(x, y, obj.ix, obj.iy) < range) {
98 activateTrap(atLeft:obj.ix < x);
100 return (firedLeft && firedRight);
106 // return `true` to stop checking
107 final bool checkTrapActivation (MapObject obj) {
108 if (firedLeft && firedRight) return true;
109 if (obj.spectral || !obj.isInstanceAlive) return false;
113 auto plr = PlayerPawn(obj);
115 if (abs(plr.iy-y-8) < prox && (plr.ix < x || plr.ix > x+8) && pointDistance(x+8, y+8, plr.ix, plr.iy) < range) {
116 activateTrap(atLeft:plr.ix < x);
118 return (firedLeft && firedRight);
121 auto enemy = MapEnemy(obj);
123 if (abs(obj.iy-y) < prox && (obj.ix < x || obj.ix > x) && pointDistance(x, y, obj.ix, obj.iy) < range) {
124 activateTrap(atLeft:obj.ix < x);
126 return (firedLeft && firedRight);
129 auto item = MapItem(obj);
131 if (item.isTreasure) return false;
132 if (abs(obj.iy-y-8) < prox && (obj.ix < x+8 || obj.ix > x+8) && pointDistance(x+8, y+8, obj.ix, obj.iy) < range) {
133 activateTrap(atLeft:obj.ix < x+8);
135 return (firedLeft && firedRight);
142 override void thinkFrame () {
143 // remove floating top part after explosion
144 if (!level.isSolidAtPoint(ix+8, iy+16+8)) {
145 //TODO: remove spears
152 if (firedLeft > 0) --firedLeft;
153 if (firedRight > 0) --firedRight;
155 if (needToCheckForActivation) checkTrapActivation(level.player);
160 if (needToCheckForActivation) {
161 level.isObjectInRect(x-range, y-range, range*2, range*2, &checkTrapActivation);
163 if (needToCheckForActivation) {
164 level.checkTilesInRect(x-range, y-range, range*2, range*2, &checkTrapActivationSolid);
168 if ((x > view_xview[0]-8 and x < view_xview[0] + view_wview[0]+8 and
169 y > view_yview[0]-8 and y < view_yview[0] + view_hview[0]+8))
171 if (not collision_point(x, y+16, oSolid, 0, 0)) instance_destroy();
179 desc2 = "A tribal trap with a set of sharp, extendable spears on each side. Should the top be destroyed, the bottom will continue to function.";
182 toSpecialGrid = true; // it need to think, so...
187 //!!!imageSpeed = 0.5; // this is for lit spear trap, it has 4 frames (not here yet)
190 rubbleSprite1 = 'sRubbleLush';
191 rubbleSprite2 = 'sRubbleLushSmall';
196 // ////////////////////////////////////////////////////////////////////////// //
197 class MapTileSpearTrapTop['oSpearTrapTop'] : MapTileSpearTrapBase;
202 override void setupTile () {
204 if (global.cityOfGold == 1) {
205 spriteName = 'sSpearTrapGold1';
206 rightSpriteName = 'sSpearsRightGold';
212 objType = 'oSpearTrap';
214 spriteName = 'sSpearTrap1';
215 rightSpriteName = 'sSpearsRight';
219 // ////////////////////////////////////////////////////////////////////////// //
220 class MapTileSpearTrapBottom['oSpearTrapBottom'] : MapTileSpearTrapBase;
223 override void setupTile () {
225 if (global.cityOfGold == 1) {
226 spriteName = 'sSpearTrapGold2';
227 rightSpriteName = 'sSpearsRightGold';
232 override void thinkFrame () {
233 if (global.darkLevel) {
234 auto upTrap = MapTileSpearTrapTop(level.checkTileAtPoint(ix, iy-16, delegate bool (MapTile t) { return (t isa MapTileSpearTrapTop); }, castClass:MapTileSpearTrapTop));
235 litWholeTile = (upTrap && upTrap.lit);
242 objType = 'oSpearTrap';
243 spriteName = 'sSpearTrap2';
244 rightSpriteName = 'sSpearsRight';
248 // ////////////////////////////////////////////////////////////////////////// //
249 class MapTileSpearTrapTopLit['oSpearTrapTopLit'] : MapTileSpearTrapTop;
253 objType = 'oSpearTrapLit';
254 spriteName = 'sSpearTrapLit';