6649fd31e243b

6649fd31e29b5
1 Guest is here.
 

Topic: Changing Player Starting Inventory Read 1699 times  

6649fd31e3105RoSoDude

6649fd31e316f
I thought I'd make a new thread for this since it's something people might want to look into for their own mods. I'd like to see if there's any way to swap out or add to the player's gear from character creation. I'm willing to do custom scripting to make it happen, but I'm not sure where to start.

I found all of the current starting items in station.mis:
  • StarterAmp (501) - Laser Pistol if the player starts chooses OSA
  • StarterLaser (67) - Laser Pistol if the player starts chooses Energy skill
  • StarterLauncher (69) - Grenade Launcher if the player starts chooses Heavy skill
  • StarterTool (502) - Maintenance Tool if the player starts chooses Maintenance skill

Does anyone know what scripts, links, etc. govern the movement of these objects into the player's inventory?

6649fd31e32c4ZylonBane

6649fd31e331c
I've only looked at it enough to know that it's really complicated. I'd recommend just finding the links and following them back. It might not be possible to do anything truly custom beyond swapping out what the built-in scripts are doing.

6649fd31e33f5RoSoDude

6649fd31e3448
Well, that's the odd thing. I can't find any links to the starter items at all. Maybe I just don't know my ShockEd commands, but all of the other teleporting objects in that debug room (droids, assignment panel textures) have clear SwitchLinks to TeleportTraps.

6649fd31e35d8voodoo47

6649fd31e3628
I suspect the Station scripts just target the StarterSomething objnames directly, no links involved. basically, it's evil, hardcoded stuff, and making it user configurable would probably mean recreating all the Station scripts in Squirrel from scratch.

//yep, you can delete the original StarterSomething object, create any other object, give it the same name, and it will get added, so for example, delete StarterLauncher, create a shotgun, name it StarterLauncher, and you'll get a shotgun if you choose the heavy weapons career path as a marine.
« Last Edit: 17. April 2020, 21:44:45 by voodoo47 »

6649fd31e370bRoSoDude

6649fd31e3759
Maybe I can work out some evil hackery of my own, then. I've just successfully squirrel scripted property overrides for replacement objects created via TrapTweqEmit (so I can e.g. convert a Pistol into a Laser Pistol and then break the latter), so something like this feels like it might be within reach. I'll update here if I make any progress.

6649fd31e3804voodoo47

6649fd31e3850
I think you would have to reverse-engineer the original scripts, not sure whether that's doable. also, edit to my previous post.

6649fd31e392bRoSoDude

6649fd31e3978
The edit was everything I needed to know, thanks! I have starting equipment swap working from DML + squirrel script now. There's still a minor bug in that it stays as a Grenade Launcher inventory until I drop the item and voila, it becomes a Stasis Field Generator. I can probably fix that up.

6649fd31e3a4cvoodoo47

6649fd31e3a98
I think NVscript is capable of creating a named object - I would just kill the StarterLauncher upon level start, and then use a junk object to create the new object and name it StarterLauncher (with a small delay, two StarterLauncher objects trying to exist at the same time  doesn't sound like a good idea).

6649fd31e3c32RoSoDude

6649fd31e3c7f
NVScript has a NVNameOnCreation script, which would require me to create a new archetype for the Stasis Field Generator I want as a starter lest the script be applied to every other mission. And I can't create new archetypes via DML, as far as I know.

My current idea is to use NVCreateAndLink from say, A MaleRick (171) to create a Stasis Field Generator and then use a custom squirrel script to set the name of the linked object  to "StarterLauncher". However, I'm having trouble with the syntax for NVCreateAndLink. The below doesn't seem to do anything. I don't really know what I'm doing with NVRelayTrap/NVSlayMeTrap, that's copied from another thread because the game threw an error for recursive object creation without them.

Code: [Select]
+ObjProp 69 "Scripts" //StarterLauncher
{
    "Script 0" "NVDeleteTrap"
    "Script 1" ""
    "Script 2" ""
    "Script 3" ""
    "Don't Inherit" true
}
+ObjProp 69 "ObjList" = "NVDeleteTrapOn="BeginScript"; NVDeleteTrapDeleteSelf=1" //StarterLauncher
+ObjProp 171 "Scripts" //A MaleRick
{
    "Script 0" "NVCreateAndLink"
    "Script 1" "NVRelayTrap"
    "Script 2" "NVSlayMeTrap"
    "Script 3" ""
    "Don't Inherit" true
}
+ObjProp 171 "ObjList" = "NVCreateAndLinkOn="BeginScript"; NVCreateAndLinkCreate="-25"; NVCreateAndLinkLinkType="~SwitchLink"; NVCreateAndLinkLoc="3.0,0.0,0.0"; NVRelayTrapOn="BeginScript"; NVRelayTrapOnDelay=500; NVRelayTrapTDest="[me]"; NVRelayTrapTOn="killself" //A MaleRick
« Last Edit: 18. April 2020, 20:23:59 by RoSoDude »

6649fd31e4147voodoo47

6649fd31e41a1
NVScript has a NVNameOnCreation script, which would require me to create a new archetype for the Stasis Field Generator I want as a starter lest the script be applied to every other mission. And I can't create new archetypes via DML, as far as I know.
no and no. NVNameOnCreation lets you specify a custom name;
When this object is created, or at the beginning of the simulation (Sim and Create messages), the object with this script is given the name specified by the NVSymName parameter, unless an object with that name already exists.
If the name is already taken, nothing will happen unless you use the NVSymNameIncrement=1 parameter; then a number will be appended to the end of the chosen name until an unused name is found, up to 99 attempts. (For example, if you created multiple objects all set to be automatically given the name "NamedObject", then the first would be named "NamedObject", the second would become "NamedObject1", the next "NamedObject2", and so on, up to "NamedObject99".)
and you actually can create new archetypes via DML now (see the latest ND documentation). though I think you really don't need to go that far in this scenario, NVNameOnCreation should suffice.

6649fd31e429fRoSoDude

6649fd31e42f1
But how can I place the NVNameOnCreation script on an object that I've created via DML? I'd need to place it in one of the script slots in the gamesys.dml, since I don't have the concrete object ID. That's what I'm not understanding.

6649fd31e43b8voodoo47

6649fd31e4405
aha, right. hmmm, something creative will be required here - no proper answer to give right now (all I can say is that it should be possible to pop an item and name it via NVscript), I would have to jump into this myself. do you want me to?

6649fd31e44f3RoSoDude

6649fd31e4546
Well, what I'd really like is for you to explain what I'm doing wrong regarding NVCreateAndLink. Nothing gets created, A MaleRick (171) just stands there with his stupid smug face and I don't get a Stasis Field Generator out of the deal. I don't need the poor bastard to be slain either, I just want a SFG to pop out with a SwitchLink to it so I can work some squirrel script renaming magic.

6649fd31e4932voodoo47

6649fd31e4984
the objlist has bad syntax - it needs to look like this:
+ObjProp 171 "ObjList" = "NVCreateAndLinkOn="BeginScript"; NVCreateAndLinkCreate="-25"; NVCreateAndLinkLinkType="~SwitchLink"; NVCreateAndLinkLoc="3.0,0.0,0.0"; NVRelayTrapOn="BeginScript"; NVRelayTrapOnDelay=500; NVRelayTrapTDest="[me]"; NVRelayTrapTOn="killself";"
and even with that corrected, it will explode the editor really nicely - you need to make sure it fires only once, see [ScriptName]Count. there might be more issues, we'll see.

//also, SwitchLink is probably not the best choice here - if you need a neutral link that won't cause any unwanted activations, use ScriptParams. so;
+ObjProp 171 "ObjList" = "NVCreateAndLinkOn="BeginScript"; NVCreateAndLinkCount=1; NVCreateAndLinkCreate="-25"; NVCreateAndLinkLinkType="~ScriptParams"; NVCreateAndLinkLoc="3.0,0.0,0.0"; NVRelayTrapOn="BeginScript"; NVRelayTrapOnDelay=500; NVRelayTrapTDest="[me]"; NVRelayTrapTOn="killself"; NVSlayMeTrapOn="killself";"
the guy is still not killing himself, one moment. //ok, if you want to slay the guy, you need to actually activate the SlayMeTrap - added to the code above.

however, I have a hunch you actually want to remove him - in that case you will have to use NVGibTrap. the full code:
+ObjProp 171 "Scripts"
{
    "Script 0" "NVCreateAndLink"
    "Script 1" "NVRelayTrap"
    "Script 2" "NVGibTrap"
    "Script 3" ""
    "Don't Inherit" true
}
+ObjProp 171 "ObjList" = "NVCreateAndLinkOn="BeginScript"; NVCreateAndLinkCount=1; NVCreateAndLinkCreate="-25"; NVCreateAndLinkLinkType="~ScriptParams"; NVCreateAndLinkLoc="3.0,0.0,0.0"; NVRelayTrapOn="BeginScript"; NVRelayTrapOnDelay=500; NVRelayTrapTDest="[me]"; NVRelayTrapTOn="killself"; NVGibTrapOn="killself";"
an AI is not an ideal junk object to pick for shenanigans, btw.

also, no need for NVscripting on the StarterLauncher, just TweqDelete it (set the Tweq Delete prop on it with Halt: Destroy Obj, and DeleteState Anims: On //and the sim flag, duh. always forgetting that one).

one last thing - if you are deleting the junk object because you want to kill its link to the new SFG, you don't need to bother - the (ScriptParams) link will be removed when you exit the level (with the gun).
« Last Edit: 19. April 2020, 05:49:13 by voodoo47 »

6649fd31e4a4fZylonBane

6649fd31e4a9d
If you use Sim, instead of BeginScript, that message will only be sent once, the first time the map is initialized.

6649fd31e4b3dvoodoo47

6649fd31e4b89
I think BeginScript is recommended for reasons I can't recall right now.

6649fd31e4c8bRoSoDude

6649fd31e4cd9
I actually have the inventory transfer working with a custom squirrel script now. I still need to clean up my mission DML with your suggestions (TweqDelete on StarterLauncher, use ScriptParams flavor, mess around with a junk object instead of the NPC), but I have a bigger problem: the Stasis Field Generator I end up with is lacking any strings. No name, no modification info, etc. I noticed that StarterLauncher (69) had some extra strings in the Obj category (Object Look string, Object name, Object short name), so maybe I have to add those? Will be an easy fix.
« Last Edit: 18. April 2020, 22:23:51 by RoSoDude »

6649fd31e4d8bvoodoo47

6649fd31e4dd7
so it would seem.

no wonder no FM author tried to replicate the Station with all of its evils.

6649fd31e4ef2ZylonBane

6649fd31e4f40
It's because all the weapons given in training have custom names. The string system in Dark tries to automatically match up object names with the corresponding names in the string files, or the archetype name if no name is given. So yeah, when you give something a custom name you have to specify what string keys it should use.

See here for a more extreme version of this problem: https://www.systemshock.org/index.php?topic=9658.msg114385#msg114385

6649fd31e505eRoSoDude

6649fd31e50ab
Yeah, I got it all sorted already. Will post my solution in a second, but can someone point out what I'm doing wrong with TweqDelete, if anything? It works when I'm in the debug room with StarterLauncher (69), but it doesn't engage when I'm not in the same zone (NVSpy intercepts physics messages that indicate it's colliding with the ground instead of deleting itself). I noted the same thing other Tweq commands before. NVDeleteTrap worked (albeit in a roundabout way), so I might stick with that.

Code: [Select]
+ObjProp 69 "CfgTweqEmit" //StarterLauncher
{
"Halt" Destroy Obj
}
+ObjProp 69 "StTweqDelete" //StarterLauncher
{
"AnimS" On
}
« Last Edit: 19. April 2020, 01:47:55 by RoSoDude »

6649fd31e5160ZylonBane

6649fd31e51ae
By default tweqs only execute when the player is nearby. You have to add the Sim flag.

6649fd31e54d3RoSoDude

6649fd31e5529
That, and I was also using CfgTweqEmit instead of CfgTweqDelete. Oops. Thanks a bunch guys.

Here's my method for replacing the Grenade Launcher with a Stasis Field Generator in the player's starting equipment if they choose the Marine JM-432 Station assignment.

This goes in station.mis.dml:
Code: [Select]
////Replace the Grenade Launcher start with a Stasis Field Generator start
//Delete the existing Grenade Launcher
+ObjProp 69 "CfgTweqDelete" //StarterLauncher
{
    "Halt" Destroy Obj
    "AnimC" Sim
}
+ObjProp 69 "StTweqDelete" //StarterLauncher
{
    "AnimS" On
}
//Now use a junk object to spawn the SFG and set its name to StarterLauncher with some scripts
+ObjProp 107 "Scripts" //A Crate#1
{
    "Script 0" "NVCreateAndLink"
    "Script 1" "NVRelayTrap"
    "Script 2" ""
    "Script 3" "rsdSetNameOnLink"
    "Don't Inherit" true
}
+ObjProp 107 "ObjList" = "NVCreateAndLinkOn="BeginScript"; NVCreateAndLinkCreate="-25"; NVCreateAndLinkLinkType="ScriptParams"; NVCreateAndLinkLoc="5.0,-2.0,1.0"; NVCreateAndLinkCount=1; NVRelayTrapOn="BeginScript"; NVRelayTrapOnDelay=500; NVRelayTrapTDest="[me]"; NVRelayTrapTon="rsdSetName";" //A Crate#1
+ObjProp 107 "DesignNoteSS" = "rsdSetName="StarterLauncher"; rsdSetObjLookS="stasis_field_generator"; rsdSetObjName="Stasis_Field_Generator"; rsdSetObjShort="Stasis_Field_Generator"; rsdSetSett1="Stasis_Field_Generator"; rsdSetSett2="Stasis_Field_Generator"; rsdSetSHead1="Stasis_Field_Generator"; rsdSetSHead2="Stasis_Field_Generator";" //A Crate#1

Then this goes in a sq_scripts\*.nut file:

Code: [Select]
// ================================================================================
// RSD: Used to set names of objects created via NVCreateAndLink, only works with ScriptParams links
// Reads in the name and string references from Editor/Design Note
// Otherwise tries to use the object's default values, if it has any set
class rsdSetNameOnLink extends SqRootScript {
function OnrsdSetName() {
local link = Link.GetOne("ScriptParams", self);
if (link) {
local DstObj = sLink(link).dest;
local NameStr = "rsdSetName" in userparams() ? userparams().rsdSetName : Object.GetName(DstObj);
local ObjLookStr = "rsdSetObjLookS" in userparams() ? userparams().rsdSetObjLookS : Property.Get(DstObj, "ObjLookS");
local ObjName = "rsdSetObjName" in userparams() ? userparams().rsdSetObjName : Property.Get(DstObj, "ObjName");
local ObjShort = "rsdSetObjShort" in userparams() ? userparams().rsdSetObjShort : Property.Get(DstObj, "ObjShort");
local Sett1 = "rsdSetSett1" in userparams() ? userparams().rsdSetSett1 : Property.Get(DstObj, "Sett1");
local Sett2 = "rsdSetSett2" in userparams() ? userparams().rsdSetSett2 : Property.Get(DstObj, "Sett2");
local SHead1 = "rsdSetSHead1" in userparams() ? userparams().rsdSetSHead1 : Property.Get(DstObj, "SHead1");
local SHead2 = "rsdSetSHead2" in userparams() ? userparams().rsdSetSHead2 : Property.Get(DstObj, "SHead2");

Object.SetName(DstObj, NameStr);
Property.SetSimple(DstObj, "ObjLookS", ObjLookStr);
Property.SetSimple(DstObj, "ObjName",ObjName);
Property.SetSimple(DstObj, "ObjShort",ObjShort);
Property.SetSimple(DstObj, "Sett1",Sett1);
Property.SetSimple(DstObj, "Sett2",Sett2);
Property.SetSimple(DstObj, "SHead1",SHead1);
Property.SetSimple(DstObj, "SHead2",SHead2);
}
}
}

And here's proof it works as claimed:


It's a bit messy, but it's the best solution I could come up with for all of the missing strings. I may look into making a more general script that could allow one to create and link up other starting equipment as desired, rather than hacking it with the mission's built-in script to move the starter items.

EDIT: I should note, I have my own solution for the starting properties (ammo, condition, broken state) of the spawned weapon as well. May provide details later, I'm probably going to rework it some more.
« Last Edit: 19. April 2020, 04:22:00 by RoSoDude »

6649fd31e5688ZylonBane

6649fd31e56d8
If you're going to get Squirrel involved, you may as well do the entire thing with a script. Something like this:
Code: [Select]
class starterReplace extends SqRootScript {
// spawn new object and destroy this one
function OnSim() {
local objName = Object.GetName(self);
Object.SetName(self, "");
local archetype = getParam("Archetype", "Object");
local stringName = getParam("StringName", fixStringName(archetype));
local obj = Object.Create(archetype);
Object.Teleport(obj, Object.Position(self), vector());
Object.SetName(obj, objName);
setString(obj, "ObjName", stringName);
setString(obj, "ObjLookS", stringName);
setString(obj, "ObjShort", stringName);
if (Object.InheritsFrom(obj, "Weapon")) {
setString(obj, "Sett1", stringName);
setString(obj, "Sett2", stringName);
setString(obj, "SHead1", stringName);
setString(obj, "SHead2", stringName);
}
Object.Destroy(self);
}

// fetch a parameter or return default value
function getParam(key, defVal) {
return key in userparams() ? userparams()[key] : defVal;
}

// set string to archetype value, otherwise archetype name
function setString(obj, prop, def) {
local val = Property.Get(Object.Archetype(obj), prop);
Property.SetSimple(obj, prop, val ? val : def);
}

// replace all spaces with underscores
function fixStringName(txt) {
local i, c;
local txt2 = "";
for (i = 0; i < txt.len(); i++) {
c = txt.slice(i, i + 1);
txt2 += c == " " ? "_" : c;
}
return txt2;
}
}
Just drop on the object you want to replace, and supply the archetype you're replacing it with as a design note parameter.

6649fd31e5795voodoo47

6649fd31e57e2
that's going to be very useful in the future.

I almost had a pretty simple solution involving an extra dml archetype going, but not going to bother now, this is much more proper.
1 Guest is here.
Oh, and it's the passion that you play.
Contact SMF 2.0.19 | SMF © 2016, Simple Machines | Terms and Policies
FEEP
6649fd31e58dc