6742ede39b913

6742ede39ced8
1 Guest is here.
 

Topic: Changing Player Starting Inventory Read 2328 times  

6742ede39d890RoSoDude

6742ede39d907
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?

6742ede39da7eZylonBane

6742ede39dad6
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.

6742ede39dbb1RoSoDude

6742ede39dc0d
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.

6742ede39ddf1voodoo47

6742ede39de48
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 »

6742ede39df3aRoSoDude

6742ede39df8b
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.

6742ede39e045voodoo47

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

6742ede39e168RoSoDude

6742ede39e1b6
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.

6742ede39e29cvoodoo47

6742ede39e2e9
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).

6742ede39e498RoSoDude

6742ede39e4e5
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 »

6742ede39ea0fvoodoo47

6742ede39ea67
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.

6742ede39eb33RoSoDude

6742ede39eb80
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.

6742ede39ec2dvoodoo47

6742ede39ec77
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?

6742ede39ed90RoSoDude

6742ede39ede5
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.

6742ede39f162voodoo47

6742ede39f1b1
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 »

6742ede39f25cZylonBane

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

6742ede39f394voodoo47

6742ede39f3de
I think BeginScript is recommended for reasons I can't recall right now.

6742ede39f4bfRoSoDude

6742ede39f508
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 »

6742ede39f5a0voodoo47

6742ede39f5e9
so it would seem.

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

6742ede39f6d6ZylonBane

6742ede39f71e
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

6742ede39f822RoSoDude

6742ede39f86b
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 »

6742ede39f8fcZylonBane

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

6742ede39fc0dRoSoDude

6742ede39fc5b
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 »

6742ede39fdb8ZylonBane

6742ede39fe07
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.

6742ede39fec0voodoo47

6742ede39ff0a
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.
and it was a hot and rainy summer in a city
Contact SMF 2.0.19 | SMF © 2016, Simple Machines | Terms and Policies
FEEP
6742ede3a08a4