fixed alot of warnings, and some bugs, so it can be compiled with the current vccrun
[k8vacspelynky.git] / mapent / ghost / ghost.vc
blob378d9ec04e9c49167e94bf44e5375e957a358006
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 class ObjGhost['oGhost'] : MapObject;
22 override bool initialize () {
23   if (!::initialize()) return false;
24   //setSprite('sGhostLeft', 'sGhostRight');
25   setSprite('sGhostRight');
26   playSound('sndGhost');
27   return true;
31 override void getLightOffset (out int lxofs, out int lyofs) {
32   lxofs = 24/2;
33   lyofs = 24/2;
37 override void onAnimationLooped () {
38   auto spr = getSprite();
39        if (spr.Name == 'sGhostTurnRight') setSprite('sGhostRight');
40   else if (spr.Name == 'sGhostTurnLeft') setSprite('sGhostLeft');
41   else if (spr.Name == 'sGhostDisappear') instanceRemove();
45 // for dead players too
46 // first, the code will call `onObjectTouched()` for player
47 // if it returned `false`, the code will call this handler
48 // note that player's handler is called *after* its frame thinker,
49 // but object handler is called *before* frame thinker for the object
50 // return `true` to skip thinker on this frame
51 override bool onTouchedByPlayer (PlayerPawn plr) {
52   if (plr.dead) return false;
53   if (plr.invincible != 0) return false;
55   //!if (isRealLevel()) global.enemyDeaths[23] += 1;
56   foreach (; 0..3) level.MakeMapObject(plr.ix, plr.iy, 'oBone');
57   auto skull = level.MakeMapObject(plr.ix, plr.iy-2, 'oSkull');
58   if (skull) {
59     if (skull isa ItemThrowable) ItemThrowable(skull).breaksOnCollision = false;
60     skull.yVel = -global.randOther(1, 3);
61     skull.xVel = global.randOther(0, 3)-global.randOther(0, 3);
62   }
64   plr.dead = true;
65   plr.visible = false;
66   plr.invincible = 9999;
67   plr.bounced = true;
68   global.plife = -99;
69   playSound('sndDie');
71   if (global.plife <= 0 /*and isRealLevel()*/) level.addDeath(objName);
73   plr.removeActivatedPlayerWeapon();
74   plr.scrDropItem(LostCause.Throw, (plr.dir == Dir.Left ? -2 : 2), -4);
75   /*
76   auto it = plr.holdItem;
77   if (it) {
78     plr.holdItem = none;
79     it.xVel = (plr.dir == Dir.Left ? -2 : 2);
80     it.yVel = -4;
81   }
82   */
84   status = IDLE;
85   imageSpeed = 0.2;
86   setSprite('sGhostDisappear');
87   playSound('sndGhost');
89   // she should disappear after she kills you
90   instanceRemove();
92   return false;
96 transient array!MapObject gemsToConvert;
99 override void thinkFrame () {
100   if (hp < 1) {
101     if (countsAsKill) level.addKill(objName);
102     instanceRemove();
103     return;
104   }
106   if (status == IDLE) {
107     // do nothing
108   } else if (status == ATTACK) {
109     //auto dist = pointDistance(ix+8, iy+8, level.player.ix, level.player.iy);
110     float dir = pointDirection(ix+8, iy+8, level.player.ix, level.player.iy);
111     fltx +=  cos(dir);
112     flty += -sin(dir);
113     auto spr = getSprite();
114     if (level.player.ix < ix+8) {
115       if (spr.Name == 'sGhostRight') setSprite('sGhostTurnLeft');
116     } else {
117       if (spr.Name == 'sGhostLeft') setSprite('sGhostTurnRight');
118     }
119   }
121   // convert gems
122   gemsToConvert.clear();
123   level.isObjectInRect(x0, y0, width, height, delegate bool (MapObject o) {
124     if (o isa ItemBigGem && o.isInstanceAlive) gemsToConvert[$] = o;
125     return false;
126   });
128   foreach (MapObject g; gemsToConvert) {
129     /*auto diamond =*/ level.MakeMapObject(g.ix, g.iy, 'oDiamond');
130     g.instanceRemove();
131   }
132   gemsToConvert.clear();
134   // convert gems inside tiles
135   level.checkTilesInRect(x0, y0, width, height, delegate bool (MapTile t) {
136     t.convertGemObjectToDiamond(self);
137     return false;
138   });
142 defaultproperties {
143   objName = 'Ghost';
145   desc = "Ghost";
146   desc2 = "These apparitions haunt the ruins of ancient civilizations and burial grounds, hunting down intruders and ending their life with a single touch. There is no weapon that can harm their insubstantial bodies.";
147   setCollisionBounds(4, 0, 12, 16);
149   imageSpeed = 0.5;
150   //origX = 0;
151   //origY = 0;
152   xVel = 0;
153   yVel = 0;
154   xAcc = 0.2;
155   yAcc = 0.2;
157   // stats
158   hp = 1;
159   invincible = 1;
161   imageAlpha = 0.6; //255-int(0.6*255);
163   // status
164   /*
165   IDLE = 0;
166   ATTACK = 1;
167   */
169   status = ATTACK;
170   dir = Dir.Right;
172   depth = 0;
174   countsAsKill = true;
175   disableMirror = true;
176   lightRadius = 49;
177   canLiveOutsideOfLevel = true;