673f8ca6ec048

673f8ca6ed823
2 Guests are here.
 

Topic: Changing Player Starting Inventory Read 2310 times  

673f8ca6ee0cbRoSoDude

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

673f8ca6ee2b2ZylonBane

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

673f8ca6ee3dbRoSoDude

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

673f8ca6ee5f3voodoo47

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

673f8ca6ee732RoSoDude

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

673f8ca6ee83avoodoo47

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

673f8ca6ee93eRoSoDude

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

673f8ca6eea43voodoo47

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

673f8ca6eec1fRoSoDude

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

673f8ca6ef15fvoodoo47

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

673f8ca6ef27bRoSoDude

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

673f8ca6ef380voodoo47

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

673f8ca6ef4b7RoSoDude

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

673f8ca6ef810voodoo47

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

673f8ca6ef90cZylonBane

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

673f8ca6ef9fdvoodoo47

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

673f8ca6efb45RoSoDude

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

673f8ca6efc26voodoo47

673f8ca6efc6e
so it would seem.

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

673f8ca6efd8eZylonBane

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

673f8ca6efedbRoSoDude

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

673f8ca6f0011ZylonBane

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

673f8ca6f0336RoSoDude

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

673f8ca6f0516ZylonBane

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

673f8ca6f061fvoodoo47

673f8ca6f066b
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.
Kolya: It's not aliens, it's your squishy head.
Contact SMF 2.0.19 | SMF © 2016, Simple Machines | Terms and Policies
FEEP
673f8ca6f377e