Ship Spawning
-
enum OP_TYPE; class BaseOp { public: BaseOp( OP_TYPE ); BaseOp( const BaseOp& ); virtual bool validate(); OP_TYPE op_type; int x08; }; struct SetPersonalityParams { SetPersonalityParams(); SetPersonalityParams( const SetPersonalityParams& ); virtual bool validate(); BaseOp baseop; // 0 int state_graph; // -1, used by validate void* x10; // -1 void* x14; // -1 bool state_id; // true - state_graph_id, false - state_graph Personality personality; };
-
Mumbles about not even being allowed to have a go and fail
I kid, nice job adoxa, this’ll help tremendously.
-
Well spawning ships is rock solid now, can spawn any ship with a custom AI at will.
What I’m trying to figure out now are, in order:
-How to stop the NPC from dropping all of its equipment on death
-How to control the NPC
-How to add the NPC to the “normal” NPC list so that it disappears automatically when out of rangeI’m pretty sure the 1st point’s key is in the ShipInfo struct, while the second point obviously lies in the reversal of the Op structs.
I wish I knew just how you can find things out so fast, adoxa
-
Yeah, me too. How is that even possible? Maybe I’m just not knowledgeable enough in the subject matter but I wasn’t aware that you could even pull something so detailed (especially with regard to names of things) from just assembly level de-compilation.
-
Defining those structures was relatively trivial, due to exported constructors. Doing the points above will take a bit more effort, which I’ll not do (not for a while, anyway, by which time I’ll have forgotten). I expect point two can be solved by set_current_directive, so I suppose you want IDirectiveInfo and the remaining Ops?
-
I’m not asking you to do them at all, you’re a busy man with a lot on your plate
What I wondered is whether you could give some insight on how to do what you do. A tutorial if you want, just some tips otherwise. I’d like to stop having to ask you or w0d all the time, but I’ve never gleaned much from disassemblies
-
Well, if you want to give it a go, here’s an example using DirectiveFollowOp.
* Exported function Common.??0DirectiveFollowOp@AI@pub@@QAE@XZ | =1<===== 062DAF30 8BC1 mov eax, ecx 062DAF32 33C9 xor ecx, ecx 062DAF34 C7400404000000 mov dword[eax+04], 00000004 062DAF3B 894808 mov [eax+08], ecx 062DAF3E C7001CE13906 mov dword[eax], Common.??_7DirectiveFollowOp@AI@pub@@6B@ 062DAF44 89480C mov [eax+0C], ecx 062DAF47 C7401000001643 mov dword[eax+10], 43160000 ; 150 062DAF4E 894814 mov [eax+14], ecx 062DAF51 894818 mov [eax+18], ecx 062DAF54 89481C mov [eax+1C], ecx 062DAF57 C740200000C843 mov dword[eax+20], 43C80000 ; 400 062DAF5E C3 ret ```I have a separate program to demangle names, which gives us the namespace and constructor. [eax] is the virtual function table, [eax+04] & [eax+08] are from BaseOp. Looking at Follow in the mission files and where it reads it in content.dll (6F27400), +0C would be the nickname, but I still don't know what the other values are, apart from being float (probably maximum distance, x,y,z offset and something else). So assuming that, we can say:
namespace pub
{
namespace AI
{
enum OP_TYPE { FollowOp = 4 }; // and the others, of courseclass DirectiveFollowOp : public BaseOp // inheritance based on observation { public: DirectiveFollowOp()/* : BaseOp( FollowOp )*/; // some more functions here, should be in the CoreSDK virtual bool validate(); UINT leader; // 0 float max_distance; // 150 Vector ofs; // 0, 0, 0; copy constructor indicates Vector float unknown; // 400 };
}
} -
Very nice, that should help a lot!
Can I know what program(s)/steps you use to get the output you’ve shown? I think I read you use Ollydbg to disassemble the DLLs, but how do you get the values like 150 or 400? From the INIs, from a debug process?
-
Excuse me while I go hang myself for being so blind. -_-
-
The listing was generated by a customised PEReaDeR, which I’ve attached, since I should do a bit more on it before releasing the patch (I haven’t updated my first patches with Freddy’s better code). Use perdr -b common.dll >common.lst for the listing shown. I’ve also included the demangler:
[[url=http://adoxa.110mb.com/tde/]tde] c:/Projects/undec ??0DirectiveFollowOp@AI@pub@@QAE@XZ
public: __thiscall pub::AI::DirectiveFollowOp::DirectiveFollowOp(void) -
FriendlyFire wrote:
Excuse me while I go hang myself for being so blind. -_-Never do that.
Go blow away a criminal who escapes justice.
You will feel a lot better afterwards!
And then 8 years later they will let you out and you can do another one!
-
class IMPORT DirectiveGotoOp : public BaseOp { public: DirectiveGotoOp(class DirectiveGotoOp const &); DirectiveGotoOp(void); virtual bool validate(void); public: int x00; int iGotoType; // 1 = Vec, 0 = Ship Vector vPos; // pos int iTargetID; // id Vector vSpline1; // ? Vector vSpline2; // ? Vector vSpline3; // ? Vector vSpline4; // ? float fRange; float fThrust; bool x58; // in INIs, don't know what it does bool x59; // Always true? short iFlag; // 0 = goto, 1 = goto_cruise, 256 = goto_no_cruise int x5C; float x60; // 200 float x64; // 500 int x68; int x6C; };
-
Remove x00.
iGotoType also has 2 = spline, 3 = undefined (I guess, that’s what the constructor does).
short iFlag; is actually bool goto_cruise; bool goto_no_cruise; (“goto” is ignored).
x59 has no apparent reference in content (certainly not where it reads the Goto lines), maybe it gets used in common. -
I gathered as much for the types (I just hadn’t tested it). For the iFlag, I kinda guessed they’d be bools. It seems that goto_cruise overrides goto_no_cruise, too, if both are set to true inadvertently.
As for x00, I had to add that because of a hack I did to BaseOp. I can tell you it works perfectly right now so the definitions are proper
-
Hello everyone,
I’m very interested in this topic, and I follow it since its beginning. Thanks to your great work, I slowly understand how to make NPC’s spawning.
As Wodk4 said, It would be nice to give Waypoints to NPC. Unfortunately, I didn’t reach this objective.
Here the first thing I tried to do :
pub::AI::DirectiveGotoOp testOP; testOP.iGotoType = 1; testOP.vPos.x = -14507; testOP.vPos.y = 124; testOP.vPos.z = 11492; testOP.iFlag = 256; pub::AI::SubmitState(iSpaceObjID, (pub::AI::BaseOp*)&testOP);
but this does’nt work. (This would be too simple, you can laugh at me)
so I tried to use the Personality.cpp given by Adoxa, but unfortunately, I don’t know how to use it. I tried to place it into server.h, in the AI namespace, but I have some errors.
Can you help me to find what’s wrong ?
(No code required, but at least a little clue)Thanks a lot,
Kid -
pub::AI::DirectiveGotoOp testOP; ```Is wrong. It's waiting for a pointer (notice the *). Use
pub::AI::DirectiveGotoOp* go = new pub::AI::DirectiveGotoOp();
And remember to replace all the "." by "->". You also need to define fRange and fThrust.
-
Well, I tried to do as you said, but the spawning ship really doesn’t want to move. I think I haven’t the skill yet to understand it well, and don’t want to annoy you more than that. I don’t know what fThrust & fRange stand for, even playing with values.
(The weird thing, is that in the code quoted by Wodk4, it’s not a pointer which is used in the submit state line).Here’s my current code, according that iSpaceObjID represent a ship we’ve just created. The waypoint is approximatively 500 m away from the spawn point.
pub::AI::DirectiveGotoOp* testOP = new pub::AI::DirectiveGotoOp(); testOP->iGotoType = 1; testOP->vPos.x = -14507; testOP->vPos.y = 124; testOP->vPos.z = 11492; testOP->iFlag = 1; testOP->fRange = 1; testOP->fThrust = 1; pub::AI::SubmitState(iSpaceObjID, (pub::AI::BaseOp*)&testOP);
Really, if you don’t have the time / motivation to help me, no problem, I 'll try to go on by myself.
A huge Thanks anyway