Well for starters, you can specify a location much more neatly as a single variable, like so:
location lLoc = Location(Vector(25.0,81.0,-1.27), 0.0);
Then your CreateObject call would be:
CreateObject(OBJECT_TYPE_CREATURE, "trig_test", lLoc);
As to the double spawn, this is presumably the trigger's OnEnter? I would guess that it is firing multiple times before the DestroyObject kicks in, either by party members entering the trigger after the player, or perhaps the spawned creature itself. There are a few things you can do to limit that. One is to put the entire function inside an If check for the object entering being only the player specifically, or only a party member (including the player). That way no random NPCs or the spawned creature itself will initiate the trigger. Like so:
void main() {
object oPC = GetFirstPC();
object oEntering = GetEnteringObject();
location lLoc = Location(Vector(25.0,81.0,-1.27), 0.0);
if (oEntering == oPC)
{
CreateObject(OBJECT_TYPE_CREATURE, "trig_test", lLoc);
DestroyObject(OBJECT_SELF);
}
}
For a check of any player controlled character instead, you can leave out the oPC declaration and change the If statement to:
if (GetIsPC(oEntering))
The other thing you can do is to check for and set a boolean. Have the initial If check make sure that a boolean is set to FALSE, then set it to TRUE when the trigger fires. This will ensure the trigger only fires a single time, regardless of who enters it subsequently. Doing that means you don't need to destroy it, but you can do that as well if you want. Keeping the trigger around may be beneficial for some cases where you want to reuse it later.
void main() {
object oEntering = GetEnteringObject();
int SW_PLOT_HAS_TALKED_TO = 10;
location lLoc = Location(Vector(25.0,81.0,-1.27), 0.0);
if (GetIsPC(oEntering) && !GetLocalBoolean(OBJECT_SELF, SW_PLOT_HAS_TALKED_TO))
{
SetLocalBoolean(OBJECT_SELF, SW_PLOT_HAS_TALKED_TO, TRUE);
CreateObject(OBJECT_TYPE_CREATURE, "trig_test", lLoc);
//Uncomment the line below if you also wish to destroy the trigger.
//DelayCommand(1.0, DestroyObject(OBJECT_SELF));
}
}
The exclamation mark in front of a function means you are checking for the return value to be FALSE (well technically not TRUE, which is an important distinction per the below). Alternatively, you can also write it as:
GetLocalBoolean(OBJECT_SELF, SW_PLOT_HAS_TALKED_TO) == FALSE
Both are valid, but the second way can sometimes prove to be a little flaky with uninitialised booleans in my experience (even though that's the method Bioware most commonly used in vanilla scripts).
Note that I have declared SW_PLOT_HAS_TALKED_TO here just so you can see what I was doing. You could just cut that out and use 10 directly, or indeed use any of the plot flag locals from 0 to 10.