6649244359d39

664924435a246
1 Guest is here.
 

Topic: Changing Player Starting Inventory Read 1691 times  

664924435ac06RoSoDude

664924435ac9d
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?

664924435ae64ZylonBane

664924435aec2
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.

664924435afccRoSoDude

664924435b030
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.

664924435b1bfvoodoo47

664924435b216
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 »

664924435b32eRoSoDude

664924435b38a
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.

664924435b469voodoo47

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

664924435b598RoSoDude

664924435b5f4
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.

664924435b6e1voodoo47

664924435b72e
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).

664924435b8feRoSoDude

664924435b956
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 »

664924435bf2fvoodoo47

664924435bf91
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.

664924435c05dRoSoDude

664924435c0af
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.

664924435c160voodoo47

664924435c1ab
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?

664924435c295RoSoDude

664924435c2eb
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.

664924435c706voodoo47

664924435c75c
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 »

664924435c851ZylonBane

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

664924435c95bvoodoo47

664924435c9ac
I think BeginScript is recommended for reasons I can't recall right now.

664924435ca9eRoSoDude

664924435caef
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 »

664924435cba2voodoo47

664924435cbf1
so it would seem.

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

664924435cd09ZylonBane

664924435cd5b
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

664924435ce83RoSoDude

664924435ced4
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 »

664924435cf79ZylonBane

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

664924435d289RoSoDude

664924435d2d9
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 »

664924435d41fZylonBane

664924435d470
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.

664924435d519voodoo47

664924435d563
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.
I might come across very disillusioned but I do crossword searches all night.
Contact SMF 2.0.19 | SMF © 2016, Simple Machines | Terms and Policies
FEEP
664924435d656