Left 4 Dead 2

Left 4 Dead 2

35 个评价
Spawning Specific SI model and use multiple at once. (mapping)
由 мяFunreal 制作
This guide shows you how you can set up your map to use any SI model you want.
Like a spawnpoint that only spawns L4D1 hunters, or maybe you want a custom SI for a single spawnpoint.
   
奖励
收藏
已收藏
取消收藏
Foreword
Back in 2019 Daroot Leafstorm wrote a vscript for me which i had used to spawn the Sacrifice Tank in TUMTaRA_Infected.
After the L4D1 models came out in "The Last Stand" i modified the script to include all l4d1 variants and the male and female boomer.
At that point i was able to spawn any SI model i wanted to, no matter if they were supposed to spawn or not.

Usually the missionfile would decide which variants are used.
But that missionfile forces the model variant onto every SI of that class, which is no good.
Using this script, only specific spawnpoints will have a unique SI model.

This could also be used to end up with a custom SI model for one single spawnpoint.
Imagine the Sugarmill from Hard Rain, but every witch uses a different model.
Multiple different Fallen Survivors (or other CI) for specific locations is also possible with this.
Alternatively it can be used on survivors. Like the L4D1 bots used in "The Passing" but two different Louis' to use the Browning Machinegun (only Louis was programmed to use that thing.)

Point is; you can swap any model for any other model. But i used it for the SI.

Note:
This only works on maps you compile. It does not work to replace models on existing maps!
The Script
We need a Vscript that changes the models for us.
Here is the actual script i am using in TUMTaRA (with addition of l4d2 SI):

///////////////////////////////////////// L4D1 Infected ///////////////////////////////////////// function ConvertToSacrificeTank(){ local sacrificeTank = Ent("precache_tank") local targetTank = Ent("dlc3_hulk") NetProps.SetPropInt(targetTank, "m_nModelIndex", NetProps.GetPropInt(sacrificeTank, "m_nModelIndex")) } function ConvertToL4D1Tank(){ local L4D1Tank = Ent("precache_tank_l4d1") local targetTank_l4d1 = Ent("hulk_l4d1") NetProps.SetPropInt(targetTank_l4d1, "m_nModelIndex", NetProps.GetPropInt(L4D1Tank, "m_nModelIndex")) } function ConvertToL4D1hunter(){ local L4D1hunter = Ent("precache_hunter") local targeHunter_l4d1 = Ent("hunter_l4d1") NetProps.SetPropInt(targeHunter_l4d1, "m_nModelIndex", NetProps.GetPropInt(L4D1hunter, "m_nModelIndex")) } function ConvertToL4D1smoker(){ local L4D1smoker = Ent("precache_smoker_l4d1") local targetsmoker_l4d1 = Ent("smoker_l4d1") NetProps.SetPropInt(targetsmoker_l4d1, "m_nModelIndex", NetProps.GetPropInt(L4D1smoker, "m_nModelIndex")) } function ConvertToL4D1boomer(){ local L4D1boomer = Ent("precache_boomer") local targeboomer_l4d1 = Ent("boomer_l4d1") NetProps.SetPropInt(targeboomer_l4d1, "m_nModelIndex", NetProps.GetPropInt(L4D1boomer, "m_nModelIndex")) } ///////////////////////////////////////// L4D2 Infected ///////////////////////////////////////// function ConvertToboomette(){ local boomette = Ent("precache_boomette") local targeboomette = Ent("boomette") NetProps.SetPropInt(targeboomette, "m_nModelIndex", NetProps.GetPropInt(boomette, "m_nModelIndex")) } function ConvertToboomer_default(){ local boomer_default = Ent("precache_boomer_default") local targeboomer_default = Ent("boomer_default") NetProps.SetPropInt(targeboomer_default, "m_nModelIndex", NetProps.GetPropInt(boomer_default, "m_nModelIndex")) } function ConvertToL4D2Tank(){ local L4D2Tank = Ent("precache_tank_L4D2") local targetTank_L4D2 = Ent("hulk_L4D2") NetProps.SetPropInt(targetTank_L4D2, "m_nModelIndex", NetProps.GetPropInt(L4D2Tank, "m_nModelIndex")) } function ConvertToL4D2hunter(){ local L4D2hunter = Ent("precache_hunter") local targeHunter_L4D2 = Ent("hunter_L4D2") NetProps.SetPropInt(targeHunter_L4D2, "m_nModelIndex", NetProps.GetPropInt(L4D2hunter, "m_nModelIndex")) } function ConvertToL4D2smoker(){ local L4D2smoker = Ent("precache_smoker_L4D2") local targetsmoker_L4D2 = Ent("smoker_L4D2") NetProps.SetPropInt(targetsmoker_L4D2, "m_nModelIndex", NetProps.GetPropInt(L4D2smoker, "m_nModelIndex")) } function ConvertToBrideWitch(){ local Bridewitch = Ent("precache_witch_bride") local Targetwitch_bride = Ent("Witch_bride") NetProps.SetPropInt(Targetwitch_bride, "m_nModelIndex", NetProps.GetPropInt(Bridewitch, "m_nModelIndex")) }
Copypaste either all of it, or just the lines you want into your own vscript file.
I'd reccomend you to make your own search path for your maps, just to keep this custom script away from original content.
This guide here shows how to do That.
https://psteamcommunity.yuanyoumao.com/sharedfiles/filedetails/?id=1507939076

Note:
Technically the bride witch doesn't need this. As she got her own population which only spawns the bride variant. I'm keeping it here in case you want to use this to make your own witch models and use several of them. in which case you also need to modify that script further.
How the script works
Let's look at the first function inside that script.
function ConvertToSacrificeTank(){ local sacrificeTank = Ent("precache_tank") local targetTank = Ent("dlc3_hulk") NetProps.SetPropInt(targetTank, "m_nModelIndex", NetProps.GetPropInt(sacrificeTank, "m_nModelIndex")) }
  • ConvertToSacrificeTank = function name called upon from hammer.
  • sacrificeTank = variable name for the wished model (only used in the vscript).
  • precache_tank = name of the prop_dynamic using the model you want.
  • targetTank = tank npc variable name (only used in the vscript).
  • dlc3_hulk = spawned tanks name.
Needless to say, every swapping function for other models need their own function, variable, prop_dynamic, and spawned infected names. That's why the script is so long.

Map Setup
Your map requires the following for this to work:
  • A logic_script using your script.


  • A commentary_zombie_spawner with targetname of your choice.


  • A prop_dynamic with targetname of your choice, using the model you want to swap to.


  • A func_button, trigger or other entity capable of firing the following two outputs:

    Output 1:
    My output named = OnPressed (Or whatever your triggering entity uses) Target entities named = ***commentary_zombie_spawner name here*** Via this input = SpawnZombie With a Paparameter override of = Tank,dlc3_hulk After a delay in seconds of = 0
    Output 2:
    My output named = OnPressed (Or whatever your triggering entity uses) Target entities named = ***logic_script name here*** Via this input = RunScriptCode With a Paparameter override of = ConvertToSacrificeTank() After a delay in seconds of = 0.03 This delay is important.


How this works:
The first output spawns a tank and calls it "dlc3_hulk".
The second output runs the script code "ConvertToSacrificeTank()", which will search the spawned tank called "dlc3_hulk", search the prop_dynamic called "precache_tank" and change the spawned tanks model for whatever model "precache_tank" is using.

Note:
Using a different model, like a spitter for a tank, will end up in a spitter model moving across the map, playing the wrong animations and generally looking wonky. Its funny, you should try it.

That's it. You're all set.
Multiple spawnpoints, to spawn several tanks of the same name and swap all at once is possible.
Using single spawnpoint to spawn any SI and then swap that spawned model. is also possible.
Custom SI/CI for specific spawnpoints
If you want to use a custom SI or CI model for a specific spawnpoint, you must recompile the custom model for another name and then precache that one.

Here's a proof of concept:




One nick was harmed in the making of this screenshot.
Boomer / Boomette
For some reason valve gave the boomette at least one animation less or more.
Which means spawning the boomette and swapping her for a male boomer, breaks the swapped-to boomers animations. Same goes when you spawn a male boomer and swap him for boomette.

You can stop the boomette from spawning by editing the Missionfile and adding "no_female_boomers" "1".
Unfortunately that will be forced on all boomer spawns on the entire campaign.
14 条留言
Unknown 2023 年 11 月 22 日 下午 12:01 
Got it working as I intended. The script had to be slightly modified. Now I have L4D1 specials at the start of the chapter. And they get converted into L4D2 counterparts in the second part of this chapter.
мяFunreal  [作者] 2023 年 11 月 14 日 下午 12:41 
I have no idea if that is possible. All I know is how to force spawn custom models.
Unknown 2023 年 11 月 14 日 上午 10:23 
Does this work only for specific/scripted spawn points? I want only l4d1 specials to spawn in one part of the map, and then only l4d2 specials in the rest. I don't know how I can set this up.
мяFunreal  [作者] 2023 年 7 月 19 日 上午 11:39 
i mentioned the missionfile because the vscript you brought up can easily be done via missionfile.
so making a vscript and running it it more work than just editing the missionfile.
Shadowysn 2023 年 7 月 19 日 上午 10:18 
I'd better stop now. It's obvious I did the damage.
Shadowysn 2023 年 7 月 19 日 上午 10:13 
Ugh, okay, I tend to talk like that when backtalked. Good job, I can see your internet skills are better in provocation and analysis than mine.
The two functions I mentioned are functions for VScript, not mission files. Just to clarify.
I thought you were still referring to script files since you're using them in this guide??
мяFunreal  [作者] 2023 年 7 月 19 日 上午 9:51 
You mentioned a vscript that does the same as the missionfile, but it required more steps.
And now you mentioned yet more things that are not related to this here at all.
Shadowysn 2023 年 7 月 19 日 上午 7:36 
Uh... I was just mentioning a VScript method as a note I hoped would be helpful and I do admit I don't remember any of the exact times the VScript functions come out, I just can only recall a fuzzy time when I first use them.
Also, VScript with the right knowledge can target individual players by iterating and checking for properties like the team they're on, type of infected, their own model, and all other sorts of properties using NetProps and other methods.
So, if I wanted to change the model of one Tank that has lower than 100 hp, I can check for that.
Same goes for checking if they're a Hunter with a shotgun.
(Hey, that's a funny idea, wonder why nobody ever tried SI with guns before? VScript jank can give them guns.)
мяFunreal  [作者] 2023 年 7 月 19 日 上午 7:23 
1. this came out a month after the TLS update.
2. this changes one single model for another one. Yours changes all for the entire map.

Your smugness failed miserably.
Shadowysn 2023 年 7 月 19 日 上午 4:51 
VScript functions that IIRC were added around the time of the TLS update allow directly precaching and properly setting the model, fixing the boomer's and boomette's mismatched animations.
PrecacheModel("models/infected/boomer.mdl");
boomer.SetModel("models/infected/boomer.mdl");
Still hearing about these pre-TLS methods are nostalgic to me as a newbie VScripter before TLS.