Jump to content

Photo

Specific Bushes/Pots Drop Specific Items


  • Please log in to reply
12 replies to this topic

#1 Darkmatt

Darkmatt

    Pastel Heart

  • Members

Posted 15 February 2015 - 08:45 PM

It's time for another one of DarkMatt's "I'm not actually planning to use this but it'd be cool for everyone." script challenges!

 

If you've paid astute attention to Link to the Past/Link's Awakening or you looked at either or in an editor, you might have noticed that some pots in dungeons might give you a specific thing. (The most obvious one being fairies near the boss door.) Quest makers can possibly use this to help supply players with what they need so they don't have to rely on random chance to stay supplied for a dungeon. My question is if such a thing would be possible.

 

-If one could make an FFC act like a Bush/Pot and then be able to specify what it drops, then there you go.

-The tricky part is making it drop once. We don't want the player to get infinite fairies before the boss. We want him to just get one.

-Afterwards, we need to find a way to tell the pot that its contents have been collected, and it should now drop nothing.

-For bonus points, if there's a way for it to regain its contents if you Continue/Reset the game, that'd be nifty.

 

I'm assuming this is not done already. If it is, then feel free to link the script and call me a dummyhead.


Edited by Darkmatt, 15 February 2015 - 08:47 PM.

  • Jared likes this

#2 justin

justin

    Adept

  • Members

Posted 15 February 2015 - 09:04 PM

Isn't there a slash->Item combo type?
Edit: thinking about it, I don't think that is what that does...
If not, it's certainly scriptable. You can make an item appear based on the combo under the ffc changing. Or you could give the slashable a custom drop set by again watching the combo under the ffc for a change then spawning a 0hp enemy over top.

Edit: there are probably a few ways to do it if you are using the screen special item and screen secrets. You'd need a script if you didn't want to use those for this.

Edited by justin, 15 February 2015 - 09:27 PM.


#3 Tabletpillow

Tabletpillow

    Hi

  • Members
  • Real Name:Xavier
  • Location:Oregon

Posted 15 February 2015 - 09:22 PM

Try putting Armos chest --> item (flag 10) on the pot or bush you want,

then do room type --> special item


Edited by a30502355, 15 February 2015 - 09:23 PM.


#4 Darkmatt

Darkmatt

    Pastel Heart

  • Members

Posted 15 February 2015 - 10:02 PM

Try putting Armos chest --> item (flag 10) on the pot or bush you want,

then do room type --> special item

That only does it for one thing, though, and it takes up the screen's special item.

 

It's a way to do it, yes, but it's not without tradeoffs. The whole point of scripting is to do this stuff without any strings attached, is it not?


Edited by Darkmatt, 15 February 2015 - 10:04 PM.


#5 justin

justin

    Adept

  • Members

Posted 15 February 2015 - 11:02 PM

here you go...  two different versions.  one spawns the item# you specify, the other spawns an itemset you specify.  just set the constants, potentially remove the recycled functions at the bottom of the script if you already have them.  place the FFC on the slashable combo, doesn't have to be lined up to grid, just the top left of the ffc needs to be on the combo you want to watch.  it watches the combo for a change, and then spawns your item / itemset.

 

i gave two options for it only spawning the item once.  one is that it'll set permanent secrets, the other is it'll use a Screen->D register.  use the latter if you don't want to tie up your screen secrets with this.  unfortunately, both these options are saved with the quest, so they'll remain permanent after death or continue.  You can track Game->NumDeaths if you want to reset them in the case that the player has died, but I don't believe you can track continue, so can't respawn them in that instance.  

 

 

compiles, but is untested.

 

import "std.zh"     // only need this once
 
// set the following constants.
// scroll down to the bottom of this script, and make sure you don't already have either of the utility functions at the bottom in your script file.
// import, and place the FFCs on the slashable.  They don't have to be lined up to the grid, just the X/Y coords need to be on that combo location.
// set your D0/D1 values.
 
 
const int NPC_ITEMSET               = 177;      // ID of a dummy enemy with type different from "none", hp0, itemset overridden by script
 
const int SCREEN_D_ITEM               = 0;      // Screen->D[] register index.  If the item should only be spawned once, and you don't want to use screen secrets.
                                                // Set to a number between 0-7 that is unused by any other scripts on the screen.
 
 
// Watches for the combo under the FFC to change, and generates an item on the slashable from the dropset that you specify. 
// D0 = the itemset #
// D1 = should it only happen once?  
//      0 = will happen everytime you revisit the screen.  
//      1 = happen once, use screen secrets to track.  
//      2 = happen once, use Screen->D register to track so secrets are still available.
 
ffc script Slash_ItemSet
{
   void run(int itemset, int once)
   {
      if(once == 1 && Screen->State[ST_SECRET]) Quit();
      if(once == 2 && Screen->D[SCREEN_D_ITEM] == 1) Quit();
 
      int loc = ComboAt(this->X,this->Y);
      int c = Screen->ComboD[loc];
 
      while(true)
      {
         if(Screen->ComboD[loc] != c)
         {
            ItemSetAt(itemset,loc);
 
            if     (once==1) permaSecrets();
            else if(once==2) Screen->D[SCREEN_D_ITEM] = 1;
            Quit();
         }
 
         Waitframe();
      }
   }
}
 
 
// Watches for the combo under the FFC to change, and generates an item on the slashable.
// D0 = the item #
// D1 = should it only happen once?  
//      0 = will happen everytime you revisit the screen.  
//      1 = happen once, use screen secrets to track.  
//      2 = happen once, use Screen->D register to track so secrets are still available.
 
ffc script Slash_Item
{
   void run(int itemnum, int once)
   {
      if(once == 1 && Screen->State[ST_SECRET]) Quit();
      if(once == 2 && Screen->D[SCREEN_D_ITEM] == 1) Quit();
 
      int loc = ComboAt(this->X,this->Y);
      int c = Screen->ComboD[loc];
 
      while(true)
      {
         if(Screen->ComboD[loc] != c)
         {
            item itm = CreateItemAt(itemnum, ComboX(loc), ComboY(loc));
 
            if     (once==1) permaSecrets();
            else if(once==2) Screen->D[SCREEN_D_ITEM] = 1;
            Quit();
         }
 
         Waitframe();
      }
   }
}
 
 
 
//!!!!!!!! this function may already exist in your script file, as it is used by other database scripts.
//creates and kills an enemy of type NPC_ITEMSET to fake an itemdropset.
void ItemSetAt(int itemset,int loc){
    npc e = Screen->CreateNPC(NPC_ITEMSET);
    e->ItemSet = itemset;
        if(e->isValid()){
        e->X = loc%16*16;
        e->Y = loc-loc%16;
        }
    e->HP = HP_SILENT;
}
 
//!!!!!!!! this function is from stdextra.zh.  If you've already imported that header, just remove this.
void permaSecrets(){
   Screen->TriggerSecrets();
   Screen->State[ST_SECRET] = true;
}

  • AdmiralJaden likes this

#6 Darkmatt

Darkmatt

    Pastel Heart

  • Members

Posted 16 February 2015 - 02:57 AM

I'll see if I can get around to testing this after I slam my face into my bed for 8 hours. It looks good though.



#7 justin

justin

    Adept

  • Members

Posted 16 February 2015 - 10:32 AM

here's a new version.  this attempts to achieve your reset on death or continue.  again, it compiles but is untested.

 

import "std.zh"     // only need this once
 
// 1. set the following constants.
// 2. scroll down to the bottom of this script, and make sure you don't already have either of the utility functions at the bottom in your script file.
// 3. import, put the FFC script(s) you want to use in empty slots.  Put the global script onExit into the onExit slot (or combine this onExit script with your existing)
// 4. place the FFCs on the slashable.  They don't have to be lined up to the grid, just the X/Y coords need to be on that combo location.
// 5. set your D0/D1/D2 values.
 
 
const int NPC_ITEMSET               = 177;      // ID of a dummy enemy with type different from "none", hp0, itemset overridden by script
 
const int SCREEN_D_ITEM               = 0;      // Screen->D[] register index.  If the item should only be spawned once, and you don't want to use screen secrets.
                                                // Set to a number between 0-7 that is unused by any other scripts on the screen.
 
 
// Watches for the combo under the FFC to change, and generates an item on the slashable from the dropset that you specify. 
// D0 = the itemset #
// D1 = should it only happen once?  
//      0 = will happen everytime you revisit the screen.  
//      1 = happen once, use screen secrets to track.  
//      2 = happen once, use Screen->D register to track so secrets are still available.
// D2 = once reset.  If using D1>0, do you want to reset it on death or continue?
//      0 = no
//      1 = reset on death
//      2 = reset on continue
 
ffc script Slash_ItemSet
{
   void run(int itemset, int once, int reset)
   {
      if( (reset == 1 && Screen->D[SCREEN_D_ITEM] != Game->NumDeaths)
        ||(reset == 2 && Screen->D[SCREEN_D_ITEM] != continueCount) )
      {
         if (once == 1) Screen->State[ST_SECRET] = false;
      }
      else if (once == 1 && Screen->State[ST_SECRET]) Quit();
      else if (once == 2 && Screen->D[SCREEN_D_ITEM] > 0) Quit();
 
      int loc = ComboAt(this->X,this->Y);
      int c = Screen->ComboD[loc];
 
      while(true)
      {
         if(Screen->ComboD[loc] != c)
         {
            ItemSetAt(itemset,loc);
 
            if     (once==1) permaSecrets();
            else if(once==2 && reset == 0) Screen->D[SCREEN_D_ITEM] = 1;
 
            if      (reset==1) Screen->D[SCREEN_D_ITEM] = Game->NumDeaths;
            else if (reset==2) Screen->D[SCREEN_D_ITEM] = continueCount;
 
            Quit();
         }
 
         Waitframe();
      }
   }
}
 
 
// Watches for the combo under the FFC to change, and generates an item on the slashable.
// D0 = the item #
// D1 = should it only happen once?  
//      0 = will happen everytime you revisit the screen.  
//      1 = happen once, use screen secrets to track.  
//      2 = happen once, use Screen->D register to track so secrets are still available.
// D2 = once reset.  If using D1>0, do you want to reset it on death or continue?
//      0 = no
//      1 = reset on death
//      2 = reset on continue
 
ffc script Slash_Item
{
   void run(int itemnum, int once, int reset)
   {
      if( (reset == 1 && Screen->D[SCREEN_D_ITEM] != Game->NumDeaths)
        ||(reset == 2 && Screen->D[SCREEN_D_ITEM] != continueCount) )
      {
         if (once == 1) Screen->State[ST_SECRET] = false;
      }
      else if (once == 1 && Screen->State[ST_SECRET]) Quit();
      else if (once == 2 && Screen->D[SCREEN_D_ITEM] > 0) Quit();
 
      int loc = ComboAt(this->X,this->Y);
      int c = Screen->ComboD[loc];
 
      while(true)
      {
         if(Screen->ComboD[loc] != c)
         {
            item itm = CreateItemAt(itemnum, ComboX(loc), ComboY(loc));
 
            if     (once==1) permaSecrets();
            else if(once==2 && reset == 0) Screen->D[SCREEN_D_ITEM] = 1;
 
            if      (reset==1) Screen->D[SCREEN_D_ITEM] = Game->NumDeaths;
            else if (reset==2) Screen->D[SCREEN_D_ITEM] = continueCount;
      
            Quit();
         }
 
         Waitframe();
      }
   }
}
 
int continueCount = 0;
 
global script onExit
{
   void run()
   {
      continueCount++;
   }
}
 
 
 
//!!!!!!!! this function may already exist in your script file, as it is used by other database scripts.
//creates and kills an enemy of type NPC_ITEMSET to fake an itemdropset.
void ItemSetAt(int itemset,int loc){
    npc e = Screen->CreateNPC(NPC_ITEMSET);
    e->ItemSet = itemset;
    if(e->isValid()){
        e->X = loc%16*16;
        e->Y = loc-loc%16;
    }
    e->HP = HP_SILENT;
}
 
//!!!!!!!! this function is from stdextra.zh.  If you've already imported that header, just remove this.
void permaSecrets(){
   Screen->TriggerSecrets();
   Screen->State[ST_SECRET] = true;
}


#8 Darkmatt

Darkmatt

    Pastel Heart

  • Members

Posted 16 February 2015 - 07:57 PM

The specific item script works like a charm, but here's something I've noticed that you can do for extra credit. (I would assume the itemset script works as well, unless there's a problem with the way it calls up the itemset.)

 

For using Screen->D[] variables, you should code in a way for the player to specify which variable he wants to use to track that particular pot. That way, one can use several pots in the same screen and track each one.

 

This sounds like something I can fix, but I'm lazy. :V

 

EDIT: Went and tested the itemset script now that I've realized how easy it is to just swap the two around. It works, but you should probably make a note to set the dummy enemy's spawn type to "instant" instead of "puff". Oh, and to make sure it doesn't count as a beatable enemy. If the enemy isn't cleaned up after the itemset is spawned, you should also do that.


Edited by Darkmatt, 16 February 2015 - 08:28 PM.


#9 justin

justin

    Adept

  • Members

Posted 16 February 2015 - 09:05 PM

Good point about instant spawn, I'll add that to the comments.

As for multiple pots on screen running the script, I hadn't thought of that. It'll be tricky to track the pots. When you're on the screen you can get the item from as many pots as you put the ffc on. It's just that any pots that you didn't get the item from won't have the item if you return to the screen with d1>0.

There are only 8 Screen->D slots per screen, and the script is already using 1. There are 32 ffcs or 172 combo locations. We could take two more Screen->D variables, and using binary represent the 32 ffcs as being taken or not.

#10 Darkmatt

Darkmatt

    Pastel Heart

  • Members

Posted 16 February 2015 - 09:17 PM

More space the merrier. If you find a way to allocate more slots for this script, by all means go for it. Though we can call it good already if we just allow each FFC instance to define which slot it takes up. Unless one's using a million FFCs that all need their own slots, it should be fine.



#11 justin

justin

    Adept

  • Members

Posted 16 February 2015 - 11:22 PM

Oh, and to make sure it doesn't count as a beatable enemy. If the enemy isn't cleaned up after the itemset is spawned, you should also do that.

 

the enemy is killed right away.  that's what generates the item set.

 

 

here's the updated code with the changes you requested.  keeps the usage of Screen->D[] variables to a minimum for that they are available for other scripts.  i did away with the option for using screen secrets to designate that the "pots" have been broken, it just uses the D variables now.  again it compiles, but is untested.  if it works, i'll submit to the database.

 

import "std.zh"     // only need this once
 
// 1. set the following constants.
// 2. scroll down to the bottom of this script, and make sure you don't already have the utility function at the bottom in your script file.
// 3. import, put the FFC script(s) you want to use in empty slots.  Put the global script onExit into the onExit slot (or combine this onExit script with your existing)
// 4. place the FFCs on the slashable.  They don't have to be lined up to the grid, just the X/Y coords need to be on that combo location.
// 5. set your D0/D1/D2 values.
 
 
const int NPC_ITEMSET               = 177;      // ID of a dummy enemy with type different from "none", hp0, itemset overridden by script, instant spawn animation
 
// Screen->D[] register indexes. Set to a number between 0-7 that is unused by any other scripts on the screen.  
// These are only used if D1 for either script is >0.
const int SCREEN_D_ITEM1               = 0;      //   A binary index of FFCs 1-16, the bit for each FFC will be true if that item has been taken.
const int SCREEN_D_ITEM2               = 1;      //   As above, FFCS 17-32
const int SCREEN_D_ITEM_RESET          = 2;      //   Tracks either #deaths or #continues to see if we should be reseting the bit above.  Only used if D2>0.
 
 
// Watches for the combo under the FFC to change, and generates an item on the slashable from the dropset that you specify. 
// D0 = the itemset #
// D1 = should it only happen once?  
//      0 = will happen everytime you revisit the screen.  
//      1 = happen once, sets a bit representing this FFC to a Screen->D register to track
// D2 = once reset.  If using D1>0, do you want to reset it on death or continue?
//      0 = no
//      1 = reset on death
//      2 = reset on continue
 
 
ffc script Slash_ItemSet
{
   void run(int itemset, int once, int reset)
   {
      int thisNum = FFCNum(this);
 
      if(once != 0)
      {
         if( (reset == 1 && Screen->D[SCREEN_D_ITEM_RESET] != Game->NumDeaths)
           ||(reset == 2 && Screen->D[SCREEN_D_ITEM_RESET] != continueCount) )
         {
            if (thisNum > 16) SetScreenDBit(SCREEN_D_ITEM2,thisNum-17,false);
            else              SetScreenDBit(SCREEN_D_ITEM1,thisNum-1,false);
         }
         else if ( GetScreenDBit( Cond(thisNum > 16, SCREEN_D_ITEM2, SCREEN_D_ITEM1), Cond(thisNum > 16, thisNum-17, thisNum-1) ) ) Quit();
      }
 
      int loc = ComboAt(this->X,this->Y);
      int c = Screen->ComboD[loc];
 
      while(true)
      {
         if(Screen->ComboD[loc] != c)
         {
            ItemSetAt(itemset,loc);
 
            if (once != 0)
            {
               if (thisNum > 16) SetScreenDBit(SCREEN_D_ITEM2,thisNum-17,true);
               else              SetScreenDBit(SCREEN_D_ITEM1,thisNum-1,true);
 
               if      (reset==1) Screen->D[SCREEN_D_ITEM_RESET] = Game->NumDeaths;
               else if (reset==2) Screen->D[SCREEN_D_ITEM_RESET] = continueCount;
            }
 
            Quit();
         }
 
         Waitframe();
      }
   }
}
 
 
// Watches for the combo under the FFC to change, and generates an item on the slashable.
// D0 = the item #
// D1 = should it only happen once?  
//      0 = will happen everytime you revisit the screen.  
//      1 = happen once, sets a bit representing this FFC to a Screen->D register to track
// D2 = once reset.  If using D1>0, do you want to reset it on death or continue?
//      0 = no
//      1 = reset on death
//      2 = reset on continue
 
ffc script Slash_Item
{
   void run(int itemnum, int once, int reset)
   {
      int thisNum = FFCNum(this);
 
      if(once != 0)
      {
         if( (reset == 1 && Screen->D[SCREEN_D_ITEM_RESET] != Game->NumDeaths)
           ||(reset == 2 && Screen->D[SCREEN_D_ITEM_RESET] != continueCount) )
         {
            if (thisNum > 16) SetScreenDBit(SCREEN_D_ITEM2,thisNum-17,false);
            else              SetScreenDBit(SCREEN_D_ITEM1,thisNum-1,false);
         }
         else if ( GetScreenDBit( Cond(thisNum > 16, SCREEN_D_ITEM2, SCREEN_D_ITEM1), Cond(thisNum > 16, thisNum-17, thisNum-1) ) ) Quit();
      }
 
      int loc = ComboAt(this->X,this->Y);
      int c = Screen->ComboD[loc];
 
      while(true)
      {
         if(Screen->ComboD[loc] != c)
         {
            item itm = CreateItemAt(itemnum, ComboX(loc), ComboY(loc));
 
            if (once != 0)
            {
               if (thisNum > 16) SetScreenDBit(SCREEN_D_ITEM2,thisNum-17,true);
               else              SetScreenDBit(SCREEN_D_ITEM1,thisNum-1,true);
 
               if      (reset==1) Screen->D[SCREEN_D_ITEM_RESET] = Game->NumDeaths;
               else if (reset==2) Screen->D[SCREEN_D_ITEM_RESET] = continueCount;
            }
      
            Quit();
         }
 
         Waitframe();
      }
   }
}
 
int continueCount = 0;
 
global script onExit
{
   void run()
   {
      continueCount++;
   }
}
 
 
 
//!!!!!!!! this function may already exist in your script file, as it is used by other database scripts.
//creates and kills an enemy of type NPC_ITEMSET to fake an itemdropset.
void ItemSetAt(int itemset,int loc){
    npc e = Screen->CreateNPC(NPC_ITEMSET);
    e->ItemSet = itemset;
    if(e->isValid()){
        e->X = loc%16*16;
        e->Y = loc-loc%16;
    }
    e->HP = HP_SILENT;
}
 


#12 Darkmatt

Darkmatt

    Pastel Heart

  • Members

Posted 17 February 2015 - 06:21 PM

Using the itemset script probably is the more sensible idea because I've noticed that there's 8 Screen->D[] variables, while there's 512 item dropsets. I cannot fathom someone using all 512 and not having some they can make into 100% single item drops. (That and using the itemset script has the nice effect of making the item flicker in to existence like any other item from a pot. It's the little touches like this that really makes a script blend in to its surroundings.)

 

Currently in school. Dunno what I'm gonna do once I get back home but hopefully it entails testing this.


Edited by Darkmatt, 17 February 2015 - 06:23 PM.


#13 justin

justin

    Adept

  • Members

Posted 17 February 2015 - 07:07 PM

The two scripts are the exact same, one just spawns an item of your choosing (it could be made to flicker and/or hold over head), and the other spawns an item set.

The item version was what you initially asked for. I just added the item set version as an option. Normally the various slash combos either use one of two item sets depending on the combo type, so this just gives the option to use other item sets. Or you could use the item set sorta how you initially presented the idea, but instead of 100% getting one item, there is a little variability.

The scripts only use 3 screen D registers, you don't need to use all 8 for this. You can have all of the 32 ffcs running the script (either version, or a mix) and the script tracks whether that "pot" has been broken - it does this with just 2 of the D registers, the 3rd register is just to track deaths or continues for potential reset.

I'll add the potential for item flicker or hold up or whatever other item properties I can't remember right now, to the single item version.


1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users