673f94723bbc8

673f94723d121
2 Guests are here.
 

Topic: Changing Player Starting Inventory Read 2327 times  

673f94723db1bRoSoDude

673f94723db83
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?

673f94723dcfeZylonBane

673f94723dd56
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.

673f94723de3cRoSoDude

673f94723de93
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.

673f94723e09dvoodoo47

673f94723e0ee
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 »

673f94723e1e7RoSoDude

673f94723e236
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.

673f94723e2f2voodoo47

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

673f94723e48bRoSoDude

673f94723e4d7
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.

673f94723e598voodoo47

673f94723e5e0
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).

673f94723e73bRoSoDude

673f94723e784
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 »

673f94723ed0bvoodoo47

673f94723ed68
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.

673f94723ee3bRoSoDude

673f94723ee8a
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.

673f94723ef5fvoodoo47

673f94723efab
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?

673f94723f090RoSoDude

673f94723f0da
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.

673f94723f482voodoo47

673f94723f4d2
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 »

673f94723f583ZylonBane

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

673f94723f742voodoo47

673f94723f792
I think BeginScript is recommended for reasons I can't recall right now.

673f94723f8a3RoSoDude

673f94723f8f2
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 »

673f94723f99cvoodoo47

673f94723f9e4
so it would seem.

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

673f94723faebZylonBane

673f94723fb37
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

673f94723fc3aRoSoDude

673f94723fc85
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 »

673f94723fd42ZylonBane

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

673f947240145RoSoDude

673f947240194
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 »

673f9472402ceZylonBane

673f947240323
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.

673f9472403dfvoodoo47

673f947240429
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.
2 Guests are here.
A whole world of nasty rusty scummy fun.
Contact SMF 2.0.19 | SMF © 2016, Simple Machines | Terms and Policies
FEEP
673f947240c5e