Jump to content

LE3 Lua


Benton
 Share

Recommended Posts

Hey Josh,

If I start writing LUA code for a game will it be portable to LE3 Lua? I am talking about writing functions to load scenes, control the player etc...will there be a lot of porting the code?

Windows 7 Professional 64 bit, 16 gigs ram, 3.30GHz Quad Core, GeForce GTX 460 one gig, Leadwerks 2.5, Blender 2.62, Photoshop CS3, UU3D

Link to comment
Share on other sites

I can imagine the commands would be mostly the same, with just some differences for things like the commands to load the fw... Not too much main things.

Win7 64bit, Leadwerks SDK 2.5, Visual Studio 2012, 3DWS, 3ds Max, Photoshop CS5.

 

 

 

Life is too short to remove USB safely.

Link to comment
Share on other sites

That's what I figured but I just wanted confirmation it's not totally different :)

Windows 7 Professional 64 bit, 16 gigs ram, 3.30GHz Quad Core, GeForce GTX 460 one gig, Leadwerks 2.5, Blender 2.62, Photoshop CS3, UU3D

Link to comment
Share on other sites

Here's what a script with a lot of unnecessary variables looks like:

--Expose values here you want to modify in the editor
--Vec3 speed 1,2,3
--bool state true
--Entity target
--int health 100
--float smoothness 10
--Material material
--Sound opensound
--choice style "fast","slow","blinking"
--choiceedit style "fast","slow","blinking"
--string name "Bob"
--path file "test.txt"
--Vec2 rasterpos 2,2
--Vec4 shape 0,0,1,1

--Do initialization stuff here.
function script:Create()
     
end

--This function gets called once per world update.
function script:Update()
     
end

-This function gets called once per physics update.
function script:UpdatePhysics()
      if self.state then
           self.entity:Move(self.speed,false)
      end
end

--This functin gets called any time an entity moves
function script:UpdateMatrix()
     
end

--This function gets called once per world render, if the entity is drawn at all.  It will only be called once at most.  Animation should be performed here.
function script:Draw()
     
end

--This function gets called once per camera render.  It will be called each time an entity is drawn.
function script:DrawEach(camera)
     
end

--This function is called when the entity is freed.
function script:Free()
     
end

function script:Enable()--in,out
      self.state=true
end

function script:Disable()--in,out
      self.state=false
end

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

I don't mind the above at all, but I find it interesting that you're adding "types" to a language that has no types. My understanding is that you're doing this for the editor so it knows maybe what kind of control to display that certain exposed variable. In order to do that do you need types like Sound or Entity? Things like the 'choice style' make sense in what the needs would be for these variables, but why some of the other actual LE types like Sound or Entity? What else are you using that information towards?

 

The reason I bring this up for discussion is because 1 of the reasons people find Lua easy is because you don't have to worry about types. I personally like types, but I've read and heard the lack of specific types for Lua is a benefit.

 

Just curious if you've played around with other syntactical ways of exposing these variables and if this is the lesser of the evils? Is not having them being comments an option? Perhaps having us use a specific table name and putting them in there? Maybe having the first 3 characters of the variable name describe the display control type to the editor? Or having the table, assuming my previous comment of exposed variables being in a table at the top of each file, have subtables that describe the display control type for each variable.

 

I'm curious because using comments like that is sort of misleading to the language itself. Someone just coming to LE but who has Lua experience might not realize that these comments at the top actually get converted to actual Lua variables where as if they were defined in a table at the top it would seem more obvious that these are now usable variables and that no trickery is being done behind the scenes.

 

Just challenging things smile.png

Link to comment
Share on other sites

As far as I understand how this is going to be done, those commented variables at the top are the actual input variables that will be used for that script. If you've ever used Unity you can think of these to when you make a variable public and how it now shows up in the editor and you can assign values to each public variable.

 

If Josh is simply using comments to show the general idea and he doesn't have the details of how it'll be worked out then ignore my comments, but if he's really going to be using the comments at the top like that to define the "public" or exposed variables then I would question that style. I thought I remember him though saying the comment style is the way he was thinking of doing it. I would think something like:

 

variables =
{
  var1 = ""
  var2 = ""
}

Link to comment
Share on other sites

I don't mind the above at all, but I find it interesting that you're adding "types" to a language that has no types. My understanding is that you're doing this for the editor so it knows maybe what kind of control to display that certain exposed variable. In order to do that do you need types like Sound or Entity? Things like the 'choice style' make sense in what the needs would be for these variables, but why some of the other actual LE types like Sound or Entity? What else are you using that information towards?

Yes, this is so the editor knows how to display the visual control. The Sound, Entity, etc. fields prevent the user from dragging a sound onto a field that expects a material, for example.

 

The other alternative would be something like this:

--Expose values here you want to modify in the editor:
script.state=true--bool
script.mode=2--int
script.name="Bob"--string

 

But you get into mode complex parsing issues when you start using classes and constructors:

--Expose values here you want to modify in the editor:
script.movement=Vec3(1,2,3)--Vec3
script.rasterpos=Vec2(0)--Vec2

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

Yet another way:

script.movespeed = Vec3(1,2,3) --public
script.turnspeed = Vec3(0) --public
script.moveglobal = false --public
script.turnglobal = true --public
script.state = true --public

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

How would you define things like Sound, Material, etc in that method? script.boomSound = Sound?

 

But your last 2 posts do raise the question of private script level variables vs public script level variables. Maybe?

 

script.public.var1 = Vec3(0)
script.private.var2 = false

 

Merging your 2 posts above would look something like the below.

 

script.state = false --public bool

 

Using comments I assume you might get into possibly forcing formatting of those comments to be exact. Like what if I put a space between -- and my type or access level. Guessing it could cause parsing issues and possibly fail. Would hate to have the possibility of something like a comment causing failures.

Link to comment
Share on other sites

Using comments I assume you might get into possibly forcing formatting of those comments to be exact. Like what if I put a space between -- and my type or access level. Guessing it could cause parsing issues and possibly fail. Would hate to have the possibility of something like a comment causing failures.

My thoughts Exactly. Perhaps replacing it with another character. The character can then also define its scope. For example:

private: script.state =false$ bool

public : script.state =falsebool

 

Still, the idea of exposing the Lua variables to a Type is pretty cool.

Link to comment
Share on other sites

Don't worry about the parsing, I am pretty thorough with that stuff.

 

Connectivity is a major issue with multiple scripts. I decided early on that the connectable objects in the logic editor should just be entities, because a "script attachment" class was too abstract and confusing, i.e. connecting scripts attached to entities instead of entities. However, if an entity has an output to another entity that gets called when an "Enable" function gets called, if it has five scripts with that function, it's very hard to prevent that output from being activated five times.

 

I'm experimenting right now with a one-script per entity approach that looks like this:

entity.state=true
entity.message = "Hello!"
entity.movespeed = Vec3(1,2,3)
entity.turnspeed = Vec3(0,0.1,0)
entity.moveglobal = false
entity.turnglobal = true

function entity:Update()
self:SetColor(0,1,0,1)
self:Turn(0,0.1,0,true)
end

 

What's nice about this is you can get and set values from the C++ side to Lua, like the old key/value pairs, but more advanced:

Model* box = Model::Box();
box->SetInt("health",100)
box->SetObject("friend",Model::Sphere());
Object* o = box->GetObject("friend")

And all those values are available on the Lua side:

box.health
box.friend

 

It also makes Lua scripts nice and easy to work with:

--Bullet collides with anything, doesn't matter what
function entity;Collision(entity,position,normal,speed)
if entity:Hurt~=nil then
	entity:Hurt(5)
end
end

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

Don't worry about the parsing, I am pretty thorough with that stuff.

 

Fair enough. I think my major concern is using a comment system that actually has functionality. Giving 2 completely different meanings to 1 language feature is something I would think would be nice to avoid if possible.With such a flexible language like Lua I would think it could be avoided.

 

I'm experimenting right now with a one-script per entity approach that looks like this:

 

It seems that's not all that different than what you have today. So the results you get from the community won't be all that different than what you have today in Lua ie. pretty sparse. Doing it with one script basically seems like all your really doing in LE3D is removing the targeting system and/or global access to objects as the interaction between scripts and instead having the input/output system. If that's the only "step up" you're after in the Lua system in LE3D then it seems slightly different than originally planned. Not that that's a massive issue, but it might play into my point below.

 

If we can only have 1 script per entity, bolting on additional functionality to an entity would then require the merging of different script files. You once talked about Lua being better for sharing code, but if one has to merge scripts that sort of goes out the window as it's now not that much different than sharing C++ code.

 

I don't think there is any question it's easier to only have 1 script per entity from the aspect of C++ and how you have to handle things, but it's limiting to the majority of the demographic that would be using Lua in the first place. People looking to piece some scripts that you or the community create to give functionality. With 1 script per entity those scripts just became very very specific. No real difference than what we have today, and honestly the community created Lua scripts today are basically zero to none in terms of actual gameplay functionality. They are all pretty much just visual things. That's nice, but it doesn't allow someone to get real gameplay into their game by piecing together scripts. The more specific scripts have to be the less usability for the majority of people they are. Which leads to nobody coding them in the first place for others to use because they know nobody will because they are so specific.

 

I would ask to give us programmers who want to see the Lua community grow, a standard system that has the ability to attach multiple scripts to entities. Once given that, sit back and watch the community take over and grow it into something amazing. Let us sell these scripts if we want to, and with a few key players in the community taking part in the beginning, this thing could be huge and open the door to way more sales from the less strong programming crowd who believe it or not, can make games, but more importantly, have money just like the rest of us.

Link to comment
Share on other sites

It seems that's not all that different than what you have today. So the results you get from the community won't be all that different than what you have today in Lua ie. pretty sparse. Doing it with one script basically seems like all your really doing in LE3D is removing the targeting system and/or global access to objects as the interaction between scripts and instead having the input/output system. If that's the only "step up" you're after in the Lua system in LE3D then it seems slightly different than originally planned. Not that that's a massive issue, but it might play into my point below.

That's correct. With this approach, the differences are:

-Script debugger

-Any script can be attached to any entity, instead of having one script per model file.

-Entity get/set Lua values directly, instead of string-based keys. This includes drag and drop fields in entity properties for materials, textures, other entities, etc.

-Visual logic editor connects entity script functions, instead of entity target/message system.

-Much simpler scripts, with no attempt to implement hierarchical OO or control properties through string-based keys.

-Script values and functions are attached directly to the entity itself.

 

If we can only have 1 script per entity, bolting on additional functionality to an entity would then require the merging of different script files. You once talked about Lua being better for sharing code, but if one has to merge scripts that sort of goes out the window as it's now not that much different than sharing C++ code.

That's the big question. Multiple scripts need multiple spaces for variables. The variables have to be attached to some kind of Entity-Script attachment object. I have implemented this without a problem, and it works well. The problems arise when you try to access that entity's values from another script, or from C++ code. For example, if you want a bullet to affect a character it hits, you would have to do something like this:

 

function script:Collision(entity,normal,speed)
local script
local n

for n=0 to entity:CountScripts()-1
	script=entity:GetScript(n)
	script:AddDamage(self.damage)
end
end

 

Okay, we can do some tricks to just call the function for the one entity, and it gets called for all scripts attached to that entity, so then it would look like this:

 

function script:Collision(entity,normal,speed)
entity:CallFunction("AddDamage",self.damage)
end

 

What if the function needs to return a value? There is no version of this we can do with a simplified per-entity function like we used above:

 

function script:Collision(entity,normal,speed)
local script
local n

for n=0 to entity:CountScripts()-1
	script=entity:GetScript(n)
	if script:GetHealth()>0 then
		script:AddDamage(self.damage)
	end
end
end

 

There's very little you can do within a script itself. Gameplay comes from the interactions between scripts. Without that, you'll add one script to make an object spin around, another to make it blink colors, another to make it emit a noise, and that's pretty much all you can do.

 

With a single script per entity, this becomes very easy:

function entity:Collision(entity,normal,speed)
if entity:GetHealth()>0 then
	entity:AddDamage(self.damage)
end
end

I originally started off making the logic editor connect script-entity attachment objects, not entities, but I could quickly see that it was way too abstract, so I just made it connect entities, and merged the list of available functions. However, this causes problems because if an input is called, and multiple scripts have the function, if that function has an output to another entity, it will be called for each script that has the function. I could take stricter control of the flow on the C++ side, but I thought the idea was that when a script function was called, from anywhere, it would trigger any outputs it's connected to.

 

I don't doubt I can implement a system that has a way to control all of this, but it's a question of keeping things simple. I made the LE2 script system complex to try to accommodate the feature requests I was getting (like hierarchical OO script objects).

 

One question is just how frequently will the end user be combining multiple scripts to create emergent behavior? It's a nice idea, but beyond really simple stuff like a blinking spinning light, what can you do with multiple scripts that couldn't be done with one flexible script with some adjustable properties? I bet beginners love it, because it gives them the appearance of controlling behavior without modifying any code, but are we crippling the usability of the system to make easy stuff easier?

 

I don't think there is any question it's easier to only have 1 script per entity from the aspect of C++ and how you have to handle things, but it's limiting to the majority of the demographic that would be using Lua in the first place. People looking to piece some scripts that you or the community create to give functionality.

It seems like we have two kinds of functions. We want engine hooks to have multiple definitions, be called in order, and have unique variable spaces. On the other hand, we want script functions to be attached directly to the Entity object, share variables, and only have one definition. Maybe the former needs some kind of AddScriptHook() mechanism, while conventional script functions would simply be overridden if they exist in two scripts attached to the same entity.

 

It's also worth considering that the Unity script kiddies are the least likely demographic we will attract. They've got brand loyalty like crazy, they tend to be on the low end of the technical proficiency spectrum, and are mostly using free stuff. That's unlikely to be a potential customer.

 

I would ask to give us programmers who want to see the Lua community grow, a standard system that has the ability to attach multiple scripts to entities. Once given that, sit back and watch the community take over and grow it into something amazing. Let us sell these scripts if we want to, and with a few key players in the community taking part in the beginning, this thing could be huge and open the door to way more sales from the less strong programming crowd who believe it or not, can make games, but more importantly, have money just like the rest of us.

That's the goal, but this needs some more thought on the design.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

What if the function needs to return a value? There is no version of this we can do with a simplified per-entity function like we used above:

 

I would say using the script name as the key to getting a script attached to the current entity would be the way to get a specific scripts function/variables. Only allowing 1 of a specific script per entity is probably valid enough. That would turn it into:

 

-- collision from a bullet point of view
function script:Collision(entity,normal,speed)
    if entity:HasScript("CharacterStats") then
		 entity:GetScript("CharacterStats").AddDamage(self.damage)
    end if
end

 

This however plays into what you said above where you dropped the idea of a Script type. The above isn't complicated. Perhaps the C++ version of it is and that's why you dropped that idea? The above is pretty specific script but I'm guessing most collision scripts will be pretty specific to the game and require coding (unless you went down a big rabbit hole).

 

 

All I know is I would want something like:

 

bullet model

  • attach an empty default script to handle collision (most likely pretty specific to my game)
  • attach spinning script (I want a realistic bullet so it's spin as it's moving)
  • attach emitter script (I want some smoke trails on the bullet)
  • attach sound script (I want a buzzing noise to play while it's moving so if it flies by your head you hear it)
  • attach a move script (this will get the bullet moving in a certain direction. the weapon that shot it will set the direction & speed.)
  • ???
  • Profit :)

 

Ideally the above would be able to be made a prefab so when I fire my gun I can just create an instance of the above with 1 function call, set it's direction and speed, and let it do it's thing.

 

So in the above example I have 4 very generic scripts that I was able to just attach to 1 entity, set some editor settings, and get some bullet gameplay very easily.

Link to comment
Share on other sites

I would say using the script name as the key to getting a script attached to the current entity would be the way to get a specific scripts function/variables. Only allowing 1 of a specific script per entity is probably valid enough.

-What if you have the same script attached twice?

-My entity:AddDamage() approach allows you to add new scripts with the AddDamage() function, to act in ways that were not originally accounted for. For example, a can of paint might explode and fling paint everywhere when its health reaches zero.

 

Looking at Unity's system, I think they have sacrificed their script system for the purpose of making people think they can simply click on options to make a game. I mean, the multiple script attachments has a benefit to the total non-programmer. Let's say they get 20 "utils" more functionality than if they chose from a library of single pre-made scripts. But the cost when they crack open those scripts is -60 utils. Their scripts are a mess, and are fragmented between three script languages.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

-What if you have the same script attached twice?

 

That's what I was trying to convey with the "Only allowing 1 of a specific script per entity is probably valid enough" statement. Meaning is that really going to be a limitation to not allow 2 of the same exact scripts? I'm trying to think of why you would do this. Then again that could play into a multimap where you can loop through multiple of the same script name if required.

 

 

My entity:AddDamage() approach allows you to add new scripts with the AddDamage() function, to act in ways that were not originally accounted for. For example, a can of paint might explode and fling paint everywhere when its health reaches zero.

 

I agree, but then again maybe we were looking at the collision incorrectly. Instead of looking at it from the bullets perspective maybe we should be looking at it from other entities perspective. Like in your example we would have a paint can model that we attach a default script to and inside it's OnCollision we can check to see if the entity that hit us is a "Bullet" and then we can do your paint can scenario.

 

I mean, the multiple script attachments has a benefit to the total non-programmer. Let's say they get 20 "utils" more functionality than if they chose from a library of single pre-made scripts. But the cost when they crack open those scripts is -60 utils. Their scripts are a mess, and are fragmented between three script languages.

 

The language issue is a problem Unity wanted to create to support more languages. I don't agree with their decision on that, but then again you won't have that issue because it's just Lua. That's much cleaner. I think the main thing to remember is there isn't a whole lot preventing the community from making single pre-made gameplay oriented scripts today and yet it's just not happening. I guess this then comes down to why you think it's not happening. I believe it's not happening today because as a script programmer I don't see much point in making such specific scripts that will hardly ever get used because because they are so specific. I say this simply by looking at how many more "generic" scripts Unity has that were created by the community because of the generic fashion system they have.

 

I keep going back to things like rotation, emitters, & sound. How can I get all 3 pieces of functionality attached to an entity with 1 script? Are we going to have a RotationEmitterSound script? Then an EmitterSound script? Then a RotationSound script? Some things will need sound only, or emitter and sound, and/or any combination of the above and many other pieces of functionality that people would want to mix and match to get their desired functionality. This isn't even just for the script kiddies. It would be way easier for anyone to be able to piece things together. This just seems like the natural evolution at some point.

Link to comment
Share on other sites

I keep going back to things like rotation, emitters, & sound. How can I get all 3 pieces of functionality attached to an entity with 1 script? Are we going to have a RotationEmitterSound script? Then an EmitterSound script? Then a RotationSound script? Some things will need sound only, or emitter and sound, and/or any combination of the above and many other pieces of functionality that people would want to mix and match to get their desired functionality. This isn't even just for the script kiddies. It would be way easier for anyone to be able to piece things together. This just seems like the natural evolution at some point.

That's a good point for consideration.

 

I can't attach values directly to entities in Lua and be able to access them from C++ (which I absolutely need for the script debugger) so there has to be a script table associated with the entity. Fortunately, I can make it a little cleaner than LE2. If you perform a raycast or something, the resulting entity you get will have a script or scripts table attached to it, only accessible in Lua. This is a way to directly access an entity's script object:

pick = CameraPick(camera,x,y)
if pick then
   pick.entity.script:DoSomething()
end

 

Here's a comparison of two approaches for script attachments. The top one uses a single script. The bottom one uses multiple scripts. Both are manageable:

function script:Collision(entity,normal,speed)
   if entity.script~=nil then
       entity.script:AddDamage(5)
   end
end

function script:Collision(entity,normal,speed)
   if entity.scripts~=nil then
       for index,script in ipairs(entity.scripts) do
           script:AddDamage(5)
       end
   end
end

 

The big reason we aren't getting general-purpose scripts written now includes:

-No script debugging.

-One script file per model file design discourages reuse.

-Only models can have scripts.

-LE2 scripts include a lot of class stuff that I should have skipped.

 

I'll do some experiments next with multiple scripts, and have outputs linked between entity scripts, instead of entities.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

Here's an example of a single script that looks at an entity. The "target" value is an entity that you drag onto script properties in the editor:

script.target=nil--Entity
script.lookspeed=0.1--float

function script:Update()
self.entity:Point(self.target,self.lookspeed)
end

 

And then this script can be used to switch the target entity. The two entities are assigned by drag and drop in the editor:

script.entitytomodify=nil--Entity
script.replacement=nil--Entity

function script:SwitchTarget()
self.entitytomodify.script.target=replacement
end

What's nice here is the SwitchTarget script can be used with anything, instead of only working with one type of companion script you decide on ahead of time.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

I have renamed the "SwitchTarget" script to "ToggleTarget". I added a KeyDown script function. This entity is now linked to the space key. When the space key is pressed, the ToggleTarget() function is called.

script.target=nil--Entity
script.newtarget=nil--Entity

function script:ToggleTarget()
local temp = self.target.script.target
self.target.script.target=self.newtarget
self.newtarget=temp
end

function script:KeyDown(keycode)
if keycode==Key.Space then
	self:ToggleTarget()
end
end

I have a chain of about five entities linked together now so that when I hit a key, they react. The flexibility of Lua works really well here. I'm not even sure a flowgraph mode is needed if you can assign entities in the editor. I'll keep playing around with this.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

I must say, being able to add more then one script is a MUST.

 

Lets say you have a bird script. You want some birds to be mute, and some birds to be making noise. You have to create two scripts for one bird model. You may as well just have two models and two scripts like LE2 because on a bigger scale it can get even worse. Lets say you make a class for playing a sound. You put this class into many many scripts, say 50. Later on, you discover that your sound class is interfering somewhere and you got to change it. Now you are screwed, you got 50 scripts to change.

 

If you can only have one script per model you better make some other way of adding blocks of code to objects, because if you don't then its no better then LE2's lua.

Windows 7 Professional 64 bit, 16 gigs ram, 3.30GHz Quad Core, GeForce GTX 460 one gig, Leadwerks 2.5, Blender 2.62, Photoshop CS3, UU3D

Link to comment
Share on other sites

I must say, being able to add more then one script is a MUST.

 

Lets say you have a bird script. You want some birds to be mute, and some birds to be making noise. You have to create two scripts for one bird model. You may as well just have two models and two scripts like LE2 because on a bigger scale it can get even worse. Lets say you make a class for playing a sound. You put this class into many many scripts, say 50. Later on, you discover that your sound class is interfering somewhere and you got to change it. Now you are screwed, you got 50 scripts to change.

Thanks for your input.

 

With this script, you can specify the function to call in the editor. It reminds me of the input/output system in HL2:

script.target=nil--Entity
script.key=Key.Space--keycode
script.functionname="Activate"--choiceedit "Enable","Disable","Activate","Open","Close","ToggleEnabled","ToggleActive"

function script:KeyDown(keycode)
if keycode==self.key then
	if self.target then
		if self.target.script[self.functionname] then
			self.target.script[self.functionname](self.target.script)
		end
	end
end
end

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

Had to read this a couple times. I think I get it now. You create if statements in the script and can set it to call a function visually in the editor or from code. That means it is object oriented? I must be missing something...it's almost midnight so maybe that's it.

Windows 7 Professional 64 bit, 16 gigs ram, 3.30GHz Quad Core, GeForce GTX 460 one gig, Leadwerks 2.5, Blender 2.62, Photoshop CS3, UU3D

Link to comment
Share on other sites

It reminds me of the input/output system in HL2:

 

That would be a pretty good system to follow too. I don't think it kills your idea of a flowgraph though. Either linking input/output with text like Hammer and HL or via a visual flowgraph, the idea of input/output is the same, it's just how you want to represent it.

 

So if you go this route you COULD only allow 1 script per entity. Note entity NOT model. This would mean we would be required to be able to add phantom entities that have no visual representation and are there solely for functionality of scripts so that we can link inputs/outputs. I think that could get messy for the level so I still like the idea of multiple scripts, but I would love the Hammer/HL style of input/output linking.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...