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 class EnemyBlob['oBlob'] : MapEnemy;
29 override bool initialize () {
30 if (!::initialize()) return false;
31 setSprite('sBlobStand');
32 //counter = global.randOther(10, 30);
33 //value = 4000+global.levelType*2000;
38 override bool onTouchedByPlayerWeapon (PlayerPawn plr, PlayerWeapon wobj) {
41 scrCreateBloblets(xCenter, yCenter, 1);
42 plr.playSound('sndHit');
47 // for dead players too
48 // first, the code will call `onObjectTouched()` for player
49 // if it returned `false`, the code will call this handler
50 // note that player's handler is called *after* its frame thinker,
51 // but object handler is called *before* frame thinker for the object
52 // return `true` to skip thinker on this frame
53 override bool onTouchedByPlayer (PlayerPawn plr) {
54 if (plr.dead) return false;
56 // slow player down and absorb poison
59 //if collision_point(x+8, y+8, oCharacter, 0, 0)
60 if (fabs(plr.xVel) == 0 && plr.iy <= iy+8 && plr.status != CLIMBING) {
61 if (plr.ix > ix+8) plr.fltx -= 1; else if (plr.ix < ix+8) plr.fltx += 1;
70 override bool onExplosionTouch (MapObject xplo) {
71 if (invincible) return false;
73 scrCreateBloblets(xCenter, yCenter, 5);
75 if (countsAsKill) level.addKill(objName);
82 override void thinkFrame () {
84 if (!isInstanceAlive) return;
88 yVel = fmin(yVel+myGrav, yVelLimit);
90 if (level.isSolidAtPoint(ix+8, iy+8)) hp = 0;
93 scrCreateBloblets(ix+8, iy+8, global.randOther(2, 4));
94 if (countsAsKill) level.addKill(objName);
99 if (isCollisionBottom(1) && status != STUNNED) yVel = 0;
104 if (status == IDLE) {
105 setSprite('sBlobStand');
106 if (counter > 0) --counter; else { dir = global.randOther(0, 1); status = WALK; }
107 } else if (status == WALK) {
109 if (isCollisionLeft(1) or isCollisionRight(1)) {
110 if (facing == LEFT) facing = RIGHT; else facing = LEFT;
115 if (dir == Dir.Left && !level.isSolidAtPoint(x-1, y+16)) dir = Dir.Right;
116 else if (dir == Dir.Right && !level.isSolidAtPoint(x+16, y+16)) dir = Dir.Left;
118 if ((!level.isSolidAtPoint(x-1, y+16) || level.isSolidAtPoint(x-1, y)) &&
119 (!level.isSolidAtPoint(x+16, y+16) || level.isSolidAtPoint(x+16, y)))
121 dir = (level.isSolidAtPoint(x-1, y) ? Dir.Right : Dir.Left);
123 } else if (dir == Dir.Left) {
129 if (global.randOther(1, 120) == 1) {
131 counter = global.randOther(50, 100);
134 } else if (status == ATTACK) {
138 if (isCollision()) flty -= 2;
140 if (status != STUNNED) {
141 imageSpeed = (xVel == 0 ? 0.2 : 0.3);
142 setSprite('sBlobWalkL');
145 if (status == IDLE) setSprite('sBlobStand');
148 if (status != STUNNED and facing == RIGHT) {
149 if (xVel == 0) image_speed = 0.2; else image_speed = 0.4;
150 sprite_index = sSnakeWalkR;
159 desc2 = "Hardly more than an annoyance, this mass of goo feeds on decomposing matter.";
161 setCollisionBounds(2, 0, 14, 16);
178 doBasicPhysics = false;
179 flying = false; // don't fall
182 leavesBody = true; // we will do our own death sequence