Note: LucasForums Archive Project
The content here was reconstructed by scraping the Wayback Machine in an effort to restore some of what was lost when LF went down. The LucasForums Archive Project claims no ownership over the content or assets that were archived on archive.org.

This project is meant for research purposes only.

Making NPCs fight. Yes, another scripting question. Help would be greatly appreciated

Page: 1 of 1
 mattcrowston
12-21-2005, 3:33 AM
#1
Hello. Its been a while since I have posted. But I got the urge too pick up my mod again. I am totally new to scripting. I have made a few scripts to spawn containers and creatures, and I am starting to find a slight understanding of it. But there is still so much standing in front of me holding back my ideas. Any wisdom from the scripting masters I so highly admire would be very much appreciated.

What I want to do is spawn 2 npcs at a location, and have them fighting each other as I run into them. Once I run into them, I want one of the fighters to yell "die." Not at me but at their opponent. Then this will be followed by him casting force crush on the challenger.

Here is the code I have so far:

void main()

{

object oMattsL=GetObjectByTag("n_mattsloran");
if (oMattsL==OBJECT_INVALID)
{
float x1=-75.38; //Here is where you add the 'whereami' cheat coordinate 1.
float y1=63.73; //Here is where you add the 'whereami' cheat coordinate 2.
float z1=120.09621; //Here is where you add the 'whereami' cheat coordinate 3.
float r1=202.06235; // This is where you set the orientation of the placeable, set in degrees.

vector MyVec1 = Vector(x1,y1,z1); //line 1
location MyLoc1 = Location(MyVec1, r1); //line 2

object oMattsL = CreateObject(OBJECT_TYPE_CREATURE, "n_mattsloran", MyLoc1);

SetMinOneHP(oMattsL,1);
}
object oEthanM=GetObjectByTag("n_ethanmorn");
if (oEthanM==OBJECT_INVALID)
{


float x2=-70.24244; //Here is where you add the 'whereami' cheat coordinate 1.
float y2=63.46703; //Here is where you add the 'whereami' cheat coordinate 2.
float z2=120.15303; //Here is where you add the 'whereami' cheat coordinate 3.
float r2=1.53733; // This is where you set the orientation of the placeable, set in degrees.


vector MyVec2 = Vector(x2,y2,z2); //line 1
location MyLoc2 = Location(MyVec2, r2); //line 2

object oEthanM = CreateObject(OBJECT_TYPE_CREATURE, "n_ethanmorn", MyLoc2);


SetMinOneHP(oEthanM,1);
}

SetNPCAIStyle(oMattsL, NPC_AISTYLE_JEDI_SUPPORT);
SetNPCAIStyle(oEthanM, NPC_AISTYLE_JEDI_SUPPORT);
SetLocalBoolean(oMattsL, 89, TRUE);
SetLocalBoolean(oEthanM, 89, TRUE);

DelayCommand(0.5, ExecuteScript("k_ai_master", oMattsL, 1003));
DelayCommand(0.5, ExecuteScript("k_ai_master", oEthanM, 1003));

DelayCommand(15, AssignCommand(oMattsL, ActionStartConversation(oEthanM, "mc_mattskillethan")));
}


Now I know the last line doesn't work. But the rest does spawn my npcs and has them fighting endlessly. I thought maybe starting a dialog where npc "mattsl" says die, followed with a script would work to cast the force crush. If you can help me work this out, I would be forever thankful.

MattC
 stoffe
12-21-2005, 11:41 AM
#2
What I want to do is spawn 2 npcs at a location, and have them fighting each other as I run into them. Once I run into them, I want one of the fighters to yell "die." Not at me but at their opponent. Then this will be followed by him casting force crush on the challenger.


Something like this would probably work if put as the heartbeat script of a non-static Invisible Placeable placed (or spawned when the fight should occur) in the area that will act as the scene controller:



void main() {
int nState = GetLocalNumber(OBJECT_SELF, 1);
object oMattSL, oEthanM;

// Step 1: Spawn combatants and start fight...
if (nState == 0) {
// Spawn creatures...
oMattSL = CreateObject(OBJECT_TYPE_CREATURE, "n_mattsloran", Location(Vector(-75.38, 63.73, 120.09), 202.06235));
oEthanM = CreateObject(OBJECT_TYPE_CREATURE, "n_ethanmorn", Location(Vector(-70.24, 63.46, 120.15), 1.53));

// Make them use force powers...
SetNPCAIStyle(oMattSL, NPC_AISTYLE_JEDI_SUPPORT);
SetNPCAIStyle(oEthanM, NPC_AISTYLE_JEDI_SUPPORT);

// Make them hostile to eachother, but not anyone else.
ChangeToStandardFaction(oMattSL, STANDARD_FACTION_GIZKA_1);
ChangeToStandardFaction(oEthanM, STANDARD_FACTION_GIZKA_2);

// Make them unkillable.
SetMinOneHP(oMattSL, TRUE);
SetMinOneHP(oEthanM, TRUE);

// Make them fight...
DelayCommand(0.5, ExecuteScript("k_ai_master", oMattSL, 1003));
DelayCommand(0.5, ExecuteScript("k_ai_master", oEthanM, 1003));

// Give the Crusher the power if he doesn't have it.
if (!GetHasSpell(FORCE_POWER_FORCE_CRUSH, oMattSL))
GrantSpell(FORCE_POWER_FORCE_CRUSH, oMattSL);

// Go to next step on next heartbeat.
SetLocalNumber(OBJECT_SELF, 1, 1);
}
// Step 2: Make sure the fight keeps going until the player within 15m of either of them.
else if (nState == 1) {
object oPC = GetFirstPC();
oMattSL = GetObjectByTag("n_mattsloran");
oEthanM = GetObjectByTag("n_ethanmorn");

// Player is close and within sight, go to next step...
if (((GetDistanceBetween2D(oMattSL, oPC) < 15.0) || (GetDistanceBetween2D(oEthanM, oPC) < 15.0))
&& (GetObjectSeen(oPC, oMattSL) || GetObjectSeen(oPC, oEthanM)))
{
SetLocalNumber(OBJECT_SELF, 1, 2);
}
// Player not close, make sure they don't stop fighting.
else if (!GetIsInCombat(oMattSL) || !GetIsInCombat(oEthanM)) {
DelayCommand(0.5, ExecuteScript("k_ai_master", oMattSL, 1003));
DelayCommand(0.5, ExecuteScript("k_ai_master", oEthanM, 1003));
}
}
// Step 3: Make the Crusher crush the Crushee...
else if (nState == 2) {
oMattSL = GetObjectByTag("n_mattsloran");
oEthanM = GetObjectByTag("n_ethanmorn");

// Disable combat AI.
SetLocalBoolean(oMattSL, 87, TRUE);
SetLocalBoolean(oEthanM, 87, TRUE);

// Stop the fighting to have better control of what's happening...
AssignCommand(oMattSL, ClearAllActions());
AssignCommand(oEthanM, ClearAllActions());
CancelCombat(oMattSL);
CancelCombat(oEthanM);

// The Crusher barks "Die!"
BarkString(oMattSL, 37374);

// Make victim killable...
SetMinOneHP(oEthanM, FALSE);

// Me will Crush you!
talent tCrush = TalentSpell( FORCE_POWER_FORCE_CRUSH );
AssignCommand(oMattSL, ActionUseTalentOnObject(tCrush, oEthanM));

// Set this step as done.
SetLocalNumber(OBJECT_SELF, 1, 3);
}
}
 mattcrowston
12-21-2005, 4:49 PM
#3
Thank you very much Stoffe, I was hoping you would be able to give me some input. I am going to try this out. But I have a couple questions first. What exactly is the function of a heart beat script. Admittedly creature events still baffle me too. And the invisible placeable. Do I spawn that from the trigger I was originally spawning the creatures from? And how close would I want to spawn the placeable to my fighters? Thanks again stoffe. I love this forum.


MattC
 stoffe
12-21-2005, 9:06 PM
#4
What exactly is the function of a heart beat script. Admittedly creature events still baffle me too. And the invisible placeable. Do I spawn that from the trigger I was originally spawning the creatures from? And how close would I want to spawn the placeable to my fighters? Thanks again stoffe. I love this forum.


A heartbeat script is a script that runs once every round on the object (creature, placeable, area etc) it's attached to. This is roughly (but not always exactly) every 6 seconds.

As for the invisible placeable it doesn't matter where you put it as long as you make it unbreakable. Though it's probably safest to place it somewhere outside the game world, such as inside a wall, below the floor or above the celing/sky of the area.

The purpose of this placeable would just be to maintain the scene and make the correct things happen. Delete the placeable when the scene is over to stop the script running.

I think using the heartbeat of a placeable to control the scene is a bit safer than using a recursive function on your trigger's script, since I don't remember if recursive function calls are terminated if the player leaves the module.

Alternatively, you could use the heartbeat script on the trigger to do the same, but I'm unsure if you could get rid of the script taking up resources (however small they might be) when the scene is over if you do this. I don't remember if RemoveHeartbeat() works on anything more than creatures and placeables, or if DestroyObject() works properly on triggers in KotOR/TSL (there was some bug with destroying triggers in NWN before, causing them to be half-destroyed where their scripts were still running but they couldn't be accessed).
 mattcrowston
12-22-2005, 5:10 AM
#5
A heartbeat script is a script that runs once every round on the object (creature, placeable, area etc) it's attached to. This is roughly (but not always exactly) every 6 seconds.

As for the invisible placeable it doesn't matter where you put it as long as you make it unbreakable. Though it's probably safest to place it somewhere outside the game world, such as inside a wall, below the floor or above the celing/sky of the area.

The purpose of this placeable would just be to maintain the scene and make the correct things happen. Delete the placeable when the scene is over to stop the script running.

Okay, I created a placeable, located just below the ground exactly where the fighters are supposed to be spawned. I compiled the script exactly like you posted it. Set it to the onheartbeat event of the placeable. Unfortuneately the fighters never spawn. Now I have a problem. I don't know how to debug this problem very well. I don't know if the placeable that I made isn't spawning, or if its the placeable thats not working once spawned, or possibly even the onheartbeat script. Any ideas on how I could work this out. Thanks.

MattC
 stoffe
12-22-2005, 7:13 AM
#6
Okay, I created a placeable, located just below the ground exactly where the fighters are supposed to be spawned. I compiled the script exactly like you posted it. Set it to the onheartbeat event of the placeable. Unfortuneately the fighters never spawn. Now I have a problem. I don't know how to debug this problem very well. I don't know if the placeable that I made isn't spawning, or if its the placeable thats not working once spawned, or possibly even the onheartbeat script.

Make sure your custom placeable doesn't have the Static flag set, or it won't be scriptable. Make sure you've spelled the name of the script correctly in the placeable's event handler slot, and that the name isn't longer than 16 characters. Also double-check that the Resrefs and Tags used in the script to spawn and access the NPCs are correct.

For debugging, use the function...SendMessageToPC(GetPartyLeader(), "The debug message..."); to print progress text to the Feedback log. That way you'll see what fires and what doesn't fire.
 mattcrowston
12-22-2005, 8:40 PM
#7
Make sure your custom placeable doesn't have the Static flag set, or it won't be scriptable. Make sure you've spelled the name of the script correctly in the placeable's event handler slot, and that the name isn't longer than 16 characters. Also double-check that the Resrefs and Tags used in the script to spawn and access the NPCs are correct.

Ok, thanks for being patient with me stoffe. I consider this a great help. I double-checked tags, resrefs, script names being called and script name lengths. Anyways it worked. I am pretty sure it was one of the script names. It was about 18 characters.

The thing is though. I know the script you posted for me had a check to see if the npc possessed the force power "force crush." And if he didn't the script would give it too him. Well anyway everything was working fine. He was yelling "Die!" But not casting "force crush" on his opponent. I went into the "MattsL" utc file and made sure he did possess "force crush." Now hes casting it on the other npc even before he yells "Die!" or the opponent has even been made killable.

I love how everything is working up to that point, and indeed it has actually worked exactly how I want it too once. But the 4 or so other times I tried it, it just didn't work so perfectly. Anyone with an idea or could help out, I would appreciate it. Happy holidays.


MattC
 mattcrowston
04-22-2006, 7:06 AM
#8
Hey hows everyone doing? I have been playing around with scripts, and I have even figured out how to use some of the dialogs functionality. Such as conditional scripts and global variables. I still have a lot ahead of me to actually create whats in my head. But I have made a really small recording of just a little snip of the action. This file is just over 1.5 megs and is about 12 secs long. I think its kinda neat, so if you are interested, check it out.

The file is a clip of a lightsaber battle betweeen Ethan Morn and Matts Loran.
Ethan Morn Gets Crushed (http://www.fileh.com/MattCrowston/Ethan_Morn_Gets_Crushed.avi)

If your not interested in the vid, heres just a screen.
http://www.fileh.com/MattCrowston/EthanMornCrushed.jpg)

I must pass all the credit onto Stoffe for providing me with some perfectly functional code, that I was about to work with. Without that, I would have nothing.

I am still working on a number of ideas. But this is purely for personal enjoyment. I wouldn't be expecting anything in the immediate future. But thanks a lot for checking it out.

MattC

Matt, because of the size of that pic I have altered the image to url links so those interested can click on it instead. Cool screenie though! ;) -RH
 mattcrowston
04-22-2006, 8:39 AM
#9
Matt, because of the size of that pic I have altered the image to url links so those interested can click on it instead. Cool screenie though! ;) -RH

Thank you Redhawke. That had crossed my mind too. Must have forgotten.


MattC
Page: 1 of 1