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 // recoded by Ketmar // Invisible Vector
20 class PlayerPowerup : Object abstract;
24 int renderPriority; // from lower to higher
25 bool lostOnDeath = true;
27 bool prePreDucking; // for cape
30 // called when the player get it for the first time
37 // called when the player lost it (for some reason)
38 bool onDeactivate (optional bool forced) {
44 void onPlayerDied () {
45 onDeactivate(forced:true);
57 void prePreDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
61 void preDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
65 void postDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
69 void lastDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
73 // ////////////////////////////////////////////////////////////////////////// //
74 class PPCape : PlayerPowerup;
83 // called when the player get it for the first time
84 override bool onActivate () {
85 owner.global.hasCape = true;
93 // called when the player lost it (for some reason)
94 override bool onDeactivate (optional bool forced) {
95 owner.global.hasCape = false;
103 override void onPostThink () {
104 visible = (owner.status != MapObject::DUCKTOHANG);
106 if (!owner.whipping && (owner.status == MapObject::CLIMBING || owner.isExitingSprite())) {
109 sprName = 'sCapeBack';
112 } else if (owner.dir == MapObject::Dir.Right) {
114 dy = (owner.status == MapObject::DUCKING || owner.stunned ? 2 : -2);
115 if (open) sprName = 'sCapeUR';
116 else if (fabs(owner.xVel) > 0.4 && owner.status != MapObject::DUCKING) sprName = 'sCapeRight';
117 else sprName = 'sCapeDR';
119 beforePlayer = false;
123 dy = (owner.status == MapObject::DUCKING || owner.stunned ? 2 : -2);
124 if (open) sprName = 'sCapeUL';
125 else if (fabs(owner.xVel) > 0.4 && owner.status != MapObject::DUCKING) sprName = 'sCapeLeft';
126 else sprName = 'sCapeDL';
128 beforePlayer = false;
131 //writeln("CAPE: '", sprName, "'; before=", beforePlayer);
135 final void doDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
136 if (!sprName) return;
138 auto spr = owner.level.sprStore[sprName];
139 if (!spr || spr.frames.length < 1) return;
140 auto spf = spr.frames[0];
141 if (!spf || spf.width < 1 || spf.height < 1) return;
144 owner.getInterpCoords(currFrameDelta, scale, out xi, out yi);
149 xi -= spf.xofs*scale;
150 yi -= spf.yofs*scale;
152 spf.blitAt(xi-xpos, yi-ypos, scale);
156 override void prePreDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
157 if (!visible || owner.status != MapObject::DUCKING) return;
158 doDrawWithOfs(xpos, ypos, scale, currFrameDelta);
162 override void preDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
163 if (!visible || beforePlayer || owner.status == MapObject::DUCKING) return;
164 doDrawWithOfs(xpos, ypos, scale, currFrameDelta);
168 override void lastDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
169 if (!visible || !beforePlayer) return;
170 doDrawWithOfs(xpos, ypos, scale, currFrameDelta);
176 renderPriority = 1010; // behind the bricks
177 sprName = 'sCapeRight';
181 // ////////////////////////////////////////////////////////////////////////// //
182 class PPParachute : PlayerPowerup;
189 // called when the player get it for the first time
190 override bool onActivate () {
198 // called when the player lost it (for some reason)
199 override bool onDeactivate (optional bool forced) {
205 override void onPostThink () {
207 auto spr = owner.level.sprStore['sParaOpen'];
209 if (imageFrame >= spr.frames.length) {
219 final void doDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
220 auto spr = owner.level.sprStore[opening ? 'sParaOpen' : 'sParachute'];
221 if (!spr || spr.frames.length < 1) return;
222 auto spf = spr.frames[imageFrame];
223 if (!spf || spf.width < 1 || spf.height < 1) return;
226 owner.getInterpCoords(currFrameDelta, scale, out xi, out yi);
231 xi -= spf.xofs*scale;
232 yi -= spf.yofs*scale;
234 spf.blitAt(xi-xpos, yi-ypos, scale);
238 override void preDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
239 doDrawWithOfs(xpos, ypos, scale, currFrameDelta);
245 renderPriority = 1010; // behind the bricks