Jump to content

Photo

Mirrored Room FFC

Request

  • Please log in to reply
14 replies to this topic

#1 symbiote01

symbiote01

    Doyen(ne)

  • Members
  • Real Name:Doug
  • Location:WA

Posted 10 July 2015 - 11:53 PM

e28a69d3-ee44-494e-99e4-d32a760f4e60.png

 

Okay, I've been contemplating this for a while now, and even talked about it a little in Script Discussion.  I'm looking to make reflections of Link, enemies, and the various weapons in the 'mirror' (visually a work in progress).  I've tried coding this myself, but all it leads to is frustration.  

 

I'm in search of someone willing to do a mirror script for me:

 

It would probably be an FFC script, where the location of the FFC equals the edge of the mirror itself (so, somewhere along the plane where the mirror meets the floor).  The plan was to track Link's position relative to the FFC (horizontal plane), and draw an eweapon of Link's current tile (flipped so up is down, etc) at the location above it [so,eweapon->X = FFC->X - (Link->X - FFC->X) and eweapon->Y = Link->Y].  Repeat this effect for enemies, lweapons, and other eweapons (and maybe combo with a flag... say flag 100).  I've heard it is possible- but it's beyond me.

 

Purely visual?  One possible application might be to make enemies that are invisible, but their reflection aren't.  Or push blocks or switches that are in the mirror but not outside it.

 

I can assign flags to the mirror so that it reflects magic, etc, so that isn't a problem.


  • Jared, SkyLizardGirl and Dark Ice Dragon like this

#2 ywkls

ywkls

    Master

  • Members

Posted 11 July 2015 - 01:19 AM

I've been thinking about doing something like this for an event later in my game, but there's a big problem with the idea. For every enemy, projectile or whatever onscreen; there'd have to be a corresponding script or ffc to handle it. Since we only have 32 to work with; that pretty much limits the potential number of things on any screen that used this effect.

 

The second problem is synchronizing the movement of the ffc's animation with whatever is moving. The speed of Link's animation, the enemy's animation and so forth would have to be known. Why? Because the essence of doing this is to create a whole bunch of combos that look like whatever is supposed to be mirrored.

 

That adds in a third problem. What is Link is doing something other than just walking around? Well, then we've got to figure out what he's doing and if that includes using an item; figure out which one and properly mirror it too!

 

But...

 

The actual code for mirroring anything is fairly simple. Here it is.

import "std.zh"

const int LINK_MIRROR = 31680;//Combo number for first of 8 combos corresponding to Link's sprite.
//In this order. Facing Down Unmoving, Facing Down Moving, Facing Up Unmoving, Facing Up Moving.
//Facing Left Unmoving, Facing Left Moving, Facing Right Unmoving, Facing Right Moving.


ffc script Link_Mirror_Effect{
     void run(){
           int LastY;
           int LastX;
           while(true){
                if(Link->Dir == DIR_UP && Link->Y == LastY)this->Data = LINK_MIRROR;
                else if(Link->Dir == DIR_UP && Link->Y != LastY)this->Data = LINK_MIRROR+1;
                else if(Link->Dir == DIR_DOWN && Link->Y == LastY)this->Data = LINK_MIRROR+2;
                else if(Link->Dir == DIR_DOWN && Link->Y != LastY)this->Data = LINK_MIRROR+3;
                else if(Link->Dir == DIR_LEFT && Link->X == LastX)this->Data = LINK_MIRROR+4;
                else if(Link->Dir == DIR_LEFT && Link->X != LastX)this->Data = LINK_MIRROR+5;
                else if(Link->Dir == DIR_RIGHT && Link->X == LastX)this->Data = LINK_MIRROR+6;
                else if(Link->Dir == DIR_RIGHT && Link->X != LastX)this->Data = LINK_MIRROR+7;
                this->X = Link->X;
                //The vertical movement is current set up to make it where the ffc starts at the top edge of a room with walls two combos thick.
                //This code would have to change is the mirror was elsewhere.
                if(Link->Y < LastY  && Abs(Link->Y-this->Y) >16)this->Y++;
                else if(Link->Y > LastY  && Abs(Link->Y-this->Y) >16)this->Y--;
                LastX = Link->X;
                LastY = Link->Y;
                Waitframe();
           }
     }
}
           

In this example, I created a combo that was Link facing down and not moving, followed by facing down and moving, facing up unmoving, facing up moving, facing left unmoving, facing left moving, facing right unmoving and facing right moving.

 

Testing it out, the animations don't quite match Link's but otherwise it looks just like I'd imagine it would. So, you'd just have to do the same for every enemy, weapon or whatever was supposed to be on the screen, then create a script to handle it. Maybe like this...

ffc script Enemy_Mirror_Effect{
     void run(int enemyCombo, int enemyID){
           int LastY;
           npc n;
           bool copy;
           for(i = 0; i<Screen->NumNPCs(); i++){
               n= Screen->LoadNPC(i);
               if(n->ID = enemyID)copy = true;
           }
           int LastX;
           while(copy){
                if(n->Dir == DIR_UP && n->Y == LastY)this->Data = enemyCombo;;
                else if(n->Dir == DIR_UP && n->Y != LastY)this->Data = enemyCombo+1;
                else if(n->Dir == DIR_DOWN && n->Y == LastY)this->Data = enemyCombo+2;
                else if(n->Dir == DIR_DOWN && n->Y != LastY)this->Data = enemyCombo+3; 
                else if(n->Dir == DIR_LEFT && n->X == LastX)this->Data = enemyCombo+4; 
                else if(n->Dir == DIR_LEFT && n->X != LastX)this->Data = enemyCombo+5; 
                else if(n->Dir == DIR_RIGHT && n->X == LastX)this->Data = enemyCombo+6; 
                else if(n->Dir == DIR_RIGHT && n->X != LastX)this->Data = enemyCombo+7; 
                this->X = n->X; 
                if(n->Y < LastY && Abs(n->Y-this->Y) >16)this->Y++; 
                else if(n->Y > LastY && Abs(n->Y-this->Y) >16)this->Y--; 
                LastX = n->X; 
                LastY = n->Y;
                if(n->HP <=- || !n->isValid())break; 
                Waitframe(); 
           }
           this->Data = 0; 
      } 
}

The only problem I can see with this is that you couldn't have more than one of each type of enemy on the screen. But it would be very easy to use for the 'enemies only visible in mirror' idea.

 

I'll see if I can figure out how to do the block pushing thing later.

 

I'd also like to request a copy of those tiles used for the mirror.

 

Edit: Your idea of using eweapons for this would work, I think. I'll have to see if I can figure out a way to put it into use.


Edited by ywkls, 11 July 2015 - 01:38 AM.

  • SkyLizardGirl likes this

#3 Lejes

Lejes

    Seeker of Runes

  • Members
  • Location:Flying High Above Monsteropolis

Posted 11 July 2015 - 02:15 AM

I think the easiest way to do this is to simply scan for every enemy, weapon, flagged combo, etc. in the room with for loops and do DrawTile and DrawCombo as appropriate. That way, there isn't a limit of 32 objects. Assuming you don't want to have a completely flat mirror (like the one in the screen mockup), you would need a careful layer set up. You don't want the mirror images to show up in front of anything outside the mirror, but you want them to still be behind those pillars.

Edited by Lejes, 11 July 2015 - 02:15 AM.

  • ywkls likes this

#4 Unames

Unames

    Newbie

  • Members

Posted 11 July 2015 - 03:44 AM

I have tried to do something like this in the past, and the only way this could be done effectively would be to set up specific rules for each enemy and item that would be present in the mirror room, as simply flipping the tile has issues with perspective. I wrote some code for the method of vertically flipping the tile.

.SZQQH9E.png 

The script to do this was something like this:

global script slot2{
     void run(){
        while (true){
              Waitdraw();
              if(Screen->Flags[SF_MISC]&0x008) //Flag script 2
			{
				for (int i = 1; i <= Screen->NumNPCs(); i++)
				{
					npc enm = Screen->LoadNPC(i);
					Screen->DrawTile(2, enm->X, enm->Y + 16, enm->Tile, 1, 1, enm->CSet, 16, 8, 0, 0, 0, 2, true, 64);
				}
				for (int i = 1; i <= Screen->NumLWeapons(); i++)
				{
					lweapon wpn = Screen->LoadLWeapon(i);
					int fl = wpn->Flip;
					if (fl > 1) {fl -= 2;}
					else {fl += 2;}
					Screen->DrawTile(2, wpn->X, wpn->Y + 16, wpn->Tile, 1, 1, wpn->CSet, 16, 8, 0, 0, 0, fl, true, 64);
				}
				for (int i = 1; i <= Screen->NumEWeapons(); i++)
				{
					eweapon wpn = Screen->LoadEWeapon(i);
					int fl = wpn->Flip;
					if (fl > 1) {fl -= 2;}
					else {fl += 2;}
					Screen->DrawTile(2, wpn->X, wpn->Y + 16, wpn->Tile, 1, 1, wpn->CSet, 16, 8, 0, 0, 0, fl, true, 64);
				}
				Screen->DrawTile(2, Link->X, Link->Y + 16, Link->Tile, 1, 1, 6, 16, 8, 0, 0, 0, 2, true, 64);
			}
              Waitframe();
           }
     }
} 

Note that this code is designed for reflections from above, does not work correctly with most lweapons and with some enemies.

 

Ensuring the reflections are only drawn in the mirror can be done by setting layer 2 or 3 as background and putting the frame of the mirror and everything else on layer 0 and above, with the glass of the mirror on the background layer. The draw commands can then be set up to draw on the background layer.

n6E8kB4.png


  • Jared and ywkls like this

#5 ywkls

ywkls

    Master

  • Members

Posted 11 July 2015 - 12:16 PM

Based on the code by Unames, I came up with a way to do this using just an ffc. However, it still has a few bugs. Here's the code and an explanation of the bugs.

import "std.zh"


ffc script Mirror_Effect{
     void run(){
           int LastX;
           int LastY;
           int LastEnemyY;
           int LastEWY;
           int LastLWY;
           int EnemyCopyY;
           int EWCopyY;
           int LWCopyY;
           int Link_tile;
           while(true){
                //Match tiles with Link. Currently offset for the amount of frames in my animation of Link.     
                if(Link->Dir == DIR_UP)Link_tile= Link->Tile+3;
                else if(Link->Dir == DIR_DOWN && Link->Y == LastY)Link_tile= Link->Tile-3;
                else{
                      Link_tile = Link->Tile;
                }
                //The vertical movement is current set up to make it where the ffc starts at the top edge of a room with walls two combos thick.
                //This code would have to change is the mirror was elsewhere.
                if(Link->Y < LastY  && Abs(Link->Y-this->Y) >16)this->Y++;
                else if(Link->Y > LastY  && Abs(Link->Y-this->Y) >16)this->Y--;
                Screen->DrawTile(2, Link->X, this->Y, Link_tile, 1, 1, 6, 16, 16, 0, 0, 0, 0, true, 64);
                //Track all enemies in the room.
                for (int i = 1; i <= Screen->NumNPCs(); i++){
		     npc enm = Screen->LoadNPC(i);
                     int tile;
                     //Change tile base on enemy's direction. Currently set up for a enemy with 4 frames of animation.
                     if(enm->Dir == DIR_UP)tile = enm->Tile+4;
                     else if (enm->Dir ==DIR_DOWN)tile = enm->Tile-4;
                     else{
                          tile = enm->Tile;
                     }
                     //Sometimes the enemy movement code works. Sometimes it doesn't.
                     if(enm->Y < LastEnemyY  && Abs(enm->Y-EnemyCopyY) >16)EnemyCopyY++;
                     else if(enm->Y > LastEnemyY  && Abs(enm->Y-EnemyCopyY) >16)EnemyCopyY--;
                     Screen->DrawTile(2, enm->X, EnemyCopyY, tile, 1, 1, enm->CSet, 16, 16, 0, 0, 0, 0, true, 64);
                     LastEnemyY = enm->Y;
                }
                //Track all Lweapons. Offset if Link is facing up or down.
		for (int i = 1; i <= Screen->NumLWeapons(); i++){
		     lweapon wpn = Screen->LoadLWeapon(i);
		     int fl = wpn->Flip;
		     if (fl >1)fl = 0;
                     if(wpn->Y < LastLWY  && Abs(wpn->Y-LWCopyY) >16)LWCopyY++;
                     else if(wpn->Y > LastLWY  && Abs(wpn->Y-LWCopyY) >16)LWCopyY--;
                     //This is supposed to adjust the position of the lweapon based on whether you're facing up, down, left or right and whether you're moving.
                     //Stationary Lweapons like bombs are trickier to follow.
                     //The hookshot chain cannot be created this way.
                     if(Link->Dir == DIR_UP&& Link->Y == LastY)Screen->DrawTile(2, wpn->X, this->Y+16, wpn->Tile, 1, 1, wpn->CSet, 16, 16, 0, 0, 0, fl, true, 64);
                     else if(Link->Dir == DIR_DOWN && Link->Y == LastY)Screen->DrawTile(2, wpn->X, this->Y-16, wpn->Tile, 1, 1, wpn->CSet, 16, 16, 0, 0, 0, fl, true, 64);
                     else if(Link->Dir == DIR_UP && Link->Y != LastY)Screen->DrawTile(2, wpn->X,LWCopyY+16, wpn->Tile, 1, 1, wpn->CSet, 16, 16, 0, 0, 0, fl, true, 64);
                     else if(Link->Dir == DIR_DOWN && Link->Y != LastY)Screen->DrawTile(2, wpn->X, LWCopyY-16, wpn->Tile, 1, 1, wpn->CSet, 16, 16, 0, 0, 0, fl, true, 64);
                     //I've gotten this code to work for facing all directions before, but left and right seem to have decided to malfunction.
                     else{
                          Screen->DrawTile(2, wpn->X, LWCopyY-16, wpn->Tile, 1, 1, wpn->CSet, 16, 16, 0, 0, 0, fl, true, 64);
                     }
                     LastLWY = wpn->Y;
                }
                //Track all Eweapons. This actually seems to work.
		for (int i = 1; i <= Screen->NumEWeapons(); i++){
		     eweapon wpn = Screen->LoadEWeapon(i);
	             int fl = wpn->Flip;
		     if (fl >1)fl = 0;
                     if(wpn->Y < LastEWY  && Abs(wpn->Y-EWCopyY) >16)EWCopyY++;
                     else if(wpn->Y > LastEWY  && Abs(wpn->Y-EWCopyY) >16)EWCopyY--;
                     Screen->DrawTile(2, wpn->X, EWCopyY, wpn->Tile, 1, 1, wpn->CSet, 16, 16, 0, 0, 0, 0, true, 64);                    
                     LastEWY = wpn->Y;
                }
                LastX = Link->X;
                LastY = Link->Y;
                Waitframe();
           }
     }
}

The code that makes the tiles for the duplicate enemies move vertically at the same time as their counterparts works sometimes, and sometimes it doesn't. Since that code is identical to all the rest of the code, I don't know why this is happening. 

 

Getting the lweapons to work properly is the part I'm having the most trouble with.


Edited by ywkls, 11 July 2015 - 12:21 PM.


#6 symbiote01

symbiote01

    Doyen(ne)

  • Members
  • Real Name:Doug
  • Location:WA

Posted 13 July 2015 - 04:09 PM

So, here's an updated version of the game in-action:

Mirror_Room42.png

I am using a modified version of ywkls code (see below).  Ignore the little red arrows at the bottom left of the mirror- they are pointing to the bottom edge of the ffc itself.  Also, I had cheats on and was invincible, and the screencap just happened to get my Wizzrobe when he flashed red.  His actual color is reflected properly.

 

What it currently does:

  • Mirrors Link (or in my case, the Wizzrobe).  Note the reflection shows the Wizzrobe's backside, while the original shows his front (while facing right)
  • Mirrors his weapons (minus the hookshot chain and some scripted effects).
  • Mirrors 1x1 enemies.  Again, the blue darknut's reflection shows his shield, while the original's shield is mostly behind.  Likewise, the red darknut reflection is holding his sword left-handed, while the original is obviously right-handed.  The mirror darknut (!) was out of the mirror's visual range, but his reflection works, too.
  • Mirrors enemy weapons.  Not very well pictured here- but I do know that it works.

What doesn't reflect (yet):

  • Spawned item reflection (like rupees, keys, or other drops).
  • Blocks and pots (those seen on the screen are mockups).  I plan to put a Flag on those and have the script look for the flag and copy their current tile.  It might not work for the pots- I haven't played with it yet.
  • Visible ffcs like scripted enemies, moving platforms, etc.
  • Enemies larger than 1x1.

Instead of moving the ffc around like ywkls did, I put it at a fixed position (the bottom edge of the mirror) and did Y-axis calculations based on that location (the Y position of the ffc minus n's Y distance from the ffc (plus an offset)).  This stabilized the reflections and automatically placed enemies, eweapons and lweapons in their proper place.

ffc script Mirror_Effect{
   void run(){
      int LastX;
      int LastY;
      int Link_tile;
      int Link_Flip;
      int LReflect_Y;
      int Reflect_YOffset = 22;  //The offset, in pixels, to draw various things
      while(true){
//Link's Reflection
   //Match tiles with Link. Currently offset for the amount of frames in my animation of Link.
   //Currently set up to use BSZelda-style Link movement.  
         if(Link->Dir == DIR_LEFT){
            Link_tile= Link->Tile+4; // Finds the Right tiles, because they can be different-
            Link_Flip = 1;  // and flips them horizontally, so they look face left.
            if(Link->Action == LA_ATTACKING) Link_tile=Link->Tile +1; // Finds the Right-attacking tile.  Already flipped, above.
         }else if(Link->Dir == DIR_RIGHT){
            Link_tile= Link->Tile-4; // Finds the Left tiles, as above-
            Link_Flip = 0;  // but doesn't flip them, because the game engine does that for you.
            if(Link->Action == LA_ATTACKING) Link_tile=Link->Tile -1; // Finds the Left-attacking tile.
         }else if(Link->Dir == DIR_DOWN){
            Link_tile = Link->Tile+4;
            Link_Flip = 1;
            if(Link->Action == LA_ATTACKING) Link_tile=Link->Tile +1;
         }else{
            Link_tile = Link->Tile-4;
            Link_Flip = 1;
            if(Link->Action == LA_ATTACKING) Link_tile=Link->Tile -1;
         }
   //  The vertical movement is currently set up to make it where the ffc is placed at the bottom edge of the mirror.  Unlike ywkls
   //  version, the ffc itself does not move- all movements are calculated based on the ffc's fixed position.
         LReflect_Y = this->Y - (Link->Y - this->Y)+Reflect_YOffset;
         Screen->DrawTile(1, Link->X, LReflect_Y, Link_tile, 1, 1, 6, 16, 16, 0, 0, 0, Link_Flip, true, 64);
//Enemy Reflection
   //Track all enemies in the room.
         for (int i = 1; i <= Screen->NumNPCs(); i++){
            npc enm = Screen->LoadNPC(i);
            int tile; int EReflect_Y;
    //Change tile base on enemy's direction. Currently set up for a enemy with 4 frames of animation.
            if(enm->Dir == DIR_LEFT){tile = enm->Tile+4;}
            else if (enm->Dir == DIR_RIGHT){tile = enm->Tile-4;}
            else if (enm->Dir == DIR_DOWN){tile = enm->Tile-4;}
            else{tile = enm->Tile+4;}
            EReflect_Y = this->Y - (enm->Y - this->Y)+Reflect_YOffset;
            Screen->DrawTile(1, enm->X, EReflect_Y, tile, 1, 1, enm->CSet, 16, 16, 0, 0, 0, 1, true, 64);
         }
//LWeapon Reflection
   //Track all Lweapons. Offset if Link is facing up or down.
         for (int i = 1; i <= Screen->NumLWeapons(); i++){
            lweapon wpn = Screen->LoadLWeapon(i);
            int fl = wpn->Flip; int LWReflect_Y;
            if (fl >1)fl = 0;
            LWReflect_Y = this->Y - (wpn->Y - this->Y)+Reflect_YOffset;
    //This is supposed to adjust the position of the lweapon based on whether you're facing up, down, left or right and whether you're moving.
    //Stationary Lweapons like bombs are trickier to follow.
    //The hookshot chain cannot be created this way.
            if(Link->Dir == DIR_UP&& Link->Y == LastY)Screen->DrawTile(1, wpn->X, LWReflect_Y, wpn->Tile, 1, 1, wpn->CSet, 16, 16, 0, 0, 0, 3, true, 64);
            else if(Link->Dir == DIR_DOWN && Link->Y == LastY)Screen->DrawTile(1, wpn->X, LWReflect_Y, wpn->Tile, 1, 1, wpn->CSet, 16, 16, 0, 0, 0, fl, true, 64);
            else if(Link->Dir == DIR_UP && Link->Y != LastY)Screen->DrawTile(1, wpn->X,LWReflect_Y, wpn->Tile, 1, 1, wpn->CSet, 16, 16, 0, 0, 0, fl, true, 64);
            else if(Link->Dir == DIR_DOWN && Link->Y != LastY)Screen->DrawTile(1, wpn->X, LWReflect_Y, wpn->Tile, 1, 1, wpn->CSet, 16, 16, 0, 0, 0, fl, true, 64);
            else{
               Screen->DrawTile(1, wpn->X, LWReflect_Y+6, wpn->Tile, 1, 1, wpn->CSet, 16, 16, 0, 0, 0, fl, true, 64);
            }
         }
//EWeapon Reflection
   //Track all Eweapons. This actually seems to work.
         for (int i = 1; i <= Screen->NumEWeapons(); i++){
            eweapon wpn = Screen->LoadEWeapon(i);
            int fl = wpn->Flip; int EWReflect_Y;
            if (fl >1)fl = 0;
            EWReflect_Y = this->Y - (wpn->Y - this->Y)+Reflect_YOffset;
            Screen->DrawTile(1, wpn->X, EWReflect_Y, wpn->Tile, 1, 1, wpn->CSet, 16, 16, 0, 0, 0, fl, true, 64);                   
         }
//Flag Reflection
   //Haven't figured this part out yet.
//Item Reflection
   //Haven't bothered with this part yet.
//Cleanup
         LastX = Link->X;
         LastY = Link->Y;
         Waitframe();
      }
   }
}

Edited by symbiote01, 13 July 2015 - 06:53 PM.

  • ywkls likes this

#7 ywkls

ywkls

    Master

  • Members

Posted 14 July 2015 - 09:17 AM

That seems to work much better than what I had. So far, I've attempted several different versions of this code since I last posted what I'd come up with, each of which had a load of problems. I'm not exactly sure how to do the whole 'reflected combos' part. I had a theory, but it didn't work so I'll have to do some more research. As for the item part, that seems to be even harder. As far as I can tell, scripts can detect how many items there are in a room, but I don't know if there is a way to tell where those items are at.

 

For larger enemies, I'd change this line of code as follows. I haven't tested it, but it should work.

 Screen->DrawTile(1, enm->X, EReflect_Y, tile, enm->TileWidth, enm->TileHeight, enm->CSet, 16, 16, 0, 0, 0, 1, true, 64);
         

Edited by ywkls, 14 July 2015 - 09:18 AM.


#8 symbiote01

symbiote01

    Doyen(ne)

  • Members
  • Real Name:Doug
  • Location:WA

Posted 14 July 2015 - 11:16 AM

UPDATE:

I seem to have overstated myself.  Currently, Hammers act very strangely in the mirror- I'll need to study it and do a specific case for that item.  Also, other Link actions (when using Dyn's fire, for example) cause strangeness for Link.  I imagine a few || statements to specify them would do the trick.



#9 Avaro

Avaro

    o_o

  • Members
  • Real Name:Robin
  • Location:Germany

Posted 14 July 2015 - 12:19 PM

Just an idea, but if you actually get this to work you could make a secret where a block or something looks slightly different in the mirror than it looks on the screen and that could be a hint that you have to do something with that block.


  • Espilan, symbiote01, Dark Ice Dragon and 1 other like this

#10 ywkls

ywkls

    Master

  • Members

Posted 14 July 2015 - 12:44 PM

Another thing I conceived of was secrets that had to be triggered by hitting their reflections, or paths or secrets that were only visible in the reflection. I may not be able to get any work on this done this week since I have other things to take care of that will be interfering with the amount of time I have for coding and Zelda Classic in general. But I will be thinking about it... and probably studying up on my notes on coding and such.


  • symbiote01 likes this

#11 Timelord

Timelord

    The Timelord

  • Banned
  • Location:Prydon Academy

Posted 15 July 2015 - 08:54 AM

I'll read through that massive block of code later this week, and see if I can simplify this. This may be a good use of script flags, layers, and transparency. Drawing enemies, and lweapons to a higher layer, and placing an overlay on top of that layer, to assign the mirror hue.

You can literally copy enemies, lweapons, sprites, and the like, globally, invert their coordinates, and invert their facing direction every frame...possibly placing all the mirror combos in an array, reading if they are on layer 3, and if so, drawing the inverted objects to layer 2. The reason the hammer, and hookshot are giving you problems, is because you can;t create, or duplicate them, but you can fake it.

Otherwise, this is a very cool idea, and flipping gorgeous. I may wish to use it in a game somewhere, meself.

Edited by ZoriaRPG, 15 July 2015 - 08:57 AM.

  • ywkls likes this

#12 symbiote01

symbiote01

    Doyen(ne)

  • Members
  • Real Name:Doug
  • Location:WA

Posted 15 July 2015 - 09:38 PM

So, here's another revised version.  It includes items and anything with Flag 102.  It still doesn't do enemies bigger than 1x1 though- it tries, but they are left-right flipped incorrectly (left side on the right and vice versa).  And sometimes the hammer does weird things still.

ffc script Mirror_Effect{
	void run(){
		int LastX;
		int LastY;
		int Link_tile;
		int Link_Flip;
		int LReflect_Y;
		int Reflect_YOffset = 22;  //The offset, in pixels, to draw various things
		while(true){

	//Enemy Reflection
			//Track all enemies in the room.
			for (int i = 1; i <= Screen->NumNPCs(); i++){
				npc enm = Screen->LoadNPC(i);
				int tile; int EReflect_Y;
				//Change tile base on enemy's direction. Currently set up for a enemy with 4 frames of animation.
				if(enm->Dir == DIR_LEFT){tile = enm->Tile+4;}
				else if (enm->Dir == DIR_RIGHT){tile = enm->Tile-4;}
				else if (enm->Dir == DIR_DOWN){tile = enm->Tile-4;}
				else{tile = enm->Tile+4;}
				EReflect_Y = this->Y - (enm->Y - this->Y)+Reflect_YOffset;
				Screen->DrawTile(1, enm->X, EReflect_Y, tile, enm->TileWidth, enm->TileHeight, enm->CSet, 16, 16, 0, 0, 0, 1, true, 64);
			}

	//LWeapon Reflection
			//Track all Lweapons. Offset if Link is facing up or down.
			for (int i = 1; i <= Screen->NumLWeapons(); i++){
				lweapon wpn = Screen->LoadLWeapon(i);
				int fl = wpn->Flip; int LWReflect_Y;
				if (fl >1)fl = 0;
				LWReflect_Y = this->Y - (wpn->Y - this->Y)+Reflect_YOffset;
				//This is supposed to adjust the position of the lweapon based on whether you're facing up, down, left or right and whether you're moving.
				//Stationary Lweapons like bombs are trickier to follow.
				//The hookshot chain cannot be created this way.
				if(Link->Dir == DIR_UP&& Link->Y == LastY)Screen->DrawTile(1, wpn->X, LWReflect_Y, wpn->Tile, 1, 1, wpn->CSet, 16, 16, 0, 0, 0, 3, true, 64);
				else if(Link->Dir == DIR_DOWN && Link->Y == LastY)Screen->DrawTile(1, wpn->X, LWReflect_Y, wpn->Tile, 1, 1, wpn->CSet, 16, 16, 0, 0, 0, fl, true, 64);
				else if(Link->Dir == DIR_UP && Link->Y != LastY)Screen->DrawTile(1, wpn->X,LWReflect_Y, wpn->Tile, 1, 1, wpn->CSet, 16, 16, 0, 0, 0, fl, true, 64);
				else if(Link->Dir == DIR_DOWN && Link->Y != LastY)Screen->DrawTile(1, wpn->X, LWReflect_Y, wpn->Tile, 1, 1, wpn->CSet, 16, 16, 0, 0, 0, fl, true, 64);
				//I've gotten this code to work for facing all directions before, but left and right seem to have decided to malfunction.
				else{
					Screen->DrawTile(1, wpn->X, LWReflect_Y+6, wpn->Tile, 1, 1, wpn->CSet, 16, 16, 0, 0, 0, fl, true, 64);
				}
			}

	//EWeapon Reflection
			//Track all Eweapons. This actually seems to work.
			for (int i = 1; i <= Screen->NumEWeapons(); i++){
				eweapon wpn = Screen->LoadEWeapon(i);
				int fl = wpn->Flip; int EWReflect_Y;
				if (fl >1)fl = 0;
				EWReflect_Y = this->Y - (wpn->Y - this->Y)+Reflect_YOffset;
				Screen->DrawTile(1, wpn->X, EWReflect_Y, wpn->Tile, 1, 1, wpn->CSet, 16, 16, 0, 0, 0, fl, true, 64);                    
			}
	//Flag Reflection
			//Haven't figured this part out yet.
			for (int i = 0; i <= 175; i++){
				if (ComboFI(i, CF_SCRIPT4)){
					int Flagtile = Screen->ComboD[i];
					int FReflect_Y = this->Y - (ComboY(i) - this->Y)+Reflect_YOffset+8;
					Screen->FastCombo(1, ComboX(i), FReflect_Y, Flagtile, 3, 128);
//					Screen->DrawTile(1, ComboX(i), FReflect_Y, Flagtile, 1, 1, 3, 16, 16, 0, 0, 0, 0, true, 128);
				}	
			}
	//Item Reflection- none of these will be flipped, because few if any items have a direction.  Yes, that means things like clocks will show the face in the mirror too. 
			for (int i = 1; i <= Screen->NumItems(); i++){
				item itm = Screen->LoadItem(i);
				int IReflect_Y = this->Y - (itm->Y - this->Y)+Reflect_YOffset+8;
				Screen->DrawTile(1, itm->X, IReflect_Y, itm->Tile, 1, 1, itm->CSet, 16,16,0, 0, 0, 0, true, 128);
			}
	//Link's Reflection
			//Match tiles with Link. Currently offset for the amount of frames in my animation of Link.
			//Currently set up to use BSZelda-style Link movement.
			//I moved this to the end so Link would be drawn last, above other tiles.
			if(Link->Dir == DIR_LEFT){
				Link_tile= Link->Tile+4;	// Finds the Right tiles, because they can be different-
				Link_Flip = 1;		// and flips them horizontally, so they look face left.
				if(Link->Action > 1) Link_tile=Link->Tile +1; // Finds the Right-attacking tile.  Already flipped, above.
			}else if(Link->Dir == DIR_RIGHT){
				Link_tile= Link->Tile-4;	// Finds the Left tiles, as above-
				Link_Flip = 0;		// but doesn't flip them, because the game engine does that for you.
				if(Link->Action > 1) Link_tile=Link->Tile -1; // If Link is attacking, using the hammer, etc, it does this.  This technically does stupid things
								// if Link is swimming, so don't use in rooms where when Link would be swimming.
			}else if(Link->Dir == DIR_DOWN){
				Link_tile = Link->Tile+4;
				Link_Flip = 1;
				if(Link->Action > 1) Link_tile=Link->Tile +1;
			}else{
				Link_tile = Link->Tile-4;
				Link_Flip = 1;
				if(Link->Action > 1) Link_tile=Link->Tile -1;
			}
			
			//  The vertical movement is currently set up to make it where the ffc is placed at the bottom edge of the mirror.  Unlike ywkls
			//  version, the ffc itself does not move- all movements are calculated based on the ffc's fixed position.
			LReflect_Y = this->Y - (Link->Y - this->Y)+Reflect_YOffset;
			Screen->DrawTile(1, Link->X, LReflect_Y, Link_tile, 1, 1, 6, 16, 16, 0, 0, 0, Link_Flip, true, 64);
			
	//Cleanup
			LastX = Link->X;
			LastY = Link->Y;
			Waitframe();
		}
	}
}

Edited by symbiote01, 15 July 2015 - 09:39 PM.


#13 Espilan

Espilan

    Peahat.

  • Members
  • Real Name:Michael
  • Location:Ohio

Posted 25 July 2015 - 01:45 AM

Just an idea, but if you actually get this to work you could make a secret where a block or something looks slightly different in the mirror than it looks on the screen and that could be a hint that you have to do something with that block.

 

What about something like the mirror rooms in certain levels in Kirby Triple Deluxe? If it doesn't show a reflection, it's not real, and if it does show a reflection, it is real. Kirby 3D also had the same mirrors showing reflections for things that were otherwise invisible. Would probably be a pain in the butt to set up, but it would be pretty cool to see.


Edited by Espilan, 25 July 2015 - 01:47 AM.


#14 symbiote01

symbiote01

    Doyen(ne)

  • Members
  • Real Name:Doug
  • Location:WA

Posted 25 July 2015 - 06:25 PM

Well, as written, invisible enemies WILL show up in the mirror.  LWeapons and EWeapons, I've discovered, behave strangely when fired directly at the mirror- once they cross the y-axis line created by the FFC, the reflection draws outside of the mirror.  This looks particularly bizarre with the Mace and Chain scripted weapon (both EWeapon and LWeapon form).  I haven't done it yet, but I'm sure it's an easy fix.

 

I added Script 4 as an Inherent flag for pots AND their undercombos in my game, so this script automatically reflects them.  As of right now, pots do not reflect the sprite when they break.  Sometimes enemies show their death sprite, other times not.  Dunno why.

 

To do what Espilan wants, I suppose you could specify certain EnemyIDs to NOT reflect.



#15 Alucard648

Alucard648

    Wizard

  • Members
  • Location:castle Dracula

Posted 08 April 2022 - 09:10 AM

My failed attempt at fixing the mirror script. Damn lweapons...

const int MIRROR_REFLECT_Y_OFFSET = 0;//The offset, in pixels, to draw various things
//Align FFC at bottom edge of mirror
ffc script Mirror_Image{
	void run(){
		int LastX;
		int LastY;
		int Link_tile;
		int Link_Flip;
		int LReflect_Y;
		while(true){

	//Enemy Reflection
			//Track all enemies in the room.
			for (int i = 1; i <= Screen->NumNPCs(); i++){
				npc enm = Screen->LoadNPC(i);
				int tile; int EReflect_Y;
				//Change tile base on enemy's direction. Currently set up for a enemy with 4 frames of animation.
				if(enm->Dir == DIR_LEFT){tile = enm->Tile+4;}
				else if (enm->Dir == DIR_RIGHT){tile = enm->Tile-4;}
				else if (enm->Dir == DIR_DOWN){tile = enm->Tile-4;}
				else{tile = enm->Tile+4;}
				EReflect_Y = this->Y - (enm->Y - this->Y)+MIRROR_REFLECT_Y_OFFSET;
				Screen->DrawTile(1, enm->X, EReflect_Y, tile, enm->TileWidth, enm->TileHeight, enm->CSet, -1, -1, 0, 0, 0, 1, true, 64);
			}

	//LWeapon Reflection
			//Track all Lweapons. Offset if Link is facing up or down.
			for (int i = 1; i <= Screen->NumLWeapons(); i++){
				lweapon wpn = Screen->LoadLWeapon(i);
				int fl = wpn->Flip; 
				int LWReflect_Y;
				//if (fl >1)fl = 0;
				if (fl<2)fl+=2;
				else fl-=2;
				LWReflect_Y = this->Y - (wpn->Y - this->Y)+MIRROR_REFLECT_Y_OFFSET;
				//This is supposed to adjust the position of the lweapon based on whether you're facing up, down, left or right and whether you're moving.
				//Stationary Lweapons like bombs are trickier to follow.
				//The hookshot chain cannot be created this way.
				if(Link->Dir == DIR_UP&& Link->Y == LastY)Screen->DrawTile(1, wpn->X, LWReflect_Y, wpn->Tile, 1, 1, wpn->CSet, -1, -1, 0, 0, 0, 3, true, 64);
				else if(Link->Dir == DIR_DOWN && Link->Y == LastY)Screen->DrawTile(1, wpn->X, LWReflect_Y, wpn->Tile, 1, 1, wpn->CSet, -1, -1, 0, 0, 0, fl, true, 64);
				else if(Link->Dir == DIR_UP && Link->Y != LastY)Screen->DrawTile(1, wpn->X,LWReflect_Y, wpn->Tile, 1, 1, wpn->CSet, -1, -1, 0, 0, 0, fl, true, 64);
				else if(Link->Dir == DIR_DOWN && Link->Y != LastY)Screen->DrawTile(1, wpn->X, LWReflect_Y, wpn->Tile, 1, 1, wpn->CSet, -1, -1, 0, 0, 0, fl, true, 64);
				//I've gotten this code to work for facing all directions before, but left and right seem to have decided to malfunction.
				else{
					Screen->DrawTile(1, wpn->X, LWReflect_Y+6, wpn->Tile, 1, 1, wpn->CSet, -1, -1, 0, 0, 0, fl, true, 64);
				}
			}

	//EWeapon Reflection
			//Track all Eweapons. This actually seems to work.
			for (int i = 1; i <= Screen->NumEWeapons(); i++){
				eweapon wpn = Screen->LoadEWeapon(i);
				int fl = wpn->Flip; int EWReflect_Y;
				if (fl >1)fl = 0;
				EWReflect_Y = this->Y - (wpn->Y - this->Y)+MIRROR_REFLECT_Y_OFFSET;
				Screen->DrawTile(1, wpn->X, EWReflect_Y, wpn->Tile, 1, 1, wpn->CSet, -1, -1, 0, 0, 0, fl, true, 64);                    
			}
	//Flag Reflection
			//Haven't figured this part out yet.
			for (int i = 0; i <= 175; i++){
				if (ComboFI(i, CF_SCRIPT4)){
					int Flagtile = Screen->ComboD[i];
					int FReflect_Y = this->Y - (ComboY(i) - this->Y)+MIRROR_REFLECT_Y_OFFSET+8;
					Screen->FastCombo(1, ComboX(i), FReflect_Y, Flagtile, 3, 128);
//					Screen->DrawTile(1, ComboX(i), FReflect_Y, Flagtile, 1, 1, 3, -1, -1, 0, 0, 0, 0, true, 128);
				}	
			}
	//Item Reflection- none of these will be flipped, because few if any items have a direction.  Yes, that means things like clocks will show the face in the mirror too. 
			for (int i = 1; i <= Screen->NumItems(); i++){
				item itm = Screen->LoadItem(i);
				int IReflect_Y = this->Y - (itm->Y - this->Y)+MIRROR_REFLECT_Y_OFFSET+8;
				Screen->DrawTile(1, itm->X, IReflect_Y, itm->Tile, 1, 1, itm->CSet, -1,-1,0, 0, 0, 0, true, 128);
			}
	//Link's Reflection
			//Match tiles with Link. Currently offset for the amount of frames in my animation of Link.
			//Currently set up to use BSZelda-style Link movement.
			//I moved this to the end so Link would be drawn last, above other tiles.
			if(Link->Dir == DIR_LEFT){
				Link_tile= Link->Tile;	// Finds the Right tiles, because they can be different-
				Link_Flip = 0;		// and flips them horizontally, so they look face left.
				if(Link->Action == LA_ATTACKING || Link->Action==LA_SWIMMING || Link->Z>0) Link_tile=Link->Tile; // Finds the Right-attacking tile.  Already flipped, above.
			}else if(Link->Dir == DIR_RIGHT){
				Link_tile= Link->Tile;	// Finds the Left tiles, as above-
				Link_Flip = 0;		// but doesn't flip them, because the game engine does that for you.
				if(Link->Action == LA_ATTACKING || Link->Action==LA_SWIMMING || Link->Z>0) Link_tile=Link->Tile; // If Link is attacking, using the hammer, etc, it does this.  This technically does stupid things
								// if Link is swimming, so don't use in rooms where when Link would be swimming.
			}else if(Link->Dir == DIR_DOWN){
				Link_tile = Link->Tile-9;
				Link_Flip = 1;
				if(Link->Action == LA_ATTACKING || Link->Action==LA_SWIMMING || Link->Z>0) Link_tile=Link->Tile-3;
			}else{
				Link_tile = Link->Tile+9;
				Link_Flip = 1;
				if(Link->Action == LA_ATTACKING || Link->Action==LA_SWIMMING || Link->Z>0) Link_tile=Link->Tile+3;
			}
			
			//  The vertical movement is currently set up to make it where the ffc is placed at the bottom edge of the mirror.  Unlike ywkls
			//  version, the ffc itself does not move- all movements are calculated based on the ffc's fixed position.
			LReflect_Y = this->Y - (Link->Y - this->Y)+MIRROR_REFLECT_Y_OFFSET;
			Screen->DrawTile(1, Link->X, LReflect_Y-Link->Z, Link_tile, 1, 1, 6, -1, -1, 0, 0, 0, Link_Flip, true, 64);
			
	//Cleanup
			LastX = Link->X;
			LastY = Link->Y;
			//debugValue(1, this->Y);
			Waitframe();
		}
	}
}

https://drive.google...iew?usp=sharing





Also tagged with one or more of these keywords: Request

1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users