1 /**********************************************************************************
2 * Copyright (c) 2008, 2009 Derek Yu and Mossmouth, LLC
3 * Copyright (c) 2018, Ketmar Dark
5 * This file is part of Spelunky.
7 * You can redistribute and/or modify Spelunky, including its source code, under
8 * the terms of the Spelunky User License.
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.
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/>
17 **********************************************************************************/
18 // recoded by Ketmar // Invisible Vector
19 class PlayerPowerup : Object abstract;
23 int renderPriority; // from lower to higher
24 bool lostOnDeath = true;
26 bool prePreDucking; // for cape
29 // called when the player get it for the first time
36 // called when the player lost it (for some reason)
37 bool onDeactivate (optional bool forced) {
43 void onPlayerDied () {
44 onDeactivate(forced:true);
56 void prePreDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
60 void preDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
64 void postDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
68 void lastDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
72 // ////////////////////////////////////////////////////////////////////////// //
73 class PPCape : PlayerPowerup;
82 // called when the player get it for the first time
83 override bool onActivate () {
84 owner.global.hasCape = true;
92 // called when the player lost it (for some reason)
93 override bool onDeactivate (optional bool forced) {
94 owner.global.hasCape = false;
102 override void onPostThink () {
103 visible = (owner.status != MapObject::DUCKTOHANG);
105 if (!owner.whipping && (owner.status == MapObject::CLIMBING || owner.isExitingSprite())) {
108 sprName = 'sCapeBack';
111 } else if (owner.dir == MapObject::Dir.Right) {
113 dy = (owner.status == MapObject::DUCKING || owner.stunned ? 2 : -2);
114 if (open) sprName = 'sCapeUR';
115 else if (fabs(owner.xVel) > 0.4 && owner.status != MapObject::DUCKING) sprName = 'sCapeRight';
116 else sprName = 'sCapeDR';
118 beforePlayer = false;
122 dy = (owner.status == MapObject::DUCKING || owner.stunned ? 2 : -2);
123 if (open) sprName = 'sCapeUL';
124 else if (fabs(owner.xVel) > 0.4 && owner.status != MapObject::DUCKING) sprName = 'sCapeLeft';
125 else sprName = 'sCapeDL';
127 beforePlayer = false;
130 //writeln("CAPE: '", sprName, "'; before=", beforePlayer);
134 final void doDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
135 if (!sprName) return;
137 auto spr = owner.level.sprStore[sprName];
138 if (!spr || spr.frames.length < 1) return;
139 auto spf = spr.frames[0];
140 if (!spf || spf.width < 1 || spf.height < 1) return;
143 owner.getInterpCoords(currFrameDelta, scale, out xi, out yi);
148 xi -= spf.xofs*scale;
149 yi -= spf.yofs*scale;
151 spf.tex.blitAt(xi-xpos, yi-ypos, scale);
155 override void prePreDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
156 if (!visible || owner.status != MapObject::DUCKING) return;
157 doDrawWithOfs(xpos, ypos, scale, currFrameDelta);
161 override void preDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
162 if (!visible || beforePlayer || owner.status == MapObject::DUCKING) return;
163 doDrawWithOfs(xpos, ypos, scale, currFrameDelta);
167 override void lastDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
168 if (!visible || !beforePlayer) return;
169 doDrawWithOfs(xpos, ypos, scale, currFrameDelta);
175 renderPriority = 1010; // behind the bricks
176 sprName = 'sCapeRight';
180 // ////////////////////////////////////////////////////////////////////////// //
181 class PPParachute : PlayerPowerup;
188 // called when the player get it for the first time
189 override bool onActivate () {
197 // called when the player lost it (for some reason)
198 override bool onDeactivate (optional bool forced) {
204 override void onPostThink () {
206 auto spr = owner.level.sprStore['sParaOpen'];
208 if (imageFrame >= spr.frames.length) {
218 final void doDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
219 auto spr = owner.level.sprStore[opening ? 'sParaOpen' : 'sParachute'];
220 if (!spr || spr.frames.length < 1) return;
221 auto spf = spr.frames[imageFrame];
222 if (!spf || spf.width < 1 || spf.height < 1) return;
225 owner.getInterpCoords(currFrameDelta, scale, out xi, out yi);
230 xi -= spf.xofs*scale;
231 yi -= spf.yofs*scale;
233 spf.tex.blitAt(xi-xpos, yi-ypos, scale);
237 override void preDrawWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
238 doDrawWithOfs(xpos, ypos, scale, currFrameDelta);
244 renderPriority = 1010; // behind the bricks