option to spawn ghost on the first level
[k8vacspelynky.git] / PlayerPowerup.vc
blob2629a4e45b66817f660f13d578b6217632c73375
1 /**********************************************************************************
2  * Copyright (c) 2008, 2009 Derek Yu and Mossmouth, LLC
3  * Copyright (c) 2018, Ketmar Dark
4  *
5  * This file is part of Spelunky.
6  *
7  * You can redistribute and/or modify Spelunky, including its source code, under
8  * the terms of the Spelunky User License.
9  *
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.
12  *
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/>
16  *
17  **********************************************************************************/
18 // recoded by Ketmar // Invisible Vector
19 class PlayerPowerup : Object abstract;
21 name id;
22 PlayerPawn owner;
23 int renderPriority; // from lower to higher
24 bool lostOnDeath = true;
25 bool active;
28 // called when the player get it for the first time
29 bool onActivate () {
30   active = true;
31   return true;
35 // called when the player lost it (for some reason)
36 bool onDeactivate (optional bool forced) {
37   active = false;
38   return true;
42 void onPlayerDied () {
43   onDeactivate(forced:true);
47 void onPreThink () {
51 void onPostThink () {
55 void preDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
59 void postDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
63 void lastDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
67 // ////////////////////////////////////////////////////////////////////////// //
68 class PPCape : PlayerPowerup;
70 bool visible;
71 int dx, dy;
72 name sprName;
73 bool beforePlayer;
74 bool open;
77 // called when the player get it for the first time
78 override bool onActivate () {
79   owner.global.hasCape = true;
80   visible = true;
81   active = true;
82   //open = false;
83   return true;
87 // called when the player lost it (for some reason)
88 override bool onDeactivate (optional bool forced) {
89   owner.global.hasCape = false;
90   visible = false;
91   active = false;
92   open = false;
93   return true;
97 override void onPostThink () {
98   visible = (owner.status != MapObject::DUCKTOHANG);
100   /*
101   if (instance_exists(oTransition) && !instance_exists(oPDummy))
102   {
103       instance_destroy();
104   }
105   */
107   /*
108   else if (instance_exists(oPDummy))
109   {
110       if (oPDummy.sprite_index == sPExit || oPDummy.sprite_index == sDamselExit || oPDummy.sprite_index == sTunnelExit)
111       {
112           x = oPDummy.x;
113           y = oPDummy.y+4;
114           sprite_index = sCapeBack;
115           depth = 0;
116       }
117       else
118       {
119           x = oPDummy.x - 4;
120           y = oPDummy.y - 2;
121           if (oPDummy.sprite_index == sRunLeft || oPDummy.sprite_index == sDamselRunL || oPDummy.sprite_index == sTunnelRunL) sprite_index = sCapeRight;
122           else sprite_index = sCapeDR;
123           depth = 100;
124       }
125   }
126   */
128   if (!owner.whipping && (owner.status == MapObject::CLIMBING || owner.isExitingSprite())) {
129     dx = 0;
130     dy = 4;
131     sprName = 'sCapeBack';
132     //depth = 0;
133     beforePlayer = true;
134   }
135   else if (owner.dir == MapObject::Dir.Right) {
136     dx = -4;
137     dy = (owner.status == MapObject::DUCKING || owner.stunned ? 2 : -2);
138          if (open) sprName = 'sCapeUR';
139     else if (fabs(owner.xVel) > 0 && owner.status != MapObject::DUCKING) sprName = 'sCapeRight';
140     else sprName = 'sCapeDR';
141     //depth = 111;
142     beforePlayer = false;
143   } else {
144     // left
145     dx = 4;
146     dy = (owner.status == MapObject::DUCKING || owner.stunned ? 2 : -2);
147          if (open) sprName = 'sCapeUL';
148     else if (fabs(owner.xVel) > 0 && owner.status != MapObject::DUCKING) sprName = 'sCapeLeft';
149     else sprName = 'sCapeDL';
150     //depth = 111;
151     beforePlayer = false;
152   }
154   //writeln("CAPE: '", sprName, "'; before=", beforePlayer);
158 final void doDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
159   if (!sprName) return;
161   auto spr = owner.level.sprStore[sprName];
162   if (!spr || spr.frames.length < 1) return;
163   auto spf = spr.frames[0];
164   if (!spf || spf.width < 1 || spf.height < 1) return;
166   int xi, yi;
167   owner.getInterpCoords(currFrameDelta, scale, out xi, out yi);
169   xi += dx*scale;
170   yi += dy*scale;
172   xi -= spf.xofs*scale;
173   yi -= spf.yofs*scale;
175   spf.tex.blitAt(xi-xpos, yi-ypos, scale);
179 override void preDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
180   if (!visible || beforePlayer) return;
181   doDrawWithOfs(xpos, ypos, scale, currFrameDelta);
185 override void lastDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
186   if (!visible || !beforePlayer) return;
187   doDrawWithOfs(xpos, ypos, scale, currFrameDelta);
191 defaultproperties {
192   id = 'Cape';
193   renderPriority = 100;
194   sprName = 'sCapeRight';
198 // ////////////////////////////////////////////////////////////////////////// //
199 class PPParachute : PlayerPowerup;
201 const int dx = -8;
202 const int dy = -16;
203 int imageFrame = 0;
204 bool opening;
206 // called when the player get it for the first time
207 override bool onActivate () {
208   active = true;
209   opening = true;
210   imageFrame = 0;
211   return true;
215 // called when the player lost it (for some reason)
216 override bool onDeactivate (optional bool forced) {
217   active = false;
218   return true;
222 override void onPostThink () {
223   if (opening) {
224     auto spr = owner.level.sprStore['sParaOpen'];
225     ++imageFrame;
226     if (imageFrame >= spr.frames.length) {
227       opening = false;
228       imageFrame = 0;
229     }
230   } else {
231     imageFrame = 0;
232   }
236 final void doDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
237   auto spr = owner.level.sprStore[opening ? 'sParaOpen' : 'sParachute'];
238   if (!spr || spr.frames.length < 1) return;
239   auto spf = spr.frames[imageFrame];
240   if (!spf || spf.width < 1 || spf.height < 1) return;
242   int xi, yi;
243   owner.getInterpCoords(currFrameDelta, scale, out xi, out yi);
245   xi += dx*scale;
246   yi += dy*scale;
248   xi -= spf.xofs*scale;
249   yi -= spf.yofs*scale;
251   spf.tex.blitAt(xi-xpos, yi-ypos, scale);
255 override void preDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
256   doDrawWithOfs(xpos, ypos, scale, currFrameDelta);
260 defaultproperties {
261   id = 'Parachute';
262   renderPriority = 100;