The Commander, on 26 December 2013 - 07:31 PM, said:
I haven't even looked at the LUA code for this, but this is the kind of LUA coding I am use to in Garry's Mod
function pSpawn(ply)
local decider = math.random(1,5)
if decider == 1 then ply:SetPos(Vector(-1809.119019,-5081.286621,151.301315)) end
if decider == 2 then ply:SetPos(Vector(-1849.182983,-4930.058594,140.910019)) end
if decider == 3 then ply:SetPos(Vector(-2011.731445,-4952.591797,146.132523)) end
if decider == 4 then ply:SetPos(Vector(-1728.267944,-5109.243652,129.985275)) end
if decider == 5 then ply:SetPos(Vector(-1580.698730,-5029.461426,114.260880)) end
end
hook.Add( "PlayerSpawn", "customspawn", pSpawn )
What this does is that it overrides the default spawn points in a source map being run on Garry's Mod and respawns the player at one of the five positions listed above.
I find this bad style because you codify something that's not interesting enough to be code, namely merely data. As a consequence, the code is also more redundant than necessary. Consider this rewrite:
local spawnPositions = {
{ -1809.119019, -5081.286621, 151.301315 },
{ -1849.182983, -4930.058594, 140.910019 },
{ -2011.731445, -4952.591797, 146.132523 },
{ -1728.267944, -5109.243652, 129.985275 },
{ -1580.698730, -5029.461426, 114.260880 },
}
local function pSpawn(ply)
local decider = math.random(1, #spawnPositions)
ply:SetPos(Vector(spawnPositions[1], spawnPositions[2], spawnPositions[3]))
end
hook.Add("PlayerSpawn", "customspawn", pSpawn)
Besides being a lot nicer to look at, its runtime is also is also independent of the number of spawn positions (for an abstract performance model not taking into account real-wordly stuff such as CPU caches, etc.). It may not matter in this particular case, but for functions run in a tight loop, it could be significant. Incidentally, long if/if-else cascades are also something you often see in CON code.
James, on 26 December 2013 - 02:10 PM, said:
I'm not, CON's main appeal was that I didn't need to know programming to use it. All of the examples and stuff so far in this topic are completely foreign to me. It doesn't matter in anycase, since CON will always be around in some form. I just don't have the time to learn a complicated language these days.
What are the characteristics of a language by which you consider it 'programming' or not? From a bird's eye view, Lua and CON aren't that different: both are based on a sequential model of computation, both are imperative. Sure, there are advanced concepts... but you don't need to know all of Lua to make good use of it. Let's look at a snippet I posted a while ago, prefixed with line numbers. I claim that you almost don't need to have had prior exposure to programming at all to understand it (but assuming you know what a Build map contains).
1 for w=0,gv.numwalls-1 do
2 local wal = wall[w]
3 if (wal.overpicnum == D.W_FORCEFIELD or wal.overpicnum == D.W_FORCEFIELD+1) then
4 if (wal.lotag==34) then
5 if (wal.cstatbits:test(85)) then -- cstat has any of the bits 64+16+4+1 set?
6 wal.cstat = 0
7 else
8 wal.cstat = 85
9 end
10 end
11 end
12 end
Commenting the non-obvious parts:
- Line 1 contains a loop over the indices of all walls in the currently loaded map. Each iteration of the loop, 'w' takes on a value from 0 to the numebr of walls minus one, in sequence.
- In line 2, a reference to a wall object is stored into a variable named 'wal'. The variable has local scope: it can be referred to up to the 'end' at line 12 closing the generic 'for', and it is said to go
out of scope thereafter. Because the variable 'wal' stored a
reference to the w'th wall (and not, say, a copy of it), you can use it to both read from and write to the original object, wall[w].
- Line 5 may be slightly unusual. As the comment says, it checks whether the wall's cstat has any the bits in {64, 16, 4, 1} set. In CON, this would be written as
getwall[w].cstat tmp
ifand tmp 85
{
// ...
}
In Lunatic, you can also access wal.cstat, but some convenience is provided for carrying out bitwise operations on such members: .cstatbits lets you query or operate on .cstat without calling bitwise functions directly (in Lua, there are no bitwise operators). The ':' syntax can be though of a
method invocation on 'wal.cstatbits'. Methods are like functions, but "tied to" a particular object. I'm being vague here... maybe someone else can explain it better.
- Becuase of the semantics of Lua's 'or' and 'and' operators, lines 5 to 9 can be collapsed into
wal.cstat = (wal.cstatbits:test(85)) and 0 or 85
Nice, huh?
James, on 26 December 2013 - 02:10 PM, said:
Well that's good to hear, but from what I understand (unless I've missed something) the new stuff added to make new breakable lights is lua only.
Actually, EVENT_DAMAGEHPLANE also runs in CON, from both C-CON and LunaCON builds, but its interface (how to decode passed RETURN, what values to provide to RETURN on leaving) is undocumented. The question is: why would you want to write a DAMAGEHPLANE event in CON? Two reasons you'd not:
- In Lunatic, you can have a reference to an object that is a "ceiling-or-floor". That is, if you want some code to run for both ceilings and floors, you don't need to duplicate it, once with sector[].ceiling* accesses and the other one with sector[].floor* ones. Less redundancy: good.
- EVENT_DAMAGEHPLANE receives in RETURN a value that encodes which part (ceiling or floor) of what sector was hit. But it also examines RETURN after the event has left. If you chain multiple events, there's no way to obtain the original, passed value of RETURN from a second DAMAGEPLANE event once the first one has modified it (to signal the action to take). In Lunatic, a trick is used: RETURN is also passed in the 'dist' argument. In CON, it can't be queried directly, but only compared for inequality against a number with
ifdistl/
ifdistg.
The ability to chain this event means that you can code each hplane-breaking effect independently. This is shown in test/damagehplane.lua: the code for TROR-bunch glass breaking and the new breakable ceiling picnums live in two separate event definitions. So, if the event is properly written, you can provide a stand-alone mutator merrily working together with other DAMAGEHPLANE events.