hedgewars/uScript.pas
branchsdl2transition
changeset 11362 ed5a6478e710
parent 11317 62287d4044e7
child 11468 2f6f8baa2a97
--- a/hedgewars/uScript.pas	Tue Nov 10 18:16:35 2015 +0100
+++ b/hedgewars/uScript.pas	Tue Nov 10 20:43:13 2015 +0100
@@ -1,6 +1,6 @@
 (*
  * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2013 Andrey Korotaev <unC0Rr@gmail.com>
+ * Copyright (c) 2004-2015 Andrey Korotaev <unC0Rr@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -13,7 +13,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *)
 
 {$INCLUDE "options.inc"}
@@ -35,9 +35,11 @@
 procedure ScriptClearStack;
 
 procedure ScriptLoad(name : shortstring);
+procedure ScriptOnPreviewInit;
 procedure ScriptOnGameInit;
 procedure ScriptOnScreenResize;
 procedure ScriptSetInteger(name : shortstring; value : LongInt);
+procedure ScriptSetString(name : shortstring; value : shortstring);
 
 procedure ScriptCall(fname : shortstring);
 function ScriptCall(fname : shortstring; par1: LongInt) : LongInt;
@@ -46,6 +48,7 @@
 function ScriptCall(fname : shortstring; par1, par2, par3, par4 : LongInt) : LongInt;
 function ScriptExists(fname : shortstring) : boolean;
 
+procedure LuaParseString(s: shortString);
 
 //function ParseCommandOverride(key, value : shortstring) : shortstring;  This did not work out well
 
@@ -85,7 +88,10 @@
     uVisualGearsList,
     uGearsHandlersMess,
     uPhysFSLayer,
-    typinfo
+    SDLh
+{$IFNDEF PAS2C}
+    , typinfo
+{$ENDIF}
     ;
 
 var luaState : Plua_State;
@@ -95,22 +101,241 @@
     ScriptAmmoReinforcement : shortstring;
     ScriptLoaded : boolean;
     mapDims : boolean;
+    PointsBuffer: shortstring;
+    prevCursorPoint: TPoint;  // why is tpoint still in sdlh...
 
 procedure ScriptPrepareAmmoStore; forward;
 procedure ScriptApplyAmmoStore; forward;
 procedure ScriptSetAmmo(ammo : TAmmoType; count, probability, delay, reinforcement: Byte); forward;
 procedure ScriptSetAmmoDelay(ammo : TAmmoType; delay: Byte); forward;
 
+var LuaDebugInfo: lua_Debug;
+
+procedure SetGlobals; forward;
+procedure LuaParseString(s: shortString);
+begin
+    SetGlobals;
+    AddFileLog('[Lua] input string: ' + s);
+    AddChatString(#3 + '[Lua] > ' + s);
+    if luaL_dostring(luaState, Str2PChar(s)) <> 0 then
+        begin
+        AddFileLog('[Lua] input string parsing error!');
+        AddChatString(#5 + '[Lua] Error while parsing!');
+        end;
+end;
+
+function LuaUpdateDebugInfo(): Boolean;
+begin
+    FillChar(LuaDebugInfo, sizeof(LuaDebugInfo), 0);
+
+    if lua_getstack(luaState, 1, @LuaDebugInfo) = 0 then
+        exit(false); // stack not deep enough
+
+    // get source name and line count
+    lua_getinfo(luaState, PChar('Sl'), @LuaDebugInfo);
+    exit(true);
+end;
+
 procedure LuaError(s: shortstring);
+var src: shortstring;
+const
+    maxsrclen = 20;
 begin
+    if LuaUpdateDebugInfo() then
+        begin
+        src:= StrPas(LuaDebugInfo.source);
+        s:= 'LUA ERROR [ ... '
+            + copy(src, Length(src) - maxsrclen, maxsrclen - 3) + ':'
+            + inttostr(LuaDebugInfo.currentLine) + ']: ' + s;
+        end
+    else
+        s:= 'LUA ERROR: ' + s;
     WriteLnToConsole(s);
     AddChatString(#5 + s);
+    if cTestLua then
+        halt(HaltTestLuaError);
+end;
+
+procedure LuaCallError(error, call, paramsyntax: shortstring);
+begin
+    LuaError(call + ': ' + error);
+    LuaError('-- SYNTAX: ' + call + ' ( ' + paramsyntax + ' )');
+end;
+
+procedure LuaParameterCountError(expected, call, paramsyntax: shortstring; wrongcount: LongInt); inline;
+begin
+    // TODO: i18n?
+    LuaCallError('Wrong number of parameters! (is: ' + inttostr(wrongcount) + ', should be: '+ expected + ')', call, paramsyntax);
+end;
+
+// compare with allowed count
+function CheckLuaParamCount(L : Plua_State; count: LongInt; call, paramsyntax: shortstring): boolean; inline;
+var c: LongInt;
+begin
+    c:= lua_gettop(L);
+    if c <> count then
+        begin
+        LuaParameterCountError('exactly ' + inttostr(count), call, paramsyntax, c);
+        exit(false);
+        end;
+
+    CheckLuaParamCount:= true;
+end;
+
+// check if is either count1 or count2
+function CheckAndFetchParamCount(L : Plua_State; count1, count2: LongInt; call, paramsyntax: shortstring; out actual: LongInt): boolean; inline;
+begin
+    actual:= lua_gettop(L);
+    if (actual <> count1) and (actual <> count2) then
+        begin
+        LuaParameterCountError('either ' + inttostr(count1) + ' or ' + inttostr(count2), call, paramsyntax, actual);
+        exit(false);
+        end;
+
+    CheckAndFetchParamCount:= true;
+end;
+
+// check if is in range of count1 and count2
+function CheckAndFetchParamCountRange(L : Plua_State; count1, count2: LongInt; call, paramsyntax: shortstring; out actual: LongInt): boolean; inline;
+begin
+    actual:= lua_gettop(L);
+    if (actual < count1) or (actual > count2) then
+        begin
+        LuaParameterCountError('at least ' + inttostr(count1) + ', but at most ' + inttostr(count2), call, paramsyntax, actual);
+        exit(false);
+        end;
+
+    CheckAndFetchParamCountRange:= true;
+end;
+
+// check if is same or higher as minCount
+function CheckAndFetchLuaParamMinCount(L : Plua_State; minCount: LongInt; call, paramsyntax: shortstring; out actual: LongInt): boolean; inline;
+begin
+    actual:= lua_gettop(L);
+    if (actual < minCount) then
+        begin
+        LuaParameterCountError(inttostr(minCount) + ' or more', call, paramsyntax, actual);
+        exit(false);
+        end;
+
+    CheckAndFetchLuaParamMinCount:= true;
+end;
+
+function LuaToGearTypeOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline;
+begin
+    if lua_isnoneornil(L, i) then i:= -1
+    else i:= lua_tointeger(L, i);
+    if (i < ord(Low(TGearType))) or (i > ord(High(TGearType))) then
+        begin
+        LuaCallError('Invalid gearType!', call, paramsyntax);
+        LuaToGearTypeOrd:= -1;
+        end
+    else
+        LuaToGearTypeOrd:= i;
 end;
 
-procedure LuaParameterCountError(call, paramsyntax: shortstring; wrongcount: LongInt);
+function LuaToVisualGearTypeOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline;
+begin
+    if lua_isnoneornil(L, i) then i:= -1
+    else i:= lua_tointeger(L, i);
+    if (i < ord(Low(TVisualGearType))) or (i > ord(High(TVisualGearType))) then
+        begin
+        LuaCallError('Invalid visualGearType!', call, paramsyntax);
+        LuaToVisualGearTypeOrd:= -1;
+        end
+    else
+        LuaToVisualGearTypeOrd:= i;
+end;
+
+function LuaToAmmoTypeOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline;
+begin
+    if lua_isnoneornil(L, i) then i:= -1
+    else i:= lua_tointeger(L, i);
+    if (i < ord(Low(TAmmoType))) or (i > ord(High(TAmmoType))) then
+        begin
+        LuaCallError('Invalid ammoType!', call, paramsyntax);
+        LuaToAmmoTypeOrd:= -1;
+        end
+    else
+        LuaToAmmoTypeOrd:= i;
+end;
+
+function LuaToStatInfoTypeOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline;
+begin
+    if lua_isnoneornil(L, i) then i:= -1
+    else i:= lua_tointeger(L, i);
+    if (i < ord(Low(TStatInfoType))) or (i > ord(High(TStatInfoType))) then
+        begin
+        LuaCallError('Invalid statInfoType!', call, paramsyntax);
+        LuaToStatInfoTypeOrd:= -1;
+        end
+    else
+        LuaToStatInfoTypeOrd:= i;
+end;
+
+function LuaToSoundOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline;
 begin
-    // TODO: i18n?
-    LuaError('Lua: Wrong number of parameters (' + inttostr(wrongcount) + ') passed to ' + call + '!     syntax: ' + call + ' ( ' + paramsyntax + ' )');
+    if lua_isnoneornil(L, i) then i:= -1
+    else i:= lua_tointeger(L, i);
+    if (i < ord(Low(TSound))) or (i > ord(High(TSound))) then
+        begin
+        LuaCallError('Invalid soundId!', call, paramsyntax);
+        LuaToSoundOrd:= -1;
+        end
+    else
+        LuaToSoundOrd:= i;
+end;
+
+function LuaToHogEffectOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline;
+begin
+    if lua_isnoneornil(L, i) then i:= -1
+    else i:= lua_tointeger(L, i);
+    if (i < ord(Low(THogEffect))) or (i > ord(High(THogEffect))) then
+        begin
+        LuaCallError('Invalid gear type!', call, paramsyntax);
+        LuaToHogEffectOrd:= -1;
+        end
+    else
+        LuaToHogEffectOrd:= i;
+end;
+
+function LuaToCapGroupOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline;
+begin
+    if lua_isnoneornil(L, i) then i:= -1
+    else i:= lua_tointeger(L, i);
+    if (i < ord(Low(TCapGroup))) or (i > ord(High(TCapGroup))) then
+        begin
+        LuaCallError('Invalid capgroup type!', call, paramsyntax);
+        LuaToCapGroupOrd:= -1;
+        end
+    else
+        LuaToCapGroupOrd:= i;
+end;
+
+function LuaToSpriteOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline;
+begin
+    if lua_isnoneornil(L, i) then i:= -1
+    else i:= lua_tointeger(L, i);
+    if (i < ord(Low(TSprite))) or (i > ord(High(TSprite))) then
+        begin
+        LuaCallError('Invalid sprite id!', call, paramsyntax);
+        LuaToSpriteOrd:= -1;
+        end
+    else
+        LuaToSpriteOrd:= i;
+end;
+
+function LuaToMapGenOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline;
+begin
+    if lua_isnoneornil(L, i) then i:= -1
+    else i:= lua_tointeger(L, i);
+    if (i < ord(Low(TMapGen))) or (i > ord(High(TMapGen))) then
+        begin
+        LuaCallError('Invalid mapgen id!', call, paramsyntax);
+        LuaToMapGenOrd:= -1;
+        end
+    else
+        LuaToMapGenOrd:= i;
 end;
 
 // wrapped calls //
@@ -118,82 +343,65 @@
 // functions called from Lua:
 // function(L : Plua_State) : LongInt; Cdecl;
 // where L contains the state, returns the number of return values on the stack
-// call lua_gettop(L) to receive number of parameters passed
+// call CheckLuaParamCount or CheckAndFetchParamCount
+// to validate/get the number of passed arguments (see their call definitions)
+//
+// use as return value the number of variables pushed back to the lua script
 
 function lc_band(L: PLua_State): LongInt; Cdecl;
 begin
-    if lua_gettop(L) <> 2 then
-        begin
-        LuaParameterCountError('band', 'value1, value2', lua_gettop(L));
+    if CheckLuaParamCount(L, 2, 'band', 'value1, value2') then
+        lua_pushinteger(L, lua_tointeger(L, 2) and lua_tointeger(L, 1))
+    else
         lua_pushnil(L);
-        end
-    else
-        lua_pushinteger(L, lua_tointeger(L, 2) and lua_tointeger(L, 1));
     lc_band := 1;
 end;
 
 function lc_bor(L: PLua_State): LongInt; Cdecl;
 begin
-    if lua_gettop(L) <> 2 then
-        begin
-        LuaParameterCountError('bor', 'value1, value2', lua_gettop(L));
+    if CheckLuaParamCount(L, 2, 'bor', 'value1, value2') then
+        lua_pushinteger(L, lua_tointeger(L, 2) or lua_tointeger(L, 1))
+    else
         lua_pushnil(L);
-        end
-    else
-        lua_pushinteger(L, lua_tointeger(L, 2) or lua_tointeger(L, 1));
     lc_bor := 1;
 end;
 
 function lc_bnot(L: PLua_State): LongInt; Cdecl;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('bnot', 'value', lua_gettop(L));
+    if CheckLuaParamCount(L, 1, 'bnot', 'value') then
+        lua_pushinteger(L, (not lua_tointeger(L, 1)))
+    else
         lua_pushnil(L);
-        end
-    else
-        lua_pushinteger(L, not lua_tointeger(L, 1));
     lc_bnot := 1;
 end;
 
 function lc_div(L: PLua_State): LongInt; Cdecl;
 begin
-    if lua_gettop(L) <> 2 then
-        begin
-        LuaParameterCountError('div', 'dividend, divisor', lua_gettop(L));
+    if CheckLuaParamCount(L, 2, 'div', 'dividend, divisor') then
+        lua_pushinteger(L, lua_tointeger(L, 1) div lua_tointeger(L, 2))
+    else
         lua_pushnil(L);
-        end
-    else
-        lua_pushinteger(L, lua_tointeger(L, 1) div lua_tointeger(L, 2));
     lc_div := 1;
 end;
 
 function lc_getinputmask(L : Plua_State) : LongInt; Cdecl;
 begin
-    if lua_gettop(L) <> 0 then
-        LuaParameterCountError('GetInputMask', '', lua_gettop(L))
-    else
+    if CheckLuaParamCount(L, 0, 'GetInputMask', '') then
         lua_pushinteger(L, InputMask);
     lc_getinputmask:= 1
 end;
 
 function lc_setinputmask(L : Plua_State) : LongInt; Cdecl;
 begin
-    if lua_gettop(L) <> 1 then
-        LuaParameterCountError('SetInputMask', 'mask', lua_gettop(L))
-    else
+    if CheckLuaParamCount(L, 1, 'SetInputMask', 'mask') then
         InputMask:= lua_tointeger(L, 1);
     lc_setinputmask:= 0
 end;
 
 function lc_writelntoconsole(L : Plua_State) : LongInt; Cdecl;
 begin
-    if lua_gettop(L) = 1 then
-        begin
+    if CheckLuaParamCount(L, 1, 'WriteLnToConsole', 'string') then
         WriteLnToConsole('Lua: ' + lua_tostring(L ,1));
-        end
-    else
-        LuaParameterCountError('WriteLnToConsole', 'string', lua_gettop(L));
     lc_writelntoconsole:= 0;
 end;
 
@@ -202,29 +410,124 @@
     i,c: LongWord;
     s: shortstring;
 begin
-    if lua_gettop(L) = 1 then
+    if CheckLuaParamCount(L, 1, 'ParseCommand', 'string') then
         begin
-        t:= lua_tolstring(L,1,@c);
+        t:= lua_tolstring(L, 1, Psize_t(@c));
 
         for i:= 1 to c do s[i]:= t[i-1];
         s[0]:= char(c);
 
         ParseCommand(s, true, true);
 
-        end
-    else
-        LuaParameterCountError('ParseCommand', 'string', lua_gettop(L));
+        end;
     lc_parsecommand:= 0;
 end;
 
+// sets weapon to the desired ammo type
+function lc_setweapon(L : Plua_State) : LongInt; Cdecl;
+var at: LongInt;
+const
+    call = 'SetWeapon';
+    params = 'ammoType';
+begin
+    // no point to run this without any CurrentHedgehog
+    if (CurrentHedgehog <> nil) and (CheckLuaParamCount(L, 1, call, params)) then
+        begin
+        at:= LuaToAmmoTypeOrd(L, 1, call, params);
+        if at >= 0 then
+            ParseCommand('setweap ' + char(at), true, true);
+        end;
+    lc_setweapon:= 0;
+end;
+
+// no parameter means reset to default (and 0 means unlimited)
+function lc_setmaxbuilddistance(L : Plua_State) : LongInt; Cdecl;
+var np: LongInt;
+const
+    call = 'SetMaxBuildDistance';
+    params = '[ distInPx ]';
+begin
+    if CheckAndFetchParamCountRange(L, 0, 1, call, params, np) then
+        begin
+        if np = 0 then
+            begin
+            // no args? reset
+            cBuildMaxDist:= cDefaultBuildMaxDist;
+            end
+        else
+            CBuildMaxDist:= lua_tointeger(L, 1);
+        end;
+    lc_setmaxbuilddistance:= 0;
+end;
+
+// sets weapon to whatever weapons is next (wraps around, amSkip is skipped)
+function lc_setnextweapon(L : Plua_State) : LongInt; Cdecl;
+var at          : LongInt;
+    nextAmmo    : TAmmo;
+    s, a, cs, fa: LongInt;
+const
+    call = 'SetNextWeapon';
+    params = '';
+begin
+    if (CurrentHedgehog <> nil) and (CheckLuaParamCount(L, 0, call, params)) then
+        begin
+        at:= -1;
+        with CurrentHedgehog^ do
+            begin
+            cs:= 0; // current slot
+            fa:= 0; // first ammo item to check
+
+            // if something is selected, find it's successor
+            if curAmmoType <> amNothing then
+                begin
+                // get current slot index
+                cs:= Ammoz[CurAmmoType].Slot;
+                // find current ammo index
+                while (fa < cMaxSlotAmmoIndex)
+                    and (Ammo^[cs, fa].AmmoType <> CurAmmoType) do
+                        inc(fa);
+                // increase once more because we won't successor
+                inc(fa);
+                end;
+
+            // find first available ammo
+            // revisit current slot too (current item might not be first)
+            for s:= cs to cs + cMaxSlotIndex + 1 do
+                begin
+                for a:= fa to cMaxSlotAmmoIndex do
+                    begin
+                    // check if we went full circle
+                    if (a = fa) and (s = cs + cMaxSlotIndex + 1)  then
+                        exit(0);
+
+                    // get ammo
+                    nextAmmo:= Ammo^[s mod (cMaxSlotIndex + 1), a];
+                    // only switch to ammos the hog actually has
+                    if (nextAmmo.AmmoType <> amNothing)
+                        and (nextAmmo.AmmoType <> amSkip) and (nextAmmo.Count > 0) then
+                            begin
+                            at:= ord(nextAmmo.AmmoType);
+                            break;
+                            end;
+                    end;
+                // stop slot loop if something was found
+                if at >= 0 then
+                    break;
+                // check following slots starting with first item
+                fa:= 0;
+                end;
+            end;
+
+        if at >= 0 then
+            ParseCommand('setweap ' + char(at), true, true);
+        end;
+    lc_setnextweapon:= 0;
+end;
+
 function lc_showmission(L : Plua_State) : LongInt; Cdecl;
 begin
-    if lua_gettop(L) = 5 then
-        begin
-        ShowMission(lua_tostring(L, 1), lua_tostring(L, 2), lua_tostring(L, 3), lua_tointeger(L, 4), lua_tointeger(L, 5));
-        end
-    else
-        LuaParameterCountError('ShowMission', 'caption, subcaption, text, icon, time', lua_gettop(L));
+    if CheckLuaParamCount(L, 5, 'ShowMission', 'caption, subcaption, text, icon, time') then
+        ShowMission(lua_tostringA(L, 1), lua_tostringA(L, 2), lua_tostringA(L, 3), lua_tointeger(L, 4), lua_tointeger(L, 5));
     lc_showmission:= 0;
 end;
 
@@ -236,181 +539,189 @@
 end;
 
 function lc_enablegameflags(L : Plua_State) : LongInt; Cdecl;
-var i : integer;
+var i, n : integer;
 begin
-    for i:= 1 to lua_gettop(L) do
-        GameFlags := GameFlags or LongWord(lua_tointeger(L, i));
-    ScriptSetInteger('GameFlags', GameFlags);
+    // can have 1 or more arguments
+    if CheckAndFetchLuaParamMinCount(L, 1, 'EnableGameFlags', 'gameFlag, ... ', n) then
+        begin
+        for i:= 1 to n do
+            GameFlags := GameFlags or LongWord(lua_tointeger(L, i));
+        ScriptSetInteger('GameFlags', GameFlags);
+        end;
     lc_enablegameflags:= 0;
 end;
 
 function lc_disablegameflags(L : Plua_State) : LongInt; Cdecl;
-var i : integer;
+var i , n: integer;
 begin
-    for i:= 1 to lua_gettop(L) do
-        GameFlags := GameFlags and not(LongWord(lua_tointeger(L, i)));
-    ScriptSetInteger('GameFlags', GameFlags);
+    // can have 1 or more arguments
+    if CheckAndFetchLuaParamMinCount(L, 1, 'DisableGameFlags', 'gameFlag, ... ', n) then
+        begin
+        for i:= 1 to n do
+            GameFlags := GameFlags and (not LongWord(lua_tointeger(L, i)));
+        ScriptSetInteger('GameFlags', GameFlags);
+        end;
     lc_disablegameflags:= 0;
 end;
 
 function lc_cleargameflags(L : Plua_State) : LongInt; Cdecl;
 begin
-    // Silence hint
-    L:= L;
-    GameFlags:= 0;
-    ScriptSetInteger('GameFlags', GameFlags);
+    if CheckLuaParamCount(L, 0, 'ClearGameFlags', '') then
+        begin
+        GameFlags:= 0;
+        ScriptSetInteger('GameFlags', GameFlags);
+        end;
     lc_cleargameflags:= 0;
 end;
 
+function lc_getgameflag(L : Plua_State) : LongInt; Cdecl;
+begin
+    if CheckLuaParamCount(L, 1, 'GetGameFlag', 'gameflag') then
+        lua_pushboolean(L, (GameFlags and LongWord(lua_tointeger(L, 1)) <> 0))
+    else
+        lua_pushnil(L);
+    lc_getgameflag:= 1;
+end;
+
 function lc_addcaption(L : Plua_State) : LongInt; Cdecl;
+var cg: LongInt;
+const
+    call = 'AddCaption';
+    params = 'text [, color, captiongroup]';
 begin
-    if lua_gettop(L) = 1 then
-        AddCaption(lua_tostring(L, 1), cWhiteColor, capgrpMessage)
-    else if lua_gettop(L) = 3 then
+    if CheckAndFetchParamCount(L, 1, 3, call, params, cg) then
         begin
-        AddCaption(lua_tostring(L, 1), lua_tointeger(L, 2) shr 8, TCapGroup(lua_tointeger(L, 3)));
-        end
-    else
-        LuaParameterCountError('AddCaption', 'text[, color, captiongroup]', lua_gettop(L));
+        if cg = 1 then
+            AddCaption(lua_tostringA(L, 1), cWhiteColor, capgrpMessage)
+        else
+            begin
+            cg:= LuaToCapGroupOrd(L, 3, call, params);
+            if cg >= 0 then
+                AddCaption(lua_tostringA(L, 1), lua_tointeger(L, 2) shr 8, TCapGroup(cg));
+            end
+        end;
     lc_addcaption:= 0;
 end;
 
 function lc_campaignlock(L : Plua_State) : LongInt; Cdecl;
 begin
-    if lua_gettop(L) = 1 then
+    if CheckLuaParamCount(L, 1, 'CampaignLock', 'TODO') then
         begin
-        // to be done
-        end
-    else
-        LuaParameterCountError('CampaignLock', 'TODO', lua_gettop(L));
+        // TODO
+        end;
     lc_campaignlock:= 0;
 end;
 
 function lc_campaignunlock(L : Plua_State) : LongInt; Cdecl;
 begin
-    if lua_gettop(L) = 1 then
+    if CheckLuaParamCount(L, 1, 'CampaignUnlock', 'TODO') then
         begin
-        // to be done
-        end
-    else
-        LuaParameterCountError('CampaignUnlock', 'TODO', lua_gettop(L));
+        // TODO
+        end;
     lc_campaignunlock:= 0;
 end;
 
 function lc_spawnfakehealthcrate(L: Plua_State) : LongInt; Cdecl;
 var gear: PGear;
 begin
-    if lua_gettop(L) <> 4 then
-        begin
-        LuaParameterCountError('SpawnFakeHealthCrate', 'x, y, explode, poison', lua_gettop(L));
-        lua_pushnil(L);
-        end
-    else
+    if CheckLuaParamCount(L, 4,'SpawnFakeHealthCrate', 'x, y, explode, poison') then
         begin
         gear := SpawnFakeCrateAt(lua_tointeger(L, 1), lua_tointeger(L, 2),
         HealthCrate, lua_toboolean(L, 3), lua_toboolean(L, 4));
-        lua_pushinteger(L, gear^.uid);
-        end;
+        if gear <> nil then
+             lua_pushinteger(L, gear^.uid)
+        else lua_pushnil(L)
+        end
+    else
+        lua_pushnil(L);
     lc_spawnfakehealthcrate := 1;
 end;
 
 function lc_spawnfakeammocrate(L: PLua_State): LongInt; Cdecl;
 var gear: PGear;
 begin
-    if lua_gettop(L) <> 4 then
-        begin
-        LuaParameterCountError('SpawnFakeAmmoCrate', 'x, y, explode, poison', lua_gettop(L));
-        lua_pushnil(L);
-        end
-    else
+    if CheckLuaParamCount(L, 4,'SpawnFakeAmmoCrate', 'x, y, explode, poison') then
         begin
         gear := SpawnFakeCrateAt(lua_tointeger(L, 1), lua_tointeger(L, 2),
         AmmoCrate, lua_toboolean(L, 3), lua_toboolean(L, 4));
-        lua_pushinteger(L, gear^.uid);
-        end;
+        if gear <> nil then
+             lua_pushinteger(L, gear^.uid)
+        else lua_pushnil(L)
+        end
+    else
+        lua_pushnil(L);
     lc_spawnfakeammocrate := 1;
 end;
 
 function lc_spawnfakeutilitycrate(L: PLua_State): LongInt; Cdecl;
 var gear: PGear;
 begin
-    if lua_gettop(L) <> 4 then
-        begin
-        LuaParameterCountError('SpawnFakeUtilityCrate', 'x, y, explode, poison', lua_gettop(L));
-        lua_pushnil(L);
-        end
-    else
+    if CheckLuaParamCount(L, 4,'SpawnFakeUtilityCrate', 'x, y, explode, poison') then
         begin
         gear := SpawnFakeCrateAt(lua_tointeger(L, 1), lua_tointeger(L, 2),
         UtilityCrate, lua_toboolean(L, 3), lua_toboolean(L, 4));
-        lua_pushinteger(L, gear^.uid);
-        end;
+        if gear <> nil then
+             lua_pushinteger(L, gear^.uid)
+        else lua_pushnil(L)
+        end
+    else
+        lua_pushnil(L);
     lc_spawnfakeutilitycrate := 1;
 end;
 
 function lc_spawnhealthcrate(L: Plua_State) : LongInt; Cdecl;
 var gear: PGear;
-var health: LongInt;
+var health, n: LongInt;
 begin
-    if (lua_gettop(L) < 2) or (lua_gettop(L) > 3) then
+    if CheckAndFetchParamCount(L, 2, 3, 'SpawnHealthCrate', 'x, y [, health]', n) then
         begin
-        LuaParameterCountError('SpawnHealthCrate', 'x, y[, health]', lua_gettop(L));
-        lua_pushnil(L);
-        end
-    else
-        begin
-        if lua_gettop(L) = 3 then
+        if n = 3 then
             health:= lua_tointeger(L, 3)
         else
             health:= cHealthCaseAmount;
         gear := SpawnCustomCrateAt(lua_tointeger(L, 1), lua_tointeger(L, 2), HealthCrate, health, 0);
         if gear <> nil then
-            lua_pushinteger(L, gear^.uid)
-        else
-            lua_pushnil(L);
-        end;
+             lua_pushinteger(L, gear^.uid)
+        else lua_pushnil(L);
+        end
+    else
+        lua_pushnil(L);
     lc_spawnhealthcrate := 1;
 end;
 
 function lc_spawnammocrate(L: PLua_State): LongInt; Cdecl;
 var gear: PGear;
+    n   : LongInt;
 begin
-    if (lua_gettop(L) <> 3) and (lua_gettop(L) <> 4) then
+    if CheckAndFetchParamCount(L, 3, 4, 'SpawnAmmoCrate', 'x, y, content [, amount]', n) then
         begin
-        LuaParameterCountError('SpawnAmmoCrate', 'x, y, content[, amount]', lua_gettop(L));
-        lua_pushnil(L);
-        end
-    else
-        begin
-        if (lua_gettop(L) = 3) then
+        if n = 3 then
              gear := SpawnCustomCrateAt(lua_tointeger(L, 1), lua_tointeger(L, 2), AmmoCrate, lua_tointeger(L, 3), 0)
         else gear := SpawnCustomCrateAt(lua_tointeger(L, 1), lua_tointeger(L, 2), AmmoCrate, lua_tointeger(L, 3), lua_tointeger(L, 4));
         if gear <> nil then
-            lua_pushinteger(L, gear^.uid)
-        else
-            lua_pushnil(L);
-        end;
+             lua_pushinteger(L, gear^.uid)
+        else lua_pushnil(L);
+        end
+    else
+        lua_pushnil(L);
     lc_spawnammocrate := 1;
 end;
 
 function lc_spawnutilitycrate(L: PLua_State): LongInt; Cdecl;
 var gear: PGear;
+    n   : LongInt;
 begin
-    if (lua_gettop(L) <> 3) and (lua_gettop(L) <> 4) then
+    if CheckAndFetchParamCount(L, 3, 4, 'SpawnUtilityCrate', 'x, y, content [, amount]', n) then
         begin
-        LuaParameterCountError('SpawnUtilityCrate', 'x, y, content[, amount]', lua_gettop(L));
-        lua_pushnil(L);
-        end
-    else
-        begin
-        if (lua_gettop(L) = 3) then
+        if n = 3 then
              gear := SpawnCustomCrateAt(lua_tointeger(L, 1), lua_tointeger(L, 2), UtilityCrate, lua_tointeger(L, 3), 0)
         else gear := SpawnCustomCrateAt(lua_tointeger(L, 1), lua_tointeger(L, 2), UtilityCrate, lua_tointeger(L, 3), lua_tointeger(L, 4));
         if gear <> nil then
-            lua_pushinteger(L, gear^.uid)
-        else
-            lua_pushnil(L);
-       end;
+             lua_pushinteger(L, gear^.uid)
+        else lua_pushnil(L);
+       end
+    else
+        lua_pushnil(L);
     lc_spawnutilitycrate := 1;
 end;
 
@@ -419,37 +730,39 @@
     x, y, s, t: LongInt;
     dx, dy: hwFloat;
     gt: TGearType;
+const
+    call = 'AddGear';
+    params = 'x, y, gearType, state, dx, dy, timer';
 begin
-    if lua_gettop(L) <> 7 then
+    if CheckLuaParamCount(L, 7, call, params) then
         begin
-        LuaParameterCountError('AddGear', 'x, y, gearType, state, dx, dy, timer', lua_gettop(L));
-        lua_pushnil(L); // return value on stack (nil)
+        t:= LuaToGearTypeOrd(L, 3, call, params);
+        if t >= 0 then
+            begin
+            gt:= TGearType(t);
+            x:= lua_tointeger(L, 1);
+            y:= lua_tointeger(L, 2);
+            s:= lua_tointeger(L, 4);
+            dx:= int2hwFloat(lua_tointeger(L, 5)) / 1000000;
+            dy:= int2hwFloat(lua_tointeger(L, 6)) / 1000000;
+            t:= lua_tointeger(L, 7);
+
+            gear:= AddGear(x, y, gt, s, dx, dy, t);
+            lastGearByUID:= gear;
+            lua_pushinteger(L, gear^.uid)
+            end
+        else
+            lua_pushnil(L);
         end
     else
-        begin
-        x:= lua_tointeger(L, 1);
-        y:= lua_tointeger(L, 2);
-        gt:= TGearType(lua_tointeger(L, 3));
-        s:= lua_tointeger(L, 4);
-        dx:= int2hwFloat(lua_tointeger(L, 5)) / 1000000;
-        dy:= int2hwFloat(lua_tointeger(L, 6)) / 1000000;
-        t:= lua_tointeger(L, 7);
-
-        gear:= AddGear(x, y, gt, s, dx, dy, t);
-        lastGearByUID:= gear;
-        lua_pushinteger(L, gear^.uid)
-        end;
+        lua_pushnil(L);
     lc_addgear:= 1; // 1 return value
 end;
 
 function lc_deletegear(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('DeleteGear', 'gearUid', lua_gettop(L));
-        end
-    else
+    if CheckLuaParamCount(L, 1, 'DeleteGear', 'gearUid') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
@@ -460,61 +773,68 @@
 
 function lc_addvisualgear(L : Plua_State) : LongInt; Cdecl;
 var vg : PVisualGear;
-    x, y, s: LongInt;
+    x, y, s, n, layer: LongInt;
     c: Boolean;
     vgt: TVisualGearType;
+    uid: Longword;
+const
+    call = 'AddVisualGear';
+    params = 'x, y, visualGearType, state, critical [, layer]';
 begin
-    if lua_gettop(L) <> 5 then
+    uid:= 0;
+    if CheckAndFetchParamCount(L, 5, 6, call, params, n) then
         begin
-        LuaParameterCountError('AddVisualGear', 'x, y, visualGearType, state, critical', lua_gettop(L));
-        lua_pushnil(L); // return value on stack (nil)
+        s:= LuaToVisualGearTypeOrd(L, 3, call, params);
+        if s >= 0 then
+            begin
+            vgt:= TVisualGearType(s);
+            x:= lua_tointeger(L, 1);
+            y:= lua_tointeger(L, 2);
+            s:= lua_tointeger(L, 4);
+            c:= lua_toboolean(L, 5);
+
+            if n = 6 then
+                begin
+                layer:= lua_tointeger(L, 6);
+                vg:= AddVisualGear(x, y, vgt, s, c, layer);
+                end
+            else
+                vg:= AddVisualGear(x, y, vgt, s, c);
+
+            if vg <> nil then
+                begin
+                lastVisualGearByUID:= vg;
+                uid:= vg^.uid;
+                lua_pushinteger(L, uid);
+                end;
+            end
+            else
+                lua_pushnil(L);
         end
     else
-        begin
-        x:= lua_tointeger(L, 1);
-        y:= lua_tointeger(L, 2);
-        vgt:= TVisualGearType(lua_tointeger(L, 3));
-        s:= lua_tointeger(L, 4);
-        c:= lua_toboolean(L, 5);
-
-        vg:= AddVisualGear(x, y, vgt, s, c);
-        if vg <> nil then
-            begin
-            lastVisualGearByUID:= vg;
-            lua_pushinteger(L, vg^.uid)
-            end
-        else
-            lua_pushinteger(L, 0)
-        end;
+        lua_pushnil(L); // return value on stack (nil)
     lc_addvisualgear:= 1; // 1 return value
 end;
 
 function lc_deletevisualgear(L : Plua_State) : LongInt; Cdecl;
 var vg : PVisualGear;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('DeleteVisualGear', 'vgUid', lua_gettop(L));
-        end
-    else
+    vg:= nil;
+    if CheckLuaParamCount(L, 1, 'DeleteVisualGear', 'vgUid') then
         begin
         vg:= VisualGearByUID(lua_tointeger(L, 1));
         if vg <> nil then
             DeleteVisualGear(vg);
         end;
-    lc_deletevisualgear:= 0
+    // allow caller to know whether there was something to delete
+    lua_pushboolean(L, vg <> nil);
+    lc_deletevisualgear:= 1
 end;
 
 function lc_getvisualgearvalues(L : Plua_State) : LongInt; Cdecl;
 var vg: PVisualGear;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('GetVisualGearValues', 'vgUid', lua_gettop(L));
-        lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L);
-        lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L)
-        end
-    else
+    if CheckLuaParamCount(L, 1, 'GetVisualGearValues', 'vgUid') then
         begin
         vg:= VisualGearByUID(lua_tointeger(L, 1));
         if vg <> nil then
@@ -533,119 +853,238 @@
         else
             begin
             lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L);
-            lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L)
+            lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L);
             end
+        end
+    else
+        begin
+        lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L);
+        lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L);
         end;
-    lc_getvisualgearvalues:= 10;
+    lc_getvisualgearvalues:= 10
 end;
 
 function lc_setvisualgearvalues(L : Plua_State) : LongInt; Cdecl;
 var vg : PVisualGear;
 begin
-    if lua_gettop(L) <> 11 then
-        begin
-        LuaParameterCountError('SetVisualGearValues', 'vgUid, X, Y, dX, dY, Angle, Frame, FrameTicks, State, Timer, Tint', lua_gettop(L));
-        lua_pushnil(L); // return value on stack (nil)
-        end
-    else
-        begin
+// Param count can be 1-11 at present
+//    if CheckLuaParamCount(L, 11, 'SetVisualGearValues', 'vgUid, X, Y, dX, dY, Angle, Frame, FrameTicks, State, Timer, Tint') then
+//        begin
         vg:= VisualGearByUID(lua_tointeger(L, 1));
         if vg <> nil then
             begin
-            vg^.X:= lua_tointeger(L, 2);
-            vg^.Y:= lua_tointeger(L, 3);
-            vg^.dX:= lua_tonumber(L, 4);
-            vg^.dY:= lua_tonumber(L, 5);
-            vg^.Angle:= lua_tonumber(L, 6);
-            vg^.Frame:= lua_tointeger(L, 7);
-            if lua_tointeger(L, 8) <> 0 then
-                vg^.FrameTicks:= lua_tointeger(L, 8);  // find a better way to do this. maybe need to break all these up.
-            vg^.State:= lua_tointeger(L, 9);
-            vg^.Timer:= lua_tointeger(L, 10);
-            vg^.Tint:= lua_tointeger(L, 11);
+            if not lua_isnoneornil(L, 2) then
+                vg^.X:= lua_tointeger(L, 2);
+            if not lua_isnoneornil(L, 3) then
+                vg^.Y:= lua_tointeger(L, 3);
+            if not lua_isnoneornil(L, 4) then
+                vg^.dX:= lua_tonumber(L, 4);
+            if not lua_isnoneornil(L, 5) then
+                vg^.dY:= lua_tonumber(L, 5);
+            if not lua_isnoneornil(L, 6) then
+                vg^.Angle:= lua_tonumber(L, 6);
+            if not lua_isnoneornil(L, 7) then
+                vg^.Frame:= lua_tointeger(L, 7);
+            if not lua_isnoneornil(L, 8) then
+                vg^.FrameTicks:= lua_tointeger(L, 8);
+            if not lua_isnoneornil(L, 9) then
+                vg^.State:= lua_tointeger(L, 9);
+            if not lua_isnoneornil(L, 10) then
+                vg^.Timer:= lua_tointeger(L, 10);
+            if not lua_isnoneornil(L, 11) then
+                vg^.Tint:= lua_tointeger(L, 11)
+            end;
+//        end
+//    else
+//        lua_pushnil(L); // return value on stack (nil)
+    lc_setvisualgearvalues:= 0
+end;
+
+// so. going to use this to get/set some of the more obscure gear values which weren't already exposed elsewhere
+// can keep adding things in the future. isnoneornil makes it safe
+function lc_getgearvalues(L : Plua_State) : LongInt; Cdecl;
+var gear: PGear;
+begin
+    if CheckLuaParamCount(L, 1, 'GetGearValues', 'gearUid') then
+        begin
+        gear:= GearByUID(lua_tointeger(L, 1));
+        if gear <> nil then
+            begin
+            lua_pushinteger(L, gear^.Angle);
+            lua_pushinteger(L, gear^.Power);
+            lua_pushinteger(L, gear^.WDTimer);
+            lua_pushinteger(L, gear^.Radius);
+            lua_pushinteger(L, hwRound(gear^.Density * _10000));
+            lua_pushinteger(L, gear^.Karma);
+            lua_pushnumber(L,  gear^.DirAngle);
+            lua_pushinteger(L, gear^.AdvBounce);
+            lua_pushinteger(L, Integer(gear^.ImpactSound));
+            lua_pushinteger(L, gear^.nImpactSounds);
+            lua_pushinteger(L, gear^.Tint);
+            lua_pushinteger(L, gear^.Damage)
             end
+        else
+            begin
+            lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L);
+            lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L);
+            lua_pushnil(L); lua_pushnil(L)
+            end
+        end
+    else
+        begin
+        lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L);
+        lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); lua_pushnil(L);
+        lua_pushnil(L); lua_pushnil(L)
         end;
-    lc_setvisualgearvalues:= 0;
+    lc_getgearvalues:= 12
+end;
+
+function lc_setgearvalues(L : Plua_State) : LongInt; Cdecl;
+var gear : PGear;
+begin
+// Currently allows 1-13 params
+//    if CheckLuaParamCount(L, 13, 'SetGearValues', 'gearUid, Angle, Power, WDTimer, Radius, Density, Karma, DirAngle, AdvBounce, ImpactSound, # ImpactSounds, Tint, Damage') then
+//        begin
+        gear:= GearByUID(lua_tointeger(L, 1));
+        if gear <> nil then
+            begin
+            if not lua_isnoneornil(L, 2) then
+                gear^.Angle := lua_tointeger(L, 2);
+            if not lua_isnoneornil(L, 3) then
+                gear^.Power := lua_tointeger(L, 3);
+            if not lua_isnoneornil(L, 4) then
+                gear^.WDTimer := lua_tointeger(L, 4);
+            if not lua_isnoneornil(L, 5) then
+                gear^.Radius := lua_tointeger(L, 5);
+            if not lua_isnoneornil(L, 6) then
+                gear^.Density:= int2hwFloat(lua_tointeger(L, 6)) / 10000;
+            if not lua_isnoneornil(L, 7) then
+                gear^.Karma := lua_tointeger(L, 7);
+            if not lua_isnoneornil(L, 8) then
+                gear^.DirAngle:= lua_tonumber(L, 8);
+            if not lua_isnoneornil(L, 9) then
+                gear^.AdvBounce := lua_tointeger(L, 9);
+            if not lua_isnoneornil(L, 10) then
+                gear^.ImpactSound := TSound(lua_tointeger(L, 10));
+            if not lua_isnoneornil(L, 11) then
+                gear^.nImpactSounds := lua_tointeger(L, 11);
+            if not lua_isnoneornil(L, 12) then
+                gear^.Tint := lua_tointeger(L, 12);
+            if not lua_isnoneornil(L, 13) then
+                gear^.Damage := lua_tointeger(L, 13);
+            end;
+//        end
+//    else
+//        lua_pushnil(L); // return value on stack (nil)
+    lc_setgearvalues:= 0
 end;
 
 function lc_getfollowgear(L : Plua_State) : LongInt; Cdecl;
 begin
-    if lua_gettop(L) <> 0 then
+    if CheckLuaParamCount(L, 0, 'GetFollowGear', '') then
         begin
-        LuaParameterCountError('GetFollowGear', '', lua_gettop(L));
-        lua_pushnil(L); // return value on stack (nil)
-        end
-    else
         if FollowGear = nil then
             lua_pushnil(L)
         else
             lua_pushinteger(L, FollowGear^.uid);
+        end
+    else
+        lua_pushnil(L);
     lc_getfollowgear:= 1; // 1 return value
 end;
 
 function lc_getgeartype(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('GetGearType', 'gearUid', lua_gettop(L));
-        lua_pushnil(L); // return value on stack (nil)
-        end
-    else
+    if CheckLuaParamCount(L, 1, 'GetGearType', 'gearUid') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
             lua_pushinteger(L, ord(gear^.Kind))
         else
             lua_pushnil(L);
-        end;
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
     lc_getgeartype:= 1
 end;
 
 function lc_getgearmessage(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('GetGearMessage', 'gearUid', lua_gettop(L));
-        lua_pushnil(L); // return value on stack (nil)
-        end
-    else
+    if CheckLuaParamCount(L, 1, 'GetGearMessage', 'gearUid') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
             lua_pushinteger(L, gear^.message)
         else
             lua_pushnil(L);
-        end;
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
     lc_getgearmessage:= 1
 end;
 
 function lc_getgearelasticity(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('GetGearElasticity', 'gearUid', lua_gettop(L));
-        lua_pushnil(L); // return value on stack (nil)
-        end
-    else
+    if CheckLuaParamCount(L, 1, 'GetGearElasticity', 'gearUid') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
             lua_pushinteger(L, hwRound(gear^.elasticity * _10000))
         else
             lua_pushnil(L);
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
+    lc_getgearelasticity:= 1
+end;
+
+function lc_setgearelasticity(L : Plua_State) : LongInt; Cdecl;
+var gear: PGear;
+begin
+    if CheckLuaParamCount(L, 2, 'SetGearElasticity', 'gearUid, Elasticity') then
+        begin
+        gear:= GearByUID(lua_tointeger(L, 1));
+        if gear <> nil then
+            gear^.Elasticity:= int2hwFloat(lua_tointeger(L, 2)) / 10000
         end;
-    lc_getgearelasticity:= 1
+    lc_setgearelasticity:= 0
+end;
+
+function lc_getgearfriction(L : Plua_State) : LongInt; Cdecl;
+var gear : PGear;
+begin
+    if CheckLuaParamCount(L, 1, 'GetGearFriction', 'gearUid') then
+        begin
+        gear:= GearByUID(lua_tointeger(L, 1));
+        if gear <> nil then
+            lua_pushinteger(L, hwRound(gear^.friction * _10000))
+        else
+            lua_pushnil(L);
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
+    lc_getgearfriction:= 1
+end;
+
+function lc_setgearfriction(L : Plua_State) : LongInt; Cdecl;
+var gear: PGear;
+begin
+    if CheckLuaParamCount(L, 2, 'SetGearFriction', 'gearUid, Friction') then
+        begin
+        gear:= GearByUID(lua_tointeger(L, 1));
+        if gear <> nil then
+            gear^.Friction:= int2hwFloat(lua_tointeger(L, 2)) / 10000
+        end;
+    lc_setgearfriction:= 0
 end;
 
 function lc_setgearmessage(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 2 then
-        LuaParameterCountError('SetGearMessage', 'gearUid, message', lua_gettop(L))
-    else
+    if CheckLuaParamCount(L, 2, 'SetGearMessage', 'gearUid, message') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
@@ -657,28 +1096,23 @@
 function lc_getgearpos(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('GetGearPos', 'gearUid', lua_gettop(L));
-        lua_pushnil(L); // return value on stack (nil)
-        end
-    else
+    if CheckLuaParamCount(L, 1, 'GetGearPos', 'gearUid') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
             lua_pushinteger(L, gear^.Pos)
         else
             lua_pushnil(L);
-        end;
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
     lc_getgearpos:= 1
 end;
 
 function lc_setgearpos(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 2 then
-        LuaParameterCountError('SetGearPos', 'gearUid, value', lua_gettop(L))
-    else
+    if CheckLuaParamCount(L, 2, 'SetGearPos', 'gearUid, value') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
@@ -690,28 +1124,23 @@
 function lc_getgearcollisionmask(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('GetGearCollisionMask', 'gearUid', lua_gettop(L));
-        lua_pushnil(L); // return value on stack (nil)
-        end
-    else
+    if CheckLuaParamCount(L, 1, 'GetGearCollisionMask', 'gearUid') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
             lua_pushinteger(L, gear^.CollisionMask)
         else
             lua_pushnil(L);
-        end;
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
     lc_getgearcollisionmask:= 1
 end;
 
 function lc_setgearcollisionmask(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 2 then
-        LuaParameterCountError('SetGearCollisionMask', 'gearUid, mask', lua_gettop(L))
-    else
+    if CheckLuaParamCount(L, 2, 'SetGearCollisionMask', 'gearUid, mask') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
@@ -723,9 +1152,7 @@
 function lc_gethoglevel(L : Plua_State): LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 1 then
-        LuaParameterCountError('GetHogLevel', 'gearUid', lua_gettop(L))
-    else
+    if CheckLuaParamCount(L, 1, 'GetHogLevel', 'gearUid') then
         begin
         gear := GearByUID(lua_tointeger(L, 1));
         if (gear <> nil) and ((gear^.Kind = gtHedgehog) or (gear^.Kind = gtGrave)) and (gear^.Hedgehog <> nil) then
@@ -739,9 +1166,7 @@
 function lc_sethoglevel(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 2 then
-        LuaParameterCountError('SetHogLevel', 'gearUid, level', lua_gettop(L))
-    else
+    if CheckLuaParamCount(L, 2, 'SetHogLevel', 'gearUid, level') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if (gear <> nil) and (gear^.Kind = gtHedgehog) and (gear^.Hedgehog <> nil) then
@@ -753,12 +1178,7 @@
 function lc_gethogclan(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('GetHogClan', 'gearUid', lua_gettop(L));
-        lua_pushnil(L); // return value on stack (nil)
-        end
-    else
+    if CheckLuaParamCount(L, 1, 'GetHogClan', 'gearUid') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if (gear <> nil) and ((gear^.Kind = gtHedgehog) or (gear^.Kind = gtGrave)) and (gear^.Hedgehog <> nil) then
@@ -767,18 +1187,18 @@
             end
         else
             lua_pushnil(L);
-        end;
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
     lc_gethogclan:= 1
 end;
 
 function lc_getclancolor(L : Plua_State) : LongInt; Cdecl;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('GetClanColor', 'clan', lua_gettop(L));
+    if CheckLuaParamCount(L, 1, 'GetClanColor', 'clan') then
+        lua_pushinteger(L, ClansArray[lua_tointeger(L, 1)]^.Color shl 8 or $FF)
+    else
         lua_pushnil(L); // return value on stack (nil)
-        end
-    else lua_pushinteger(L, ClansArray[lua_tointeger(L, 1)]^.Color shl 8 or $FF);
     lc_getclancolor:= 1
 end;
 
@@ -788,11 +1208,11 @@
     hh   : THedgehog;
     i, j : LongInt;
 begin
-    if lua_gettop(L) <> 2 then
-        LuaParameterCountError('SetClanColor', 'clan, color', lua_gettop(L))
-    else
+    if CheckLuaParamCount(L, 2, 'SetClanColor', 'clan, color') then
         begin
-        clan := ClansArray[lua_tointeger(L, 1)];
+	i:= lua_tointeger(L,1);
+	if i >= ClansCount then exit(0);
+        clan := ClansArray[i];
         clan^.Color:= lua_tointeger(L, 2) shr 8;
 
         for i:= 0 to Pred(clan^.TeamsNumber) do
@@ -803,75 +1223,111 @@
                 hh:= team^.Hedgehogs[j];
                 if (hh.Gear <> nil) or (hh.GearHidden <> nil) then
                     begin
-                    FreeTexture(hh.NameTagTex);
-                    hh.NameTagTex:= RenderStringTex(hh.Name, clan^.Color, fnt16);
+                    FreeAndNilTexture(hh.NameTagTex);
+                    hh.NameTagTex:= RenderStringTex(ansistring(hh.Name), clan^.Color, fnt16);
                     RenderHealth(hh);
                     end;
                 end;
-            FreeTexture(team^.NameTagTex);
-            team^.NameTagTex:= RenderStringTex(clan^.Teams[i]^.TeamName, clan^.Color, fnt16);
+            FreeAndNilTexture(team^.NameTagTex);
+            team^.NameTagTex:= RenderStringTex(ansistring(clan^.Teams[i]^.TeamName), clan^.Color, fnt16);
             end;
 
+	    FreeAndNilTexture(clan^.HealthTex);
         clan^.HealthTex:= makeHealthBarTexture(cTeamHealthWidth + 5, clan^.Teams[0]^.NameTagTex^.h, clan^.Color);
         end;
 
     lc_setclancolor:= 0
 end;
 
+function lc_gethogvoicepack(L : Plua_State) : LongInt; Cdecl;
+var gear : PGear;
+begin
+    if CheckLuaParamCount(L, 1, 'GetHogVoicepack', 'gearUid') then
+        begin
+        gear:= GearByUID(lua_tointeger(L, 1));
+        if (gear <> nil) and (gear^.Kind = gtHedgehog) and (gear^.Hedgehog <> nil) then
+            lua_pushstring(L, str2pchar(gear^.Hedgehog^.Team^.Voicepack^.name))
+        else
+            lua_pushnil(L);
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
+    lc_gethogvoicepack:= 1
+end;
+
+function lc_gethoggrave(L : Plua_State) : LongInt; Cdecl;
+var gear : PGear;
+begin
+    if CheckLuaParamCount(L, 1, 'GetHogGrave', 'gearUid') then
+        begin
+        gear:= GearByUID(lua_tointeger(L, 1));
+        if (gear <> nil) and ((gear^.Kind = gtHedgehog) or (gear^.Kind = gtGrave)) and (gear^.Hedgehog <> nil) then
+            lua_pushstring(L, str2pchar(gear^.Hedgehog^.Team^.GraveName))
+        else
+            lua_pushnil(L);
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
+    lc_gethoggrave:= 1
+end;
+
+function lc_gethogflag(L : Plua_State) : LongInt; Cdecl;
+var gear : PGear;
+begin
+    if CheckLuaParamCount(L, 1, 'GetHogFlag', 'gearUid') then
+        begin
+        gear:= GearByUID(lua_tointeger(L, 1));
+        if (gear <> nil) and (gear^.Kind = gtHedgehog) and (gear^.Hedgehog <> nil) then
+            lua_pushstring(L, str2pchar(gear^.Hedgehog^.Team^.Flag))
+        else
+            lua_pushnil(L);
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
+    lc_gethogflag:= 1
+end;
+
 function lc_gethogteamname(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('GetHogTeamName', 'gearUid', lua_gettop(L));
-        lua_pushnil(L); // return value on stack (nil)
-        end
-    else
+    if CheckLuaParamCount(L, 1, 'GetHogTeamName', 'gearUid') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if (gear <> nil) and ((gear^.Kind = gtHedgehog) or (gear^.Kind = gtGrave)) and (gear^.Hedgehog <> nil) then
-            begin
             lua_pushstring(L, str2pchar(gear^.Hedgehog^.Team^.TeamName))
-            end
         else
             lua_pushnil(L);
-        end;
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
     lc_gethogteamname:= 1
 end;
 
 function lc_sethogteamname(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 2 then
-        begin
-        LuaParameterCountError('SetHogTeamName', 'gearUid, name', lua_gettop(L));
-        lua_pushnil(L); // return value on stack (nil)
-        end
-    else
+    if CheckLuaParamCount(L, 2, 'SetHogTeamName', 'gearUid, name') then
         begin
         gear := GearByUID(lua_tointeger(L, 1));
         if (gear <> nil) and ((gear^.Kind = gtHedgehog) or (gear^.Kind = gtGrave)) and (gear^.Hedgehog <> nil) then
             begin
             gear^.Hedgehog^.Team^.TeamName := lua_tostring(L, 2);
 
-            FreeTexture(gear^.Hedgehog^.Team^.NameTagTex);
-            gear^.Hedgehog^.Team^.NameTagTex:= RenderStringTex(gear^.Hedgehog^.Team^.TeamName, gear^.Hedgehog^.Team^.Clan^.Color, fnt16);
+            FreeAndNilTexture(gear^.Hedgehog^.Team^.NameTagTex);
+            gear^.Hedgehog^.Team^.NameTagTex:= RenderStringTex(ansistring(gear^.Hedgehog^.Team^.TeamName), gear^.Hedgehog^.Team^.Clan^.Color, fnt16);
             end
         else
             lua_pushnil(L);
-        end;
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
     lc_sethogteamname:= 1
 end;
 
 function lc_gethogname(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('GetHogName', 'gearUid', lua_gettop(L));
-        lua_pushnil(L); // return value on stack (nil)
-        end
-    else
+    if CheckLuaParamCount(L, 1, 'GetHogName', 'gearUid') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if (gear <> nil) and ((gear^.Kind = gtHedgehog) or (gear^.Kind = gtGrave)) and (gear^.Hedgehog <> nil) then
@@ -880,27 +1336,24 @@
             end
         else
             lua_pushnil(L);
-        end;
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
     lc_gethogname:= 1
 end;
 
 function lc_sethogname(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 2 then
-        begin
-        LuaParameterCountError('SetHogName', 'gearUid, name', lua_gettop(L));
-        lua_pushnil(L)
-        end
-    else
+    if CheckLuaParamCount(L, 2, 'SetHogName', 'gearUid, name') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if (gear <> nil) and (gear^.Kind = gtHedgehog) and (gear^.Hedgehog <> nil) then
             begin
             gear^.Hedgehog^.Name:= lua_tostring(L, 2);
 
-            FreeTexture(gear^.Hedgehog^.NameTagTex);
-            gear^.Hedgehog^.NameTagTex:= RenderStringTex(gear^.Hedgehog^.Name, gear^.Hedgehog^.Team^.Clan^.Color, fnt16)
+            FreeAndNilTexture(gear^.Hedgehog^.NameTagTex);
+            gear^.Hedgehog^.NameTagTex:= RenderStringTex(ansistring(gear^.Hedgehog^.Name), gear^.Hedgehog^.Team^.Clan^.Color, fnt16)
             end
         end;
     lc_sethogname:= 0;
@@ -909,87 +1362,87 @@
 function lc_gettimer(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('GetTimer', 'gearUid', lua_gettop(L));
-        lua_pushnil(L); // return value on stack (nil)
-        end
-    else
+    if CheckLuaParamCount(L, 1, 'GetTimer', 'gearUid') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
             lua_pushinteger(L, gear^.Timer)
         else
             lua_pushnil(L);
-        end;
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
     lc_gettimer:= 1
 end;
 
+function lc_getflighttime(L : Plua_State) : LongInt; Cdecl;
+var gear : PGear;
+begin
+    if CheckLuaParamCount(L, 1, 'GetFlightTime', 'gearUid') then
+        begin
+        gear:= GearByUID(lua_tointeger(L, 1));
+        if gear <> nil then
+            lua_pushinteger(L, gear^.FlightTime)
+        else
+            lua_pushnil(L);
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
+    lc_getflighttime:= 1
+end;
+
 function lc_gethealth(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('GetHealth', 'gearUid', lua_gettop(L));
-        lua_pushnil(L); // return value on stack (nil)
-        end
-    else
+    if CheckLuaParamCount(L, 1, 'GetHealth', 'gearUid') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
             lua_pushinteger(L, gear^.Health)
         else
             lua_pushnil(L);
-        end;
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
     lc_gethealth:= 1
 end;
 
 function lc_getx(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('GetX', 'gearUid', lua_gettop(L));
-        lua_pushnil(L); // return value on stack (nil)
-        end
-    else
+    if CheckLuaParamCount(L, 1, 'GetX', 'gearUid') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
             lua_pushinteger(L, hwRound(gear^.X))
         else
             lua_pushnil(L);
-        end;
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
     lc_getx:= 1
 end;
 
 function lc_gety(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('GetY', 'gearUid', lua_gettop(L));
-        lua_pushnil(L); // return value on stack (nil)
-        end
-    else
+    if CheckLuaParamCount(L, 1, 'GetY', 'gearUid') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
             lua_pushinteger(L, hwRound(gear^.Y))
         else
             lua_pushnil(L);
-        end;
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
     lc_gety:= 1
 end;
 
 function lc_copypv(L : Plua_State) : LongInt; Cdecl;
 var gears, geard : PGear;
 begin
-    if lua_gettop(L) <> 2 then
-        begin
-        LuaParameterCountError('CopyPV', 'fromGearUid, toGearUid', lua_gettop(L));
-        end
-    else
+    if CheckLuaParamCount(L, 2, 'CopyPV', 'fromGearUid, toGearUid') then
         begin
         gears:= GearByUID(lua_tointeger(L, 1));
         geard:= GearByUID(lua_tointeger(L, 2));
@@ -1001,15 +1454,13 @@
             geard^.dY:= gears^.dY;
             end
         end;
-    lc_copypv:= 1
+    lc_copypv:= 0
 end;
 
 function lc_followgear(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 1 then
-        LuaParameterCountError('FollowGear', 'gearUid', lua_gettop(L))
-    else
+    if CheckLuaParamCount(L, 1, 'FollowGear', 'gearUid') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then FollowGear:= gear
@@ -1021,42 +1472,47 @@
 var gear : PGear;
    vgear : PVisualGear;
        s : LongWord;
+       n : LongInt;
 begin
-    if lua_gettop(L) = 4 then
-        s:= lua_tointeger(L, 4)
-    else
-        s:= 0;
-
-    if (lua_gettop(L) = 4) or (lua_gettop(L) = 3) then
+    if CheckAndFetchParamCount(L, 3, 4, 'HogSay', 'gearUid, text, manner [, vgState]', n) then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
             begin
+            // state defaults to 0 if state param is given
+            if n = 4 then
+                s:= lua_tointeger(L, 4)
+            else
+                s:= 0;
             vgear:= AddVisualGear(0, 0, vgtSpeechBubble, s, true);
             if vgear <> nil then
                begin
                vgear^.Text:= lua_tostring(L, 2);
-               vgear^.Hedgehog:= gear^.Hedgehog;
+               if Gear^.Kind = gtHedgehog then
+                   begin
+                   AddChatString(#9+'[' + gear^.Hedgehog^.Name + '] '+vgear^.text);
+                   vgear^.Hedgehog:= gear^.Hedgehog
+                   end
+               else vgear^.Frame:= gear^.uid;
+
                vgear^.FrameTicks:= lua_tointeger(L, 3);
                if (vgear^.FrameTicks < 1) or (vgear^.FrameTicks > 3) then
                    vgear^.FrameTicks:= 1;
                lua_pushinteger(L, vgear^.Uid);
-               AddChatString(#1+'[' + gear^.Hedgehog^.Name + '] '+vgear^.text)
                end
             end
-            else
-                lua_pushnil(L)
+        else
+            lua_pushnil(L)
         end
-    else LuaParameterCountError('HogSay', 'gearUid, text, manner[, vgState]', lua_gettop(L));
+    else
+        lua_pushnil(L);
     lc_hogsay:= 1
 end;
 
 function lc_switchhog(L : Plua_State) : LongInt; Cdecl;
 var gear, prevgear : PGear;
 begin
-    if lua_gettop(L) <> 1 then
-        LuaParameterCountError('SwitchHog', 'gearUid', lua_gettop(L))
-    else
+    if CheckLuaParamCount(L, 1, 'SwitchHog', 'gearUid') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
 // should we allow this when there is no current hedgehog? might do some odd(er) things to turn sequence.
@@ -1083,93 +1539,78 @@
     lc_switchhog:= 0
 end;
 
-{function lc_addammo(L : Plua_State) : LongInt; Cdecl;
-var gear : PGear;
-begin
-
-    if lua_gettop(L) = 3 then
-    begin
-    gear:= GearByUID(lua_tointeger(L, 1));
-        if (gear <> nil) and (gear^.Hedgehog <> nil) then
-            AddAmmoAmount(gear^.Hedgehog^, TAmmoType(lua_tointeger(L, 2)), lua_tointeger(L,3) );
-    end else
-
-    if lua_gettop(L) = 2 then
-    begin
-    gear:= GearByUID(lua_tointeger(L, 1));
-        if (gear <> nil) and (gear^.Hedgehog <> nil) then
-            AddAmmo(gear^.Hedgehog^, TAmmoType(lua_tointeger(L, 2)));
-    end else
-    begin
-        LuaParameterCountError('AddAmmo', 'TODO', lua_gettop(L));
-    end;
-
-    lc_addammo:= 0;
-
-end;}
-
 function lc_addammo(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
+    at, n: LongInt;
+const
+    call = 'AddAmmo';
+    params = 'gearUid, ammoType [, ammoCount]';
 begin
-    if (lua_gettop(L) = 3) or (lua_gettop(L) = 2) then
+    if CheckAndFetchParamCount(L, 2, 3, call, params, n) then
         begin
-        gear:= GearByUID(lua_tointeger(L, 1));
-        if (gear <> nil) and (gear^.Hedgehog <> nil) then
-            if lua_gettop(L) = 2 then
-                AddAmmo(gear^.Hedgehog^, TAmmoType(lua_tointeger(L, 2)))
-            else
-                SetAmmo(gear^.Hedgehog^, TAmmoType(lua_tointeger(L, 2)), lua_tointeger(L, 3))
-        end
-    else LuaParameterCountError('AddAmmo', 'gearUid, ammoType[, ammoCount]', lua_gettop(L));
+        at:= LuaToAmmoTypeOrd(L, 2, call, params);
+        if at >= 0 then
+            begin
+            gear:= GearByUID(lua_tointeger(L, 1));
+            if (gear <> nil) and (gear^.Hedgehog <> nil) then
+                if n = 2 then
+                    AddAmmo(gear^.Hedgehog^, TAmmoType(at))
+                else
+                    SetAmmo(gear^.Hedgehog^, TAmmoType(at), lua_tointeger(L, 3))
+            end;
+        end;
     lc_addammo:= 0
 end;
 
 function lc_getammocount(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
     ammo : PAmmo;
+    at   : LongInt;
+const
+    call = 'GetAmmoCount';
+    params = 'gearUid, ammoType';
 begin
-    if (lua_gettop(L) = 2) then
+    if CheckLuaParamCount(L, 2, call, params) then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if (gear <> nil) and (gear^.Hedgehog <> nil) then
             begin
-            ammo:= GetAmmoEntry(gear^.Hedgehog^, TAmmoType(lua_tointeger(L, 2)));
-            if ammo^.AmmoType = amNothing then
-                lua_pushinteger(L, 0)
-            else
-                lua_pushinteger(L, ammo^.Count)
+            at:= LuaToAmmoTypeOrd(L, 2, call, params);
+            if at >= 0 then
+                begin
+                ammo:= GetAmmoEntry(gear^.Hedgehog^, TAmmoType(at));
+                if ammo^.AmmoType = amNothing then
+                    lua_pushinteger(L, 0)
+                else
+                    lua_pushinteger(L, ammo^.Count);
+                end;
             end
-        else lua_pushinteger(L, 0)
+        else lua_pushinteger(L, 0);
         end
     else
-        begin
-        LuaParameterCountError('GetAmmoCount', 'gearUid, ammoType', lua_gettop(L));
-        lua_pushnil(L)
-        end;
+        lua_pushnil(L);
     lc_getammocount:= 1
 end;
 
 function lc_sethealth(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 2 then
-        begin
-        LuaParameterCountError('SetHealth', 'gearUid, health', lua_gettop(L));
-        end
-    else
+    if CheckLuaParamCount(L, 2, 'SetHealth', 'gearUid, health') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
             begin
             gear^.Health:= lua_tointeger(L, 2);
 
-        if (gear^.Kind = gtHedgehog) and (gear^.Hedgehog <> nil) then
-            begin
-            RenderHealth(gear^.Hedgehog^);
-            RecountTeamHealth(gear^.Hedgehog^.Team)
-            end;
-
-            SetAllToActive;
+            if (gear^.Kind = gtHedgehog) and (gear^.Hedgehog <> nil) then
+                begin
+                RenderHealth(gear^.Hedgehog^);
+                RecountTeamHealth(gear^.Hedgehog^.Team)
+                end;
+            // Why did this do a "setalltoactive" ?
+            //SetAllToActive;
+            Gear^.Active:= true;
+            AllInactive:= false
             end
         end;
     lc_sethealth:= 0
@@ -1178,11 +1619,7 @@
 function lc_settimer(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 2 then
-        begin
-        LuaParameterCountError('SetTimer', 'gearUid, timer', lua_gettop(L));
-        end
-    else
+    if CheckLuaParamCount(L, 2, 'SetTimer', 'gearUid, timer') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then gear^.Timer:= lua_tointeger(L, 2)
@@ -1190,45 +1627,65 @@
     lc_settimer:= 0
 end;
 
+function lc_setflighttime(L : Plua_State) : LongInt; Cdecl;
+var gear : PGear;
+begin
+    if CheckLuaParamCount(L, 2, 'SetFlightTime', 'gearUid, flighttime') then
+        begin
+        gear:= GearByUID(lua_tointeger(L, 1));
+        if gear <> nil then gear^.FlightTime:= lua_tointeger(L, 2)
+        end;
+    lc_setflighttime:= 0
+end;
+
 function lc_seteffect(L : Plua_State) : LongInt; Cdecl;
 var gear: PGear;
+    t   : LongInt;
+const
+    call = 'SetEffect';
+    params = 'gearUid, effect, effectState';
 begin
-    if lua_gettop(L) <> 3 then
-        LuaParameterCountError('SetEffect', 'gearUid, effect, enabled', lua_gettop(L))
-    else begin
-        gear := GearByUID(lua_tointeger(L, 1));
-        if (gear <> nil) and (gear^.Hedgehog <> nil) then
-            gear^.Hedgehog^.Effects[THogEffect(lua_tointeger(L, 2))]:= lua_tointeger(L, 3);
-    end;
+    if CheckLuaParamCount(L, 3, call, params) then
+        begin
+        t:= LuaToHogEffectOrd(L, 2, call, params);
+        if t >= 0 then
+            begin
+            gear := GearByUID(lua_tointeger(L, 1));
+            if (gear <> nil) and (gear^.Hedgehog <> nil) then
+                gear^.Hedgehog^.Effects[THogEffect(t)]:= lua_tointeger(L, 3);
+            end;
+        end;
     lc_seteffect := 0;
 end;
 
 function lc_geteffect(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
+    t    : LongInt;
+const
+    call = 'GetEffect';
+    params = 'gearUid, effect';
 begin
-    if lua_gettop(L) <> 2 then
+    if CheckLuaParamCount(L, 2, call, params) then
         begin
-        LuaParameterCountError('GetEffect', 'gearUid, effect', lua_gettop(L));
+        t:= LuaToHogEffectOrd(L, 2, call, params);
+        if t >= 0 then
+            begin
+            gear:= GearByUID(lua_tointeger(L, 1));
+            if (gear <> nil) and (gear^.Hedgehog <> nil) then
+                lua_pushinteger(L, gear^.Hedgehog^.Effects[THogEffect(t)])
+            else
+                lua_pushinteger(L, 0)
+            end;
         end
     else
-        begin
-        gear:= GearByUID(lua_tointeger(L, 1));
-        if (gear <> nil) and (gear^.Hedgehog <> nil) then
-            lua_pushinteger(L, gear^.Hedgehog^.Effects[THogEffect(lua_tointeger(L, 2))])
-        else
-            lua_pushinteger(L, 0)
-        end;
+        lua_pushinteger(L, 0);
     lc_geteffect:= 1
 end;
 
 function lc_setstate(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 2 then
-        begin
-        LuaParameterCountError('SetState', 'gearUid, state', lua_gettop(L));
-        end
-    else
+    if CheckLuaParamCount(L, 2, 'SetState', 'gearUid, state') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
@@ -1243,48 +1700,39 @@
 function lc_getstate(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('GetState', 'gearUid', lua_gettop(L));
-        end
-    else
+    if CheckLuaParamCount(L, 1, 'GetState', 'gearUid') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
             lua_pushinteger(L, gear^.State)
         else
             lua_pushnil(L)
-        end;
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
     lc_getstate:= 1
 end;
 
 function lc_gettag(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('GetTag', 'gearUid', lua_gettop(L));
-        lua_pushnil(L); // return value on stack (nil)
-        end
-    else
+    if CheckLuaParamCount(L, 1, 'GetTag', 'gearUid') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
             lua_pushinteger(L, gear^.Tag)
         else
             lua_pushnil(L);
-        end;
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
     lc_gettag:= 1
 end;
 
 function lc_settag(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 2 then
-        begin
-        LuaParameterCountError('SetTag', 'gearUid, tag', lua_gettop(L));
-        end
-    else
+    if CheckLuaParamCount(L, 2, 'SetTag', 'gearUid, tag') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
@@ -1305,50 +1753,62 @@
 
 function lc_sendstat(L : Plua_State) : LongInt; Cdecl;
 var statInfo : TStatInfoType;
-var i : LongInt;
-var color : shortstring;
+    i, n     : LongInt;
+    color, tn: shortstring;
+    needsTn  : boolean;
+const
+    call = 'SendStat';
+    params = 'statInfoType, color [, teamname]';
 begin
-    statInfo := TStatInfoType(lua_tointeger(L, 1));
-    if (lua_gettop(L) <> 2) and ((statInfo <> siPlayerKills)
-            and (statInfo <> siClanHealth)) then
+    if CheckAndFetchParamCount(L, 2, 3, call, params, n) then
         begin
-        LuaParameterCountError('SendStat', 'statInfoType, color', lua_gettop(L));
-        end
-    else if (lua_gettop(L) <> 3) and ((statInfo = siPlayerKills)
-            or (statInfo = siClanHealth)) then
-        begin
-        LuaParameterCountError('SendStat', 'siClanHealth, color, teamname', lua_gettop(L));
-        end
-    else
-        begin
-        if ((statInfo = siPlayerKills) or (statInfo = siClanHealth)) then
+        i:= LuaToStatInfoTypeOrd(L, 1, call, params);
+        if i >= 0 then
             begin
-            // 3: team name
-            for i:= 0 to Pred(TeamsCount) do
+            statInfo:= TStatInfoType(i);
+            needsTn:= ((statInfo = siPlayerKills) or (statInfo = siClanHealth));
+            // check if param count is correct for the used statInfo
+            if (n = 3) <> needsTn then
+                begin
+                if n = 3 then
+                    LuaCallError(EnumToStr(statInfo) + ' does not support the teamname parameter', call, params)
+                else
+                    LuaCallError(EnumToStr(statInfo) + ' requires the teamname parameter', call, params);
+                end
+            else // count is correct!
                 begin
-                with TeamsArray[i]^ do
+                if needsTn then
                     begin
-                        if TeamName = lua_tostring(L, 3) then
+                    // 3: team name
+                    for i:= 0 to Pred(TeamsCount) do
+                        begin
+                        color:= _S'0';
+                        tn:= lua_tostring(L, 3);
+                        with TeamsArray[i]^ do
                             begin
-                            color := uUtils.IntToStr(Clan^.Color);
-                            Break;
+                                if TeamName = tn then
+                                    begin
+                                    color := uUtils.IntToStr(Clan^.Color);
+                                    Break;
+                                    end
                             end
+                        end;
+                    if (statInfo = siPlayerKills) then
+                        begin
+                            SendStat(siPlayerKills, color + ' ' +
+                                lua_tostring(L, 2) + ' ' + tn);
+                        end
+                    else if (statInfo = siClanHealth) then
+                        begin
+                            SendStat(siClanHealth, color + ' ' +
+                                lua_tostring(L, 2));
+                        end
                     end
+                else
+                    begin
+                    SendStat(statInfo,lua_tostring(L, 2));
+                    end;
                 end;
-            if (statInfo = siPlayerKills) then
-                begin
-                    SendStat(siPlayerKills, color + ' ' +
-                        lua_tostring(L, 2) + ' ' + TeamsArray[i]^.TeamName);
-                end
-            else if (statInfo = siClanHealth) then
-                begin
-                    SendStat(siClanHealth, color + ' ' +
-                        lua_tostring(L, 2));
-                end
-            end
-        else
-            begin
-            SendStat(statInfo,lua_tostring(L, 2));
             end;
         end;
     lc_sendstat:= 0
@@ -1365,54 +1825,60 @@
 var gear: PGear;
     fall: boolean;
     tryhard: boolean;
-    left, right: LongInt;
+    left, right, n: LongInt;
 begin
-    tryhard:= false;
-    if (lua_gettop(L) <> 4) and (lua_gettop(L) <> 5) then
-        LuaParameterCountError('FindPlace', 'gearUid, fall, left, right[, tryHarder]', lua_gettop(L))
-    else
+    if CheckAndFetchParamCount(L, 4, 5, 'FindPlace', 'gearUid, fall, left, right [, tryHarder]', n) then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         fall:= lua_toboolean(L, 2);
         left:= lua_tointeger(L, 3);
         right:= lua_tointeger(L, 4);
-        if lua_gettop(L) = 5 then
-            tryhard:= lua_toboolean(L, 5);
+        if n = 5 then
+            tryhard:= lua_toboolean(L, 5)
+        else
+            tryhard:= false;
         if gear <> nil then
             FindPlace(gear, fall, left, right, tryhard);
         if gear <> nil then
             lua_pushinteger(L, gear^.uid)
         else
             lua_pushnil(L);
-        end;
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
     lc_findplace:= 1
 end;
 
 function lc_playsound(L : Plua_State) : LongInt; Cdecl;
 var gear: PGear;
+    n, s: LongInt;
+const
+    call = 'PlaySound';
+    params = 'soundId [, hhGearUid]';
 begin
-    if lua_gettop(L) = 1 then
-        PlaySound(TSound(lua_tointeger(L, 1)))
-    else if lua_gettop(L) = 2 then
+    if CheckAndFetchParamCount(L, 1, 2, call, params, n) then
         begin
-        gear:= GearByUID(lua_tointeger(L, 2));
-        if (gear <> nil) and (gear^.Kind = gtHedgehog) and (gear^.Hedgehog <> nil) then
-            AddVoice(TSound(lua_tointeger(L, 1)),gear^.Hedgehog^.Team^.Voicepack)
-        end
-    else LuaParameterCountError('PlaySound', 'soundId', lua_gettop(L));
+        s:= LuaToSoundOrd(L, 1, call, params);
+        if s >= 0 then
+            begin
+            // no gear specified
+            if n = 1 then
+                PlaySound(TSound(s))
+            else
+                begin
+                gear:= GearByUID(lua_tointeger(L, 2));
+                if (gear <> nil) and (gear^.Kind = gtHedgehog) and (gear^.Hedgehog <> nil) then
+                    AddVoice(TSound(s),gear^.Hedgehog^.Team^.Voicepack)
+                end;
+            end;
+        end;
     lc_playsound:= 0;
 end;
 
 function lc_addteam(L : Plua_State) : LongInt; Cdecl;
 var np: LongInt;
 begin
-    np:= lua_gettop(L);
-    if (np < 5) or (np > 6) then
-        begin
-        LuaParameterCountError('AddTeam', 'teamname, color, grave, fort, voicepack[, flag]', lua_gettop(L));
-        //lua_pushnil(L)
-        end
-    else
+    if CheckAndFetchParamCount(L, 5, 6, 'AddTeam', 'teamname, color, grave, fort, voicepack [, flag]', np) then
         begin
         ParseCommand('addteam x ' + lua_tostring(L, 2) + ' ' + lua_tostring(L, 1), true, true);
         ParseCommand('grave ' + lua_tostring(L, 3), true, true);
@@ -1423,35 +1889,73 @@
         // fails on x64
         //lua_pushinteger(L, LongInt(CurrentTeam));
         end;
+    //else
+        //lua_pushnil(L)
     lc_addteam:= 0;//1;
 end;
 
+function lc_dismissteam(L : Plua_State) : LongInt; Cdecl;
+var HHGear: PGear;
+    i, h  : LongInt;
+    hidden: boolean;
+begin
+    if CheckLuaParamCount(L, 1, 'DismissTeam', 'teamname') then
+        begin
+        if TeamsCount > 0 then
+            for i:= 0 to Pred(TeamsCount) do
+                begin
+                // skip teams that don't have matching name
+                if TeamsArray[i]^.TeamName <> lua_tostring(L, 1) then
+                    continue;
+
+                // destroy all hogs of matching team, including the hidden ones
+                for h:= 0 to cMaxHHIndex do
+                    begin
+                    hidden:= (TeamsArray[i]^.Hedgehogs[h].GearHidden <> nil);
+                    if hidden then
+                        RestoreHog(@TeamsArray[i]^.Hedgehogs[h]);
+                    // destroy hedgehog gear, if any
+                    HHGear:= TeamsArray[i]^.Hedgehogs[h].Gear;
+                    if HHGear <> nil then
+                        begin
+                        // smoke effect
+                        if (not hidden) then
+                            begin
+                            AddVisualGear(hwRound(HHGear^.X), hwRound(HHGear^.Y), vgtSmokeWhite);
+                            AddVisualGear(hwRound(HHGear^.X) - 16 + Random(32), hwRound(HHGear^.Y) - 16 + Random(32), vgtSmokeWhite);
+                            AddVisualGear(hwRound(HHGear^.X) - 16 + Random(32), hwRound(HHGear^.Y) - 16 + Random(32), vgtSmokeWhite);
+                            AddVisualGear(hwRound(HHGear^.X) - 16 + Random(32), hwRound(HHGear^.Y) - 16 + Random(32), vgtSmokeWhite);
+                            AddVisualGear(hwRound(HHGear^.X) - 16 + Random(32), hwRound(HHGear^.Y) - 16 + Random(32), vgtSmokeWhite);
+                            end;
+                        HHGear^.Message:= HHGear^.Message or gmDestroy;
+                        end;
+                    end;
+                // can't dismiss more than one team
+                break;
+                end;
+        end;
+    lc_dismissteam:= 0;
+end;
+
 function lc_addhog(L : Plua_State) : LongInt; Cdecl;
 var temp: ShortString;
 begin
-    if lua_gettop(L) <> 4 then
-        begin
-        LuaParameterCountError('AddHog', 'hogname, botlevel, health, hat', lua_gettop(L));
-        lua_pushnil(L)
-        end
-    else
+    if CheckLuaParamCount(L, 4, 'AddHog', 'hogname, botlevel, health, hat') then
         begin
         temp:= lua_tostring(L, 4);
         ParseCommand('addhh ' + lua_tostring(L, 2) + ' ' + lua_tostring(L, 3) + ' ' + lua_tostring(L, 1), true, true);
         ParseCommand('hat ' + temp, true, true);
         lua_pushinteger(L, CurrentHedgehog^.Gear^.uid);
-        end;
+        end
+    else
+        lua_pushnil(L);
     lc_addhog:= 1;
 end;
 
 function lc_hogturnleft(L : Plua_State) : LongInt; Cdecl;
 var gear: PGear;
 begin
-    if lua_gettop(L) <> 2 then
-        begin
-        LuaParameterCountError('HogTurnLeft', 'gearUid, boolean', lua_gettop(L));
-        end
-    else
+    if CheckLuaParamCount(L, 2, 'HogTurnLeft', 'gearUid, boolean') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
@@ -1463,13 +1967,7 @@
 function lc_getgearposition(L : Plua_State) : LongInt; Cdecl;
 var gear: PGear;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('GetGearPosition', 'gearUid', lua_gettop(L));
-        lua_pushnil(L);
-        lua_pushnil(L)
-        end
-    else
+    if CheckLuaParamCount(L, 1, 'GetGearPosition', 'gearUid') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
@@ -1482,6 +1980,11 @@
             lua_pushnil(L);
             lua_pushnil(L)
             end;
+        end
+    else
+        begin
+        lua_pushnil(L);
+        lua_pushnil(L)
         end;
     lc_getgearposition:= 2;
 end;
@@ -1491,9 +1994,7 @@
     col: boolean;
     x, y: LongInt;
 begin
-    if lua_gettop(L) <> 3 then
-        LuaParameterCountError('SetGearPosition', 'gearUid, x, y', lua_gettop(L))
-    else
+    if CheckLuaParamCount(L, 3, 'SetGearPosition', 'gearUid, x, y') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
@@ -1516,13 +2017,7 @@
 function lc_getgeartarget(L : Plua_State) : LongInt; Cdecl;
 var gear: PGear;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('GetGearTarget', 'gearUid', lua_gettop(L));
-        lua_pushnil(L);
-        lua_pushnil(L)
-        end
-    else
+    if CheckLuaParamCount(L, 1, 'GetGearTarget', 'gearUid') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
@@ -1535,6 +2030,11 @@
             lua_pushnil(L);
             lua_pushnil(L)
             end
+        end
+    else
+        begin
+        lua_pushnil(L);
+        lua_pushnil(L)
         end;
     lc_getgeartarget:= 2;
 end;
@@ -1542,9 +2042,7 @@
 function lc_setgeartarget(L : Plua_State) : LongInt; Cdecl;
 var gear: PGear;
 begin
-    if lua_gettop(L) <> 3 then
-        LuaParameterCountError('SetGearTarget', 'gearUid, x, y', lua_gettop(L))
-    else
+    if CheckLuaParamCount(L, 3, 'SetGearTarget', 'gearUid, x, y') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
@@ -1560,13 +2058,7 @@
 var gear: PGear;
 var t: LongInt;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('GetGearVelocity', 'gearUid', lua_gettop(L));
-        lua_pushnil(L);
-        lua_pushnil(L)
-        end
-    else
+    if CheckLuaParamCount(L, 1, 'GetGearVelocity', 'gearUid') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
@@ -1577,6 +2069,11 @@
             lua_pushinteger(L, t);
             lua_pushinteger(L, hwRound(gear^.dY * 1000000))
             end
+        end
+    else
+        begin
+        lua_pushnil(L);
+        lua_pushnil(L);
         end;
     lc_getgearvelocity:= 2;
 end;
@@ -1584,9 +2081,7 @@
 function lc_setgearvelocity(L : Plua_State) : LongInt; Cdecl;
 var gear: PGear;
 begin
-    if lua_gettop(L) <> 3 then
-        LuaParameterCountError('SetGearVelocity', 'gearUid, dx, dy', lua_gettop(L))
-    else
+    if CheckLuaParamCount(L, 3, 'SetGearVelocity', 'gearUid, dx, dy') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
@@ -1601,9 +2096,7 @@
 
 function lc_setzoom(L : Plua_State) : LongInt; Cdecl;
 begin
-    if lua_gettop(L) <> 1 then
-        LuaParameterCountError('SetZoom', 'zoomLevel', lua_gettop(L))
-    else
+    if CheckLuaParamCount(L, 1, 'SetZoom', 'zoomLevel') then
         begin
         ZoomValue:= lua_tonumber(L, 1);
         if ZoomValue < cMaxZoomLevel then
@@ -1616,47 +2109,51 @@
 
 function lc_getzoom(L : Plua_State) : LongInt; Cdecl;
 begin
-    if lua_gettop(L) <> 0 then
-        begin
-        LuaParameterCountError('GetZoom', '', lua_gettop(L));
-        lua_pushnil(L)
-        end
+    if CheckLuaParamCount(L, 0, 'GetZoom', '') then
+        lua_pushnumber(L, ZoomValue)
     else
-        lua_pushnumber(L, ZoomValue);
+        lua_pushnil(L);
     lc_getzoom:= 1
 end;
 
 function lc_setammo(L : Plua_State) : LongInt; Cdecl;
-var np: LongInt;
+var np, at: LongInt;
+const
+    call = 'SetAmmo';
+    params = 'ammoType, count, probability, delay [, numberInCrate]';
 begin
-    np:= lua_gettop(L);
-    if (np < 4) or (np > 5) then
-        LuaParameterCountError('SetAmmo', 'ammoType, count, probability, delay[, numberInCrate]', lua_gettop(L))
-    else if np = 4 then
-        ScriptSetAmmo(TAmmoType(lua_tointeger(L, 1)), lua_tointeger(L, 2), lua_tointeger(L, 3), lua_tointeger(L, 4), 1)
-    else
-        ScriptSetAmmo(TAmmoType(lua_tointeger(L, 1)), lua_tointeger(L, 2), lua_tointeger(L, 3), lua_tointeger(L, 4), lua_tointeger(L, 5));
+    if CheckAndFetchParamCount(L, 4, 5, call, params, np) then
+        begin
+        at:= LuaToAmmoTypeOrd(L, 1, call, params);
+        if at >= 0 then
+            begin
+            if np = 4 then
+                ScriptSetAmmo(TAmmoType(at), lua_tointeger(L, 2), lua_tointeger(L, 3), lua_tointeger(L, 4), 1)
+            else
+                ScriptSetAmmo(TAmmoType(at), lua_tointeger(L, 2), lua_tointeger(L, 3), lua_tointeger(L, 4), lua_tointeger(L, 5));
+            end;
+        end;
     lc_setammo:= 0
 end;
 
 function lc_setammodelay(L : Plua_State) : LongInt; Cdecl;
-var np: LongInt;
+var at: LongInt;
+const
+    call = 'SetAmmoDelay';
+    params = 'ammoType, delay';
 begin
-    np:= lua_gettop(L);
-    if (np <> 2) then
-        LuaParameterCountError('SetAmmoDelay', 'ammoType, delay', lua_gettop(L))
-    else
-        ScriptSetAmmoDelay(TAmmoType(lua_tointeger(L, 1)), lua_tointeger(L, 2));
+    if CheckLuaParamCount(L, 2, call, params) then
+        begin
+        at:= LuaToAmmoTypeOrd(L, 1, call, params);
+        if at >= 0 then
+            ScriptSetAmmoDelay(TAmmoType(at), lua_tointeger(L, 2));
+        end;
     lc_setammodelay:= 0
 end;
 
 function lc_setammostore(L : Plua_State) : LongInt; Cdecl;
-var np: LongInt;
 begin
-    np:= lua_gettop(L);
-    if (np <> 4) then
-        LuaParameterCountError('SetAmmoStore', 'loadouts, probabilities, delays, reinforments', lua_gettop(L))
-    else
+    if CheckLuaParamCount(L, 4, 'SetAmmoStore', 'loadouts, probabilities, delays, reinforments') then
         begin
         ScriptAmmoLoadout:= lua_tostring(L, 1);
         ScriptAmmoProbability:= lua_tostring(L, 2);
@@ -1669,12 +2166,7 @@
 function lc_getrandom(L : Plua_State) : LongInt; Cdecl;
 var m : LongInt;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('GetRandom', 'number', lua_gettop(L));
-        lua_pushnil(L); // return value on stack (nil)
-        end
-    else
+    if CheckLuaParamCount(L, 1, 'GetRandom', 'number') then
         begin
         m:= lua_tointeger(L, 1);
         if (m > 0) then
@@ -1684,15 +2176,15 @@
             LuaError('Lua: Tried to pass 0 to GetRandom!');
             lua_pushnil(L);
             end
-        end;
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
     lc_getrandom:= 1
 end;
 
 function lc_setwind(L : Plua_State) : LongInt; Cdecl;
 begin
-    if lua_gettop(L) <> 1 then
-        LuaParameterCountError('SetWind', 'windSpeed', lua_gettop(L))
-    else
+    if CheckLuaParamCount(L, 1, 'SetWind', 'windSpeed') then
         begin
         cWindSpeed:= int2hwfloat(lua_tointeger(L, 1)) / 100 * cMaxWindSpeed;
         cWindSpeedf:= SignAs(cWindSpeed,cWindSpeed).QWordValue / SignAs(_1,_1).QWordValue;
@@ -1705,71 +2197,60 @@
 
 function lc_getdatapath(L : Plua_State) : LongInt; Cdecl;
 begin
-    if lua_gettop(L) <> 0 then
-        begin
-        LuaParameterCountError('GetDataPath', '', lua_gettop(L));
+    if CheckLuaParamCount(L, 0, 'GetDataPath', '') then
+        lua_pushstring(L, str2pchar(cPathz[ptData]))
+    else
         lua_pushnil(L);
-        end
-    else
-        lua_pushstring(L, str2pchar(cPathz[ptData]));
     lc_getdatapath:= 1
 end;
 
 function lc_getuserdatapath(L : Plua_State) : LongInt; Cdecl;
 begin
-    if lua_gettop(L) <> 0 then
-        begin
-        LuaParameterCountError('GetUserDataPath', '', lua_gettop(L));
+    if CheckLuaParamCount(L, 0, 'GetUserDataPath', '') then
+        lua_pushstring(L, str2pchar(cPathz[ptData]))
+    else
         lua_pushnil(L);
-        end
-    else
-        lua_pushstring(L, str2pchar(cPathz[ptData]));
     lc_getuserdatapath:= 1
 end;
 
 function lc_maphasborder(L : Plua_State) : LongInt; Cdecl;
 begin
-    if lua_gettop(L) <> 0 then
-        begin
-        LuaParameterCountError('MapHasBorder', '', lua_gettop(L));
+    if CheckLuaParamCount(L, 0, 'MapHasBorder', '') then
+        lua_pushboolean(L, hasBorder)
+    else
         lua_pushnil(L);
-        end
-    else
-        lua_pushboolean(L, hasBorder);
     lc_maphasborder:= 1
 end;
 
 function lc_getgearradius(L : Plua_State) : LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('GetGearRadius', 'gearUid', lua_gettop(L));
-        lua_pushnil(L); // return value on stack (nil)
-        end
-    else
+    if CheckLuaParamCount(L, 1, 'GetGearRadius', 'gearUid') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
             lua_pushinteger(L, gear^.Radius)
         else
             lua_pushnil(L);
-        end;
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
     lc_getgearradius:= 1
 end;
 
 function lc_gethoghat(L : Plua_State): LongInt; Cdecl;
 var gear : PGear;
 begin
-    if lua_gettop(L) <> 1 then
-        LuaParameterCountError('GetHogHat', 'gearUid', lua_gettop(L))
-    else begin
+    if CheckLuaParamCount(L, 1, 'GetHogHat', 'gearUid') then
+        begin
         gear := GearByUID(lua_tointeger(L, 1));
         if (gear <> nil) and ((gear^.Kind = gtHedgehog) or (gear^.Kind = gtGrave)) and (gear^.Hedgehog <> nil) then
             lua_pushstring(L, str2pchar(gear^.Hedgehog^.Hat))
         else
             lua_pushnil(L);
-    end;
+        end
+    else
+        lua_pushnil(L);
     lc_gethoghat := 1;
 end;
 
@@ -1777,12 +2258,7 @@
 var gear : PGear;
     hat: ShortString;
 begin
-    if lua_gettop(L) <> 2 then
-        begin
-        LuaParameterCountError('SetHogHat', 'gearUid, hat', lua_gettop(L));
-        lua_pushnil(L)
-        end
-    else
+    if CheckLuaParamCount(L, 2, 'SetHogHat', 'gearUid, hat') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if (gear <> nil) and (gear^.Kind = gtHedgehog) and (gear^.Hedgehog <> nil) then
@@ -1799,42 +2275,133 @@
     lc_sethoghat:= 0;
 end;
 
-function lc_placegirder(L : Plua_State) : LongInt; Cdecl;
+function lc_placesprite(L : Plua_State) : LongInt; Cdecl;
+var spr   : TSprite;
+    lf    : Word;
+    tint  : LongWord;
+    i, n : LongInt;
+    placed, behind, flipHoriz, flipVert : boolean;
+const
+    call = 'PlaceSprite';
+    params = 'x, y, sprite, frameIdx, tint, behind, flipHoriz, flipVert, [, landFlag, ... ]';
 begin
-    if lua_gettop(L) <> 3 then
-        LuaParameterCountError('PlaceGirder', 'x, y, state', lua_gettop(L))
-    else
-        TryPlaceOnLand(
+    placed:= false;
+    if CheckAndFetchLuaParamMinCount(L, 4, call, params, n) then
+        begin
+        if not lua_isnoneornil(L, 5) then
+	        tint := lua_tointeger(L, 5)
+        else tint := $FFFFFFFF;
+        if not lua_isnoneornil(L, 6) then
+	        behind := lua_toboolean(L, 6)
+        else behind := false;
+        if not lua_isnoneornil(L, 7) then
+	        flipHoriz := lua_toboolean(L, 7)
+        else flipHoriz := false;
+        if not lua_isnoneornil(L, 8) then
+	        flipVert := lua_toboolean(L, 8)
+        else flipVert := false;
+        lf:= 0;
+
+        // accept any amount of landflags, loop is never executed if n<9
+        for i:= 9 to n do
+            lf:= lf or lua_tointeger(L, i);
+
+        n:= LuaToSpriteOrd(L, 3, call, params);
+        if n >= 0 then
+            begin
+            spr:= TSprite(n);
+            if SpritesData[spr].Surface = nil then
+                LuaError(call + ': ' + EnumToStr(spr) + ' cannot be placed! (required information not loaded)' )
+            else
+                placed:= ForcePlaceOnLand(
+                    lua_tointeger(L, 1) - SpritesData[spr].Width div 2,
+                    lua_tointeger(L, 2) - SpritesData[spr].Height div 2,
+                    spr, lua_tointeger(L, 4), lf, tint, behind, flipHoriz, flipVert);
+            end;
+        end;
+
+    lua_pushboolean(L, placed);
+    lc_placesprite:= 1
+end;
+
+function lc_erasesprite(L : Plua_State) : LongInt; Cdecl;
+var spr   : TSprite;
+    lf    : Word;
+    i, n : LongInt;
+    eraseOnLFMatch, onlyEraseLF, flipHoriz, flipVert : boolean;
+const
+    call = 'EraseSprite';
+    params = 'x, y, sprite, frameIdx, eraseOnLFMatch, onlyEraseLF, flipHoriz, flipVert, [, landFlag, ... ]';
+begin
+    if CheckAndFetchLuaParamMinCount(L, 4, call, params, n) then
+        begin
+        if not lua_isnoneornil(L, 5) then
+	        eraseOnLFMatch := lua_toboolean(L, 5)
+        else eraseOnLFMatch := false;
+        if not lua_isnoneornil(L, 6) then
+	        onlyEraseLF := lua_toboolean(L, 6)
+        else onlyEraseLF := false;
+        if not lua_isnoneornil(L, 7) then
+	        flipHoriz := lua_toboolean(L, 7)
+        else flipHoriz := false;
+        if not lua_isnoneornil(L, 8) then
+	        flipVert := lua_toboolean(L, 8)
+        else flipVert := false;
+        lf:= 0;
+
+        // accept any amount of landflags, loop is never executed if n<9
+        for i:= 9 to n do
+            lf:= lf or lua_tointeger(L, i);
+
+        n:= LuaToSpriteOrd(L, 3, call, params);
+        if n >= 0 then
+            begin
+            spr:= TSprite(n);
+            if SpritesData[spr].Surface = nil then
+                LuaError(call + ': ' + EnumToStr(spr) + ' cannot be placed! (required information not loaded)' )
+            else
+                EraseLand(
+                    lua_tointeger(L, 1) - SpritesData[spr].Width div 2,
+                    lua_tointeger(L, 2) - SpritesData[spr].Height div 2,
+                    spr, lua_tointeger(L, 4), lf, eraseOnLFMatch, onlyEraseLF, flipHoriz, flipVert);
+            end;
+        end;
+    lc_erasesprite:= 0
+end;
+
+function lc_placegirder(L : Plua_State) : LongInt; Cdecl;
+var placed: boolean;
+begin
+    placed:= false;
+    if CheckLuaParamCount(L, 3, 'PlaceGirder', 'x, y, frameIdx') then
+        placed:= TryPlaceOnLandSimple(
             lua_tointeger(L, 1) - SpritesData[sprAmGirder].Width div 2,
             lua_tointeger(L, 2) - SpritesData[sprAmGirder].Height div 2,
             sprAmGirder, lua_tointeger(L, 3), true, false);
-    lc_placegirder:= 0
+
+    lua_pushboolean(L, placed);
+    lc_placegirder:= 1
 end;
 
 function lc_getcurammotype(L : Plua_State): LongInt; Cdecl;
 begin
-    if lua_gettop(L) <> 0 then
-        LuaParameterCountError('GetCurAmmoType', '', lua_gettop(L))
+    if (CurrentHedgehog <> nil) and (CheckLuaParamCount(L, 0, 'GetCurAmmoType', '')) then
+        lua_pushinteger(L, ord(CurrentHedgehog^.CurAmmoType))
     else
-        lua_pushinteger(L, ord(CurrentHedgehog^.CurAmmoType));
+        lua_pushinteger(L, ord(amNothing));
     lc_getcurammotype := 1;
 end;
 
 function lc_savecampaignvar(L : Plua_State): LongInt; Cdecl;
 begin
-    if lua_gettop(L) <> 2 then
-        LuaParameterCountError('SaveCampaignVar', 'varname, value', lua_gettop(L))
-    else begin
+    if CheckLuaParamCount(L, 2, 'SaveCampaignVar', 'varname, value') then
         SendIPC('V!' + lua_tostring(L, 1) + ' ' + lua_tostring(L, 2) + #0);
-    end;
     lc_savecampaignvar := 0;
 end;
 
 function lc_getcampaignvar(L : Plua_State): LongInt; Cdecl;
 begin
-    if (lua_gettop(L) <> 1) then
-        LuaParameterCountError('GetCampaignVar', 'varname', lua_gettop(L))
-    else
+    if CheckLuaParamCount(L, 1, 'GetCampaignVar', 'varname') then
         SendIPCAndWaitReply('V?' + lua_tostring(L, 1) + #0);
     lua_pushstring(L, str2pchar(CampaignVariable));
     lc_getcampaignvar := 1;
@@ -1843,9 +2410,7 @@
 function lc_hidehog(L: Plua_State): LongInt; Cdecl;
 var gear: PGear;
 begin
-    if lua_gettop(L) <> 1 then
-        LuaParameterCountError('HideHog', 'gearUid', lua_gettop(L))
-    else
+    if CheckLuaParamCount(L, 1, 'HideHog', 'gearUid') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         HideHog(gear^.hedgehog)
@@ -1857,9 +2422,7 @@
 var i, h: LongInt;
     uid: LongWord;
 begin
-    if lua_gettop(L) <> 1 then
-        LuaParameterCountError('RestoreHog', 'gearUid', lua_gettop(L))
-    else
+    if CheckLuaParamCount(L, 1, 'RestoreHog', 'gearUid') then
         begin
         uid:= LongWord(lua_tointeger(L, 1));
         if TeamsCount > 0 then
@@ -1878,14 +2441,9 @@
 function lc_testrectforobstacle(L : Plua_State) : LongInt; Cdecl;
 var rtn: Boolean;
 begin
-    if lua_gettop(L) <> 5 then
+    if CheckLuaParamCount(L, 5, 'TestRectForObstacle', 'x1, y1, x2, y2, landOnly') then
         begin
-        LuaParameterCountError('TestRectForObstacle', 'x1, y1, x2, y2, landOnly', lua_gettop(L));
-        lua_pushnil(L); // return value on stack (nil)
-        end
-    else
-        begin
-        rtn:= TestRectancleForObstacle(
+        rtn:= TestRectangleForObstacle(
                     lua_tointeger(L, 1),
                     lua_tointeger(L, 2),
                     lua_tointeger(L, 3),
@@ -1893,47 +2451,165 @@
                     lua_toboolean(L, 5)
                     );
         lua_pushboolean(L, rtn);
-        end;
+        end
+    else
+        lua_pushnil(L); // return value on stack (nil)
     lc_testrectforobstacle:= 1
 end;
 
 
-function lc_setaihintsongear(L : Plua_State) : LongInt; Cdecl;
+function lc_getgravity(L : Plua_State) : LongInt; Cdecl;
+begin
+    if CheckLuaParamCount(L, 0, 'GetGravity', '') then
+        lua_pushinteger(L, hwRound(SignAs(_0_5, cGravity) + (cGravity * 50 / cMaxWindSpeed)));
+    lc_getgravity:= 1
+end;
+
+function lc_setgravity(L : Plua_State) : LongInt; Cdecl;
+begin
+    if CheckLuaParamCount(L, 1, 'SetGravity', 'percent') then
+        begin
+        cGravity:= _0_02 * lua_tointeger(L, 1) * cMaxWindSpeed;
+        cGravityf:= 0.00025 * lua_tointeger(L, 1) * 0.02
+        end;
+    lc_setgravity:= 0
+end;
+
+function lc_setwaterline(L : Plua_State) : LongInt; Cdecl;
+var iterator: PGear;
+begin
+    if CheckLuaParamCount(L, 1, 'SetWaterLine', 'waterline') then
+        begin
+        cWaterLine:= lua_tointeger(L,1);
+        AllInactive:= false;
+        iterator:= GearsList;
+        while iterator <> nil do
+            begin
+            if not (iterator^.Kind in [gtPortal, gtAirAttack]) and (iterator^.Message and (gmAllStoppable or gmLJump or gmHJump) = 0) then
+                begin
+                iterator^.Active:= true;
+                if iterator^.dY.QWordValue = 0 then iterator^.dY.isNegative:= false;
+                iterator^.State:= iterator^.State or gstMoving;
+                DeleteCI(iterator)
+                end;
+            iterator:= iterator^.NextGear
+            end
+        end;
+    lc_setwaterline:= 0
+end;
+
+function lc_setgearaihints(L : Plua_State) : LongInt; Cdecl;
 var gear: PGear;
 begin
-    if lua_gettop(L) <> 2 then
-        LuaParameterCountError('SetAIHintOnGear', 'gearUid, aiHints', lua_gettop(L))
-    else
+    if CheckLuaParamCount(L, 2, 'SetAIHintOnGear', 'gearUid, aiHints') then
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
         if gear <> nil then
             gear^.aihints:= lua_tointeger(L, 2);
         end;
-    lc_setaihintsongear:= 0
+    lc_setgearaihints:= 0
 end;
 
 
 function lc_hedgewarsscriptload(L : Plua_State) : LongInt; Cdecl;
 begin
-    if lua_gettop(L) <> 1 then
-        begin
-        LuaParameterCountError('HedgewarsScriptLoad', 'scriptPath', lua_gettop(L));
-        lua_pushnil(L)
-        end
+    if CheckLuaParamCount(L, 1, 'HedgewarsScriptLoad', 'scriptPath') then
+        ScriptLoad(lua_tostring(L, 1))
     else
-        ScriptLoad(lua_tostring(L, 1));
+        lua_pushnil(L);
     lc_hedgewarsscriptload:= 0;
 end;
 
 
 function lc_declareachievement(L : Plua_State) : LongInt; Cdecl;
 begin
-    if lua_gettop(L) <> 4 then
-        LuaParameterCountError('DeclareAchievement', 'achievementId, teamname, location, value', lua_gettop(L))
-    else
+    if CheckLuaParamCount(L, 4, 'DeclareAchievement', 'achievementId, teamname, location, value') then
         declareAchievement(lua_tostring(L, 1), lua_tostring(L, 2), lua_tostring(L, 3), lua_tointeger(L, 4));
     lc_declareachievement:= 0
 end;
+
+
+procedure ScriptFlushPoints();
+begin
+    ParseCommand('draw ' + PointsBuffer, true, true);
+    PointsBuffer:= '';
+end;
+
+
+function lc_addPoint(L : Plua_State) : LongInt; Cdecl;
+var np, param: LongInt;
+begin
+    if CheckAndFetchParamCountRange(L, 2, 4, 'AddPoint', 'x, y [, width [, erase] ]', np) then
+        begin
+        // x
+        param:= LongInt(lua_tointeger(L,1));
+        PointsBuffer:= PointsBuffer + char((param shr 8) and $FF);
+        PointsBuffer:= PointsBuffer + char((param and $FF));
+        // y
+        param:= LongInt(lua_tointeger(L,2));
+        PointsBuffer:= PointsBuffer + char((param shr 8) and $FF);
+        PointsBuffer:= PointsBuffer + char((param and $FF));
+        // width
+        if np > 2 then
+            begin
+            param:= lua_tointeger(L,3);
+            param:= (param or $80);
+            // erase
+            if (np > 3) and lua_toboolean(L, 4) then
+                param:= (param or $40);
+            PointsBuffer:= PointsBuffer + char(param);
+            end
+        // no width defined
+        else
+            PointsBuffer:= PointsBuffer + char(0);
+
+        // flush before shortstring limit length is reached
+        if length(PointsBuffer) > 245 then
+            ScriptFlushPoints();
+        end;
+    lc_addPoint:= 0
+end;
+
+
+function lc_flushPoints(L : Plua_State) : LongInt; Cdecl;
+begin
+    if CheckLuaParamCount(L, 0, 'FlushPoints', '') then
+        if length(PointsBuffer) > 0 then
+            ScriptFlushPoints();
+    lc_flushPoints:= 0
+end;
+
+// stuff for lua tests
+function lc_endluatest(L : Plua_State) : LongInt; Cdecl;
+var rstring: shortstring;
+const
+    call = 'EndLuaTest';
+    params = 'TEST_SUCCESSFUL or TEST_FAILED';
+begin
+    if CheckLuaParamCount(L, 1, call, params) then
+        begin
+
+        case lua_tointeger(L, 1) of
+            HaltTestSuccess : rstring:= 'Success';
+            HaltTestLuaError: rstring:= 'FAILED';
+        else
+            begin
+            LuaCallError('Parameter must be either ' + params, call, params);
+            exit(0);
+            end;
+        end;
+
+        if cTestLua then
+            begin
+            WriteLnToConsole('Lua test finished, result: ' + rstring);
+            halt(lua_tointeger(L, 1));
+            end
+        else LuaError('Not in lua test mode, engine will keep running. Reported test result: ' + rstring);
+
+        end;
+
+    lc_endluatest:= 0;
+end;
 ///////////////////
 
 procedure ScriptPrintStack;
@@ -1987,6 +2663,28 @@
     lua_pop(luaState, 1);
 end;
 
+procedure ScriptOnPreviewInit;
+begin
+// not required if there is no script to run
+if not ScriptLoaded then
+    exit;
+
+ScriptSetString('Seed', cSeed);
+ScriptSetInteger('TemplateFilter', cTemplateFilter);
+ScriptSetInteger('TemplateNumber', LuaTemplateNumber);
+ScriptSetInteger('MapGen', ord(cMapGen));
+ScriptSetInteger('MapFeatureSize', cFeatureSize);
+
+ScriptCall('onPreviewInit');
+
+// pop game variables
+ParseCommand('seed ' + ScriptGetString('Seed'), true, true);
+cTemplateFilter  := ScriptGetInteger('TemplateFilter');
+LuaTemplateNumber:= ScriptGetInteger('TemplateNumber');
+cMapGen          := TMapGen(ScriptGetInteger('MapGen'));
+cFeatureSize     := ScriptGetInteger('MapFeatureSize');
+end;
+
 procedure ScriptOnGameInit;
 var i, j, k: LongInt;
 begin
@@ -1995,12 +2693,15 @@
     exit;
 
 // push game variables so they may be modified by the script
+ScriptSetInteger('CursorX', CursorPoint.X);
+ScriptSetInteger('CursorY', CursorPoint.Y);
 ScriptSetInteger('BorderColor', ExplosionBorderColor);
 ScriptSetInteger('GameFlags', GameFlags);
 ScriptSetString('Seed', cSeed);
 ScriptSetInteger('TemplateFilter', cTemplateFilter);
 ScriptSetInteger('TemplateNumber', LuaTemplateNumber);
-ScriptSetInteger('MapGen', cMapGen);
+ScriptSetInteger('MapGen', ord(cMapGen));
+ScriptSetInteger('MapFeatureSize', cFeatureSize);
 ScriptSetInteger('ScreenHeight', cScreenHeight);
 ScriptSetInteger('ScreenWidth', cScreenWidth);
 ScriptSetInteger('TurnTime', cHedgehogTurnTime);
@@ -2018,8 +2719,8 @@
 ScriptSetInteger('SuddenDeathTurns', cSuddenDTurns);
 ScriptSetInteger('WaterRise', cWaterRise);
 ScriptSetInteger('HealthDecrease', cHealthDecrease);
+ScriptSetInteger('GetAwayTime', cGetAwayTime);
 ScriptSetString('Map', cMapName);
-
 ScriptSetString('Theme', '');
 ScriptSetString('Goals', '');
 
@@ -2029,7 +2730,8 @@
 ParseCommand('seed ' + ScriptGetString('Seed'), true, true);
 cTemplateFilter  := ScriptGetInteger('TemplateFilter');
 LuaTemplateNumber:= ScriptGetInteger('TemplateNumber');
-cMapGen          := ScriptGetInteger('MapGen');
+cMapGen          := TMapGen(ScriptGetInteger('MapGen'));
+cFeatureSize     := ScriptGetInteger('MapFeatureSize');
 GameFlags        := ScriptGetInteger('GameFlags');
 cHedgehogTurnTime:= ScriptGetInteger('TurnTime');
 cCaseFactor      := ScriptGetInteger('CaseFreq');
@@ -2046,6 +2748,7 @@
 cSuddenDTurns    := ScriptGetInteger('SuddenDeathTurns');
 cWaterRise       := ScriptGetInteger('WaterRise');
 cHealthDecrease  := ScriptGetInteger('HealthDecrease');
+cGetAwayTime     := ScriptGetInteger('GetAwayTime');
 
 if cMapName <> ScriptGetString('Map') then
     ParseCommand('map ' + ScriptGetString('Map'), true, true);
@@ -2133,8 +2836,8 @@
 
 if ret <> 0 then
     begin
-    LuaError('Lua: Failed to load ' + name + '(error ' + IntToStr(ret) + ')');
-    LuaError('Lua: ' + lua_tostring(luaState, -1));
+    LuaError('Failed to load ' + name + '(error ' + IntToStr(ret) + ')');
+    LuaError(lua_tostring(luaState, -1));
     end
 else
     begin
@@ -2143,7 +2846,7 @@
     lua_pcall(luaState, 0, 0, 0);
     ScriptLoaded:= true
     end;
-    hedgewarsMountPackage(Str2PChar(copy(s, 1, length(s)-4)+'.hwp'));
+hedgewarsMountPackage(Str2PChar(copy(s, 1, length(s)-4)+'.hwp'));
 end;
 
 procedure SetGlobals;
@@ -2152,6 +2855,25 @@
 ScriptSetInteger('GameTime', GameTicks);
 ScriptSetInteger('TotalRounds', TotalRounds);
 ScriptSetInteger('WaterLine', cWaterLine);
+if isCursorVisible and (not bShowAmmoMenu) then
+    begin
+    if (prevCursorPoint.X <> CursorPoint.X) or 
+       (prevCursorPoint.Y <> CursorPoint.Y) then
+        begin
+        ScriptSetInteger('CursorX', CursorPoint.X - WorldDx);
+        ScriptSetInteger('CursorY', cScreenHeight - CursorPoint.Y- WorldDy);
+        prevCursorPoint.X:= CursorPoint.X;
+        prevCursorPoint.Y:= CursorPoint.Y;
+        end
+    end
+else
+    begin
+    ScriptSetInteger('CursorX', NoPointX);
+    ScriptSetInteger('CursorY', NoPointX);
+    prevCursorPoint.X:= NoPointX;
+    prevCursorPoint.Y:= NoPointX
+    end;
+
 if not mapDims then
     begin
     mapDims:= true;
@@ -2169,18 +2891,24 @@
 
 procedure GetGlobals;
 begin
+// TODO
+// Use setters instead, because globals should be read-only!
+// Otherwise globals might be changed by Lua, but then unexpectatly overwritten by engine when a ScriptCall is triggered by whatever Lua is doing!
+// Sure, one could work around that in engine (e.g. by setting writable globals in SetGlobals only when their engine-side value has actually changed since SetGlobals was called the last time...), but things just get messier and messier then.
+// It is inconsistent anyway to have some globals be read-only and others not with no indication whatsoever.
+// -- sheepluva
 TurnTimeLeft:= ScriptGetInteger('TurnTimeLeft');
 end;
 
 procedure ScriptCall(fname : shortstring);
 begin
-if not ScriptLoaded or (not ScriptExists(fname)) then
+if (not ScriptLoaded) or (not ScriptExists(fname)) then
     exit;
 SetGlobals;
 lua_getglobal(luaState, Str2PChar(fname));
 if lua_pcall(luaState, 0, 0, 0) <> 0 then
     begin
-    LuaError('Lua: Error while calling ' + fname + ': ' + lua_tostring(luaState, -1));
+    LuaError('Error while calling ' + fname + ': ' + lua_tostring(luaState, -1));
     lua_pop(luaState, 1)
     end;
 GetGlobals;
@@ -2225,8 +2953,8 @@
 
 function ScriptCall(fname : shortstring; par1, par2, par3, par4 : LongInt) : LongInt;
 begin
-if not ScriptLoaded or (not ScriptExists(fname)) then
-    exit;
+if (not ScriptLoaded) or (not ScriptExists(fname)) then
+    exit(0);
 SetGlobals;
 lua_getglobal(luaState, Str2PChar(fname));
 lua_pushinteger(luaState, par1);
@@ -2236,7 +2964,7 @@
 ScriptCall:= 0;
 if lua_pcall(luaState, 4, 1, 0) <> 0 then
     begin
-    LuaError('Lua: Error while calling ' + fname + ': ' + lua_tostring(luaState, -1));
+    LuaError('Error while calling ' + fname + ': ' + lua_tostring(luaState, -1));
     lua_pop(luaState, 1)
     end
 else
@@ -2361,6 +3089,8 @@
     st : TSound;
     he : THogEffect;
     cg : TCapGroup;
+    spr: TSprite;
+    mg : TMapGen;
 begin
 // initialize lua
 luaState:= lua_open;
@@ -2385,6 +3115,7 @@
 ScriptSetInteger('gfLowGravity', gfLowGravity);
 ScriptSetInteger('gfLaserSight', gfLaserSight);
 ScriptSetInteger('gfInvulnerable', gfInvulnerable);
+ScriptSetInteger('gfResetHealth', gfResetHealth);
 ScriptSetInteger('gfVampiric', gfVampiric);
 ScriptSetInteger('gfKarma', gfKarma);
 ScriptSetInteger('gfArtillery', gfArtillery);
@@ -2420,7 +3151,6 @@
 ScriptSetInteger('gmPrecise', gmPrecise);
 ScriptSetInteger('gmAllStoppable', gmAllStoppable);
 
-
 // speech bubbles
 ScriptSetInteger('SAY_SAY', 1);
 ScriptSetInteger('SAY_THINK', 2);
@@ -2450,30 +3180,44 @@
 for cg:= Low(TCapGroup) to High(TCapGroup) do
     ScriptSetInteger(EnumToStr(cg), ord(cg));
 
-ScriptSetInteger('gstDrowning'       ,$00000001);
-ScriptSetInteger('gstHHDriven'       ,$00000002);
-ScriptSetInteger('gstMoving'         ,$00000004);
-ScriptSetInteger('gstAttacked'       ,$00000008);
-ScriptSetInteger('gstAttacking'      ,$00000010);
-ScriptSetInteger('gstCollision'      ,$00000020);
-ScriptSetInteger('gstHHChooseTarget' ,$00000040);
-ScriptSetInteger('gstHHJumping'      ,$00000100);
-ScriptSetInteger('gsttmpFlag'        ,$00000200);
-ScriptSetInteger('gstHHThinking'     ,$00000800);
-ScriptSetInteger('gstNoDamage'       ,$00001000);
-ScriptSetInteger('gstHHHJump'        ,$00002000);
-ScriptSetInteger('gstAnimation'      ,$00004000);
-ScriptSetInteger('gstHHDeath'        ,$00008000);
-ScriptSetInteger('gstWinner'         ,$00010000);
-ScriptSetInteger('gstWait'           ,$00020000);
-ScriptSetInteger('gstNotKickable'    ,$00040000);
-ScriptSetInteger('gstLoser'          ,$00080000);
-ScriptSetInteger('gstHHGone'         ,$00100000);
-ScriptSetInteger('gstInvisible'      ,$00200000);
+for spr:= Low(TSprite) to High(TSprite) do
+    ScriptSetInteger(EnumToStr(spr), ord(spr));
+
+for mg:= Low(TMapGen) to High(TMapGen) do
+    ScriptSetInteger(EnumToStr(mg), ord(mg));
+
+ScriptSetInteger('gstDrowning'      , gstDrowning);
+ScriptSetInteger('gstHHDriven'      , gstHHDriven);
+ScriptSetInteger('gstMoving'        , gstMoving);
+ScriptSetInteger('gstAttacked'      , gstAttacked);
+ScriptSetInteger('gstAttacking'     , gstAttacking);
+ScriptSetInteger('gstCollision'     , gstCollision);
+ScriptSetInteger('gstChooseTarget'  , gstChooseTarget);
+ScriptSetInteger('gstHHJumping'     , gstHHJumping);
+ScriptSetInteger('gsttmpFlag'       , gsttmpFlag);
+ScriptSetInteger('gstHHThinking'    , gstHHThinking);
+ScriptSetInteger('gstNoDamage'      , gstNoDamage);
+ScriptSetInteger('gstHHHJump'       , gstHHHJump);
+ScriptSetInteger('gstAnimation'     , gstAnimation);
+ScriptSetInteger('gstHHDeath'       , gstHHDeath);
+ScriptSetInteger('gstWinner'        , gstWinner);
+ScriptSetInteger('gstWait'          , gstWait);
+ScriptSetInteger('gstNotKickable'   , gstNotKickable);
+ScriptSetInteger('gstLoser'         , gstLoser);
+ScriptSetInteger('gstHHGone'        , gstHHGone);
+ScriptSetInteger('gstInvisible'     , gstInvisible);
+ScriptSetInteger('gstSubmersible'   , gstSubmersible);
+ScriptSetInteger('gstFrozen'        , gstFrozen);
+ScriptSetInteger('gstNoGravity'     , gstNoGravity);
 
 // ai hints
-ScriptSetInteger('aihUsualProcessing' ,$00000000);
-ScriptSetInteger('aihDoesntMatter'    ,$00000001);
+ScriptSetInteger('aihUsualProcessing', aihUsualProcessing);
+ScriptSetInteger('aihDoesntMatter'   , aihDoesntMatter);
+
+// land flags
+ScriptSetInteger('lfIndestructible', lfIndestructible);
+ScriptSetInteger('lfIce'           , lfIce);
+ScriptSetInteger('lfBouncy'        , lfBouncy);
 
 // register functions
 lua_register(luaState, _P'HideHog', @lc_hidehog);
@@ -2487,14 +3231,18 @@
 lua_register(luaState, _P'GetInputMask', @lc_getinputmask);
 lua_register(luaState, _P'SetInputMask', @lc_setinputmask);
 lua_register(luaState, _P'AddGear', @lc_addgear);
+lua_register(luaState, _P'DismissTeam', @lc_dismissteam);
 lua_register(luaState, _P'EnableGameFlags', @lc_enablegameflags);
 lua_register(luaState, _P'DisableGameFlags', @lc_disablegameflags);
 lua_register(luaState, _P'ClearGameFlags', @lc_cleargameflags);
+lua_register(luaState, _P'GetGameFlag', @lc_getgameflag);
 lua_register(luaState, _P'DeleteGear', @lc_deletegear);
 lua_register(luaState, _P'AddVisualGear', @lc_addvisualgear);
 lua_register(luaState, _P'DeleteVisualGear', @lc_deletevisualgear);
 lua_register(luaState, _P'GetVisualGearValues', @lc_getvisualgearvalues);
 lua_register(luaState, _P'SetVisualGearValues', @lc_setvisualgearvalues);
+lua_register(luaState, _P'GetGearValues', @lc_getgearvalues);
+lua_register(luaState, _P'SetGearValues', @lc_setgearvalues);
 lua_register(luaState, _P'SpawnHealthCrate', @lc_spawnhealthcrate);
 lua_register(luaState, _P'SpawnAmmoCrate', @lc_spawnammocrate);
 lua_register(luaState, _P'SpawnUtilityCrate', @lc_spawnutilitycrate);
@@ -2532,6 +3280,9 @@
 lua_register(luaState, _P'GetHogClan', @lc_gethogclan);
 lua_register(luaState, _P'GetClanColor', @lc_getclancolor);
 lua_register(luaState, _P'SetClanColor', @lc_setclancolor);
+lua_register(luaState, _P'GetHogVoicepack', @lc_gethogvoicepack);
+lua_register(luaState, _P'GetHogFlag', @lc_gethogflag);
+lua_register(luaState, _P'GetHogGrave', @lc_gethoggrave);
 lua_register(luaState, _P'GetHogTeamName', @lc_gethogteamname);
 lua_register(luaState, _P'SetHogTeamName', @lc_sethogteamname);
 lua_register(luaState, _P'GetHogName', @lc_gethogname);
@@ -2549,6 +3300,8 @@
 lua_register(luaState, _P'SetTag', @lc_settag);
 lua_register(luaState, _P'SetTimer', @lc_settimer);
 lua_register(luaState, _P'GetTimer', @lc_gettimer);
+lua_register(luaState, _P'SetFlightTime', @lc_setflighttime);
+lua_register(luaState, _P'GetFlightTime', @lc_getflighttime);
 lua_register(luaState, _P'SetZoom', @lc_setzoom);
 lua_register(luaState, _P'GetZoom', @lc_getzoom);
 lua_register(luaState, _P'HogSay', @lc_hogsay);
@@ -2557,6 +3310,9 @@
 lua_register(luaState, _P'CampaignLock', @lc_campaignlock);
 lua_register(luaState, _P'CampaignUnlock', @lc_campaignunlock);
 lua_register(luaState, _P'GetGearElasticity', @lc_getgearelasticity);
+lua_register(luaState, _P'SetGearElasticity', @lc_setgearelasticity);
+lua_register(luaState, _P'GetGearFriction', @lc_getgearfriction);
+lua_register(luaState, _P'SetGearFriction', @lc_setgearfriction);
 lua_register(luaState, _P'GetGearRadius', @lc_getgearradius);
 lua_register(luaState, _P'GetGearMessage', @lc_getgearmessage);
 lua_register(luaState, _P'SetGearMessage', @lc_setgearmessage);
@@ -2571,14 +3327,28 @@
 lua_register(luaState, _P'MapHasBorder', @lc_maphasborder);
 lua_register(luaState, _P'GetHogHat', @lc_gethoghat);
 lua_register(luaState, _P'SetHogHat', @lc_sethoghat);
+lua_register(luaState, _P'EraseSprite', @lc_erasesprite);
+lua_register(luaState, _P'PlaceSprite', @lc_placesprite);
 lua_register(luaState, _P'PlaceGirder', @lc_placegirder);
 lua_register(luaState, _P'GetCurAmmoType', @lc_getcurammotype);
 lua_register(luaState, _P'TestRectForObstacle', @lc_testrectforobstacle);
+lua_register(luaState, _P'GetGravity', @lc_getgravity);
+lua_register(luaState, _P'SetGravity', @lc_setgravity);
+lua_register(luaState, _P'SetWaterLine', @lc_setwaterline);
+lua_register(luaState, _P'SetNextWeapon', @lc_setnextweapon);
+lua_register(luaState, _P'SetWeapon', @lc_setweapon);
+lua_register(luaState, _P'SetMaxBuildDistance', @lc_setmaxbuilddistance);
+// drawn map functions
+lua_register(luaState, _P'AddPoint', @lc_addPoint);
+lua_register(luaState, _P'FlushPoints', @lc_flushPoints);
 
-lua_register(luaState, _P'SetGearAIHints', @lc_setaihintsongear);
+lua_register(luaState, _P'SetGearAIHints', @lc_setgearaihints);
 lua_register(luaState, _P'HedgewarsScriptLoad', @lc_hedgewarsscriptload);
 lua_register(luaState, _P'DeclareAchievement', @lc_declareachievement);
 
+ScriptSetInteger('TEST_SUCCESSFUL'   , HaltTestSuccess);
+ScriptSetInteger('TEST_FAILED'       , HaltTestFailed);
+lua_register(luaState, _P'EndLuaTest', @lc_endluatest);
 
 ScriptClearStack; // just to be sure stack is empty
 ScriptLoaded:= false;
@@ -2672,6 +3442,9 @@
 procedure initModule;
 begin
 mapDims:= false;
+PointsBuffer:= '';
+prevCursorPoint.X:= NoPointX;
+prevCursorPoint.Y:= 0;
 end;
 
 procedure freeModule;