Loading a custom NPC into game through spawn point
by Paul Fassett · in Technical Issues · 08/02/2005 (11:29 am) · 13 replies
I've done a bit of looking around and didn't find much info on this an was wondering if you guys could shed some light on this. I have an npcmaker script that I am using to spawn in interactable npcs into the game. Right now it uses the demoplayer datablock and this is no good because I want a different shape file to be loaded based on perameters I input into the spawn sphere properties in the level editor.
Heres what I have so far.
This is in the markers.cs
datablock MissionMarkerData(NpcMaker : SpawnSphereMarker)
{
ingamename = "NpcMaker";
category = "Misc";
shapeFile = "~/data/shapes/markers/octahedron.dts";
NpcType = DemoPlayer;
};
What I want to do is get rid of the demoPlayer and use a custom datablock to spawn in an npc which uses the RPG dialog interact scripts already implemented and I want to define the shapefile to be used by some kind of dynamic field located in the spawn sphere in game. Sound possible?
I guess what I need to know is how do you add a dynamic field and how do you pull info like this from it?
Heres what I have so far.
This is in the markers.cs
datablock MissionMarkerData(NpcMaker : SpawnSphereMarker)
{
ingamename = "NpcMaker";
category = "Misc";
shapeFile = "~/data/shapes/markers/octahedron.dts";
NpcType = DemoPlayer;
};
What I want to do is get rid of the demoPlayer and use a custom datablock to spawn in an npc which uses the RPG dialog interact scripts already implemented and I want to define the shapefile to be used by some kind of dynamic field located in the spawn sphere in game. Sound possible?
I guess what I need to know is how do you add a dynamic field and how do you pull info like this from it?
#2
I am new to programming so even the simplest things elude me, so this resource you pointed out may be easy for a novice to follow but most certainly not a noob like me. So any further more indepth explaination would be great. Heres an example of what I am doing.
Markers.cs
In game.cs I have added
exec("./Purg_NPC");
And I have created a script called Purg_NPC.cs
Now I would have figured this to work seeing as how it should no longer be pulling info from DemoPlayer but the old player shapefile still shows up in game. I'm absolutly positive I'm coding retarded, so what am I doing wrong or what am I missing.
EDIT and also for some reason the shape that gets loaded is still using the demoplayer datablock. WTF?
08/02/2005 (11:57 am)
Ok I did read your comments on the resource but in your explaination you left things out saying "Don't remember what goes there". Also it looks like what you are doing in those resources is creating a datablock for each shapefile or each different npc, I want to define the shapefile through a dynamic field.I am new to programming so even the simplest things elude me, so this resource you pointed out may be easy for a novice to follow but most certainly not a noob like me. So any further more indepth explaination would be great. Heres an example of what I am doing.
Markers.cs
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
datablock MissionMarkerData(WayPointMarker)
{
category = "Misc";
shapeFile = "~/data/shapes/markers/octahedron.dts";
};
datablock MissionMarkerData(SpawnSphereMarker)
{
category = "Misc";
shapeFile = "~/data/shapes/markers/octahedron.dts";
};
datablock MissionMarkerData(NpcMaker : SpawnSphereMarker)
{
ingamename = "NpcMaker";
category = "Misc";
shapeFile = "~/data/shapes/markers/octahedron.dts";
//Added by Paul August 2. This datablock defines an NPC
//Datablock with default values with a basic shapefile defined
//The shape file must be changed through the datablock defined
//below in game through the dynamic field.
NpcType = NpcDataBlock;
//default setting in case something goes wrong with the code.
//NpcType = DemoPlayer;
};
//------------------------------------------------------------------------------
// - serveral marker types may share MissionMarker datablock type
function MissionMarkerData::create(%block)
{
switch$(%block)
{
case "WayPointMarker":
%obj = new WayPoint() {
dataBlock = %block;
};
return(%obj);
case "SpawnSphereMarker":
%obj = new SpawnSphere() {
datablock = %block;
};
return(%obj);
case "NpcMaker":
%obj = new SpawnSphere() {
datablock = %block;
name = "BigBadNpc";
script = "Test";
//Paul added this shape field on the 2nd
//of august. This field is meant to have
//the user be able to define the path to a
//shapefile for each npc spawned into the game
//by defining this dynamic field in the editor
//to point to the path of the desired shape file.
shape = "";
};
return(%obj);
}
return(-1);
}In game.cs I have added
exec("./Purg_NPC");
And I have created a script called Purg_NPC.cs
exec("~/data/shapes/Jacob/jacob.cs");
datablock NpcDataBlock()
{
shapeFile = "~/data/shapes/Jacob/jacob.dts";
};Now I would have figured this to work seeing as how it should no longer be pulling info from DemoPlayer but the old player shapefile still shows up in game. I'm absolutly positive I'm coding retarded, so what am I doing wrong or what am I missing.
EDIT and also for some reason the shape that gets loaded is still using the demoplayer datablock. WTF?
#3
Also, I don't know how the spawn sphere is spawning AIPlayers, but you would have to add a reference to the datablock you are choosing into the call to AIPlayer::Spawn()...
You may be able to do something like this, but I havent tried it and don't know if it will work:
What I would suggest doing, is tracing to figure out how the spawnsphere is calling AIPlayer::Spawn() ... Adding a datablock argument to AIPlayer::Spawn (As I detailed in my RPGDialog comments) and trying to feed the datablock from the SpawnSphere dynamic values into that spawn call.
Try and get that working. Once yo uget it working for one datablock you can create new datablocks for all your different shapes, and feed all of them in through the spawn sphere.
I have a question. Are you defining all of the RPGDIalog things in your sphere (or wlil you be) such as script, name, startquestion etc. ? That would be a very useful addition to the resource and you should contact the authro when you finish. I would also be very interested in the code. I did it manually (which is a pain in the ass). And I dont have time to do what you're doing.
:) Hope this helps.
My comments were in the order of "I don't remember what order the arguments are in"... Simply because all those comments were made while I was away from my work machine. Open AIPlayer.cs and figure out what order the arguments are in. Easy as that.
Also, Mark (who the comments were directed at) is a complete noob. My comments are noob friendly :) so long as you put the effort into understanding htem and using them.
08/03/2005 (4:22 am)
Paul, Don't dynamically define the shapefile... Deynamically define the datablock... Then define all the databocks you need in your NPC.cs file like this:PlayerData (NPCDataBlock : PlayerBody)
{
ShapeFile = "~/data/shapes/Jacob/jacob.dts";
}Also, I don't know how the spawn sphere is spawning AIPlayers, but you would have to add a reference to the datablock you are choosing into the call to AIPlayer::Spawn()...
You may be able to do something like this, but I havent tried it and don't know if it will work:
What I would suggest doing, is tracing to figure out how the spawnsphere is calling AIPlayer::Spawn() ... Adding a datablock argument to AIPlayer::Spawn (As I detailed in my RPGDialog comments) and trying to feed the datablock from the SpawnSphere dynamic values into that spawn call.
Try and get that working. Once yo uget it working for one datablock you can create new datablocks for all your different shapes, and feed all of them in through the spawn sphere.
I have a question. Are you defining all of the RPGDIalog things in your sphere (or wlil you be) such as script, name, startquestion etc. ? That would be a very useful addition to the resource and you should contact the authro when you finish. I would also be very interested in the code. I did it manually (which is a pain in the ass). And I dont have time to do what you're doing.
:) Hope this helps.
%obj = AIPlayer::Spawn(...); %obj.getDatablock().ShapeFile = "SHAPEDIRECTORY";
My comments were in the order of "I don't remember what order the arguments are in"... Simply because all those comments were made while I was away from my work machine. Open AIPlayer.cs and figure out what order the arguments are in. Easy as that.
Also, Mark (who the comments were directed at) is a complete noob. My comments are noob friendly :) so long as you put the effort into understanding htem and using them.
#4
08/03/2005 (5:49 am)
Yeah my main problem is that I had absolutely no idea how datablocks works. After doing a bit of reading I believe I now have a very firm grasp on whats going on. I appreciate your help. I'll look into implementing somethings from your post in a bit. Thank you very much for your reply.
#5
:)
08/03/2005 (6:33 am)
No problem. Feel free to email me as well if you have problems, or look me up on msn (email in profile):)
#6
datablock NpcDataBlock(){
shapeFile= "~/data/shapes/Jacob/jacob.dts";
};
im not sure exactly what youre attempting to do here, but as far as I know this wont work because npcdatablock is not a valid datablock type.
whenever you use "new" or "datablock" to create an object or datablock you must use one of the predefined object types like player/playerdata, aiplayer/aiplayerdata, camera/cameradata etc. am i right?
08/03/2005 (6:36 am)
Exec("~/data/shapes/Jacob/jacob.cs");datablock NpcDataBlock(){
shapeFile= "~/data/shapes/Jacob/jacob.dts";
};
im not sure exactly what youre attempting to do here, but as far as I know this wont work because npcdatablock is not a valid datablock type.
whenever you use "new" or "datablock" to create an object or datablock you must use one of the predefined object types like player/playerdata, aiplayer/aiplayerdata, camera/cameradata etc. am i right?
#7
new AIPlayer()
{
...
DataBlock;
...
};
08/03/2005 (7:48 am)
Sean - The issue was that he didnt know what a datablock was for or how to use it. He was trying to instantiate a player by calling datablock NpcDataBlock()... when what you have to do is create a datablock alled npcDataBlock and then use that to instantiate a player (or aiPlayer in this case)new AIPlayer()
{
...
DataBlock;
...
};
#8
So now I am trying to get the vector from the bounds transform and I am using a class I saw referenced to called getBounds() problem is I don't think this will work in script only c++ I'm probably so wrong about this :) Basically all these questions are being posted to meet the end of one goal which is to be able to get npcs in game that the player can talk to. Here is the offending code.
Code before the change
Here is the code after further modding to use the getBounds() class or function or whatever it's supposed to be.
Basically if someone knows how torque gets the transform of the players bounds that would be sexcelent. And thanks again.
EDIT: I just read through the whole part about submitting this as a resource, what I plan on doing is building a custom rpg dialog system and a custom npc spawning system that is a whole lot more user friendly then releasing the resource and a copy of our game demo with the package. I hope that at some point I can gear torque towards better object interaction and make it suitable out of the box for people trying to make an RPG.
This includes things like an NPC editor, dialog editor, and a better organization of NPC behaviors by creating a set of behaviors for NPCs like evilNpc goodNpc neutralNpc commonerNpc ect and being able to assign these behaviors to an npcs spawn sphere, that way you could spawn an npc with a particular set of default values and behaviours so they will react to you differently depending on what you do. It's going to be a huge process and I would love to get some voluntiers but no one seems to be willing so I have been going it alone with only the help of one friend.
08/03/2005 (8:26 am)
Ok I got another question, what I have set up is a way to interact with objects via a ray that gets it's vector from the eye node. Problem is in order for this to work the eye node must be in front of the player model and the players collision or the eye will only interact with the players mesh or collision. Problem with that is the eye node now goes inside of meshes screwing up the 3rd person camera.So now I am trying to get the vector from the bounds transform and I am using a class I saw referenced to called getBounds() problem is I don't think this will work in script only c++ I'm probably so wrong about this :) Basically all these questions are being posted to meet the end of one goal which is to be able to get npcs in game that the player can talk to. Here is the offending code.
Code before the change
function player::InteractionRay(%this)
{
%vec = %this.getEyeVector();
%nrm = VectorNormalize(%vec);
%vec = VectorScale(%nrm, 25);
%trans = %this.getEyeTransform();
%pos = PosFromTransform(%trans);
%targetpos = VectorAdd(%pos, %vec);
%target = ContainerRayCast(%pos, %targetpos, $TypeMasks::PlayerObjectType);
if (%target) {
%rayCast = firstWord(%target);
return %rayCast;
}
return false;
}Here is the code after further modding to use the getBounds() class or function or whatever it's supposed to be.
function player::InteractionRay(%this)
{
%vec = %this.getBounds();
%nrm = VectorNormalize(%vec);
%vec = VectorScale(%nrm, 25);
%trans = %this.getBounds();//getBounds() is a tsmesh class defined in
//tsmesh.cpp. I hope I can call it from script :P
%pos = PosFromTransform(%trans);
%targetpos = VectorAdd(%pos, %vec);
%target = ContainerRayCast(%pos, %targetpos, $TypeMasks::PlayerObjectType);
if (%target) {
%rayCast = firstWord(%target);
return %rayCast;
}
return false;
}Basically if someone knows how torque gets the transform of the players bounds that would be sexcelent. And thanks again.
EDIT: I just read through the whole part about submitting this as a resource, what I plan on doing is building a custom rpg dialog system and a custom npc spawning system that is a whole lot more user friendly then releasing the resource and a copy of our game demo with the package. I hope that at some point I can gear torque towards better object interaction and make it suitable out of the box for people trying to make an RPG.
This includes things like an NPC editor, dialog editor, and a better organization of NPC behaviors by creating a set of behaviors for NPCs like evilNpc goodNpc neutralNpc commonerNpc ect and being able to assign these behaviors to an npcs spawn sphere, that way you could spawn an npc with a particular set of default values and behaviours so they will react to you differently depending on what you do. It's going to be a huge process and I would love to get some voluntiers but no one seems to be willing so I have been going it alone with only the help of one friend.
#9
08/03/2005 (8:52 am)
Here is what we have so far.//this line of code takes the animations for shapeBaseData jacob.dts
//and compiles up the shapeFile and it's animations for use in the'
//below entity datablock
exec("~/data/shapes/Jacob/jacob.cs");
//==========================================================================
//this datablock defines the model to be used when entity
//is called to be created. Also some rendering options
//are set up here.
//==========================================================================
datablock playerData (entity)
{
renderFirstPerson = false;//tells the system to render in 3rd person on start
emap = true;//if an enviroment map channel exists on a texture
//for this model, emap will display it.
shapeFile = "~/data/shapes/Jacob/jacob.dts";
name = "Entity";//Don't know what the purpose of this is.
};
//===========================================================================
//This datablock looks like it is making NPC a child of the entity
//datablock which is good because all objects that are interactable
//should be entities, then have a seperate class for their actual
//definition. So for example there can be an Item datablock that
//is used to define and item that can be picked up or used. There
//should however be one of these datablocks for each item and each
//npc so instead of jacobs shapeFile being defined in the entity
//datablock, it should be defined in a datablock called jacob : entity.
//===========================================================================
datablock playerData (npc : entity)
{
className = NPC;//I don't know what this is for
category = "NPC";//Category is supposed to be used for adding a shapefile
//to a catagory inside the level editor worldEditor creator
//don't know what it's doing here. Would be good to use
//this later however so instead of spawning in npcs we
//can create an NPC category and place them by hand.
cmdCategory = "NPCs";//I'm guessing that this is a server command that can
//can be called to execute some code but I don't see
//where the code is that is going to be executed.
emap = true;
name = "NPC";
gotoline = 0;
};
//===========================================================================
//This function grabs the player class and I guess makes the getDialog class
//a child of the player object.
//===========================================================================
//
//bunch of nested case statements which handle our dialog go here, it's long tedious
//and we will be instead using a dialog editor to parse dialog into a text file. Maybe......
//
//then our actual spawn feature.
function addNPC (%name, %position)
{
if (%name $= "")
{
%name = "Generic NPC";
}
%player = new player (%name) {
datablock = npc;
aiPlayer = true;
};
if (%location == "") {
%location = "0 0 220 1 0 0 0";
}
%player.setTransform (%location);
return %player;
}
#10
As you can see we are using case statements to handle the dialog. This is just for testing purposes and is incredibly messy. But since yesterday I have had much success and I thank you for it.
08/03/2005 (8:53 am)
Heres the other half of it.// Highlights the row passed to it
function setHighlight (%row)
{
if (%row == 1 || %row == 4)
{
rBitOne.setBitmap ("control/client/interfaces/red");
rBitTwo.setBitmap ("control/client/interfaces/black");
rBitThree.setBitmap ("control/client/interfaces/black");
%row = 1;
}
else if (%row == 2)
{
rBitOne.setBitmap ("control/client/interfaces/black");
rBitTwo.setBitmap ("control/client/interfaces/red");
rBitThree.setBitmap ("control/client/interfaces/black");
%row = 2;
}
else if (%row == 3 || %row == 0)
{
rBitOne.setBitmap ("control/client/interfaces/black");
rBitTwo.setBitmap ("control/client/interfaces/black");
rBitThree.setBitmap ("control/client/interfaces/red");
%row = 3;
}
else
{
echo ("Error in menu.");
return setHighlight (1);
}
canvas.setContent ("dialogInterface");
return %row;
}
function clearResponses()
{
responseText.setText ("");
rBitOne.setBitmap ("control/client/interfaces/black");
rBitTwo.setBitmap ("control/client/interfaces/black");
rBitThree.setBitmap ("control/client/interfaces/black");
rTextOne.setText ("");
rTextTwo.setText ("");
rTextThree.setText ("");
}
function player::interaction (%this)
{
%obj = %this.interactionRay ();
if (dialogInterface.highlighted != 0)
{
%obj.makeSelection();
return;
}
if (!%obj)
{
return;
}
if (!%obj.getDialog())
{
if (!%obj.getResponse())
{
canvas.setContent(PlayerInterface);
return;
}
DialogText.setText("");
canvas.setContent("dialogInterface");
return;
}
clearResponses();
canvas.setContent("dialogInterface");
return;
}As you can see we are using case statements to handle the dialog. This is just for testing purposes and is incredibly messy. But since yesterday I have had much success and I thank you for it.
#11
If you mean you want to find all the NPC's in the game hten just do a container radius search for AIPlayers. And set htem a variable (isNPC = true;) in hte datablock... then use an if statement to deduce what is an NPC and what isnt.
08/03/2005 (9:25 am)
Paul - What exactly do you mean, "get npcs in game that the player can talk to" ?If you mean you want to find all the NPC's in the game hten just do a container radius search for AIPlayers. And set htem a variable (isNPC = true;) in hte datablock... then use an if statement to deduce what is an NPC and what isnt.
#12
08/03/2005 (10:01 am)
Thats the problem though. We don't want to do a radius search, we want whatever is within the players line of site to be interactable within a certain distance of the bounds. What happens is the player could be trying to talk to someone in front of them and end up talking to the guy beside him or behind him.
#13
EDIT:
The radius search with a distance of 100,000 will return all NPC's... Then check if it is an NPC (isNPC == true) ... then do a los check .
:)
08/03/2005 (11:23 am)
Ok... so do a radius search then do a line of sight check... See the AIGuard resource for an example on how to do a line of sight check.EDIT:
The radius search with a distance of 100,000 will return all NPC's... Then check if it is an NPC (isNPC == true) ... then do a los check .
:)
Torque Owner Chris Labombard
Premium Preferred