Creating new contexts in script
With CreateContext or CreateContextClass you can create a new instance of context (code/script execution), which will run in parellel and you are able to use Wait independently, which won't affect the main context it was called from.
If you are simply just calling a function with no arguments, AngelScript will have no problems with that, but you'll have some problems the moment you try to pass in objects or datatypes.
Here's an example how you can avoid crashes when passing arguments into CreateContext:
(Note: this is an old tutorial, and a very hacky way to do this, use DelayedExecution and GetScriptObj instead!)
class A : IPostal3Script
{
void main()
{
CP3SObj@ self = GetContextOwner();
// Store the 'self' handle
any ObjStorage;
ObjStorage.store(@self);
CreateContextClass("B", "MyFunction", ObjStorage);
}
}
class B : IPostal3Script
{
void MyFunction(any ObjStorage)
{
CP3SObj@ obj = null;
if (ObjStorage.retrieve(@obj) == false)
return;
// From this point on the function will only continue
// if the @obj handle was compatible, thus avoiding crashes
// Kill this object.
if (obj.IsNPC() == true)
obj.SetAttr("ea_health", 0);
}
}
Passing multiple arguments:
class A : IPostal3Script
{
void main()
{
CP3SObj@ self = GetContextOwner();
int num = 1;
bool tf = false;
any ObjStorage;
any IntStorage;
any BoolStorage;
// Store stuff
ObjStorage.store(@self);
IntStorage.store(num);
BoolStorage.store(tf);
// Arguments must match B's MyFunction function's args!
CreateContextClass("B", "MyFunction", ObjStorage, IntStorage, BoolStorage);
}
}
class B : IPostal3Script
{
// Are the arguments we are trying to pass in via CreateContextClass correct here?
void MyFunction(any ObjStorage, any IntStorage, BoolStorage)
{
CP3SObj@ obj = null;
int num = 0;
bool tf = true;
if (ObjStorage.retrieve(@obj) == false)
return;
// We are confident with our integers and booleans, so we don't need to check
IntStorage.retrieve(num);
BoolStorage.retrieve(tf);
// From this point on the function will only continue
// if the @obj handle was compatible, thus avoiding crashes
// num will be 1 here
if (num > 0)
{
CP3SObj@ pPlayer = GetPlayer();
obj.TeleportTo(pPlayer);
// tf will be false here
if (tf == true)
{
// Give enough time for the object to teleport...
Wait(1.75);
obj.FireEvent("OnHearCombat", pPlayer);
}
}
}
}
Delayed Execution
You can also use DelayedExecution which can execute contexts with delay. A delay of 0 will be instantaneous.
Here's an example, a class is initiated on spawn when the Player is still looking at the loading screen, we want to execute a function when we are sure the Player is fully loaded in:
// Yeah it's called Personal Computer Computer, problem?
class Example : IPostal3Script
{
// Dummy
void Init(){}
CP3SObj@ self;
Example(CP3SObj@ obj)
{
@self = @obj;
engine.DelayedExecution(0, "Example", "Test", self);
}
// This will execute when the Player is no longer loading!
void Test()
{
CP3SObj@ mon = null;
array<CP3SObj@> aNPC = engine.GetArrayOfEntitiesRadius(self, 96);
for (uint i = 0; i < aNPC.length(); i++)
{
if ( @aNPC[i] == null )
continue;
if ( @aNPC[i] == @self )
continue;
if ( aNPC[i].GetBaseEntity().GetClassName() != "cr_prop_interactable" )
continue;
if ( aNPC[i].GetManner() != "PCMonitor" )
continue;
@mon = @aNPC[i];
break;
}
if (mon != null)
Printf("mon is not null!\n");
else
Printf("mon is null!\n");
}
}