fixed alot of warnings, and some bugs, so it can be compiled with the current vccrun
[k8vacspelynky.git] / mapent / items / dice.vc
blob2376f8fecbb16e6eb0b40807496a412c335f5c16
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 ItemDice['oDice'] : MapItem;
21 enum RollState {
22   None, // ready to roll
23   Rolling, // rolled
24   Finished, // landed in shop
25   Failed, // landed outside of the shop
27 RollState rollState;
29 bool pickedOutsideOfAShop;
32 override bool initialize () {
33   if (!::initialize()) return false;
34   setSprite('sDice1');
35   value = global.randOther(1, 6);
36   return true;
40 // 0: failed roll
41 final int getRollNumber () {
42   if (rollState != RollState.Finished) return 0;
43   return value;
47 final void resetRollState () {
48   rollState = RollState.None;
52 bool isReadyToThrowForBet () {
53   if (!forSale) return false;
54   return ((rollState == RollState.Failed || rollState == RollState.None) && level.player.bet);
58 bool isInsideCrapsShop () {
59   if (!level.isInShop(ix/16, iy/16)) return false;
60   auto sst = level.lg.roomShopType(ix/16, iy/16);
61   return (sst == 'Craps');
65 // various side effects
66 // called only if object was succesfully put into player hands
67 override void onPickedUp (PlayerPawn plr) {
68   pickedOutsideOfAShop = !isInsideCrapsShop();
69   if (rollState != RollState.Finished) rollState = RollState.None;
73 override void drawSignsWithOfs (int xpos, int ypos, int scale, float currFrameDelta) {
74   if (!forSale) return;
75   if ((rollState == RollState.Failed || rollState == RollState.None) && level.player.bet) {
76     int xi, yi;
77     getInterpCoords(currFrameDelta, scale, out xi, out yi);
78     auto spr = level.sprStore['sRedArrowDown'];
79     if (spr && spr.frames.length) {
80       auto spf = spr.frames[0];
81       spf.blitAt(xi-xpos-spf.xofs*scale, yi-ypos-(12+spf.yofs)*scale, scale);
82     }
83   }
87 override void onCheckItemStolen (PlayerPawn plr) {
88   if (!heldBy || pickedOutsideOfAShop) return;
89   if (forSale && !level.player.bet && rollState != RollState.Failed) {
90     bool inShop = level.isInShop(ix/16, iy/16);
91     if (!inShop) {
92       level.scrShopkeeperAnger(GameLevel::SCAnger.ItemStolen); // don't steal it!
93     }
94   }
98 override void thinkFrame () {
99   if (forSale && /*!forVending && cost > 0 &&*/ !level.hasAliveShopkeepers(skipAngry:true)) {
100     forSale = false;
101     cost = 0;
102   }
104   //lightRadius = max(origLightRadius, (forSale && level.isInShop(ix/16, iy/16) ? 64 : 0));
105   if (forSale && level.isInShop(ix/16, iy/16)) {
106     lightRadius = max(default.lightRadius, 64);
107   } else {
108     lightRadius = default.lightRadius;
109   }
111   if (heldBy) {
112     /*
113          if (oCharacter.facing == LEFT) x = oCharacter.x - 4;
114     else if (oCharacter.facing == RIGHT) x = oCharacter.x + 4;
116     if (heavy) {
117       if (oCharacter.state == DUCKING and abs(oCharacter.xVel) < 2) y = oCharacter.y; else y = oCharacter.y-2;
118     } else {
119       if (oCharacter.state == DUCKING and abs(oCharacter.xVel) < 2) y = oCharacter.y+4; else y = oCharacter.y+2;
120     }
121     depth = 1;
123     if (oCharacter.holdItem == 0) held = false;
124     */
125     // stealing makes shopkeeper angry
126     //writeln("!!! fs=", forSale, "; bet=", level.player.bet, "; st=", rollState);
127   } else {
128     moveRel(xVel, yVel);
130     bool colLeft = !!isCollisionLeft(1);
131     bool colRight = !!isCollisionRight(1);
132     bool colBot = !!isCollisionBottom(1);
133     //bool colTop = !!isCollisionTop(1);
135     if (!colBot && yVel < 6) yVel += myGrav;
137          if (fabs(xVel) < 0.1) xVel = 0;
138     else if (colLeft || colRight) xVel = -xVel*0.5;
140     if (colBot) {
141       // bounce
142       if (yVel > 1) { ++bounceCount; yVel = -yVel*bounceFactor; } else yVel = 0;
143       // friction
144            if (fabs(xVel) < 0.1) xVel = 0;
145       else if (fabs(xVel) != 0) xVel *= frictionFactor;
146       if (fabs(yVel) < 1) {
147         flty -= 1;
148         if (!isCollisionBottom(1)) flty += 1;
149         yVel = 0;
150       }
151     }
153     if (colLeft) {
154       if (!colRight) fltx += 1;
155       //yVel = 0;
156     } else if (colRight) {
157       fltx -= 1;
158       //yVel = 0;
159     }
161     if (isCollisionTop(1)) {
162       if (yVel < 0) yVel = -yVel*0.8; else flty += 1;
163     }
165     //!depth = (global.hasSpectacles ? 0 : 101); //???
167     if (isCollisionInRect(ix-3, iy-3, 7, 7, &level.cbCollisionLava)) {
168       myGrav = 0;
169       xVel = 0;
170       yVel = 0;
171       shiftY(0.05);
172     } else {
173       myGrav = 0.6;
174     }
176     if (isCollisionAtPoint(ix, iy-5, &level.cbCollisionLava)) {
177       instanceRemove();
178       return;
179     }
180   }
182   if (!isInstanceAlive || spectral) return;
184   if (fabs(xVel) > 3 || fabs(yVel) > 3) {
185     /*
186     auto plr = level.player;
187     if (plr.isRectCollision(ix+enemyColX, iy+enemyColY, enemyColW, enemyColH)) {
188       doPlayerColAction(plr);
189     }
190     */
191     spectral = true;
192     level.forEachObjectInRect(ix-2, iy-2, 5, 5, &doObjectColAction);
193     spectral = false;
194   }
196   // roll states
197   if (fabs(yVel) > 2 || fabs(xVel) > 2) {
198     setSprite('sDiceRoll');
199     if (rollState != RollState.Rolling) {
200       //auto ost = value;
201       value = global.randOther(1, 6);
202       //writeln("DICE: oldval=", ost, "; newval=", value);
203     }
204     switch (rollState) {
205       case RollState.Finished:
206         // NO CHEATING!
207         if (level.player.bet > 0) level.scrShopkeeperAnger(GameLevel::SCAnger.CrapsCheated);
208         break;
209       default:
210         rollState = RollState.Rolling;
211         break;
212     }
213   } else {
214     if (yVel == 0 && fabs(xVel <= 2) && isCollisionBottom(1)) {
215       // landed
216       switch (rollState) {
217         case RollState.Rolling:
218           rollState = (isInsideCrapsShop() ? RollState.Finished : RollState.Failed);
219           if (rollState == RollState.Finished) level.player.onDieRolled(self);
220           break;
221         case RollState.Finished:
222         case RollState.Failed:
223           break;
224         case RollState.None:
225         default: rollState = RollState.None; break;
226       }
227     }
228   }
230   if (rollState != RollState.Rolling) {
231     switch (value) {
232       case 1: setSprite('sDice1'); break;
233       case 2: setSprite('sDice2'); break;
234       case 3: setSprite('sDice3'); break;
235       case 4: setSprite('sDice4'); break;
236       case 5: setSprite('sDice5'); break;
237       default: setSprite('sDice6'); break;
238     }
239   }
241   canPickUp = (rollState != RollState.Rolling);
245 defaultproperties {
246   objType = 'Dice';
247   desc = "Die";
248   desc2 = "A six-sided die. The storeowner talks to it every night before he goes to sleep.";
249   setCollisionBounds(-6, 0, 6, 8);
250   cost = 0;
251   heavy = true;
252   //rolled = false;
253   //rolling = false;
254   canBeNudged = true;
255   canPickUp = true;
256   holdYOfs = -4;
257   rollState = RollState.None;
258   bloodless = true; // just in case, lol
259   canHitEnemies = true;
260   sellingToShopAllowed = true;