Aller au contenu

Photo

Counting creatures by tag in an area


  • Veuillez vous connecter pour répondre
9 réponses à ce sujet

#1
RetpircsWols

RetpircsWols
  • Members
  • 8 messages


void main()
{

//int GetIsNight(); //not sure how to use this... want it to fire one time per day, either at night or morning...


    object oObject = GetFirstObjectInArea(OBJECT_SELF);
    // Continue looping until there are no more objects left
    while (oObject != OBJECT_INVALID)
//	string sTag = GetTag(object oObject); //The base function
	string sTag = GetTag(oObject); //I think this should return the tag of oObject
	int iFN = 0;  //number of friendly creatures in the area, based on their "Tax amount"
    {
        // Test to see if oObject is a townsperson.  If so, add it up.
		
        if (sTag = "Townsman")
           iFN = (iFN + 5);  //five gold for an average townsman
		else (sTag = "TownsmanLv2");
			iFN = (iFN + 8); //more gold for upgraded townspeople
		   
        // Move on to the next object
        oObject = GetNextObjectInArea(OBJECT_SELF);
    }
	
	    //Create Gold in the Mayor's office...would rather it go into the inventory of a chest, but near a desk for now
    int nObjectType = OBJECT_TYPE_ITEM;
    string sTax = "NW_IT_GOLD001";
    location lTarget = GetLocation(GetWaypointByTag("Mayor_Desk"));//gets the waypoint by the Mayor's Desk
	CreateObject(nObjectType, sTax, lTarget); //Make it so, Number One.
//How do I change the stack size so that iFN gold pieces apear?
	
}

I am unable to get this script to work, and it is probably a very basic lack of understanding on my part.  The script is for a single player mod where you are an overlord, claiming land as you go.  To encourage the player to protect against random incursions as well as investing in the town, you get an amount of money each day equal to the amount of townspeople you have. 

 

I tried to write a script that gets tags and loops through them, adding an appropriate amount for each creature type.  In the end, I would like to increase the stack size by the final integer from the loop.  I have a few problems here:

 

1. I do not know how to make this fire once a day... maybe put it on the town mayor as a heartbeat... 

2. I do not know how to increase the stack size of gold in the final create item function.

3. I keep getting issues with my "if" statement. 

 

 

 

Last, I know this can be abused by resting 8 hours continually... can I put an actual timer on it?

 

Thank you to anyone who takes the time to read this.  I hope it is interesting, at least.

 

Ret

 



#2
ColorsFade

ColorsFade
  • Members
  • 1 267 messages

Getting it to fire each day would be a matter of using the date functions to determine if the gold has been deposited. These functions are:

 

GetCalendarDay()

GetCalendarMonth()

GetCalendarYear()

 

You'd have to write some math yourself, to compare one date to another, as there doesn't seem to be a default function to do it. You want to write the function to get the current date, and see if it is greater than the last date for which you received gold, which would let you know that you need to hand out gold. Each time you give gold to the PC, you'd want to get that date and save it (preferably as a local on the PC). This would keep resting from being an abuse as well. 

 

The second part to this is you'd need to write a function to determine the number of days since the last time you gave out the gold. If it's been four days, you need to give the PC four day's worth of gold. If you were to use a heartbeat, probably not an issue since it likely would fire every day. But I would try and avoid a heartbeat if possible. 

 

There's a better way to do this without a heartbeat, depending on how you're doing the gold assignment. 

 

Question: does the PC have to "check with" a certain person to receive the gold?

 

If the PC has to check with someone to actually receive the gold, then this script would only need to fire when the PC performs the check. The script would then check if the current date > last time gold was given, and then check how many days. So if the PC goes on an adventure, and returns 10 days later, they'd receive 10 days worth of gold allowance. 

 

And as for the tags: You can certain do this with a tag-system, but it would also work with variables on the creatures. This would be an easy check, and then you could have some creatures that might share a tag, but don't count for the gold allowance. You could also just loop through the creatures in the area and check faction (defender, merchant) and count from there. 

 

A number of ways to solve this issue, just depends on how you want it to work exactly. 



#3
ColorsFade

ColorsFade
  • Members
  • 1 267 messages

One other note on your if statement. 

 

It really should read like this: 

object oObject = GetFirstObjectInArea(OBJECT_SELF);
// Continue looping until there are no more objects left
while (oObject != OBJECT_INVALID)
{
     string sTag = GetTag(oObject); //I think this should return the tag of oObject
     int iFN = 0;  //number of friendly creatures in the area, based on their "Tax amount"
     

     if (sTag = "Townsman")
     {
        iFN = (iFN + 5);  //five gold for an average townsman
     }

     if(sTag = "TownsmanLv2")
     {
	 iFN = (iFN + 8); //more gold for upgraded townspeople
     }
		   
     // Move on to the next object
     oObject = GetNextObjectInArea(OBJECT_SELF);
}

You don't need an else statement. If the first "if" statement fails, it falls through to the next. If that statement fails, it goes onto the next object. Your "if" statement was writte in a way that broke the fall-through logic. And since the checks for each "if" statement are unique, it's not possible for both to fire, so you don't need an else statement. 


  • GCoyote aime ceci

#4
Tchos

Tchos
  • Members
  • 5 030 messages

2. I do not know how to increase the stack size of gold in the final create item function.

 

Make a container to contain the gold, and use:

CreateItemOnObject("NW_IT_GOLD001", oTarget, nStackSize);



#5
Clangeddin86

Clangeddin86
  • Members
  • 220 messages

Try with this and see if it works:

void main()
{
	if (GetIsNight() == FALSE) return; // The script will not fire during day.
	object oAREA = OBJECT_SELF;	// I think I read somewhere that it's more efficient defining OBJECT_SELF somewhere rather than repeating it every time it should be called.
    object oObject = GetFirstObjectInArea(oAREA);
	string sTag;
	int iFN;  //number of friendly creatures in the area, based on their "Tax amount"
    while (GetIsObjectValid(oObject) == TRUE) // Continue looping until there are no more objects left
	{
		sTag = GetTag(oObject); //I think this should return the tag of oObject
		if (sTag == "Townsman") // Test to see if oObject is a townsperson.  If so, add it up.
		{
			iFN = (iFN + 5);  //five gold for an average townsman
		}
		else if (sTag == "TownsmanLv2")
		{
			iFN = (iFN + 8); //more gold for upgraded townspeople
		}
		oObject = GetNextObjectInArea(oAREA); // Move on to the next object
	}
	//Create Gold in the Mayor's office.
    location lTarget = GetLocation(GetWaypointByTag("Mayor_Desk"));//gets the waypoint by the Mayor's Desk
	object oCHEST = CreateObject(OBJECT_TYPE_PLACEABLE, "PLC_MC_Estate_Chest", lTarget);
	object oGOLD = CreateItemOnObject("NW_IT_GOLD001", oCHEST, iFN); // This should create iFN gold inside the chest
}

There were some syntax errors in the original code, this should also trigger only at night and create a chest with the gold inside near the mayor's desk.

Keep in mind though, that if OBJECT_SELF is not an area it will call the area where the caller currently is, this means that if the player is outside of town (conquering something else), the script will not trigger while he's away. To make sure that all conquered areas trigger this script no matter where the player is another loop counting all possible areas to be conquered may be needed.

This script does not fix the rest exploit, but that can be taken care of later, for the time being, just test it to see if it works properly.

Another issue is that it may trigger multiple times during night, but I would have to know when this script is triggered and who triggers it.

 

About the chest creation, it's perhaps best creating it outside of the script (in area building) as a permanent placeable and then get it via a tag, that shuld even remove the need for a location.



#6
RetpircsWols

RetpircsWols
  • Members
  • 8 messages
void TaxTime ();

void main()
{

DelayCommand(1.0f,TaxTime());  //I do not know how to call a sub routine without delay command...

}

void TaxTime()
{
//int GetIsNight(); //not sure how to use this... want it to fire one time per day, either at night or morning...


    object oObject = GetFirstObjectInArea(OBJECT_SELF);     // Continue looping until there are no more objects left
    while (oObject != OBJECT_INVALID)
	int nFN = 0;  //number of friendly creatures in the area, based on their "Tax amount"
	string sTag = GetTag(oObject); //I think this should return the tag of oObject
    {
        // Test to see if oObject is a townsperson.  If so, add it up.		
        if (sTag == "Townsman")
		{
           nFN = ((nFN) + 5);  //five gold for an average townsman
		}
		if (sTag == "TownsmanLv2")
		{
			nFN = (nFN + 8); //more gold for upgraded townspeople
		}
        // Move on to the next object
        oObject = GetNextObjectInArea(OBJECT_SELF);
    }
	

	CreateItemOnObject("NW_IT_GOLD001", "TaxChest", nFN); //should now deposit in your chest in your castle, to be picked up at your leisure
	
	DelayCommand(4320.0f,TaxTime()); //4320 real seconds in one game day - wait for 72 real-time minutes of play, then check again
	
}

Thank you for the comments.  You guys could clearly do a better job than I can. 

 

ColorsFade: Thank you for both comments.  The answer to your question, based on Tchos' answer, is that it will be deposited into a chest in the player's castle.  Thank you for fixing my if statement; I am incredibly rusty and was never all that good when I wasn't (I changed my major from computer science because I could not get help with my college programs).

 

Tchos, I hope I implemented that right.  You nailed it with what I should do.

 

UPDATE: I posted this before Clan's post came in.  Thank you, yet again, Clangeddin.  The == in the if statement makes it work right. 

 

Now I have an error declaration at line 34 - the actual create item.

 

Finally, I think this will be called from a conversation by the mayor, who will be in the area, when he swears fealty to you.

 

Ret



#7
Clangeddin86

Clangeddin86
  • Members
  • 220 messages

In your last code, move lines 17 and 18 above line 16. That's probably causing a syntax error or a redefinition of variables inside a loop (which usually generates an error or won't run the code properly as variables are generally defined only once).



#8
Clangeddin86

Clangeddin86
  • Members
  • 220 messages

Ok, in your last version of the code there still two issues: the one I mentioned above (it would have triggered an error on line 39 with wrong stack on variable left) and the one on line 34 was a declaration error caused by the fact that you used a string (the tag I suppose) rather than an object (which should be the chest itself). You may also wanna change the second if to "else if" to make the code a little more efficient, should you decide to add more townsmen levels later on. (it checks only until it finds it, with if it checks every time instead).

This one below compiles successfully, so this should be a starting point for testing, the other issues can be taken care of later when the script won't work "as intended".

void TaxTime()
{
	//int GetIsNight(); //not sure how to use this... want it to fire one time per day, either at night or morning...
	
	object oObject = GetFirstObjectInArea(OBJECT_SELF);     // Continue looping until there are no more objects left
	
	int nFN = 0;  //number of friendly creatures in the area, based on their "Tax amount"
	string sTag; //Define it outside of the loop
	while (oObject != OBJECT_INVALID)
	{
		sTag = GetTag(oObject); // Get it inside the loop
		// Test to see if oObject is a townsperson.  If so, add it up.		
		if (sTag == "Townsman")
		{
			nFN = ((nFN) + 5);  //five gold for an average townsman
		}
		else if (sTag == "TownsmanLv2")
		{
			nFN = (nFN + 8); //more gold for upgraded townspeople
		}
		// Move on to the next object
		oObject = GetNextObjectInArea(OBJECT_SELF);
	}
	
	object oCHEST = GetObjectByTag("TaxChest");
	object oGOLD = CreateItemOnObject("NW_IT_GOLD001", oCHEST, nFN); //should now deposit in your chest in your castle, to be picked up at your leisure
	DelayCommand(4320.0f,TaxTime()); //4320 real seconds in one game day - wait for 72 real-time minutes of play, then check again
}
     
void main()
{
	DelayCommand(0.1, TaxTime());  //I do not know how to call a sub routine without delay command...    
}

Since you are using a recursive DelayCommand, be careful to fire this script only once, or else you'll get the gold every time you speak to the mayor and the recursive calls will keep on stacking on top of each other, making the game eventually unplayable.



#9
RetpircsWols

RetpircsWols
  • Members
  • 8 messages

Quite incredible.  It works perfectly.  Thank you, gentlemen, for your help.



#10
Tchos

Tchos
  • Members
  • 5 030 messages
void main()
{
	DelayCommand(0.1, TaxTime());  //I do not know how to call a sub routine without delay command...
}

 
As defined in the script, TaxTime() is a new function, and you can call it without DelayCommand just like this:

void main()
{
	TaxTime();
}