All Aboard the ASCII Train

JavaScript (ES6), 149 144 bytes

s=>`    o O Oa   ___  
   o     a  | $& | 
  TS__[O]a  |___| 
 {======|a_|"""""|
./o--000'a"\`-0-0-'`.replace(/a(.*)/g,(_,c)=>s.replace(/./g,c))

I don't think the engine itself can be compressed, but perhaps it's possible.

Test snippet

let f =

s=>`    o O Oa   ___  
   o     a  | $& | 
  TS__[O]a  |___| 
 {======|a_|"""""|
./o--000'a"\`-0-0-'`.replace(/a(.*)/g,(_,c)=>s.replace(/./g,c))

O.innerHTML = f("CODE GOLF")
<input value="CODE GOLF" oninput="O.innerHTML=f(this.value.replace(/\n/g,'&lt;br&gt;'))"><br>
<pre id=O></pre>


PHP, 218 211 204 187 183 bytes

    o O O<?for(;$y<5;print"\n".["   o     ","  TS__[O]"," {======|","./o--000'"][+$y++])for($p=0;$c=a&$argn[$p++];)echo["   ___  ","  | $c | ","  |___| ",'_|"""""|',"\"`-0-0-'"][+$y];

Takes input from STDIN; run with -nR.

Compressing the engine or wagon would require more code to decompress than it saves on storage.
I see no more potential here.


Befunge, 276 270 bytes

p1p~:7>7+#:`#~_$:v
>#p0p10:p00:+1g00_v#:
v"!!```!!!"v>0p01g\-0g1+53p  
v"!}!#!}!!"v0 p115<
v"!}```}!!"v^:-1<
v"}#####}`">00g:|
>"(.1.1.a#"^+<v1<
v"P!P!p!!! "v5>g00p
v"!!!!!p!!!"v6
v"^P\``TU!!"vp
v"}>>>>>>|!"v+
>"(111..p0/"v6
v-1:g110">>"<g
>:11p!#v_p011^
#-:#1_@>$$$$>,#

Try it online!

Explanation

The car and engine are encoded as two sets of five strings on lines 3 to 12. The character values are off by 1 so as to avoid having to deal with the double quotes which can't be used in a Befunge string.

The code works by building up the full set of characters needed to render the train on the stack. For each line of output, an appropriate car string is first added to the stack, repeated as many times as necessary for the cargo, and then one copy of the appropriate engine string.

After each line has been constructed, a pair of the down arrows to left of the strings is replaced with a right arrow, so the next iteration of the loop follows a different path through the code, using a different pair of strings for the car and engine.

Once all the data has been built up on the stack, there's a final rendering loop which writes out the characters, subtracting 1 each time to account for the initial encoding.

As a bonus, the source is designed in the shape of a gun turret, in case the train comes under attack. Golfers destroyed my gun turret.