//std_functions.zh for 2.50.2 //05-SEPT-2015 // // Some utility routines // //Wait for n frames void Waitframes(int n) { while(n-- > 0) Waitframe(); } //Returns a if cond is true, else b. Overloaded. float Cond(bool cond, float a, float b) { if (cond) return a; else return b; } bool Cond(bool cond, bool a, bool b) { if (cond) return a; else return b; } npc Cond(bool cond, npc a, npc b) { if (cond) return a; else return b; } item Cond(bool cond, item a, item b) { if (cond) return a; else return b; } lweapon Cond(bool cond, lweapon a, lweapon b) { if (cond) return a; else return b; } eweapon Cond(bool cond, eweapon a, eweapon b) { if (cond) return a; else return b; } ffc Cond(bool cond, ffc a, ffc b) { if (cond) return a; else return b; } itemdata Cond(bool cond, itemdata a, itemdata b) { if (cond) return a; else return b; } // Chooses one of the options randomly and fairly. float Choose(float a, float b) { if (Rand(2)==0) return a; else return b; } float Choose(float a, float b, float c) { int r = Rand(3); if (r==0) return a; else if (r==1) return b; else return c; } float Choose(float a, float b, float c, float d) { int r = Rand(4); if (r==0) return a; else if (r==1) return b; else if (r==2) return c; else return d; } float Choose(float a, float b, float c, float d, float e) { int r = Rand(5); if (r==0) return a; else if (r==1) return b; else if (r==2) return c; else if (r==3) return d; else return e; } float Choose(float a, float b, float c, float d, float e, float f) { int r = Rand(6); if (r==0) return a; else if (r==1) return b; else if (r==2) return c; else if (r==3) return d; else if (r==4) return e; else return f; } //Returns the logarithm of x to the given base float LogToBase(float x, float base){ return Ln(x)/Ln(base); } //Truncates x to an integer int Floor(float x) { if(x < 0) return (x-.9999)<<0; return x<<0; } //Raises x to the nearest integer int Ceiling(float x) { if(x < 0) return x<<0; return (x+.9999)<<0; } //Rounds x to the nearest integer float Round(float x) { if(x < 0) return (x-.5)<<0; return (x+.5)<<0; } //Returns true if the integer is odd (or even in IsEven) bool IsOdd(int x) { return ((x & 1) == 1); } bool IsEven(int x) { return ((x & 1) == 0); } //Clamps x to the range of low, high. int Clamp(int x, int low, int high) { if(xhigh) x=high; return x; } //same as Clamp, but with reversed values. int VBound(int x, int high, int low) { if(xhigh) x=high; return x; } //Returns the Quotient only of x divided by y int Div(float x, float y) { return (x/y)<<0; } //Returns a random integer in the bounds of min and max int Rand(int min, int max) { return min+(Rand((1+max)-min)); } //Returns a random floating point number up to n float Randf(float n) { return (Rand(0x7fff)/0x7fff)*n; } //Returns a random floating point number between min and max float Randf(float n1, float n2) { return n1 + (Rand(0x7fff)/(0x7fff))*(n2-n1); } //Converts 'd' in degrees to radians float DegtoRad(float d) { return d*0.0174; } //Converts 'r' in radians to degrees float RadtoDeg(float r) { return r*57.2958; } //Returns the sign of n int Sign(int n) { if (n > 0) return 1; else if (n < 0) return -1; else return 0; } //Finds the location of a combo, given its (x,y) coordinates on the screen int ComboAt(int x, int y) { x = VBound(x,255,0); y = VBound(y,175,0); return (y & 240)+(x>>4); } //Snaps 'x' to the combo grid //Equivalent to calling ComboX(ComboAt(x,foo)); int GridX(int x) { return (x >> 4) << 4; } //Snaps 'y' to the combo grid //Equivalent to calling ComboY(ComboAt(foo,y)); int GridY(int y) { return (y >> 4) << 4; } //Returns the correct offset to be at the front of a sprite facing in the direction 'dir' int AtFrontX(int dir) { int x = 0; if(dir == DIR_UP || dir == DIR_DOWN) x = 8; else if(dir == DIR_RIGHT) x = 16; return x; } int AtFrontY(int dir) { int y = 0; if(dir == DIR_DOWN) y = 16; else if(dir == DIR_LEFT || dir == DIR_RIGHT) y = 8; return y; } //Returns the correct offset to be 'dist' pixels away from the front of a sprite facing in the direction 'dir' int InFrontX(int dir, int dist) { int x = 0; if(dir == DIR_LEFT) x = -16+dist; else if(dir == DIR_RIGHT) x = 16-dist; return x; } int InFrontY(int dir, int dist){ int y = 0; if(dir == DIR_UP) y = -16+dist; else if(dir == DIR_DOWN) y = 16-dist; return y; } // Get the X and Y coordinates at the center of a sprite int CenterX(ffc anFFC) { return anFFC->X+8*anFFC->TileWidth; } int CenterY(ffc anFFC) { return anFFC->Y+8*anFFC->TileHeight; } int CenterX(npc anNPC) { return anNPC->X+8*anNPC->TileWidth; } int CenterY(npc anNPC) { return anNPC->Y+8*anNPC->TileHeight; } int CenterX(eweapon anEWeapon) { return anEWeapon->X+8*anEWeapon->TileWidth; } int CenterY(eweapon anEWeapon) { return anEWeapon->Y+8*anEWeapon->TileHeight; } int CenterX(lweapon anLWeapon) { return anLWeapon->X+8*anLWeapon->TileWidth; } int CenterY(lweapon anLWeapon) { return anLWeapon->Y+8*anLWeapon->TileHeight; } int CenterLinkX() { return Link->X+8; } int CenterLinkY() { return Link->Y+8; } //Return the coordinates of a combo on the screen int ComboX(int loc) { return loc%16*16; } int ComboY(int loc) { return loc&0xF0; } //Returns true if the combo at '(x, y)' has either an inherent or place flag of type 'flag' bool ComboFI(int x, int y, int flag){ int loc = ComboAt(x,y); return Screen->ComboF[loc] == flag || Screen->ComboI[loc] == flag; } //Returns true if the combo at 'loc' has either an inherent or place flag of type 'flag' bool ComboFI(int loc, int flag){ return Screen->ComboF[loc] == flag || Screen->ComboI[loc] == flag; } //Sets bit 'bit' of Screen->D[] register 'd' to 'state' void SetScreenDBit(int dmap, int screen, int d, int bit, bool state){ int curstate = Game->GetDMapScreenD(dmap, screen, d); if(state) Game->SetDMapScreenD(dmap, screen, d, curstate | (1 << bit)); else Game->SetDMapScreenD(dmap, screen, d, curstate & ~(1 << bit)); } void SetScreenDBit(int screen, int d, int bit, bool state){ int curstate = Game->GetScreenD(screen, d); if(state) Game->SetScreenD(screen, d, curstate | (1 << bit)); else Game->SetScreenD(screen, d, curstate & ~(1 << bit)); } void SetScreenDBit(int d, int bit, bool state){ if(state) Screen->D[d] |= (1 << bit); else Screen->D[d] &= ~(1 << bit); } //Returns the state of bit 'bit' of Screen->D[] register 'd' bool GetScreenDBit(int dmap, int screen, int d, int bit){ return ( Game->GetDMapScreenD(dmap, screen, d) & (1 << bit) ) != 0; } bool GetScreenDBit(int screen, int d, int bit){ return ( Game->GetScreenD(screen, d) & (1 << bit) ) != 0; } bool GetScreenDBit(int d, int bit){ return (Screen->D[d] & (1 << bit)) != 0; } //A shorthand way to get a combo on the current layer. //Layer 0 is the screen itself. int GetLayerComboD(int layer, int pos) { if (layer==0) return Screen->ComboD[pos]; else return Game->GetComboData(Screen->LayerMap(layer), Screen->LayerScreen(layer), pos); } //A shorthand way to set a combo on the current layer. //Layer 0 is the screen itself. void SetLayerComboD(int layer, int pos, int combo) { if (layer == 0) Screen->ComboD[pos] = combo; else Game->SetComboData(Screen->LayerMap(layer), Screen->LayerScreen(layer), pos, combo); } //A shorthand way to get a combo flag on the current layer. //Layer 0 is the screen itself. int GetLayerComboF(int layer, int pos) { if (layer==0) return Screen->ComboF[pos]; else return Game->GetComboFlag(Screen->LayerMap(layer), Screen->LayerScreen(layer), pos); } //A shorthand way to set a combo flag on the current layer. //Layer 0 is the screen itself. void SetLayerComboF(int layer, int pos, int flag) { if (layer == 0) Screen->ComboF[pos] = flag; else Game->SetComboFlag(Screen->LayerMap(layer), Screen->LayerScreen(layer), pos, flag); } //A shorthand way to get a combo type on the current layer. //Layer 0 is the screen itself. int GetLayerComboT(int layer, int pos) { if (layer==0) return Screen->ComboT[pos]; else return Game->GetComboType(Screen->LayerMap(layer), Screen->LayerScreen(layer), pos); } //A shorthand way to set a combo type on the current layer. //Layer 0 is the screen itself. void SetLayerComboT(int layer, int pos, int type) { if (layer == 0) Screen->ComboT[pos] = type; else Game->SetComboType(Screen->LayerMap(layer), Screen->LayerScreen(layer), pos, type); } //A shorthand way to get a combo's solidity on the current layer. //Layer 0 is the screen itself. int GetLayerComboS(int layer, int pos) { if (layer==0) return Screen->ComboS[pos]; else return Game->GetComboSolid(Screen->LayerMap(layer), Screen->LayerScreen(layer), pos); } //A shorthand way to set a combo's solidity on the current layer. //Layer 0 is the screen itself. void SetLayerComboS(int layer, int pos, int solidity) { if (layer == 0) Screen->ComboS[pos] = solidity; else Game->SetComboSolid(Screen->LayerMap(layer), Screen->LayerScreen(layer), pos, solidity); } //A shorthand way to get a combo inherent flag on the current layer. //Layer 0 is the screen itself. int GetLayerComboI(int layer, int pos) { if (layer==0) return Screen->ComboI[pos]; else return Game->GetComboInherentFlag(Screen->LayerMap(layer), Screen->LayerScreen(layer), pos); } //A shorthand way to set a combo inherent flag on the current layer. //Layer 0 is the screen itself. void SetLayerComboI(int layer, int pos, int flag) { if (layer == 0) Screen->ComboI[pos] = flag; else Game->SetComboInherentFlag(Screen->LayerMap(layer), Screen->LayerScreen(layer), pos, flag); } //A shorthand way to get a combo CSet on the current layer. //Layer 0 is the screen itself. int GetLayerComboC(int layer, int pos) { if (layer==0) return Screen->ComboC[pos]; else return Game->GetComboCSet(Screen->LayerMap(layer), Screen->LayerScreen(layer), pos); } //A shorthand way to set a combo CSet on the current layer. //Layer 0 is the screen itself. void SetLayerComboC(int layer, int pos, int cset) { if (layer == 0) Screen->ComboC[pos] = flag; else Game->SetComboCSet(Screen->LayerMap(layer), Screen->LayerScreen(layer), pos, cset); } //Copies the combos and csets from one screen to another. //Only copies layer 0! void ScreenCopy(int destmap, int destscr, int srcmap, int srcscr) { for (int i = 0; i < 176; i++) { Game->SetComboData(destmap,destscr, i, Game->GetComboData(srcmap,srcscr,i)); Game->SetComboCSet(destmap,destscr, i, Game->GetComboCSet(srcmap,srcscr,i)); } } //Swaps a row of tiles of length 'length' between positions 'first' and 'second' void SwapTileRow(int first, int second, int length){ for(int i=0;iDrawString which includes a position to start drawing from in the string //Does not check for overflow void DrawString(int layer, int x, int y, int font, int color, int background_color, int format, int opacity, int string, int start){ int buffer[256]; for(int i=start;string[i]!=0;i++) buffer[i-start] = string[i]; Screen->DrawString(layer,x,y,font,color,background_color,format,opacity,buffer); } //Overload to Screen->DrawString which includes a start and end position to draw the string //Does not check for overflow void DrawString(int layer, int x, int y, int font, int color, int background_color, int format, int opacity, int string, int start, int end){ int buffer[256]; for(int i=start;iDrawString(layer,x,y,font,color,background_color,format,opacity,buffer); } // A very simple layer 0 tile drawing routine. void DrawTileSimple(int x, int y, int tile, int color) { Screen->FastTile(0, x, y, tile, color, 128); } //Returns the distance between two sets of coordinates using Pythagoras' Theorem float Distance(int x1, int y1, int x2, int y2) { int x = (x1-x2); int y = (y1-y2); return Sqrt(x*x+y*y); } //Returns the direction of the vector from point 1 to point 2, in degrees from -180 to 180. (0 = right) float Angle(int x1, int y1, int x2, int y2) { return ArcTan(x2-x1, y2-y1)*57.2958; } //The above, but in radians. float RadianAngle(int x1, int y1, int x2, int y2) { return ArcTan(x2-x1, y2-y1); } // Returns the X component of a vector with a degree angle. // A length of 3 and angle of 0 returns 3. // A length of 3 and angle of 45 returns approx. 1.57. // A length of 3 and angle of 90 returns 0. float VectorX(int len, float angle) { return Cos(angle)*len; } // Returns the Y component of a vector with a degree angle. // A length of 3 and angle of 0 returns 0. // A length of 3 and angle of 45 returns approx. 1.57. // A length of 3 and angle of 90 returns 3. float VectorY(int len, float angle) { return Sin(angle)*len; } //rotates X about a center point by an amount of degrees float RotatePointX(float x, float y, float centerX, float centerY, float degrees) { float dx = x - centerX; float dy = y - centerY; return (Cos(degrees) * dx) - (Sin(degrees) * dy) + centerX; } //rotates Y about a center point by an amount of degrees float RotatePointY(float x, float y, float centerX, float centerY, float degrees) { float dx = x - centerX; float dy = y - centerY; return (Sin(degrees) * dx) - (Cos(degrees) * dy) + centerY; } //scales X to centerX by a given scale float ScalePointX(float x, float centerX, float scale) { return (scale * (x - centerX)) + centerX; } //scales Y to centerY by a given scale float ScalePointY(float y, float centerY, float scale) { return (scale * (y - centerY)) + centerY; } //rotates and scales X about a center point by an amount of degrees float RotateScalePointX(float x, float y, float centerX, float centerY, float degrees, float scaleX, float scaleY) { float dx = (x - centerX) * scaleX; float dy = (y - centerY) * scaleY; return (Cos(degrees) * dx) - (Sin(degrees) * dy) + centerX; } //rotates and scales Y about a center point by an amount of degrees float RotateScalePointY(float x, float y, float centerX, float centerY, float degrees, float scaleX, float scaleY) { float dx = (x - centerX) * scaleX; float dy = (y - centerY) * scaleY; return (Sin(degrees) * dx) - (Cos(degrees) * dy) + centerY; } // Interpolates between p1 and p2 given 't' clamped within range 0,1. float Lerp(float p1, float p2, float t) { return (p1 + (p2 - p1) * t); } // Returns the dot product of two vectors. float DotProduct( float x1, float y1, float x2, float y2 ) { return (x1 * x2 + y1 * y2); } // Returns the cross product of two vectors. float CrossProduct( float x1, float y1, float x2, float y2 ) { return (x1 * y2 - y1 * x2); } // Returns the squared distance of a vector. float DistanceSquared( float x, float y ) { return (x * x + y * y); } // Finds the center of p1 and p2. float Midpoint(float p1, float p2) { return Lerp(p1, p2, 0.5); } // Performs a "Smooth" Interpolation given 't' clamped within range 0,1. float SmoothStep(float p1, float p2, float t) { t = (t * t) * (3.0 - (2.0 * t)); return Lerp(p1, p2, t); } // Returns an angle pointing (t)percentage more accurate to the target than the specified radian_angle. float TurnTowards( int X, int Y, int targetX, int targetY, float radian_angle, float t ) { float a = ArcTan( targetX - X, targetY - Y ); float d = WrapAngle(a - radian_angle); if ( d > PI ) d =-( PI2 - d ); else if ( d < -PI ) d = PI2 + d; return WrapAngle(radian_angle + d * t); } // Wraps radian value towards the range of -PI,PI. float WrapAngle( float radians ) { while (radians <= -PI) radians += PI2; while (radians > PI) radians -= PI2; return radians; } // Wraps degree value towards the range of -180,180. float WrapDegrees( float degrees ) { while (degrees <= -180) degrees += 360; while (degrees > 180) degrees -= 360; return degrees; } // Converts a counterclockwise degree angle (from -180 to 180) into one of the eight // standard directions (DIR_UP etc.) used by ZC. int AngleDir8(float angle) { if (angle <= 157.5 && angle > 112.5) return DIR_LEFTDOWN; else if (angle <= 112.5 && angle > 67.5) return DIR_DOWN; else if (angle <= 67.5 && angle > 22.5) return DIR_RIGHTDOWN; else if (angle <= 22.5 && angle > -22.5) return DIR_RIGHT; else if (angle <= -22.5 && angle > -67.5) return DIR_RIGHTUP; else if (angle <= -67.5 && angle > -112.5) return DIR_UP; else if (angle <= -112.5 && angle > -157.5) return DIR_LEFTUP; else return DIR_LEFT; } //The above, but for radian angles. int RadianAngleDir8(float angle) { return AngleDir8(angle*57.2958); } // Converts a counterclockwise degree angle (from -180 to 180) into one of the four // standard directions (DIR_UP, DIR_DOWN, DIR_LEFT, DIR_RIGHT) used by ZC. int AngleDir4(float angle) { if (angle <= 135 && angle > 45) return DIR_DOWN; else if (angle <= 45 && angle > -45) return DIR_RIGHT; else if (angle <= -45 && angle > -135) return DIR_UP; else return DIR_LEFT; } //The above, but for radian angles. int RadianAngleDir4(float angle) { return AngleDir4(angle*57.2958); } //Returns the opposite direction to angle 'dir' int OppositeDir(int dir) { return Cond(dir < 4, dir^1b, dir^11b); } //Converts directions to go round in a circle rather than U, D, L, R int SpinDir(int dir) { if(dir==0) return DIR_UP; else if(dir==1) return DIR_RIGHT; else if(dir==2) return DIR_DOWN; else if(dir==3) return DIR_LEFT; return -1; } //Draws an ffc to a given layer. If the ffc is larger than 1x1 its graphics must all be comboed void DrawToLayer(ffc f, int layer, int opacity){ Screen->DrawCombo(layer,f->X,f->Y,f->Data,f->TileWidth,f->TileHeight,f->CSet,-1,-1,0,0,0,-1,0,true,opacity); } //Draws an npc to a given layer void DrawToLayer(npc n, int layer, int opacity){ Screen->DrawTile(layer,n->X,n->Y,n->Tile,n->TileWidth,n->TileHeight,n->CSet,-1,-1,0,0,0,0,true,opacity); } //Draws an lweapon to a given layer void DrawToLayer(lweapon l, int layer, int opacity){ Screen->DrawTile(layer,l->X,l->Y,l->Tile,l->TileWidth,l->TileHeight,l->CSet,-1,-1,0,0,0,0,true,opacity); } //Draws an eweapon to a given layer void DrawToLayer(eweapon e, int layer, int opacity){ Screen->DrawTile(layer,e->X,e->Y,e->Tile,e->TileWidth,e->TileHeight,e->CSet,-1,-1,0,0,0,0,true,opacity); } //Draws an item to a given layer void DrawToLayer(item i, int layer, int opacity){ Screen->DrawTile(layer,i->X,i->Y,i->Tile,i->TileWidth,i->TileHeight,i->CSet,-1,-1,0,0,0,0,true,opacity); } //Generalized and optimized rectangle collision checking function. //Returns true if the bounding box of box1 and box2 overlap. bool RectCollision(int box1_x1, int box1_y1, int box1_x2, int box1_y2, int box2_x1, int box2_y1, int box2_x2, int box2_y2) { if( box1_y2 < box2_y1 ) return false; else if( box1_y1 > box2_y2 ) return false; else if( box1_x2 < box2_x1 ) return false; else if( box1_x1 > box2_x2 ) return false; return true; } //Check for collisions of two squares given upper-left coordinates and a side length for each. bool SquareCollision(int c1x, int c1y, int side1, int c2x, int c2y, int side2) { return RectCollision(c1x, c1y, c1x+side1, c1y+side1, c2x, c2y, c2x+side1, c2y+side1); } //Check for collisions of two squares given center coordinates and a halved side length for each. bool SquareCollision2(int c1x, int c1y, int radius1, int c2x, int c2y, int radius2) { if( c1y + radius1 < c2y - radius2 ) return false; else if( c1y - radius1 > c2y + radius2 ) return false; else if( c1x + radius1 < c2x - radius2 ) return false; else if( c1x - radius1 > c2x + radius2 ) return false; return true; } //Returns true if the two circles c1 and c2 overlap. bool CircleCollision(int c1x, int c1y, int radius1, int c2x, int c2y, int radius2) { return (Distance(c1x,c1y,c2x,c2y) <= (radius1+radius2)); } //Returns true if there is a collision between the hitboxes of an lweapon and an eweapon. bool Collision(lweapon a, eweapon b) { int ax = a->X + a->HitXOffset; int bx = b->X + b->HitXOffset; int ay = a->Y + a->HitYOffset; int by = b->Y + b->HitYOffset; return RectCollision(ax, ay, ax+a->HitWidth, ay+a->HitHeight, bx, by, bx+b->HitWidth, by+b->HitHeight) && (a->Z + a->HitZHeight >= b->Z) && (a->Z <= b->Z + b->HitZHeight); } //A collision between an lweapon and an lweapon. bool Collision(lweapon a, lweapon b) { int ax = a->X + a->HitXOffset; int bx = b->X + b->HitXOffset; int ay = a->Y + a->HitYOffset; int by = b->Y + b->HitYOffset; return RectCollision(ax, ay, ax+a->HitWidth, ay+a->HitHeight, bx, by, bx+b->HitWidth, by+b->HitHeight) && (a->Z + a->HitZHeight >= b->Z) && (a->Z <= b->Z + b->HitZHeight); } //A collision between an eweapon and an eweapon. bool Collision(eweapon a, eweapon b) { int ax = a->X + a->HitXOffset; int bx = b->X + b->HitXOffset; int ay = a->Y + a->HitYOffset; int by = b->Y + b->HitYOffset; return RectCollision(ax, ay, ax+a->HitWidth, ay+a->HitHeight, bx, by, bx+b->HitWidth, by+b->HitHeight) && (a->Z + a->HitZHeight >= b->Z) && (a->Z <= b->Z + b->HitZHeight); } //A collision between an lweapon and an npc. bool Collision(lweapon a, npc b) { int ax = a->X + a->HitXOffset; int bx = b->X + b->HitXOffset; int ay = a->Y + a->HitYOffset; int by = b->Y + b->HitYOffset; return RectCollision(ax, ay, ax+a->HitWidth, ay+a->HitHeight, bx, by, bx+b->HitWidth, by+b->HitHeight) && (a->Z + a->HitZHeight >= b->Z) && (a->Z <= b->Z + b->HitZHeight); } //A collision between an eweapon and an npc. bool Collision(eweapon a, npc b) { int ax = a->X + a->HitXOffset; int bx = b->X + b->HitXOffset; int ay = a->Y + a->HitYOffset; int by = b->Y + b->HitYOffset; return RectCollision(ax, ay, ax+a->HitWidth, ay+a->HitHeight, bx, by, bx+b->HitWidth, by+b->HitHeight) && (a->Z + a->HitZHeight >= b->Z) && (a->Z <= b->Z + b->HitZHeight); } //A collision between an npc and an npc. bool Collision(npc a, npc b) { int ax = a->X + a->HitXOffset; int bx = b->X + b->HitXOffset; int ay = a->Y + a->HitYOffset; int by = b->Y + b->HitYOffset; return RectCollision(ax, ay, ax+a->HitWidth, ay+a->HitHeight, bx, by, bx+b->HitWidth, by+b->HitHeight) && (a->Z + a->HitZHeight >= b->Z) && (a->Z <= b->Z + b->HitZHeight); } //A collision between an item and an lweapon. bool Collision(item a, lweapon b) { int ax = a->X + a->HitXOffset; int bx = b->X + b->HitXOffset; int ay = a->Y + a->HitYOffset; int by = b->Y + b->HitYOffset; return RectCollision(ax, ay, ax+a->HitWidth, ay+a->HitHeight, bx, by, bx+b->HitWidth, by+b->HitHeight) && (a->Z + a->HitZHeight >= b->Z) && (a->Z <= b->Z + b->HitZHeight); } //A collision between an item and an eweapon. bool Collision(item a, eweapon b) { int ax = a->X + a->HitXOffset; int bx = b->X + b->HitXOffset; int ay = a->Y + a->HitYOffset; int by = b->Y + b->HitYOffset; return RectCollision(ax, ay, ax+a->HitWidth, ay+a->HitHeight, bx, by, bx+b->HitWidth, by+b->HitHeight) && (a->Z + a->HitZHeight >= b->Z) && (a->Z <= b->Z + b->HitZHeight); } //A collision between an item and an npc. bool Collision(item a, npc b) { int ax = a->X + a->HitXOffset; int bx = b->X + b->HitXOffset; int ay = a->Y + a->HitYOffset; int by = b->Y + b->HitYOffset; return RectCollision(ax, ay, ax+a->HitWidth, ay+a->HitHeight, bx, by, bx+b->HitWidth, by+b->HitHeight) && (a->Z + a->HitZHeight >= b->Z) && (a->Z <= b->Z + b->HitZHeight); } //A collision between an item and an item. bool Collision(item a, item b) { int ax = a->X + a->HitXOffset; int bx = b->X + b->HitXOffset; int ay = a->Y + a->HitYOffset; int by = b->Y + b->HitYOffset; return RectCollision(ax, ay, ax+a->HitWidth, ay+a->HitHeight, bx, by, bx+b->HitWidth, by+b->HitHeight) && (a->Z + a->HitZHeight >= b->Z) && (a->Z <= b->Z + b->HitZHeight); } //A collision between an ffc and an lweapon. Uses TileWidth and TileHeight for the FFC's bounding box. Ignores the Z axis. bool Collision(ffc f, lweapon b) { int bx = b->X + b->HitXOffset; int by = b->Y + b->HitYOffset; return RectCollision(f->X, f->Y, f->X+(f->TileWidth*16), f->Y+(f->TileHeight*16), bx, by, bx+b->HitWidth, by+b->HitHeight); } //A collision between an ffc and an eweapon. Uses TileWidth and TileHeight for the FFC's bounding box. Ignores the Z axis. bool Collision(ffc f, eweapon b) { int bx = b->X + b->HitXOffset; int by = b->Y + b->HitYOffset; return RectCollision(f->X, f->Y, f->X+(f->TileWidth*16), f->Y+(f->TileHeight*16), bx, by, bx+b->HitWidth, by+b->HitHeight); } //A collision between an ffc and an npc. Uses TileWidth and TileHeight for the FFC's bounding box. Ignores the Z axis. bool Collision(ffc f, npc b) { int bx = b->X + b->HitXOffset; int by = b->Y + b->HitYOffset; return RectCollision(f->X, f->Y, f->X+(f->TileWidth*16), f->Y+(f->TileHeight*16), bx, by, bx+b->HitWidth, by+b->HitHeight); } //A collision between an ffc and an item. Uses TileWidth and TileHeight for the FFC's bounding box. Ignores the Z axis. bool Collision(ffc f, item b) { int bx = b->X + b->HitXOffset; int by = b->Y + b->HitYOffset; return RectCollision(f->X, f->Y, f->X+(f->TileWidth*16), f->Y+(f->TileHeight*16), bx, by, bx+b->HitWidth, by+b->HitHeight); } //A collision between an ffc and an ffc. Uses TileWidth and TileHeight for the FFCs' bounding boxes. bool Collision(ffc f, ffc f2) { return RectCollision(f->X, f->Y, f->X+(f->TileWidth*16), f->Y+(f->TileHeight*16), f2->X, f2->Y, f2->X+f2->TileWidth*16, f2->Y+f2->TileHeight*16); } //A circular collision between an ffc and an ffc. Uses TileWidth and TileHeight to find the centre of the FFCs. bool Collision(ffc f, int radius1, ffc f2, int radius2) { return CircleCollision(f->X+f->TileWidth/2, f->Y+f->TileHeight/2, radius1,f2->X+f2->TileWidth/2, f2->Y+f2->TileHeight/2, radius2); } // So that you don't have to remember the ordering of the args bool Collision(eweapon a, lweapon b) { return Collision(b, a); } bool Collision(npc a, lweapon b) { return Collision(b, a); } bool Collision(npc a, eweapon b) { return Collision(b, a); } bool Collision(lweapon a, item b) { return Collision(b, a); } bool Collision(eweapon a, item b) { return Collision(b, a); } bool Collision(npc a, item b) { return Collision(b, a); } bool Collision(lweapon a, ffc b) { return Collision(b, a); } bool Collision(eweapon a, ffc b) { return Collision(b, a); } bool Collision(npc a, ffc b) { return Collision(b, a); } bool Collision(item a, ffc b) { return Collision(b, a); } // Returns true if there is a collision between Link's hitbox and the eweapon's. // This only checks hitboxes. bool LinkCollision(eweapon b) { int ax = Link->X + Link->HitXOffset; int bx = b->X + b->HitXOffset; int ay = Link->Y + Link->HitYOffset; int by = b->Y + b->HitYOffset; return RectCollision(ax, ay, ax+Link->HitWidth, ay+Link->HitHeight, bx, by, bx+b->HitWidth, by+b->HitHeight) && (Link->Z + Link->HitZHeight >= b->Z) && (Link->Z <= b->Z + b->HitZHeight); } // Returns true if there is a collision between Link's hitbox and the lweapon's. // This only checks hitboxes. bool LinkCollision(lweapon b) { int ax = Link->X + Link->HitXOffset; int bx = b->X + b->HitXOffset; int ay = Link->Y + Link->HitYOffset; int by = b->Y + b->HitYOffset; return RectCollision(ax, ay, ax+Link->HitWidth, ay+Link->HitHeight, bx, by, bx+b->HitWidth, by+b->HitHeight) && (Link->Z + Link->HitZHeight >= b->Z) && (Link->Z <= b->Z + b->HitZHeight); } // Returns true if there is a collision between Link's hitbox and the item's. // This only checks hitboxes. bool LinkCollision(item b) { int ax = Link->X + Link->HitXOffset; int bx = b->X + b->HitXOffset; int ay = Link->Y + Link->HitYOffset; int by = b->Y + b->HitYOffset; return RectCollision(ax, ay, ax+Link->HitWidth, ay+Link->HitHeight, bx, by, bx+b->HitWidth, by+b->HitHeight) && (Link->Z + Link->HitZHeight >= b->Z) && (Link->Z <= b->Z + b->HitZHeight); } // Returns true if there is a collision between Link's hitbox and the npc's. // This only checks hitboxes. Uses TileWidth and TileHeight to find the centre of the FFCs. bool LinkCollision(npc b) { int ax = Link->X + Link->HitXOffset; int bx = b->X + b->HitXOffset; int ay = Link->Y + Link->HitYOffset; int by = b->Y + b->HitYOffset; return RectCollision(ax, ay, ax+Link->HitWidth, ay+Link->HitHeight, bx, by, bx+b->HitWidth, by+b->HitHeight) && (Link->Z + Link->HitZHeight >= b->Z) && (Link->Z <= b->Z + b->HitZHeight); } // Returns true if there is a collision between Link's hitbox and the FFC's. // This only checks hitboxes. bool LinkCollision(ffc f) { int ax = Link->X + Link->HitXOffset; int ay = Link->Y + Link->HitYOffset; return RectCollision(f->X, f->Y, f->X+(f->TileWidth*16), f->Y+(f->TileHeight*16), ax, ay, ax+Link->HitWidth, ay+Link->HitHeight); } // Returns the X coordinate of the left edge of the hitbox. int HitboxLeft(eweapon a) { return (a->X + a->HitXOffset); } int HitboxLeft(lweapon a) { return (a->X + a->HitXOffset); } int HitboxLeft(item a) { return (a->X + a->HitXOffset); } int HitboxLeft(npc a) { return (a->X + a->HitXOffset); } int HitboxLeft(ffc a) { return a->X; } // Returns the X coordinate of the right edge of the hitbox. int HitboxRight(eweapon a) { return (a->X + a->HitXOffset + a->HitWidth - 1); } int HitboxRight(lweapon a) { return (a->X + a->HitXOffset + a->HitWidth - 1); } int HitboxRight(item a) { return (a->X + a->HitXOffset + a->HitWidth - 1); } int HitboxRight(npc a) { return (a->X + a->HitXOffset + a->HitWidth - 1); } int HitboxRight(ffc a) { return a->X + a->TileWidth*16 - 1; } // Returns the Y coordinate of the top edge of the hitbox. int HitboxTop(eweapon a) { return (a->Y + a->HitYOffset); } int HitboxTop(lweapon a) { return (a->Y + a->HitYOffset); } int HitboxTop(item a) { return (a->Y + a->HitYOffset); } int HitboxTop(npc a) { return (a->Y + a->HitYOffset); } int HitboxTop(ffc a) { return a->Y; } // Returns the Y coordinate of the bottom edge of the hitbox. int HitboxBottom(eweapon a) { return (a->Y + a->HitYOffset + a->HitHeight - 1); } int HitboxBottom(lweapon a) { return (a->Y + a->HitYOffset + a->HitHeight - 1); } int HitboxBottom(item a) { return (a->Y + a->HitYOffset + a->HitHeight - 1); } int HitboxBottom(npc a) { return (a->Y + a->HitYOffset + a->HitHeight - 1); } //Uses TileWidth and TileHeight for the FFC's bounding box. int HitboxBottom(ffc a) { return a->Y + (a->TileHeight*16) - 1; } //Returns the number of an FFC, and -1 for a non-valid FFC (which should never happen) int FFCNum(ffc f) { for(int i=1; i<=32; i++) if(f == Screen->LoadFFC(i)) return i; return -1; } //Functions for those who are not comfortable with binary //Returns true if the left mouse button is pressed bool InputLeftClick() { return (Link->InputMouseB&MB_LEFTCLICK) != 0; } //Returns true if the right mouse button is pressed bool InputRightClick() { return (Link->InputMouseB&MB_RIGHTCLICK) != 0; } //Returns the item ID of the item equipped to Link's A button int GetEquipmentA() { return (Link->Equipment&0xFF); } //Returns the item ID of the item equipped to Link's B button int GetEquipmentB() { return ((Link->Equipment&0xFF00)>>8); } //Returns true if Link is using item 'id' bool UsingItem(int id){ return (GetEquipmentA() == id && Link->InputA) || (GetEquipmentB() == id && Link->InputB); } //Returns the number of Triforce Pieces Link currently has int NumTriforcePieces(){ int ret = 0; for(int i=1;i<=8;i++) if(Game->LItems[i]&LI_TRIFORCE) ret++; return ret; } //Returns 1 if Screen Flag 'flag' is set from category 'category', 0 if it's not and -1 if an invalid flag is passed //Flags are numbered starting from 0 int ScreenFlag(int category, int flag) { int catsizes[] = {3,7,5,3,2,4,4,2,3,7}; if(flag < 0 || flag >= catsizes[category]) return -1; return Screen->Flags[category]&(1<= catsizes[category]) return -1; return Screen->EFlags[category]&(1<DMapFlags[dmap]&flag)!=0; } //Sets a certain DMap flag to 'state' void SetDMapFlag(int dmap, int flag, bool state){ if(state) Game->DMapFlags[dmap] |= flag; else Game->DMapFlags[dmap] &= ~flag; } //Returns true if an item's Pickup state is set //Use the IP_ constants for the 'pickup' argument of this function bool GetItemPickup(item i, int pickup) { return (i->Pickup&pickup) != 0; } //Sets an item's Pickup state to 'state' void SetItemPickup(item i, int pickup, bool state) { if(state) i->Pickup |= pickup; else i->Pickup &= ~pickup; } //Returns true if an npc's Misc. flag is set. bool GetNPCMiscFlag(npc e, int flag) { return (e->MiscFlags&flag) != 0; } //Returns true if Link has the level item 'itm' from level 'level' //Overloaded to use the current level if no 'level' arg is entered //Use the LI_ constants for the 'itm' argument bool GetLevelItem(int level, int itm) { return (Game->LItems[level]&itm) != 0; } bool GetLevelItem(int itm) { return (Game->LItems[Game->GetCurLevel()]&itm) != 0; } //Gives or removes a level item from Link's inventory void SetLevelItem(int level, int itm, bool state) { if(state) Game->LItems[level] |= itm; else Game->LItems[level] &= ~itm; } void SetLevelItem(int itm, bool state) { if(state) Game->LItems[Game->GetCurLevel()] |= itm; else Game->LItems[Game->GetCurLevel()] &= ~itm; } //Create an NPC and set its X and Y position in one command npc CreateNPCAt(int id, int x, int y) { npc nme = Screen->CreateNPC(id); if(nme->isValid()) { nme->X = x; nme->Y = y; } return nme; } //Create an Item and set its X and Y position in one command item CreateItemAt(int id, int x, int y) { item it = Screen->CreateItem(id); if(it->isValid()) { it->X = x; it->Y = y; } return it; } //Create an LWeapon and set its X and Y position in one command lweapon CreateLWeaponAt(int id, int x, int y) { lweapon lw = Screen->CreateLWeapon(id); if(lw->isValid()) { lw->X = x; lw->Y = y; } return lw; } //Create an EWeapon and set its X and Y position in one command eweapon CreateEWeaponAt(int id, int x, int y) { eweapon ew = Screen->CreateEWeapon(id); if(ew->isValid()) { ew->X = x; ew->Y = y; } return ew; } //Creates an lweapon at 'distx,disty' away from where Link is facing lweapon NextToLink(int id, int distx, int disty) { lweapon l = CreateLWeaponAt(id, Link->X+InFrontX(Link->Dir, distx), Link->Y+InFrontY(Link->Dir, disty)); if(l->isValid()) { l->Dir = Link->Dir; } return l; } //Creates an lweapon 'dist' pixels away from the front of Link lweapon NextToLink(int id, int dist) { return NextToLink(id, dist, dist); } eweapon NextToNPC(npc n, int id, int distx, int disty) { eweapon e = CreateEWeaponAt(id, n->X+InFrontX(n->Dir, distx), n->Y+InFrontY(n->Dir, disty)); if(e->isValid()) { e->Dir = n->Dir; } return e; } eweapon NextToNPC(npc n, int id, int dist) { return NextToNPC(n, id, dist, dist); } //Aim-type constants, for use with AimEWeapon //**Moved** to std_constants.zh //Various methods for shooting at Link and at random void AimEWeapon(eweapon e, int aimtype) { int angle = RadianAngle(e->X, e->Y, Link->X, Link->Y); if(aimtype == AT_4DIR) { e->Dir = RadianAngleDir4(angle); } else if(aimtype == AT_8DIR) { e->Dir = RadianAngleDir8(angle); } else if(aimtype == AT_ANGULAR) { e->Angular = true; e->Angle = angle; e->Dir = RadianAngleDir8(angle); } else if(aimtype == AT_RAND4DIR) { e->Dir = Rand(4); } else if(aimtype == AT_RAND8DIR) { e->Dir = Rand(8); } else if(aimtype == AT_RANDANGULAR) { e->Angular = true; e->Angle = Randf(PI2); e->Dir = RadianAngleDir8(e->Angle); } } //Aiming at enemies and at random void AimLWeapon(lweapon l, npc n, int aimtype) { int angle = RadianAngle(l->X, l->Y, n->X, n->Y); if(aimtype == AT_4DIR) { l->Dir = RadianAngleDir4(angle); } else if(aimtype == AT_8DIR) { l->Dir = RadianAngleDir8(angle); } else if(aimtype == AT_ANGULAR) { l->Angular = true; l->Angle = angle; l->Dir = RadianAngleDir8(angle); } else AimLWeapon(l, aimtype); } void AimLWeapon(lweapon l, int aimtype) { if(aimtype == AT_RAND4DIR) { l->Dir = Rand(4); } else if(aimtype == AT_RAND8DIR) { l->Dir = Rand(8); } else if(aimtype == AT_RANDANGULAR) { l->Angular = true; l->Angle = Randf(PI2); l->Dir = RadianAngleDir8(l->Angle); } } //Turns a WPN_ constant to an EW_ constant int WeaponTypeToID(int wpnt) { if(wpnt == WPN_ENEMYFLAME) return EW_FIRE; else if(wpnt == WPN_ENEMYWIND) return EW_WIND; else if(wpnt == WPN_ENEMYFIREBALL) return EW_FIREBALL; else if(wpnt == WPN_ENEMYARROW) return EW_ARROW; else if(wpnt == WPN_ENEMYBRANG) return EW_BRANG; else if(wpnt == WPN_ENEMYSWORD) return EW_BEAM; else if(wpnt == WPN_ENEMYROCK) return EW_ROCK; else if(wpnt == WPN_ENEMYMAGIC) return EW_MAGIC; else if(wpnt == WPN_ENEMYBOMB) return EW_BOMB; else if(wpnt == WPN_ENEMYSBOMB) return EW_SBOMB; else if(wpnt == WPN_ENEMYLITBOMB) return EW_BOMBBLAST; else if(wpnt == WPN_ENEMYLITSBOMB) return EW_SBOMBBLAST; else if(wpnt == WPN_ENEMYFIRETRAIL) return EW_FIRETRAIL; else if(wpnt == WPN_ENEMYFLAME2) return EW_FIRE2; else if(wpnt == WPN_ENEMYFIREBALL2) return EW_FIREBALL2; return -1; } //Removes LWeapon 'l' from the screen void Remove(lweapon l){ if(!l->isValid()) return; l->DeadState = WDS_DEAD; l->X = 32768; } //Removes EWeapon 'e' from the screen void Remove(eweapon e){ if(!e->isValid()) return; e->DeadState = WDS_DEAD; e->X = 32768; } //Removes Item 'i' from the screen void Remove(item i){ if(!i->isValid()) return; i->X = 32768; } //Removes NPC 'n' from the screen void Remove(npc n){ if(!n->isValid()) return; n->X = 32768; n->HP = -1000; } //Creates a timeout item (like a rupee or heart) item CreateTimeoutItem(int id, int x, int y) { item Spawn = Screen->CreateItem(id); SetItemPickup(Spawn, IP_TIMEOUT, true); Spawn->HitWidth = 16; Spawn->HitHeight = 16; Spawn->X = x; Spawn->Y = y; } // Use the I_ constants. // Warning: these iterate over every onscreen item. // Iterating over every onscreen lweapon multiple times per frame may // cause slowdown in Zelda Classic. int NumItemsOf(int type) { int ret = 0; item it; for (int i = Screen->NumItems(); i >0 ; i--) { it = Screen->LoadItem(i); if (it->ID == type) ret++; } return ret; } // Use the LW_ constants. // Warning: these iterate over every onscreen lweapon. // Iterating over every onscreen lweapon multiple times per frame may // cause slowdown in Zelda Classic. int NumLWeaponsOf(int type) { int ret = 0; lweapon w; for (int i = Screen->NumLWeapons(); i > 0; i--) { w = Screen->LoadLWeapon(i); if (w->ID == type) ret++; } return ret; } int NumEWeaponsOf(int type) { int ret = 0; eweapon w; for (int i = Screen->NumEWeapons(); i > 0; i--) { w = Screen->LoadEWeapon(i); if (w->ID == type) ret++; } return ret; } int NumNPCsOf(int type) { int ret = 0; npc n; for (int i = Screen->NumNPCs(); i > 0 ; i--) { n = Screen->LoadNPC(i); if (n->ID == type) ret++; } return ret; } // Returns the first LWeapon of the given type. Use the LW_ constants. // If none exist, it returns an uninitialised pointer. lweapon LoadLWeaponOf(int type) { lweapon w; for (int i=1; i <= Screen->NumLWeapons(); i++) { w = Screen->LoadLWeapon(i); if (w->ID == type) return w; } lweapon w2; return w2; } // Returns the first EWeapon of the given type. Use the EW_ constants. // If none exist, it returns an uninitialised pointer. eweapon LoadEWeaponOf(int type) { eweapon w; for (int i=1; i <= Screen->NumEWeapons(); i++) { w = Screen->LoadEWeapon(i); if (w->ID == type) return w; } eweapon w2; return w2; } // Returns the first NPC of the given type. Use the NPCT_ constants. // If none exist, it returns an uninitialised pointer. npc LoadNPCOfType(int type) { npc n; for (int i=1; i <= Screen->NumNPCs(); i++) { n = Screen->LoadNPC(i); if (n->Type == type) return n; } npc n2; return n2; } // Returns the first NPC of the given ID. Use the NPC_ constants. // If none exist, it returns an uninitialised pointer. npc LoadNPCOf(int type) { npc n; for (int i=1; i <= Screen->NumNPCs(); i++) { n = Screen->LoadNPC(i); if (n->ID == type) return n; } npc n2; return n2; } //Returns the position of the first instance of the given combo, or -1. int FirstComboOf(int t, int layer) { for (int i = 0; i < 176; i++) { if (layer == 0) { if (Screen->ComboD[i] == t) return i; } else { if (GetLayerComboD(layer,i) == t) return i; } } return -1; } //Returns the position of the last instance of the given combo, or -1. int LastComboOf(int t, int layer) { for (int i = 175; i >= 0; i--) { if (layer == 0) { if (Screen->ComboD[i] == t) return i; } else { if (GetLayerComboD(layer,i) == t) return i; } } return -1; } //Returns the position of the first instance of the given combo, or -1. int FirstComboTypeOf(int t, int layer) { for (int i = 0; i < 176; i++) { if (layer == 0) { if (Screen->ComboT[i] == t) return i; } else { if (GetLayerComboT(layer,i) == t) return i; } } return -1; } //Returns the position of the last instance of the given combo, or -1. int LastComboTypeOf(int t, int layer) { for (int i = 175; i >= 0; i--) { if (layer == 0) { if (Screen->ComboT[i] == t) return i; } else { if (GetLayerComboT(layer,i) == t) return i; } } return -1; } //Returns the position of the first instance of the given combo flag, or -1. //Checks inherent flags too! int FirstComboFlagOf(int t, int layer) { for (int i = 0; i < 176; i++) { if (layer == 0) { if (Screen->ComboF[i] == t || Screen->ComboI[i] == t) return i; } else { if (Game->GetComboFlag(Screen->LayerMap(layer), Screen->LayerScreen(layer),i) == t || Game->GetComboInherentFlag(Screen->LayerMap(layer), Screen->LayerScreen(layer),i) == t) return i; } } return -1; } //Returns the position of the last instance of the given combo flag, or -1. //Checks inherent flags too! int LastComboFlagOf(int t, int layer) { for (int i = 175; i >= 0; i--) { if (layer == 0) { if (Screen->ComboF[i] == t || Screen->ComboI[i] == t) return i; } else { if (Game->GetComboFlag(Screen->LayerMap(layer), Screen->LayerScreen(layer),i) == t || Game->GetComboInherentFlag(Screen->LayerMap(layer), Screen->LayerScreen(layer),i) == t) return i; } } return -1; } // Returns true if the combo at the given position is water. bool IsWater(int position) { int combo=Screen->ComboT[position]; if(combo==CT_WATER || combo==CT_SWIMWARP || combo==CT_DIVEWARP || (combo>=CT_SWIMWARPB && combo<=CT_DIVEWARPD)) return true; else return false; } // Returns true if the combo at the given position is a pit. bool IsPit(int position) { int combo=Screen->ComboT[position]; if(combo==CT_PIT || combo==CT_PITR || (combo>=CT_PITB && combo<=CT_PITD)) return true; else return false; } //Creates and returns an exact copy of the passed LWeapon. Assumes that the passed pointer is valid. lweapon Duplicate(lweapon a) { lweapon b = Screen->CreateLWeapon(a->ID); b->X = a->X; b->Y = a->Y; b->Z = a->Z; b->Jump = a->Jump; b->Extend = a->Extend; b->TileWidth = a->TileWidth; b->TileHeight = a->TileHeight; b->HitWidth = a->HitWidth; b->HitHeight = a->HitHeight; b->HitZHeight = a->HitZHeight; b->HitXOffset = a->HitXOffset; b->HitYOffset = a->HitYOffset; b->DrawXOffset = a->DrawXOffset; b->DrawYOffset = a->DrawYOffset; b->DrawZOffset = a->DrawZOffset; b->Tile = a->Tile; b->CSet = a->CSet; b->DrawStyle = a->DrawStyle; b->Dir = a->Dir; b->OriginalTile = a->OriginalTile; b->OriginalCSet = a->OriginalCSet; b->FlashCSet = a->FlashCSet; b->NumFrames = a->NumFrames; b->Frame = a->Frame; b->ASpeed = a->ASpeed; b->Damage = a->Damage; b->Step = a->Step; b->Angle = a->Angle; b->Angular = a->Angular; b->CollDetection = a->CollDetection; b->DeadState = a->DeadState; b->Flash = a->Flash; b->Flip = a->Flip; for (int i = 0; i < 16; i++) b->Misc[i] = a->Misc[i]; return b; } //Creates and returns an exact copy of the passed EWeapon. Assumes that the passed pointer is valid. eweapon Duplicate(eweapon a) { eweapon b = Screen->CreateEWeapon(a->ID); b->X = a->X; b->Y = a->Y; b->Z = a->Z; b->Jump = a->Jump; b->Extend = a->Extend; b->TileWidth = a->TileWidth; b->TileHeight = a->TileHeight; b->HitWidth = a->HitWidth; b->HitHeight = a->HitHeight; b->HitZHeight = a->HitZHeight; b->HitXOffset = a->HitXOffset; b->HitYOffset = a->HitYOffset; b->DrawXOffset = a->DrawXOffset; b->DrawYOffset = a->DrawYOffset; b->DrawZOffset = a->DrawZOffset; b->Tile = a->Tile; b->CSet = a->CSet; b->DrawStyle = a->DrawStyle; b->Dir = a->Dir; b->OriginalTile = a->OriginalTile; b->OriginalCSet = a->OriginalCSet; b->FlashCSet = a->FlashCSet; b->NumFrames = a->NumFrames; b->Frame = a->Frame; b->ASpeed = a->ASpeed; b->Damage = a->Damage; b->Step = a->Step; b->Angle = a->Angle; b->Angular = a->Angular; b->CollDetection = a->CollDetection; b->DeadState = a->DeadState; b->Flash = a->Flash; b->Flip = a->Flip; for (int i = 0; i < 16; i++) b->Misc[i] = a->Misc[i]; return b; } //This should allow any scripted object to easily mimic Link styled LOZ solidity collision //checking, be it Link, FFCs, or enemies. //Note - You should use full_tile=true if you don't want the upper eight pixels to overlap //solid combos as per LOZ1 behavior. bool CanWalk(int x, int y, int dir, int step, bool full_tile) { int c=8; int xx = x+15; int yy = y+15; if(full_tile) c=0; if(dir==0) return !(y-step<0||Screen->isSolid(x,y+c-step)||Screen->isSolid(x+8,y+c-step)||Screen->isSolid(xx,y+c-step)); else if(dir==1) return !(yy+step>=176||Screen->isSolid(x,yy+step)||Screen->isSolid(x+8,yy+step)||Screen->isSolid(xx,yy+step)); else if(dir==2) return !(x-step<0||Screen->isSolid(x-step,y+c)||Screen->isSolid(x-step,y+c+7)||Screen->isSolid(x-step,yy)); else if(dir==3) return !(xx+step>=256||Screen->isSolid(xx+step,y+c)||Screen->isSolid(xx+step,y+c+7)||Screen->isSolid(xx+step,yy)); return false; //invalid direction } //Returns true if Link is on a sideview screen bool IsSideview() { return Screen->Flags[SF_ROOMTYPE] & 4; } //Returns true if the sprite at (x,y) is standing on a sideview platform on a sideview screen, as worked out //by ZC's internal code. //For 16 pixel high sprites only. bool OnSidePlatform(int x, int y) { return (Screen->isSolid(x+4,y+16) && Screen->isSolid(x+12,y+16) && Screen->Flags[SF_ROOMTYPE]&4); } //Returns true if a sprite of height 'h' at position (x,y) with an offset of (xOff,yOff) is standing //on a sideview platform on a sideview screen. bool OnSidePlatform(int x, int y, int xOff, int yOff, int h) { return (Screen->isSolid((x+xOff)+4,(y+yOff)+h) && Screen->isSolid((x+xOff)+12,(y+yOff)+h) && Screen->Flags[SF_ROOMTYPE]&4); } //Kills all of Link's inputs void NoAction() { Link->InputUp = false; Link->PressUp = false; Link->InputDown = false; Link->PressDown = false; Link->InputLeft = false; Link->PressLeft = false; Link->InputRight = false; Link->PressRight = false; Link->InputR = false; Link->PressR = false; Link->InputL = false; Link->PressL = false; Link->InputA = false; Link->PressA = false; Link->InputB = false; Link->PressB = false; Link->InputEx1 = false; Link->PressEx1 = false; Link->InputEx2 = false; Link->PressEx2 = false; Link->InputEx3 = false; Link->PressEx3 = false; Link->InputEx4 = false; Link->PressEx4 = false; } //NoAction, then Waitframe or (equivalent of) Waitframes void WaitNoAction() { NoAction(); Waitframe(); } void WaitNoAction(int frames) { for(int i = 0; i < frames; i++) WaitNoAction(); } //Get an NPC's name from an ID void GetNPCName(int ID, int string) { npc n = Screen->CreateNPC(ID); n->GetName(string); Remove(n); } void GetMessage(int ID, int string) { Game->GetMessage(ID, string); int i; for(i = MAX_MESSAGELENGTH-2; string[i] == ' '; i--); string[i+1] = 0; } itemdata GetItemData(item i) { return Game->LoadItemData(i->ID); } int GetHighestLevelItem(int itemclass) { itemdata id; int ret = -1; int curlevel = -1000; //143 is default max items, increase if you add lots of your own for(int i = 0; i < 143; i++) { id = Game->LoadItemData(i); if(id->Family != itemclass) continue; if(id->Level > curlevel) { curlevel = id->Level; ret = i; } } return ret; } int GetHighestLevelItem(item i) { itemdata argid = GetItemData(i); int ret = i->ID; int curlevel = argid->Level; itemdata id; //143 is max items, decrease to improve speed if you need to for(int i = 0; i < 256; i++) { id = Game->LoadItemData(i); if(id->Family != argid->Family) continue; if(id->Level > curlevel) { curlevel = id->Level; ret = i; } } return ret; } // Convert between map and DMap screens int DMapToMap(int screen, int dmap) { return screen+Game->DMapOffset[dmap]; } int MapToDMap(int screen, int dmap) { return screen-Game->DMapOffset[dmap]; } //Safe Sqrt functions if an irrational number would be involved. //Returns square root of 'val'. Returns -32768 is a negative number, is passed as 'val'. Returns '0' for Sqrt(0). float SafeSqrt(float val){ if ( val > MAX_CONSTANT ) val = MAX_CONSTANT; if ( val > 0 && val <= MAX_CONSTANT ) return Sqrt(val); if ( val < 0 ) return -32678; return 0; } //Returns square root of 'val'. Returns 'specifyNegRet' if a negative value is passed as 'val'. Returns '0' for Sqrt(0). float SafeSqrt(float val, float specifyNegRet){ if ( val > MAX_CONSTANT ) val = MAX_CONSTANT; if ( val > 0 && val <= MAX_CONSTANT ) return Sqrt(val); if ( val < 0 ) return specifyNegRet; return 0; } //Fairly select between true or false. int ChooseB(){ return Rand(0,1); } //Trace each index of an array, and print strings to make them legible. void TraceArray(int arr){ int str[]="Tracing array with Pointer: "; int bufferPtr[7]=" "; itoa(arr,bufferPointer); int mainBuffer[40]=" "; strcat(str,mainBuffer); strcat(bufferPointer,mainBuffer); TraceNL(); TraceS(mainBuffer); TraceNL(); for ( int q = 0; q <= SizeOfArray(arr); q++ ) { int str2[]="Index: "; int str3[]="is : "; int buffer[22]=" "; int bufferAmt[7]=" "; int bufferIndex[7]=" "; itoa(arr[q],bufferAmt); itoa(q,bufferIndex); strcat(str2,buffer); strcat(bufferIndex,buffer); strcat(str3,buffer); strcat(bufferAmt,buffer); TraceS(buffer); TraceNL(); } } //Shorthand for TraceArray() void TraceA(int arr){ TraceArray(arr); }