Author Topic: Change Name Script  (Read 3351 times)

0 Members and 1 Guest are viewing this topic.

Offline FelixJim

  • 28
  • User 11092
For a mission idea I had, I wanted to change a ship's name. Knowing that this was impossible an extremely bad idea, I FREDed a solution which involved some ship-create and ship-vanish trickery. I got this working, but found it was quite messy every single time I wanted to do it. Instead I decided to try and write a script that did this for me. It's worth noting that my entire experience in programming is the first few chapters of a beginners book of C++ a few years ago, and although this script seems to work, I've so little experience in this sort of thing I don't know where the pitfalls are, and I'm sure I've included an awful lot of bad practices if nothing else. I'm basically putting this out here for the critique I need so I know where I'm going wrong (bound to be something on a first attempt).

tl;dr: This isn't a release so much as a "please give advice" (although feel free if you do want to use it despite the lack of guarantees that it will work).

Code: [Select]
#Conditional Hooks
$Application: FS2_Open

$On Game Init:
[
--Swap first ship (old) with a similar ship (new) to give the illusion that the ship's name has changed
--Most obvious omission is the lack of any control over orders - will need to FRED these back in
cn = function (old, new)

local oldship = mn.Ships[old] --Create a handle for the old ship
local newship = mn.createShip(new, oldship.Class, oldship.Orientation, oldship.Position) --Create the new ship

--Copy over information from the old to the new ship
mn.runSEXP("ship-copy-damage !" .. old .. "! !" .. new .. "!")
newship.Team = oldship.Team
newship.AfterburnerFuelLeft = oldship.AfterburnerFuelLeft
newship.CountermeasuresLeft = oldship.CountermeasuresLeft
newship.WeaponEnergyLeft = oldship.WeaponEnergyLeft

--Physics
--This seems to be the cleanest way to keep the ship moving uninterrupted, but requires a delay before changing back (ohgodno)
newship.Physics.ForwardAccelerationTime = 0

local i = 1
while cn_ph[1][i] ~= nil and cn_ph[i][1] ~= false do --Find the first empty row of cn_ph
i = i + 1
end

cn_ph[1][i] = newship.Name --Copy over information needed to later change back the forward acceleration
cn_ph[2][i] = oldship.Physics.ForwardAccelerationTime
cn_ph[3][i] = mn.getMissionTime()+1

--Transfer Cargo
--This causes a null vec3d error... but not on its own. Most likely related to Mantis ticket 0002787, but doesn't cause any problems here
local dock = oldship.Class.Model.Dockingbays --Get a handle on the dockingbays
if #dock > 0 then --Requires a docking point
local dockname = dock[1]:getName() --Pick the first dockingbay
mn.runSEXP("jettison-cargo-delay !" .. old .. "! !0!") --Make sure old's dockingbay is free
mn.runSEXP("set-docked !" .. old .. "! !" .. dockname .. "! !" .. new .. "! !" .. dockname .. "!") --New doesn't move here
mn.runSEXP("transfer-cargo !" .. old .. "! !" .. new .. "!") --Transfer the cargo
mn.runSEXP("jettison-cargo-delay !" .. old .. "! !0!") --Undock ships
end

--If player knows what the old ship's cargo is, should know new cargo too
if (mn.evaluateSEXP("(is-cargo-known-delay !0! !" .. old .. "!)")) then
mn.runSEXP("set-scanned !" .. new .. "!")
end

--If player has old ship targeted, should now target new ship
if hv.Player.Target == oldship then
hv.Player.Target = newship
end

--If old ship is on escort list, new ship should be too (not necessarily same priority)
if #mn.EscortShips > 0 then --Don't bother doing anything if no ships are escorted
for i=1,#mn.EscortShips do --Cycle through escort ships to check if any are the old ship
if mn.EscortShips[i] == oldship then
mn.runSEXP("add-remove-escort !" .. new .. "! !50!") --Add new ship to escort list
break --No need to run through rest of escort list
end
end
end

mn.runSEXP("ship-vanish !" .. old .. "!") --Vanish the old ship

end
]

$On Gameplay Start:
[
cn_ph = {} --Global table used for the delay required during physics section of cn()
for i=1,3 do --3 columns
cn_ph[i] = {} --dynamic # of rows
end
]

$State: GS_STATE_GAME_PLAY
$On Frame:
[
if cn_ph ~= nil then --Prevent calling before creation or after housekeeping
for i=1,table.getn(cn_ph) do --Cycle through cn_ph for entries to change the forward acceleration back from the physics section of cn()
if cn_ph[1][i] and mn.getMissionTime() > cn_ph[3][i] then
mn.Ships[cn_ph[1][i]].Physics.ForwardAccelerationTime = cn_ph[2][i]
cn_ph[1][i] = false --Free up this row to be used again (other columns will just be overwritten)
end
end
end
]

$On Mission End:
[
--Housekeeping
cn_ph = nil
]

#End

One thing that has just occurred to me is that a ship named "false" very well might screw parts of this up... oops. Anyway, I'll see what you make of it as it is.

EDIT: I forgot to mention the known limitations of the script. Anything non-standard about the ship (changed loadout, for example) won't be preserved (could probably add this in, but as I don't need it for my use I won't bother unless others are interested in using it). The ship's orders will have to be re-given - I can see how to give orders via scripting, but I don't think you can access the ship's current orders, so it wouldn't know what orders to give. With regards to the motion of the ship, I've tried to build the script to give best results when the ship is following a waypoint and has already reached top speed; any other situation might cause a second of odd behaviour. I can't see a way to access the escort priority of the ship either, so if the original ship was in the escort list the new ship will be too, but always at priority 50, regardless of what the original ship was at. If the original ship has no docking points then the cargo won't be copied over. And as I mentioned before, if the new ship's name is "false", then I think it's forward acceleration will be permanently reduced to 0 (unverified). And... I think that's it.

EDIT2: No it isn't. If the original ship was docked to something this won't be preserved. I don't think this is possible, I'm not sure. This is a kind of hacky way of going about a simple name change, so there's probably a million and one other details that are lost (whether the ship is protected, other ships' orders regarding the original ship.... pretty much any of the Additional Ship Properties or locked weapons/afterburner, callsign, alt name, texture replacement, departure info are all things that are coming to mind even as I write). I'd really like to have a list of all the information the engine stores about a ship so I can tick things off as handled, potentially handleable or "you will need to reset this manually via sexp once script has run", but I haven't a clue where/how I'd get such a list.
« Last Edit: February 03, 2013, 05:38:29 am by FelixJim »
In-Mission Techroom Script v0.4 - See information from the techroom in game
Simple Animation Script v0.2 - Make your own on-screen animations for FSO
Visible Waypoints Script - Makes waypoints visible in-game
Run From File Script - Get around the pesky 31 character limit for script-eval

 

Offline mjn.mixael

  • Cutscene Master
  • 212
  • Chopped liver
    • Steam
    • Twitter
Tagged. I'm interested in this.
Cutscene Upgrade Project - Mainhall Remakes - Between the Ashes
Youtube Channel - P3D Model Box
Between the Ashes is looking for committed testers, PM me for details.
Freespace Upgrade Project See what's happening.

 

Offline FelixJim

  • 28
  • User 11092
Interested enough to test it at all? I was hoping for a bit more of a response, but I'd be glad of any feedback.
In-Mission Techroom Script v0.4 - See information from the techroom in game
Simple Animation Script v0.2 - Make your own on-screen animations for FSO
Visible Waypoints Script - Makes waypoints visible in-game
Run From File Script - Get around the pesky 31 character limit for script-eval

 

Offline zookeeper

  • *knock knock* Who's there? Poe. Poe who?
  • 210
Here's what I'd do...

Code: [Select]
#Conditional Hooks
$Application: FS2_Open

$On Game Init: [

    cn = function(oldname, newname)
        mn.Ships[oldname].Name = newname
    end

]

What makes you think that would be an extremely bad idea, especially in comparison to your method?

 
Here's what I'd do...

Code: [Select]
#Conditional Hooks
$Application: FS2_Open

$On Game Init: [

    cn = function(oldname, newname)
        mn.Ships[oldname].Name = newname
    end

]

What makes you think that would be an extremely bad idea, especially in comparison to your method?
When I saw this thread the first time I thought the same and tested it but for some reason the game ignored the change of .Name completely outside of scripting. What I found is that at least in my test cases the game didn't seem to care about two ships having identical names when one of them is created after mission start.


Then some general things I noticed in FelixJim's script:
I can't see any reason why you want to delay the physics setup at all (and even if a delay is necessary one frame should be fine).
Setup of docking and escort lists is something I would do in FRED using normal variables and events because both can be accessed or are known by the FREDer and can be really mission specific and tricky.
Ship create makes it hard to use that ship in events (FRED should complain all the time).
Here goes scripting and copy paste coding
Freespace RTS Mod
Checkpoint/Shipsaveload script

 

Offline zookeeper

  • *knock knock* Who's there? Poe. Poe who?
  • 210
When I saw this thread the first time I thought the same and tested it but for some reason the game ignored the change of .Name completely outside of scripting.

Well... now that you said that, I tested it myself too, and it worked for me just fine. I'm using an almost-latest nightly, but I doubt that makes a difference.

Code: [Select]
$Formula: ( when
   ( has-time-elapsed 7 )
   ( script-eval
      "cn('Alpha 2', 'Foobar')"
   )
)
+Name: Event name
+Repeat Count: 1
+Interval: 1

 

Offline FelixJim

  • 28
  • User 11092
When I tried to alter the name directly it actually worked perfectly, as far as I could see. Then I tried it in a debug build, which dropped dead from shock without so much as an error message, so I wasn't so sure it was a good idea.

As to the physics delay, from testing I think that the code needs finish at the script, do some physics calculations just in the regular engine, and then I need to change the value back. With single threading I don't see another way to dip in and out of the script like this.

Docking isn't carried over - that mess of docking nonsense is just to move the cargo across. It's kind of a fine line what should be handled in the script and in FRED, you can probably do most in either, so I was trying to see how much of it I could move script-side.

Creating ships does cause issues unless you reference the ship with a variable like @ship(Alpha 1) altered to @ship(mynewship) at the start in FRED (thank you Axem), but, again, I didn't see a way around that without setting up a lot more FRED-side than I wanted to.

Thanks all for comments!
In-Mission Techroom Script v0.4 - See information from the techroom in game
Simple Animation Script v0.2 - Make your own on-screen animations for FSO
Visible Waypoints Script - Makes waypoints visible in-game
Run From File Script - Get around the pesky 31 character limit for script-eval

 

Offline zookeeper

  • *knock knock* Who's there? Poe. Poe who?
  • 210
When I tried to alter the name directly it actually worked perfectly, as far as I could see. Then I tried it in a debug build, which dropped dead from shock without so much as an error message, so I wasn't so sure it was a good idea.

Well, I did try my version on a debug build, but it was in the simplest kind of mission and it certainly sounds possible that in a more complicated mission it could cause a severe problem somehow.