Aller au contenu

Photo

Area heartbeat


32 réponses à ce sujet

#1
mj crom

mj crom
  • Members
  • 69 messages
Hi all,

in NWN, heartbeat was pretty easy to implement.

It is a little more complicated with the event driven engine of DA.

I would like that when the PC is in an area, this area randomly spawns stuff every x seconds.
The "randomly spawn stuff" is ok, but I can't figure out the "every x seconds" part.

Any Idea?

#2
Nodrak

Nodrak
  • Members
  • 144 messages
There are many ways to go about this I suspect, and to me it seems like the traditional heartbeat would be too frequent, unless you really wanted the players to get swarmed... Let alone any implications of how to hook into said event.
Is this just a tiny room?  Is it an area where you have to define where the monsters should come from?  Is there anything else in the area?  Should the monsters spawn relative to where the players are in a larger area?
From what I see, in DAO only players have heartbeat events, and they happen every 3s, and it also seems like the creature heartbeat is simply used to seed AI behavior changes based on time.  There also appear to be engine level heartbeat events, but I doubt any script will be able to hook into those.
Even considering the following in player_core.nss
// -----------------------------------------------------------------
// Legacy Heartbeat event. Left for the consumption of modders.
// Be careful with it, it's not nice to run on a lot of creatures...
// -----------------------------------------------------------------
case EVENT_TYPE_HEARTBEAT:
{
bEventHandled = TRUE;
break;
 }

There is no certanty that the area or module itself is passed this event.  As per events.xls, there are 3 heatbeat events:
EVENT_TYPE_AOE_HEARTBEAT
EVENT_TYPE_HEARTBEAT2
EVENT_TYPE_HEARTBEAT

The first two are engine events, and the 3rd is not called anywhere outside of player_core.  Which leads me to the start of my post, in that you will likey have to seek out another method.  A simple test would be to make a script that hooks EVENT_TYPE_HEARTBEAT and put it in your module script, and see if it gets run (make it give you gold or something, so you can see it every few seconds).

#3
mj crom

mj crom
  • Members
  • 69 messages
The heartbeat system is used to randomly populate an area with stuff. I put a random on each heartbeat, like 10%, so that the player won't be swarmed, no worries, I took that into account.

Actually, my NWN2 system works on the area HB, and spawns critters through WP.

And I checked, there are no "delay" functions either.

Another function I imagined is that, as EVENT_TYPE_HEARTBEAT2 goes on creature, I could change the WP with an invisible immortal immobile creature, that would be the spawning point of the system, with an initiateheartbeat() when the PC comes close, or enters the area...

But I will give a try to the module HB, as you propose.

Modifié par mj crom, 26 novembre 2009 - 03:33 .


#4
DavidSims

DavidSims
  • BioWare Employees
  • 196 messages
edit: double post.

Modifié par DavidSims, 26 novembre 2009 - 04:11 .


#5
DavidSims

DavidSims
  • BioWare Employees
  • 196 messages
You can make your own heartbeat with a DelayEvent function call in the spawn script, and call it again every time in the handler for that event. You can set the frequency to be whatever you want.

#6
Craig Graff

Craig Graff
  • Members
  • 608 messages
You want DelayEvent.

#7
mj crom

mj crom
  • Members
  • 69 messages
Yes please ^^

#8
Craig Graff

Craig Graff
  • Members
  • 608 messages
My point is that there is a function called DelayEvent you should be using.

Edit: I'm not finding a good explanation for this on the wiki (though I may just be missing it), so I'll see about putting one up a bit later today.

Modifié par Craig Graff, 26 novembre 2009 - 04:08 .


#9
Nodrak

Nodrak
  • Members
  • 144 messages
Basically, in short, you can add a script that gets run when a player enters the area, either via the module override script, or via that specialized M2DA file people use to run scipts in the OC areas, or even via a placeable trigger on the ground at the entrance (or any means, like say an item, or an npc). You just need some 'seed' event to call a script, then in that script you can do logic like spawn creatures, then call 'DelayEvent(Time to Delay, Object to Pass Event to)' If you delay the event to the same script, you can in effect, achieve a heartbeat with your deisred rate.

#10
mj crom

mj crom
  • Members
  • 69 messages
So I can DelayEvent a function, like CreateObject ? I thought DelayEvent was for event ...

#11
sillyrobot

sillyrobot
  • Members
  • 171 messages
DelayEvent is indeed a function. http://social.biowar....php/DelayEvent

#12
DavidSims

DavidSims
  • BioWare Employees
  • 196 messages

mj crom wrote...

So I can DelayEvent a function, like CreateObject ? I thought DelayEvent was for event ...


No, there is no way to delay a function call.

DelayEvent signals the event to the specified object after the delay.

You can make an area heartbeat this way by first sending a heartbeat event to the area, then within the area's script have a case for the heartbeat event, and within that handling delay a heartbeat event sent back to the area. Every time the heartbeat is run, it queues up the next one.

#13
Hoagsie

Hoagsie
  • Members
  • 101 messages
Wouldn't be possible to make a new and empty event to fire?



So you would call



DelayEvent(5f, null, EVENT_BOGUS_DO_NOTHING, null);



??

#14
DavidSims

DavidSims
  • BioWare Employees
  • 196 messages

Hoagsie wrote...

Wouldn't be possible to make a new and empty event to fire?

So you would call

DelayEvent(5f, null, EVENT_BOGUS_DO_NOTHING, null);

??


Yes, but what would be the point? It would do nothing.

Although some events are sent by the engine, many are entirely scripted. The event type is just an integer. You can make whatever events you want with whatever event type you want and with whatever parameters stored on the event you want. You can send these events to any object you want. The event handling is done entirely through scripting, so you can see exactly what will happen by tracing through the object's script. You do however have to be very careful about overlapping event type IDs. For safety, using the EVENT_TYPE_CUSTOM_EVENT_1 is a good idea.

#15
Hoagsie

Hoagsie
  • Members
  • 101 messages
When I read the thread I thought the OP was looking for a way to delay an action by so long and the DelayEvent function seems to be the only way. So, if that's what you want to do you likely just want something to "hang" for a bit before you do something else.

#16
Nodrak

Nodrak
  • Members
  • 144 messages
You can do something like this:

my_custom_area_script.nss

#begin psuedo code
EventType(Event_area_load)
{
DelayEvent(10.0f, myarea, myevent, "my_custom_area_script.ncs")
}

EventType(myevent)
{
SpawnMonster()
DelayEvent(10.0f, myarea, myevent, "my_custom_area_script.ncs")
}
#end psuedo code

Though that assumes an area is classified as an object, which should be as per Script.ldf:
int OBJECT_TYPE_INVALID           = 0;
int OBJECT_TYPE_GUI               = 1;
int OBJECT_TYPE_TILE              = 2;
int OBJECT_TYPE_MODULE            = 4;
int OBJECT_TYPE_AREA              = 8;
int OBJECT_TYPE_STORE             = 16;
int OBJECT_TYPE_CREATURE          = 32;
int OBJECT_TYPE_ITEM              = 64;
int OBJECT_TYPE_TRIGGER           = 128;
int OBJECT_TYPE_PROJECTILE        = 256;
int OBJECT_TYPE_PLACEABLE         = 512;
int OBJECT_TYPE_AREAOFEFFECTOBJECT= 2048;
int OBJECT_TYPE_WAYPOINT          = 4096;
int OBJECT_TYPE_SOUND             = 16384;
int OBJECT_TYPE_PARTY             = 32768;
int OBJECT_TYPE_MAPPATCH          = 65536;
int OBJECT_TYPE_VFX               = 131072;
int OBJECT_TYPE_MAP               = 262144;

Modifié par Nodrak, 04 décembre 2009 - 07:13 .


#17
mj crom

mj crom
  • Members
  • 69 messages
Thanks a lot for what you have done so far Nodrak, but could it be possible to have a more detailed description of what to do, and where goes what? Mu scripting is from NWN2, and I have a very hard time figuring out the event part of DAO scripting. Not the basic event part (the part that switches through various events case), but I can't figure out what you say.



And this heartbeat stuff is quit crucial for my mod .

#18
georage

georage
  • Members
  • 247 messages
//script named 'my_heartbeat'

#include "utility_h"
#include "wrappers_h"
#include "events_h"

void main()
{
    object oPC=GetMainControlled();
    object oMod=GetModule();
    
        ////////////////////////// 
        //simple counter for testing, be sure to declare variable 'Heartbeat' in var_modname 2DA
        if(IsObjectValid(oPC))
            {
            int iCounter=GetLocalInt(oMod,"Heartbeat");
            iCounter++;  
            SetLocalInt(oMod,"Heartbeat",iCounter);    
            DisplayFloatyMessage(oPC, "Heartbeat="+IntToString(GetLocalInt(oMod,"Heartbeat")), FLOATY_MESSAGE, 14654488, 1.0);
            }

DelayEvent(6.0f,oPC,Event(EVENT_TYPE_HEARTBEAT),"my_heartbeat");
}

To kick things off you can do several things, the easiest for testing is to draw a trigger around the module startpoint and put this on it.

void main()
{
            if(GetLocalInt(OBJECT_SELF,"TRIGGER_DO_ONCE_A")==0)
                {  
                SetLocalInt(OBJECT_SELF,"TRIGGER_DO_ONCE_A",1);    
                DelayEvent(6.0f,oPC,Event(EVENT_TYPE_HEARTBEAT),"my_heartbeat");
                }
} 

Modifié par georage, 08 décembre 2009 - 08:36 .


#19
mj crom

mj crom
  • Members
  • 69 messages
Thanks georage, I tried that, it works like a charm. Thanks a lot :-)

#20
Sunjammer

Sunjammer
  • Members
  • 925 messages
Actually there is a bug in that code.  It routes the delayed event to the Player therefore it isn't an Area heartbeat so much as a Player heartbeat.  Depending on what you are doing this could have a significant effect as OBJECT_SELF will point to the wrong object.

Additionally there is an issue when using DelayEvent with an area object: the scriptname parameter does not appear to have any effect and so you must use the area's assigned script to handle the delayed event.

#21
georage

georage
  • Members
  • 247 messages
True, but you can replace OBJECT_SELF with GetModule()



The point of my post being to show you can make a master heartbeat which is quite flexible.



Simply check if various objects (creatures, areas, etc) are valid, and if so, execute a certain portion of code.



To work more like NESS, the popular spawn script from NWN, you would simply check for the PC as above, but also check to see which area the PC is in. Then you execute the portion of code you need to spawn creatures in that particular area.



Of course, adding a Spawn() function to each area would work too.

#22
mj crom

mj crom
  • Members
  • 69 messages
Well, I built the spawning around the PC, not around the Area.

And the "kicker" lacks the "event_h" include.

But it certainly achieved its goal for me :-)

#23
Sunjammer

Sunjammer
  • Members
  • 925 messages

georage wrote...

True, but you can replace OBJECT_SELF with GetModule()

Which would do what exactly? In your "area" heartbeat OBJECT_SELF is the PC and in order to get a reference to the area you're suggesting GetModule?

:o

To correct the DelayEvent calls replace the reference oPC with GetArea in the kicker and OBJECT_SELF in the event script.

Modifié par Sunjammer, 09 décembre 2009 - 07:29 .


#24
georage

georage
  • Members
  • 247 messages
I never claimed what I offered was an area heartbeat. And I was not trying to get a reference to an area. Otherwise I would define oArea.

I understand you are the superior programmer Sunjammer. Thanks for your help.

Modifié par georage, 09 décembre 2009 - 07:57 .


#25
georage

georage
  • Members
  • 247 messages
And you are right, GetModule() does not appear to work.