fixed alot of warnings, and some bugs, so it can be compiled with the current vccrun
[k8vacspelynky.git] / mapent / enemies / giantspider.vc
blobf439ba140d9ee4287f8c4e3527394579040937ab
1 /**********************************************************************************
2  * Copyright (c) 2008, 2009 Derek Yu and Mossmouth, LLC
3  * Copyright (c) 2010, Moloch
4  * Copyright (c) 2018, Ketmar Dark
5  *
6  * This file is part of Spelunky.
7  *
8  * You can redistribute and/or modify Spelunky, including its source code, under
9  * the terms of the Spelunky User License.
10  *
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.
13  *
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/>
17  *
18  **********************************************************************************/
19 // ////////////////////////////////////////////////////////////////////////// //
20 class EnemyGiantSpiderHang['oGiantSpiderHang'] : MapEnemy;
22 bool pasteless;
23 bool createWeb = true;
25 //int whipped;
26 int squirtTimer;
28 //int bounceCounter;
29 int alarm0Left;
32 void initNonHang () {
33   setSprite('sGiantSpider');
34   status = IDLE;
35   setCollisionBounds(2, 16, 30, 32);
36   xVel = 0;
37   yVel = 0;
38   yDelta = -0.4;
39   myGrav = 0.3;
40   myGravNorm = 0.3;
41   imageSpeed = 0.8;
42   whipTimer = 10;
43   whipTimerValue = 10;
44   squirtTimer = global.randOther(100, 500);
45   flying = false;
49 override bool initialize () {
50   if (!::initialize()) return false;
51   writeln("*** GIANT SPIDER GENERATED");
52   setSprite('sGiantSpiderHang');
53   if (createWeb) {
54     level.MakeMapObject(ix, iy+16, 'oWeb');
55     level.MakeMapObject(ix+16, iy+16, 'oWeb');
56   }
57   return true;
61 override void onAnimationLooped () {
62   if (spriteLName == 'sGiantSpiderFlip') {
63     setSprite('sGiantSpider');
64     imageSpeed = 0.4;
65   } else if (spriteLName == 'sGiantSpiderSquirt') {
66     status = IDLE;
67     imageSpeed = 0.4;
68   }
72 override bool onInsideBlock (MapTile block) {
73   // if we are inside a block, die
74   if (hp < 1) return false;
75   hp = 0;
76   return false;
80 override bool onTouchedByPlayer (PlayerPawn plr) {
81   if (plr.dead || dead) return false;
83   // jumped on - oCaveman, oManTrap replaces this script with its own
84   if (abs(plr.ix-(ix+16)) > 16) {
85     // do nothing
86   } else if ((plr.status == JUMPING || plr.status == FALLING) && plr.iy < iy+16 && !plr.swimming) {
87     writeln("touched by player!");
88     plr.yVel = -6-0.2*plr.yVel;
89     if (global.hasSpikeShoes) {
90       hp -= trunci(3*(ffloor(plr.fallTimer/16.0)+1));
91       spillBlood(amount:2);
92     } else {
93       hp -= trunci(1*(ffloor(plr.fallTimer/16.0)+1));
94       spillBlood(amount:1);
95     }
96     plr.fallTimer = 0;
97     plr.playSound('sndHit');
98   } else if (plr.invincible == 0) {
99     plr.blink = 30;
100     plr.invincible = 30;
101     if (plr.iy < iy) plr.yVel = -6;
102     plr.xVel = (plr.ix < ix ? -6 : 6);
103     if (global.plife > 0) {
104       global.plife -= damage;
105       if (global.plife <= 0 /*and isRealLevel()*/) level.addDeath(objName);
106     }
107     plr.playSound('sndHurt');
108   }
110   return false; // don't skip thinker
114 // return `false` to do standard weapon processing
115 override bool onTouchedByPlayerWeapon (PlayerPawn plr, PlayerWeapon wpn) {
116   if (wpn !isa WeaponWhip) return false;
117   if (hp > 0 && !dead && !stunned && status < STUNNED) wpn.hitEnemy = true;
119   if (invincible <= 0) {
120     hp -= wpn.damage;
121     spillBlood(amount:1);
122     plr.playSound('sndHit');
123   }
125   return true;
129 void createPaste () {
130   if (!pasteless) {
131     pasteless = true;
132     /*auto obj =*/ level.MakeMapObject(ix+16, iy+24, 'oPaste');
133   }
137 void onDead () {
138   createPaste();
139   spillBlood(amount:4);
140   if (countsAsKill) level.addKill(objName);
141   //!!!with (oBossBlock) dying = true;
142   foreach (; 0..global.randOther(1, 3)) {
143     MapObject gem = none;
144     switch (global.randOther(1, 3)) {
145       case 1: gem = level.MakeMapObject(ix+16, iy+24, 'oEmeraldBig'); break;
146       case 2: gem = level.MakeMapObject(ix+16, iy+24, 'oSapphireBig'); break;
147       case 3: gem = level.MakeMapObject(ix+16, iy+24, 'oRubyBig'); break;
148     }
149     if (gem) {
150       gem.xVel = global.randOther(0, 3)-global.randOther(0, 3);
151       gem.yVel = -2;
152     }
153   }
154   instanceRemove();
158 override bool onHitByItem (MapItem item) {
159   // item does no damage?
160   if (!item.damage) return false;
162   if (status == HANG) {
163     initNonHang();
164     setSprite('sGiantSpiderFlip');
165     playSound('sndGiantSpider');
166   }
168   return ::onHitByItem(item);
172 override void thinkFrame () {
173   ::thinkFrame();
174   if (!isInstanceAlive) return;
176   if (status == HANG) {
177     int x = ix, y = iy;
179     if (level.isSolidAtPoint(x+16, y+8)) hp = 0;
180     if (hp < 1) { onDead(); return; }
182     if (hp < 10 || !level.isSolidAtPoint(x, y-16) ||
183         (level.player.iy > y && abs(level.player.ix-(x+16)) < 8 && distanceToEntityCenter(level.player) < 90) ||
184         level.isObjectInRect(x0, y0, width, height, delegate bool (MapObject o) { return (o isa ItemBomb); }, castClass:ItemBomb))
185     {
186       initNonHang();
187       setSprite('sGiantSpiderFlip');
188       playSound('sndGiantSpider');
189     }
190   }
192   if (status != HANG) {
193     // bounce timer
194     if (alarm0Left > 0) {
195       if (--alarm0Left == 0) {
196         if (spriteLName != 'sGiantSpiderSquirt') {
197           status = BOUNCE;
198           if (isCollisionBottom(1)) {
199             setSprite('sGiantSpider'); //k8:???
200             yVel = -global.randOther(2, 5);
201             xVel = (level.player.ix < ix+16 ? -2.5 : 2.5);
202           } else {
203             setSprite('sGiantSpiderJump');
204           }
205         }
206       }
207     }
209     /*
210     if (level.isSolidAtPoint(ix+16, iy+24)) {
211       writeln("solid kill");
212       hp = 0;
213     }
214     */
216     /*
217     if (isCollision()) {
218       writeln("solid kill");
219       hp = 0;
220     }
221     */
223     moveRel(xVel, yVel);
224     int x = ix, y = iy;
226     yVel = fmin(yVelLimit, yVel+myGrav);
228     if (hp < 1) {
229       onDead();
230       return;
231     }
233     if (isCollisionRight(1)) xVel = 1;
234     if (isCollisionLeft(1)) xVel = -1;
236     if (status != CRAWL && isCollisionTop(1) && isCollisionBottom(1)) {
237       status = CRAWL;
238       xVel = (level.player.ix < x+16 ? -1 : 1);
239     }
241     if (squirtTimer > 0) squirtTimer -= 1;
243     if (status == IDLE) {
244       if (spriteLName != 'sGiantSpiderFlip') setSprite('sGiantSpider');
245       alarm0Left = global.randOther(5, 20);
246       status = (squirtTimer == 0 ? SQUIRT : RECOVER);
247     } else if (status == CRAWL) {
248       setSprite('sGiantSpiderCrawl');
249            if (!isCollisionTop(1) || !isCollisionBottom(1)) status = IDLE;
250       else if (isCollisionRight(1)) xVel = -1;
251       else if (isCollisionLeft(1)) xVel = 1;
252     } else if (status == SQUIRT) {
253       setSprite('sGiantSpiderSquirt');
254       if (imageFrame >= 5 && squirtTimer == 0) {
255         level.MakeMapObject(x+16, y+16, 'oWebBall');
256         squirtTimer = (global.config.bizarre ? global.randOther(100, 500) : global.randOther(100, 1000));
257       }
258     } else if (status == RECOVER) {
259       if (isCollisionBottom(1)) xVel = 0;
260     } else if (status == BOUNCE && distanceToEntityCenter(level.player) < 120) {
261       if (isCollisionBottom(1)) {
262         setSprite('sGiantSpider');
263         yVel = -global.randOther(3, 6);
264         xVel = (level.player.ix < x+16 ? -2.5 : 2.5);
265         playSound('sndSpiderJump');
266         if (global.randOther(1, 4) == 1) { status = IDLE; xVel = 0; yVel = 0; }
267       } else {
268         setSprite('sGiantSpiderJump');
269       }
270     } else if (status != DROWNED) {
271       status = IDLE;
272       //xVel = 0;
273     }
275     if (isCollisionTop(1)) yVel = 1;
276     //if (isCollisionLeft(1) or isCollisionRight(1)) xVel = -xVel; // in the original
277     //if (isCollisionSolid()) y -= 2; // in the original
278   }
282 defaultproperties {
283   objName = 'Giant Spider';
285   desc = "Giant Spider";
286   desc2 = "An overgrown spider with the ability to launch a sticky web at its prey.";
288   setCollisionBounds(0, 0, 32, 16);
289   xVel = 0;
290   yVel = 0;
291   yDelta = -0.4;
292   imageSpeed = 0.4;
294   // stats
295   hp = 10; //k8: 1 for non-hanging giant spider; wtf?!
296   invincible = 0;
297   pasteless = false;
299   //invincible = 0;
300   whipTimer = 10;
301   whipTimerValue = 10;
302   //squirtTimer = rand(100, 500);
303   damage = 2;
305   // status
306   /*
307   IDLE = 0;
308   BOUNCE = 1;
309   RECOVER = 2;
310   WALK = 3;
311   */
313   status = HANG;
314   //bounceCounter = 0;
316   doBasicPhysics = false;
317   leavesBody = true; // we'll do our own low hp processing
319   bloodOfsX = 16;
320   bloodOfsY = 24;
322   //shakeCounter = 0;
323   //shakeToggle = 1;
327 // ////////////////////////////////////////////////////////////////////////// //
328 class EnemyGiantSpider['oGiantSpider'] : EnemyGiantSpiderHang;
331 override bool initialize () {
332   if (!::initialize()) return false;
333   initNonHang();
334   return true;