Jump to content

Photo

Counters


  • Please log in to reply
10 replies to this topic

#1 Cukeman

Cukeman

    "Tra la la, look for Sahasrahla. ... ... ..."

  • Banned
  • Location:Hyrule/USA

Posted 22 December 2017 - 06:04 PM

In the Item Editor, under Pickup -> Counter Reference, there are 25 script slots.

Would someone help explain how to use these?

I want to make custom versions of items that will disappear upon use.

For example, I could make single-use swords for Link to collect and use.

Is making a new Counter hard?

 

EDIT: Hmm, if I use levels, and remove highest level on use, that would basically act the same as a counter, right? There are 165 custom item slots... wonder if that's enough


Edited by Cukeman, 22 December 2017 - 09:06 PM.


#2 Binx

Binx

    Formerly Lineas

  • Members
  • Real Name:Brian
  • Location:Lancaster, CA

Posted 23 December 2017 - 02:37 AM

Counters are an easy to set up script.
item script CounterItem
{
   void run(int c)
      {
         if(Game->Counter[c] > 0)
            {
               Game->DCounter[c] -= 1;
            }
         else if(Game->Counter[c] == 0)
            {
               return;
            }
      }
}
Assign the number associated with the counter slot you want to use (CR_ constants in std_constants.zh) as D0, attach as an action script.
 
You don't need scripting to use the counter for ammo, just to make it decrease after use. The pickup tab in the item editor allows you to set a counter reference, as you already have seen.

Edited by Binx, 25 December 2017 - 12:24 PM.


#3 Timelord

Timelord

    The Timelord

  • Banned
  • Location:Prydon Academy

Posted 23 December 2017 - 05:16 AM

Counters are an easy to set up script.

item script CounterItem
{
   void run(int c)
      {
         if(Game->Counter[c] > 0)
            {
               Game->DCounter[c] -= 1;
            }
         else if(Game->Counter[c] = 0)
            {
               return;
            }
      }
}
[...]


You have an equality/assign error there. ;)
 
item script CounterItem
	//Note that item classes with a built-in 
	//effect will run even if the script does not!
	//A bow, will still fire arrows, even if you try to 
	//tie it to Game->Counter[SCRIPT]. 
	//In order to fix this, you need to script
	//all of the effects of the item, and use a custom itemclass. 
{
void run(int ctr_id)
{
	if(Game->Counter[ctr_id] > 0)
	{
               --Game->DCounter[ctr_id];
	}
	else
	{
		//Do error effects.
		Quit();
	}
}
I'll try to prioritise adding a counter ref to the 'Use Cost' value in the Item Editor, instead of locking it to CR_MAGIC (or CR_RUPEES).

#4 Cukeman

Cukeman

    "Tra la la, look for Sahasrahla. ... ... ..."

  • Banned
  • Location:Hyrule/USA

Posted 23 December 2017 - 05:57 AM

//Note that item classes with a built-in
//effect will run even if the script does not!
//A bow, will still fire arrows, even if you try to
//tie it to Game->Counter[SCRIPT].

//In order to fix this, you need to script
//all of the effects of the item, and use a custom itemclass.


But that won't happen if I have the Remove Item When Used box checked in the item editor, right? That way I could still use non-custom classes, unless I'm overlooking something.
 

EDIT: Oh, that would remove the entire item when I used it a single time, even if it still had ammo left, wouldn't it?

 

EDIT 2: In that case, wouldn't a simpler scripting solution be to remove item when counter reaches 0, rather than rescripting an existing item?

 

I'll try to prioritise adding a counter ref to the 'Use Cost' value in the Item Editor, instead of locking it to CR_MAGIC (or CR_RUPEES).


Nice thought, that would add a lot of flexibility to quest making.

 

EDIT 3: I might be able to make do with itemclass levels, we'll see.


Edited by Cukeman, 23 December 2017 - 07:37 AM.


#5 Timelord

Timelord

    The Timelord

  • Banned
  • Location:Prydon Academy

Posted 23 December 2017 - 12:16 PM

But that won't happen if I have the Remove Item When Used box checked in the item editor, right? That way I could still use non-custom classes, unless I'm overlooking something.

EDIT: Oh, that would remove the entire item when I used it a single time, even if it still had ammo left, wouldn't it?

EDIT 2: In that case, wouldn't a simpler scripting solution be to remove item when counter reaches 0, rather than rescripting an existing item?

[...]


You can do that, but it requires a slightly different hack.

You need a global array to store what items Link owns, and a function in your global loop (prior to Waitdraw) that enables, or disables them, based on the counters.

That would need to be somewhat hard-coded. To make this work, you need to flag an index of the global array using item pick-up scripts.

Note: In 2.50.x, you need to manually enter item editor args with the item ID and other fields.

Using 2.50.x
 
int OwnsItems[256];


//For every item in the game, if it uses a counter, set the index that matches its ID to 
//the desired counter. The pickup-script does this for you, but there is no way to read
//what counter an item would use in 2.50.x, so you need to use an InitD arg. 
//I'm initialising this manually, because counte r0 is CR_LIFE, and if we initialised
//each index to '0', then items would all use HP. :D 
int TieToCounter[256] = 
    { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1 };

//Likewise, this stores the minimum cost of every item. 
//I'm initialising this manually so that it has a clear table, for hard-coding, if needed.
int ItemCounterCosts[256] =
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };

int GetItemCounter(int itm_id) { return TieToCounter[itm_id]; }
int GetItemCost(int itm_id) { return ItemCounterCosts[itm_id]; }


//! Item Script Args : 
//!     These are shared between the pickup-script and the action-script, per item!
//! D0: The message to display, if any.
//! D1: The ID of the item. In 2.54, you could do this->ID, but in 2.50.x this is needed.
//! D2: The counter to use.
//! D3: The cost per use. 

//Pick-Up Scriot
item script new_item
{
    //D2 is the counter. Don't leave it at '0' unless you want the item
    //to drain Link's HP!
    //(If the cost value is also '0', then that would be safe, but it isn't a good idea.)
    void run(int msg, int itm_id, int use_ctr, int cost)
    {
        OwnsItems[itm_id] = 1;
        if ( msg > 0 ) Screen->Message(msg);
        TieToCounter[itm_id] = use_ctr;
        ItemCounterCosts[itm_id] = cost;
    }
}

//Action Script
item script use_counter_cost
{
    void run(int a, int itm_id, int c, int d)
    //InitD args are shared between use and pickup scripts. 
    {
        Game->DCounter[GetItemCounter(itm_id) -= GetItemCost(itm_id);
        //Do other item stuff here if needed.
    }
}

void EnableDisableItems()
{
    int c;
    for ( int q = 0; q < 256; ++q )
    {
        c = GetItemCounter(q);
        if ( OwnsItem[q] ) 
        {
            if ( Link->Item[q] )
            {
                if ( c > 0 )
                {
                    if ( Game->Counter[c] <= GetItemCost(q) ) 
                    {
                        Link->Item[q] = false;
                    }
                }
            }
            if ( !Link->Item[q] )
            {
                //No counter assigned. 
                if ( c <= 0 ) { Link->Item[q] = true; } 
                //! Caution, this may interfere with other things that set items false.
                if ( c > 0 ) 
                {
                    if ( Game->Counter[c] >= GetItemCost(q) )
                    {
                        Link->Item[q] = true;  //same possible problem. 
                        //Multiple sources of setting/unsetting items can create script bugs. 
                    }
                }
            }
        }    
    }
}



global script test
{
    void run()
    {
        while(true)
        {
            EnableDisableItems();
            Waitdraw();
            Waitframe();
        }
    }
}

Have fun!

#6 Binx

Binx

    Formerly Lineas

  • Members
  • Real Name:Brian
  • Location:Lancaster, CA

Posted 25 December 2017 - 12:25 PM

You have an equality/assign error there. ;)

Good catch, fixed it. That's what I get for not testing the code before posting

#7 Cukeman

Cukeman

    "Tra la la, look for Sahasrahla. ... ... ..."

  • Banned
  • Location:Hyrule/USA

Posted 26 December 2017 - 10:37 PM

I guess with my idea of using levels to simulate quantity (5 levels for 5 uses) means capacity upgrades aren't possible(?)

 

I can live with a workaround, just want to make sure I'm not overlooking stuff.


Edited by Cukeman, 26 December 2017 - 10:38 PM.


#8 Cukeman

Cukeman

    "Tra la la, look for Sahasrahla. ... ... ..."

  • Banned
  • Location:Hyrule/USA

Posted 28 December 2017 - 01:33 PM

Counters are an easy to set up script.

item script CounterItem
{
   void run(int c)
      {
         if(Game->Counter[c] > 0)
            {
               Game->DCounter[c] -= 1;
            }
         else if(Game->Counter[c] == 0)
            {
               return;
            }
      }
}
Assign the number associated with the counter slot you want to use (CR_ constants in std_constants.zh) as D0, attach as an action script.
 
You don't need scripting to use the counter for ammo, just to make it decrease after use. The pickup tab in the item editor allows you to set a counter reference, as you already have seen.

 

 

 

I think I'm going to go ahead and try this. I'm a little confused about how to use it though.

What do you mean by "number associated"? What does [c] represent?



#9 Russ

Russ

    Caelan, the Encouraging

  • Administrators
  • Location:Washington

Posted 28 December 2017 - 04:20 PM

ZC has several counters. You can find them in std_constants.zh.



So, as an example, if c were equal to 1, it would decrease your rupees by one when you used it. 7-31 are only for use by scripts, so you'd probably wanna use one of those (unless you want this item to use bomb amo, rupees, magic, or some other built-in mechanic counter).
  • Cukeman likes this

#10 Avaro

Avaro

    o_o

  • Members
  • Real Name:Robin
  • Location:Germany

Posted 28 December 2017 - 04:37 PM

That said, I Binx' script isn't gonna prevent the item from being used when the counter hits 0.


  • Cukeman likes this

#11 Cukeman

Cukeman

    "Tra la la, look for Sahasrahla. ... ... ..."

  • Banned
  • Location:Hyrule/USA

Posted 28 December 2017 - 05:31 PM

ohhh, now I'm starting to understand




1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users