Aller au contenu

Photo

How to make the Beggar take up itens automatically on the ground?


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

#1
WhiteTiger

WhiteTiger
  • Members
  • 479 messages

So, I am trying to make the Beggar take itens dropped in your around, possibly these settings must be made in OnPerception Event.

If it sees an item on the ground, have it picked up and added it to his inventory.

 

It's possible? write yours suggestions on comments please

 

Thanks all.

 

 

beggar.jpg

 

SOLVED.

Add this to Creature Beggar OnHeartBeat event - especifically (save as a copy if you're using the original onheartbeat script).

//////////////////////////////////////////////////////////////
///////////////SCRIPT By WhiteTiger and henesua///////////////
//////////////////////////////////////////////////////////////
 
    //START - Beggar Pick Up Items
            object oItem = GetFirstObjectInShape(SHAPE_SPHERE, 25.0, GetLocation(OBJECT_SELF), TRUE, OBJECT_TYPE_ITEM);
            if (oItem!=OBJECT_INVALID)
    {
        ClearAllActions();
        ActionPickUpItem(oItem);
        return;
    }
    //END
 
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////

Modifié par WhiteTiger, 13 mars 2014 - 10:30 .


#2
Proleric

Proleric
  • Members
  • 2 346 messages
Certainly possible, but the OnPerception event is for creatures, not items.

You could use the module OnUnacquireItem event; when the PC drops an item in the beggar 's area, and the beggar sees it (GetObjectSeen), action him to pick it up.

#3
The Mad Poet

The Mad Poet
  • Members
  • 425 messages

I think I recall something called a 'Trash Fairy' script. I tried looking, but I couldn't find it. It was a fairy that spawned into areas when there were items left loose for so long. It ran around and picked them up, then destroyed itself.

 

It isn't exactly what you looking for... but I can't see why it can't be changed a bit to work what you want. If anyone can find it anyway.



#4
WhiteTiger

WhiteTiger
  • Members
  • 479 messages

1.Thanks, Proleric. Then now I'll not work with OnPerception events.

I'm thinking about starting to do module OnUnacquireItem script using this:

What's the "When the PC Drops an item in the beggar's area"?

 

2. Thanks, The Mad Poet. The item does not need to necessarily be with the beggar, this was to kill then and recover the itens. And its not need to work as a cleaning map itens, but the beggar should pick the item quickly. But it would be good if you can post the link of this system.


Modifié par WhiteTiger, 10 mars 2014 - 04:19 .


#5
Proleric

Proleric
  • Members
  • 2 346 messages
You can determine whether the PC and the beggar are in the same area using GetArea.

I'm not clear now whether you're looking for realistic behaviour from the beggar, in a fixed place, or whether you want to sweep several areas for discarded items occasionally?

If it's the latter, you'd need to spawn the beggar into the area from time to time, or else when there's an item to collect. You could tell the beggar to home in on the items, or, less efficiently, have them wander around until they see one. Note that if the PC has left the area, the beggar will become almost inactive, unless you bump up his AI level.

If the beggar's activity is not simultaneous with the item drop, you'll need a way of knowing which items the beggar can retrieve. Using OnUnacquireItem, you could make a list of discarded items, using local variables on the module, area or PC. However, you might find it easier to use the area OnHeartbeat event, cycling through the objects in the area until you find an item.

All this is assuming that you're changing the official campaign or a single player module. If you're thinking about a PW, there are significant efficiency issues, which the PW experts here can tell you about.

#6
Pstemarie

Pstemarie
  • Members
  • 2 745 messages

You could use the module OnUnAcquireItem event. When the PC puts down an item, the beggar walks over to it and picks it up, placing it in his inventory. No need for raising the AI of the beggar or sweeping the area for the item. To make the beggar wander the area, make sure you are using the XP2 Monster AI scripts for its script events and then just assign the int variable X2_L_SPAWN_USE_AMBIENT = 1 to make the beggar move around the area. 

 

The beggar will move around randomly until the PC drops an item, at which point, he will head straight for it and pick it up. If you want the beggar to stay alive, set his Plot flag to TRUE (i.e. check the box under the Basic tab in the Creature Properties window.

 

Place this code in your modules UnAcquireItem event...

 

void doPickupItem(object oItem)
{
    ActionMoveToObject(oItem); // OR
    //ActionMoveToLocation(GetLocation(oItem));
    ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW, 1.0, 4.0);
    ActionPickUpItem(oItem);
}
 
void main ()
{
     //existing code
 

    // * Looting Beggar Custom Code
    if (!GetIsObjectValid(oOwner)) //confirm item was dropped - might be better way to do this
    {
        object oBeggar = GetNearestObjectByTag("LOOT_BEGGAR", oPC);
        if (GetIsObjectValid(oBeggar))
        {
            AssignCommand(oBeggar, ClearAllActions());
            AssignCommand(oBeggar, doPickupItem(oItem));
        }
    }     

}

  • henesua aime ceci

#7
WhiteTiger

WhiteTiger
  • Members
  • 479 messages

Proleric,

 

Yes, it's a realist action.

 

Pstemarie,

 

Thanks for the contribution script. The commoner Beggar are created by a Painting Encounters, so he is free to walk around the area.

My OnUnacquire Event module are using this information:

 

    object oItem = GetModuleItemLost();
    object oPC = GetModuleItemLostBy();
    object oCurrentPossessor = GetItemPossessor(oItem);
 
What's the setup do you mean with oBeggar and oOwner?


#8
Pstemarie

Pstemarie
  • Members
  • 2 745 messages

 

Pstemarie,

 

Thanks for the contribution script. The commoner Beggar are created by a Painting Encounters, so he is free to walk around the area.

My OnUnacquire Event module are using this information:

 

    object oItem = GetModuleItemLost();
    object oPC = GetModuleItemLostBy();
    object oCurrentPossessor = GetItemPossessor(oItem);
 
What's the setup do you mean with oBeggar and oOwner?

 

 

In the script snibbets I posted above - which was inserted into the default BioWare module OnAquireItem script - if oItem doesn't have an owner (object oOwner is OBJECT_INVALID), then oItem must have been placed on the ground and is thus free to pickup by the beggar.

 

You could also extend this by giving the beggar a store. After all, what good are all the items he's picked up if he can't trade for coin with which to buy whiskey?


  • WhiteTiger aime ceci

#9
henesua

henesua
  • Members
  • 3 863 messages

Pstemarie - I think he was asking how your object labels work with his object labels.

 

I think they go as follows:

oCurrentPossessor   = oOwner

oBeggar is defined by Pstemarie's script.


  • WhiteTiger aime ceci

#10
WhiteTiger

WhiteTiger
  • Members
  • 479 messages

Pstemarie,

"You could also extend this by giving the beggar a store. After all, what good are all the items he's picked up if he can't trade for coin with which to buy whiskey?" yeah, good idea

 

henesua,

 

object oOwner = GetItemPossessor(oItem);

 

object oPC = GetModuleItemLostBy();

 

OK.

 

EDITED*

 

OK, all working fine.



#11
WhiteTiger

WhiteTiger
  • Members
  • 479 messages

Sometimes he tries to get the item, but another action cancels. The beggar is subject to move constantly time by time and this cancell the pickuping item. Do not have a function that can help us?



#12
The Mad Poet

The Mad Poet
  • Members
  • 425 messages
//Treasure trash Fairy
//Modified Heartbeat script based on the funky trash fairy script by
//Undead Waiter.
//Instead of collecting items dropped by players, this fairy loots the
//bodybags of dead monsters. A script developed as my module slowed
//severely when people left treasure they didn't want.
//As with the trash fairy, set character to plot and place this script in
//the on heartbeat event script of it. Set the creature to SLOW or V.SLOW
//to give players the time to decide whethere they want the treasure or
//not.
//Adjust perception as needed.


// Created 7.27.2002 by Undead Waiter
// Modified 16th April 2003 by Ogotu.
void main()
{
//Main variable declarations
int iResetValue = GetLocalInt(OBJECT_SELF, "ResetNumber");
//For Multiple faires that work together, change this for each fairy
//and save the H/B script as a different name.
//Note first will attract the fairy to the first object spawned
//object oBodyBagDestroy = GetObjectByTag("BodyBag",0);
object oBodyBagDestroy = GetObjectByTag("BodyBag",1);
//object oBodyBagDestroy = GetObjectByTag("BodyBag",2);
//object oBodyBagDestroy = GetObjectByTag("BodyBag",3);
//object oBodyBagDestroy = GetObjectByTag("BodyBag",4);
int iHasInventory = GetHasInventory(oBodyBagDestroy);

//Make sure no one has created an item called "BodyBag" by checking for an
//inventory
if (iHasInventory == TRUE)
  {
     if (oBodyBagDestroy != OBJECT_INVALID)

        {

         //I know, i'm just too lazy to do a loop.
         ActionMoveToObject(oBodyBagDestroy,FALSE,100.0);
         ActionTakeItem(GetFirstItemInInventory(oBodyBagDestroy),oBodyBagDestroy);
         ActionTakeItem(GetNextItemInInventory(oBodyBagDestroy),oBodyBagDestroy);
         ActionTakeItem(GetNextItemInInventory(oBodyBagDestroy),oBodyBagDestroy);
         ActionTakeItem(GetNextItemInInventory(oBodyBagDestroy),oBodyBagDestroy);
         ActionTakeItem(GetNextItemInInventory(oBodyBagDestroy),oBodyBagDestroy);
         ActionTakeItem(GetNextItemInInventory(oBodyBagDestroy),oBodyBagDestroy);
         ActionTakeItem(GetNextItemInInventory(oBodyBagDestroy),oBodyBagDestroy);
         ActionTakeItem(GetNextItemInInventory(oBodyBagDestroy),oBodyBagDestroy);
         ActionTakeItem(GetNextItemInInventory(oBodyBagDestroy),oBodyBagDestroy);
         ActionTakeItem(GetNextItemInInventory(oBodyBagDestroy),oBodyBagDestroy);
         ActionTakeItem(GetNextItemInInventory(oBodyBagDestroy),oBodyBagDestroy);
         ActionTakeItem(GetNextItemInInventory(oBodyBagDestroy),oBodyBagDestroy);
         //Too lazy here too
         ActionDoCommand(DestroyObject(GetFirstItemInInventory(OBJECT_SELF)));
         ActionDoCommand(DestroyObject(GetNextItemInInventory(OBJECT_SELF)));
         ActionDoCommand(DestroyObject(GetNextItemInInventory(OBJECT_SELF)));
         ActionDoCommand(DestroyObject(GetNextItemInInventory(OBJECT_SELF)));
         ActionDoCommand(DestroyObject(GetNextItemInInventory(OBJECT_SELF)));
         ActionDoCommand(DestroyObject(GetNextItemInInventory(OBJECT_SELF)));
         ActionDoCommand(DestroyObject(GetNextItemInInventory(OBJECT_SELF)));
         ActionDoCommand(DestroyObject(GetNextItemInInventory(OBJECT_SELF)));
         ActionDoCommand(DestroyObject(GetNextItemInInventory(OBJECT_SELF)));
         ActionDoCommand(DestroyObject(GetNextItemInInventory(OBJECT_SELF)));
         ActionDoCommand(DestroyObject(GetNextItemInInventory(OBJECT_SELF)));
         ActionDoCommand(DestroyObject(GetNextItemInInventory(OBJECT_SELF)));
         ActionDoCommand(DestroyObject(GetNextItemInInventory(OBJECT_SELF)));
         ActionDoCommand(DestroyObject(GetNextItemInInventory(OBJECT_SELF)));
        }
   }
}

This is the one I found from ' http://nwvault.ign.c....Detail&id=1731 '

 

Looking at it now... I'm sure there is a much better way to do this then what this code is. But maybe it'll spark an idea.

// Modified Trash Fairy
// Place on HeartBeat of your trash fairy
// Kudos to the original Trash Fairy Authors

void DestroyIfNoOwner (object oItem)
    {
    object oHolder = GetItemPossessor(oItem);
    if ((oHolder == OBJECT_INVALID) || (GetTag (oHolder) == "BodyBag"))
        DestroyObject (oItem);
    }

void main()
{
object oItem = GetNearestObject(OBJECT_TYPE_ITEM);
object oInventory;
if (oItem == OBJECT_INVALID)
    oItem = GetNearestObjectByTag ("BodyBag");

if (oItem != OBJECT_INVALID)
    {
    ActionMoveToObject(oItem);

    if (GetHasInventory (oItem))
        {
        oInventory = GetFirstItemInInventory (oItem);
        while (oInventory != OBJECT_INVALID)
            {
            ActionDoCommand (DestroyIfNoOwner (oInventory));
            oInventory = GetNextItemInInventory (oItem);
            }
        }
    else
        {
        ActionDoCommand(DestroyIfNoOwner(oItem));
        }
    }
}

This is the second one I found from ' http://nwvault.ign.c....Detail&id=2203 '

 

This one looks a little better anyway. Still a HB script though. You could probably make a similar effect by making it work OnEnter though with a trigger, or as was suggested on the UnAcquire. Then there is the all famous Pseudo HB. I'm not sure what method would be best for you, and I'm not sure which is the best use of resources. Personally... I'd go with the UnAcquired script. That one fires less often, and only when there actually is something to pick up. Far as I know with scripting the usual answer is 'Less is More'.

 

 

Sometimes he tries to get the item, but another action cancels. The beggar is subject to move constantly time by time and this cancell the pickuping item. Do not have a function that can help us?

 

If your running the animations from the ambient system then they are probably firing off and interfering. I've had that problem before when scripting actions. Maybe once the script starts you can find a way to disable them until they're done picking up the garbage? Maybe removing the variable from the beggar, then giving it back after 30 seconds or so would work? I'm not THAT familiar with the ambient animations, so I'm unsure.



#13
WhiteTiger

WhiteTiger
  • Members
  • 479 messages

Pstemarie help us with a nice system. Possibly we will not need more the Trash Fairy script for now. The problem is that the beggar has a time to complete the action to pick up the item from the floor, the duration is 1 second to 4 seconds was chosen in

 

ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW, 1.0, 4.0);

 

If waypoint call Beggar before 4 seconds playing animation to walk out, the ActionPickUpItem(oItem); does not occur.

 

PS: I already tryied reduce/remove the animation time, it isn't a good way to solve it.



#14
The Mad Poet

The Mad Poet
  • Members
  • 425 messages

Pstemarie help us with a nice system. Possibly we will not need the script Trash Fairy now. But the problem is that the beggar has a time to complete the action to pick up the item from the floor, the duration is 1 second to 4 seconds was chosen in

 

ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW, 1.0, 4.0);

 

If waypoint call Beggar before 4 seconds playing animation to walk out, the ActionPickUpItem(oItem); does not occur.

 

Oh... you got both actions running and it que's the other out. Well timing is the only solution I can think of. You can delay it I believe... something like:

 

ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW, 1.0, 4.0);

DelayCommand(4.5f,ActionPickUpItem(oItem));

 
Then the action to pick up the item shouldn't be up until after the animation is already done.


#15
WhiteTiger

WhiteTiger
  • Members
  • 479 messages

This don't work... We need disable AI (Artificial inteligence).

 

first

 

SetAILevel(oBeggar, AI_LEVEL_VERY_LOW); 

 

after

 

DelayCommand(10.0, SetAILevel(oBeggar, AI_LEVEL_NORMAL)); 



#16
Proleric

Proleric
  • Members
  • 2 346 messages
You can force a series of actions to run without interruption:
Action...
Action...
ActionDoCommand(SetCommandable(TRUE));
SetCommandable(FALSE);


#17
WhiteTiger

WhiteTiger
  • Members
  • 479 messages

OK, the final OnUnacquireItem script working correctly ( with some changes):

void doPickupItem(object oItem)
{
    ActionMoveToObject(oItem, TRUE); // TRUE to RUN
    ActionPickUpItem(oItem);
    return;
}

void main()
{
//... Your UnacquiredScript

// Beggar Pick up item system
   object oItem = GetModuleItemLost(); 
   object oPC = GetModuleItemLostBy();
    object oActualPossessor = GetItemPossessor(oItem);

    if (!GetIsObjectValid(oActualPossessor)) 
    {
        object oBeggar = GetNearestObjectByTag("YourTAGBeggar", oPC);
        if (GetIsObjectValid(oBeggar))
        {
            SetAILevel(oBeggar, AI_LEVEL_VERY_LOW);
            AssignCommand(oBeggar, ClearAllActions());
            DelayCommand(5.0, AssignCommand(oBeggar, doPickupItem(oItem))); // don't remove this delay
            DelayCommand(18.0, SetAILevel(oBeggar, AI_LEVEL_DEFAULT));
            return;
        }
    }
}

Thanks to Pstemarie.



#18
WhiteTiger

WhiteTiger
  • Members
  • 479 messages

You can force a series of actions to run without interruption:

Action...
Action...
ActionDoCommand(SetCommandable(TRUE));
SetCommandable(FALSE);

Proleric,

No, can't setting commandable because if stuck can't pick up item. 

 

Pstemarie,

 

OK, this is working well. And if the Beggar saw a item already dropped? The beggar is walking and saw a item on ground, he can't pick up this ):

 

EDITED: The Mad Poet has something intersting on your script code Fairy Trash: object oItem = GetNearestObject(OBJECT_TYPE_ITEM);

Can we use this to make Beggar pick up whatever item on the ground?


Modifié par WhiteTiger, 10 mars 2014 - 10:26 .


#19
Pstemarie

Pstemarie
  • Members
  • 2 745 messages
Sorry about the error in the original script - hadn't finished my coffee yet. Anyway, what I missed were the calls for SetCommandable to disable the ambient system while the Beggar was getting loot. Thanks for catching that, Proleric. Anyway here is a fully functional version of the script to cut into your module's UnAcquire event. I used the HotU event - x2_mod_def_unaqu.nss - as a base, so the variables conform to that.
 
Whenever a PC drops an item the Beggar moves to it, stoops and picks it up, then moves off. I reduced the time the animation plays to 2.0 seconds because 4 second seemed too long. I have also dropped multiple items and the action queue for the Beggar stacked - he went to the first item and picked it up, then the second item and picked that up, and so on.
 
//insert the following code into x2_mod_def_unaqu.nss
 
void doPickupItem(object oItem)
{
    ActionMoveToLocation(GetLocation(oItem));
    ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW, 1.0, 2.0);
    ActionPickUpItem(oItem);
    ActionDoCommand(SetCommandable(TRUE));
    SetCommandable(FALSE);
}
 
void main ()
{
     //existing code
 

    // * Looting Beggar Custom Code
    if (!GetIsObjectValid(oOwner)) //confirm item was dropped - might be better way to do this
    {
        object oBeggar = GetNearestObjectByTag("LOOT_BEGGAR", oPC);
        if (GetIsObjectValid(oBeggar))
        {
            AssignCommand(oBeggar, ClearAllActions());
            AssignCommand(oBeggar, doPickupItem(oItem));
        }
    }     

}

For picking up items just laying around in the area, you need to do a similar script as this in the Beggar's OnPerception or OnHeartbeat event. I would recommend OnPerception if you can get that working right.



#20
henesua

henesua
  • Members
  • 3 863 messages

Will OnPerception work for seeing an item?



#21
WhiteTiger

WhiteTiger
  • Members
  • 479 messages

Pstemarie, 

 

1.It's unnecessary use ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW, 1.0, 2.0); because the next action already have this included ActionPickUpItem(oItem);

 

So we do not have the delay. Why delay?

 

2.To be more realist, add 05 secs delay waiting before Beggar walk to pick up item.

 

I would like to check if the beggar acquired item or if the player was in front of him and blocked the action. Well, he could try to take the item back if it is not in your inventory.

 

henesua,

 

Proleric says (on the top) that OnPerception event is only for creatures and not for itens.


Modifié par WhiteTiger, 10 mars 2014 - 11:57 .


#22
henesua

henesua
  • Members
  • 3 863 messages

you could do this in OnHeartbeat. A couple ways to insert the code in OnHeartbeat. In a default OnHeartbeat (not recommended unless this behavior is common), in a unique OnHeartbeat for the beggar (easiest), in a User Defined OnHeartbeat add on that you switch on for the beggar.

 

Which ever of those three options you decide to use for this special heartbeat code, the code itself would probably need to be a GetFirstObjectInShape  ---> GetNextObjectInShape loop looking for items, and responding to the first one it sees. I'd use a sphere shape with a tight radius.

 

 

Another option that may or may not be of interest to you is to generate a silent shout when an item is dropped in an area. And then in the Beggar's onconveration script provide a hook for responding to that shout. You would also want to tell the beggar to listen for this particular shout during the OnSpawn event. You'd need to fiddle with the item putting out a shout, or if that does not work creating a framework that tells the hearer of the shout the object reference of the item dropped.



#23
Pstemarie

Pstemarie
  • Members
  • 2 745 messages

Will OnPerception work for seeing an item?

 

After further research, no, GetObjectSeen does not work for items - it only works for creatures. Therefore, you'd have to scan the area for items laying on the ground at regular intervals (i.e. via the creature's or module's Heartbeat) and then have the Beggar pick them up. Combined with the OnUnAcquire script from above, it should take care of cleaning an area.



#24
Pstemarie

Pstemarie
  • Members
  • 2 745 messages

Pstemarie, 

 

1.It's unnecessary use ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW, 1.0, 2.0); because the next action already have this included ActionPickUpItem(oItem);

 

So we do not have the delay. Why delay?

 

2.To be more realist, add 05 secs delay waiting before Beggar walk to pick up item.

 

I would like to check if the beggar acquired item or if the player was in front of him and blocked the action. Well, he could try to take the item back if it is not in your inventory.

 

I missed that - you can tell I don't use these specific actions that often. Anyway, the function now looks like this...

void doPickupItem(object oItem)
{
    ActionForceMoveToLocation(GetLocation(oItem));
    ActionPickUpItem(oItem);
    ActionDoCommand(SetCommandable(TRUE));
    SetCommandable(FALSE);
}

No need for a delay in the function because its now a forced action stack - ActionPickUpItem() will only execute AFTER ActionForceMoveToLocation() is finished - thanks to the addition of SetCommandable(). As for the rest - if the PC blocked the action, you seem pretty capable and I'm certain you'll figure that part out :)



#25
The Mad Poet

The Mad Poet
  • Members
  • 425 messages

Solution: 

 

FloatingTextStringOnCreature(oPC, "Stop making this hard on me!", TRUE);

ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDeath(TRUE), oPC);

 

That'll teach 'em!


  • Pstemarie aime ceci